#ifndef OPENSSL_NO_ENGINE
# include <openssl/engine.h>
#endif
+#include "internal/threads.h"
#include "ssl_locl.h"
#define SSL_ENC_DES_IDX 0
static STACK_OF(SSL_COMP) *ssl_comp_methods = NULL;
+static CRYPTO_ONCE ssl_load_builtin_comp_once = CRYPTO_ONCE_STATIC_INIT;
+
/*
* Constant SSL_MAX_DIGEST equal to size of digests array should be defined
* in the ssl_locl.h
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
+static const ssl_cipher_table ssl_cipher_table_kx[] = {
+ { SSL_kRSA, NID_kx_rsa },
+ { SSL_kECDHE, NID_kx_ecdhe },
+ { SSL_kDHE, NID_kx_dhe },
+ { SSL_kECDHEPSK, NID_kx_ecdhe_psk },
+ { SSL_kDHEPSK, NID_kx_dhe_psk },
+ { SSL_kRSAPSK, NID_kx_rsa_psk },
+ { SSL_kPSK, NID_kx_psk },
+ { SSL_kSRP, NID_kx_srp },
+ { SSL_kGOST, NID_kx_gost }
+};
+
+static const ssl_cipher_table ssl_cipher_table_auth[] = {
+ { SSL_aRSA, NID_auth_rsa },
+ { SSL_aECDSA, NID_auth_ecdsa },
+ { SSL_aPSK, NID_auth_psk },
+ { SSL_aDSS, NID_auth_dss },
+ { SSL_aGOST01, NID_auth_gost01 },
+ { SSL_aGOST12, NID_auth_gost12 },
+ { SSL_aSRP, NID_auth_srp },
+ { SSL_aNULL, NID_auth_null }
+};
+
/* Utility function for table lookup */
static int ssl_cipher_info_find(const ssl_cipher_table * table,
size_t table_cnt, uint32_t mask)
#define CIPHER_DEL 3
#define CIPHER_ORD 4
#define CIPHER_SPECIAL 5
+/*
+ * Bump the ciphers to the top of the list.
+ * This rule isn't currently supported by the public cipherstring API.
+ */
+#define CIPHER_BUMP 6
typedef struct cipher_order_st {
const SSL_CIPHER *cipher;
* "COMPLEMENTOFDEFAULT" (does *not* include ciphersuites not found in
* ALL!)
*/
- {0, SSL_TXT_CMPDEF, 0, 0, 0, ~SSL_eNULL, 0, 0, SSL_NOT_DEFAULT, 0, 0, 0},
+ {0, SSL_TXT_CMPDEF, 0, 0, 0, 0, 0, 0, SSL_NOT_DEFAULT, 0, 0, 0},
/*
* key exchange aliases (some of those using only a single bit here
return ((*a)->id - (*b)->id);
}
-static void load_builtin_compressions(void)
+static void do_load_builtin_compressions(void)
{
- int got_write_lock = 0;
-
- CRYPTO_r_lock(CRYPTO_LOCK_SSL);
- if (ssl_comp_methods == NULL) {
- CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
- CRYPTO_w_lock(CRYPTO_LOCK_SSL);
- got_write_lock = 1;
-
- if (ssl_comp_methods == NULL) {
- SSL_COMP *comp = NULL;
- COMP_METHOD *method = COMP_zlib();
-
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
- ssl_comp_methods = sk_SSL_COMP_new(sk_comp_cmp);
- if (COMP_get_type(method) != NID_undef
- && ssl_comp_methods != NULL) {
- comp = OPENSSL_malloc(sizeof(*comp));
- if (comp != NULL) {
- comp->method = method;
- comp->id = SSL_COMP_ZLIB_IDX;
- comp->name = COMP_get_name(method);
- sk_SSL_COMP_push(ssl_comp_methods, comp);
- sk_SSL_COMP_sort(ssl_comp_methods);
- }
- }
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+ SSL_COMP *comp = NULL;
+ COMP_METHOD *method = COMP_zlib();
+
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE);
+ ssl_comp_methods = sk_SSL_COMP_new(sk_comp_cmp);
+
+ if (COMP_get_type(method) != NID_undef && ssl_comp_methods != NULL) {
+ comp = OPENSSL_malloc(sizeof(*comp));
+ if (comp != NULL) {
+ comp->method = method;
+ comp->id = SSL_COMP_ZLIB_IDX;
+ comp->name = COMP_get_name(method);
+ sk_SSL_COMP_push(ssl_comp_methods, comp);
+ sk_SSL_COMP_sort(ssl_comp_methods);
}
}
+ CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE);
+}
- if (got_write_lock)
- CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
- else
- CRYPTO_r_unlock(CRYPTO_LOCK_SSL);
+static void load_builtin_compressions(void)
+{
+ CRYPTO_THREAD_run_once(&ssl_load_builtin_comp_once,
+ do_load_builtin_compressions);
}
#endif
algo_strength, strength_bits);
#endif
- if (rule == CIPHER_DEL)
+ if (rule == CIPHER_DEL || rule == CIPHER_BUMP)
reverse = 1; /* needed to maintain sorting between
* currently deleted ciphers */
ll_append_head(&head, curr, &tail);
curr->active = 0;
}
+ } else if (rule == CIPHER_BUMP) {
+ if (curr->active)
+ ll_append_head(&head, curr, &tail);
} else if (rule == CIPHER_KILL) {
/* reverse == 0 */
if (head == curr)
disabled_mac, disabled_ssl, co_list, &head,
&tail);
- /* Now arrange all ciphers by preference: */
+ /* Now arrange all ciphers by preference. */
/*
* Everything else being equal, prefer ephemeral ECDH over other key
- * exchange mechanisms
+ * exchange mechanisms.
+ * For consistency, prefer ECDSA over RSA (though this only matters if the
+ * server has both certificates, and is using the DEFAULT, or a client
+ * preference).
*/
+ ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, 0, 0, 0, 0, CIPHER_ADD,
+ -1, &head, &tail);
ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head,
&tail);
ssl_cipher_apply_rule(0, SSL_kECDHE, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head,
&tail);
- /* AES is our preferred symmetric cipher */
- ssl_cipher_apply_rule(0, 0, 0, SSL_AES, 0, 0, 0, CIPHER_ADD, -1, &head,
- &tail);
+
+ /* Within each strength group, we prefer GCM over CHACHA... */
+ ssl_cipher_apply_rule(0, 0, 0, SSL_AESGCM, 0, 0, 0, CIPHER_ADD, -1,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, 0, 0, SSL_CHACHA20, 0, 0, 0, CIPHER_ADD, -1,
+ &head, &tail);
+
+ /*
+ * ...and generally, our preferred cipher is AES.
+ * Note that AEADs will be bumped to take preference after sorting by
+ * strength.
+ */
+ ssl_cipher_apply_rule(0, 0, 0, SSL_AES ^ SSL_AESGCM, 0, 0, 0, CIPHER_ADD,
+ -1, &head, &tail);
/* Temporarily enable everything else for sorting */
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
return NULL;
}
+ /*
+ * Partially overrule strength sort to prefer TLS 1.2 ciphers/PRFs.
+ * TODO(openssl-team): is there an easier way to accomplish all this?
+ */
+ ssl_cipher_apply_rule(0, 0, 0, 0, 0, SSL_TLSV1_2, 0, CIPHER_BUMP, -1,
+ &head, &tail);
+
+ /*
+ * Irrespective of strength, enforce the following order:
+ * (EC)DHE + AEAD > (EC)DHE > rest of AEAD > rest.
+ * Within each group, ciphers remain sorted by strength and previous
+ * preference, i.e.,
+ * 1) ECDHE > DHE
+ * 2) GCM > CHACHA
+ * 3) AES > rest
+ * 4) TLS 1.2 > legacy
+ *
+ * Because we now bump ciphers to the top of the list, we proceed in
+ * reverse order of preference.
+ */
+ ssl_cipher_apply_rule(0, 0, 0, 0, SSL_AEAD, 0, 0, CIPHER_BUMP, -1,
+ &head, &tail);
+ ssl_cipher_apply_rule(0, SSL_kDHE | SSL_kECDHE, 0, 0, 0, 0, 0,
+ CIPHER_BUMP, -1, &head, &tail);
+ ssl_cipher_apply_rule(0, SSL_kDHE | SSL_kECDHE, 0, 0, SSL_AEAD, 0, 0,
+ CIPHER_BUMP, -1, &head, &tail);
+
/* Now disable everything (maintaining the ordering!) */
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
const SSL_CIPHER *ssl_get_cipher_by_char(SSL *ssl, const unsigned char *ptr)
{
- const SSL_CIPHER *c;
- c = ssl->method->get_cipher_by_char(ptr);
+ const SSL_CIPHER *c = ssl->method->get_cipher_by_char(ptr);
+
if (c == NULL || c->valid == 0)
return NULL;
return c;
{
int i;
if (c == NULL)
- return -1;
+ return NID_undef;
i = ssl_cipher_info_lookup(ssl_cipher_table_cipher, c->algorithm_enc);
if (i == -1)
- return -1;
+ return NID_undef;
return ssl_cipher_table_cipher[i].nid;
}
int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *c)
{
- int i;
- if (c == NULL)
- return -1;
- i = ssl_cipher_info_lookup(ssl_cipher_table_mac, c->algorithm_mac);
+ int i = ssl_cipher_info_lookup(ssl_cipher_table_mac, c->algorithm_mac);
+
if (i == -1)
- return -1;
+ return NID_undef;
return ssl_cipher_table_mac[i].nid;
}
+
+int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *c)
+{
+ int i = ssl_cipher_info_lookup(ssl_cipher_table_kx, c->algorithm_mkey);
+
+ if (i == -1)
+ return NID_undef;
+ return ssl_cipher_table_kx[i].nid;
+}
+
+int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *c)
+{
+ int i = ssl_cipher_info_lookup(ssl_cipher_table_auth, c->algorithm_auth);
+
+ if (i == -1)
+ return NID_undef;
+ return ssl_cipher_table_auth[i].nid;
+}
+
+int SSL_CIPHER_is_aead(const SSL_CIPHER *c)
+{
+ return (c->algorithm_mac & SSL_AEAD) ? 1 : 0;
+}