From 8d90809bb33041e7fc7b10bc81d57f61e20daec2 Mon Sep 17 00:00:00 2001 From: bluhm <> Date: Thu, 21 Feb 2019 23:06:33 +0000 Subject: Test that all supported TLS ciphers actually work. Establish connections between client and server implemented with LibreSSL or OpenSSL with a fixed cipher on each side. Check the used cipher in the session print out. --- src/regress/lib/libssl/interop/LICENSE | 2 +- src/regress/lib/libssl/interop/Makefile | 3 +- src/regress/lib/libssl/interop/Makefile.inc | 36 ++++- src/regress/lib/libssl/interop/README | 4 +- src/regress/lib/libssl/interop/cert/Makefile | 8 +- src/regress/lib/libssl/interop/cipher/Makefile | 180 +++++++++++++++++++++++++ src/regress/lib/libssl/interop/client.c | 39 ++++-- src/regress/lib/libssl/interop/server.c | 62 +++++++-- 8 files changed, 308 insertions(+), 26 deletions(-) create mode 100644 src/regress/lib/libssl/interop/cipher/Makefile (limited to 'src') diff --git a/src/regress/lib/libssl/interop/LICENSE b/src/regress/lib/libssl/interop/LICENSE index 8695620495..838e7f45cc 100644 --- a/src/regress/lib/libssl/interop/LICENSE +++ b/src/regress/lib/libssl/interop/LICENSE @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Alexander Bluhm + * Copyright (c) 2018-2019 Alexander Bluhm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/src/regress/lib/libssl/interop/Makefile b/src/regress/lib/libssl/interop/Makefile index dcde044d97..36b233c189 100644 --- a/src/regress/lib/libssl/interop/Makefile +++ b/src/regress/lib/libssl/interop/Makefile @@ -1,9 +1,10 @@ -# $OpenBSD: Makefile,v 1.5 2018/11/11 00:15:04 bluhm Exp $ +# $OpenBSD: Makefile,v 1.6 2019/02/21 23:06:33 bluhm Exp $ SUBDIR = libressl openssl openssl11 # the above binaries must have been built before we can continue SUBDIR += netcat SUBDIR += session +SUBDIR += cipher SUBDIR += cert .include diff --git a/src/regress/lib/libssl/interop/Makefile.inc b/src/regress/lib/libssl/interop/Makefile.inc index 7dadc3607b..dfe1424949 100644 --- a/src/regress/lib/libssl/interop/Makefile.inc +++ b/src/regress/lib/libssl/interop/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.5 2018/11/11 00:15:04 bluhm Exp $ +# $OpenBSD: Makefile.inc,v 1.6 2019/02/21 23:06:33 bluhm Exp $ .PATH: ${.CURDIR}/.. @@ -37,7 +37,9 @@ run-self-client-server: client server 127.0.0.1.crt CLEANFILES += 127.0.0.1.{crt,key} \ ca.{crt,key,srl} fake-ca.{crt,key} \ - {client,server}.{req,crt,key} + {client,server}.{req,crt,key} \ + {dsa,ec,gost,rsa}.{key,req,crt} \ + dh.param 127.0.0.1.crt: openssl req -batch -new \ @@ -57,3 +59,33 @@ client.req server.req: client.crt server.crt: ca.crt ${@:R}.req openssl x509 -CAcreateserial -CAkey ca.key -CA ca.crt \ -req -in ${@:R}.req -out $@ + +dh.param: + openssl dhparam -out $@ 1024 + +dsa.key: + openssl dsaparam -genkey -out $@ 2048 + +ec.key: + openssl ecparam -genkey -name secp256r1 -out $@ + +gost.key: + openssl genpkey -algorithm gost2001 \ + -pkeyopt paramset:A -pkeyopt dgst:md_gost94 -out $@ + +rsa.key: + openssl genrsa -out $@ 2048 + +dsa.req ec.req rsa.req: ${@:R}.key + openssl req -batch -new \ + -subj /L=OpenBSD/O=tls-regress/OU=${@:R}/CN=localhost/ \ + -nodes -key ${@:R}.key -out $@ + +gost.req: ${@:R}.key + openssl req -batch -new -md_gost94 \ + -subj /L=OpenBSD/O=tls-regress/OU=${@:R}/CN=localhost/ \ + -nodes -key ${@:R}.key -out $@ + +dsa.crt ec.crt gost.crt rsa.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 42d87acfdb..54910e554d 100644 --- a/src/regress/lib/libssl/interop/README +++ b/src/regress/lib/libssl/interop/README @@ -17,4 +17,6 @@ libtls. Test TLS session reuse multiple times with different library combinations. 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. +enforcing peer certificate results in 1944 test cases. The cipher +test establishes connections between implementations for each +supported cipher. diff --git a/src/regress/lib/libssl/interop/cert/Makefile b/src/regress/lib/libssl/interop/cert/Makefile index 3e7a07cdfe..11bc4aa2ab 100644 --- a/src/regress/lib/libssl/interop/cert/Makefile +++ b/src/regress/lib/libssl/interop/cert/Makefile @@ -1,4 +1,10 @@ -# $OpenBSD: Makefile,v 1.3 2018/11/11 07:39:34 bluhm Exp $ +# $OpenBSD: Makefile,v 1.4 2019/02/21 23:06:33 bluhm Exp $ + +# Connect a client to a server. Both can be current libressl, or +# openssl 1.0.2, or openssl 1.1. Create client and server certificates +# that are signed by a CA and not signed by a fake CA. Try all +# combinations with, without, and with wrong CA for client and server +# and check the result of certificate verification. LIBRARIES = libressl .if exists(/usr/local/bin/eopenssl) diff --git a/src/regress/lib/libssl/interop/cipher/Makefile b/src/regress/lib/libssl/interop/cipher/Makefile new file mode 100644 index 0000000000..5593ab233f --- /dev/null +++ b/src/regress/lib/libssl/interop/cipher/Makefile @@ -0,0 +1,180 @@ +# $OpenBSD: Makefile,v 1.1 2019/02/21 23:06:33 bluhm Exp $ + +# Connect a client to a server. Both can be current libressl, or +# openssl 1.0.2, or openssl 1.1. Create lists of supported ciphers +# and pin client and server to one of the ciphers. Use server +# certificate with compatible type. Check that client and server +# have used correct cipher by grepping in their session print out. + +check-cipher-GOST2001-GOST89-GOST89-client-libressl-server-libressl: + # cipher GOST2012256-GOST89-GOST89 is used in out file + # TODO: figure out why it is not GOST2001 + @echo DISABLED + +check-cipher-ADH-AES128-GCM-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ADH-AES128-SHA-client-openssl11-server-openssl11 \ +check-cipher-ADH-AES128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ADH-AES256-GCM-SHA384-client-openssl11-server-openssl11 \ +check-cipher-ADH-AES256-SHA-client-openssl11-server-openssl11 \ +check-cipher-ADH-AES256-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ADH-CAMELLIA128-SHA-client-openssl11-server-openssl11 \ +check-cipher-ADH-CAMELLIA128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ADH-CAMELLIA256-SHA-client-openssl11-server-openssl11 \ +check-cipher-ADH-CAMELLIA256-SHA256-client-openssl11-server-openssl11 \ +check-cipher-AECDH-AES128-SHA-client-openssl11-server-openssl11 \ +check-cipher-AECDH-AES256-SHA-client-openssl11-server-openssl11 \ +check-cipher-AES128-GCM-SHA256-client-openssl11-server-openssl11 \ +check-cipher-AES128-SHA-client-openssl11-server-openssl11 \ +check-cipher-AES128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-AES256-GCM-SHA384-client-openssl11-server-openssl11 \ +check-cipher-AES256-SHA-client-openssl11-server-openssl11 \ +check-cipher-AES256-SHA256-client-openssl11-server-openssl11 \ +check-cipher-CAMELLIA128-SHA-client-openssl11-server-openssl11 \ +check-cipher-CAMELLIA128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-CAMELLIA256-SHA-client-openssl11-server-openssl11 \ +check-cipher-CAMELLIA256-SHA256-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-AES128-GCM-SHA256-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-AES128-SHA-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-AES128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-AES256-GCM-SHA384-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-AES256-SHA-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-AES256-SHA256-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-CAMELLIA128-SHA-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-CAMELLIA128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-CAMELLIA256-SHA-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-CAMELLIA256-SHA256-client-openssl11-server-openssl11 \ +check-cipher-DHE-RSA-CHACHA20-POLY1305-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-AES128-GCM-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-AES128-SHA-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-AES128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-AES256-GCM-SHA384-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-AES256-SHA-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-AES256-SHA384-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-ECDSA-CHACHA20-POLY1305-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-AES128-GCM-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-AES128-SHA-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-AES128-SHA256-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-AES256-GCM-SHA384-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-AES256-SHA-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-AES256-SHA384-client-openssl11-server-openssl11 \ +check-cipher-ECDHE-RSA-CHACHA20-POLY1305-client-openssl11-server-openssl11: + # openssl11 always prints TLS_AES_256_GCM_SHA384 as cipher in out file + @echo DISABLED + +LIBRARIES = libressl +.if exists(/usr/local/bin/eopenssl) +LIBRARIES += openssl +.endif +.if exists(/usr/local/bin/eopenssl11) +LIBRARIES += openssl11 +.endif + +CLEANFILES = *.tmp *.ciphers ciphers.mk + +.for clib in ${LIBRARIES} +client-${clib}.ciphers: + LD_LIBRARY_PATH=/usr/local/lib/e${clib} \ + ../${clib}/client -l ALL -L >$@.tmp + sed -n 's/^cipher //p' <$@.tmp | sort -u >$@ + rm $@.tmp +.endfor +.for slib in ${LIBRARIES} +server-${slib}.ciphers: 127.0.0.1.crt dsa.crt ec.crt rsa.crt + LD_LIBRARY_PATH=/usr/local/lib/e${slib} \ + ../${slib}/server -l ALL -L >$@.tmp + sed -n 's/^cipher //p' <$@.tmp | sort -u >$@ + rm $@.tmp +.endfor + +.for clib in ${LIBRARIES} +.for slib in ${LIBRARIES} +ciphers.mk: client-${clib}-server-${slib}.ciphers +client-${clib}-server-${slib}.ciphers: \ + client-${clib}.ciphers server-${slib}.ciphers client-libressl.ciphers + # get ciphers shared between client and server + sort client-${clib}.ciphers server-${slib}.ciphers >$@.tmp + uniq -d <$@.tmp >$@ + # we are only interested in cipers supported by libressl + sort $@ client-libressl.ciphers >$@.tmp + uniq -d <$@.tmp >$@ + rm $@.tmp +.endfor +.endfor + +ciphers.mk: + rm -f $@ $@.tmp +.for clib in ${LIBRARIES} +.for slib in ${LIBRARIES} + echo 'CIPHERS_${clib}_${slib} =' >>$@.tmp \ + `cat client-${clib}-server-${slib}.ciphers` +.endfor +.endfor + mv $@.tmp $@ + +# hack to convert generated lists into usable make variables +.if exists(ciphers.mk) +.include "ciphers.mk" +.else +regress: ciphers.mk + ${MAKE} -C ${.CURDIR} regress +.endif + +LEVEL_libressl = +LEVEL_openssl = +LEVEL_openssl11 = ,@SECLEVEL=0 + +.for clib in ${LIBRARIES} +.for slib in ${LIBRARIES} +.for cipher in ${CIPHERS_${clib}_${slib}} + +.if "${cipher:M*-DSS-*}" != "" +TYPE_${cipher} = dsa +.elif "${cipher:M*-ECDSA-*}" != "" +TYPE_${cipher} = ec +.elif "${cipher:M*-GOST89-*}" != "" +TYPE_${cipher} = gost +.elif "${cipher:M*-RSA-*}" != "" +TYPE_${cipher} = rsa +.else +TYPE_${cipher} = 127.0.0.1 +.endif + +.if "${slib}" == "openssl" && \ + "${cipher:MADH-*}${cipher:MEDH-*}${cipher:MDHE-*}" != "" +DHPARAM_${cipher}_${slib} = -p dh.param +.else +DHPARAM_${cipher}_${slib} = +.endif + +REGRESS_TARGETS += run-cipher-${cipher}-client-${clib}-server-${slib} +run-cipher-${cipher}-client-${clib}-server-${slib} \ +client-cipher-${cipher}-client-${clib}-server-${slib}.out \ +server-cipher-${cipher}-client-${clib}-server-${slib}.out: dh.param \ + 127.0.0.1.crt ${TYPE_${cipher}}.crt ../${clib}/client ../${slib}/server + @echo '\n======== $@ ========' + LD_LIBRARY_PATH=/usr/local/lib/e${slib} \ + ../${slib}/server >${@:S/^run/server/}.out \ + -c ${TYPE_${cipher}}.crt -k ${TYPE_${cipher}}.key \ + -l ${cipher}${LEVEL_${slib}} ${DHPARAM_${cipher}_${slib}} \ + 127.0.0.1 0 + LD_LIBRARY_PATH=/usr/local/lib/e${clib} \ + ../${clib}/client >${@:S/^run/client/}.out \ + -l ${cipher}${LEVEL_${clib}} \ + `sed -n 's/listen sock: //p' ${@:S/^run/server/}.out` + grep -q '^success$$' ${@:S/^run/server/}.out || \ + { sleep 1; grep -q '^success$$' ${@:S/^run/server/}.out; } + grep -q '^success$$' ${@:S/^run/client/}.out + +REGRESS_TARGETS += check-cipher-${cipher}-client-${clib}-server-${slib} +check-cipher-${cipher}-client-${clib}-server-${slib}: \ + client-cipher-${cipher}-client-${clib}-server-${slib}.out \ + server-cipher-${cipher}-client-${clib}-server-${slib}.out + @echo '\n======== $@ ========' + grep -q ' Cipher *: ${cipher}$$' ${@:S/^check/server/}.out + grep -q ' Cipher *: ${cipher}$$' ${@:S/^check/client/}.out + +.endfor +.endfor +.endfor + +.include diff --git a/src/regress/lib/libssl/interop/client.c b/src/regress/lib/libssl/interop/client.c index 6f14837895..136dc38d09 100644 --- a/src/regress/lib/libssl/interop/client.c +++ b/src/regress/lib/libssl/interop/client.c @@ -1,6 +1,6 @@ -/* $OpenBSD: client.c,v 1.6 2019/02/11 12:22:44 bluhm Exp $ */ +/* $OpenBSD: client.c,v 1.7 2019/02/21 23:06:33 bluhm Exp $ */ /* - * Copyright (c) 2018 Alexander Bluhm + * Copyright (c) 2018-2019 Alexander Bluhm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,8 +34,8 @@ void __dead usage(void); void __dead usage(void) { - fprintf(stderr, - "usage: client [-sv] [-C CA] [-c crt -k key] host port"); + fprintf(stderr, "usage: client [-Lsv] [-C CA] [-c crt -k key] " + "[-l cipers] host port\n"); exit(2); } @@ -47,12 +47,13 @@ main(int argc, char *argv[]) SSL *ssl; BIO *bio; SSL_SESSION *session = NULL; - int ch, error, sessionreuse = 0, verify = 0; + int ch, error, listciphers = 0, sessionreuse = 0, verify = 0; char buf[256]; - char *ca = NULL, *crt = NULL, *key = NULL; - char *host_port, *host, *port; + char *ca = NULL, *crt = NULL, *key = NULL, *ciphers = NULL; + char *host_port, *host = "127.0.0.1", *port = "0"; - while ((ch = getopt(argc, argv, "C:c:k:sv")) != -1) { + + while ((ch = getopt(argc, argv, "C:c:k:Ll:sv")) != -1) { switch (ch) { case 'C': ca = optarg; @@ -63,6 +64,12 @@ main(int argc, char *argv[]) case 'k': key = optarg; break; + case 'L': + listciphers = 1; + break; + case 'l': + ciphers = optarg; + break; case 's': /* multiple reueses are possible */ sessionreuse++; @@ -79,7 +86,7 @@ main(int argc, char *argv[]) if (argc == 2) { host = argv[0]; port = argv[1]; - } else { + } else if (!listciphers) { usage(); } if (asprintf(&host_port, strchr(host, ':') ? "[%s]:%s" : "%s:%s", @@ -130,6 +137,19 @@ main(int argc, char *argv[]) SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT); } + if (ciphers) { + if (SSL_CTX_set_cipher_list(ctx, ciphers) <= 0) + err_ssl(1, "SSL_CTX_set_cipher_list"); + } + + if (listciphers) { + ssl = SSL_new(ctx); + if (ssl == NULL) + err_ssl(1, "SSL_new"); + print_ciphers(SSL_get_ciphers(ssl)); + return 0; + } + do { /* setup bio for socket operations */ bio = BIO_new_connect(host_port); @@ -148,7 +168,6 @@ main(int argc, char *argv[]) ssl = SSL_new(ctx); if (ssl == NULL) err_ssl(1, "SSL_new"); - print_ciphers(SSL_get_ciphers(ssl)); SSL_set_bio(ssl, bio, bio); /* resuse session if possible */ if (session != NULL) { diff --git a/src/regress/lib/libssl/interop/server.c b/src/regress/lib/libssl/interop/server.c index 3cbadda4c5..ee9c7c70a0 100644 --- a/src/regress/lib/libssl/interop/server.c +++ b/src/regress/lib/libssl/interop/server.c @@ -1,6 +1,6 @@ -/* $OpenBSD: server.c,v 1.6 2019/02/11 12:22:44 bluhm Exp $ */ +/* $OpenBSD: server.c,v 1.7 2019/02/21 23:06:33 bluhm Exp $ */ /* - * Copyright (c) 2018 Alexander Bluhm + * Copyright (c) 2018-2019 Alexander Bluhm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,8 +35,8 @@ void __dead usage(void); void __dead usage(void) { - fprintf(stderr, - "usage: server [-svv] [-C CA] [-c crt -k key] [host port]"); + fprintf(stderr, "usage: server [-Lsvv] [-C CA] [-c crt -k key] " + "[-l cipers] [-p dhparam] [host port]\n"); exit(2); } @@ -48,12 +48,12 @@ main(int argc, char *argv[]) SSL *ssl; BIO *abio, *cbio; SSL_SESSION *session; - int ch, error, sessionreuse = 0, verify = 0; - char buf[256]; - char *ca = NULL, *crt = NULL, *key = NULL; + int ch, error, listciphers = 0, sessionreuse = 0, verify = 0; + char buf[256], *dhparam = NULL; + char *ca = NULL, *crt = NULL, *key = NULL, *ciphers = NULL; char *host_port, *host = "127.0.0.1", *port = "0"; - while ((ch = getopt(argc, argv, "C:c:k:sv")) != -1) { + while ((ch = getopt(argc, argv, "C:c:k:Ll:p:sv")) != -1) { switch (ch) { case 'C': ca = optarg; @@ -64,6 +64,15 @@ main(int argc, char *argv[]) case 'k': key = optarg; break; + case 'L': + listciphers = 1; + break; + case 'l': + ciphers = optarg; + break; + case 'p': + dhparam = optarg; + break; case 's': /* multiple reueses are possible */ sessionreuse++; @@ -81,7 +90,7 @@ main(int argc, char *argv[]) if (argc == 2) { host = argv[0]; port = argv[1]; - } else if (argc != 0) { + } else if (argc != 0 && !listciphers) { usage(); } if (asprintf(&host_port, strchr(host, ':') ? "[%s]:%s" : "%s:%s", @@ -112,6 +121,27 @@ main(int argc, char *argv[]) if (ctx == NULL) err_ssl(1, "SSL_CTX_new"); +#if OPENSSL_VERSION_NUMBER >= 0x10100000 + /* needed to use DHE cipher with libressl */ + if (SSL_CTX_set_dh_auto(ctx, 1) <= 0) + err_ssl(1, "SSL_CTX_set_dh_auto"); +#endif + /* needed to use ADH, EDH, DHE cipher with openssl */ + if (dhparam != NULL) { + DH *dh; + FILE *file; + + file = fopen(dhparam, "r"); + if (file == NULL) + err(1, "fopen %s", dhparam); + dh = PEM_read_DHparams(file, NULL, NULL, NULL); + if (dh == NULL) + err_ssl(1, "PEM_read_DHparams"); + if (SSL_CTX_set_tmp_dh(ctx, dh) <= 0) + err_ssl(1, "SSL_CTX_set_tmp_dh"); + fclose(file); + } + /* needed when linking with OpenSSL 1.0.2p */ if (SSL_CTX_set_ecdh_auto(ctx, 1) <= 0) err_ssl(1, "SSL_CTX_set_ecdh_auto"); @@ -151,6 +181,19 @@ main(int argc, char *argv[]) err_ssl(1, "SSL_CTX_set_session_id_context"); } + if (ciphers) { + if (SSL_CTX_set_cipher_list(ctx, ciphers) <= 0) + err_ssl(1, "SSL_CTX_set_cipher_list"); + } + + if (listciphers) { + ssl = SSL_new(ctx); + if (ssl == NULL) + err_ssl(1, "SSL_new"); + print_ciphers(SSL_get_ciphers(ssl)); + return 0; + } + /* setup bio for socket operations */ abio = BIO_new_accept(host_port); if (abio == NULL) @@ -182,7 +225,6 @@ main(int argc, char *argv[]) ssl = SSL_new(ctx); if (ssl == NULL) err_ssl(1, "SSL_new"); - print_ciphers(SSL_get_ciphers(ssl)); SSL_set_bio(ssl, cbio, cbio); if ((error = SSL_accept(ssl)) <= 0) err_ssl(1, "SSL_accept %d", error); -- cgit v1.2.3-55-g6feb