diff options
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/s2_clnt.c | 32 | ||||
-rw-r--r-- | ssl/s2_srvr.c | 29 | ||||
-rw-r--r-- | ssl/s3_lib.c | 46 | ||||
-rw-r--r-- | ssl/s3_srvr.c | 4 | ||||
-rw-r--r-- | ssl/ssl.h | 3 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 4 |
6 files changed, 90 insertions, 28 deletions
diff --git a/ssl/s2_clnt.c b/ssl/s2_clnt.c index 28d6d65296..3e06286375 100644 --- a/ssl/s2_clnt.c +++ b/ssl/s2_clnt.c @@ -287,7 +287,7 @@ static int get_server_hello(SSL *s) unsigned char *buf; unsigned char *p; int i,j; - STACK_OF(SSL_CIPHER) *sk=NULL,*cl; + STACK_OF(SSL_CIPHER) *sk=NULL,*cl, *prio, *allow; buf=(unsigned char *)s->init_buf->data; p=buf; @@ -414,27 +414,43 @@ static int get_server_hello(SSL *s) sk_SSL_CIPHER_set_cmp_func(sk,ssl_cipher_ptr_id_cmp); /* get the array of ciphers we will accept */ - cl=ssl_get_ciphers_by_id(s); - + cl=SSL_get_ciphers(s); + sk_SSL_CIPHER_set_cmp_func(cl,ssl_cipher_ptr_id_cmp); + + /* + * If server preference flag set, choose the first + * (highest priority) cipher the server sends, otherwise + * client preference has priority. + */ + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) + { + prio = sk; + allow = cl; + } + else + { + prio = cl; + allow = sk; + } /* In theory we could have ciphers sent back that we * don't want to use but that does not matter since we * will check against the list we originally sent and * for performance reasons we should not bother to match * the two lists up just to check. */ - for (i=0; i<sk_SSL_CIPHER_num(cl); i++) + for (i=0; i<sk_SSL_CIPHER_num(prio); i++) { - if (sk_SSL_CIPHER_find(sk, - sk_SSL_CIPHER_value(cl,i)) >= 0) + if (sk_SSL_CIPHER_find(allow, + sk_SSL_CIPHER_value(prio,i)) >= 0) break; } - if (i >= sk_SSL_CIPHER_num(cl)) + if (i >= sk_SSL_CIPHER_num(prio)) { ssl2_return_error(s,SSL2_PE_NO_CIPHER); SSLerr(SSL_F_GET_SERVER_HELLO,SSL_R_NO_CIPHER_MATCH); return(-1); } - s->session->cipher=sk_SSL_CIPHER_value(cl,i); + s->session->cipher=sk_SSL_CIPHER_value(prio,i); if (s->session->peer != NULL) /* can't happen*/ diff --git a/ssl/s2_srvr.c b/ssl/s2_srvr.c index 1ed02540ae..974d6e6de7 100644 --- a/ssl/s2_srvr.c +++ b/ssl/s2_srvr.c @@ -450,6 +450,7 @@ static int get_client_hello(SSL *s) unsigned char *p; STACK_OF(SSL_CIPHER) *cs; /* a stack of SSL_CIPHERS */ STACK_OF(SSL_CIPHER) *cl; /* the ones we want to use */ + STACK_OF(SSL_CIPHER) *prio, *allow; int z; /* This is a bit of a hack to check for the correct packet @@ -555,21 +556,37 @@ static int get_client_hello(SSL *s) &s->session->ciphers); if (cs == NULL) goto mem_err; - cl=ssl_get_ciphers_by_id(s); + cl=SSL_get_ciphers(s); - for (z=0; z<sk_SSL_CIPHER_num(cs); z++) + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) + { + prio=sk_SSL_CIPHER_dup(cl); + if (prio == NULL) goto mem_err; + allow = cs; + } + else + { + prio = cs; + allow = cl; + } + for (z=0; z<sk_SSL_CIPHER_num(prio); z++) { - if (sk_SSL_CIPHER_find(cl,sk_SSL_CIPHER_value(cs,z)) < 0) + if (sk_SSL_CIPHER_find(allow,sk_SSL_CIPHER_value(prio,z)) < 0) { - sk_SSL_CIPHER_delete(cs,z); + sk_SSL_CIPHER_delete(prio,z); z--; } } - + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) + { + sk_SSL_CIPHER_free(s->session->ciphers); + s->session->ciphers = prio; + } /* s->session->ciphers should now have a list of * ciphers that are on both the client and server. * This list is ordered by the order the client sent - * the ciphers. + * the ciphers or in the order of the server's preference + * if SSL_OP_CIPHER_SERVER_PREFERENCE was set. */ } p+=s->s2->tmp.cipher_spec_length; diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 700a4ddbbf..76c499e67a 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -1364,10 +1364,11 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) return(2); } -SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *have, - STACK_OF(SSL_CIPHER) *pref) +SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, + STACK_OF(SSL_CIPHER) *srvr) { SSL_CIPHER *c,*ret=NULL; + STACK_OF(SSL_CIPHER) *prio, *allow; int i,j,ok; CERT *cert; unsigned long alg,mask,emask; @@ -1375,20 +1376,45 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *have, /* Let's see which ciphers we can support */ cert=s->cert; - sk_SSL_CIPHER_set_cmp_func(pref,ssl_cipher_ptr_id_cmp); +#if 0 + /* Do not set the compare functions, because this may lead to a + * reordering by "id". We want to keep the original ordering. + * We may pay a price in performance during sk_SSL_CIPHER_find(), + * but would have to pay with the price of sk_SSL_CIPHER_dup(). + */ + sk_SSL_CIPHER_set_cmp_func(srvr, ssl_cipher_ptr_id_cmp); + sk_SSL_CIPHER_set_cmp_func(clnt, ssl_cipher_ptr_id_cmp); +#endif #ifdef CIPHER_DEBUG - printf("Have %d from %p:\n", sk_SSL_CIPHER_num(pref), pref); - for(i=0 ; i < sk_SSL_CIPHER_num(pref) ; ++i) + printf("Server has %d from %p:\n", sk_SSL_CIPHER_num(srvr), srvr); + for(i=0 ; i < sk_SSL_CIPHER_num(srvr) ; ++i) + { + c=sk_SSL_CIPHER_value(srvr,i); + printf("%p:%s\n",c,c->name); + } + printf("Client sent %d from %p:\n", sk_SSL_CIPHER_num(clnt), clnt); + for(i=0 ; i < sk_SSL_CIPHER_num(clnt) ; ++i) { - c=sk_SSL_CIPHER_value(pref,i); + c=sk_SSL_CIPHER_value(clnt,i); printf("%p:%s\n",c,c->name); } #endif - for (i=0; i<sk_SSL_CIPHER_num(have); i++) + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) + { + prio = srvr; + allow = clnt; + } + else + { + prio = clnt; + allow = srvr; + } + + for (i=0; i<sk_SSL_CIPHER_num(prio); i++) { - c=sk_SSL_CIPHER_value(have,i); + c=sk_SSL_CIPHER_value(prio,i); ssl_set_cert_masks(cert,c); mask=cert->mask; @@ -1418,10 +1444,10 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *have, if (!ok) continue; - j=sk_SSL_CIPHER_find(pref,c); + j=sk_SSL_CIPHER_find(allow,c); if (j >= 0) { - ret=sk_SSL_CIPHER_value(pref,j); + ret=sk_SSL_CIPHER_value(allow,j); break; } } diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 54e0a03057..4841109c4b 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -755,7 +755,7 @@ static int ssl3_get_client_hello(SSL *s) } } - /* Given s->session->ciphers and ssl_get_ciphers_by_id(s), we must + /* Given s->session->ciphers and SSL_get_ciphers, we must * pick a cipher */ if (!s->hit) @@ -772,7 +772,7 @@ static int ssl3_get_client_hello(SSL *s) } ciphers=NULL; c=ssl3_choose_cipher(s,s->session->ciphers, - ssl_get_ciphers_by_id(s)); + SSL_get_ciphers(s)); if (c == NULL) { @@ -337,6 +337,9 @@ typedef struct ssl_session_st #define SSL_OP_SINGLE_DH_USE 0x00100000L /* Set to also use the tmp_rsa key when doing RSA operations. */ #define SSL_OP_EPHEMERAL_RSA 0x00200000L +/* Set on servers to choose the cipher according to the server's + * preferences */ +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L /* The next flag deliberately changes the ciphertest, this is a check * for the PKCS#1 attack */ diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index cc45cbddd0..f0ee7443aa 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -565,8 +565,8 @@ void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len); int ssl3_enc(SSL *s, int send_data); int ssl3_mac(SSL *ssl, unsigned char *md, int send_data); unsigned long ssl3_output_cert_chain(SSL *s, X509 *x); -SSL_CIPHER *ssl3_choose_cipher(SSL *ssl,STACK_OF(SSL_CIPHER) *have, - STACK_OF(SSL_CIPHER) *pref); +SSL_CIPHER *ssl3_choose_cipher(SSL *ssl,STACK_OF(SSL_CIPHER) *clnt, + STACK_OF(SSL_CIPHER) *srvr); int ssl3_setup_buffers(SSL *s); int ssl3_new(SSL *s); void ssl3_free(SSL *s); |