From b88042ee7a2d2fc6e740c79270b86ab3fe455897 Mon Sep 17 00:00:00 2001 From: bluhm <> Date: Fri, 9 Nov 2018 06:30:41 +0000 Subject: The cert subdir is testing all combinations of certificate validation. Having the three libraries, client and server certificates, missing or invalid CA or certificates, and enforcing peer certificate results in 1944 new test cases. --- src/regress/lib/libssl/interop/Makefile | 4 +- src/regress/lib/libssl/interop/Makefile.inc | 43 +++++++------- src/regress/lib/libssl/interop/README | 5 ++ src/regress/lib/libssl/interop/cert/Makefile | 70 +++++++++++++++++++++++ src/regress/lib/libssl/interop/client.c | 58 ++++++++++++++++--- src/regress/lib/libssl/interop/libressl/Makefile | 9 ++- src/regress/lib/libssl/interop/openssl/Makefile | 9 ++- src/regress/lib/libssl/interop/openssl11/Makefile | 9 ++- src/regress/lib/libssl/interop/server.c | 70 ++++++++++++++++++----- src/regress/lib/libssl/interop/util.c | 12 +++- src/regress/lib/libssl/interop/util.h | 3 +- 11 files changed, 244 insertions(+), 48 deletions(-) create mode 100644 src/regress/lib/libssl/interop/cert/Makefile diff --git a/src/regress/lib/libssl/interop/Makefile b/src/regress/lib/libssl/interop/Makefile index d89376aaf6..0226cae4ab 100644 --- a/src/regress/lib/libssl/interop/Makefile +++ b/src/regress/lib/libssl/interop/Makefile @@ -1,5 +1,5 @@ -# $OpenBSD: Makefile,v 1.2 2018/11/07 19:09:01 bluhm Exp $ +# $OpenBSD: Makefile,v 1.3 2018/11/09 06:30:41 bluhm Exp $ -SUBDIR = libressl openssl openssl11 +SUBDIR = libressl openssl openssl11 cert .include diff --git a/src/regress/lib/libssl/interop/Makefile.inc b/src/regress/lib/libssl/interop/Makefile.inc index 1a1ef30ca6..9daae79e57 100644 --- a/src/regress/lib/libssl/interop/Makefile.inc +++ b/src/regress/lib/libssl/interop/Makefile.inc @@ -1,17 +1,15 @@ -# $OpenBSD: Makefile.inc,v 1.3 2018/11/07 20:46:28 bluhm Exp $ +# $OpenBSD: Makefile.inc,v 1.4 2018/11/09 06:30:41 bluhm Exp $ .PATH: ${.CURDIR}/.. SRCS_client = client.c util.c SRCS_server = server.c util.c WARNINGS = yes -REGRESS_TARGETS = # check that program is linked with correct libraries .for p in ${PROGS} CLEANFILES += ldd-$p.out -REGRESS_TARGETS += run-ldd-$p ldd-$p.out: $p LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ldd $p >$@ .endfor @@ -19,12 +17,13 @@ ldd-$p.out: $p # run netcat server and connect with test client CLEANFILES += nc-client.out netcat-l.out netcat-l.fstat -REGRESS_TARGETS += run-client nc-client.out run-client: client 127.0.0.1.crt @echo '\n======== $@ ========' echo "greeting" | nc -l -c -C 127.0.0.1.crt -K 127.0.0.1.key \ 127.0.0.1 0 >netcat-l.out & \ - sleep 1; fstat -p $$! >netcat-l.fstat + for i in `jot 1000`; do fstat -p $$! >netcat-l.fstat; \ + grep -q ' stream tcp .*:[1-9][0-9]*$$' netcat-l.fstat && exit 0; \ + done; exit 1 LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ./client \ `sed -n 's/.* stream tcp .*:/127.0.0.1 /p' netcat-l.fstat` \ >nc-client.out @@ -38,12 +37,11 @@ nc-client.out run-client: client 127.0.0.1.crt # run test server and connect with netcat client CLEANFILES += nc-server.out netcat.out -REGRESS_TARGETS += run-server nc-server.out run-server: server 127.0.0.1.crt @echo '\n======== $@ ========' LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ./server 127.0.0.1 0 \ >nc-server.out - echo "hello" | nc -c -T noverify \ + echo "hello" | nc -c -R 127.0.0.1.crt \ `sed -n 's/listen sock: //p' nc-server.out` \ >netcat.out # check that the server child run successfully to the end @@ -56,7 +54,6 @@ nc-server.out run-server: server 127.0.0.1.crt # run test server and with test client, self test the ssl library CLEANFILES += self-client.out self-server.out -REGRESS_TARGETS += run-self self-client.out self-server.out run-self: client server 127.0.0.1.crt @echo '\n======== $@ ========' LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ./server 127.0.0.1 0 \ @@ -73,23 +70,27 @@ self-client.out self-server.out run-self: client server 127.0.0.1.crt # server must have read client hello grep -q '^<<< hello$$' self-server.out -.for o in nc-client nc-server self-client self-server - -# check that client and server have used correct runtime library - -REGRESS_TARGETS += run-version-$o - -# check that client and server have used correct TLS protocol - -REGRESS_TARGETS += run-protocol-$o - -.endfor - # create certificates for TLS -CLEANFILES += 127.0.0.1.crt 127.0.0.1.key +CLEANFILES += 127.0.0.1.{crt,key} \ + ca.{crt,key,srl} fake-ca.{crt,key} \ + {client,server}.{req,crt,key} 127.0.0.1.crt: openssl req -batch -new \ -subj /L=OpenBSD/O=tls-regress/OU=server/CN=127.0.0.1/ \ -nodes -newkey rsa -keyout 127.0.0.1.key -x509 -out $@ + +ca.crt fake-ca.crt: + openssl req -batch -new \ + -subj /L=OpenBSD/O=tls-regress/OU=ca/CN=root/ \ + -nodes -newkey rsa -keyout ${@:R}.key -x509 -out $@ + +client.req server.req: + openssl req -batch -new \ + -subj /L=OpenBSD/O=tls-regress/OU=${@:R}/CN=localhost/ \ + -nodes -newkey rsa -keyout ${@:R}.key -out $@ + +client.crt server.crt: ca.crt ${@:R}.req + openssl x509 -CAcreateserial -CAkey ca.key -CA ca.crt \ + -req -in ${@:R}.req -out $@ diff --git a/src/regress/lib/libssl/interop/README b/src/regress/lib/libssl/interop/README index 1bd418c9cc..b53b47b878 100644 --- a/src/regress/lib/libssl/interop/README +++ b/src/regress/lib/libssl/interop/README @@ -12,3 +12,8 @@ that the highest available TLS version is selected. LibreSSL TLS Currently OpenSSL 1.0.2p and OpenSSL 1.1.1 from ports are used. As soon as LibreSSL supports TLS 1.3, it should be used automatically when netcat is communicating with OpenSSL 1.1. + +The cert subdir is testing all combinations of certificate validation. +Having the three libraries, client and server certificates, missing +or invalid CA or certificates, and enforcing peer certificate results +in 1944 test cases. diff --git a/src/regress/lib/libssl/interop/cert/Makefile b/src/regress/lib/libssl/interop/cert/Makefile new file mode 100644 index 0000000000..dabc0441f0 --- /dev/null +++ b/src/regress/lib/libssl/interop/cert/Makefile @@ -0,0 +1,70 @@ +# $OpenBSD: Makefile,v 1.1 2018/11/09 06:30:41 bluhm Exp $ + +.if ! exists(/usr/local/bin/eopenssl) || ! exists(/usr/local/bin/eopenssl11) +regress: + # install openssl-1.0.2p and openssl-1.1.1 from ports + @echo SKIPPED +.endif + +CLEANFILES += client.out server.out + +.for cca in noca ca fakeca +.for sca in noca ca fakeca +.for ccert in nocert cert +.for scert in nocert cert +.for cv in noverify verify +.for sv in noverify verify certverify + +# remember when certificate verification should fail +.if (("${cv}" == verify && "${cca}" == ca && "${scert}" == cert) || \ + "${cv}" == noverify) && \ + (("${sv}" == verify && "${ccert}" == nocert) || \ + ("${sv}" == verify && "${sca}" == ca && "${ccert}" == cert) || \ + ("${sv}" == certverify && "${sca}" == ca && "${ccert}" == cert) || \ + "${sv}" == noverify) +FAIL_${cca}_${sca}_${ccert}_${scert}_${cv}_${sv} = +.else +FAIL_${cca}_${sca}_${ccert}_${scert}_${cv}_${sv} = ! +.endif + +.for clib in libressl openssl openssl11 +.for slib in libressl openssl openssl11 + +REGRESS_TARGETS += \ +run-client-${clib}-${cca}-${ccert}-${cv}-server-${slib}-${sca}-${scert}-${sv} + +run-client-${clib}-${cca}-${ccert}-${cv}-server-${slib}-${sca}-${scert}-${sv}:\ + 127.0.0.1.crt ca.crt fake-ca.crt client.crt server.crt \ + ../${clib}/client ../${slib}/server + @echo '\n======== $@ ========' + LD_LIBRARY_PATH=/usr/local/lib/e${slib} \ + ../${slib}/server >server.out \ + ${sca:S/^noca//:S/^fakeca/-C fake-ca.crt/:S/^ca/-C ca.crt/} \ + ${scert:S/^nocert//:S/^cert/-c server.crt -k server.key/} \ + ${sv:S/^noverify//:S/^verify/-v/:S/^certverify/-vv/} \ + 127.0.0.1 0 + ${FAIL_${cca}_${sca}_${ccert}_${scert}_${cv}_${sv}} \ + LD_LIBRARY_PATH=/usr/local/lib/e${clib} \ + ../${clib}/client >client.out \ + ${cca:S/^noca//:S/^fakeca/-C fake-ca.crt/:S/^ca/-C ca.crt/} \ + ${ccert:S/^nocert//:S/^cert/-c server.crt -k server.key/} \ + ${cv:S/^noverify//:S/^verify/-v/} \ + `sed -n 's/listen sock: //p' server.out` +.if empty(${FAIL_${cca}_${sca}_${ccert}_${scert}_${cv}_${sv}}) + grep '^success$$' server.out + grep '^success$$' client.out +.elif ! ("${sv}" == certverify && "${ccert}" == nocert) || \ + ("${cv}" == verify && "${scert}" != cert) + grep '^verify: fail' client.out server.out +.endif + +.endfor +.endfor +.endfor +.endfor +.endfor +.endfor +.endfor +.endfor + +.include diff --git a/src/regress/lib/libssl/interop/client.c b/src/regress/lib/libssl/interop/client.c index 60fb718fdb..c312d7ae8a 100644 --- a/src/regress/lib/libssl/interop/client.c +++ b/src/regress/lib/libssl/interop/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.3 2018/11/07 19:09:01 bluhm Exp $ */ +/* $OpenBSD: client.c,v 1.4 2018/11/09 06:30:41 bluhm Exp $ */ /* * Copyright (c) 2018 Alexander Bluhm * @@ -34,7 +34,8 @@ void __dead usage(void); void __dead usage(void) { - fprintf(stderr, "usage: client host port"); + fprintf(stderr, + "usage: client [-c] [-C CA] [-c crt -k key] host port"); exit(2); } @@ -46,19 +47,42 @@ main(int argc, char *argv[]) SSL *ssl; BIO *bio; SSL_SESSION *session; - int error; - char buf[256]; + int error, verify = 0; + char buf[256], ch; + char *ca = NULL, *crt = NULL, *key = NULL; char *host_port, *host, *port; - if (argc == 3) { - host = argv[1]; - port = argv[2]; + while ((ch = getopt(argc, argv, "C:c:k:v")) != -1) { + switch (ch) { + case 'C': + ca = optarg; + break; + case 'c': + crt = optarg; + break; + case 'k': + key = optarg; + break; + case 'v': + verify = 1; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc == 2) { + host = argv[0]; + port = argv[1]; } else { usage(); } if (asprintf(&host_port, strchr(host, ':') ? "[%s]:%s" : "%s:%s", host, port) == -1) err(1, "asprintf host port"); + if ((crt == NULL && key != NULL) || (crt != NULL && key == NULL)) + errx(1, "certificate and private key must be used together"); SSL_library_init(); SSL_load_error_strings(); @@ -78,6 +102,26 @@ main(int argc, char *argv[]) if (ctx == NULL) err_ssl(1, "SSL_CTX_new"); + /* load client certificate */ + if (crt != NULL) { + if (SSL_CTX_use_certificate_file(ctx, crt, + SSL_FILETYPE_PEM) <= 0) + err_ssl(1, "SSL_CTX_use_certificate_file"); + if (SSL_CTX_use_PrivateKey_file(ctx, key, + SSL_FILETYPE_PEM) <= 0) + err_ssl(1, "SSL_CTX_use_PrivateKey_file"); + if (SSL_CTX_check_private_key(ctx) <= 0) + err_ssl(1, "SSL_CTX_check_private_key"); + } + + /* verify server certificate */ + if (ca != NULL) { + if (SSL_CTX_load_verify_locations(ctx, ca, NULL) <= 0) + err_ssl(1, "SSL_CTX_load_verify_locations"); + } + SSL_CTX_set_verify(ctx, verify ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, + verify_callback); + /* setup ssl and bio for socket operations */ ssl = SSL_new(ctx); if (ssl == NULL) diff --git a/src/regress/lib/libssl/interop/libressl/Makefile b/src/regress/lib/libssl/interop/libressl/Makefile index 19557ffbc1..6923e12469 100644 --- a/src/regress/lib/libssl/interop/libressl/Makefile +++ b/src/regress/lib/libssl/interop/libressl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.3 2018/11/07 20:46:28 bluhm Exp $ +# $OpenBSD: Makefile,v 1.4 2018/11/09 06:30:41 bluhm Exp $ PROGS = client server CPPFLAGS = @@ -6,6 +6,13 @@ LDFLAGS = LDADD = -lssl -lcrypto DPADD = ${LIBSSL} ${LIBCRYPTO} LD_LIBRARY_PATH = +REGRESS_TARGETS = run-self +.for p in ${PROGS} +REGRESS_TARGETS += run-ldd-$p run-$p +.for x in nc self +REGRESS_TARGETS += run-version-$x-$p run-protocol-$x-$p +.endfor +.endfor run-protocol-self-client run-protocol-self-server \ run-protocol-nc-client run-protocol-nc-server: diff --git a/src/regress/lib/libssl/interop/openssl/Makefile b/src/regress/lib/libssl/interop/openssl/Makefile index ad0c7288ca..5c51c029ce 100644 --- a/src/regress/lib/libssl/interop/openssl/Makefile +++ b/src/regress/lib/libssl/interop/openssl/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.3 2018/11/07 20:46:28 bluhm Exp $ +# $OpenBSD: Makefile,v 1.4 2018/11/09 06:30:41 bluhm Exp $ .if ! exists(/usr/local/bin/eopenssl) regress: @@ -13,6 +13,13 @@ LDADD = -lssl -lcrypto DPADD = /usr/local/lib/eopenssl/libssl.a \ /usr/local/lib/eopenssl/libcrypto.a LD_LIBRARY_PATH = /usr/local/lib/eopenssl +REGRESS_TARGETS = run-self +.for p in ${PROGS} +REGRESS_TARGETS += run-ldd-$p run-$p +.for x in nc self +REGRESS_TARGETS += run-version-$x-$p run-protocol-$x-$p +.endfor +.endfor .for p in ${PROGS} run-ldd-$p: ldd-$p.out diff --git a/src/regress/lib/libssl/interop/openssl11/Makefile b/src/regress/lib/libssl/interop/openssl11/Makefile index e7257a3976..ec6f6db7ec 100644 --- a/src/regress/lib/libssl/interop/openssl11/Makefile +++ b/src/regress/lib/libssl/interop/openssl11/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.2 2018/11/07 20:46:28 bluhm Exp $ +# $OpenBSD: Makefile,v 1.3 2018/11/09 06:30:41 bluhm Exp $ .if ! exists(/usr/local/bin/eopenssl11) regress: @@ -13,6 +13,13 @@ LDADD = -lssl -lcrypto DPADD = /usr/local/lib/eopenssl11/libssl.a \ /usr/local/lib/eopenssl11/libcrypto.a LD_LIBRARY_PATH = /usr/local/lib/eopenssl11 +REGRESS_TARGETS = run-self +.for p in ${PROGS} +REGRESS_TARGETS += run-ldd-$p run-$p +.for x in nc self +REGRESS_TARGETS += run-version-$x-$p run-protocol-$x-$p +.endfor +.endfor run-protocol-nc-client run-protocol-nc-server: @echo '\n======== $@ ========' diff --git a/src/regress/lib/libssl/interop/server.c b/src/regress/lib/libssl/interop/server.c index 0aece87583..6c0c720dfe 100644 --- a/src/regress/lib/libssl/interop/server.c +++ b/src/regress/lib/libssl/interop/server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.3 2018/11/07 19:09:01 bluhm Exp $ */ +/* $OpenBSD: server.c,v 1.4 2018/11/09 06:30:41 bluhm Exp $ */ /* * Copyright (c) 2018 Alexander Bluhm * @@ -34,7 +34,8 @@ void __dead usage(void); void __dead usage(void) { - fprintf(stderr, "usage: server [host port]"); + fprintf(stderr, + "usage: server [-vv] [-C CA] [-c crt -k key] [host port]"); exit(2); } @@ -46,22 +47,46 @@ main(int argc, char *argv[]) SSL *ssl; BIO *bio; SSL_SESSION *session; - int error; - char buf[256]; - char *crt, *key, *host_port, *host = "127.0.0.1", *port = "0"; - - if (argc == 3) { - host = argv[1]; - port = argv[2]; - } else if (argc != 1) { + int error, verify = 0; + char buf[256], ch; + char *ca = NULL, *crt = NULL, *key = NULL; + char *host_port, *host = "127.0.0.1", *port = "0"; + + while ((ch = getopt(argc, argv, "C:c:k:v")) != -1) { + switch (ch) { + case 'C': + ca = optarg; + break; + case 'c': + crt = optarg; + break; + case 'k': + key = optarg; + break; + case 'v': + /* use twice to force client cert */ + verify++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc == 2) { + host = argv[0]; + port = argv[1]; + } else if (argc != 0) { usage(); } if (asprintf(&host_port, strchr(host, ':') ? "[%s]:%s" : "%s:%s", host, port) == -1) err(1, "asprintf host port"); - if (asprintf(&crt, "%s.crt", host) == -1) + if ((crt == NULL && key != NULL) || (crt != NULL && key == NULL)) + errx(1, "certificate and private key must be used together"); + if (crt == NULL && asprintf(&crt, "%s.crt", host) == -1) err(1, "asprintf crt"); - if (asprintf(&key, "%s.key", host) == -1) + if (key == NULL && asprintf(&key, "%s.key", host) == -1) err(1, "asprintf key"); SSL_library_init(); @@ -94,6 +119,23 @@ main(int argc, char *argv[]) if (SSL_CTX_check_private_key(ctx) <= 0) err_ssl(1, "SSL_CTX_check_private_key"); + /* request client certificate and verify it */ + if (ca != NULL) { + STACK_OF(X509_NAME) *x509stack; + + x509stack = SSL_load_client_CA_file(ca); + if (x509stack == NULL) + err_ssl(1, "SSL_load_client_CA_file"); + SSL_CTX_set_client_CA_list(ctx, x509stack); + if (SSL_CTX_load_verify_locations(ctx, ca, NULL) <= 0) + err_ssl(1, "SSL_CTX_load_verify_locations"); + } + SSL_CTX_set_verify(ctx, + verify == 0 ? SSL_VERIFY_NONE : + verify == 1 ? SSL_VERIFY_PEER : + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, + verify_callback); + /* setup ssl and bio for socket operations */ ssl = SSL_new(ctx); if (ssl == NULL) @@ -109,9 +151,11 @@ main(int argc, char *argv[]) printf("listen "); print_sockname(bio); - /* fork to background and accept */ + /* fork to background, set timeout, and accept */ if (daemon(1, 1) == -1) err(1, "daemon"); + if ((int)alarm(60) == -1) + err(1, "alarm"); if (BIO_do_accept(bio) <= 0) err_ssl(1, "BIO_do_accept wait"); bio = BIO_pop(bio); diff --git a/src/regress/lib/libssl/interop/util.c b/src/regress/lib/libssl/interop/util.c index b012d73193..5190e81828 100644 --- a/src/regress/lib/libssl/interop/util.c +++ b/src/regress/lib/libssl/interop/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.2 2018/11/07 06:29:26 bluhm Exp $ */ +/* $OpenBSD: util.c,v 1.3 2018/11/09 06:30:41 bluhm Exp $ */ /* * Copyright (c) 2018 Alexander Bluhm * @@ -133,3 +133,13 @@ err_ssl(int eval, const char *fmt, ...) verrx(eval, fmt, ap); va_end(ap); } + +int +verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) +{ + printf("verify: %s\n", preverify_ok ? "pass" : "fail"); + if (fflush(stdout) != 0) + err(1, "fflush stdout"); + + return preverify_ok; +} diff --git a/src/regress/lib/libssl/interop/util.h b/src/regress/lib/libssl/interop/util.h index 78f7bb63b6..7414a037d7 100644 --- a/src/regress/lib/libssl/interop/util.h +++ b/src/regress/lib/libssl/interop/util.h @@ -1,4 +1,4 @@ -/* $OpenBSD: util.h,v 1.2 2018/11/07 06:29:26 bluhm Exp $ */ +/* $OpenBSD: util.h,v 1.3 2018/11/09 06:30:41 bluhm Exp $ */ /* * Copyright (c) 2018 Alexander Bluhm * @@ -20,3 +20,4 @@ void print_ciphers(STACK_OF(SSL_CIPHER) *); void print_sockname(BIO *); void print_peername(BIO *); void err_ssl(int, const char *, ...); +int verify_callback(int, X509_STORE_CTX *); -- cgit v1.2.3-55-g6feb