提交 836f9960 编写于 作者: L Lutz Jänicke

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.
上级 1613c4d3
......@@ -3,6 +3,12 @@
Changes between 0.9.6 and 0.9.7 [xx XXX 2000]
*) New option SSL_OP_CIPHER_SERVER_PREFERENCE allows the server to override
the clients preferred ciphersuites and rather use its own preferences.
Should help to work around M$ SGC (Server Gated Cryptography) bug in
Internet Explorer by ensuring unchanged hash method during stepup.
[Lutz Jaenicke]
*) Make mkdef.pl recognise all DECLARE_ASN1 macros, change rijndael
to aes and add a new 'exist' option to print out symbols that don't
appear to exist.
......
......@@ -151,6 +151,7 @@ static void sc_usage(void)
BIO_printf(bio_err," -tls1 - just use TLSv1\n");
BIO_printf(bio_err," -no_tls1/-no_ssl3/-no_ssl2 - turn off that protocol\n");
BIO_printf(bio_err," -bugs - Switch on all SSL implementation bug workarounds\n");
BIO_printf(bio_err," -serverpref - Use server's cipher preferences (only SSLv2)\n");
BIO_printf(bio_err," -cipher - preferred cipher to use, use the 'openssl ciphers'\n");
BIO_printf(bio_err," command to see what is available\n");
BIO_printf(bio_err," -engine id - Initialise and use the specified engine\n");
......@@ -311,6 +312,8 @@ int MAIN(int argc, char **argv)
off|=SSL_OP_NO_SSLv3;
else if (strcmp(*argv,"-no_ssl2") == 0)
off|=SSL_OP_NO_SSLv2;
else if (strcmp(*argv,"-serverpref") == 0)
off|=SSL_OP_CIPHER_SERVER_PREFERENCE;
else if (strcmp(*argv,"-cipher") == 0)
{
if (--argc < 1) goto bad;
......
......@@ -231,6 +231,7 @@ static void sv_usage(void)
BIO_printf(bio_err," -CAfile arg - PEM format file of CA's\n");
BIO_printf(bio_err," -nocert - Don't use any certificates (Anon-DH)\n");
BIO_printf(bio_err," -cipher arg - play with 'openssl ciphers' to see what goes here\n");
BIO_printf(bio_err," -serverpref - Use server's cipher preferences\n");
BIO_printf(bio_err," -quiet - No server output\n");
BIO_printf(bio_err," -no_tmp_rsa - Do not generate a tmp RSA key\n");
BIO_printf(bio_err," -ssl2 - Just talk SSLv2\n");
......@@ -508,6 +509,8 @@ int MAIN(int argc, char *argv[])
if (--argc < 1) goto bad;
CApath= *(++argv);
}
else if (strcmp(*argv,"-serverpref") == 0)
{ off|=SSL_OP_CIPHER_SERVER_PREFERENCE; }
else if (strcmp(*argv,"-cipher") == 0)
{
if (--argc < 1) goto bad;
......
......@@ -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*/
......
......@@ -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;
......
......@@ -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;
}
}
......
......@@ -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 */
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册