Commit 07df5018 authored by Rob Stradling's avatar Rob Stradling Committed by Ben Laurie
Browse files

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.
parent 1b9a59c3
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -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

+13 −3
Original line number Diff line number Diff line
@@ -3066,7 +3066,10 @@ void ssl3_clear(SSL *s)
		s->s3->tlsext_custom_types = NULL;
		}
	s->s3->tlsext_custom_types_count = 0;	
#endif
#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;
@@ -4128,11 +4131,18 @@ SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt,
		if (!ok) continue;
		ii=sk_SSL_CIPHER_find(allow,c);
		if (ii >= 0)
			{
			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);
	}

+1 −1
Original line number Diff line number Diff line
@@ -615,7 +615,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
+9 −1
Original line number Diff line number Diff line
@@ -580,7 +580,15 @@ typedef struct ssl3_state_st
	 * as the types were received in the client hello. */
	unsigned short *tlsext_custom_types;
	size_t tlsext_custom_types_count; /* how many tlsext_custom_types */
#endif

#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
+89 −0
Original line number Diff line number Diff line
@@ -1762,6 +1762,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 */

static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) 
	{	
	unsigned short type;
@@ -1781,6 +1864,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
	s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
	                       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 */

	/* Clear any signature algorithms extension received */
	if (s->cert->peer_sigalgs)
		{