From e1c7871de80029b81824df4d59edc6de5293835f Mon Sep 17 00:00:00 2001 From: Todd Short Date: Mon, 21 Dec 2015 15:19:29 -0500 Subject: [PATCH] Use ChaCha only if prioritized by clnt IFF the client has ChaCha first, and server cipher priority is used, and the new SSL_OP_PRIORITIZE_CHACHA_FOR_MOBILE option is used, then reprioritize ChaCha above everything else. This way, A matching ChaCha cipher will be selected if there is a match. If no ChaCha ciphers match, then the other ciphers are used. Reviewed-by: Paul Dale Reviewed-by: Tim Hudson Reviewed-by: Andy Polyakov (Merged from https://github.com/openssl/openssl/pull/4436) --- apps/apps.h | 4 + doc/man1/s_server.pod | 10 +- doc/man3/SSL_CONF_cmd.pod | 26 +++- doc/man3/SSL_CTX_set_options.pod | 13 +- include/openssl/ssl.h | 3 + ssl/s3_lib.c | 52 ++++++- ssl/ssl_conf.c | 6 +- test/handshake_helper.c | 5 + test/handshake_helper.h | 1 + test/recipes/80-test_ssl_new.t | 2 +- test/ssl-tests/25-cipher.conf | 244 +++++++++++++++++++++++++++++++ test/ssl-tests/25-cipher.conf.in | 151 +++++++++++++++++++ test/ssl_test.c | 13 ++ test/ssl_test_ctx.c | 6 + test/ssl_test_ctx.h | 1 + test/ssl_test_ctx_test.c | 2 + 16 files changed, 528 insertions(+), 11 deletions(-) create mode 100644 test/ssl-tests/25-cipher.conf create mode 100644 test/ssl-tests/25-cipher.conf.in diff --git a/apps/apps.h b/apps/apps.h index a279d42b56..bb89eaecf6 100644 --- a/apps/apps.h +++ b/apps/apps.h @@ -204,6 +204,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, OPT_S_NOTLS1_3, OPT_S_BUGS, OPT_S_NO_COMP, OPT_S_NOTICKET, \ OPT_S_SERVERPREF, OPT_S_LEGACYRENEG, OPT_S_LEGACYCONN, \ OPT_S_ONRESUMP, OPT_S_NOLEGACYCONN, OPT_S_ALLOW_NO_DHE_KEX, \ + OPT_S_PRIORITIZE_CHACHA, \ OPT_S_STRICT, OPT_S_SIGALGS, OPT_S_CLIENTSIGALGS, OPT_S_GROUPS, \ OPT_S_CURVES, OPT_S_NAMEDCURVE, OPT_S_CIPHER, \ OPT_S_RECORD_PADDING, OPT_S_DEBUGBROKE, OPT_S_COMP, \ @@ -233,6 +234,8 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, "Disallow initial connection to servers that don't support RI"}, \ {"allow_no_dhe_kex", OPT_S_ALLOW_NO_DHE_KEX, '-', \ "In TLSv1.3 allow non-(ec)dhe based key exchange on resumption"}, \ + {"prioritize_chacha", OPT_S_PRIORITIZE_CHACHA, '-', \ + "Prioritize ChaCha ciphers when preferred by clients"}, \ {"strict", OPT_S_STRICT, '-', \ "Enforce strict certificate checks as per TLS standard"}, \ {"sigalgs", OPT_S_SIGALGS, 's', \ @@ -270,6 +273,7 @@ int set_cert_times(X509 *x, const char *startdate, const char *enddate, case OPT_S_ONRESUMP: \ case OPT_S_NOLEGACYCONN: \ case OPT_S_ALLOW_NO_DHE_KEX: \ + case OPT_S_PRIORITIZE_CHACHA: \ case OPT_S_STRICT: \ case OPT_S_SIGALGS: \ case OPT_S_CLIENTSIGALGS: \ diff --git a/doc/man1/s_server.pod b/doc/man1/s_server.pod index 0e28e4e2f1..ad04359efd 100644 --- a/doc/man1/s_server.pod +++ b/doc/man1/s_server.pod @@ -105,6 +105,7 @@ B B [B<-no_resumption_on_reneg>] [B<-no_legacy_server_connect>] [B<-allow_no_dhe_kex>] +[B<-prioritize_chacha>] [B<-strict>] [B<-sigalgs val>] [B<-client_sigalgs val>] @@ -510,6 +511,10 @@ Disable RFC4507bis session ticket support. Use the server's cipher preferences, rather than the client's preferences. +=item B<-prioritize_chacha> + +Prioritize ChaCha ciphers when preferred by clients. Requires B<-serverpref>. + =item B<-no_resumption_on_reneg> Set the B option. @@ -718,7 +723,10 @@ L =head1 HISTORY -The -no_alt_chains options was first added to OpenSSL 1.1.0. +The -no_alt_chains option was first added to OpenSSL 1.1.0. + +The -allow-no-dhe-kex and -prioritize_chacha options were first added to +OpenSSL 1.1.1. =head1 COPYRIGHT diff --git a/doc/man3/SSL_CONF_cmd.pod b/doc/man3/SSL_CONF_cmd.pod index a8121865a9..06b98bd416 100644 --- a/doc/man3/SSL_CONF_cmd.pod +++ b/doc/man3/SSL_CONF_cmd.pod @@ -171,6 +171,13 @@ Use server and not client preference order when determining which cipher suite, signature algorithm or elliptic curve to use for an incoming connection. Equivalent to B. Only used by servers. +=item B<-prioritize_chacha> + +Prioritize ChaCha ciphers when the client has a ChaCha20 cipher at the top of +its preference list. This usually indicates a client without AES hardware +acceleration (e.g. mobile) is in use. Equivalent to B. +Only used by servers. Requires B<-serverpref>. + =item B<-no_resumption_on_reneg> set SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION flag. Only used by servers. @@ -382,21 +389,26 @@ B: enable various bug workarounds. Same as B. B: enable single use DH keys, set by default. Inverse of B. Only used by servers. -B enable single use ECDH keys, set by default. Inverse of +B: enable single use ECDH keys, set by default. Inverse of B. Only used by servers. -B use server and not client preference order when +B: use server and not client preference order when determining which cipher suite, signature algorithm or elliptic curve to use for an incoming connection. Equivalent to B. Only used by servers. -B set +B: prioritizes ChaCha ciphers when the client has a +ChaCha20 cipher at the top of its preference list. This usually indicates +a mobile client is in use. Equivalent to B. +Only used by servers. + +B: set B flag. Only used by servers. -B permits the use of unsafe legacy renegotiation. +B: permits the use of unsafe legacy renegotiation. Equivalent to B. -B permits the use of unsafe legacy renegotiation +B: permits the use of unsafe legacy renegotiation for OpenSSL clients only. Equivalent to B. Set by default. @@ -595,9 +607,11 @@ B. B and B where added in OpenSSL 1.1.0. +B and B were added in OpenSSL 1.1.1. + =head1 COPYRIGHT -Copyright 2012-2016 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2012-2017 The OpenSSL Project Authors. All Rights Reserved. Licensed under the OpenSSL license (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/doc/man3/SSL_CTX_set_options.pod b/doc/man3/SSL_CTX_set_options.pod index bd7f111d4c..072fdb7c5c 100644 --- a/doc/man3/SSL_CTX_set_options.pod +++ b/doc/man3/SSL_CTX_set_options.pod @@ -180,6 +180,15 @@ messages, and ignore renegotiation requests via ClientHello. In TLSv1.3 allow a non-(ec)dhe based key exchange mode on resumption. This means that there will be no forward secrecy for the resumed session. +=item SSL_OP_PRIORITIZE_CHACHA + +When SSL_OP_CIPHER_SERVER_PREFERENCE is set, temporarily reprioritize +ChaCha20-Poly1305 ciphers to the top of the server cipher list if a +ChaCha20-Poly1305 cipher is at the top of the client cipher list. This helps +those clients (e.g. mobile) use ChaCha20-Poly1305 if that cipher is anywhere +in the server cipher list; but still allows other clients to use AES and other +ciphers. Requires B. + =back The following options no longer have any effect but their identifiers are @@ -306,9 +315,11 @@ L The attempt to always try to use secure renegotiation was added in Openssl 0.9.8m. +B was added in OpenSSL 1.1.1. + =head1 COPYRIGHT -Copyright 2001-2016 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2001-2017 The OpenSSL Project Authors. All Rights Reserved. Licensed under the OpenSSL license (the "License"). You may not use this file except in compliance with the License. You can obtain a copy diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 176425a61d..a5251b59cc 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -338,6 +338,9 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); # define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000U /* Disable encrypt-then-mac */ # define SSL_OP_NO_ENCRYPT_THEN_MAC 0x00080000U +/* Prioritize Chacha20Poly1305 when client does. + * Modifies SSL_OP_CIPHER_SERVER_PREFERENCE */ +# define SSL_OP_PRIORITIZE_CHACHA 0x00200000U /* * Set on servers to choose the cipher according to the server's preferences */ diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index f4423b2855..c063fff87a 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -4120,6 +4120,9 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, STACK_OF(SSL_CIPHER) *prio, *allow; int i, ii, ok; unsigned long alg_k = 0, alg_a = 0, mask_k = 0, mask_a = 0; +#ifndef OPENSSL_NO_CHACHA + STACK_OF(SSL_CIPHER) *prio_chacha = NULL; +#endif /* Let's see which ciphers we can support */ @@ -4145,9 +4148,53 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, } #endif - if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s)) { + /* SUITE-B takes precedence over server preference and ChaCha priortiy */ + if (tls1_suiteb(s)) { + prio = srvr; + allow = clnt; + } else if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { prio = srvr; allow = clnt; +#ifndef OPENSSL_NO_CHACHA + /* If ChaCha20 is at the top of the client preference list, + and there are ChaCha20 ciphers in the server list, then + temporarily prioritize all ChaCha20 ciphers in the servers list. */ + if (s->options & SSL_OP_PRIORITIZE_CHACHA && sk_SSL_CIPHER_num(clnt) > 0) { + c = sk_SSL_CIPHER_value(clnt, 0); + if (c->algorithm_enc == SSL_CHACHA20POLY1305) { + /* ChaCha20 is client preferred, check server... */ + int num = sk_SSL_CIPHER_num(srvr); + int found = 0; + for (i = 0; i < num; i++) { + c = sk_SSL_CIPHER_value(srvr, i); + if (c->algorithm_enc == SSL_CHACHA20POLY1305) { + found = 1; + break; + } + } + if (found) { + prio_chacha = sk_SSL_CIPHER_new_null(); + /* if reserve fails, then there's likely a memory issue */ + if (prio_chacha != NULL) { + /* Put all ChaCha20 at the top, starting with the one we just found */ + sk_SSL_CIPHER_push(prio_chacha, c); + for (i++; i < num; i++) { + c = sk_SSL_CIPHER_value(srvr, i); + if (c->algorithm_enc == SSL_CHACHA20POLY1305) + sk_SSL_CIPHER_push(prio_chacha, c); + } + /* Pull in the rest */ + for (i = 0; i < num; i++) { + c = sk_SSL_CIPHER_value(srvr, i); + if (c->algorithm_enc != SSL_CHACHA20POLY1305) + sk_SSL_CIPHER_push(prio_chacha, c); + } + prio = prio_chacha; + } + } + } + } +# endif } else { prio = clnt; allow = srvr; @@ -4229,6 +4276,9 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, break; } } +#ifndef OPENSSL_NO_CHACHA + sk_SSL_CIPHER_free(prio_chacha); +#endif return ret; } diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index 1a8dc1543d..fe090ae40d 100644 --- a/ssl/ssl_conf.c +++ b/ssl/ssl_conf.c @@ -368,7 +368,8 @@ static int cmd_Options(SSL_CONF_CTX *cctx, const char *value) SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION), SSL_FLAG_TBL_INV("EncryptThenMac", SSL_OP_NO_ENCRYPT_THEN_MAC), SSL_FLAG_TBL("NoRenegotiation", SSL_OP_NO_RENEGOTIATION), - SSL_FLAG_TBL("AllowNoDHEKEX", SSL_OP_ALLOW_NO_DHE_KEX) + SSL_FLAG_TBL("AllowNoDHEKEX", SSL_OP_ALLOW_NO_DHE_KEX), + SSL_FLAG_TBL("PrioritizeChaCha", SSL_OP_PRIORITIZE_CHACHA) }; if (value == NULL) return -3; @@ -588,6 +589,7 @@ static const ssl_conf_cmd_tbl ssl_conf_cmds[] = { SSL_CONF_CMD_SWITCH("no_resumption_on_reneg", SSL_CONF_FLAG_SERVER), SSL_CONF_CMD_SWITCH("no_legacy_server_connect", SSL_CONF_FLAG_SERVER), SSL_CONF_CMD_SWITCH("allow_no_dhe_kex", 0), + SSL_CONF_CMD_SWITCH("prioritize_chacha", SSL_CONF_FLAG_SERVER), SSL_CONF_CMD_SWITCH("strict", 0), SSL_CONF_CMD_STRING(SignatureAlgorithms, "sigalgs", 0), SSL_CONF_CMD_STRING(ClientSignatureAlgorithms, "client_sigalgs", 0), @@ -660,6 +662,8 @@ static const ssl_switch_tbl ssl_cmd_switches[] = { {SSL_OP_LEGACY_SERVER_CONNECT, SSL_TFLAG_INV}, /* allow_no_dhe_kex */ {SSL_OP_ALLOW_NO_DHE_KEX, 0}, + /* chacha reprioritization */ + {SSL_OP_PRIORITIZE_CHACHA, 0}, {SSL_CERT_FLAG_TLS_STRICT, SSL_TFLAG_CERT}, /* strict */ }; diff --git a/test/handshake_helper.c b/test/handshake_helper.c index 188ec9ed96..78eaa012e2 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -39,6 +39,7 @@ void HANDSHAKE_RESULT_free(HANDSHAKE_RESULT *result) OPENSSL_free(result->server_alpn_negotiated); sk_X509_NAME_pop_free(result->server_ca_names, X509_NAME_free); sk_X509_NAME_pop_free(result->client_ca_names, X509_NAME_free); + OPENSSL_free(result->cipher); OPENSSL_free(result); } @@ -1324,6 +1325,7 @@ static HANDSHAKE_RESULT *do_handshake_internal( EVP_PKEY *tmp_key; const STACK_OF(X509_NAME) *names; time_t start; + const char* cipher; if (ret == NULL) return NULL; @@ -1543,6 +1545,9 @@ static HANDSHAKE_RESULT *do_handshake_internal( ret->client_resumed = SSL_session_reused(client.ssl); ret->server_resumed = SSL_session_reused(server.ssl); + cipher = SSL_CIPHER_get_name(SSL_get_current_cipher(client.ssl)); + ret->cipher = dup_str((const unsigned char*)cipher, strlen(cipher)); + if (session_out != NULL) *session_out = SSL_get1_session(client.ssl); diff --git a/test/handshake_helper.h b/test/handshake_helper.h index 96c670e387..9dcbeb78f7 100644 --- a/test/handshake_helper.h +++ b/test/handshake_helper.h @@ -64,6 +64,7 @@ typedef struct handshake_result { STACK_OF(X509_NAME) *client_ca_names; /* Session id status */ ssl_session_id_t session_id; + char *cipher; } HANDSHAKE_RESULT; HANDSHAKE_RESULT *HANDSHAKE_RESULT_new(void); diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t index 42bf4625d3..3b1447b9f2 100644 --- a/test/recipes/80-test_ssl_new.t +++ b/test/recipes/80-test_ssl_new.t @@ -28,7 +28,7 @@ map { s/\^// } @conf_files if $^O eq "VMS"; # We hard-code the number of tests to double-check that the globbing above # finds all files as expected. -plan tests => 24; # = scalar @conf_srcs +plan tests => 25; # = scalar @conf_srcs # Some test results depend on the configuration of enabled protocols. We only # verify generated sources in the default configuration. diff --git a/test/ssl-tests/25-cipher.conf b/test/ssl-tests/25-cipher.conf new file mode 100644 index 0000000000..101ee7c517 --- /dev/null +++ b/test/ssl-tests/25-cipher.conf @@ -0,0 +1,244 @@ +# Generated with generate_ssl_tests.pl + +num_tests = 9 + +test-0 = 0-cipher-server-1 +test-1 = 1-cipher-server-2 +test-2 = 2-cipher-server-client-list +test-3 = 3-cipher-server-pref-1 +test-4 = 4-cipher-server-pref-2 +test-5 = 5-cipher-server-pref-client-list +test-6 = 6-cipher-server-pref-not-mobile +test-7 = 7-cipher-server-pref-mobile +test-8 = 8-cipher-server-pref-mobile2 +# =========================================================== + +[0-cipher-server-1] +ssl_conf = 0-cipher-server-1-ssl + +[0-cipher-server-1-ssl] +server = 0-cipher-server-1-server +client = 0-cipher-server-1-client + +[0-cipher-server-1-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[0-cipher-server-1-client] +CipherString = ECDHE-RSA-AES256-SHA384 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-0] +ExpectedCipher = ECDHE-RSA-AES256-SHA384 + + +# =========================================================== + +[1-cipher-server-2] +ssl_conf = 1-cipher-server-2-ssl + +[1-cipher-server-2-ssl] +server = 1-cipher-server-2-server +client = 1-cipher-server-2-client + +[1-cipher-server-2-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[1-cipher-server-2-client] +CipherString = ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-1] +ExpectedCipher = ECDHE-RSA-AES128-SHA256 + + +# =========================================================== + +[2-cipher-server-client-list] +ssl_conf = 2-cipher-server-client-list-ssl + +[2-cipher-server-client-list-ssl] +server = 2-cipher-server-client-list-server +client = 2-cipher-server-client-list-client + +[2-cipher-server-client-list-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[2-cipher-server-client-list-client] +CipherString = ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-2] +ExpectedCipher = ECDHE-RSA-AES128-SHA256 + + +# =========================================================== + +[3-cipher-server-pref-1] +ssl_conf = 3-cipher-server-pref-1-ssl + +[3-cipher-server-pref-1-ssl] +server = 3-cipher-server-pref-1-server +client = 3-cipher-server-pref-1-client + +[3-cipher-server-pref-1-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +Options = ServerPreference +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[3-cipher-server-pref-1-client] +CipherString = ECDHE-RSA-AES256-SHA384 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-3] +ExpectedCipher = ECDHE-RSA-AES256-SHA384 + + +# =========================================================== + +[4-cipher-server-pref-2] +ssl_conf = 4-cipher-server-pref-2-ssl + +[4-cipher-server-pref-2-ssl] +server = 4-cipher-server-pref-2-server +client = 4-cipher-server-pref-2-client + +[4-cipher-server-pref-2-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +Options = ServerPreference +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[4-cipher-server-pref-2-client] +CipherString = ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-4] +ExpectedCipher = ECDHE-RSA-AES128-SHA256 + + +# =========================================================== + +[5-cipher-server-pref-client-list] +ssl_conf = 5-cipher-server-pref-client-list-ssl + +[5-cipher-server-pref-client-list-ssl] +server = 5-cipher-server-pref-client-list-server +client = 5-cipher-server-pref-client-list-client + +[5-cipher-server-pref-client-list-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256 +MaxProtocol = TLSv1.2 +Options = ServerPreference +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[5-cipher-server-pref-client-list-client] +CipherString = ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-5] +ExpectedCipher = ECDHE-RSA-AES256-SHA384 + + +# =========================================================== + +[6-cipher-server-pref-not-mobile] +ssl_conf = 6-cipher-server-pref-not-mobile-ssl + +[6-cipher-server-pref-not-mobile-ssl] +server = 6-cipher-server-pref-not-mobile-server +client = 6-cipher-server-pref-not-mobile-client + +[6-cipher-server-pref-not-mobile-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305 +MaxProtocol = TLSv1.2 +Options = ServerPreference +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[6-cipher-server-pref-not-mobile-client] +CipherString = ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-6] +ExpectedCipher = ECDHE-RSA-AES256-SHA384 + + +# =========================================================== + +[7-cipher-server-pref-mobile] +ssl_conf = 7-cipher-server-pref-mobile-ssl + +[7-cipher-server-pref-mobile-ssl] +server = 7-cipher-server-pref-mobile-server +client = 7-cipher-server-pref-mobile-client + +[7-cipher-server-pref-mobile-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305 +MaxProtocol = TLSv1.2 +Options = ServerPreference,PrioritizeChaCha +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[7-cipher-server-pref-mobile-client] +CipherString = ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-7] +ExpectedCipher = ECDHE-RSA-CHACHA20-POLY1305 + + +# =========================================================== + +[8-cipher-server-pref-mobile2] +ssl_conf = 8-cipher-server-pref-mobile2-ssl + +[8-cipher-server-pref-mobile2-ssl] +server = 8-cipher-server-pref-mobile2-server +client = 8-cipher-server-pref-mobile2-client + +[8-cipher-server-pref-mobile2-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305 +MaxProtocol = TLSv1.2 +Options = ServerPreference,PrioritizeChaCha +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[8-cipher-server-pref-mobile2-client] +CipherString = ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-CHACHA20-POLY1305 +MaxProtocol = TLSv1.2 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-8] +ExpectedCipher = ECDHE-RSA-AES256-SHA384 + + diff --git a/test/ssl-tests/25-cipher.conf.in b/test/ssl-tests/25-cipher.conf.in new file mode 100644 index 0000000000..c4b0b0509a --- /dev/null +++ b/test/ssl-tests/25-cipher.conf.in @@ -0,0 +1,151 @@ +# -*- mode: perl; -*- +# Copyright 2017 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +## Test version negotiation + +use strict; +use warnings; + +package ssltests; + + +our @tests = ( + { + name => "cipher-server-1", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384" + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES256-SHA384", + }, + }, + { + name => "cipher-server-2", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES128-SHA256" + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES128-SHA256", + }, + }, + { + name => "cipher-server-client-list", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384", + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES128-SHA256", + }, + }, + { + name => "cipher-server-pref-1", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256", + "Options" => "ServerPreference", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384" + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES256-SHA384", + }, + }, + { + name => "cipher-server-pref-2", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256", + "Options" => "ServerPreference", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES128-SHA256" + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES128-SHA256", + }, + }, + { + name => "cipher-server-pref-client-list", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256", + "Options" => "ServerPreference", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384", + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES256-SHA384", + }, + }, + { + name => "cipher-server-pref-not-mobile", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305", + "Options" => "ServerPreference", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384", + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES256-SHA384", + }, + }, + { + name => "cipher-server-pref-mobile", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305", + "Options" => "ServerPreference,PrioritizeChaCha", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384", + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-CHACHA20-POLY1305", + }, + }, + { + name => "cipher-server-pref-mobile2", + server => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CHACHA20-POLY1305", + "Options" => "ServerPreference,PrioritizeChaCha", + }, + client => { + "MaxProtocol" => "TLSv1.2", + "CipherString" => "ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-CHACHA20-POLY1305", + }, + test => { + "ExpectedCipher" => "ECDHE-RSA-AES256-SHA384", + }, + }, +); diff --git a/test/ssl_test.c b/test/ssl_test.c index dcdd867f43..a21a0f773b 100644 --- a/test/ssl_test.c +++ b/test/ssl_test.c @@ -318,6 +318,18 @@ static int check_client_ca_names(HANDSHAKE_RESULT *result, result->client_ca_names); } +static int check_cipher(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx) +{ + if (test_ctx->expected_cipher == NULL) + return 1; + if (!TEST_ptr(result->cipher)) + return 0; + if (!TEST_str_eq(test_ctx->expected_cipher, + result->cipher)) + return 0; + return 1; +} + /* * This could be further simplified by constructing an expected * HANDSHAKE_RESULT, and implementing comparison methods for @@ -338,6 +350,7 @@ static int check_test(HANDSHAKE_RESULT *result, SSL_TEST_CTX *test_ctx) #ifndef OPENSSL_NO_NEXTPROTONEG ret &= check_npn(result, test_ctx); #endif + ret &= check_cipher(result, test_ctx); ret &= check_alpn(result, test_ctx); ret &= check_resumption(result, test_ctx); ret &= check_tmp_key(result, test_ctx); diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c index 62417ac2c1..71445c5e24 100644 --- a/test/ssl_test_ctx.c +++ b/test/ssl_test_ctx.c @@ -615,6 +615,10 @@ __owur static int parse_expected_client_ca_names(SSL_TEST_CTX *test_ctx, return parse_expected_ca_names(&test_ctx->expected_client_ca_names, value); } +/* ExpectedCipher */ + +IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CTX, test, expected_cipher) + /* Known test options and their corresponding parse methods. */ /* Top-level options. */ @@ -650,6 +654,7 @@ static const ssl_test_ctx_option ssl_test_ctx_options[] = { { "ExpectedClientSignType", &parse_expected_client_sign_type }, { "ExpectedClientCANames", &parse_expected_client_ca_names }, { "UseSCTP", &parse_test_use_sctp }, + { "ExpectedCipher", &parse_test_expected_cipher }, }; /* Nested client options. */ @@ -728,6 +733,7 @@ void SSL_TEST_CTX_free(SSL_TEST_CTX *ctx) OPENSSL_free(ctx->expected_alpn_protocol); sk_X509_NAME_pop_free(ctx->expected_server_ca_names, X509_NAME_free); sk_X509_NAME_pop_free(ctx->expected_client_ca_names, X509_NAME_free); + OPENSSL_free(ctx->expected_cipher); OPENSSL_free(ctx); } diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h index cec6b77f73..2d7b0c207f 100644 --- a/test/ssl_test_ctx.h +++ b/test/ssl_test_ctx.h @@ -210,6 +210,7 @@ typedef struct { int use_sctp; /* Whether to expect a session id from the server */ ssl_session_id_t session_id_expected; + char *expected_cipher; } SSL_TEST_CTX; const char *ssl_test_result_name(ssl_test_result_t result); diff --git a/test/ssl_test_ctx_test.c b/test/ssl_test_ctx_test.c index d064511df2..70ebb2a0bd 100644 --- a/test/ssl_test_ctx_test.c +++ b/test/ssl_test_ctx_test.c @@ -93,6 +93,8 @@ static int testctx_eq(SSL_TEST_CTX *ctx, SSL_TEST_CTX *ctx2) ctx2->expected_npn_protocol) || !TEST_str_eq(ctx->expected_alpn_protocol, ctx2->expected_alpn_protocol) + || !TEST_str_eq(ctx->expected_cipher, + ctx2->expected_cipher) || !TEST_int_eq(ctx->resumption_expected, ctx2->resumption_expected) || !TEST_int_eq(ctx->session_id_expected, -- GitLab