… | |
… | |
119 | =cut |
119 | =cut |
120 | |
120 | |
121 | sub LATENCY() { 3 } # assumed max. network latency |
121 | sub LATENCY() { 3 } # assumed max. network latency |
122 | |
122 | |
123 | our @FRAMINGS = qw(json storable); # the framing types we accept and send, in order of preference |
123 | our @FRAMINGS = qw(json storable); # the framing types we accept and send, in order of preference |
124 | our @AUTH_SND = qw(hmac_md6_64_256); # auth types we send |
124 | our @AUTH_SND = qw(tls_md6_64_256 hmac_md6_64_256); # auth types we send |
125 | our @AUTH_RCV = (@AUTH_SND, qw(cleartext)); # auth types we accept |
125 | our @AUTH_RCV = (@AUTH_SND, qw(tls_anon cleartext)); # auth types we accept |
126 | |
126 | |
127 | #AnyEvent::Handle::register_write_type mp_record => sub { |
127 | #AnyEvent::Handle::register_write_type mp_record => sub { |
128 | #}; |
128 | #}; |
129 | |
129 | |
130 | sub new { |
130 | sub new { |
… | |
… | |
179 | |
179 | |
180 | my $greeting_kv = $self->{greeting} ||= {}; |
180 | my $greeting_kv = $self->{greeting} ||= {}; |
181 | |
181 | |
182 | $self->{local_node} ||= $AnyEvent::MP::Kernel::NODE; |
182 | $self->{local_node} ||= $AnyEvent::MP::Kernel::NODE; |
183 | |
183 | |
184 | $greeting_kv->{"tls"} = "1.0" if $arg{tls_ctx}; |
184 | $greeting_kv->{tls} = "1.0" if $arg{tls_ctx}; |
185 | $greeting_kv->{provider} = "AE-$AnyEvent::MP::Kernel::VERSION"; |
185 | $greeting_kv->{provider} = "AE-$AnyEvent::MP::Kernel::VERSION"; |
186 | $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport}; |
186 | $greeting_kv->{peeraddr} = AnyEvent::Socket::format_hostport $self->{peerhost}, $self->{peerport}; |
187 | $greeting_kv->{timeout} = $arg{timeout}; |
187 | $greeting_kv->{timeout} = $arg{timeout}; |
188 | |
188 | |
189 | # send greeting |
189 | # send greeting |
… | |
… | |
212 | return $self->error ("I refuse to talk to myself"); |
212 | return $self->error ("I refuse to talk to myself"); |
213 | } elsif ($AnyEvent::MP::Kernel::NODE{$rnode} && $AnyEvent::MP::Kernel::NODE{$rnode}{transport}) { |
213 | } elsif ($AnyEvent::MP::Kernel::NODE{$rnode} && $AnyEvent::MP::Kernel::NODE{$rnode}{transport}) { |
214 | return $self->error ("$rnode already connected, not connecting again."); |
214 | return $self->error ("$rnode already connected, not connecting again."); |
215 | } |
215 | } |
216 | |
216 | |
217 | my $s_auth; |
|
|
218 | for my $auth_ (split /,/, $auths) { |
|
|
219 | if (grep $auth_ eq $_, @AUTH_SND) { |
|
|
220 | $s_auth = $auth_; |
|
|
221 | last; |
|
|
222 | } |
|
|
223 | } |
|
|
224 | |
|
|
225 | defined $s_auth |
|
|
226 | or return $self->error ("$auths: no common auth type supported"); |
|
|
227 | |
|
|
228 | die unless $s_auth eq "hmac_md6_64_256"; # hardcoded atm. |
|
|
229 | |
|
|
230 | my $s_framing; |
|
|
231 | for my $framing_ (split /,/, $framings) { |
|
|
232 | if (grep $framing_ eq $_, @FRAMINGS) { |
|
|
233 | $s_framing = $framing_; |
|
|
234 | last; |
|
|
235 | } |
|
|
236 | } |
|
|
237 | |
|
|
238 | defined $s_framing |
|
|
239 | or return $self->error ("$framings: no common framing method supported"); |
|
|
240 | |
|
|
241 | $self->{remote_node} = $rnode; |
217 | $self->{remote_node} = $rnode; |
242 | |
218 | |
243 | $self->{remote_greeting} = { |
219 | $self->{remote_greeting} = { |
244 | map /^([^=]+)(?:=(.*))?/ ? ($1 => $2) : (), |
220 | map /^([^=]+)(?:=(.*))?/ ? ($1 => $2) : (), |
245 | @kv |
221 | @kv |
… | |
… | |
250 | my $rgreeting2 = $_[1]; |
226 | my $rgreeting2 = $_[1]; |
251 | |
227 | |
252 | "$lgreeting1\012$lgreeting2" ne "$rgreeting1\012$rgreeting2" # echo attack? |
228 | "$lgreeting1\012$lgreeting2" ne "$rgreeting1\012$rgreeting2" # echo attack? |
253 | or return $self->error ("authentication error, echo attack?"); |
229 | or return $self->error ("authentication error, echo attack?"); |
254 | |
230 | |
|
|
231 | my $tls = $self->{tls_ctx} && 1 == int $self->{remote_greeting}{tls}; |
|
|
232 | |
|
|
233 | my $s_auth; |
|
|
234 | for my $auth_ (split /,/, $auths) { |
|
|
235 | if (grep $auth_ eq $_, @AUTH_SND and ($auth_ !~ /^tls_/ or $tls)) { |
|
|
236 | $s_auth = $auth_; |
|
|
237 | last; |
|
|
238 | } |
|
|
239 | } |
|
|
240 | |
|
|
241 | defined $s_auth |
|
|
242 | or return $self->error ("$auths: no common auth type supported"); |
|
|
243 | |
|
|
244 | my $s_framing; |
|
|
245 | for my $framing_ (split /,/, $framings) { |
|
|
246 | if (grep $framing_ eq $_, @FRAMINGS) { |
|
|
247 | $s_framing = $framing_; |
|
|
248 | last; |
|
|
249 | } |
|
|
250 | } |
|
|
251 | |
|
|
252 | defined $s_framing |
|
|
253 | or return $self->error ("$framings: no common framing method supported"); |
|
|
254 | |
255 | my $key; |
255 | my $key; |
256 | my $lauth; |
256 | my $lauth; |
257 | |
257 | |
258 | if ($self->{tls_ctx} and 1 == int $self->{remote_greeting}{tls}) { |
258 | if ($tls) { |
259 | $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept"; |
259 | $self->{tls} = $lgreeting2 lt $rgreeting2 ? "connect" : "accept"; |
260 | $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx}); |
260 | $self->{hdl}->starttls ($self->{tls}, $self->{tls_ctx}); |
261 | $s_auth = "tls"; |
261 | |
262 | $lauth = ""; |
262 | $lauth = |
|
|
263 | $s_auth eq "tls_anon" ? "" |
|
|
264 | : $s_auth eq "tls_md6_64_256" ? Digest::MD6::md6_hex "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012" |
|
|
265 | : return $self->error ("$s_auth: fatal, selected unsupported snd auth method"); |
|
|
266 | |
263 | } elsif (length $secret) { |
267 | } elsif (length $secret) { |
|
|
268 | return $self->error ("$s_auth: fatal, selected unsupported snd auth method") |
|
|
269 | unless $s_auth eq "hmac_md6_64_256"; # hardcoded atm. |
|
|
270 | |
264 | $key = Digest::MD6::md6 $secret; |
271 | $key = Digest::MD6::md6 $secret; |
265 | # we currently only support hmac_md6_64_256 |
272 | # we currently only support hmac_md6_64_256 |
266 | $lauth = Digest::HMAC_MD6::hmac_md6_hex $key, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012", 64, 256; |
273 | $lauth = Digest::HMAC_MD6::hmac_md6_hex $key, "$lgreeting1\012$lgreeting2\012$rgreeting1\012$rgreeting2\012", 64, 256; |
|
|
274 | |
267 | } else { |
275 | } else { |
268 | return $self->error ("unable to handshake TLS and no shared secret configured"); |
276 | return $self->error ("unable to handshake TLS and no shared secret configured"); |
269 | } |
277 | } |
270 | |
278 | |
271 | $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012"); |
279 | $self->{hdl}->push_write ("$s_auth;$lauth;$s_framing\012"); |
… | |
… | |
277 | my ($auth_method, $rauth2, $r_framing) = split /;/, $rline; |
285 | my ($auth_method, $rauth2, $r_framing) = split /;/, $rline; |
278 | |
286 | |
279 | my $rauth = |
287 | my $rauth = |
280 | $auth_method eq "hmac_md6_64_256" ? Digest::HMAC_MD6::hmac_md6_hex $key, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012", 64, 256 |
288 | $auth_method eq "hmac_md6_64_256" ? Digest::HMAC_MD6::hmac_md6_hex $key, "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012", 64, 256 |
281 | : $auth_method eq "cleartext" ? unpack "H*", $secret |
289 | : $auth_method eq "cleartext" ? unpack "H*", $secret |
282 | : $auth_method eq "tls" ? ($self->{tls} ? "" : "\012\012") # \012\012 never matches |
290 | : $auth_method eq "tls_anon" ? ($tls ? "" : "\012\012") # \012\012 never matches |
|
|
291 | : $auth_method eq "tls_md6_64_256" ? ($tls ? Digest::MD6::md6_hex "$rgreeting1\012$rgreeting2\012$lgreeting1\012$lgreeting2\012" : "\012\012") |
283 | : return $self->error ("$auth_method: fatal, selected unsupported auth method"); |
292 | : return $self->error ("$auth_method: fatal, selected unsupported rcv auth method"); |
284 | |
293 | |
285 | if ($rauth2 ne $rauth) { |
294 | if ($rauth2 ne $rauth) { |
286 | return $self->error ("authentication failure/shared secret mismatch"); |
295 | return $self->error ("authentication failure/shared secret mismatch"); |
287 | } |
296 | } |
288 | |
297 | |
… | |
… | |
498 | |
507 | |
499 | =item the authentication method chosen |
508 | =item the authentication method chosen |
500 | |
509 | |
501 | This must be one of the methods offered by the other side in the greeting. |
510 | This must be one of the methods offered by the other side in the greeting. |
502 | |
511 | |
|
|
512 | Note that all methods starting with C<tls_> are only valid I<iff> TLS was |
|
|
513 | successfully handshaked (and to be secure the implementation must enforce |
|
|
514 | this). |
|
|
515 | |
503 | The currently supported authentication methods are: |
516 | The currently supported authentication methods are: |
504 | |
517 | |
505 | =over 4 |
518 | =over 4 |
506 | |
519 | |
507 | =item cleartext |
520 | =item cleartext |
… | |
… | |
532 | |
545 | |
533 | rauth = HMAC_MD6 key, "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012" |
546 | rauth = HMAC_MD6 key, "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012" |
534 | |
547 | |
535 | This is the token that is expected from the other side. |
548 | This is the token that is expected from the other side. |
536 | |
549 | |
537 | =item tls |
550 | =item tls_anon |
538 | |
551 | |
539 | This type is only valid iff TLS was enabled and the TLS handshake |
552 | This type is only valid iff TLS was enabled and the TLS handshake |
540 | was successful. It has no authentication data, as the server/client |
553 | was successful. It has no authentication data, as the server/client |
541 | certificate was successfully verified. |
554 | certificate was successfully verified. |
542 | |
555 | |
543 | Implementations supporting TLS I<must> accept this authentication type. |
556 | This authentication type is slightly less secure than the others, as it |
|
|
557 | allows a man-in-the-middle attacker to change some of the connection |
|
|
558 | parameters (such as the framing format), although there is no known attack |
|
|
559 | that exploits this in a way that is worse than just denying the service. |
|
|
560 | |
|
|
561 | By default, this implementation accepts but uses this authentication |
|
|
562 | method. |
|
|
563 | |
|
|
564 | =item tls_md6_64_256 |
|
|
565 | |
|
|
566 | This type is only valid iff TLS was enabled and the TLS handshake |
|
|
567 | was successful. |
|
|
568 | |
|
|
569 | This authentication type simply calculates: |
|
|
570 | |
|
|
571 | lauth = MD6 "rgreeting1\012rgreeting2\012lgreeting1\012lgreeting2\012" |
|
|
572 | |
|
|
573 | and lowercase-hex encodes the result and sends it as authentication |
|
|
574 | data. No shared secret is required (authentication is done by TLS). The |
|
|
575 | checksum solely exists to make tinkering with the greeting hard. |
544 | |
576 | |
545 | =back |
577 | =back |
546 | |
578 | |
547 | =item the authentication data |
579 | =item the authentication data |
548 | |
580 | |