diff options
author | Heikki Vatiainen <hvn@radiatorsoftware.com> | 2023-08-22 00:38:16 +0300 |
---|---|---|
committer | Heikki Vatiainen <hvn@radiatorsoftware.com> | 2023-08-22 00:38:16 +0300 |
commit | a2f5ff3f04c75ab61cd3a95e0ecf81a1455cbd30 (patch) | |
tree | a621c76ea14560321da146d634ef99ef699cb1bc | |
parent | 9fac2c27abaa299cdadddacac3b61ef88de27b07 (diff) |
GH-71 Expose SSL_client_hello_isv2().
Also start documenting SSL_CTX_set_client_hello_cb() family of functions.
-rw-r--r-- | SSLeay.xs | 3 | ||||
-rw-r--r-- | lib/Net/SSLeay.pod | 43 | ||||
-rw-r--r-- | t/local/48_client_hello_callback.t | 59 |
3 files changed, 102 insertions, 3 deletions
@@ -5893,6 +5893,9 @@ SSL_CTX_set_client_hello_cb(SSL_CTX *ctx, SV *callback, SV *arg=&PL_sv_undef) SSL_CTX_set_client_hello_cb(ctx, ssl_client_hello_cb_fn_invoke, NULL); } +int +SSL_client_hello_isv2(SSL *s) + #endif int diff --git a/lib/Net/SSLeay.pod b/lib/Net/SSLeay.pod index 4f03f86..e4ad82e 100644 --- a/lib/Net/SSLeay.pod +++ b/lib/Net/SSLeay.pod @@ -3584,6 +3584,34 @@ Retrieve the previously set TLS key logging callback. Check openssl doc L<https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_keylog_callback.html> +=item * CTX_set_client_hello_cb + +B<COMPATIBILITY:> not available in Net-SSLeay-1.92 and before; requires at least OpenSSL 1.1.1pre1, not in LibreSSL + +Set a callback function called during the early stages of ClientHello processing on the server. +When callback is undef, the existing callback is disabled. + + Net::SSLeay::CTX_set_client_hello_cb($ctx, $f, [$arg]); + # $ctx - value corresponding to openssl's SSL_CTX structure + # $f - sub { my ($ssl, $arg) = @_; ...; return ($ret, $al); } + # $arg - optional data passed to the callback function when invoked + # + # returns: no return value + +The callback function will be called like this: + + client_hello_cb_func($ssl, $arg); + # $ssl - value corresponding to OpenSSL's SSL object associated with the connection + # $arg - data to callback + # + # An alert code must be returned with SSL_CLIENT_HELLO_FAILURE. + # Return value examples: + # ok: return Net::SSLeay::CLIENT_HELLO_SUCCESS(); + # suspend: return Net::SSLeay::CLIENT_HELLO_RETRY(); + # error: return (Net::SSLeay::CLIENT_HELLO_FAILURE(), Net::SSLeay::AD_NO_APPLICATION_PROTOCOL()); + +Check openssl doc L<https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_hello_cb.html> + =back =head3 Low level API: SSL_* related functions @@ -5467,6 +5495,21 @@ Sets TLS servername extension on SLL object $ssl to value $name. # # returns: 1 on success, 0 on failure +=item * client_hello_isv2 + +B<COMPATIBILITY:> not available in Net-SSLeay-1.92 and before; requires at least OpenSSL 1.1.1pre1, not in LibreSSL + +B<NOTE:> to be used only from a callback set with L<CTX_set_client_hello_cb>. + +Indicate if the ClientHello was carried in a SSLv2 record and is in the SSLv2 format. + + my $rv = client_hello_isv2($s); + # $s - value corresponding to openssl's SSL structure + # + # returns: 1 for SSLv2-format ClientHellos and 0 otherwise + +Check openssl doc L<https://www.openssl.org/docs/manmaster/man3/SSL_client_hello_isv2.html> + =back =head3 Low level API: RAND_* related functions diff --git a/t/local/48_client_hello_callback.t b/t/local/48_client_hello_callback.t index c421423..a521856 100644 --- a/t/local/48_client_hello_callback.t +++ b/t/local/48_client_hello_callback.t @@ -11,7 +11,7 @@ BEGIN { } elsif (not can_fork()) { plan skip_all => "fork() not supported on this system"; } else { - plan tests => 16; + plan tests => 19; } } @@ -25,6 +25,19 @@ my $key_pem = data_file_path('simple-cert.key.pem'); my $cb_test_arg = [1, 'string for hello cb test arg']; +# As of 2023-08, even the latest in-development OpenSSL allows +# connections with SSLv2 ClientHello. Tested with OpenSSL 0.9.8f as +# client and OpenSSL 3.2.0-dev from git master branch as +# server. Trigger alert 42 as a marker. +sub client_hello_cb_v2hello_detection +{ + my ($ssl, $arg) = @_; + + is(Net::SSLeay::client_hello_isv2($ssl), 1, 'SSLv2 ClientHello'); + my $al = Net::SSLeay::AD_BAD_CERTIFICATE(); + return (Net::SSLeay::CLIENT_HELLO_ERROR(), $al); +} + # See that the exact same reference with unchanged contents are made # available for the callback. Allow handshake to proceed. sub client_hello_cb_value_passing @@ -86,6 +99,7 @@ my @cb_tests = ( # argument passed to the callback # true if the callback function triggers croak() # true if the client needs to test that ALPN alert (120) is received + [ \&client_hello_cb_v2hello_detection, undef, 0 ], [ \&client_hello_cb_value_passing, \$cb_test_arg, 0 ], [ \&client_hello_cb_alert_alpn, undef, 0, 'alerts'], [ \&client_hello_cb_alert_alpn, undef, 0, 'alerts'], # Call again to increase alert counter @@ -147,6 +161,7 @@ my @results; } { + # SSL client my $alpn_alert_count = 0; # Use info callback to count TLS alert 120 occurences (ALPN alert). @@ -158,7 +173,21 @@ my @results; } }; - # SSL client + # Start with SSLv2 ClientHello detection test. Send a canned SSLv2 + # ClientHello. + { + my $s_clientv2 = $server->connect(); + my $clientv2_hello = get_sslv2_hello(); + syswrite($s_clientv2, $clientv2_hello, length $clientv2_hello); + sysread($s_clientv2, my $buf, 16384); + + # Alert (15), version (0303|4), length (0002), level fatal (02), bad cert(2a) + push @results, [unpack('H*', $buf) =~ m/^15030.0002022a\z/, 'Alert from SSLv2 ClientHello']; + close($s_clientv2) || die("s_clientv2 close"); + shift @cb_tests; + } + + # The rest of tests use client's TLS stack foreach my $cb_test (@cb_tests) { my $s_c = $server->connect(); @@ -187,6 +216,30 @@ my @results; waitpid $pid, 0; push @results, [$? == 0, 'server exited with 0']; END { - Test::More->builder->current_test(14); + Test::More->builder->current_test(16); ok( $_->[0], $_->[1] ) for (@results); } + +# Use a canned SSLv2 ClientHello for testing OpenSSL's +# SSL_client_hello_isv2() +sub get_sslv2_hello +{ + # Captures with OpenSSL 0.9.8f. The second capture uses TLSv1.0 as + # Version but still includes a number of SSLv2 ciphersuites. + # + # openssl s_client -connect 127.0.0.1:443 -ssl2 + # openssl s_client -connect 127.0.0.1:443 + my $sslv2_sslv2_hex_f = '802e0100020015000000100700c00500800300800100800600400400800200808f11701ccdc4eab421b6d03e4942ea98'; + my $sslv2_tlsv1_hex_f = '807a01030100510000002000003900003800003500001600001300000a0700c000003300003200002f0000070500800300800000050000040100800000150000120000090600400000140000110000080000060400800000030200807f0913623fe5e84de01bc7733ae8fcdcefda1ef60a4c960ac7251f6560841566'; + + # Captures with OpenSSL 0.9.8zh. + # + # The first capture is similar to 0.9.8f but the ciphersuites are + # now ordered with the strongest first.The second capture uses + # TLSv1.0 as Version but compared to 0.9.8f has a more modern set + # of ciphers and includes TLS_EMPTY_RENEGOTIATION_INFO_SCSV. + my $sslv2_sslv2_hex_zh = '802e0100020015000000100700c006004005008004008003008002008001008015c9eb78cbf9702542ac2d4c46b6101a'; + my $sslv2_tlsv1_hex_zh = '805901030100300000002000003900003800003500001600001300000a00003300003200002f0000070000050000040000150000120000090000ff1f90dda05ec4a857523dcc0ae06c461a99c36ce647a84aa64061c054333376b9'; + + return pack('H*', $sslv2_tlsv1_hex_zh); +} |