Document cipher suite configuration.
The cipher suite rules could also be anchored on SSL_TXT_* if desired. I
currently documented them in prose largely because SSL_TXT_* also
defines protocol version strings and those are weird; SSL_TXT_TLSV1_1
isn't even a cipher rule. (And, in fact, those are the only SSL_TXT_*
macros that we can't blindly remove. I found some code that #ifdef's the
version SSL_TXT_* macros to decide if version-locked SSL_METHODs are
available.)
Also they clutter the header. I was thinking maybe we should dump a lot
of the random constants into a separate undocumented header or perhaps
just unexport them.
I'm slightly torn on this though and could easily be convinced in the
other direction. (Playing devil's advocate, anchoring on SSL_TXT_* means
we're less likely to forget to document one so long as adding a
SSL_TXT_* macro is the convention.)
Change-Id: Ide2ae44db9d6d8f29c24943090c210da0108dc37
Reviewed-on: https://boringssl-review.googlesource.com/5962
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index b2adb3f..b5b6371 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -913,6 +913,131 @@
SSL *ssl, const SSL_PRIVATE_KEY_METHOD *key_method);
+/* Cipher suite configuration.
+ *
+ * OpenSSL uses a mini-language to configure cipher suites. The language
+ * maintains an ordered list of enabled ciphers, along with an ordered list of
+ * disabled but available ciphers. Initially, all ciphers are disabled with a
+ * default ordering. The cipher string is then interpreted as a sequence of
+ * directives, separated by colons, each of which modifies this state.
+ *
+ * Most directives consist of a one character or empty opcode followed by a
+ * selector which matches a subset of available ciphers.
+ *
+ * Available opcodes are:
+ *
+ * The empty opcode enables and appends all matching disabled ciphers to the
+ * end of the enabled list. The newly appended ciphers are ordered relative to
+ * each other matching their order in the disabled list.
+ *
+ * |-| disables all matching enabled ciphers and prepends them to the disabled
+ * list, with relative order from the enabled list preserved. This means the
+ * most recently disabled ciphers get highest preference relative to other
+ * disabled ciphers if re-enabled.
+ *
+ * |+| moves all matching enabled ciphers to the end of the enabled list, with
+ * relative order preserved.
+ *
+ * |!| deletes all matching ciphers, enabled or not, from either list. Deleted
+ * ciphers will not matched by future operations.
+ *
+ * A selector may be a specific cipher (using the OpenSSL name for the cipher)
+ * or one or more rules separated by |+|. The final selector matches the
+ * intersection of each rule. For instance, |AESGCM+aECDSA| matches
+ * ECDSA-authenticated AES-GCM ciphers.
+ *
+ * Available cipher rules are:
+ *
+ * |ALL| matches all ciphers.
+ *
+ * |kRSA|, |kDHE|, |kECDHE|, and |kPSK| match ciphers using plain RSA, DHE,
+ * ECDHE, and plain PSK key exchanges, respectively. Note that ECDHE_PSK is
+ * matched by |kECDHE| and not |kPSK|.
+ *
+ * |aRSA|, |aECDSA|, and |aPSK| match ciphers authenticated by RSA, ECDSA, and
+ * a pre-shared key, respectively.
+ *
+ * |RSA|, |DHE|, |ECDHE|, |PSK|, |ECDSA|, and |PSK| are aliases for the
+ * corresponding |k*| or |a*| cipher rule. |RSA| is an alias for |kRSA|, not
+ * |aRSA|.
+ *
+ * |3DES|, |RC4|, |AES128|, |AES256|, |AES|, |AESGCM|, |CHACHA20| match
+ * ciphers whose bulk cipher use the corresponding encryption scheme. Note
+ * that |AES|, |AES128|, and |AES256| match both CBC and GCM ciphers.
+ *
+ * |MD5|, |SHA1|, |SHA256|, and |SHA384| match legacy cipher suites using the
+ * corresponding hash function in their MAC. AEADs are matched by none of
+ * these.
+ *
+ * |SHA| is an alias for |SHA1|.
+ *
+ * Although implemented, authentication-only ciphers match no rules and must be
+ * explicitly selected by name.
+ *
+ * Deprecated cipher rules:
+ *
+ * |kEDH|, |EDH|, |kEECDH|, and |EECDH| are legacy aliases for |kDHE|, |DHE|,
+ * |kECDHE|, and |ECDHE|, respectively.
+ *
+ * |MEDIUM| and |HIGH| match ciphers historically labeled by OpenSSL as
+ * 'medium' and 'high', respectively.
+ *
+ * |FIPS| matches ciphers historically FIPS-approved in OpenSSL.
+ *
+ * |SSLv3| and |TLSv1| match ciphers available in TLS 1.1 or earlier.
+ * |TLSv1_2| matches ciphers new in TLS 1.2. This is confusing and should not
+ * be used.
+ *
+ * Unknown rules silently match nothing.
+ *
+ * The special |@STRENGTH| directive will sort all enabled ciphers by strength.
+ *
+ * The |DEFAULT| directive, when appearing at the front of the string, expands
+ * to the default ordering of available ciphers.
+ *
+ * If configuring a server, one may also configure equal-preference groups to
+ * partially respect the client's preferences when
+ * |SSL_OP_CIPHER_SERVER_PREFERENCE| is enabled. Ciphers in an equal-preference
+ * group have equal priority and use the client order. This may be used to
+ * enforce that AEADs are preferred but select AES-GCM vs. ChaCha20-Poly1305
+ * based on client preferences. An equal-preference is specified with square
+ * brackets, combining multiple selectors separated by |. For example:
+ *
+ * [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]
+ *
+ * Once an equal-preference group is used, future directives must be
+ * opcode-less. */
+
+/* SSL_DEFAULT_CIPHER_LIST is the default cipher suite configuration. It is
+ * substituted when a cipher string starts with 'DEFAULT'. */
+#define SSL_DEFAULT_CIPHER_LIST "ALL"
+
+/* SSL_CTX_set_cipher_list configures the cipher list for |ctx|, evaluating
+ * |str| as a cipher string. It returns one on success and zero on failure. */
+OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str);
+
+/* SSL_CTX_set_cipher_list configures the TLS 1.0+ cipher list for |ctx|,
+ * evaluating |str| as a cipher string. It returns one on success and zero on
+ * failure. If set, servers will use this cipher suite list for TLS 1.0 or
+ * higher. */
+OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str);
+
+/* SSL_CTX_set_cipher_list configures the TLS 1.1+ cipher list for |ctx|,
+ * evaluating |str| as a cipher string. It returns one on success and zero on
+ * failure. If set, servers will use this cipher suite list for TLS 1.1 or
+ * higher. */
+OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str);
+
+/* SSL_set_cipher_list configures the cipher list for |ssl|, evaluating |str| as
+ * a cipher string. It returns one on success and zero on failure. */
+OPENSSL_EXPORT int SSL_set_cipher_list(SSL *ssl, const char *str);
+
+/* SSL_get_ciphers returns the cipher list for |ssl|, in order of preference. If
+ * |SSL_CTX_set_cipher_list_tls10| or |SSL_CTX_set_cipher_list_tls11| has been
+ * used, the corresponding list for the current version is returned. */
+OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl);
+
+
/* Connection information. */
/* SSL_get_peer_certificate returns the peer's leaf certificate or NULL if the
@@ -2310,30 +2435,8 @@
#define SSL_TXT_ALL "ALL"
-/* COMPLEMENTOF* definitions. These identifiers are used to (de-select) ciphers
- * normally not being used.
- *
- * Example: "RC4" will activate all ciphers using RC4 including ciphers without
- * authentication, which would normally disabled by DEFAULT (due the "!ADH"
- * being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" will make sure
- * that it is also disabled in the specific selection. COMPLEMENTOF*
- * identifiers are portable between version, as adjustments to the default
- * cipher setup will also be included here.
- *
- * COMPLEMENTOFDEFAULT does not experience the same special treatment that
- * DEFAULT gets, as only selection is being done and no sorting as needed for
- * DEFAULT. */
#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT"
-/* The following cipher list is used by default. It also is substituted when an
- * application-defined cipher list string starts with 'DEFAULT'. */
-#define SSL_DEFAULT_CIPHER_LIST "ALL"
-
-/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always
- * starts with a reasonable order, and all we have to do for DEFAULT is
- * throwing out anonymous and unencrypted ciphersuites! (The latter are not
- * actually enabled by ALL, but "ALL:RSA" would enable some of them.) */
-
/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
#define SSL_SENT_SHUTDOWN 1
#define SSL_RECEIVED_SHUTDOWN 2
@@ -2536,20 +2639,15 @@
OPENSSL_EXPORT size_t SSL_get0_certificate_types(SSL *ssl,
const uint8_t **out_types);
-OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str);
-OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls10(SSL_CTX *, const char *str);
-OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls11(SSL_CTX *, const char *str);
OPENSSL_EXPORT int SSL_want(const SSL *s);
OPENSSL_EXPORT int SSL_get_fd(const SSL *s);
OPENSSL_EXPORT int SSL_get_rfd(const SSL *s);
OPENSSL_EXPORT int SSL_get_wfd(const SSL *s);
-OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *s, int n);
OPENSSL_EXPORT int SSL_pending(const SSL *s);
OPENSSL_EXPORT int SSL_set_fd(SSL *s, int fd);
OPENSSL_EXPORT int SSL_set_rfd(SSL *s, int fd);
OPENSSL_EXPORT int SSL_set_wfd(SSL *s, int fd);
-OPENSSL_EXPORT int SSL_set_cipher_list(SSL *s, const char *str);
OPENSSL_EXPORT const char *SSL_state_string(const SSL *s);
OPENSSL_EXPORT const char *SSL_state_string_long(const SSL *s);
@@ -2557,8 +2655,6 @@
OPENSSL_EXPORT int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *ses);
OPENSSL_EXPORT int SSL_SESSION_print(BIO *fp, const SSL_SESSION *ses);
-OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
-
/* SSL_renegotiate_pending returns one if |ssl| is in the middle of a
* renegotiation. */
OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl);
@@ -2896,6 +2992,10 @@
* For example, "TLSv1.2" or "SSLv3". */
OPENSSL_EXPORT const char *SSL_get_version(const SSL *ssl);
+/* SSL_get_cipher_list returns the name of the |n|th cipher in the output of
+ * |SSL_get_ciphers| or NULL if out of range. Use |SSL_get_ciphers| insteads. */
+OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *ssl, int n);
+
/* Private structures.
*
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 74bd633..5190a53 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1367,29 +1367,27 @@
return ctx->session_cache_mode;
}
-/* return a STACK of the ciphers available for the SSL and in order of
- * preference */
-STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s) {
- if (s == NULL) {
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) {
+ if (ssl == NULL) {
return NULL;
}
- if (s->cipher_list != NULL) {
- return s->cipher_list->ciphers;
+ if (ssl->cipher_list != NULL) {
+ return ssl->cipher_list->ciphers;
}
- if (s->version >= TLS1_1_VERSION && s->ctx != NULL &&
- s->ctx->cipher_list_tls11 != NULL) {
- return s->ctx->cipher_list_tls11->ciphers;
+ if (ssl->version >= TLS1_1_VERSION && ssl->ctx != NULL &&
+ ssl->ctx->cipher_list_tls11 != NULL) {
+ return ssl->ctx->cipher_list_tls11->ciphers;
}
- if (s->version >= TLS1_VERSION && s->ctx != NULL &&
- s->ctx->cipher_list_tls10 != NULL) {
- return s->ctx->cipher_list_tls10->ciphers;
+ if (ssl->version >= TLS1_VERSION && ssl->ctx != NULL &&
+ ssl->ctx->cipher_list_tls10 != NULL) {
+ return ssl->ctx->cipher_list_tls10->ciphers;
}
- if (s->ctx != NULL && s->ctx->cipher_list != NULL) {
- return s->ctx->cipher_list->ciphers;
+ if (ssl->ctx != NULL && ssl->ctx->cipher_list != NULL) {
+ return ssl->ctx->cipher_list->ciphers;
}
return NULL;
@@ -1413,16 +1411,15 @@
return NULL;
}
-/* The old interface to get the same thing as SSL_get_ciphers() */
-const char *SSL_get_cipher_list(const SSL *s, int n) {
+const char *SSL_get_cipher_list(const SSL *ssl, int n) {
const SSL_CIPHER *c;
STACK_OF(SSL_CIPHER) *sk;
- if (s == NULL) {
+ if (ssl == NULL) {
return NULL;
}
- sk = SSL_get_ciphers(s);
+ sk = SSL_get_ciphers(ssl);
if (sk == NULL || n < 0 || (size_t)n >= sk_SSL_CIPHER_num(sk)) {
return NULL;
}
@@ -1435,20 +1432,15 @@
return c->name;
}
-/* specify the ciphers to be used by default by the SSL_CTX */
int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
- STACK_OF(SSL_CIPHER) *sk;
-
- sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list,
- &ctx->cipher_list_by_id, str);
- /* ssl_create_cipher_list may return an empty stack if it was unable to find
- * a cipher matching the given rule string (for example if the rule string
- * specifies a cipher which has been disabled). This is not an error as far
- * as ssl_create_cipher_list is concerned, and hence ctx->cipher_list and
- * ctx->cipher_list_by_id has been updated. */
- if (sk == NULL) {
+ STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
+ ctx->method, &ctx->cipher_list, &ctx->cipher_list_by_id, str);
+ if (cipher_list == NULL) {
return 0;
- } else if (sk_SSL_CIPHER_num(sk) == 0) {
+ }
+
+ /* |ssl_create_cipher_list| may succeed but return an empty cipher list. */
+ if (sk_SSL_CIPHER_num(cipher_list) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}
@@ -1457,12 +1449,14 @@
}
int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) {
- STACK_OF(SSL_CIPHER) *sk;
-
- sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls10, NULL, str);
- if (sk == NULL) {
+ STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
+ ctx->method, &ctx->cipher_list_tls10, NULL, str);
+ if (cipher_list == NULL) {
return 0;
- } else if (sk_SSL_CIPHER_num(sk) == 0) {
+ }
+
+ /* |ssl_create_cipher_list| may succeed but return an empty cipher list. */
+ if (sk_SSL_CIPHER_num(cipher_list) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}
@@ -1471,12 +1465,14 @@
}
int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) {
- STACK_OF(SSL_CIPHER) *sk;
-
- sk = ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls11, NULL, str);
- if (sk == NULL) {
+ STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
+ ctx->method, &ctx->cipher_list_tls11, NULL, str);
+ if (cipher_list == NULL) {
return 0;
- } else if (sk_SSL_CIPHER_num(sk) == 0) {
+ }
+
+ /* |ssl_create_cipher_list| may succeed but return an empty cipher list. */
+ if (sk_SSL_CIPHER_num(cipher_list) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}
@@ -1484,17 +1480,15 @@
return 1;
}
-/* specify the ciphers to be used by the SSL */
-int SSL_set_cipher_list(SSL *s, const char *str) {
- STACK_OF(SSL_CIPHER) *sk;
-
- sk = ssl_create_cipher_list(s->ctx->method, &s->cipher_list,
- &s->cipher_list_by_id, str);
-
- /* see comment in SSL_CTX_set_cipher_list */
- if (sk == NULL) {
+int SSL_set_cipher_list(SSL *ssl, const char *str) {
+ STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
+ ssl->ctx->method, &ssl->cipher_list, &ssl->cipher_list_by_id, str);
+ if (cipher_list == NULL) {
return 0;
- } else if (sk_SSL_CIPHER_num(sk) == 0) {
+ }
+
+ /* |ssl_create_cipher_list| may succeed but return an empty cipher list. */
+ if (sk_SSL_CIPHER_num(cipher_list) == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHER_MATCH);
return 0;
}