Equal preference cipher groups.
This change implements equal-preference groups of cipher suites. This allows, for example, a server to prefer one of AES-GCM or ChaCha20 ciphers, but to allow the client to pick which one. When coupled with clients that will boost AES-GCM in their preferences when AES-NI is present, this allows us to use AES-GCM when the hardware exists and ChaCha20 otherwise.
This commit is contained in:
parent
c26c802a89
commit
858a88daf2
74
ssl/s3_lib.c
74
ssl/s3_lib.c
@ -3737,15 +3737,40 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p)
|
||||
return(2);
|
||||
}
|
||||
|
||||
struct ssl_cipher_preference_list_st* ssl_get_cipher_preferences(SSL *s)
|
||||
{
|
||||
if (s->cipher_list != NULL)
|
||||
return(s->cipher_list);
|
||||
|
||||
if (s->version >= TLS1_1_VERSION)
|
||||
{
|
||||
if (s->ctx != NULL && s->ctx->cipher_list_tls11 != NULL)
|
||||
return s->ctx->cipher_list_tls11;
|
||||
}
|
||||
|
||||
if ((s->ctx != NULL) && (s->ctx->cipher_list != NULL))
|
||||
return(s->ctx->cipher_list);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
|
||||
STACK_OF(SSL_CIPHER) *srvr)
|
||||
struct ssl_cipher_preference_list_st *server_pref)
|
||||
{
|
||||
SSL_CIPHER *c,*ret=NULL;
|
||||
STACK_OF(SSL_CIPHER) *prio, *allow;
|
||||
STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow;
|
||||
int i,ok;
|
||||
size_t cipher_index;
|
||||
CERT *cert;
|
||||
unsigned long alg_k,alg_a,mask_k,mask_a,emask_k,emask_a;
|
||||
/* in_group_flags will either be NULL, or will point to an array of
|
||||
* bytes which indicate equal-preference groups in the |prio| stack.
|
||||
* See the comment about |in_group_flags| in the
|
||||
* |ssl_cipher_preference_list_st| struct. */
|
||||
const unsigned char *in_group_flags;
|
||||
/* group_min contains the minimal index so far found in a group, or -1
|
||||
* if no such value exists yet. */
|
||||
int group_min = -1;
|
||||
|
||||
/* Let's see which ciphers we can support */
|
||||
cert=s->cert;
|
||||
@ -3778,11 +3803,13 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
|
||||
if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || tls1_suiteb(s))
|
||||
{
|
||||
prio = srvr;
|
||||
in_group_flags = server_pref->in_group_flags;
|
||||
allow = clnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
prio = clnt;
|
||||
in_group_flags = NULL;
|
||||
allow = srvr;
|
||||
}
|
||||
|
||||
@ -3792,10 +3819,12 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
|
||||
{
|
||||
c=sk_SSL_CIPHER_value(prio,i);
|
||||
|
||||
ok = 1;
|
||||
|
||||
/* Skip TLS v1.2 only ciphersuites if not supported */
|
||||
if ((c->algorithm_ssl & SSL_TLSV1_2) &&
|
||||
if ((c->algorithm_ssl & SSL_TLSV1_2) &&
|
||||
!SSL_USE_TLS1_2_CIPHERS(s))
|
||||
continue;
|
||||
ok = 0;
|
||||
|
||||
ssl_set_cert_masks(cert,c);
|
||||
mask_k = cert->mask_k;
|
||||
@ -3813,12 +3842,12 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
|
||||
#ifndef OPENSSL_NO_PSK
|
||||
/* with PSK there must be server callback set */
|
||||
if ((alg_a & SSL_aPSK) && s->psk_server_callback == NULL)
|
||||
continue;
|
||||
ok = 0;
|
||||
#endif /* OPENSSL_NO_PSK */
|
||||
|
||||
if (SSL_C_IS_EXPORT(c))
|
||||
{
|
||||
ok = (alg_k & emask_k) && (alg_a & emask_a);
|
||||
ok = ok && (alg_k & emask_k) && (alg_a & emask_a);
|
||||
#ifdef CIPHER_DEBUG
|
||||
printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s (export)\n",ok,alg_k,alg_a,emask_k,emask_a,
|
||||
(void *)c,c->name);
|
||||
@ -3826,7 +3855,7 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = (alg_k & mask_k) && (alg_a & mask_a);
|
||||
ok = ok && (alg_k & mask_k) && (alg_a & mask_a);
|
||||
#ifdef CIPHER_DEBUG
|
||||
printf("%d:[%08lX:%08lX:%08lX:%08lX]%p:%s\n",ok,alg_k,alg_a,mask_k,mask_a,(void *)c,
|
||||
c->name);
|
||||
@ -3842,17 +3871,32 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
|
||||
#endif /* OPENSSL_NO_EC */
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
|
||||
if (!ok) continue;
|
||||
if (sk_SSL_CIPHER_find(allow, &cipher_index, c))
|
||||
if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c))
|
||||
{
|
||||
#if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLSEXT)
|
||||
if ((alg_k & SSL_kEECDH) && (alg_a & SSL_aECDSA) && s->s3->is_probably_safari)
|
||||
if (in_group_flags != NULL && in_group_flags[i] == 1)
|
||||
{
|
||||
if (!ret) ret=sk_SSL_CIPHER_value(allow, cipher_index);
|
||||
continue;
|
||||
/* This element of |prio| is in a group. Update
|
||||
* the minimum index found so far and continue
|
||||
* looking. */
|
||||
if (group_min == -1 || group_min > cipher_index)
|
||||
group_min = cipher_index;
|
||||
}
|
||||
#endif
|
||||
ret=sk_SSL_CIPHER_value(allow, cipher_index);
|
||||
else
|
||||
{
|
||||
if (group_min != -1 && group_min < cipher_index)
|
||||
cipher_index = group_min;
|
||||
ret=sk_SSL_CIPHER_value(allow,cipher_index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (in_group_flags != NULL &&
|
||||
in_group_flags[i] == 0 &&
|
||||
group_min != -1)
|
||||
{
|
||||
/* We are about to leave a group, but we found a match
|
||||
* in it, so that's our answer. */
|
||||
ret=sk_SSL_CIPHER_value(allow,group_min);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1249,7 +1249,7 @@ int ssl3_get_client_hello(SSL *s)
|
||||
ciphers=NULL;
|
||||
|
||||
/* check if some cipher was preferred by call back */
|
||||
pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
|
||||
pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, ssl_get_cipher_preferences(s));
|
||||
if (pref_cipher == NULL)
|
||||
{
|
||||
al=SSL_AD_HANDSHAKE_FAILURE;
|
||||
@ -1260,12 +1260,12 @@ int ssl3_get_client_hello(SSL *s)
|
||||
s->session->cipher=pref_cipher;
|
||||
|
||||
if (s->cipher_list)
|
||||
sk_SSL_CIPHER_free(s->cipher_list);
|
||||
ssl_cipher_preference_list_free(s->cipher_list);
|
||||
|
||||
if (s->cipher_list_by_id)
|
||||
sk_SSL_CIPHER_free(s->cipher_list_by_id);
|
||||
|
||||
s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
s->cipher_list = ssl_cipher_preference_list_from_ciphers(s->session->ciphers);
|
||||
s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
|
||||
}
|
||||
}
|
||||
@ -1319,7 +1319,7 @@ int ssl3_get_client_hello(SSL *s)
|
||||
s->rwstate = SSL_NOTHING;
|
||||
}
|
||||
c=ssl3_choose_cipher(s,s->session->ciphers,
|
||||
SSL_get_ciphers(s));
|
||||
ssl_get_cipher_preferences(s));
|
||||
|
||||
if (c == NULL)
|
||||
{
|
||||
|
47
ssl/ssl.h
47
ssl/ssl.h
@ -879,18 +879,55 @@ struct ssl_comp_st
|
||||
DECLARE_STACK_OF(SSL_COMP)
|
||||
DECLARE_LHASH_OF(SSL_SESSION);
|
||||
|
||||
/* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with
|
||||
* equal-preference groups. For TLS clients, the groups are moot because the
|
||||
* server picks the cipher and groups cannot be expressed on the wire. However,
|
||||
* for servers, the equal-preference groups allow the client's preferences to
|
||||
* be partially respected. (This only has an effect with
|
||||
* SSL_OP_CIPHER_SERVER_PREFERENCE).
|
||||
*
|
||||
* The equal-preference groups are expressed by grouping SSL_CIPHERs together.
|
||||
* All elements of a group have the same priority: no ordering is expressed
|
||||
* within a group.
|
||||
*
|
||||
* The values in |ciphers| are in one-to-one correspondence with
|
||||
* |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of
|
||||
* bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to
|
||||
* indicate that the corresponding SSL_CIPHER is not the last element of a
|
||||
* group, or 0 to indicate that it is.
|
||||
*
|
||||
* For example, if |in_group_flags| contains all zeros then that indicates a
|
||||
* traditional, fully-ordered preference. Every SSL_CIPHER is the last element
|
||||
* of the group (i.e. they are all in a one-element group).
|
||||
*
|
||||
* For a more complex example, consider:
|
||||
* ciphers: A B C D E F
|
||||
* in_group_flags: 1 1 0 0 1 0
|
||||
*
|
||||
* That would express the following, order:
|
||||
*
|
||||
* A E
|
||||
* B -> D -> F
|
||||
* C
|
||||
*/
|
||||
struct ssl_cipher_preference_list_st
|
||||
{
|
||||
STACK_OF(SSL_CIPHER) *ciphers;
|
||||
unsigned char *in_group_flags;
|
||||
};
|
||||
|
||||
struct ssl_ctx_st
|
||||
{
|
||||
const SSL_METHOD *method;
|
||||
|
||||
STACK_OF(SSL_CIPHER) *cipher_list;
|
||||
struct ssl_cipher_preference_list_st *cipher_list;
|
||||
/* same as above but sorted for lookup */
|
||||
STACK_OF(SSL_CIPHER) *cipher_list_by_id;
|
||||
/* cipher_list_tls11 is the list of ciphers when TLS 1.1 or greater is
|
||||
* in use. This only applies to server connections as, for clients, the
|
||||
* version number is known at connect time and so the cipher list can
|
||||
* be set then. */
|
||||
STACK_OF(SSL_CIPHER) *cipher_list_tls11;
|
||||
struct ssl_cipher_preference_list_st *cipher_list_tls11;
|
||||
|
||||
struct x509_store_st /* X509_STORE */ *cert_store;
|
||||
LHASH_OF(SSL_SESSION) *sessions;
|
||||
@ -1414,7 +1451,7 @@ struct ssl_st
|
||||
#endif
|
||||
|
||||
/* crypto */
|
||||
STACK_OF(SSL_CIPHER) *cipher_list;
|
||||
struct ssl_cipher_preference_list_st *cipher_list;
|
||||
STACK_OF(SSL_CIPHER) *cipher_list_by_id;
|
||||
|
||||
/* These are the ones being used, the ones in SSL_SESSION are
|
||||
@ -3016,5 +3053,9 @@ void ERR_load_SSL_strings(void);
|
||||
#define SSL_R_DTLS_MESSAGE_TOO_BIG 429
|
||||
#define SSL_R_INVALID_SRP_USERNAME 430
|
||||
#define SSL_R_TOO_MANY_EMPTY_FRAGMENTS 431
|
||||
#define SSL_R_NESTED_GROUP 432
|
||||
#define SSL_R_UNEXPECTED_GROUP_CLOSE 433
|
||||
#define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 434
|
||||
#define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 435
|
||||
|
||||
#endif
|
||||
|
170
ssl/ssl_ciph.c
170
ssl/ssl_ciph.c
@ -218,6 +218,7 @@ typedef struct cipher_order_st
|
||||
const SSL_CIPHER *cipher;
|
||||
int active;
|
||||
int dead;
|
||||
int in_group;
|
||||
struct cipher_order_st *next,*prev;
|
||||
} CIPHER_ORDER;
|
||||
|
||||
@ -697,6 +698,7 @@ static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method,
|
||||
co_list[co_list_num].next = NULL;
|
||||
co_list[co_list_num].prev = NULL;
|
||||
co_list[co_list_num].active = 0;
|
||||
co_list[co_list_num].in_group = 0;
|
||||
co_list_num++;
|
||||
#ifdef KSSL_DEBUG
|
||||
printf("\t%d: %s %lx %lx %lx\n",i,c->name,c->id,c->algorithm_mkey,c->algorithm_auth);
|
||||
@ -808,7 +810,7 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
|
||||
unsigned long alg_enc, unsigned long alg_mac,
|
||||
unsigned long alg_ssl,
|
||||
unsigned long algo_strength,
|
||||
int rule, int strength_bits,
|
||||
int rule, int strength_bits, int in_group,
|
||||
CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p)
|
||||
{
|
||||
CIPHER_ORDER *head, *tail, *curr, *curr2, *last;
|
||||
@ -816,8 +818,8 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
|
||||
int reverse = 0;
|
||||
|
||||
#ifdef CIPHER_DEBUG
|
||||
printf("Applying rule %d with %08lx/%08lx/%08lx/%08lx/%08lx %08lx (%d)\n",
|
||||
rule, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, strength_bits);
|
||||
printf("Applying rule %d with %08lx/%08lx/%08lx/%08lx/%08lx %08lx (%d) in_group:%d\n",
|
||||
rule, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, strength_bits, in_group);
|
||||
#endif
|
||||
|
||||
if (rule == CIPHER_DEL)
|
||||
@ -892,6 +894,7 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
|
||||
{
|
||||
ll_append_tail(&head, curr, &tail);
|
||||
curr->active = 1;
|
||||
curr->in_group = in_group;
|
||||
}
|
||||
}
|
||||
/* Move the added cipher to this location */
|
||||
@ -901,6 +904,7 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
|
||||
if (curr->active)
|
||||
{
|
||||
ll_append_tail(&head, curr, &tail);
|
||||
curr->in_group = 0;
|
||||
}
|
||||
}
|
||||
else if (rule == CIPHER_DEL)
|
||||
@ -913,6 +917,7 @@ static void ssl_cipher_apply_rule(unsigned long cipher_id,
|
||||
* works in reverse to maintain the order) */
|
||||
ll_append_head(&head, curr, &tail);
|
||||
curr->active = 0;
|
||||
curr->in_group = 0;
|
||||
}
|
||||
}
|
||||
else if (rule == CIPHER_KILL)
|
||||
@ -983,7 +988,7 @@ static int ssl_cipher_strength_sort(CIPHER_ORDER **head_p,
|
||||
*/
|
||||
for (i = max_strength_bits; i >= 0; i--)
|
||||
if (number_uses[i] > 0)
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, head_p, tail_p);
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ORD, i, 0, head_p, tail_p);
|
||||
|
||||
OPENSSL_free(number_uses);
|
||||
return(1);
|
||||
@ -995,7 +1000,8 @@ static int ssl_cipher_process_rulestr(const char *rule_str,
|
||||
{
|
||||
unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength;
|
||||
const char *l, *buf;
|
||||
int j, multi, found, rule, retval, ok, buflen;
|
||||
int j, multi, found, rule, retval, ok, buflen, in_group = 0,
|
||||
has_group = 0;
|
||||
unsigned long cipher_id = 0;
|
||||
char ch;
|
||||
|
||||
@ -1007,14 +1013,68 @@ static int ssl_cipher_process_rulestr(const char *rule_str,
|
||||
|
||||
if (ch == '\0')
|
||||
break; /* done */
|
||||
if (ch == '-')
|
||||
if (in_group)
|
||||
{
|
||||
if (ch == ']')
|
||||
{
|
||||
if (!in_group)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_UNEXPECTED_GROUP_CLOSE);
|
||||
retval = found = in_group = 0;
|
||||
break;
|
||||
}
|
||||
if (*tail_p)
|
||||
(*tail_p)->in_group = 0;
|
||||
in_group = 0;
|
||||
l++;
|
||||
continue;
|
||||
}
|
||||
if (ch == '|')
|
||||
{ rule = CIPHER_ADD; l++; continue; }
|
||||
else if (!(ch >= 'a' && ch <= 'z') &&
|
||||
!(ch >= 'A' && ch <= 'Z') &&
|
||||
!(ch >= '0' && ch <= '9'))
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP);
|
||||
retval = found = in_group = 0;
|
||||
break;
|
||||
}
|
||||
else
|
||||
rule = CIPHER_ADD;
|
||||
}
|
||||
else if (ch == '-')
|
||||
{ rule = CIPHER_DEL; l++; }
|
||||
else if (ch == '+')
|
||||
{ rule = CIPHER_ORD; l++; }
|
||||
else if (ch == '!' && has_group)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
|
||||
retval = found = in_group = 0;
|
||||
break;
|
||||
}
|
||||
else if (ch == '!')
|
||||
{ rule = CIPHER_KILL; l++; }
|
||||
else if (ch == '@' && has_group)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS);
|
||||
retval = found = in_group = 0;
|
||||
break;
|
||||
}
|
||||
else if (ch == '@')
|
||||
{ rule = CIPHER_SPECIAL; l++; }
|
||||
else if (ch == '[')
|
||||
{
|
||||
if (in_group)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP);
|
||||
retval = found = in_group = 0;
|
||||
break;
|
||||
}
|
||||
in_group = 1;
|
||||
has_group = 1;
|
||||
l++;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ rule = CIPHER_ADD; }
|
||||
|
||||
@ -1057,7 +1117,7 @@ static int ssl_cipher_process_rulestr(const char *rule_str,
|
||||
* alphanumeric, so we call this an error.
|
||||
*/
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND);
|
||||
retval = found = 0;
|
||||
retval = found = in_group = 0;
|
||||
l++;
|
||||
break;
|
||||
}
|
||||
@ -1224,7 +1284,7 @@ static int ssl_cipher_process_rulestr(const char *rule_str,
|
||||
{
|
||||
ssl_cipher_apply_rule(cipher_id,
|
||||
alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength,
|
||||
rule, -1, head_p, tail_p);
|
||||
rule, -1, in_group, head_p, tail_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1234,6 +1294,12 @@ static int ssl_cipher_process_rulestr(const char *rule_str,
|
||||
if (*l == '\0') break; /* done */
|
||||
}
|
||||
|
||||
if (in_group)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND);
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
return(retval);
|
||||
}
|
||||
#ifndef OPENSSL_NO_EC
|
||||
@ -1297,16 +1363,19 @@ static int check_suiteb_cipher_list(const SSL_METHOD *meth, CERT *c,
|
||||
|
||||
|
||||
STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
|
||||
STACK_OF(SSL_CIPHER) **cipher_list,
|
||||
struct ssl_cipher_preference_list_st **cipher_list,
|
||||
STACK_OF(SSL_CIPHER) **cipher_list_by_id,
|
||||
const char *rule_str, CERT *c)
|
||||
{
|
||||
int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases;
|
||||
unsigned long disabled_mkey, disabled_auth, disabled_enc, disabled_mac, disabled_ssl;
|
||||
STACK_OF(SSL_CIPHER) *cipherstack, *tmp_cipher_list;
|
||||
STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL;
|
||||
const char *rule_p;
|
||||
CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
|
||||
const SSL_CIPHER **ca_list = NULL;
|
||||
unsigned char *in_group_flags = NULL;
|
||||
unsigned int num_in_group_flags = 0;
|
||||
struct ssl_cipher_preference_list_st *pref_list = NULL;
|
||||
|
||||
/*
|
||||
* Return with error if nothing to do.
|
||||
@ -1348,32 +1417,32 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
|
||||
/* Now arrange all ciphers by preference: */
|
||||
|
||||
/* Everything else being equal, prefer ephemeral ECDH over other key exchange mechanisms */
|
||||
ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_ADD, -1, 0, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kEECDH, 0, 0, 0, 0, 0, CIPHER_DEL, -1, 0, &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);
|
||||
ssl_cipher_apply_rule(0, 0, 0, SSL_AES, 0, 0, 0, CIPHER_ADD, -1, 0, &head, &tail);
|
||||
|
||||
/* Temporarily enable everything else for sorting */
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_ADD, -1, 0, &head, &tail);
|
||||
|
||||
/* Low priority for MD5 */
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, SSL_MD5, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
|
||||
/* Move anonymous ciphers to the end. Usually, these will remain disabled.
|
||||
* (For applications that allow them, they aren't too bad, but we prefer
|
||||
* authenticated ciphers.) */
|
||||
ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, 0, SSL_aNULL, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
|
||||
/* Move ciphers without forward secrecy to the end */
|
||||
ssl_cipher_apply_rule(0, 0, SSL_aECDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
/* ssl_cipher_apply_rule(0, 0, SSL_aDH, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail); */
|
||||
ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kPSK, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kKRB5, 0,0, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, 0, SSL_aECDH, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
/* ssl_cipher_apply_rule(0, 0, SSL_aDH, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail); */
|
||||
ssl_cipher_apply_rule(0, SSL_kRSA, 0, 0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kPSK, 0,0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, SSL_kKRB5, 0,0, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
|
||||
/* RC4 is sort-of broken -- move the the end */
|
||||
ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, 0, 0, SSL_RC4, 0, 0, 0, CIPHER_ORD, -1, 0, &head, &tail);
|
||||
|
||||
/* Now sort by symmetric encryption strength. The above ordering remains
|
||||
* in force within each class */
|
||||
@ -1384,7 +1453,7 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
|
||||
}
|
||||
|
||||
/* Now disable everything (maintaining the ordering!) */
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, &head, &tail);
|
||||
ssl_cipher_apply_rule(0, 0, 0, 0, 0, 0, 0, CIPHER_DEL, -1, 0, &head, &tail);
|
||||
|
||||
|
||||
/*
|
||||
@ -1429,21 +1498,18 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
|
||||
OPENSSL_free((void *)ca_list); /* Not needed anymore */
|
||||
|
||||
if (!ok)
|
||||
{ /* Rule processing failure */
|
||||
OPENSSL_free(co_list);
|
||||
return(NULL);
|
||||
}
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Allocate new "cipherstack" for the result, return with error
|
||||
* if we cannot get one.
|
||||
*/
|
||||
if ((cipherstack = sk_SSL_CIPHER_new_null()) == NULL)
|
||||
{
|
||||
OPENSSL_free(co_list);
|
||||
return(NULL);
|
||||
}
|
||||
goto err;
|
||||
|
||||
in_group_flags = OPENSSL_malloc(num_of_ciphers);
|
||||
if (!in_group_flags)
|
||||
goto err;
|
||||
/*
|
||||
* The cipher selection for the list is done. The ciphers are added
|
||||
* to the resulting precedence to the STACK_OF(SSL_CIPHER).
|
||||
@ -1457,35 +1523,65 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method,
|
||||
#endif
|
||||
{
|
||||
sk_SSL_CIPHER_push(cipherstack, curr->cipher);
|
||||
in_group_flags[num_in_group_flags++] = curr->in_group;
|
||||
#ifdef CIPHER_DEBUG
|
||||
printf("<%s>\n",curr->cipher->name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
OPENSSL_free(co_list); /* Not needed any longer */
|
||||
co_list = NULL;
|
||||
|
||||
tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack);
|
||||
if (tmp_cipher_list == NULL)
|
||||
{
|
||||
sk_SSL_CIPHER_free(cipherstack);
|
||||
return NULL;
|
||||
}
|
||||
goto err;
|
||||
pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st));
|
||||
if (!pref_list)
|
||||
goto err;
|
||||
pref_list->ciphers = cipherstack;
|
||||
pref_list->in_group_flags = OPENSSL_malloc(num_in_group_flags);
|
||||
if (!pref_list->in_group_flags)
|
||||
goto err;
|
||||
memcpy(pref_list->in_group_flags, in_group_flags, num_in_group_flags);
|
||||
OPENSSL_free(in_group_flags);
|
||||
in_group_flags = NULL;
|
||||
if (*cipher_list != NULL)
|
||||
sk_SSL_CIPHER_free(*cipher_list);
|
||||
*cipher_list = cipherstack;
|
||||
ssl_cipher_preference_list_free(*cipher_list);
|
||||
*cipher_list = pref_list;
|
||||
pref_list = NULL;
|
||||
|
||||
if (cipher_list_by_id != NULL)
|
||||
{
|
||||
if (*cipher_list_by_id != NULL)
|
||||
sk_SSL_CIPHER_free(*cipher_list_by_id);
|
||||
*cipher_list_by_id = tmp_cipher_list;
|
||||
tmp_cipher_list = NULL;
|
||||
(void)sk_SSL_CIPHER_set_cmp_func(*cipher_list_by_id,ssl_cipher_ptr_id_cmp);
|
||||
|
||||
sk_SSL_CIPHER_sort(*cipher_list_by_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
sk_SSL_CIPHER_free(tmp_cipher_list);
|
||||
tmp_cipher_list = NULL;
|
||||
}
|
||||
|
||||
return(cipherstack);
|
||||
|
||||
err:
|
||||
if (co_list)
|
||||
OPENSSL_free(co_list);
|
||||
if (in_group_flags)
|
||||
OPENSSL_free(in_group_flags);
|
||||
if (cipherstack)
|
||||
sk_SSL_CIPHER_free(cipherstack);
|
||||
if (tmp_cipher_list)
|
||||
sk_SSL_CIPHER_free(tmp_cipher_list);
|
||||
if (pref_list && pref_list->in_group_flags)
|
||||
OPENSSL_free(pref_list->in_group_flags);
|
||||
if (pref_list)
|
||||
OPENSSL_free(pref_list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len)
|
||||
|
@ -348,7 +348,9 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_RSA_KEY), "MISSING_TMP_RSA_KEY"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_RSA_PKEY), "MISSING_TMP_RSA_PKEY"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_VERIFY_MESSAGE), "MISSING_VERIFY_MESSAGE"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS), "MIXED_SPECIAL_OPERATOR_WITH_GROUPS"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MULTIPLE_SGC_RESTARTS), "MULTIPLE_SGC_RESTARTS"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NESTED_GROUP), "NESTED_GROUP"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NON_SSLV2_INITIAL_PACKET), "NON_SSLV2_INITIAL_PACKET"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATES_RETURNED), "NO_CERTIFICATES_RETURNED"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_ASSIGNED), "NO_CERTIFICATE_ASSIGNED"},
|
||||
@ -491,7 +493,9 @@ const ERR_STRING_DATA SSL_error_string_data[] = {
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES), "UNABLE_TO_LOAD_SSL2_MD5_ROUTINES"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES), "UNABLE_TO_LOAD_SSL3_MD5_ROUTINES"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES), "UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_GROUP_CLOSE), "UNEXPECTED_GROUP_CLOSE"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "UNEXPECTED_MESSAGE"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP), "UNEXPECTED_OPERATOR_IN_GROUP"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_RECORD), "UNEXPECTED_RECORD"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNINITIALIZED), "UNINITIALIZED"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_ALERT_TYPE), "UNKNOWN_ALERT_TYPE"},
|
||||
|
@ -250,9 +250,13 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx,const SSL_METHOD *meth)
|
||||
|
||||
ctx->method=meth;
|
||||
|
||||
sk=ssl_create_cipher_list(ctx->method,&(ctx->cipher_list),
|
||||
&(ctx->cipher_list_by_id),
|
||||
meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, ctx->cert);
|
||||
sk=ssl_create_cipher_list(
|
||||
ctx->method, &ctx->cipher_list, &ctx->cipher_list_by_id,
|
||||
meth->version == SSL2_VERSION ?
|
||||
"SSLv2" :
|
||||
SSL_DEFAULT_CIPHER_LIST,
|
||||
ctx->cert);
|
||||
|
||||
if ((sk == NULL) || (sk_SSL_CIPHER_num(sk) <= 0))
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_CTX_set_ssl_version, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS);
|
||||
@ -520,6 +524,71 @@ int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm)
|
||||
return X509_VERIFY_PARAM_set1(ssl->param, vpm);
|
||||
}
|
||||
|
||||
void ssl_cipher_preference_list_free(
|
||||
struct ssl_cipher_preference_list_st *cipher_list)
|
||||
{
|
||||
sk_SSL_CIPHER_free(cipher_list->ciphers);
|
||||
OPENSSL_free(cipher_list->in_group_flags);
|
||||
OPENSSL_free(cipher_list);
|
||||
}
|
||||
|
||||
struct ssl_cipher_preference_list_st*
|
||||
ssl_cipher_preference_list_dup(
|
||||
struct ssl_cipher_preference_list_st *cipher_list)
|
||||
{
|
||||
struct ssl_cipher_preference_list_st* ret = NULL;
|
||||
size_t n = sk_SSL_CIPHER_num(cipher_list->ciphers);
|
||||
|
||||
ret = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st));
|
||||
if (!ret)
|
||||
goto err;
|
||||
ret->ciphers = NULL;
|
||||
ret->in_group_flags = NULL;
|
||||
ret->ciphers = sk_SSL_CIPHER_dup(cipher_list->ciphers);
|
||||
if (!ret->ciphers)
|
||||
goto err;
|
||||
ret->in_group_flags = OPENSSL_malloc(n);
|
||||
if (!ret->in_group_flags)
|
||||
goto err;
|
||||
memcpy(ret->in_group_flags, cipher_list->in_group_flags, n);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
if (ret->ciphers)
|
||||
sk_SSL_CIPHER_free(ret->ciphers);
|
||||
if (ret)
|
||||
OPENSSL_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ssl_cipher_preference_list_st*
|
||||
ssl_cipher_preference_list_from_ciphers(STACK_OF(SSL_CIPHER) *ciphers)
|
||||
{
|
||||
struct ssl_cipher_preference_list_st* ret = NULL;
|
||||
size_t n = sk_SSL_CIPHER_num(ciphers);
|
||||
|
||||
ret = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st));
|
||||
if (!ret)
|
||||
goto err;
|
||||
ret->ciphers = NULL;
|
||||
ret->in_group_flags = NULL;
|
||||
ret->ciphers = sk_SSL_CIPHER_dup(ciphers);
|
||||
if (!ret->ciphers)
|
||||
goto err;
|
||||
ret->in_group_flags = OPENSSL_malloc(n);
|
||||
if (!ret->in_group_flags)
|
||||
goto err;
|
||||
memset(ret->in_group_flags, 0, n);
|
||||
return ret;
|
||||
|
||||
err:
|
||||
if (ret->ciphers)
|
||||
sk_SSL_CIPHER_free(ret->ciphers);
|
||||
if (ret)
|
||||
OPENSSL_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx)
|
||||
{
|
||||
return ctx->param;
|
||||
@ -578,7 +647,8 @@ void SSL_free(SSL *s)
|
||||
if (s->init_buf != NULL) BUF_MEM_free(s->init_buf);
|
||||
|
||||
/* add extra stuff */
|
||||
if (s->cipher_list != NULL) sk_SSL_CIPHER_free(s->cipher_list);
|
||||
if (s->cipher_list != NULL)
|
||||
ssl_cipher_preference_list_free(s->cipher_list);
|
||||
if (s->cipher_list_by_id != NULL) sk_SSL_CIPHER_free(s->cipher_list_by_id);
|
||||
|
||||
/* Make the next call work :-) */
|
||||
@ -1313,19 +1383,19 @@ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s)
|
||||
|
||||
if (s->cipher_list != NULL)
|
||||
{
|
||||
return(s->cipher_list);
|
||||
return(s->cipher_list->ciphers);
|
||||
}
|
||||
|
||||
if (s->version >= TLS1_1_VERSION)
|
||||
{
|
||||
if (s->ctx != NULL && s->ctx->cipher_list_tls11 != NULL)
|
||||
return s->ctx->cipher_list_tls11;
|
||||
return s->ctx->cipher_list_tls11->ciphers;
|
||||
}
|
||||
|
||||
if ((s->ctx != NULL) &&
|
||||
(s->ctx->cipher_list != NULL))
|
||||
{
|
||||
return(s->ctx->cipher_list);
|
||||
return(s->ctx->cipher_list->ciphers);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
@ -1981,7 +2051,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
|
||||
&ret->cipher_list,&ret->cipher_list_by_id,
|
||||
meth->version == SSL2_VERSION ? "SSLv2" : SSL_DEFAULT_CIPHER_LIST, ret->cert);
|
||||
if (ret->cipher_list == NULL
|
||||
|| sk_SSL_CIPHER_num(ret->cipher_list) <= 0)
|
||||
|| sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, SSL_CTX_new, SSL_R_LIBRARY_HAS_NO_CIPHERS);
|
||||
goto err2;
|
||||
@ -2145,11 +2215,11 @@ void SSL_CTX_free(SSL_CTX *a)
|
||||
if (a->cert_store != NULL)
|
||||
X509_STORE_free(a->cert_store);
|
||||
if (a->cipher_list != NULL)
|
||||
sk_SSL_CIPHER_free(a->cipher_list);
|
||||
ssl_cipher_preference_list_free(a->cipher_list);
|
||||
if (a->cipher_list_by_id != NULL)
|
||||
sk_SSL_CIPHER_free(a->cipher_list_by_id);
|
||||
if (a->cipher_list_tls11 != NULL)
|
||||
sk_SSL_CIPHER_free(a->cipher_list_tls11);
|
||||
ssl_cipher_preference_list_free(a->cipher_list_tls11);
|
||||
if (a->cert != NULL)
|
||||
ssl_cert_free(a->cert);
|
||||
if (a->client_CA != NULL)
|
||||
|
@ -1004,10 +1004,17 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,unsigned char *p,int num,
|
||||
int ssl_cipher_list_to_bytes(SSL *s,STACK_OF(SSL_CIPHER) *sk,unsigned char *p,
|
||||
int (*put_cb)(const SSL_CIPHER *, unsigned char *));
|
||||
STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth,
|
||||
STACK_OF(SSL_CIPHER) **pref,
|
||||
struct ssl_cipher_preference_list_st **pref,
|
||||
STACK_OF(SSL_CIPHER) **sorted,
|
||||
const char *rule_str, CERT *c);
|
||||
void ssl_update_cache(SSL *s, int mode);
|
||||
struct ssl_cipher_preference_list_st* ssl_cipher_preference_list_dup(
|
||||
struct ssl_cipher_preference_list_st *cipher_list);
|
||||
void ssl_cipher_preference_list_free(
|
||||
struct ssl_cipher_preference_list_st *cipher_list);
|
||||
struct ssl_cipher_preference_list_st* ssl_cipher_preference_list_from_ciphers(
|
||||
STACK_OF(SSL_CIPHER) *ciphers);
|
||||
struct ssl_cipher_preference_list_st* ssl_get_cipher_preferences(SSL *s);
|
||||
int ssl_cipher_get_comp(const SSL_SESSION *s, SSL_COMP **comp);
|
||||
int ssl_cipher_get_evp_aead(const SSL_SESSION *s, const EVP_AEAD **aead);
|
||||
int ssl_cipher_get_evp(const SSL_SESSION *s,const EVP_CIPHER **enc,
|
||||
@ -1106,7 +1113,7 @@ int n_ssl3_mac(SSL *ssl, unsigned char *md, int send_data);
|
||||
void ssl3_free_digest_list(SSL *s);
|
||||
unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk);
|
||||
SSL_CIPHER *ssl3_choose_cipher(SSL *ssl,STACK_OF(SSL_CIPHER) *clnt,
|
||||
STACK_OF(SSL_CIPHER) *srvr);
|
||||
struct ssl_cipher_preference_list_st *srvr);
|
||||
int ssl3_setup_buffers(SSL *s);
|
||||
int ssl3_setup_read_buffer(SSL *s);
|
||||
int ssl3_setup_write_buffer(SSL *s);
|
||||
|
Loading…
Reference in New Issue
Block a user