summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Vatiainen <hvn@radiatorsoftware.com>2023-08-22 00:38:16 +0300
committerHeikki Vatiainen <hvn@radiatorsoftware.com>2023-08-22 00:38:16 +0300
commita2f5ff3f04c75ab61cd3a95e0ecf81a1455cbd30 (patch)
treea621c76ea14560321da146d634ef99ef699cb1bc
parent9fac2c27abaa299cdadddacac3b61ef88de27b07 (diff)
GH-71 Expose SSL_client_hello_isv2().
Also start documenting SSL_CTX_set_client_hello_cb() family of functions.
-rw-r--r--SSLeay.xs3
-rw-r--r--lib/Net/SSLeay.pod43
-rw-r--r--t/local/48_client_hello_callback.t59
3 files changed, 102 insertions, 3 deletions
diff --git a/SSLeay.xs b/SSLeay.xs
index be92d92..2c7e785 100644
--- a/SSLeay.xs
+++ b/SSLeay.xs
@@ -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);
+}