On Sat, Feb 13, 2021 at 11:58:04AM +0100, Jan Klemkow wrote:
> Hi,
> 
> A coworker of mine has made tests with LibreSSL [1] and found some
> regressions.  I took his test descriptions and created the following
> automated regression test.  In the repository he described his findings
> in detail.  I kept the numbers of the files and subtests in the target
> names for now.  So, its easier to match it with his files.
> 
> I don't know how to handle the result of "test-01-ssl".  Thats why its
> just a comment.  Someone may have an idea to handle this properly.
> 
> Any comments, wishes or OK's?

First of all thanks for the effort!

The perl script and probably also the Makefile should have a license.

Please add a check that tests whether the required perl modules are
installed (p5-IO-Socket-SSL and p5-Net-SSLeay) and otherwise prints
SKIPPED and their names, so I can install them if they're not present.
I never remember their exact capitalization and hyphenation...


Various comments inline, and a patch for openssl(1) at the end that may
simplify some things.

> [1]: https://github.com/noxxi/libressl-tests
> 
> Index: regress/lib/libssl/Makefile
> ===================================================================
> RCS file: /cvs/src/regress/lib/libssl/Makefile,v
> retrieving revision 1.42
> diff -u -p -r1.42 Makefile
> --- regress/lib/libssl/Makefile       14 Oct 2020 15:53:22 -0000      1.42
> +++ regress/lib/libssl/Makefile       12 Feb 2021 19:42:56 -0000
> @@ -16,6 +16,7 @@ SUBDIR += tlsext
>  SUBDIR += tlslegacy
>  SUBDIR += key_schedule
>  SUBDIR += unit
> +SUBDIR += validate

I'm not too keen on hooking up a test that fails. It breaks my workflow.
I use REGRESS_FAIL_EARLY in my environment to spot unexpected failures.

Could you add the currently failing tests to REGRESS_EXPECTED_FAILURES?

I also don't think it's a libssl regress test. It's either for
lib/libcrypto or usr.bin/openssl, probably the latter.

>  # Things that take a long time should go below here. 
>  SUBDIR += tlsfuzzer
> Index: regress/lib/libssl/validate/Makefile
> ===================================================================
> RCS file: regress/lib/libssl/validate/Makefile
> diff -N regress/lib/libssl/validate/Makefile
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ regress/lib/libssl/validate/Makefile      13 Feb 2021 10:50:30 -0000
> @@ -0,0 +1,104 @@
> +# Tests from: https://github.com/noxxi/libressl-tests
> +
> +PERL=perl

Please use consistent spacing.

PERL = perl

Could you add

OPENSSL ?= openssl

and use ${OPENSSL} instead of plain openssl throughout the Makefile?
This way we can compare with OpenSSL by doing 'make OPENSSL=eopenssl11'.

> +
> +REGRESS_TARGETS =    test-00-01-ssl
> +REGRESS_TARGETS +=   test-00-02-ssl
> +REGRESS_TARGETS +=   test-00-03-ssl
> +REGRESS_TARGETS +=   test-00-04-ssl
> +REGRESS_TARGETS +=   test-00-05-ssl
> +REGRESS_TARGETS +=   test-00-06-ssl
> +REGRESS_TARGETS +=   test-01-ssl
> +REGRESS_TARGETS +=   test-02-ssl
> +REGRESS_ROOT_TARGETS =       ${REGRESS_TARGETS}

Please drop this line. These tests do not require root.

> +REGRESS_CLEANUP =    cleanup-ssl
> +REGRESS_SETUP =              create-libressl-test-certs

I think this should be REGRESS_SETUP_ONCE. No need to regen the certs
for each and every test.

> +
> +create-libressl-test-certs: create-libressl-test-certs.pl
> +     ${PERL} ${.CURDIR}/$@.pl
> +
> +cleanup-ssl:
> +     pkill openssl || true
> +     rm *.pem *.key
> +
> +test-00-01-ssl:
> +     # unusual wildcard cert, no CA given to client
> +     # cleanup
> +     pkill openssl || true
> +     sleep 2

pkill + sleep 2 is a bit icky. It's not the first time I wanted to have
OpenSSL's -naccept option available for testing. See patch below.

> +     # start client

# start server

> +     ${KTRACE} openssl s_server -cert server-unusual-wildcard.pem \
> +         -key server-unusual-wildcard.pem -www & \

I'd suggest replacing '-www' with '-naccept 1' and...

> +         timeout=$$(($$(date +%s) + 5)); \
> +         while fstat -p $$! | ! grep -q 'tcp .* \*:4433$$'; \
> +             do test $$(date +%s) -lt $$timeout || exit 1; done
> +     # start client
> +     echo "data" | openssl s_client -verify_return_error -connect 
> 127.0.0.1:4433 \

... do 'echo "Q"' here.

Unless you want to use a random port (which may be more appropriate than
killing all openssl processes and assuming that 4433 is free), I would
just drop '-connect 127.0.0.1:4433'.

> +         | grep "Verify return code: 21"
> +
> +test-00-02-ssl:
> +     # unusual wildcard cert, CA given to client
> +     # cleanup
> +     pkill openssl || true
> +     sleep 2
> +     # start server
> +     ${KTRACE} openssl s_server -cert server-unusual-wildcard.pem \
> +         -key server-unusual-wildcard.pem -www & \
> +         timeout=$$(($$(date +%s) + 5)); \
> +         while fstat -p $$! | ! grep -q 'tcp .* \*:4433$$'; \
> +             do test $$(date +%s) -lt $$timeout || exit 1; done
> +     # start client
> +     echo "data" | openssl s_client -connect 127.0.0.1:4433 -CAfile caR.pem \
> +         | grep "Verify return code: 0"
> +
> +test-00-03-ssl:
> +     # common wildcard cert, no CA given to client
> +     # cleanup
> +     pkill openssl || true
> +     sleep 2
> +     # start server
> +     ${KTRACE} openssl s_server -cert server-common-wildcard.pem \
> +         -key server-common-wildcard.pem -www & \
> +         timeout=$$(($$(date +%s) + 5)); \
> +         while fstat -p $$! | ! grep -q 'tcp .* \*:4433$$'; \
> +             do test $$(date +%s) -lt $$timeout || exit 1; done
> +     # start client
> +     echo "data" | openssl s_client -connect 127.0.0.1:4433 \
> +         | grep "Verify return code: 21"
> +
> +test-00-04-ssl:
> +     # common wildcard cert, CA given to client
> +     # cleanup
> +     pkill openssl || true
> +     sleep 2
> +     # start server
> +     ${KTRACE} openssl s_server -cert server-unusual-wildcard.pem \
> +         -key server-unusual-wildcard.pem -www & \
> +         timeout=$$(($$(date +%s) + 5)); \
> +         while fstat -p $$! | ! grep -q 'tcp .* \*:4433$$'; \
> +             do test $$(date +%s) -lt $$timeout || exit 1; done
> +     # start client
> +     echo "data" | openssl s_client -connect 127.0.0.1:4433 -CAfile caR.pem \
> +         | grep "Verify return code: 21"
> +
> +test-00-05-ssl:
> +     # openssl verify, unusual wildcard cert
> +     openssl verify -CAfile caR.pem server-unusual-wildcard.pem \
> +         | grep "server-unusual-wildcard.pem: OK"
> +
> +test-00-06-ssl:
> +     # openssl verify, common wildcard cert
> +     openssl verify -CAfile caR.pem server-common-wildcard.pem \
> +         | grep "server-common-wildcard.pem: OK"
> +
> +test-01-ssl:
> +     # Not all chain certificates are sent in s_server
> +     # openssl s_server -cert server-subca.pem -CAfile subcaR.pem -www
> +     # XXX: don't know how to check the result

Run the server with:

openssl s_server -cert server-subca-chainS.pem -CAfile subcaR.pem

Prior to the fix (tls13_server.c -r1.62),

openssl s_client -CAfile caR.pem

would return

    Verify return code: 21 (unable to verify the first certificate)

after the fix it returns

    Verify return code: 0 (ok)


> +
> +test-02-ssl:
> +     # alternative chain not found
> +     openssl verify -verbose -trusted caR.pem -untrusted chainSX.pem 
> server-subca.pem \
> +         | grep "server-subca.pem: Ok"
> +
> +.include <bsd.regress.mk>
> Index: regress/lib/libssl/validate/create-libressl-test-certs.pl
> ===================================================================
> RCS file: regress/lib/libssl/validate/create-libressl-test-certs.pl
> diff -N regress/lib/libssl/validate/create-libressl-test-certs.pl
> --- /dev/null 1 Jan 1970 00:00:00 -0000
> +++ regress/lib/libssl/validate/create-libressl-test-certs.pl 12 Feb 2021 
> 16:34:20 -0000
> @@ -0,0 +1,107 @@
> +#!/usr/bin/perl
> +use strict;
> +use warnings;
> +use IO::Socket::SSL::Utils;
> +
> +# primitive CA - ROOT
> +my @ca = cert(
> +    CA => 1,
> +    subject => { CN => 'ROOT' }
> +);
> +out('caR.pem', pem(crt => $ca[0]));
> +out('caR.key', pem(key => $ca[1]));
> +
> +# server certificate where SAN contains in-label wildcards which are allowed 
> by
> +# RFC 6125

This was already discussed elsewhere. It's a MAY, not a MUST in the RFC,
so saying that it's allowed is not quite true. The change of behavior
was deliberate.

> +my @leafcert = cert(
> +    issuer => \@ca,
> +    purpose => 'server',
> +    subject => { CN => 'server.local' },
> +    subjectAltNames => [ 
> +     [ DNS => 'bar.server.local' ],
> +     [ DNS => 'www*.server.local'], 
> +     [ DNS => '*.www.server.local'], 
> +     [ DNS => 'foo.server.local' ],
> +     [ DNS => 'server.local' ],
> +    ]
> +);
> +out('server-unusual-wildcard.pem', pem(@leafcert));
> +
> +@leafcert = cert(
> +    issuer => \@ca,
> +    purpose => 'server',
> +    subject => { CN => 'server.local' },
> +    subjectAltNames => [ 
> +     [ DNS => 'bar.server.local' ],
> +     [ DNS => '*.www.server.local'], 
> +     [ DNS => 'foo.server.local' ],
> +     [ DNS => 'server.local' ],
> +    ]
> +);
> +out('server-common-wildcard.pem', pem(@leafcert));
> +
> +# alternative CA - OLD_ROOT
> +my @caO = cert(
> +    CA => 1,
> +    subject => { CN => 'OLD_ROOT' }
> +);
> +out('caO.pem', pem(crt => $caO[0]));
> +out('caO.key', pem(key => $caO[1]));
> +
> +# alternative ROOT CA, signed by OLD_ROOT, same key as other ROOT CA
> +my @caX = cert(
> +    issuer => \@caO,
> +    CA => 1,
> +    subject => { CN => 'ROOT' },
> +    key => $ca[1],
> +);
> +out('caX.pem', pem(crt => $caX[0]));
> +out('caX.key', pem(key => $caX[1]));
> +
> +# subCA below ROOT
> +my @subcaR = cert(
> +    issuer => \@ca,
> +    CA => 1,
> +    subject => { CN => 'SubCA.of.ROOT' }
> +);
> +out('subcaR.pem', pem(crt => $subcaR[0]));
> +out('subcaR.key', pem(key => $subcaR[1]));
> +out('chainSX.pem', pem($subcaR[0]), pem($caX[0]));
> +
> +@leafcert = cert(
> +    issuer => \@subcaR,
> +    purpose => 'server',
> +    subject => { CN => 'server.subca.local' },
> +    subjectAltNames => [ 
> +     [ DNS => 'server.subca.local' ],
> +    ]
> +);
> +out('server-subca.pem', pem(@leafcert));
> +out('server-subca-chainSX.pem', pem(@leafcert, $subcaR[0], $caX[0]));
> +out('server-subca-chainS.pem', pem(@leafcert, $subcaR[0]));
> +
> +
> +sub cert { CERT_create(not_after => 10*365*86400+time(), @_) }
> +sub pem {
> +    my @default = qw(crt key);
> +    my %m = (key => \&PEM_key2string, crt => \&PEM_cert2string);
> +    my $result = '';
> +    while (my $f = shift(@_)) {
> +     my $v;
> +     if ($f =~m{^(key|crt)$}) {
> +         $v = shift(@_);
> +     } else {
> +         $v = $f;
> +         $f = shift(@default) || 'crt';
> +     }
> +     $f = $m{$f} || die "wrong key $f";
> +     $result .= $f->($v);
> +    }
> +    return $result;
> +}
> +    
> +sub out {
> +    my $file = shift;
> +    open(my $fh,'>',"$file") or die "failed to create $file: $!";
> +    print $fh @_
> +}
> 


Index: openssl.1
===================================================================
RCS file: /cvs/src/usr.bin/openssl/openssl.1,v
retrieving revision 1.128
diff -u -p -r1.128 openssl.1
--- openssl.1   30 Dec 2020 08:26:44 -0000      1.128
+++ openssl.1   13 Feb 2021 14:41:46 -0000
@@ -4599,6 +4599,7 @@ will be used.
 .Op Fl keymatexportlen Ar len
 .Op Fl msg
 .Op Fl mtu Ar mtu
+.Op Fl naccept Ar n
 .Op Fl named_curve Ar arg
 .Op Fl nbio
 .Op Fl nbio_test
@@ -4795,6 +4796,10 @@ Export len bytes of keying material (def
 Show all protocol messages with hex dump.
 .It Fl mtu Ar mtu
 Set the link layer MTU.
+.It Fl naccept Ar n
+Exit after
+.Ar n
+connections.
 .It Fl named_curve Ar arg
 Specify the elliptic curve name to use for ephemeral ECDH keys.
 This option is deprecated; use
Index: s_apps.h
===================================================================
RCS file: /cvs/src/usr.bin/openssl/s_apps.h,v
retrieving revision 1.5
diff -u -p -r1.5 s_apps.h
--- s_apps.h    25 Apr 2018 07:12:33 -0000      1.5
+++ s_apps.h    13 Feb 2021 13:54:02 -0000
@@ -120,7 +120,7 @@ extern int verify_return_error;
 
 int do_server(int port, int type, int *ret,
     int (*cb)(char *hostname, int s, unsigned char *context),
-    unsigned char *context);
+    unsigned char *context, int naccept);
 #ifdef HEADER_X509_H
 int verify_callback(int ok, X509_STORE_CTX *ctx);
 #endif
Index: s_server.c
===================================================================
RCS file: /cvs/src/usr.bin/openssl/s_server.c,v
retrieving revision 1.44
diff -u -p -r1.44 s_server.c
--- s_server.c  2 Oct 2020 15:43:48 -0000       1.44
+++ s_server.c  13 Feb 2021 14:37:45 -0000
@@ -267,6 +267,7 @@ static struct {
        uint16_t min_version;
        const SSL_METHOD *meth;
        int msg;
+       int naccept;
        char *named_curve;
        int nbio;
        int nbio_test;
@@ -330,6 +331,19 @@ s_server_opt_mtu(char *arg)
 }
 
 static int
+s_server_opt_naccept(char *arg)
+{
+       s_server_config.naccept = strtonum(arg, 1, INT_MAX,
+           &s_server_config.errstr);
+       if (s_server_config.errstr != NULL) {
+               BIO_printf(bio_err, "invalid argument %s: %s\n",
+                   arg, s_server_config.errstr);
+               return (1);
+       }
+       return (0);
+}
+
+static int
 s_server_protocol_version_dtls1(void)
 {
        s_server_config.meth = DTLS_server_method();
@@ -699,6 +713,13 @@ static const struct option s_server_opti
        },
 #endif
        {
+               .name = "naccept",
+               .argname = "n",
+               .desc = "Exit after n connections",
+               .type = OPTION_ARG_FUNC,
+               .opt.argfunc = s_server_opt_naccept,
+       },
+       {
                .name = "named_curve",
                .argname = "arg",
                .type = OPTION_ARG,
@@ -1049,6 +1070,7 @@ s_server_main(int argc, char *argv[])
        s_server_config.dcert_format = FORMAT_PEM;
        s_server_config.dkey_format = FORMAT_PEM;
        s_server_config.key_format = FORMAT_PEM;
+       s_server_config.naccept = -1;
        s_server_config.server_verify = SSL_VERIFY_NONE;
        s_server_config.socket_type = SOCK_STREAM;
        s_server_config.tlscstatp.timeout = -1;
@@ -1435,10 +1457,12 @@ s_server_main(int argc, char *argv[])
        (void) BIO_flush(bio_s_out);
        if (s_server_config.www)
                do_server(s_server_config.port, s_server_config.socket_type,
-                   &accept_socket, www_body, s_server_config.context);
+                   &accept_socket, www_body, s_server_config.context,
+                   s_server_config.naccept);
        else
                do_server(s_server_config.port, s_server_config.socket_type,
-                   &accept_socket, sv_body, s_server_config.context);
+                   &accept_socket, sv_body, s_server_config.context,
+                   s_server_config.naccept);
        print_stats(bio_s_out, ctx);
        ret = 0;
  end:
Index: s_socket.c
===================================================================
RCS file: /cvs/src/usr.bin/openssl/s_socket.c,v
retrieving revision 1.11
diff -u -p -r1.11 s_socket.c
--- s_socket.c  28 Jun 2019 13:35:02 -0000      1.11
+++ s_socket.c  13 Feb 2021 13:52:43 -0000
@@ -132,7 +132,7 @@ init_client(int *sock, char *host, char 
 int
 do_server(int port, int type, int *ret,
     int (*cb) (char *hostname, int s, unsigned char *context),
-    unsigned char *context)
+    unsigned char *context, int naccept)
 {
        int sock;
        char *name = NULL;
@@ -161,7 +161,9 @@ do_server(int port, int type, int *ret,
                        shutdown(sock, SHUT_RDWR);
                        close(sock);
                }
-               if (i < 0) {
+               if (naccept != -1)
+                       naccept--;
+               if (i < 0 || naccept == 0) {
                        shutdown(accept_socket, SHUT_RDWR);
                        close(accept_socket);
                        return (i);

Reply via email to