From a04d78d392463df4e69a64360c952ffa5abd22f7 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 25 Sep 2015 00:26:37 +0000 Subject: Revert "external/boringssl: sync with upstream." This reverts commit 1e4884f615b20946411a74e41eb9c6aa65e2d5f3. This breaks some x86 builds. Change-Id: I4d4310663ce52bc0a130e6b9dbc22b868ff4fb25 --- src/ssl/t1_lib.c | 3173 ++++++++++++++++++++++++------------------------------ 1 file changed, 1413 insertions(+), 1760 deletions(-) (limited to 'src/ssl/t1_lib.c') diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index f30e8eb..213a647 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -106,16 +106,12 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ -#include - #include -#include #include #include #include #include -#include #include #include #include @@ -126,6 +122,9 @@ #include "internal.h" +static int tls_decrypt_ticket(SSL *s, const uint8_t *tick, int ticklen, + const uint8_t *sess_id, int sesslen, + SSL_SESSION **psess); static int ssl_check_clienthello_tlsext(SSL *s); static int ssl_check_serverhello_tlsext(SSL *s); @@ -214,7 +213,8 @@ static int tls1_check_duplicate_extensions(const CBS *cbs) { extension_types = (uint16_t *)OPENSSL_malloc(sizeof(uint16_t) * num_extensions); if (extension_types == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, tls1_check_duplicate_extensions, + ERR_R_MALLOC_FAILURE); goto done; } @@ -338,21 +338,24 @@ char SSL_early_callback_ctx_extension_get( struct tls_curve { uint16_t curve_id; int nid; - const char curve_name[8]; }; /* ECC curves from RFC4492. */ static const struct tls_curve tls_curves[] = { - {21, NID_secp224r1, "P-224"}, - {23, NID_X9_62_prime256v1, "P-256"}, - {24, NID_secp384r1, "P-384"}, - {25, NID_secp521r1, "P-521"}, + {21, NID_secp224r1}, + {23, NID_X9_62_prime256v1}, + {24, NID_secp384r1}, + {25, NID_secp521r1}, +}; + +static const uint8_t ecformats_default[] = { + TLSEXT_ECPOINTFORMAT_uncompressed, }; static const uint16_t eccurves_default[] = { 23, /* X9_62_prime256v1 */ 24, /* secp384r1 */ -#if defined(BORINGSSL_ANDROID_SYSTEM) +#if defined(ANDROID) 25, /* secp521r1 */ #endif }; @@ -378,16 +381,6 @@ int tls1_ec_nid2curve_id(uint16_t *out_curve_id, int nid) { return 0; } -const char* tls1_ec_curve_id2name(uint16_t curve_id) { - size_t i; - for (i = 0; i < sizeof(tls_curves) / sizeof(tls_curves[0]); i++) { - if (curve_id == tls_curves[i].curve_id) { - return tls_curves[i].curve_name; - } - } - return NULL; -} - /* tls1_get_curvelist sets |*out_curve_ids| and |*out_curve_ids_len| to the * list of allowed curve IDs. If |get_peer_curves| is non-zero, return the * peer's curve list. Otherwise, return the preferred list. */ @@ -542,6 +535,28 @@ static int tls1_curve_params_from_ec_key(uint16_t *out_curve_id, return 1; } +/* tls1_check_point_format returns one if |comp_id| is consistent with the + * peer's point format preferences. */ +static int tls1_check_point_format(SSL *s, uint8_t comp_id) { + uint8_t *p = s->s3->tmp.peer_ecpointformatlist; + size_t plen = s->s3->tmp.peer_ecpointformatlist_length; + size_t i; + + /* If point formats extension present check it, otherwise everything is + * supported (see RFC4492). */ + if (p == NULL) { + return 1; + } + + for (i = 0; i < plen; i++) { + if (comp_id == p[i]) { + return 1; + } + } + + return 0; +} + /* tls1_check_curve_id returns one if |curve_id| is consistent with both our * and the peer's curve preferences. Note: if called as the client, only our * preferences are checked; the peer (the server) does not send preferences. */ @@ -578,6 +593,18 @@ static int tls1_check_curve_id(SSL *s, uint16_t curve_id) { return 1; } +static void tls1_get_formatlist(SSL *s, const uint8_t **pformats, + size_t *pformatslen) { + /* If we have a custom point format list use it otherwise use default */ + if (s->tlsext_ecpointformatlist) { + *pformats = s->tlsext_ecpointformatlist; + *pformatslen = s->tlsext_ecpointformatlist_length; + } else { + *pformats = ecformats_default; + *pformatslen = sizeof(ecformats_default); + } +} + int tls1_check_ec_cert(SSL *s, X509 *x) { int ret = 0; EVP_PKEY *pkey = X509_get_pubkey(x); @@ -588,7 +615,7 @@ int tls1_check_ec_cert(SSL *s, X509 *x) { pkey->type != EVP_PKEY_EC || !tls1_curve_params_from_ec_key(&curve_id, &comp_id, pkey->pkey.ec) || !tls1_check_curve_id(s, curve_id) || - comp_id != TLSEXT_ECPOINTFORMAT_uncompressed) { + !tls1_check_point_format(s, comp_id)) { goto done; } @@ -636,8 +663,17 @@ static const uint8_t tls12_sigalgs[] = { }; size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs) { - *psigs = tls12_sigalgs; - return sizeof(tls12_sigalgs); + /* If server use client authentication sigalgs if not NULL */ + if (s->server && s->cert->client_sigalgs) { + *psigs = s->cert->client_sigalgs; + return s->cert->client_sigalgslen; + } else if (s->cert->conf_sigalgs) { + *psigs = s->cert->conf_sigalgs; + return s->cert->conf_sigalgslen; + } else { + *psigs = tls12_sigalgs; + return sizeof(tls12_sigalgs); + } } /* tls12_check_peer_sigalg parses a SignatureAndHashAlgorithm out of |cbs|. It @@ -648,26 +684,26 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, CBS *cbs, EVP_PKEY *pkey) { const uint8_t *sent_sigs; size_t sent_sigslen, i; - int sigalg = tls12_get_sigid(pkey->type); + int sigalg = tls12_get_sigid(pkey); uint8_t hash, signature; /* Should never happen */ if (sigalg == -1) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, ERR_R_INTERNAL_ERROR); *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } if (!CBS_get_u8(cbs, &hash) || !CBS_get_u8(cbs, &signature)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_DECODE_ERROR); *out_alert = SSL_AD_DECODE_ERROR; return 0; } /* Check key type is consistent with signature */ if (sigalg != signature) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -682,8 +718,8 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, } if (s->server && (!tls1_check_curve_id(s, curve_id) || - comp_id != TLSEXT_ECPOINTFORMAT_uncompressed)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); + !tls1_check_point_format(s, comp_id))) { + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_CURVE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -699,14 +735,14 @@ int tls12_check_peer_sigalg(const EVP_MD **out_md, int *out_alert, SSL *s, /* Allow fallback to SHA-1. */ if (i == sent_sigslen && hash != TLSEXT_hash_sha1) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } *out_md = tls12_get_hash(hash); if (*out_md == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_DIGEST); + OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_UNKNOWN_DIGEST); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -763,1785 +799,1128 @@ void ssl_set_client_disabled(SSL *s) { } } -/* tls_extension represents a TLS extension that is handled internally. The - * |init| function is called for each handshake, before any other functions of - * the extension. Then the add and parse callbacks are called as needed. - * - * The parse callbacks receive a |CBS| that contains the contents of the - * extension (i.e. not including the type and length bytes). If an extension is - * not received then the parse callbacks will be called with a NULL CBS so that - * they can do any processing needed to handle the absence of an extension. - * - * The add callbacks receive a |CBB| to which the extension can be appended but - * the function is responsible for appending the type and length bytes too. - * - * All callbacks return one for success and zero for error. If a parse function - * returns zero then a fatal alert with value |*out_alert| will be sent. If - * |*out_alert| isn't set, then a |decode_error| alert will be sent. */ -struct tls_extension { - uint16_t value; - void (*init)(SSL *ssl); - - int (*add_clienthello)(SSL *ssl, CBB *out); - int (*parse_serverhello)(SSL *ssl, uint8_t *out_alert, CBS *contents); - - int (*parse_clienthello)(SSL *ssl, uint8_t *out_alert, CBS *contents); - int (*add_serverhello)(SSL *ssl, CBB *out); -}; - - -/* Server name indication (SNI). - * - * https://tools.ietf.org/html/rfc6066#section-3. */ - -static void ext_sni_init(SSL *ssl) { - ssl->s3->tmp.should_ack_sni = 0; -} - -static int ext_sni_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->tlsext_hostname == NULL) { - return 1; +/* header_len is the length of the ClientHello header written so far, used to + * compute padding. It does not include the record header. Pass 0 if no padding + * is to be done. */ +uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit, + size_t header_len) { + int extdatalen = 0; + uint8_t *ret = buf; + uint8_t *orig = buf; + /* See if we support any ECC ciphersuites */ + int using_ecc = 0; + + if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s)) { + size_t i; + uint32_t alg_k, alg_a; + STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s); + + for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { + const SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i); + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) { + using_ecc = 1; + break; + } + } } - CBB contents, server_name_list, name; - if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &server_name_list) || - !CBB_add_u8(&server_name_list, TLSEXT_NAMETYPE_host_name) || - !CBB_add_u16_length_prefixed(&server_name_list, &name) || - !CBB_add_bytes(&name, (const uint8_t *)ssl->tlsext_hostname, - strlen(ssl->tlsext_hostname)) || - !CBB_flush(out)) { - return 0; + /* don't add extensions for SSLv3 unless doing secure renegotiation */ + if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) { + return orig; } - return 1; -} + ret += 2; -static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - if (contents == NULL) { - return 1; + if (ret >= limit) { + return NULL; /* should never occur. */ } - if (CBS_len(contents) != 0) { - return 0; - } + if (s->tlsext_hostname != NULL) { + /* Add TLS extension servername to the Client Hello message */ + unsigned long size_str; + long lenmax; - assert(ssl->tlsext_hostname != NULL); + /* check for enough space. + 4 for the servername type and entension length + 2 for servernamelist length + 1 for the hostname type + 2 for hostname length + + hostname length */ - if (!ssl->hit) { - assert(ssl->session->tlsext_hostname == NULL); - ssl->session->tlsext_hostname = BUF_strdup(ssl->tlsext_hostname); - if (!ssl->session->tlsext_hostname) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; + lenmax = limit - ret - 9; + size_str = strlen(s->tlsext_hostname); + if (lenmax < 0 || size_str > (unsigned long)lenmax) { + return NULL; } - } - return 1; -} + /* extension type and length */ + s2n(TLSEXT_TYPE_server_name, ret); + s2n(size_str + 5, ret); -static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - if (contents == NULL) { - return 1; - } + /* length of servername list */ + s2n(size_str + 3, ret); - /* The servername extension is treated as follows: - * - * - Only the hostname type is supported with a maximum length of 255. - * - The servername is rejected if too long or if it contains zeros, in - * which case an fatal alert is generated. - * - The servername field is maintained together with the session cache. - * - When a session is resumed, the servername callback is invoked in order - * to allow the application to position itself to the right context. - * - The servername is acknowledged if it is new for a session or when - * it is identical to a previously used for the same session. - * Applications can control the behaviour. They can at any time - * set a 'desirable' servername for a new SSL object. This can be the - * case for example with HTTPS when a Host: header field is received and - * a renegotiation is requested. In this case, a possible servername - * presented in the new client hello is only acknowledged if it matches - * the value of the Host: field. - * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - * if they provide for changing an explicit servername context for the - * session, - * i.e. when the session has been established with a servername extension. - */ - - CBS server_name_list; - char have_seen_host_name = 0; - - if (!CBS_get_u16_length_prefixed(contents, &server_name_list) || - CBS_len(&server_name_list) == 0 || - CBS_len(contents) != 0) { - return 0; + /* hostname type, length and hostname */ + *(ret++) = (uint8_t)TLSEXT_NAMETYPE_host_name; + s2n(size_str, ret); + memcpy(ret, s->tlsext_hostname, size_str); + ret += size_str; } - /* Decode each ServerName in the extension. */ - while (CBS_len(&server_name_list) > 0) { - uint8_t name_type; - CBS host_name; + /* Add RI if renegotiating */ + if (s->s3->initial_handshake_complete) { + int el; - if (!CBS_get_u8(&server_name_list, &name_type) || - !CBS_get_u16_length_prefixed(&server_name_list, &host_name)) { - return 0; + if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; } - /* Only host_name is supported. */ - if (name_type != TLSEXT_NAMETYPE_host_name) { - continue; + if ((limit - ret - 4 - el) < 0) { + return NULL; } - if (have_seen_host_name) { - /* The ServerNameList MUST NOT contain more than one name of the same - * name_type. */ - return 0; + s2n(TLSEXT_TYPE_renegotiate, ret); + s2n(el, ret); + + if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; } - have_seen_host_name = 1; + ret += el; + } - if (CBS_len(&host_name) == 0 || - CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || - CBS_contains_zero_byte(&host_name)) { - *out_alert = SSL_AD_UNRECOGNIZED_NAME; - return 0; + /* Add extended master secret. */ + if (s->version != SSL3_VERSION) { + if (limit - ret - 4 < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_extended_master_secret, ret); + s2n(0, ret); + } + + if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { + int ticklen = 0; + /* Renegotiation does not participate in session resumption. However, still + * advertise the extension to avoid potentially breaking servers which carry + * over the state from the previous handshake, such as OpenSSL servers + * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */ + if (!s->s3->initial_handshake_complete && s->session != NULL && + s->session->tlsext_tick != NULL) { + ticklen = s->session->tlsext_ticklen; } - if (!ssl->hit) { - assert(ssl->session->tlsext_hostname == NULL); - if (ssl->session->tlsext_hostname) { - /* This should be impossible. */ - return 0; - } + /* Check for enough room 2 for extension type, 2 for len rest for + * ticket. */ + if ((long)(limit - ret - 4 - ticklen) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_session_ticket, ret); + s2n(ticklen, ret); + if (ticklen) { + memcpy(ret, s->session->tlsext_tick, ticklen); + ret += ticklen; + } + } - /* Copy the hostname as a string. */ - if (!CBS_strdup(&host_name, &ssl->session->tlsext_hostname)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } + if (ssl3_version_from_wire(s, s->client_version) >= TLS1_2_VERSION) { + size_t salglen; + const uint8_t *salg; + salglen = tls12_get_psigalgs(s, &salg); + if ((size_t)(limit - ret) < salglen + 6) { + return NULL; + } + s2n(TLSEXT_TYPE_signature_algorithms, ret); + s2n(salglen + 2, ret); + s2n(salglen, ret); + memcpy(ret, salg, salglen); + ret += salglen; + } + + if (s->ocsp_stapling_enabled) { + /* The status_request extension is excessively extensible at every layer. + * On the client, only support requesting OCSP responses with an empty + * responder_id_list and no extensions. */ + if (limit - ret - 4 - 1 - 2 - 2 < 0) { + return NULL; + } - ssl->s3->tmp.should_ack_sni = 1; + s2n(TLSEXT_TYPE_status_request, ret); + s2n(1 + 2 + 2, ret); + /* status_type */ + *(ret++) = TLSEXT_STATUSTYPE_ocsp; + /* responder_id_list - empty */ + s2n(0, ret); + /* request_extensions - empty */ + s2n(0, ret); + } + + if (s->ctx->next_proto_select_cb && !s->s3->initial_handshake_complete && + !SSL_IS_DTLS(s)) { + /* The client advertises an emtpy extension to indicate its support for + * Next Protocol Negotiation */ + if (limit - ret - 4 < 0) { + return NULL; } + s2n(TLSEXT_TYPE_next_proto_neg, ret); + s2n(0, ret); } - return 1; -} + if (s->signed_cert_timestamps_enabled) { + /* The client advertises an empty extension to indicate its support for + * certificate timestamps. */ + if (limit - ret - 4 < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_certificate_timestamp, ret); + s2n(0, ret); + } -static int ext_sni_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->hit || - !ssl->s3->tmp.should_ack_sni || - ssl->session->tlsext_hostname == NULL) { - return 1; + if (s->alpn_client_proto_list && !s->s3->initial_handshake_complete) { + if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) { + return NULL; + } + s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); + s2n(2 + s->alpn_client_proto_list_len, ret); + s2n(s->alpn_client_proto_list_len, ret); + memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len); + ret += s->alpn_client_proto_list_len; } - if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; + if (s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) { + /* The client advertises an emtpy extension to indicate its support for + * Channel ID. */ + if (limit - ret - 4 < 0) { + return NULL; + } + if (s->ctx->tlsext_channel_id_enabled_new) { + s2n(TLSEXT_TYPE_channel_id_new, ret); + } else { + s2n(TLSEXT_TYPE_channel_id, ret); + } + s2n(0, ret); } - return 1; -} + if (SSL_get_srtp_profiles(s)) { + int el; + ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); -/* Renegotiation indication. - * - * https://tools.ietf.org/html/rfc5746 */ - -static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { - CBB contents, prev_finished; - if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &prev_finished) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len) || - !CBB_flush(out)) { - return 0; - } + if ((limit - ret - 4 - el) < 0) { + return NULL; + } - return 1; -} + s2n(TLSEXT_TYPE_use_srtp, ret); + s2n(el, ret); -static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - /* No renegotiation extension received. - * - * Strictly speaking if we want to avoid an attack we should *always* see - * RI even on initial ServerHello because the client doesn't see any - * renegotiation during an attack. However this would mean we could not - * connect to any server which doesn't support RI. - * - * A lack of the extension is allowed if SSL_OP_LEGACY_SERVER_CONNECT is - * defined. */ - if (ssl->options & SSL_OP_LEGACY_SERVER_CONNECT) { - return 1; + if (!ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; } - - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; + ret += el; } - const size_t expected_len = ssl->s3->previous_client_finished_len + - ssl->s3->previous_server_finished_len; + if (using_ecc) { + /* Add TLS extension ECPointFormats to the ClientHello message */ + long lenmax; + const uint8_t *formats; + const uint16_t *curves; + size_t formats_len, curves_len, i; - /* Check for logic errors */ - assert(!expected_len || ssl->s3->previous_client_finished_len); - assert(!expected_len || ssl->s3->previous_server_finished_len); + tls1_get_formatlist(s, &formats, &formats_len); - /* Parse out the extension contents. */ - CBS renegotiated_connection; - if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } + lenmax = limit - ret - 5; + if (lenmax < 0) { + return NULL; + } + if (formats_len > (size_t)lenmax) { + return NULL; + } + if (formats_len > 255) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } - /* Check that the extension matches. */ - if (CBS_len(&renegotiated_connection) != expected_len) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } + s2n(TLSEXT_TYPE_ec_point_formats, ret); + s2n(formats_len + 1, ret); + *(ret++) = (uint8_t)formats_len; + memcpy(ret, formats, formats_len); + ret += formats_len; - const uint8_t *d = CBS_data(&renegotiated_connection); - if (CRYPTO_memcmp(d, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } - d += ssl->s3->previous_client_finished_len; + /* Add TLS extension EllipticCurves to the ClientHello message */ + tls1_get_curvelist(s, 0, &curves, &curves_len); - if (CRYPTO_memcmp(d, ssl->s3->previous_server_finished, - ssl->s3->previous_server_finished_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - ssl->s3->send_connection_binding = 1; + lenmax = limit - ret - 6; + if (lenmax < 0) { + return NULL; + } + if (curves_len * 2 > (size_t)lenmax) { + return NULL; + } + if (curves_len * 2 > 65532) { + OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } - return 1; -} + s2n(TLSEXT_TYPE_elliptic_curves, ret); + s2n((curves_len * 2) + 2, ret); -static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - /* Renegotiation isn't supported as a server so this function should never be - * called after the initial handshake. */ - assert(!ssl->s3->initial_handshake_complete); - - CBS fake_contents; - static const uint8_t kFakeExtension[] = {0}; - - if (contents == NULL) { - if (ssl->s3->send_connection_binding) { - /* The renegotiation SCSV was received so pretend that we received a - * renegotiation extension. */ - CBS_init(&fake_contents, kFakeExtension, sizeof(kFakeExtension)); - contents = &fake_contents; - /* We require that the renegotiation extension is at index zero of - * kExtensions. */ - ssl->s3->tmp.extensions.received |= (1u << 0); - } else { - return 1; + s2n(curves_len * 2, ret); + for (i = 0; i < curves_len; i++) { + s2n(curves[i], ret); } } - CBS renegotiated_connection; + if (header_len > 0) { + size_t clienthello_minsize = 0; + header_len += ret - orig; + if (header_len > 0xff && header_len < 0x200) { + /* Add padding to workaround bugs in F5 terminators. See + * https://tools.ietf.org/html/draft-agl-tls-padding-03 + * + * NB: because this code works out the length of all existing extensions + * it MUST always appear last. */ + clienthello_minsize = 0x200; + } + if (s->fastradio_padding) { + /* Pad the ClientHello record to 1024 bytes to fast forward the radio + * into DCH (high data rate) state in 3G networks. Note that when + * fastradio_padding is enabled, even if the header_len is less than 255 + * bytes, the padding will be applied regardless. This is slightly + * different from the TLS padding extension suggested in + * https://tools.ietf.org/html/draft-agl-tls-padding-03 */ + clienthello_minsize = 0x400; + } + if (header_len < clienthello_minsize) { + size_t padding_len = clienthello_minsize - header_len; + /* Extensions take at least four bytes to encode. Always include least + * one byte of data if including the extension. WebSphere Application + * Server 7.0 is intolerant to the last extension being zero-length. */ + if (padding_len >= 4 + 1) { + padding_len -= 4; + } else { + padding_len = 1; + } - if (!CBS_get_u8_length_prefixed(contents, &renegotiated_connection) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_ENCODING_ERR); - return 0; - } + if (limit - ret - 4 - (long)padding_len < 0) { + return NULL; + } - /* Check that the extension matches */ - if (!CBS_mem_equal(&renegotiated_connection, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_MISMATCH); - *out_alert = SSL_AD_HANDSHAKE_FAILURE; - return 0; + s2n(TLSEXT_TYPE_padding, ret); + s2n(padding_len, ret); + memset(ret, 0, padding_len); + ret += padding_len; + } } - ssl->s3->send_connection_binding = 1; - - return 1; -} - -static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { - CBB contents, prev_finished; - if (!CBB_add_u16(out, TLSEXT_TYPE_renegotiate) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &prev_finished) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_client_finished, - ssl->s3->previous_client_finished_len) || - !CBB_add_bytes(&prev_finished, ssl->s3->previous_server_finished, - ssl->s3->previous_server_finished_len) || - !CBB_flush(out)) { - return 0; + extdatalen = ret - orig - 2; + if (extdatalen == 0) { + return orig; } - return 1; + s2n(extdatalen, orig); + return ret; } +uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *buf, uint8_t *limit) { + int extdatalen = 0; + uint8_t *orig = buf; + uint8_t *ret = buf; + int next_proto_neg_seen; + uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth; + int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA); + using_ecc = using_ecc && (s->s3->tmp.peer_ecpointformatlist != NULL); -/* Extended Master Secret. - * - * https://tools.ietf.org/html/draft-ietf-tls-session-hash-05 */ - -static void ext_ems_init(SSL *ssl) { - ssl->s3->tmp.extended_master_secret = 0; -} - -static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->version == SSL3_VERSION) { - return 1; + /* don't add extensions for SSLv3, unless doing secure renegotiation */ + if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) { + return orig; } - if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; + ret += 2; + if (ret >= limit) { + return NULL; /* should never happen. */ } - return 1; -} + if (!s->hit && s->should_ack_sni && s->session->tlsext_hostname != NULL) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } -static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; + s2n(TLSEXT_TYPE_server_name, ret); + s2n(0, ret); } - if (ssl->version == SSL3_VERSION || CBS_len(contents) != 0) { - return 0; - } + if (s->s3->send_connection_binding) { + int el; - ssl->s3->tmp.extended_master_secret = 1; - return 1; -} + if (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } -static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - if (ssl->version == SSL3_VERSION || contents == NULL) { - return 1; - } + if ((limit - ret - 4 - el) < 0) { + return NULL; + } - if (CBS_len(contents) != 0) { - return 0; - } + s2n(TLSEXT_TYPE_renegotiate, ret); + s2n(el, ret); - ssl->s3->tmp.extended_master_secret = 1; - return 1; -} + if (!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } -static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->tmp.extended_master_secret) { - return 1; + ret += el; } - if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; + if (s->s3->tmp.extended_master_secret) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } + + s2n(TLSEXT_TYPE_extended_master_secret, ret); + s2n(0, ret); } - return 1; -} + if (using_ecc) { + const uint8_t *plist; + size_t plistlen; + /* Add TLS extension ECPointFormats to the ServerHello message */ + long lenmax; + tls1_get_formatlist(s, &plist, &plistlen); -/* Session tickets. - * - * https://tools.ietf.org/html/rfc5077 */ + lenmax = limit - ret - 5; + if (lenmax < 0) { + return NULL; + } + if (plistlen > (size_t)lenmax) { + return NULL; + } + if (plistlen > 255) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } -static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { - if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) { - return 1; + s2n(TLSEXT_TYPE_ec_point_formats, ret); + s2n(plistlen + 1, ret); + *(ret++) = (uint8_t)plistlen; + memcpy(ret, plist, plistlen); + ret += plistlen; } + /* Currently the server should not respond with a SupportedCurves extension */ - const uint8_t *ticket_data = NULL; - int ticket_len = 0; - - /* Renegotiation does not participate in session resumption. However, still - * advertise the extension to avoid potentially breaking servers which carry - * over the state from the previous handshake, such as OpenSSL servers - * without upstream's 3c3f0259238594d77264a78944d409f2127642c4. */ - if (!ssl->s3->initial_handshake_complete && - ssl->session != NULL && - ssl->session->tlsext_tick != NULL) { - ticket_data = ssl->session->tlsext_tick; - ticket_len = ssl->session->tlsext_ticklen; + if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_session_ticket, ret); + s2n(0, ret); } - CBB ticket; - if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || - !CBB_add_u16_length_prefixed(out, &ticket) || - !CBB_add_bytes(&ticket, ticket_data, ticket_len) || - !CBB_flush(out)) { - return 0; + if (s->s3->tmp.certificate_status_expected) { + if ((long)(limit - ret - 4) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_status_request, ret); + s2n(0, ret); } - return 1; -} + if (s->srtp_profile) { + int el; -static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - ssl->tlsext_ticket_expected = 0; + ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); - if (contents == NULL) { - return 1; - } + if ((limit - ret - 4 - el) < 0) { + return NULL; + } - /* If |SSL_OP_NO_TICKET| is set then no extension will have been sent and - * this function should never be called, even if the server tries to send the - * extension. */ - assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); + s2n(TLSEXT_TYPE_use_srtp, ret); + s2n(el, ret); - if (CBS_len(contents) != 0) { - return 0; + if (!ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) { + OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); + return NULL; + } + ret += el; } - ssl->tlsext_ticket_expected = 1; - return 1; -} - -static int ext_ticket_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { - /* This function isn't used because the ticket extension from the client is - * handled in ssl_sess.c. */ - return 1; -} + next_proto_neg_seen = s->s3->next_proto_neg_seen; + s->s3->next_proto_neg_seen = 0; + if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) { + const uint8_t *npa; + unsigned int npalen; + int r; -static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->tlsext_ticket_expected) { - return 1; + r = s->ctx->next_protos_advertised_cb( + s, &npa, &npalen, s->ctx->next_protos_advertised_cb_arg); + if (r == SSL_TLSEXT_ERR_OK) { + if ((long)(limit - ret - 4 - npalen) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_next_proto_neg, ret); + s2n(npalen, ret); + memcpy(ret, npa, npalen); + ret += npalen; + s->s3->next_proto_neg_seen = 1; + } } - /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be - * true. */ - assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); + if (s->s3->alpn_selected) { + const uint8_t *selected = s->s3->alpn_selected; + size_t len = s->s3->alpn_selected_len; - if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; + if ((long)(limit - ret - 4 - 2 - 1 - len) < 0) { + return NULL; + } + s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); + s2n(3 + len, ret); + s2n(1 + len, ret); + *ret++ = len; + memcpy(ret, selected, len); + ret += len; + } + + /* If the client advertised support for Channel ID, and we have it + * enabled, then we want to echo it back. */ + if (s->s3->tlsext_channel_id_valid) { + if (limit - ret - 4 < 0) { + return NULL; + } + if (s->s3->tlsext_channel_id_new) { + s2n(TLSEXT_TYPE_channel_id_new, ret); + } else { + s2n(TLSEXT_TYPE_channel_id, ret); + } + s2n(0, ret); } - return 1; -} + extdatalen = ret - orig - 2; + if (extdatalen == 0) { + return orig; + } + s2n(extdatalen, orig); + return ret; +} -/* Signature Algorithms. +/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a + * ClientHello. + * cbs: the contents of the extension, not including the type and length. + * out_alert: a pointer to the alert value to send in the event of a zero + * return. * - * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ + * returns: 1 on success. */ +static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert) { + CBS protocol_name_list, protocol_name_list_copy; + const uint8_t *selected; + uint8_t selected_len; + int r; -static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) { - if (ssl3_version_from_wire(ssl, ssl->client_version) < TLS1_2_VERSION) { + if (s->ctx->alpn_select_cb == NULL) { return 1; } - const uint8_t *sigalgs_data; - const size_t sigalgs_len = tls12_get_psigalgs(ssl, &sigalgs_data); - - CBB contents, sigalgs; - if (!CBB_add_u16(out, TLSEXT_TYPE_signature_algorithms) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &sigalgs) || - !CBB_add_bytes(&sigalgs, sigalgs_data, sigalgs_len) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - -static int ext_sigalgs_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents != NULL) { - /* Servers MUST NOT send this extension. */ - *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; - OPENSSL_PUT_ERROR(SSL, SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER); - return 0; - } - - return 1; -} - -static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - OPENSSL_free(ssl->cert->peer_sigalgs); - ssl->cert->peer_sigalgs = NULL; - ssl->cert->peer_sigalgslen = 0; - - if (contents == NULL) { - return 1; - } - - CBS supported_signature_algorithms; - if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) || - CBS_len(contents) != 0 || - CBS_len(&supported_signature_algorithms) == 0 || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { - return 0; - } - - return 1; -} - -static int ext_sigalgs_add_serverhello(SSL *ssl, CBB *out) { - /* Servers MUST NOT send this extension. */ - return 1; -} - - -/* OCSP Stapling. - * - * https://tools.ietf.org/html/rfc6066#section-8 */ - -static void ext_ocsp_init(SSL *ssl) { - ssl->s3->tmp.certificate_status_expected = 0; -} - -static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl->ocsp_stapling_enabled) { - return 1; + if (!CBS_get_u16_length_prefixed(cbs, &protocol_name_list) || + CBS_len(cbs) != 0 || CBS_len(&protocol_name_list) < 2) { + goto parse_error; } - CBB contents; - if (!CBB_add_u16(out, TLSEXT_TYPE_status_request) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) || - !CBB_add_u16(&contents, 0 /* empty responder ID list */) || - !CBB_add_u16(&contents, 0 /* empty request extensions */) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} + /* Validate the protocol list. */ + protocol_name_list_copy = protocol_name_list; + while (CBS_len(&protocol_name_list_copy) > 0) { + CBS protocol_name; -static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; + if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name)) { + goto parse_error; + } } - if (CBS_len(contents) != 0) { - return 0; + r = s->ctx->alpn_select_cb( + s, &selected, &selected_len, CBS_data(&protocol_name_list), + CBS_len(&protocol_name_list), s->ctx->alpn_select_cb_arg); + if (r == SSL_TLSEXT_ERR_OK) { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = BUF_memdup(selected, selected_len); + if (!s->s3->alpn_selected) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + s->s3->alpn_selected_len = selected_len; } - ssl->s3->tmp.certificate_status_expected = 1; return 1; -} - -static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - uint8_t status_type; - if (!CBS_get_u8(contents, &status_type)) { - return 0; - } - - /* We cannot decide whether OCSP stapling will occur yet because the correct - * SSL_CTX might not have been selected. */ - ssl->s3->tmp.ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp; - return 1; +parse_error: + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } -static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { - /* The extension shouldn't be sent when resuming sessions. */ - if (ssl->hit || - !ssl->s3->tmp.ocsp_stapling_requested || - ssl->ctx->ocsp_response_length == 0) { - return 1; - } - - ssl->s3->tmp.certificate_status_expected = 1; - - return CBB_add_u16(out, TLSEXT_TYPE_status_request) && - CBB_add_u16(out, 0 /* length */); -} +static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { + int renegotiate_seen = 0; + CBS extensions; + s->should_ack_sni = 0; + s->srtp_profile = NULL; + s->s3->next_proto_neg_seen = 0; + s->s3->tmp.certificate_status_expected = 0; + s->s3->tmp.extended_master_secret = 0; -/* Next protocol negotiation. - * - * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */ + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; -static void ext_npn_init(SSL *ssl) { - ssl->s3->next_proto_neg_seen = 0; -} + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->cert->peer_sigalgs); + s->cert->peer_sigalgs = NULL; + s->cert->peer_sigalgslen = 0; -static int ext_npn_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->s3->initial_handshake_complete || - ssl->ctx->next_proto_select_cb == NULL || - SSL_IS_DTLS(ssl)) { - return 1; - } + /* Clear any shared signature algorithms */ + OPENSSL_free(s->cert->shared_sigalgs); + s->cert->shared_sigalgs = NULL; + s->cert->shared_sigalgslen = 0; - if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } + /* Clear ECC extensions */ + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); + s->s3->tmp.peer_ecpointformatlist = NULL; + s->s3->tmp.peer_ecpointformatlist_length = 0; - return 1; -} + OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); + s->s3->tmp.peer_ellipticcurvelist = NULL; + s->s3->tmp.peer_ellipticcurvelist_length = 0; -static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; + /* There may be no extensions. */ + if (CBS_len(cbs) == 0) { + goto ri_check; } - /* If any of these are false then we should never have sent the NPN - * extension in the ClientHello and thus this function should never have been - * called. */ - assert(!ssl->s3->initial_handshake_complete); - assert(!SSL_IS_DTLS(ssl)); - assert(ssl->ctx->next_proto_select_cb != NULL); - - if (ssl->s3->alpn_selected != NULL) { - /* NPN and ALPN may not be negotiated in the same connection. */ - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); + /* Decode the extensions block and check it is valid. */ + if (!CBS_get_u16_length_prefixed(cbs, &extensions) || + !tls1_check_duplicate_extensions(&extensions)) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - const uint8_t *const orig_contents = CBS_data(contents); - const size_t orig_len = CBS_len(contents); + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS extension; - while (CBS_len(contents) != 0) { - CBS proto; - if (!CBS_get_u8_length_prefixed(contents, &proto) || - CBS_len(&proto) == 0) { + /* Decode the next extension. */ + if (!CBS_get_u16(&extensions, &type) || + !CBS_get_u16_length_prefixed(&extensions, &extension)) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - } - - uint8_t *selected; - uint8_t selected_len; - if (ssl->ctx->next_proto_select_cb( - ssl, &selected, &selected_len, orig_contents, orig_len, - ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - OPENSSL_free(ssl->next_proto_negotiated); - ssl->next_proto_negotiated = BUF_memdup(selected, selected_len); - if (ssl->next_proto_negotiated == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } + /* The servername extension is treated as follows: + + - Only the hostname type is supported with a maximum length of 255. + - The servername is rejected if too long or if it contains zeros, in + which case an fatal alert is generated. + - The servername field is maintained together with the session cache. + - When a session is resumed, the servername call back invoked in order + to allow the application to position itself to the right context. + - The servername is acknowledged if it is new for a session or when + it is identical to a previously used for the same session. + Applications can control the behaviour. They can at any time + set a 'desirable' servername for a new SSL object. This can be the + case for example with HTTPS when a Host: header field is received and + a renegotiation is requested. In this case, a possible servername + presented in the new client hello is only acknowledged if it matches + the value of the Host: field. + - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + if they provide for changing an explicit servername context for the + session, + i.e. when the session has been established with a servername extension. + - On session reconnect, the servername extension may be absent. */ + + if (type == TLSEXT_TYPE_server_name) { + CBS server_name_list; + char have_seen_host_name = 0; + + if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) || + CBS_len(&server_name_list) < 1 || CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - ssl->next_proto_negotiated_len = selected_len; - ssl->s3->next_proto_neg_seen = 1; + /* Decode each ServerName in the extension. */ + while (CBS_len(&server_name_list) > 0) { + uint8_t name_type; + CBS host_name; - return 1; -} + /* Decode the NameType. */ + if (!CBS_get_u8(&server_name_list, &name_type)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents != NULL && CBS_len(contents) != 0) { - return 0; - } + /* Only host_name is supported. */ + if (name_type != TLSEXT_NAMETYPE_host_name) { + continue; + } - if (contents == NULL || - ssl->s3->initial_handshake_complete || - /* If the ALPN extension is seen before NPN, ignore it. (If ALPN is seen - * afterwards, parsing the ALPN extension will clear - * |next_proto_neg_seen|. */ - ssl->s3->alpn_selected != NULL || - ssl->ctx->next_protos_advertised_cb == NULL || - SSL_IS_DTLS(ssl)) { - return 1; - } + if (have_seen_host_name) { + /* The ServerNameList MUST NOT contain more than one name of the same + * name_type. */ + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - ssl->s3->next_proto_neg_seen = 1; - return 1; -} + have_seen_host_name = 1; -static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { - /* |next_proto_neg_seen| might have been cleared when an ALPN extension was - * parsed. */ - if (!ssl->s3->next_proto_neg_seen) { - return 1; - } + if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) || + CBS_len(&host_name) < 1) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - const uint8_t *npa; - unsigned npa_len; + if (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || + CBS_contains_zero_byte(&host_name)) { + *out_alert = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } - if (ssl->ctx->next_protos_advertised_cb( - ssl, &npa, &npa_len, ssl->ctx->next_protos_advertised_cb_arg) != - SSL_TLSEXT_ERR_OK) { - ssl->s3->next_proto_neg_seen = 0; - return 1; - } + if (!s->hit) { + assert(s->session->tlsext_hostname == NULL); + if (s->session->tlsext_hostname) { + /* This should be impossible. */ + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Copy the hostname as a string. */ + if (!CBS_strdup(&host_name, &s->session->tlsext_hostname)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + s->should_ack_sni = 1; + } + } + } else if (type == TLSEXT_TYPE_ec_point_formats) { + CBS ec_point_format_list; - CBB contents; - if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_bytes(&contents, npa, npa_len) || - !CBB_flush(out)) { - return 0; - } + if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - return 1; -} + if (!CBS_stow(&ec_point_format_list, &s->s3->tmp.peer_ecpointformatlist, + &s->s3->tmp.peer_ecpointformatlist_length)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_elliptic_curves) { + CBS elliptic_curve_list; + size_t i, num_curves; + + if (!CBS_get_u16_length_prefixed(&extension, &elliptic_curve_list) || + CBS_len(&elliptic_curve_list) == 0 || + (CBS_len(&elliptic_curve_list) & 1) != 0 || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); + s->s3->tmp.peer_ellipticcurvelist_length = 0; -/* Signed certificate timestamps. - * - * https://tools.ietf.org/html/rfc6962#section-3.3.1 */ + s->s3->tmp.peer_ellipticcurvelist = + (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); -static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl->signed_cert_timestamps_enabled) { - return 1; - } + if (s->s3->tmp.peer_ellipticcurvelist == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } - if (!CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } + num_curves = CBS_len(&elliptic_curve_list) / 2; + for (i = 0; i < num_curves; i++) { + if (!CBS_get_u16(&elliptic_curve_list, + &s->s3->tmp.peer_ellipticcurvelist[i])) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } - return 1; -} + if (CBS_len(&elliptic_curve_list) != 0) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } -static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } + s->s3->tmp.peer_ellipticcurvelist_length = num_curves; + } else if (type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_clienthello_renegotiate_ext(s, &extension, out_alert)) { + return 0; + } + renegotiate_seen = 1; + } else if (type == TLSEXT_TYPE_signature_algorithms) { + CBS supported_signature_algorithms; - /* If this is false then we should never have sent the SCT extension in the - * ClientHello and thus this function should never have been called. */ - assert(ssl->signed_cert_timestamps_enabled); + if (!CBS_get_u16_length_prefixed(&extension, + &supported_signature_algorithms) || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - if (CBS_len(contents) == 0) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + /* Ensure the signature algorithms are non-empty. It contains a list of + * SignatureAndHashAlgorithms which are two bytes each. */ + if (CBS_len(&supported_signature_algorithms) == 0 || + (CBS_len(&supported_signature_algorithms) % 2) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - /* Session resumption uses the original session information. */ - if (!ssl->hit && - !CBS_stow(contents, &ssl->session->tlsext_signed_cert_timestamp_list, - &ssl->session->tlsext_signed_cert_timestamp_list_length)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } + if (!tls1_process_sigalgs(s, &supported_signature_algorithms)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + /* If sigalgs received and no shared algorithms fatal error. */ + if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs) { + OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, + SSL_R_NO_SHARED_SIGATURE_ALGORITHMS); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + } else if (type == TLSEXT_TYPE_next_proto_neg && + !s->s3->initial_handshake_complete && + s->s3->alpn_selected == NULL && !SSL_IS_DTLS(s)) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + s->s3->next_proto_neg_seen = 1; + } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + s->ctx->alpn_select_cb && !s->s3->initial_handshake_complete) { + if (!tls1_alpn_handle_client_hello(s, &extension, out_alert)) { + return 0; + } + /* ALPN takes precedence over NPN. */ + s->s3->next_proto_neg_seen = 0; + } else if (type == TLSEXT_TYPE_channel_id && s->tlsext_channel_id_enabled && + !SSL_IS_DTLS(s)) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - return 1; -} + s->s3->tlsext_channel_id_valid = 1; + } else if (type == TLSEXT_TYPE_channel_id_new && + s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - return contents == NULL || CBS_len(contents) == 0; -} + s->s3->tlsext_channel_id_valid = 1; + s->s3->tlsext_channel_id_new = 1; + } else if (type == TLSEXT_TYPE_use_srtp) { + if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert)) { + return 0; + } + } else if (type == TLSEXT_TYPE_extended_master_secret && + s->version != SSL3_VERSION) { + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ext_sct_add_serverhello(SSL *ssl, CBB *out) { - /* The extension shouldn't be sent when resuming sessions. */ - if (ssl->hit || - ssl->ctx->signed_cert_timestamp_list_length == 0) { - return 1; + s->s3->tmp.extended_master_secret = 1; + } } - CBB contents; - return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) && - CBB_add_u16_length_prefixed(out, &contents) && - CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list, - ssl->ctx->signed_cert_timestamp_list_length) && - CBB_flush(out); -} - +ri_check: + /* Need RI if renegotiating */ -/* Application-level Protocol Negotiation. - * - * https://tools.ietf.org/html/rfc7301 */ - -static void ext_alpn_init(SSL *ssl) { - OPENSSL_free(ssl->s3->alpn_selected); - ssl->s3->alpn_selected = NULL; -} - -static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->alpn_client_proto_list == NULL || - ssl->s3->initial_handshake_complete) { - return 1; - } - - CBB contents, proto_list; - if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &proto_list) || - !CBB_add_bytes(&proto_list, ssl->alpn_client_proto_list, - ssl->alpn_client_proto_list_len) || - !CBB_flush(out)) { + if (!renegotiate_seen && s->s3->initial_handshake_complete && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, ssl_scan_clienthello_tlsext, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); return 0; } return 1; } -static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - assert(!ssl->s3->initial_handshake_complete); - assert(ssl->alpn_client_proto_list != NULL); - - if (ssl->s3->next_proto_neg_seen) { - /* NPN and ALPN may not be negotiated in the same connection. */ - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); - return 0; - } - - /* The extension data consists of a ProtocolNameList which must have - * exactly one ProtocolName. Each of these is length-prefixed. */ - CBS protocol_name_list, protocol_name; - if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) || - CBS_len(contents) != 0 || - !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) || - /* Empty protocol names are forbidden. */ - CBS_len(&protocol_name) == 0 || - CBS_len(&protocol_name_list) != 0) { +int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) { + int alert = -1; + if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, alert); return 0; } - if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected, - &ssl->s3->alpn_selected_len)) { - *out_alert = SSL_AD_INTERNAL_ERROR; + if (ssl_check_clienthello_tlsext(s) <= 0) { + OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_tlsext, + SSL_R_CLIENTHELLO_TLSEXT); return 0; } return 1; } -static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - if (ssl->ctx->alpn_select_cb == NULL || - ssl->s3->initial_handshake_complete) { - return 1; - } - - /* ALPN takes precedence over NPN. */ - ssl->s3->next_proto_neg_seen = 0; - - CBS protocol_name_list; - if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) || - CBS_len(contents) != 0 || - CBS_len(&protocol_name_list) < 2) { - return 0; - } - - /* Validate the protocol list. */ - CBS protocol_name_list_copy = protocol_name_list; - while (CBS_len(&protocol_name_list_copy) > 0) { - CBS protocol_name; - - if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) || - /* Empty protocol names are forbidden. */ - CBS_len(&protocol_name) == 0) { - return 0; - } - } +/* ssl_next_proto_validate validates a Next Protocol Negotiation block. No + * elements of zero length are allowed and the set of elements must exactly + * fill the length of the block. */ +static char ssl_next_proto_validate(const CBS *cbs) { + CBS copy = *cbs; - const uint8_t *selected; - uint8_t selected_len; - if (ssl->ctx->alpn_select_cb( - ssl, &selected, &selected_len, CBS_data(&protocol_name_list), - CBS_len(&protocol_name_list), - ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) { - OPENSSL_free(ssl->s3->alpn_selected); - ssl->s3->alpn_selected = BUF_memdup(selected, selected_len); - if (ssl->s3->alpn_selected == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; + while (CBS_len(©) != 0) { + CBS proto; + if (!CBS_get_u8_length_prefixed(©, &proto) || CBS_len(&proto) == 0) { return 0; } - ssl->s3->alpn_selected_len = selected_len; } return 1; } -static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->s3->alpn_selected == NULL) { - return 1; - } - - CBB contents, proto_list, proto; - if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &proto_list) || - !CBB_add_u8_length_prefixed(&proto_list, &proto) || - !CBB_add_bytes(&proto, ssl->s3->alpn_selected, ssl->s3->alpn_selected_len) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} +static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { + int tlsext_servername = 0; + int renegotiate_seen = 0; + CBS extensions; + /* TODO(davidben): Move all of these to some per-handshake state that gets + * systematically reset on a new handshake; perhaps allocate it fresh each + * time so it's not even kept around post-handshake. */ + s->s3->next_proto_neg_seen = 0; + s->tlsext_ticket_expected = 0; + s->s3->tmp.certificate_status_expected = 0; + s->s3->tmp.extended_master_secret = 0; + s->srtp_profile = NULL; -/* Channel ID. - * - * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */ + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; -static void ext_channel_id_init(SSL *ssl) { - ssl->s3->tlsext_channel_id_valid = 0; -} + /* Clear ECC extensions */ + OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); + s->s3->tmp.peer_ecpointformatlist = NULL; + s->s3->tmp.peer_ecpointformatlist_length = 0; -static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl->tlsext_channel_id_enabled || - SSL_IS_DTLS(ssl)) { - return 1; + /* There may be no extensions. */ + if (CBS_len(cbs) == 0) { + goto ri_check; } - if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) || - !CBB_add_u16(out, 0 /* length */)) { + /* Decode the extensions block and check it is valid. */ + if (!CBS_get_u16_length_prefixed(cbs, &extensions) || + !tls1_check_duplicate_extensions(&extensions)) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - return 1; -} + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS extension; -static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - assert(!SSL_IS_DTLS(ssl)); - assert(ssl->tlsext_channel_id_enabled); - - if (CBS_len(contents) != 0) { - return 0; - } - - ssl->s3->tlsext_channel_id_valid = 1; - return 1; -} - -static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL || - !ssl->tlsext_channel_id_enabled || - SSL_IS_DTLS(ssl)) { - return 1; - } - - if (CBS_len(contents) != 0) { - return 0; - } - - ssl->s3->tlsext_channel_id_valid = 1; - return 1; -} - -static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->tlsext_channel_id_valid) { - return 1; - } - - if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) || - !CBB_add_u16(out, 0 /* length */)) { - return 0; - } - - return 1; -} - - -/* Secure Real-time Transport Protocol (SRTP) extension. - * - * https://tools.ietf.org/html/rfc5764 */ - - -static void ext_srtp_init(SSL *ssl) { - ssl->srtp_profile = NULL; -} - -static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { - STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); - if (profiles == NULL) { - return 1; - } - const size_t num_profiles = sk_SRTP_PROTECTION_PROFILE_num(profiles); - if (num_profiles == 0) { - return 1; - } - - CBB contents, profile_ids; - if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &profile_ids)) { - return 0; - } - - size_t i; - for (i = 0; i < num_profiles; i++) { - if (!CBB_add_u16(&profile_ids, - sk_SRTP_PROTECTION_PROFILE_value(profiles, i)->id)) { - return 0; - } - } - - if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - -static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - /* The extension consists of a u16-prefixed profile ID list containing a - * single uint16_t profile ID, then followed by a u8-prefixed srtp_mki field. - * - * See https://tools.ietf.org/html/rfc5764#section-4.1.1 */ - CBS profile_ids, srtp_mki; - uint16_t profile_id; - if (!CBS_get_u16_length_prefixed(contents, &profile_ids) || - !CBS_get_u16(&profile_ids, &profile_id) || - CBS_len(&profile_ids) != 0 || - !CBS_get_u8_length_prefixed(contents, &srtp_mki) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - return 0; - } - - if (CBS_len(&srtp_mki) != 0) { - /* Must be no MKI, since we never offer one. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_MKI_VALUE); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - - STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); - - /* Check to see if the server gave us something we support (and presumably - * offered). */ - size_t i; - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(profiles); i++) { - const SRTP_PROTECTION_PROFILE *profile = - sk_SRTP_PROTECTION_PROFILE_value(profiles, i); - - if (profile->id == profile_id) { - ssl->srtp_profile = profile; - return 1; - } - } - - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; -} - -static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - CBS profile_ids, srtp_mki; - if (!CBS_get_u16_length_prefixed(contents, &profile_ids) || - CBS_len(&profile_ids) < 2 || - !CBS_get_u8_length_prefixed(contents, &srtp_mki) || - CBS_len(contents) != 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - return 0; - } - /* Discard the MKI value for now. */ - - const STACK_OF(SRTP_PROTECTION_PROFILE) *server_profiles = - SSL_get_srtp_profiles(ssl); - - /* Pick the server's most preferred profile. */ - size_t i; - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(server_profiles); i++) { - const SRTP_PROTECTION_PROFILE *server_profile = - sk_SRTP_PROTECTION_PROFILE_value(server_profiles, i); - - CBS profile_ids_tmp; - CBS_init(&profile_ids_tmp, CBS_data(&profile_ids), CBS_len(&profile_ids)); - - while (CBS_len(&profile_ids_tmp) > 0) { - uint16_t profile_id; - if (!CBS_get_u16(&profile_ids_tmp, &profile_id)) { - return 0; - } - - if (server_profile->id == profile_id) { - ssl->srtp_profile = server_profile; - return 1; - } - } - } - - return 1; -} - -static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->srtp_profile == NULL) { - return 1; - } - - CBB contents, profile_ids; - if (!CBB_add_u16(out, TLSEXT_TYPE_srtp) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &profile_ids) || - !CBB_add_u16(&profile_ids, ssl->srtp_profile->id) || - !CBB_add_u8(&contents, 0 /* empty MKI */) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - - -/* EC point formats. - * - * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ - -static int ssl_any_ec_cipher_suites_enabled(const SSL *ssl) { - if (ssl->version < TLS1_VERSION && !SSL_IS_DTLS(ssl)) { - return 0; - } - - const STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl); - - size_t i; - for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) { - const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, i); - - const uint32_t alg_k = cipher->algorithm_mkey; - const uint32_t alg_a = cipher->algorithm_auth; - if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) { - return 1; - } - } - - return 0; -} - -static int ext_ec_point_add_extension(SSL *ssl, CBB *out) { - CBB contents, formats; - if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u8_length_prefixed(&contents, &formats) || - !CBB_add_u8(&formats, TLSEXT_ECPOINTFORMAT_uncompressed) || - !CBB_flush(out)) { - return 0; - } - - return 1; -} - -static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl_any_ec_cipher_suites_enabled(ssl)) { - return 1; - } - - return ext_ec_point_add_extension(ssl, out); -} - -static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - CBS ec_point_format_list; - if (!CBS_get_u8_length_prefixed(contents, &ec_point_format_list) || - CBS_len(contents) != 0) { - return 0; - } - - /* Per RFC 4492, section 5.1.2, implementations MUST support the uncompressed - * point format. */ - if (memchr(CBS_data(&ec_point_format_list), TLSEXT_ECPOINTFORMAT_uncompressed, - CBS_len(&ec_point_format_list)) == NULL) { - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - - return 1; -} - -static int ext_ec_point_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - return ext_ec_point_parse_serverhello(ssl, out_alert, contents); -} - -static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { - const uint32_t alg_k = ssl->s3->tmp.new_cipher->algorithm_mkey; - const uint32_t alg_a = ssl->s3->tmp.new_cipher->algorithm_auth; - const int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA); - - if (!using_ecc) { - return 1; - } - - return ext_ec_point_add_extension(ssl, out); -} - - -/* EC supported curves. - * - * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ - -static void ext_ec_curves_init(SSL *ssl) { - OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist); - ssl->s3->tmp.peer_ellipticcurvelist = NULL; - ssl->s3->tmp.peer_ellipticcurvelist_length = 0; -} - -static int ext_ec_curves_add_clienthello(SSL *ssl, CBB *out) { - if (!ssl_any_ec_cipher_suites_enabled(ssl)) { - return 1; - } - - CBB contents, curves_bytes; - if (!CBB_add_u16(out, TLSEXT_TYPE_elliptic_curves) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &curves_bytes)) { - return 0; - } - - const uint16_t *curves; - size_t curves_len; - tls1_get_curvelist(ssl, 0, &curves, &curves_len); - - size_t i; - for (i = 0; i < curves_len; i++) { - if (!CBB_add_u16(&curves_bytes, curves[i])) { - return 0; - } - } - - return CBB_flush(out); -} - -static int ext_ec_curves_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - /* This extension is not expected to be echoed by servers and is ignored. */ - return 1; -} - -static int ext_ec_curves_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { - if (contents == NULL) { - return 1; - } - - CBS elliptic_curve_list; - if (!CBS_get_u16_length_prefixed(contents, &elliptic_curve_list) || - CBS_len(&elliptic_curve_list) == 0 || - (CBS_len(&elliptic_curve_list) & 1) != 0 || - CBS_len(contents) != 0) { - return 0; - } - - ssl->s3->tmp.peer_ellipticcurvelist = - (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); - - if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - - const size_t num_curves = CBS_len(&elliptic_curve_list) / 2; - size_t i; - for (i = 0; i < num_curves; i++) { - if (!CBS_get_u16(&elliptic_curve_list, - &ssl->s3->tmp.peer_ellipticcurvelist[i])) { - goto err; - } - } - - assert(CBS_len(&elliptic_curve_list) == 0); - ssl->s3->tmp.peer_ellipticcurvelist_length = num_curves; - - return 1; - -err: - OPENSSL_free(ssl->s3->tmp.peer_ellipticcurvelist); - ssl->s3->tmp.peer_ellipticcurvelist = NULL; - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; -} - -static int ext_ec_curves_add_serverhello(SSL *ssl, CBB *out) { - /* Servers don't echo this extension. */ - return 1; -} - - -/* kExtensions contains all the supported extensions. */ -static const struct tls_extension kExtensions[] = { - { - /* The renegotiation extension must always be at index zero because the - * |received| and |sent| bitsets need to be tweaked when the "extension" is - * sent as an SCSV. */ - TLSEXT_TYPE_renegotiate, - NULL, - ext_ri_add_clienthello, - ext_ri_parse_serverhello, - ext_ri_parse_clienthello, - ext_ri_add_serverhello, - }, - { - TLSEXT_TYPE_server_name, - ext_sni_init, - ext_sni_add_clienthello, - ext_sni_parse_serverhello, - ext_sni_parse_clienthello, - ext_sni_add_serverhello, - }, - { - TLSEXT_TYPE_extended_master_secret, - ext_ems_init, - ext_ems_add_clienthello, - ext_ems_parse_serverhello, - ext_ems_parse_clienthello, - ext_ems_add_serverhello, - }, - { - TLSEXT_TYPE_session_ticket, - NULL, - ext_ticket_add_clienthello, - ext_ticket_parse_serverhello, - ext_ticket_parse_clienthello, - ext_ticket_add_serverhello, - }, - { - TLSEXT_TYPE_signature_algorithms, - NULL, - ext_sigalgs_add_clienthello, - ext_sigalgs_parse_serverhello, - ext_sigalgs_parse_clienthello, - ext_sigalgs_add_serverhello, - }, - { - TLSEXT_TYPE_status_request, - ext_ocsp_init, - ext_ocsp_add_clienthello, - ext_ocsp_parse_serverhello, - ext_ocsp_parse_clienthello, - ext_ocsp_add_serverhello, - }, - { - TLSEXT_TYPE_next_proto_neg, - ext_npn_init, - ext_npn_add_clienthello, - ext_npn_parse_serverhello, - ext_npn_parse_clienthello, - ext_npn_add_serverhello, - }, - { - TLSEXT_TYPE_certificate_timestamp, - NULL, - ext_sct_add_clienthello, - ext_sct_parse_serverhello, - ext_sct_parse_clienthello, - ext_sct_add_serverhello, - }, - { - TLSEXT_TYPE_application_layer_protocol_negotiation, - ext_alpn_init, - ext_alpn_add_clienthello, - ext_alpn_parse_serverhello, - ext_alpn_parse_clienthello, - ext_alpn_add_serverhello, - }, - { - TLSEXT_TYPE_channel_id, - ext_channel_id_init, - ext_channel_id_add_clienthello, - ext_channel_id_parse_serverhello, - ext_channel_id_parse_clienthello, - ext_channel_id_add_serverhello, - }, - { - TLSEXT_TYPE_srtp, - ext_srtp_init, - ext_srtp_add_clienthello, - ext_srtp_parse_serverhello, - ext_srtp_parse_clienthello, - ext_srtp_add_serverhello, - }, - { - TLSEXT_TYPE_ec_point_formats, - NULL, - ext_ec_point_add_clienthello, - ext_ec_point_parse_serverhello, - ext_ec_point_parse_clienthello, - ext_ec_point_add_serverhello, - }, - { - TLSEXT_TYPE_elliptic_curves, - ext_ec_curves_init, - ext_ec_curves_add_clienthello, - ext_ec_curves_parse_serverhello, - ext_ec_curves_parse_clienthello, - ext_ec_curves_add_serverhello, - }, -}; - -#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension)) - -OPENSSL_COMPILE_ASSERT(kNumExtensions <= - sizeof(((SSL *)NULL)->s3->tmp.extensions.sent) * 8, - too_many_extensions_for_sent_bitset); -OPENSSL_COMPILE_ASSERT(kNumExtensions <= - sizeof(((SSL *)NULL)->s3->tmp.extensions.received) * - 8, - too_many_extensions_for_received_bitset); - -static const struct tls_extension *tls_extension_find(uint32_t *out_index, - uint16_t value) { - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].value == value) { - *out_index = i; - return &kExtensions[i]; - } - } - - return NULL; -} - -int SSL_extension_supported(unsigned extension_value) { - uint32_t index; - return extension_value == TLSEXT_TYPE_padding || - tls_extension_find(&index, extension_value) != NULL; -} - -/* header_len is the length of the ClientHello header written so far, used to - * compute padding. It does not include the record header. Pass 0 if no padding - * is to be done. */ -uint8_t *ssl_add_clienthello_tlsext(SSL *s, uint8_t *const buf, - uint8_t *const limit, size_t header_len) { - /* don't add extensions for SSLv3 unless doing secure renegotiation */ - if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) { - return buf; - } - - CBB cbb, extensions; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, buf, limit - buf) || - !CBB_add_u16_length_prefixed(&cbb, &extensions)) { - goto err; - } - - s->s3->tmp.extensions.sent = 0; - s->s3->tmp.custom_extensions.sent = 0; - - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].init != NULL) { - kExtensions[i].init(s); - } - } - - for (i = 0; i < kNumExtensions; i++) { - const size_t len_before = CBB_len(&extensions); - if (!kExtensions[i].add_clienthello(s, &extensions)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - goto err; - } - - if (CBB_len(&extensions) != len_before) { - s->s3->tmp.extensions.sent |= (1u << i); - } - } - - if (!custom_ext_add_clienthello(s, &extensions)) { - goto err; - } - - if (header_len > 0) { - header_len += CBB_len(&extensions); - if (header_len > 0xff && header_len < 0x200) { - /* Add padding to workaround bugs in F5 terminators. See - * https://tools.ietf.org/html/draft-agl-tls-padding-03 - * - * NB: because this code works out the length of all existing extensions - * it MUST always appear last. */ - size_t padding_len = 0x200 - header_len; - /* Extensions take at least four bytes to encode. Always include least - * one byte of data if including the extension. WebSphere Application - * Server 7.0 is intolerant to the last extension being zero-length. */ - if (padding_len >= 4 + 1) { - padding_len -= 4; - } else { - padding_len = 1; - } - - uint8_t *padding_bytes; - if (!CBB_add_u16(&extensions, TLSEXT_TYPE_padding) || - !CBB_add_u16(&extensions, padding_len) || - !CBB_add_space(&extensions, &padding_bytes, padding_len)) { - goto err; - } - - memset(padding_bytes, 0, padding_len); - } - } - - if (!CBB_flush(&cbb)) { - goto err; - } - - uint8_t *ret = buf; - const size_t cbb_len = CBB_len(&cbb); - /* If only two bytes have been written then the extensions are actually empty - * and those two bytes are the zero length. In that case, we don't bother - * sending the extensions length. */ - if (cbb_len > 2) { - ret += cbb_len; - } - - CBB_cleanup(&cbb); - return ret; - -err: - CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; -} - -uint8_t *ssl_add_serverhello_tlsext(SSL *s, uint8_t *const buf, - uint8_t *const limit) { - /* don't add extensions for SSLv3, unless doing secure renegotiation */ - if (s->version == SSL3_VERSION && !s->s3->send_connection_binding) { - return buf; - } - - CBB cbb, extensions; - CBB_zero(&cbb); - if (!CBB_init_fixed(&cbb, buf, limit - buf) || - !CBB_add_u16_length_prefixed(&cbb, &extensions)) { - goto err; - } - - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (!(s->s3->tmp.extensions.received & (1u << i))) { - /* Don't send extensions that were not received. */ - continue; - } - - if (!kExtensions[i].add_serverhello(s, &extensions)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - goto err; - } - } - - if (!custom_ext_add_serverhello(s, &extensions)) { - goto err; - } - - if (!CBB_flush(&cbb)) { - goto err; - } - - uint8_t *ret = buf; - const size_t cbb_len = CBB_len(&cbb); - /* If only two bytes have been written then the extensions are actually empty - * and those two bytes are the zero length. In that case, we don't bother - * sending the extensions length. */ - if (cbb_len > 2) { - ret += cbb_len; - } - - CBB_cleanup(&cbb); - return ret; - -err: - CBB_cleanup(&cbb); - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; -} - -static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) { - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (kExtensions[i].init != NULL) { - kExtensions[i].init(s); - } - } - - s->s3->tmp.extensions.received = 0; - s->s3->tmp.custom_extensions.received = 0; - /* The renegotiation extension must always be at index zero because the - * |received| and |sent| bitsets need to be tweaked when the "extension" is - * sent as an SCSV. */ - assert(kExtensions[0].value == TLSEXT_TYPE_renegotiate); - - /* There may be no extensions. */ - if (CBS_len(cbs) != 0) { - /* Decode the extensions block and check it is valid. */ - CBS extensions; - if (!CBS_get_u16_length_prefixed(cbs, &extensions) || - !tls1_check_duplicate_extensions(&extensions)) { + /* Decode the next extension. */ + if (!CBS_get_u16(&extensions, &type) || + !CBS_get_u16_length_prefixed(&extensions, &extension)) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; - - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { + if (type == TLSEXT_TYPE_server_name) { + /* The extension must be empty. */ + if (CBS_len(&extension) != 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - unsigned ext_index; - const struct tls_extension *const ext = - tls_extension_find(&ext_index, type); + /* We must have sent it in ClientHello. */ + if (s->tlsext_hostname == NULL) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } - if (ext == NULL) { - if (!custom_ext_parse_clienthello(s, out_alert, type, &extension)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - return 0; - } - continue; + tlsext_servername = 1; + } else if (type == TLSEXT_TYPE_ec_point_formats) { + CBS ec_point_format_list; + + if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) || + CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } - s->s3->tmp.extensions.received |= (1u << ext_index); - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_clienthello(s, &alert, &extension)) { - *out_alert = alert; - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)type); + if (!CBS_stow(&ec_point_format_list, &s->s3->tmp.peer_ecpointformatlist, + &s->s3->tmp.peer_ecpointformatlist_length)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_session_ticket) { + if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || CBS_len(&extension) > 0) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; return 0; } - } - } - for (i = 0; i < kNumExtensions; i++) { - if (!(s->s3->tmp.extensions.received & (1u << i))) { - /* Extension wasn't observed so call the callback with a NULL - * parameter. */ - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_clienthello(s, &alert, NULL)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - *out_alert = alert; + s->tlsext_ticket_expected = 1; + } else if (type == TLSEXT_TYPE_status_request) { + /* The extension MUST be empty and may only sent if we've requested a + * status request message. */ + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; return 0; } - } - } - return 1; -} + if (!s->ocsp_stapling_enabled) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } -int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) { - int alert = -1; - if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0) { - ssl3_send_alert(s, SSL3_AL_FATAL, alert); - return 0; - } + /* Set a flag to expect a CertificateStatus message */ + s->s3->tmp.certificate_status_expected = 1; + } else if (type == TLSEXT_TYPE_next_proto_neg && + !s->s3->initial_handshake_complete && !SSL_IS_DTLS(s)) { + uint8_t *selected; + uint8_t selected_len; - if (ssl_check_clienthello_tlsext(s) <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT); - return 0; - } + /* We must have requested it. */ + if (s->ctx->next_proto_select_cb == NULL) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } - return 1; -} + /* The data must be valid. */ + if (!ssl_next_proto_validate(&extension)) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } -static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { - uint32_t received = 0; - assert(kNumExtensions <= sizeof(received) * 8); - - if (CBS_len(cbs) != 0) { - /* Decode the extensions block and check it is valid. */ - CBS extensions; - if (!CBS_get_u16_length_prefixed(cbs, &extensions) || - !tls1_check_duplicate_extensions(&extensions)) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + if (s->ctx->next_proto_select_cb( + s, &selected, &selected_len, CBS_data(&extension), + CBS_len(&extension), + s->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + s->next_proto_negotiated = BUF_memdup(selected, selected_len); + if (s->next_proto_negotiated == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + s->next_proto_negotiated_len = selected_len; + s->s3->next_proto_neg_seen = 1; + } else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + !s->s3->initial_handshake_complete) { + CBS protocol_name_list, protocol_name; - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; + /* We must have requested it. */ + if (s->alpn_client_proto_list == NULL) { + *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { + /* The extension data consists of a ProtocolNameList which must have + * exactly one ProtocolName. Each of these is length-prefixed. */ + if (!CBS_get_u16_length_prefixed(&extension, &protocol_name_list) || + CBS_len(&extension) != 0 || + !CBS_get_u8_length_prefixed(&protocol_name_list, &protocol_name) || + CBS_len(&protocol_name_list) != 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - unsigned ext_index; - const struct tls_extension *const ext = - tls_extension_find(&ext_index, type); + if (!CBS_stow(&protocol_name, &s->s3->alpn_selected, + &s->s3->alpn_selected_len)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_channel_id && !SSL_IS_DTLS(s)) { + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } - if (ext == NULL) { - if (!custom_ext_parse_serverhello(s, out_alert, type, &extension)) { - return 0; - } - continue; + s->s3->tlsext_channel_id_valid = 1; + } else if (type == TLSEXT_TYPE_channel_id_new && !SSL_IS_DTLS(s)) { + if (CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } - if (!(s->s3->tmp.extensions.sent & (1u << ext_index))) { - /* If the extension was never sent then it is illegal. */ - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); - ERR_add_error_dataf("extension :%u", (unsigned)type); + s->s3->tlsext_channel_id_valid = 1; + s->s3->tlsext_channel_id_new = 1; + } else if (type == TLSEXT_TYPE_certificate_timestamp) { + if (CBS_len(&extension) == 0) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - received |= (1u << ext_index); + /* Session resumption uses the original session information. */ + if (!s->hit && + !CBS_stow(&extension, &s->session->tlsext_signed_cert_timestamp_list, + &s->session->tlsext_signed_cert_timestamp_list_length)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else if (type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_serverhello_renegotiate_ext(s, &extension, out_alert)) { + return 0; + } - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_serverhello(s, &alert, &extension)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)type); - *out_alert = alert; + renegotiate_seen = 1; + } else if (type == TLSEXT_TYPE_use_srtp) { + if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) { return 0; } + } else if (type == TLSEXT_TYPE_extended_master_secret) { + if (/* It is invalid for the server to select EMS and + SSLv3. */ + s->version == SSL3_VERSION || CBS_len(&extension) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + s->s3->tmp.extended_master_secret = 1; } } - size_t i; - for (i = 0; i < kNumExtensions; i++) { - if (!(received & (1u << i))) { - /* Extension wasn't observed so call the callback with a NULL - * parameter. */ - uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_serverhello(s, &alert, NULL)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); - ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value); - *out_alert = alert; + if (!s->hit && tlsext_servername == 1 && s->tlsext_hostname) { + if (s->session->tlsext_hostname == NULL) { + s->session->tlsext_hostname = BUF_strdup(s->tlsext_hostname); + if (!s->session->tlsext_hostname) { + *out_alert = SSL_AD_UNRECOGNIZED_NAME; return 0; } + } else { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; } } +ri_check: + /* Determine if we need to see RI. Strictly speaking if we want to avoid an + * attack we should *always* see RI even on initial server hello because the + * client doesn't see any renegotiation during an attack. However this would + * mean we could not connect to any server which doesn't support RI so for + * the immediate future tolerate RI absence on initial connect only. */ + if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) && + !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, ssl_scan_serverhello_tlsext, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + return 1; } +int ssl_prepare_clienthello_tlsext(SSL *s) { return 1; } + +int ssl_prepare_serverhello_tlsext(SSL *s) { return 1; } + static int ssl_check_clienthello_tlsext(SSL *s) { int ret = SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -2568,7 +1947,7 @@ static int ssl_check_clienthello_tlsext(SSL *s) { return 1; case SSL_TLSEXT_ERR_NOACK: - s->s3->tmp.should_ack_sni = 0; + s->should_ack_sni = 0; return 1; default: @@ -2577,9 +1956,22 @@ static int ssl_check_clienthello_tlsext(SSL *s) { } static int ssl_check_serverhello_tlsext(SSL *s) { - int ret = SSL_TLSEXT_ERR_OK; + int ret = SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; + /* If we are client and using an elliptic curve cryptography cipher suite, + * then if server returns an EC point formats lists extension it must contain + * uncompressed. */ + uint32_t alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + uint32_t alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if (((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) && + !tls1_check_point_format(s, TLSEXT_ECPOINTFORMAT_uncompressed)) { + OPENSSL_PUT_ERROR(SSL, ssl_check_serverhello_tlsext, + SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); + return -1; + } + ret = SSL_TLSEXT_ERR_OK; + if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) { ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg); @@ -2615,131 +2007,203 @@ int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs) { } if (ssl_check_serverhello_tlsext(s) <= 0) { - OPENSSL_PUT_ERROR(SSL, SSL_R_SERVERHELLO_TLSEXT); + OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_tlsext, + SSL_R_SERVERHELLO_TLSEXT); return 0; } return 1; } -int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, - int *out_send_ticket, const uint8_t *ticket, - size_t ticket_len, const uint8_t *session_id, - size_t session_id_len) { - int ret = 1; /* Most errors are non-fatal. */ - SSL_CTX *ssl_ctx = ssl->initial_ctx; - uint8_t *plaintext = NULL; - - HMAC_CTX hmac_ctx; - HMAC_CTX_init(&hmac_ctx); - EVP_CIPHER_CTX cipher_ctx; - EVP_CIPHER_CTX_init(&cipher_ctx); - - *out_send_ticket = 0; - *out_session = NULL; +/* Since the server cache lookup is done early on in the processing of the + * ClientHello, and other operations depend on the result, we need to handle + * any TLS session ticket extension at the same time. + * + * ctx: contains the early callback context, which is the result of a + * shallow parse of the ClientHello. + * ret: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 0: no ticket was found (or was ignored, based on settings). + * 1: a zero length extension was found, indicating that the client supports + * session tickets but doesn't currently have one to offer. + * 2: a ticket was offered but couldn't be decrypted because of a non-fatal + * error. + * 3: a ticket was successfully decrypted and *ret was set. + * + * Side effects: + * Sets s->tlsext_ticket_expected to 1 if the server will have to issue + * a new session ticket to the client because the client indicated support + * but the client either doesn't have a session ticket or we couldn't use + * the one it gave us, or if s->ctx->tlsext_ticket_key_cb asked to renew + * the client's ticket. Otherwise, s->tlsext_ticket_expected is set to 0. + */ +int tls1_process_ticket(SSL *s, const struct ssl_early_callback_ctx *ctx, + SSL_SESSION **ret) { + *ret = NULL; + s->tlsext_ticket_expected = 0; + const uint8_t *data; + size_t len; + int r; - if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { - goto done; + /* If tickets disabled behave as if no ticket present to permit stateful + * resumption. */ + if ((SSL_get_options(s) & SSL_OP_NO_TICKET) || + (s->version <= SSL3_VERSION && !ctx->extensions) || + !SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket, + &data, &len)) { + return 0; } - if (ticket_len == 0) { + if (len == 0) { /* The client will accept a ticket but doesn't currently have one. */ - *out_send_ticket = 1; - goto done; + s->tlsext_ticket_expected = 1; + return 1; + } + + r = tls_decrypt_ticket(s, data, len, ctx->session_id, ctx->session_id_len, + ret); + switch (r) { + case 2: /* ticket couldn't be decrypted */ + s->tlsext_ticket_expected = 1; + return 2; + + case 3: /* ticket was decrypted */ + return r; + + case 4: /* ticket decrypted but need to renew */ + s->tlsext_ticket_expected = 1; + return 3; + + default: /* fatal error */ + return -1; } +} + +/* tls_decrypt_ticket attempts to decrypt a session ticket. + * + * etick: points to the body of the session ticket extension. + * eticklen: the length of the session tickets extenion. + * sess_id: points at the session ID. + * sesslen: the length of the session ID. + * psess: (output) on return, if a ticket was decrypted, then this is set to + * point to the resulting session. + * + * Returns: + * -1: fatal error, either from parsing or decrypting the ticket. + * 2: the ticket couldn't be decrypted. + * 3: a ticket was successfully decrypted and *psess was set. + * 4: same as 3, but the ticket needs to be renewed. */ +static int tls_decrypt_ticket(SSL *s, const uint8_t *etick, int eticklen, + const uint8_t *sess_id, int sesslen, + SSL_SESSION **psess) { + SSL_SESSION *sess; + uint8_t *sdec; + const uint8_t *p; + int slen, mlen, renew_ticket = 0; + uint8_t tick_hmac[EVP_MAX_MD_SIZE]; + HMAC_CTX hctx; + EVP_CIPHER_CTX ctx; + SSL_CTX *tctx = s->initial_ctx; /* Ensure there is room for the key name and the largest IV * |tlsext_ticket_key_cb| may try to consume. The real limit may be lower, but * the maximum IV length should be well under the minimum size for the * session material and HMAC. */ - if (ticket_len < SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH) { - goto done; - } - const uint8_t *iv = ticket + SSL_TICKET_KEY_NAME_LEN; - - if (ssl_ctx->tlsext_ticket_key_cb != NULL) { - int cb_ret = ssl_ctx->tlsext_ticket_key_cb(ssl, (uint8_t*)ticket /* name */, - (uint8_t*)iv, &cipher_ctx, &hmac_ctx, - 0 /* decrypt */); - if (cb_ret < 0) { - ret = 0; - goto done; + if (eticklen < 16 + EVP_MAX_IV_LENGTH) { + return 2; + } + + /* Initialize session ticket encryption and HMAC contexts */ + HMAC_CTX_init(&hctx); + EVP_CIPHER_CTX_init(&ctx); + if (tctx->tlsext_ticket_key_cb) { + uint8_t *nctick = (uint8_t *)etick; + int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16, &ctx, &hctx, + 0 /* decrypt */); + if (rv < 0) { + return -1; } - if (cb_ret == 0) { - goto done; + if (rv == 0) { + return 2; } - if (cb_ret == 2) { - *out_send_ticket = 1; + if (rv == 2) { + renew_ticket = 1; } } else { - /* Check the key name matches. */ - if (memcmp(ticket, ssl_ctx->tlsext_tick_key_name, - SSL_TICKET_KEY_NAME_LEN) != 0) { - goto done; + /* Check key name matches */ + if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) { + return 2; } - if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key, - sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(), + if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), NULL) || - !EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL, - ssl_ctx->tlsext_tick_aes_key, iv)) { - ret = 0; - goto done; + !EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, + tctx->tlsext_tick_aes_key, etick + 16)) { + HMAC_CTX_cleanup(&hctx); + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; } } - size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx); - /* Check the MAC at the end of the ticket. */ - uint8_t mac[EVP_MAX_MD_SIZE]; - size_t mac_len = HMAC_size(&hmac_ctx); - if (ticket_len < SSL_TICKET_KEY_NAME_LEN + iv_len + 1 + mac_len) { + /* First, check the MAC. The MAC is at the end of the ticket. */ + mlen = HMAC_size(&hctx); + if ((size_t) eticklen < 16 + EVP_CIPHER_CTX_iv_length(&ctx) + 1 + mlen) { /* The ticket must be large enough for key name, IV, data, and MAC. */ - goto done; - } - HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len); - HMAC_Final(&hmac_ctx, mac, NULL); - if (CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) != 0) { - goto done; - } - - /* Decrypt the session data. */ - const uint8_t *ciphertext = ticket + SSL_TICKET_KEY_NAME_LEN + iv_len; - size_t ciphertext_len = ticket_len - SSL_TICKET_KEY_NAME_LEN - iv_len - - mac_len; - plaintext = OPENSSL_malloc(ciphertext_len); - if (plaintext == NULL) { - ret = 0; - goto done; - } - if (ciphertext_len >= INT_MAX) { - goto done; - } - int len1, len2; - if (!EVP_DecryptUpdate(&cipher_ctx, plaintext, &len1, ciphertext, - (int)ciphertext_len) || - !EVP_DecryptFinal_ex(&cipher_ctx, plaintext + len1, &len2)) { - ERR_clear_error(); /* Don't leave an error on the queue. */ - goto done; + HMAC_CTX_cleanup(&hctx); + EVP_CIPHER_CTX_cleanup(&ctx); + return 2; + } + eticklen -= mlen; + /* Check HMAC of encrypted ticket */ + HMAC_Update(&hctx, etick, eticklen); + HMAC_Final(&hctx, tick_hmac, NULL); + HMAC_CTX_cleanup(&hctx); + if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen)) { + EVP_CIPHER_CTX_cleanup(&ctx); + return 2; + } + + /* Attempt to decrypt session data */ + /* Move p after IV to start of encrypted ticket, update length */ + p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx); + eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx); + sdec = OPENSSL_malloc(eticklen); + if (!sdec) { + EVP_CIPHER_CTX_cleanup(&ctx); + return -1; } - - /* Decode the session. */ - SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, len1 + len2); - if (session == NULL) { - ERR_clear_error(); /* Don't leave an error on the queue. */ - goto done; + EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen); + if (EVP_DecryptFinal_ex(&ctx, sdec + slen, &mlen) <= 0) { + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_free(sdec); + return 2; + } + slen += mlen; + EVP_CIPHER_CTX_cleanup(&ctx); + p = sdec; + + sess = SSL_SESSION_from_bytes(sdec, slen); + OPENSSL_free(sdec); + if (sess) { + /* The session ID, if non-empty, is used by some clients to detect that the + * ticket has been accepted. So we copy it to the session structure. If it + * is empty set length to zero as required by standard. */ + if (sesslen) { + memcpy(sess->session_id, sess_id, sesslen); + } + sess->session_id_length = sesslen; + *psess = sess; + if (renew_ticket) { + return 4; + } + return 3; } - /* Copy the client's session ID into the new session, to denote the ticket has - * been accepted. */ - memcpy(session->session_id, session_id, session_id_len); - session->session_id_length = session_id_len; - - *out_session = session; - -done: - OPENSSL_free(plaintext); - HMAC_CTX_cleanup(&hmac_ctx); - EVP_CIPHER_CTX_cleanup(&cipher_ctx); - return ret; + ERR_clear_error(); + /* For session parse failure, indicate that we need to send a new ticket. */ + return 2; } /* Tables to translate from NIDs to TLS v1.2 ids */ @@ -2769,12 +2233,18 @@ static int tls12_find_id(int nid, const tls12_lookup *table, size_t tlen) { return -1; } -int tls12_get_sigid(int pkey_type) { - return tls12_find_id(pkey_type, tls12_sig, - sizeof(tls12_sig) / sizeof(tls12_lookup)); +static int tls12_find_nid(int id, const tls12_lookup *table, size_t tlen) { + size_t i; + for (i = 0; i < tlen; i++) { + if (table[i].id == id) { + return table[i].nid; + } + } + + return NID_undef; } -int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { +int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) { int sig_id, md_id; if (!md) { @@ -2787,7 +2257,7 @@ int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { return 0; } - sig_id = tls12_get_sigid(ssl_private_key_type(ssl)); + sig_id = tls12_get_sigid(pk); if (sig_id == -1) { return 0; } @@ -2797,6 +2267,11 @@ int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { return 1; } +int tls12_get_sigid(const EVP_PKEY *pk) { + return tls12_find_id(pk->type, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); +} + const EVP_MD *tls12_get_hash(uint8_t hash_alg) { switch (hash_alg) { case TLSEXT_hash_md5: @@ -2837,129 +2312,256 @@ static int tls12_get_pkey_type(uint8_t sig_alg) { } } -OPENSSL_COMPILE_ASSERT(sizeof(TLS_SIGALGS) == 2, - sizeof_tls_sigalgs_is_not_two); +/* Convert TLS 1.2 signature algorithm extension values into NIDs */ +static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid, + int *psignhash_nid, const uint8_t *data) { + int sign_nid = 0, hash_nid = 0; + if (!phash_nid && !psign_nid && !psignhash_nid) { + return; + } -int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { - /* Extension ignored for inappropriate versions */ - if (!SSL_USE_SIGALGS(ssl)) { - return 1; + if (phash_nid || psignhash_nid) { + hash_nid = tls12_find_nid(data[0], tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + if (phash_nid) { + *phash_nid = hash_nid; + } } - CERT *const cert = ssl->cert; - OPENSSL_free(cert->peer_sigalgs); - cert->peer_sigalgs = NULL; - cert->peer_sigalgslen = 0; + if (psign_nid || psignhash_nid) { + sign_nid = tls12_find_nid(data[1], tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); + if (psign_nid) { + *psign_nid = sign_nid; + } + } - size_t num_sigalgs = CBS_len(in_sigalgs); + if (psignhash_nid) { + if (sign_nid && hash_nid) { + OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, sign_nid); + } else { + *psignhash_nid = NID_undef; + } + } +} - if (num_sigalgs % 2 != 0) { - return 0; +/* Given preference and allowed sigalgs set shared sigalgs */ +static int tls12_do_shared_sigalgs(TLS_SIGALGS *shsig, const uint8_t *pref, + size_t preflen, const uint8_t *allow, + size_t allowlen) { + const uint8_t *ptmp, *atmp; + size_t i, j, nmatch = 0; + + for (i = 0, ptmp = pref; i < preflen; i += 2, ptmp += 2) { + /* Skip disabled hashes or signature algorithms */ + if (tls12_get_hash(ptmp[0]) == NULL || + tls12_get_pkey_type(ptmp[1]) == -1) { + continue; + } + + for (j = 0, atmp = allow; j < allowlen; j += 2, atmp += 2) { + if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1]) { + nmatch++; + if (shsig) { + shsig->rhash = ptmp[0]; + shsig->rsign = ptmp[1]; + tls1_lookup_sigalg(&shsig->hash_nid, &shsig->sign_nid, + &shsig->signandhash_nid, ptmp); + shsig++; + } + + break; + } + } + } + + return nmatch; +} + +/* Set shared signature algorithms for SSL structures */ +static int tls1_set_shared_sigalgs(SSL *s) { + const uint8_t *pref, *allow, *conf; + size_t preflen, allowlen, conflen; + size_t nmatch; + TLS_SIGALGS *salgs = NULL; + CERT *c = s->cert; + + OPENSSL_free(c->shared_sigalgs); + c->shared_sigalgs = NULL; + c->shared_sigalgslen = 0; + + /* If client use client signature algorithms if not NULL */ + if (!s->server && c->client_sigalgs) { + conf = c->client_sigalgs; + conflen = c->client_sigalgslen; + } else if (c->conf_sigalgs) { + conf = c->conf_sigalgs; + conflen = c->conf_sigalgslen; + } else { + conflen = tls12_get_psigalgs(s, &conf); } - num_sigalgs /= 2; - /* supported_signature_algorithms in the certificate request is - * allowed to be empty. */ - if (num_sigalgs == 0) { + if (s->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + pref = conf; + preflen = conflen; + allow = c->peer_sigalgs; + allowlen = c->peer_sigalgslen; + } else { + allow = conf; + allowlen = conflen; + pref = c->peer_sigalgs; + preflen = c->peer_sigalgslen; + } + + nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen); + if (!nmatch) { return 1; } - /* This multiplication doesn't overflow because sizeof(TLS_SIGALGS) is two - * (statically asserted above) and we just divided |num_sigalgs| by two. */ - cert->peer_sigalgs = OPENSSL_malloc(num_sigalgs * sizeof(TLS_SIGALGS)); - if (cert->peer_sigalgs == NULL) { + salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS)); + if (!salgs) { return 0; } - cert->peer_sigalgslen = num_sigalgs; - CBS sigalgs; - CBS_init(&sigalgs, CBS_data(in_sigalgs), CBS_len(in_sigalgs)); + nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen); + c->shared_sigalgs = salgs; + c->shared_sigalgslen = nmatch; + return 1; +} - size_t i; - for (i = 0; i < num_sigalgs; i++) { - TLS_SIGALGS *const sigalg = &cert->peer_sigalgs[i]; - if (!CBS_get_u8(&sigalgs, &sigalg->rhash) || - !CBS_get_u8(&sigalgs, &sigalg->rsign)) { - return 0; - } +/* Set preferred digest for each key type */ +int tls1_process_sigalgs(SSL *s, const CBS *sigalgs) { + CERT *c = s->cert; + + /* Extension ignored for inappropriate versions */ + if (!SSL_USE_SIGALGS(s)) { + return 1; + } + + if (CBS_len(sigalgs) % 2 != 0 || + !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) || + !tls1_set_shared_sigalgs(s)) { + return 0; } return 1; } -const EVP_MD *tls1_choose_signing_digest(SSL *ssl) { - CERT *cert = ssl->cert; - int type = ssl_private_key_type(ssl); - size_t i, j; - - static const int kDefaultDigestList[] = {NID_sha256, NID_sha384, NID_sha512, - NID_sha224, NID_sha1}; - - const int *digest_nids = kDefaultDigestList; - size_t num_digest_nids = - sizeof(kDefaultDigestList) / sizeof(kDefaultDigestList[0]); - if (cert->digest_nids != NULL) { - digest_nids = cert->digest_nids; - num_digest_nids = cert->num_digest_nids; - } - - for (i = 0; i < num_digest_nids; i++) { - const int digest_nid = digest_nids[i]; - for (j = 0; j < cert->peer_sigalgslen; j++) { - const EVP_MD *md = tls12_get_hash(cert->peer_sigalgs[j].rhash); - if (md == NULL || - digest_nid != EVP_MD_type(md) || - tls12_get_pkey_type(cert->peer_sigalgs[j].rsign) != type) { - continue; - } +const EVP_MD *tls1_choose_signing_digest(SSL *s, EVP_PKEY *pkey) { + CERT *c = s->cert; + int type = EVP_PKEY_id(pkey); + size_t i; - return md; + /* Select the first shared digest supported by our key. */ + for (i = 0; i < c->shared_sigalgslen; i++) { + const EVP_MD *md = tls12_get_hash(c->shared_sigalgs[i].rhash); + if (md == NULL || + tls12_get_pkey_type(c->shared_sigalgs[i].rsign) != type || + !EVP_PKEY_supports_digest(pkey, md)) { + continue; } + return md; } /* If no suitable digest may be found, default to SHA-1. */ return EVP_sha1(); } -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { - int ret = 0; - EVP_MD_CTX ctx; +int SSL_get_sigalgs(SSL *s, int idx, int *psign, int *phash, int *psignhash, + uint8_t *rsig, uint8_t *rhash) { + const uint8_t *psig = s->cert->peer_sigalgs; - EVP_MD_CTX_init(&ctx); - if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) { - goto err; + if (psig == NULL) { + return 0; } + if (idx >= 0) { + idx <<= 1; + if (idx >= (int)s->cert->peer_sigalgslen) { + return 0; + } + psig += idx; + if (rhash) { + *rhash = psig[0]; + } + if (rsig) { + *rsig = psig[1]; + } + tls1_lookup_sigalg(phash, psign, psignhash, psig); + } + + return s->cert->peer_sigalgslen / 2; +} + +int SSL_get_shared_sigalgs(SSL *s, int idx, int *psign, int *phash, + int *psignhash, uint8_t *rsig, uint8_t *rhash) { + TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs; + + if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen) { + return 0; + } + + shsigalgs += idx; + if (phash) { + *phash = shsigalgs->hash_nid; + } + if (psign) { + *psign = shsigalgs->sign_nid; + } + if (psignhash) { + *psignhash = shsigalgs->signandhash_nid; + } + if (rsig) { + *rsig = shsigalgs->rsign; + } + if (rhash) { + *rhash = shsigalgs->rhash; + } + + return s->cert->shared_sigalgslen; +} + +/* tls1_channel_id_hash calculates the signed data for a Channel ID on the + * given SSL connection and writes it to |md|. */ +int tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) { + EVP_MD_CTX ctx; + uint8_t temp_digest[EVP_MAX_MD_SIZE]; + unsigned temp_digest_len; + int i; static const char kClientIDMagic[] = "TLS Channel ID signature"; - EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic)); - if (ssl->hit) { + if (s->s3->handshake_buffer && + !ssl3_digest_cached_records(s, free_handshake_buffer)) { + return 0; + } + + EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic)); + + if (s->hit && s->s3->tlsext_channel_id_new) { static const char kResumptionMagic[] = "Resumption"; - EVP_DigestUpdate(&ctx, kResumptionMagic, sizeof(kResumptionMagic)); - if (ssl->session->original_handshake_hash_len == 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - goto err; + EVP_DigestUpdate(md, kResumptionMagic, sizeof(kResumptionMagic)); + if (s->session->original_handshake_hash_len == 0) { + return 0; } - EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash, - ssl->session->original_handshake_hash_len); + EVP_DigestUpdate(md, s->session->original_handshake_hash, + s->session->original_handshake_hash_len); } - uint8_t handshake_hash[EVP_MAX_MD_SIZE]; - int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash, - sizeof(handshake_hash)); - if (handshake_hash_len < 0) { - goto err; + EVP_MD_CTX_init(&ctx); + for (i = 0; i < SSL_MAX_DIGEST; i++) { + if (s->s3->handshake_dgst[i] == NULL) { + continue; + } + if (!EVP_MD_CTX_copy_ex(&ctx, s->s3->handshake_dgst[i])) { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } + EVP_DigestFinal_ex(&ctx, temp_digest, &temp_digest_len); + EVP_DigestUpdate(md, temp_digest, temp_digest_len); } - EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len); - unsigned len_u; - EVP_DigestFinal_ex(&ctx, out, &len_u); - *out_len = len_u; - - ret = 1; - -err: EVP_MD_CTX_cleanup(&ctx); - return ret; + + return 1; } /* tls1_record_handshake_hashes_for_channel_id records the current handshake @@ -2973,6 +2575,12 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *s) { return -1; } + /* It only makes sense to call this function if Channel IDs have been + * negotiated. */ + if (!s->s3->tlsext_channel_id_new) { + return -1; + } + digest_len = tls1_handshake_digest(s, s->session->original_handshake_hash, sizeof(s->session->original_handshake_hash)); @@ -2984,3 +2592,48 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *s) { return 1; } + +int tls1_set_sigalgs(CERT *c, const int *psig_nids, size_t salglen, + int client) { + uint8_t *sigalgs, *sptr; + int rhash, rsign; + size_t i; + + if (salglen & 1) { + return 0; + } + + sigalgs = OPENSSL_malloc(salglen); + if (sigalgs == NULL) { + return 0; + } + + for (i = 0, sptr = sigalgs; i < salglen; i += 2) { + rhash = tls12_find_id(*psig_nids++, tls12_md, + sizeof(tls12_md) / sizeof(tls12_lookup)); + rsign = tls12_find_id(*psig_nids++, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); + + if (rhash == -1 || rsign == -1) { + goto err; + } + *sptr++ = rhash; + *sptr++ = rsign; + } + + if (client) { + OPENSSL_free(c->client_sigalgs); + c->client_sigalgs = sigalgs; + c->client_sigalgslen = salglen; + } else { + OPENSSL_free(c->conf_sigalgs); + c->conf_sigalgs = sigalgs; + c->conf_sigalgslen = salglen; + } + + return 1; + +err: + OPENSSL_free(sigalgs); + return 0; +} -- cgit v1.1