From: Rob Stradling Date: Mon, 9 Sep 2013 11:52:41 +0000 (+0100) Subject: Don't prefer ECDHE-ECDSA ciphers when the client appears to be Safari on OS X. X-Git-Tag: OpenSSL_1_0_1f~50 X-Git-Url: http://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=4b61f6d2a675fdb57dc93991e7b332a745b44d1f Don't prefer ECDHE-ECDSA ciphers when the client appears to be Safari on OS X. OS X 10.8..10.8.3 has broken support for ECDHE-ECDSA ciphers. --- diff --git a/doc/ssl/SSL_CTX_set_options.pod b/doc/ssl/SSL_CTX_set_options.pod index cc588f3..fded060 100644 --- a/doc/ssl/SSL_CTX_set_options.pod +++ b/doc/ssl/SSL_CTX_set_options.pod @@ -88,9 +88,10 @@ As of OpenSSL 0.9.8q and 1.0.0c, this option has no effect. ... -=item SSL_OP_MSIE_SSLV2_RSA_PADDING +=item SSL_OP_SAFARI_ECDHE_ECDSA_BUG -As of OpenSSL 0.9.7h and 0.9.8a, this option has no effect. +Don't prefer ECDHE-ECDSA ciphers when the client appears to be Safari on OS X. +OS X 10.8..10.8.3 has broken support for ECDHE-ECDSA ciphers. =item SSL_OP_SSLEAY_080_CLIENT_DH_BUG diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index e7c5dcb..5539d22 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3037,6 +3037,11 @@ void ssl3_clear(SSL *s) s->s3->tmp.ecdh = NULL; } #endif +#ifndef OPENSSL_NO_TLSEXT +#ifndef OPENSSL_NO_EC + s->s3->is_probably_safari = 0; +#endif /* OPENSSL_NO_EC */ +#endif /* OPENSSL_NO_TLSEXT */ rp = s->s3->rbuf.buf; wp = s->s3->wbuf.buf; @@ -4016,8 +4021,15 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, ii=sk_SSL_CIPHER_find(allow,c); if (ii >= 0) { - ret=sk_SSL_CIPHER_value(allow,ii); - break; + if ((alg_k & SSL_kEECDH) && (alg_a & SSL_aECDSA) && s->s3->is_probably_safari) + { + if (!ret) ret=sk_SSL_CIPHER_value(allow,ii); + } + else + { + ret=sk_SSL_CIPHER_value(allow,ii); + break; + } } } return(ret); diff --git a/ssl/ssl.h b/ssl/ssl.h index 593579e..c48990e 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -555,7 +555,7 @@ struct ssl_session_st #define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008L #define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x00000010L #define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L -#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0x00000040L /* no effect since 0.9.7h and 0.9.8b */ +#define SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040L #define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080L #define SSL_OP_TLS_D5_BUG 0x00000100L #define SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200L diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 247e88c..208b392 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -539,6 +539,15 @@ typedef struct ssl3_state_st /* Set if we saw the Next Protocol Negotiation extension from our peer. */ int next_proto_neg_seen; #endif + +#ifndef OPENSSL_NO_TLSEXT +#ifndef OPENSSL_NO_EC + /* This is set to true if we believe that this is a version of Safari + * running on OS X 10.6 or newer. We wish to know this because Safari + * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */ + char is_probably_safari; +#endif /* OPENSSL_NO_EC */ +#endif /* OPENSSL_NO_TLSEXT */ } SSL3_STATE; #endif diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index e08088c..4afc3a2 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -866,6 +866,89 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha return ret; } +#ifndef OPENSSL_NO_EC +/* ssl_check_for_safari attempts to fingerprint Safari using OS X + * SecureTransport using the TLS extension block in |d|, of length |n|. + * Safari, since 10.6, sends exactly these extensions, in this order: + * SNI, + * elliptic_curves + * ec_point_formats + * + * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8, + * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them. + * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from + * 10.8..10.8.3 (which don't work). + */ +static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) { + unsigned short type, size; + static const unsigned char kSafariExtensionsBlock[] = { + 0x00, 0x0a, /* elliptic_curves extension */ + 0x00, 0x08, /* 8 bytes */ + 0x00, 0x06, /* 6 bytes of curve ids */ + 0x00, 0x17, /* P-256 */ + 0x00, 0x18, /* P-384 */ + 0x00, 0x19, /* P-521 */ + + 0x00, 0x0b, /* ec_point_formats */ + 0x00, 0x02, /* 2 bytes */ + 0x01, /* 1 point format */ + 0x00, /* uncompressed */ + }; + + /* The following is only present in TLS 1.2 */ + static const unsigned char kSafariTLS12ExtensionsBlock[] = { + 0x00, 0x0d, /* signature_algorithms */ + 0x00, 0x0c, /* 12 bytes */ + 0x00, 0x0a, /* 10 bytes */ + 0x05, 0x01, /* SHA-384/RSA */ + 0x04, 0x01, /* SHA-256/RSA */ + 0x02, 0x01, /* SHA-1/RSA */ + 0x04, 0x03, /* SHA-256/ECDSA */ + 0x02, 0x03, /* SHA-1/ECDSA */ + }; + + if (data >= (d+n-2)) + return; + data += 2; + + if (data > (d+n-4)) + return; + n2s(data,type); + n2s(data,size); + + if (type != TLSEXT_TYPE_server_name) + return; + + if (data+size > d+n) + return; + data += size; + + if (TLS1_get_version(s) >= TLS1_2_VERSION) + { + const size_t len1 = sizeof(kSafariExtensionsBlock); + const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock); + + if (data + len1 + len2 != d+n) + return; + if (memcmp(data, kSafariExtensionsBlock, len1) != 0) + return; + if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0) + return; + } + else + { + const size_t len = sizeof(kSafariExtensionsBlock); + + if (data + len != d+n) + return; + if (memcmp(data, kSafariExtensionsBlock, len) != 0) + return; + } + + s->s3->is_probably_safari = 1; +} +#endif /* OPENSSL_NO_EC */ + int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) { unsigned short type; @@ -886,6 +969,11 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in SSL_TLSEXT_HB_DONT_SEND_REQUESTS); #endif +#ifndef OPENSSL_NO_EC + if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) + ssl_check_for_safari(s, data, d, n); +#endif /* OPENSSL_NO_EC */ + if (data >= (d+n-2)) goto ri_check; n2s(data,len);