From 805a2e9e1388f21bd381a8c55e66bae2e6325667 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Fri, 25 Nov 2016 23:19:56 +0000 Subject: [PATCH 1/1] Provide server side extension init and finalisation functions Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich Salz Reviewed-by: Rich Salz Reviewed-by: Richard Levitte --- include/openssl/ssl.h | 1 + ssl/ssl_err.c | 1 + ssl/statem/extensions.c | 265 ++++++++++++++++++++++++++++++----- ssl/statem/extensions_srvr.c | 108 -------------- ssl/statem/statem_srvr.c | 112 +++++++++------ 5 files changed, 305 insertions(+), 182 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 2a9d0de6c8..9dd87d16e5 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2308,6 +2308,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET 460 # define SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST 461 # define SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP 462 +# define SSL_F_TLS_EXT_FINAL_RENEGOTIATE 483 # define SSL_F_TLS_GET_MESSAGE_BODY 351 # define SSL_F_TLS_GET_MESSAGE_HEADER 387 # define SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT 449 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index ce74d4497e..11c63c7390 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -338,6 +338,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { "tls_construct_server_status_request"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP), "tls_construct_server_use_srtp"}, + {ERR_FUNC(SSL_F_TLS_EXT_FINAL_RENEGOTIATE), "tls_ext_final_renegotiate"}, {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_BODY), "tls_get_message_body"}, {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_HEADER), "tls_get_message_header"}, {ERR_FUNC(SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT), diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index a50756a071..c6c9813d45 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -11,12 +11,31 @@ #include "../ssl_locl.h" #include "statem_locl.h" +static int tls_ext_final_renegotiate(SSL *s, unsigned int context, int sent, + int *al); +static int tls_ext_init_server_name(SSL *s, unsigned int context); +static int tls_ext_final_server_name(SSL *s, unsigned int context, int sent, + int *al); +static int tls_ext_init_status_request(SSL *s, unsigned int context); +#ifndef OPENSSL_NO_NEXTPROTONEG +static int tls_ext_init_npn(SSL *s, unsigned int context); +#endif +static int tls_ext_init_alpn(SSL *s, unsigned int context); +static int tls_ext_init_sig_algs(SSL *s, unsigned int context); +#ifndef OPENSSL_NO_SRP +static int tls_ext_init_srp(SSL *s, unsigned int context); +#endif +static int tls_ext_init_etm(SSL *s, unsigned int context); +#ifndef OPENSSL_NO_SRTP +static int tls_ext_init_srtp(SSL *s, unsigned int context); +#endif + typedef struct { /* The ID for the extension */ unsigned int type; /* - * Initialise extension before parsing. Always called even if extension not - * present + * Initialise extension before parsing. Always called for relevant contexts + * even if extension not present */ int (*init_ext)(SSL *s, unsigned int context); /* Parse extension received by server from client */ @@ -28,10 +47,11 @@ typedef struct { /* Construct extension sent by client */ int (*construct_client_ext)(SSL *s, WPACKET *pkt, int *al); /* - * Finalise extension after parsing. Always called even if extension not - * present + * Finalise extension after parsing. Always called where an extensions was + * initialised even if the extension was not present. |sent| is set to 1 if + * the extension was seen, or 0 otherwise. */ - int (*finalise_ext)(SSL *s, unsigned int context); + int (*finalise_ext)(SSL *s, unsigned int context, int sent, int *al); unsigned int context; } EXTENSION_DEFINITION; @@ -48,31 +68,31 @@ static const EXTENSION_DEFINITION ext_defs[] = { tls_parse_server_renegotiate, tls_construct_server_renegotiate, tls_construct_client_renegotiate, - NULL, + tls_ext_final_renegotiate, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_SSL3_ALLOWED | EXT_TLS1_2_AND_BELOW_ONLY }, { TLSEXT_TYPE_server_name, - NULL, + tls_ext_init_server_name, tls_parse_client_server_name, tls_parse_server_server_name, tls_construct_server_server_name, tls_construct_client_server_name, - NULL, + tls_ext_final_server_name, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, #ifndef OPENSSL_NO_SRP { TLSEXT_TYPE_srp, - NULL, + tls_ext_init_srp, tls_parse_client_srp, NULL, NULL, tls_construct_client_srp, NULL, - EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY + EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, #endif #ifndef OPENSSL_NO_EC @@ -109,7 +129,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { }, { TLSEXT_TYPE_signature_algorithms, - NULL, + tls_ext_init_sig_algs, tls_parse_client_sig_algs, NULL, NULL, @@ -120,7 +140,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { #ifndef OPENSSL_NO_OCSP { TLSEXT_TYPE_status_request, - NULL, + tls_ext_init_status_request, tls_parse_client_status_request, tls_parse_server_status_request, tls_construct_server_status_request, @@ -133,7 +153,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { #ifndef OPENSSL_NO_NEXTPROTONEG { TLSEXT_TYPE_next_proto_neg, - NULL, + tls_ext_init_npn, tls_parse_client_npn, tls_parse_server_npn, tls_construct_server_next_proto_neg, @@ -144,7 +164,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { #endif { TLSEXT_TYPE_application_layer_protocol_negotiation, - NULL, + tls_ext_init_alpn, tls_parse_client_alpn, tls_parse_server_alpn, tls_construct_server_alpn, @@ -156,7 +176,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { #ifndef OPENSSL_NO_SRTP { TLSEXT_TYPE_use_srtp, - NULL, + tls_ext_init_srtp, tls_parse_client_use_srtp, tls_parse_server_use_srtp, tls_construct_server_use_srtp, @@ -168,7 +188,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { #endif { TLSEXT_TYPE_encrypt_then_mac, - NULL, + tls_ext_init_etm, tls_parse_client_etm, tls_parse_server_etm, tls_construct_server_etm, @@ -329,6 +349,21 @@ static int find_extension_definition(SSL *s, unsigned int type, return 0; } +static int extension_is_relevant(SSL *s, unsigned int extctx, + unsigned int thisctx) +{ + if ((SSL_IS_DTLS(s) + && (extctx & EXT_TLS_IMPLEMENTATION_ONLY) != 0) + || (s->version == SSL3_VERSION + && (extctx & EXT_SSL3_ALLOWED) == 0) + || (SSL_IS_TLS13(s) + && (extctx & EXT_TLS1_2_AND_BELOW_ONLY) != 0) + || (!SSL_IS_TLS13(s) && (extctx & EXT_TLS1_3_ONLY) != 0)) + return 0; + + return 1; +} + /* * Gather a list of all the extensions from the data in |packet]. |context| * tells us which message this extension is for. Ttls_parse_server_ec_pt_formatshe raw extension data is @@ -413,12 +448,20 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context, */ for (i = 0; i < OSSL_NELEM(ext_defs); i++) { if(ext_defs[i].init_ext != NULL && (ext_defs[i].context & context) != 0 + && extension_is_relevant(s, ext_defs[i].context, context) && !ext_defs[i].init_ext(s, context)) { *ad = SSL_AD_INTERNAL_ERROR; goto err; } } + /* + * Initialise server side custom extensions. Client side is done during + * construction of extensions for the ClientHello. + */ + if ((context & (EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_SERVER_HELLO)) != 0) + custom_ext_init(&s->cert->srv_ext); + *res = raw_extensions; *numfound = num_extensions; return 1; @@ -429,12 +472,14 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context, } /* - * Parse all remaining extensions that have not yet been parsed. Also calls the - * finalisation for all extensions at the end. Returns 1 for success or 0 for - * failure. On failure, |*al| is populated with a suitable alert code. + * Runs the parsers for all of the extensions in the given list |exts|, which + * should have |numexts| extensions in it. The parsers are only run if they are + * applicable for the given |context| and the parser has not already been run + * for that extension. Returns 1 on success or 0 on failure. In the event of a + * failure |*al| is populated with a suitable alert code. */ -int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, - size_t numexts, int *al) +static int tls_parse_extension_list(SSL *s, int context, RAW_EXTENSION *exts, + size_t numexts, int *al) { size_t loop; @@ -461,14 +506,7 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, : extdef->parse_server_ext; /* Check if extension is defined for our protocol. If not, skip */ - if ((SSL_IS_DTLS(s) - && (extdef->context & EXT_TLS_IMPLEMENTATION_ONLY) != 0) - || (s->version == SSL3_VERSION - && (extdef->context & EXT_SSL3_ALLOWED) == 0) - || (SSL_IS_TLS13(s) - && (extdef->context & EXT_TLS1_2_AND_BELOW_ONLY) != 0) - || (!SSL_IS_TLS13(s) - && (extdef->context & EXT_TLS1_3_ONLY) != 0)) + if (!extension_is_relevant(s, extdef->context, context)) continue; } @@ -497,15 +535,44 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, return 0; } + return 1; +} + +/* + * Parse all remaining extensions that have not yet been parsed. Also calls the + * finalisation for all extensions at the end. The given extensions must be in + * order of type (which happens by default during collection). Returns 1 for + * success or 0 for failure. On failure, |*al| is populated with a suitable + * alert code. + */ +int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, + size_t numexts, int *al) +{ + size_t loop; + + if (!tls_parse_extension_list(s, context, exts, numexts, al)) + return 0; + /* * Finalise all known extensions relevant to this context, whether we have * found them or not */ for (loop = 0; loop < OSSL_NELEM(ext_defs); loop++) { if(ext_defs[loop].finalise_ext != NULL - && (ext_defs[loop].context & context) != 0 - && !ext_defs[loop].finalise_ext(s, context)) { - *al = SSL_AD_INTERNAL_ERROR; + && (ext_defs[loop].context & context) != 0) { + size_t curr; + + /* + * Work out whether this extension was sent or not. The sent + * extensions in |exts| are sorted by order of type + */ + for (curr = 0; curr < numexts + && exts[curr].type < ext_defs[loop].type; curr++) + continue; + + if (!ext_defs[loop].finalise_ext(s, context, + (curr < numexts && exts[curr].type == ext_defs[loop].type), + al)) return 0; } } @@ -527,7 +594,7 @@ int tls_parse_extension(SSL *s, int type, int context, RAW_EXTENSION *exts, if (ext == NULL) return 1; - return tls_parse_all_extensions(s, context, ext, 1, al); + return tls_parse_extension_list(s, context, ext, 1, al); } int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, @@ -624,3 +691,135 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, return 1; } + +static int tls_ext_final_renegotiate(SSL *s, unsigned int context, int sent, + int *al) +{ + if (!s->server) + return 1; + + /* Need RI if renegotiating */ + if (s->renegotiate + && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) + && !sent) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_EXT_FINAL_RENEGOTIATE, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return 1; +} + +static int tls_ext_init_server_name(SSL *s, unsigned int context) +{ + if (s->server) + s->servername_done = 0; + + return 1; +} + +/* Call the servername callback. Returns 1 for success or 0 for failure. */ +static int tls_ext_final_server_name(SSL *s, unsigned int context, int sent, + int *al) +{ + int ret = SSL_TLSEXT_ERR_NOACK; + int altmp = SSL_AD_UNRECOGNIZED_NAME; + + if (!s->server) + return 1; + + if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) + ret = s->ctx->tlsext_servername_callback(s, &altmp, + s->ctx->tlsext_servername_arg); + else if (s->initial_ctx != NULL + && s->initial_ctx->tlsext_servername_callback != 0) + ret = s->initial_ctx->tlsext_servername_callback(s, &altmp, + s->initial_ctx->tlsext_servername_arg); + + switch (ret) { + case SSL_TLSEXT_ERR_ALERT_FATAL: + *al = altmp; + return 0; + + case SSL_TLSEXT_ERR_ALERT_WARNING: + *al = altmp; + return 1; + + case SSL_TLSEXT_ERR_NOACK: + s->servername_done = 0; + return 1; + + default: + return 1; + } +} + +static int tls_ext_init_status_request(SSL *s, unsigned int context) +{ + if (s->server) + s->tlsext_status_type = -1; + + return 1; +} + +#ifndef OPENSSL_NO_NEXTPROTONEG +static int tls_ext_init_npn(SSL *s, unsigned int context) +{ + if (s->server) + s->s3->next_proto_neg_seen = 0; + + return 1; +} +#endif + +static int tls_ext_init_alpn(SSL *s, unsigned int context) +{ + if (s->server) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + s->s3->alpn_selected_len = 0; + OPENSSL_free(s->s3->alpn_proposed); + s->s3->alpn_proposed = NULL; + s->s3->alpn_proposed_len = 0; + } + + return 1; +} + +static int tls_ext_init_sig_algs(SSL *s, unsigned int context) +{ + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3->tmp.peer_sigalgs); + s->s3->tmp.peer_sigalgs = NULL; + + return 1; +} + +#ifndef OPENSSL_NO_SRP +static int tls_ext_init_srp(SSL *s, unsigned int context) +{ + OPENSSL_free(s->srp_ctx.login); + s->srp_ctx.login = NULL; + + return 1; +} +#endif + +static int tls_ext_init_etm(SSL *s, unsigned int context) +{ + if (s->server) + s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC; + + return 1; +} + +#ifndef OPENSSL_NO_SRTP +static int tls_ext_init_srtp(SSL *s, unsigned int context) +{ + if (s->server) + s->srtp_profile = NULL; + + return 1; +} +#endif diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 70898891e2..5a796cee5a 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -648,71 +648,6 @@ int tls_parse_client_ems(SSL *s, PACKET *pkt, int *al) return 1; } -#ifndef OPENSSL_NO_EC -/*- - * ssl_check_for_safari attempts to fingerprint Safari using OS X - * SecureTransport using the TLS extension block in |hello|. - * 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 CLIENTHELLO_MSG *hello) -{ - unsigned int type; - PACKET sni, tmppkt; - size_t ext_len; - - 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 */ - 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 */ - }; - - /* Length of the common prefix (first two extensions). */ - static const size_t kSafariCommonExtensionsLength = 18; - - tmppkt = hello->extensions; - - if (!PACKET_forward(&tmppkt, 2) - || !PACKET_get_net_2(&tmppkt, &type) - || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) { - return; - } - - if (type != TLSEXT_TYPE_server_name) - return; - - ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ? - sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength; - - s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock, - ext_len); -} -#endif /* !OPENSSL_NO_EC */ - /* * Process all remaining ClientHello extensions that we collected earlier and * haven't already processed. @@ -724,37 +659,6 @@ static void ssl_check_for_safari(SSL *s, const CLIENTHELLO_MSG *hello) */ int tls_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al) { - /* Reset various flags that might get set by extensions during parsing */ - s->servername_done = 0; - s->tlsext_status_type = -1; -#ifndef OPENSSL_NO_NEXTPROTONEG - s->s3->next_proto_neg_seen = 0; -#endif - - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; - s->s3->alpn_selected_len = 0; - OPENSSL_free(s->s3->alpn_proposed); - s->s3->alpn_proposed = NULL; - s->s3->alpn_proposed_len = 0; - -#ifndef OPENSSL_NO_EC - if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) - ssl_check_for_safari(s, hello); -#endif /* !OPENSSL_NO_EC */ - - /* Clear any signature algorithms extension received */ - OPENSSL_free(s->s3->tmp.peer_sigalgs); - s->s3->tmp.peer_sigalgs = NULL; - s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC; - -#ifndef OPENSSL_NO_SRP - OPENSSL_free(s->srp_ctx.login); - s->srp_ctx.login = NULL; -#endif - - s->srtp_profile = NULL; - /* * We process the supported_groups extension first so that is done before * we get to key_share which needs to use the information in it. @@ -764,18 +668,6 @@ int tls_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al) return 0; } - /* Need RI if renegotiating */ - if (s->renegotiate - && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) - && tls_get_extension_by_type(hello->pre_proc_exts, - hello->num_extensions, - TLSEXT_TYPE_renegotiate) == NULL) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; - } - return tls_parse_all_extensions(s, EXT_CLIENT_HELLO, hello->pre_proc_exts, hello->num_extensions, al); } diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 14fa0ed028..bfdd4383f1 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1062,41 +1062,6 @@ int dtls_construct_hello_verify_request(SSL *s, WPACKET *pkt) return 1; } -/* - * Check the results of extension parsing. Currently just calls the servername - * callback. Returns 1 for success or 0 for failure. - */ -static int tls_check_clienthello_tlsext(SSL *s) -{ - int ret = SSL_TLSEXT_ERR_NOACK; - int al = SSL_AD_UNRECOGNIZED_NAME; - - if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) - ret = s->ctx->tlsext_servername_callback(s, &al, - s->ctx->tlsext_servername_arg); - else if (s->initial_ctx != NULL - && s->initial_ctx->tlsext_servername_callback != 0) - ret = s->initial_ctx->tlsext_servername_callback(s, &al, - s->initial_ctx->tlsext_servername_arg); - - switch (ret) { - case SSL_TLSEXT_ERR_ALERT_FATAL: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - return 0; - - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(s, SSL3_AL_WARNING, al); - return 1; - - case SSL_TLSEXT_ERR_NOACK: - s->servername_done = 0; - return 1; - - default: - return 1; - } -} - /* * Parse the extensions in the ClientHello that were collected earlier. Returns * 1 for success or 0 for failure. @@ -1105,21 +1070,81 @@ static int tls_parse_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello) { int al = -1; - custom_ext_init(&s->cert->srv_ext); + if (tls_scan_clienthello_tlsext(s, hello, &al) <= 0) { ssl3_send_alert(s, SSL3_AL_FATAL, al); return 0; } - if (!tls_check_clienthello_tlsext(s)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_TLSEXT, SSL_R_CLIENTHELLO_TLSEXT); - return 0; - } - return 1; } +#ifndef OPENSSL_NO_EC +/*- + * ssl_check_for_safari attempts to fingerprint Safari using OS X + * SecureTransport using the TLS extension block in |hello|. + * 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 CLIENTHELLO_MSG *hello) +{ + unsigned int type; + PACKET sni, tmppkt; + size_t ext_len; + + 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 */ + 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 */ + }; + + /* Length of the common prefix (first two extensions). */ + static const size_t kSafariCommonExtensionsLength = 18; + + tmppkt = hello->extensions; + + if (!PACKET_forward(&tmppkt, 2) + || !PACKET_get_net_2(&tmppkt, &type) + || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) { + return; + } + + if (type != TLSEXT_TYPE_server_name) + return; + + ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ? + sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength; + + s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock, + ext_len); +} +#endif /* !OPENSSL_NO_EC */ + MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) { int i, al = SSL_AD_INTERNAL_ERROR; @@ -1494,6 +1519,11 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) goto f_err; } +#ifndef OPENSSL_NO_EC + if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) + ssl_check_for_safari(s, &clienthello); +#endif /* !OPENSSL_NO_EC */ + /* TLS extensions */ if (!tls_parse_clienthello_tlsext(s, &clienthello)) { SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT); -- 2.34.1