Skip to content

Commit a2f5ff3

Browse files
committed
GH-71 Expose SSL_client_hello_isv2().
Also start documenting SSL_CTX_set_client_hello_cb() family of functions.
1 parent 9fac2c2 commit a2f5ff3

File tree

3 files changed

+102
-3
lines changed

3 files changed

+102
-3
lines changed

SSLeay.xs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5893,6 +5893,9 @@ SSL_CTX_set_client_hello_cb(SSL_CTX *ctx, SV *callback, SV *arg=&PL_sv_undef)
58935893
SSL_CTX_set_client_hello_cb(ctx, ssl_client_hello_cb_fn_invoke, NULL);
58945894
}
58955895

5896+
int
5897+
SSL_client_hello_isv2(SSL *s)
5898+
58965899
#endif
58975900

58985901
int

lib/Net/SSLeay.pod

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,34 @@ Retrieve the previously set TLS key logging callback.
35843584

35853585
Check openssl doc L<https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_keylog_callback.html>
35863586

3587+
=item * CTX_set_client_hello_cb
3588+
3589+
B<COMPATIBILITY:> not available in Net-SSLeay-1.92 and before; requires at least OpenSSL 1.1.1pre1, not in LibreSSL
3590+
3591+
Set a callback function called during the early stages of ClientHello processing on the server.
3592+
When callback is undef, the existing callback is disabled.
3593+
3594+
Net::SSLeay::CTX_set_client_hello_cb($ctx, $f, [$arg]);
3595+
# $ctx - value corresponding to openssl's SSL_CTX structure
3596+
# $f - sub { my ($ssl, $arg) = @_; ...; return ($ret, $al); }
3597+
# $arg - optional data passed to the callback function when invoked
3598+
#
3599+
# returns: no return value
3600+
3601+
The callback function will be called like this:
3602+
3603+
client_hello_cb_func($ssl, $arg);
3604+
# $ssl - value corresponding to OpenSSL's SSL object associated with the connection
3605+
# $arg - data to callback
3606+
#
3607+
# An alert code must be returned with SSL_CLIENT_HELLO_FAILURE.
3608+
# Return value examples:
3609+
# ok: return Net::SSLeay::CLIENT_HELLO_SUCCESS();
3610+
# suspend: return Net::SSLeay::CLIENT_HELLO_RETRY();
3611+
# error: return (Net::SSLeay::CLIENT_HELLO_FAILURE(), Net::SSLeay::AD_NO_APPLICATION_PROTOCOL());
3612+
3613+
Check openssl doc L<https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_hello_cb.html>
3614+
35873615
=back
35883616

35893617
=head3 Low level API: SSL_* related functions
@@ -5467,6 +5495,21 @@ Sets TLS servername extension on SLL object $ssl to value $name.
54675495
#
54685496
# returns: 1 on success, 0 on failure
54695497

5498+
=item * client_hello_isv2
5499+
5500+
B<COMPATIBILITY:> not available in Net-SSLeay-1.92 and before; requires at least OpenSSL 1.1.1pre1, not in LibreSSL
5501+
5502+
B<NOTE:> to be used only from a callback set with L<CTX_set_client_hello_cb>.
5503+
5504+
Indicate if the ClientHello was carried in a SSLv2 record and is in the SSLv2 format.
5505+
5506+
my $rv = client_hello_isv2($s);
5507+
# $s - value corresponding to openssl's SSL structure
5508+
#
5509+
# returns: 1 for SSLv2-format ClientHellos and 0 otherwise
5510+
5511+
Check openssl doc L<https://www.openssl.org/docs/manmaster/man3/SSL_client_hello_isv2.html>
5512+
54705513
=back
54715514

54725515
=head3 Low level API: RAND_* related functions

t/local/48_client_hello_callback.t

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ BEGIN {
1111
} elsif (not can_fork()) {
1212
plan skip_all => "fork() not supported on this system";
1313
} else {
14-
plan tests => 16;
14+
plan tests => 19;
1515
}
1616
}
1717

@@ -25,6 +25,19 @@ my $key_pem = data_file_path('simple-cert.key.pem');
2525

2626
my $cb_test_arg = [1, 'string for hello cb test arg'];
2727

28+
# As of 2023-08, even the latest in-development OpenSSL allows
29+
# connections with SSLv2 ClientHello. Tested with OpenSSL 0.9.8f as
30+
# client and OpenSSL 3.2.0-dev from git master branch as
31+
# server. Trigger alert 42 as a marker.
32+
sub client_hello_cb_v2hello_detection
33+
{
34+
my ($ssl, $arg) = @_;
35+
36+
is(Net::SSLeay::client_hello_isv2($ssl), 1, 'SSLv2 ClientHello');
37+
my $al = Net::SSLeay::AD_BAD_CERTIFICATE();
38+
return (Net::SSLeay::CLIENT_HELLO_ERROR(), $al);
39+
}
40+
2841
# See that the exact same reference with unchanged contents are made
2942
# available for the callback. Allow handshake to proceed.
3043
sub client_hello_cb_value_passing
@@ -86,6 +99,7 @@ my @cb_tests = (
8699
# argument passed to the callback
87100
# true if the callback function triggers croak()
88101
# true if the client needs to test that ALPN alert (120) is received
102+
[ \&client_hello_cb_v2hello_detection, undef, 0 ],
89103
[ \&client_hello_cb_value_passing, \$cb_test_arg, 0 ],
90104
[ \&client_hello_cb_alert_alpn, undef, 0, 'alerts'],
91105
[ \&client_hello_cb_alert_alpn, undef, 0, 'alerts'], # Call again to increase alert counter
@@ -147,6 +161,7 @@ my @results;
147161
}
148162

149163
{
164+
# SSL client
150165
my $alpn_alert_count = 0;
151166

152167
# Use info callback to count TLS alert 120 occurences (ALPN alert).
@@ -158,7 +173,21 @@ my @results;
158173
}
159174
};
160175

161-
# SSL client
176+
# Start with SSLv2 ClientHello detection test. Send a canned SSLv2
177+
# ClientHello.
178+
{
179+
my $s_clientv2 = $server->connect();
180+
my $clientv2_hello = get_sslv2_hello();
181+
syswrite($s_clientv2, $clientv2_hello, length $clientv2_hello);
182+
sysread($s_clientv2, my $buf, 16384);
183+
184+
# Alert (15), version (0303|4), length (0002), level fatal (02), bad cert(2a)
185+
push @results, [unpack('H*', $buf) =~ m/^15030.0002022a\z/, 'Alert from SSLv2 ClientHello'];
186+
close($s_clientv2) || die("s_clientv2 close");
187+
shift @cb_tests;
188+
}
189+
190+
# The rest of tests use client's TLS stack
162191
foreach my $cb_test (@cb_tests) {
163192
my $s_c = $server->connect();
164193

@@ -187,6 +216,30 @@ my @results;
187216
waitpid $pid, 0;
188217
push @results, [$? == 0, 'server exited with 0'];
189218
END {
190-
Test::More->builder->current_test(14);
219+
Test::More->builder->current_test(16);
191220
ok( $_->[0], $_->[1] ) for (@results);
192221
}
222+
223+
# Use a canned SSLv2 ClientHello for testing OpenSSL's
224+
# SSL_client_hello_isv2()
225+
sub get_sslv2_hello
226+
{
227+
# Captures with OpenSSL 0.9.8f. The second capture uses TLSv1.0 as
228+
# Version but still includes a number of SSLv2 ciphersuites.
229+
#
230+
# openssl s_client -connect 127.0.0.1:443 -ssl2
231+
# openssl s_client -connect 127.0.0.1:443
232+
my $sslv2_sslv2_hex_f = '802e0100020015000000100700c00500800300800100800600400400800200808f11701ccdc4eab421b6d03e4942ea98';
233+
my $sslv2_tlsv1_hex_f = '807a01030100510000002000003900003800003500001600001300000a0700c000003300003200002f0000070500800300800000050000040100800000150000120000090600400000140000110000080000060400800000030200807f0913623fe5e84de01bc7733ae8fcdcefda1ef60a4c960ac7251f6560841566';
234+
235+
# Captures with OpenSSL 0.9.8zh.
236+
#
237+
# The first capture is similar to 0.9.8f but the ciphersuites are
238+
# now ordered with the strongest first.The second capture uses
239+
# TLSv1.0 as Version but compared to 0.9.8f has a more modern set
240+
# of ciphers and includes TLS_EMPTY_RENEGOTIATION_INFO_SCSV.
241+
my $sslv2_sslv2_hex_zh = '802e0100020015000000100700c006004005008004008003008002008001008015c9eb78cbf9702542ac2d4c46b6101a';
242+
my $sslv2_tlsv1_hex_zh = '805901030100300000002000003900003800003500001600001300000a00003300003200002f0000070000050000040000150000120000090000ff1f90dda05ec4a857523dcc0ae06c461a99c36ce647a84aa64061c054333376b9';
243+
244+
return pack('H*', $sslv2_tlsv1_hex_zh);
245+
}

0 commit comments

Comments
 (0)