[PATCH] Tests: ssl session ticket key rotation tests

Sergey Kandaurov pluknet at nginx.com
Tue Dec 20 15:51:07 UTC 2022


> On 16 Dec 2022, at 01:54, Maxim Dounin <mdounin at mdounin.ru> wrote:
> 
> Hello!
> 
> On Thu, Dec 15, 2022 at 06:14:34AM +0400, Sergey Kandaurov wrote:
> 
>> # HG changeset patch
>> # User Sergey Kandaurov <pluknet at nginx.com>
>> # Date 1671070326 -14400
>> #      Thu Dec 15 06:12:06 2022 +0400
>> # Node ID 82dc9c3a4ec81636e42e1417ce6661f3b0e4d358
>> # Parent  ff6c99824947575d4a8d3c9aeea8d6b68e0ace29
>> Tests: ssl session ticket key rotation tests.
>> 
>> diff --git a/ssl_session_ticket_key.t b/ssl_session_ticket_key.t
>> new file mode 100644
>> --- /dev/null
>> +++ b/ssl_session_ticket_key.t
>> @@ -0,0 +1,141 @@
>> +#!/usr/bin/perl
>> +
>> +# (C) Sergey Kandaurov
>> +# (C) Nginx, Inc.
>> +
>> +# Tests for rotation of SSL session ticket keys.
>> +
>> +###############################################################################
>> +
>> +use warnings;
>> +use strict;
>> +
>> +use Test::More;
>> +
>> +BEGIN { use FindBin; chdir($FindBin::Bin); }
>> +
>> +use lib 'lib';
>> +use Test::Nginx;
>> +
>> +###############################################################################
>> +
>> +select STDERR; $| = 1;
>> +select STDOUT; $| = 1;
>> +
>> +eval {
>> +	require Net::SSLeay; die if $Net::SSLeay::VERSION < 1.86;
>> +	Net::SSLeay::load_error_strings();
>> +	Net::SSLeay::SSLeay_add_ssl_algorithms();
>> +	Net::SSLeay::randomize();
>> +};
>> +plan(skip_all => 'Net::SSLeay version => 1.86 required') if $@;
>> +
>> +my $t = Test::Nginx->new()->has(qw/http http_ssl/)->has_daemon('openssl')
>> +	->plan(2)->write_file_expand('nginx.conf', <<'EOF');
>> +
>> +%%TEST_GLOBALS%%
>> +
>> +daemon off;
>> +worker_processes 2;
>> +
>> +events {
>> +}
>> +
>> +http {
>> +    %%TEST_GLOBALS_HTTP%%
>> +
>> +    ssl_certificate_key localhost.key;
>> +    ssl_certificate localhost.crt;
>> +
>> +    server {
>> +        listen       127.0.0.1:8080 ssl;
>> +        server_name  localhost;
>> +
>> +        ssl_session_cache shared:SSL:1m;
>> +        ssl_session_timeout 2;
>> +    }
>> +}
>> +
>> +EOF
>> +
>> +$t->write_file('openssl.conf', <<EOF);
>> +[ req ]
>> +default_bits = 2048
>> +encrypt_key = no
>> +distinguished_name = req_distinguished_name
>> +[ req_distinguished_name ]
>> +EOF
>> +
>> +my $d = $t->testdir();
>> +
>> +foreach my $name ('localhost') {
>> +	system('openssl req -x509 -new '
>> +		. "-config $d/openssl.conf -subj /CN=$name/ "
>> +		. "-out $d/$name.crt -keyout $d/$name.key "
>> +		. ">>$d/openssl.out 2>&1") == 0
>> +		or die "Can't create certificate for $name: $!\n";
>> +}
>> +
>> +$t->run();
>> +
>> +###############################################################################
>> +
>> +# any test can fail depending on which worker process served connection,
>> +# with a single worker process it is only the 2nd test that fails
>> +local $TODO = 'not yet' unless $t->has_version('1.23.2');
> 
> It might worth explaining why the test uses multiple worker 
> processes, and why the first test might fail.
> 

Makes sense, added a lengthy comment.

Pushed in http://hg.nginx.org/nginx-tests/rev/5817625792bd

>> +
>> +my $ses = get_ssl_session();
>> +my $key = get_ticket_key_name($ses);
>> +
>> +sleep 1;
>> +
>> +$ses = get_ssl_session($ses);
> 
> Any specific reasons to try to reuse sessions?  The result is 
> not checked anywhere (well, it might make sense to actually test 
> that sessions can be reused, but that's a different question).

Looks like a leftover from early testing, tnx.

While checking that sessions are properly restored may have sense,
I'd abstain from doing so as essentially it is a (fragile) testing
of SSL protocols.
Basically, if you continue to receive tickets protected with the
same key, then transitively it looks like such sessions are reusable,
because the ticket key is the default one.  But that's not always so,
it depends on when the session is started and time to rotate keys.
In edge cases, an attempt to reuse a just expired session results
in a full SSL handshake and a new session, but a new session ticket
is sent protected with the same going to expire default ticket key,
because keys rotation didn't happen yet due to a second difference
compared to when OpenSSL decides that the session has expired.  The
behaviour is specific to TLSv1.3, where ticket are always renewed.
Still, and this is an opposite edge case, such new session obtained
with a going to expire key is reusable and, if reused after its key
has expired and rotated, this will result in the ticket renewal
protected with a different, new key.

Long story short, key rotation doesn't necessary match to session
reuse.  Testing that ticket keys are rotated should be sufficient.

-- 
Sergey Kandaurov


More information about the nginx-devel mailing list