summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorLutz Jänicke <jaenicke@openssl.org>2001-02-09 19:56:31 +0000
committerLutz Jänicke <jaenicke@openssl.org>2001-02-09 19:56:31 +0000
commit836f996010d6a5f38d9a13279c37e84a42819966 (patch)
treee5188ce6a43977577a5efb7884da010b9805c993 /ssl
parent1613c4d3bff02bd2715e0e8a61356e82f9c0e147 (diff)
New Option SSL_OP_CIPHER_SERVER_PREFERENCE allows TLS/SSLv3 server to override
the clients choice; in SSLv2 the client uses the server's preferences.
Diffstat (limited to 'ssl')
-rw-r--r--ssl/s2_clnt.c32
-rw-r--r--ssl/s2_srvr.c29
-rw-r--r--ssl/s3_lib.c46
-rw-r--r--ssl/s3_srvr.c4
-rw-r--r--ssl/ssl.h3
-rw-r--r--ssl/ssl_locl.h4
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)
{
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 6b7487724f..9fa02fda0b 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -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);