summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/apps.h4
-rw-r--r--doc/man1/s_server.pod10
-rw-r--r--doc/man3/SSL_CONF_cmd.pod26
-rw-r--r--doc/man3/SSL_CTX_set_options.pod13
-rw-r--r--include/openssl/ssl.h3
-rw-r--r--ssl/s3_lib.c52
-rw-r--r--ssl/ssl_conf.c6
-rw-r--r--test/handshake_helper.c5
-rw-r--r--test/handshake_helper.h1
-rw-r--r--test/recipes/80-test_ssl_new.t2
-rw-r--r--test/ssl-tests/25-cipher.conf244
-rw-r--r--test/ssl-tests/25-cipher.conf.in151
-rw-r--r--test/ssl_test.c13
-rw-r--r--test/ssl_test_ctx.c6
-rw-r--r--test/ssl_test_ctx.h1
-rw-r--r--test/ssl_test_ctx_test.c2
16 files changed, 528 insertions, 11 deletions
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<openssl> B<s_server>
[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<SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION> option.
@@ -718,7 +723,10 @@ L<SSL_CTX_set_max_pipelines(3)>
=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<SSL_OP_CIPHER_SERVER_PREFERENCE>. 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<SSL_OP_PRIORITIZE_CHACHA>.
+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<Bugs>: enable various bug workarounds. Same as B<SSL_OP_ALL>.
B<DHSingle>: enable single use DH keys, set by default. Inverse of
B<SSL_OP_DH_SINGLE>. Only used by servers.
-B<ECDHSingle> enable single use ECDH keys, set by default. Inverse of
+B<ECDHSingle>: enable single use ECDH keys, set by default. Inverse of
B<SSL_OP_ECDH_SINGLE>. Only used by servers.
-B<ServerPreference> use server and not client preference order when
+B<ServerPreference>: 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<SSL_OP_CIPHER_SERVER_PREFERENCE>. Only used by servers.
-B<NoResumptionOnRenegotiation> set
+B<PrioritizeChaCha>: 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<SSL_OP_PRIORITIZE_CHACHA>.
+Only used by servers.
+
+B<NoResumptionOnRenegotiation>: set
B<SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION> flag. Only used by servers.
-B<UnsafeLegacyRenegotiation> permits the use of unsafe legacy renegotiation.
+B<UnsafeLegacyRenegotiation>: permits the use of unsafe legacy renegotiation.
Equivalent to B<SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION>.
-B<UnsafeLegacyServerConnect> permits the use of unsafe legacy renegotiation
+B<UnsafeLegacyServerConnect>: permits the use of unsafe legacy renegotiation
for OpenSSL clients only. Equivalent to B<SSL_OP_LEGACY_SERVER_CONNECT>.
Set by default.
@@ -595,9 +607,11 @@ B<SSL_CONF_TYPE_UNKNOWN>.
B<MinProtocol> and B<MaxProtocol> where added in OpenSSL 1.1.0.
+B<AllowNoDHEKEX> and B<PrioritizeChaCha> 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<SSL_OP_CIPHER_SERVER_PREFERENCE>.
+
=back
The following options no longer have any effect but their identifiers are
@@ -306,9 +315,11 @@ L<dhparam(1)>
The attempt to always try to use secure renegotiation was added in
Openssl 0.9.8m.
+B<SSL_OP_PRIORITIZE_CHACHA> 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,