diff options
Diffstat (limited to 'src/ssl/t1_lib.c')
-rw-r--r-- | src/ssl/t1_lib.c | 3135 |
1 files changed, 1741 insertions, 1394 deletions
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index 213a647..f30e8eb 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -106,12 +106,16 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ +#include <openssl/ssl.h> + #include <assert.h> +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/bytestring.h> +#include <openssl/digest.h> #include <openssl/err.h> #include <openssl/evp.h> #include <openssl/hmac.h> @@ -122,9 +126,6 @@ #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); @@ -213,8 +214,7 @@ 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, tls1_check_duplicate_extensions, - ERR_R_MALLOC_FAILURE); + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto done; } @@ -338,24 +338,21 @@ 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}, - {23, NID_X9_62_prime256v1}, - {24, NID_secp384r1}, - {25, NID_secp521r1}, -}; - -static const uint8_t ecformats_default[] = { - TLSEXT_ECPOINTFORMAT_uncompressed, + {21, NID_secp224r1, "P-224"}, + {23, NID_X9_62_prime256v1, "P-256"}, + {24, NID_secp384r1, "P-384"}, + {25, NID_secp521r1, "P-521"}, }; static const uint16_t eccurves_default[] = { 23, /* X9_62_prime256v1 */ 24, /* secp384r1 */ -#if defined(ANDROID) +#if defined(BORINGSSL_ANDROID_SYSTEM) 25, /* secp521r1 */ #endif }; @@ -381,6 +378,16 @@ 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. */ @@ -535,28 +542,6 @@ 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. */ @@ -593,18 +578,6 @@ 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); @@ -615,7 +588,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) || - !tls1_check_point_format(s, comp_id)) { + comp_id != TLSEXT_ECPOINTFORMAT_uncompressed) { goto done; } @@ -663,17 +636,8 @@ static const uint8_t tls12_sigalgs[] = { }; size_t tls12_get_psigalgs(SSL *s, const uint8_t **psigs) { - /* 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); - } + *psigs = tls12_sigalgs; + return sizeof(tls12_sigalgs); } /* tls12_check_peer_sigalg parses a SignatureAndHashAlgorithm out of |cbs|. It @@ -684,26 +648,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); + int sigalg = tls12_get_sigid(pkey->type); uint8_t hash, signature; /* Should never happen */ if (sigalg == -1) { - OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, ERR_R_INTERNAL_ERROR); + OPENSSL_PUT_ERROR(SSL, 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, tls12_check_peer_sigalg, SSL_R_DECODE_ERROR); + OPENSSL_PUT_ERROR(SSL, 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, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE); + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -718,8 +682,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) || - !tls1_check_point_format(s, comp_id))) { - OPENSSL_PUT_ERROR(SSL, tls12_check_peer_sigalg, SSL_R_WRONG_CURVE); + comp_id != TLSEXT_ECPOINTFORMAT_uncompressed)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -735,14 +699,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, tls12_check_peer_sigalg, SSL_R_WRONG_SIGNATURE_TYPE); + OPENSSL_PUT_ERROR(SSL, 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, tls12_check_peer_sigalg, SSL_R_UNKNOWN_DIGEST); + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_DIGEST); *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -799,1128 +763,1785 @@ void ssl_set_client_disabled(SSL *s) { } } -/* 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; - } - } +/* 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; } - /* don't add extensions for SSLv3 unless doing secure renegotiation */ - if (s->client_version == SSL3_VERSION && !s->s3->send_connection_binding) { - return orig; + 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; } - ret += 2; + return 1; +} - if (ret >= limit) { - return NULL; /* should never occur. */ +static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, CBS *contents) { + if (contents == NULL) { + return 1; } - if (s->tlsext_hostname != NULL) { - /* Add TLS extension servername to the Client Hello message */ - unsigned long size_str; - long lenmax; + if (CBS_len(contents) != 0) { + return 0; + } - /* 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 */ + assert(ssl->tlsext_hostname != NULL); - lenmax = limit - ret - 9; - size_str = strlen(s->tlsext_hostname); - if (lenmax < 0 || size_str > (unsigned long)lenmax) { - return NULL; + 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; } + } - /* extension type and length */ - s2n(TLSEXT_TYPE_server_name, ret); - s2n(size_str + 5, ret); + return 1; +} - /* length of servername list */ - s2n(size_str + 3, ret); +static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { + if (contents == NULL) { + return 1; + } - /* 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; + /* 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; } - /* Add RI if renegotiating */ - if (s->s3->initial_handshake_complete) { - int el; + /* Decode each ServerName in the extension. */ + while (CBS_len(&server_name_list) > 0) { + uint8_t name_type; + CBS host_name; - if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) { - OPENSSL_PUT_ERROR(SSL, ssl_add_clienthello_tlsext, ERR_R_INTERNAL_ERROR); - return NULL; + if (!CBS_get_u8(&server_name_list, &name_type) || + !CBS_get_u16_length_prefixed(&server_name_list, &host_name)) { + return 0; } - if ((limit - ret - 4 - el) < 0) { - return NULL; + /* Only host_name is supported. */ + if (name_type != TLSEXT_NAMETYPE_host_name) { + continue; } - 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; + if (have_seen_host_name) { + /* The ServerNameList MUST NOT contain more than one name of the same + * name_type. */ + return 0; } - ret += el; - } + have_seen_host_name = 1; - /* 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 (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; } - /* 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; + if (!ssl->hit) { + assert(ssl->session->tlsext_hostname == NULL); + if (ssl->session->tlsext_hostname) { + /* This should be impossible. */ + return 0; + } + + /* Copy the hostname as a string. */ + if (!CBS_strdup(&host_name, &ssl->session->tlsext_hostname)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } + + ssl->s3->tmp.should_ack_sni = 1; } } - 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; - } + return 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); +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->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); + if (!CBB_add_u16(out, TLSEXT_TYPE_server_name) || + !CBB_add_u16(out, 0 /* length */)) { + return 0; } - 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; + return 1; +} + + +/* 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 (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; + return 1; +} + +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 (s->ctx->tlsext_channel_id_enabled_new) { - s2n(TLSEXT_TYPE_channel_id_new, ret); + + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + const size_t expected_len = ssl->s3->previous_client_finished_len + + ssl->s3->previous_server_finished_len; + + /* Check for logic errors */ + assert(!expected_len || ssl->s3->previous_client_finished_len); + assert(!expected_len || ssl->s3->previous_server_finished_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; + } + + /* 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; + } + + 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; + + 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; + + return 1; +} + +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 { - s2n(TLSEXT_TYPE_channel_id, ret); + return 1; } - s2n(0, ret); } - if (SSL_get_srtp_profiles(s)) { - int el; + CBS renegotiated_connection; - ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0); + 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 - el) < 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_use_srtp, ret); - s2n(el, ret); + ssl->s3->send_connection_binding = 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; - } - ret += el; + 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; } - 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; + return 1; +} - tls1_get_formatlist(s, &formats, &formats_len); - 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; - } +/* Extended Master Secret. + * + * https://tools.ietf.org/html/draft-ietf-tls-session-hash-05 */ - 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; +static void ext_ems_init(SSL *ssl) { + ssl->s3->tmp.extended_master_secret = 0; +} - /* Add TLS extension EllipticCurves to the ClientHello message */ - tls1_get_curvelist(s, 0, &curves, &curves_len); +static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { + if (ssl->version == SSL3_VERSION) { + return 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; - } + if (!CBB_add_u16(out, TLSEXT_TYPE_extended_master_secret) || + !CBB_add_u16(out, 0 /* length */)) { + return 0; + } - s2n(TLSEXT_TYPE_elliptic_curves, ret); - s2n((curves_len * 2) + 2, ret); + return 1; +} - s2n(curves_len * 2, ret); - for (i = 0; i < curves_len; i++) { - s2n(curves[i], ret); - } +static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; } - 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 (ssl->version == SSL3_VERSION || CBS_len(contents) != 0) { + return 0; + } - if (limit - ret - 4 - (long)padding_len < 0) { - return NULL; - } + ssl->s3->tmp.extended_master_secret = 1; + return 1; +} - s2n(TLSEXT_TYPE_padding, ret); - s2n(padding_len, ret); - memset(ret, 0, padding_len); - ret += padding_len; - } +static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { + if (ssl->version == SSL3_VERSION || contents == NULL) { + return 1; } - extdatalen = ret - orig - 2; - if (extdatalen == 0) { - return orig; + if (CBS_len(contents) != 0) { + return 0; } - s2n(extdatalen, orig); - return ret; + ssl->s3->tmp.extended_master_secret = 1; + return 1; } -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); +static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { + if (!ssl->s3->tmp.extended_master_secret) { + 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; +} + + +/* Session tickets. + * + * https://tools.ietf.org/html/rfc5077 */ + +static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { + if (SSL_get_options(ssl) & SSL_OP_NO_TICKET) { + return 1; } - if (!s->hit && s->should_ack_sni && s->session->tlsext_hostname != NULL) { - if ((long)(limit - ret - 4) < 0) { - return NULL; - } + const uint8_t *ticket_data = NULL; + int ticket_len = 0; - s2n(TLSEXT_TYPE_server_name, ret); - s2n(0, ret); + /* 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->s3->send_connection_binding) { - int el; + 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 (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) { - OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, ERR_R_INTERNAL_ERROR); - return NULL; - } + return 1; +} - if ((limit - ret - 4 - el) < 0) { - return NULL; - } +static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + ssl->tlsext_ticket_expected = 0; - s2n(TLSEXT_TYPE_renegotiate, ret); - s2n(el, ret); + if (contents == NULL) { + 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; - } + /* 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); - ret += el; + if (CBS_len(contents) != 0) { + return 0; } - if (s->s3->tmp.extended_master_secret) { - if ((long)(limit - ret - 4) < 0) { - return NULL; - } + 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; +} - s2n(TLSEXT_TYPE_extended_master_secret, ret); - s2n(0, ret); +static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { + if (!ssl->tlsext_ticket_expected) { + return 1; } - if (using_ecc) { - const uint8_t *plist; - size_t plistlen; - /* Add TLS extension ECPointFormats to the ServerHello message */ - long lenmax; + /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be + * true. */ + assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); - tls1_get_formatlist(s, &plist, &plistlen); + if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || + !CBB_add_u16(out, 0 /* length */)) { + return 0; + } - 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; - } + return 1; +} - s2n(TLSEXT_TYPE_ec_point_formats, ret); - s2n(plistlen + 1, ret); - *(ret++) = (uint8_t)plistlen; - memcpy(ret, plist, plistlen); - ret += plistlen; + +/* Signature Algorithms. + * + * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ + +static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) { + if (ssl3_version_from_wire(ssl, ssl->client_version) < TLS1_2_VERSION) { + return 1; } - /* Currently the server should not respond with a SupportedCurves extension */ - 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); + 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; } - 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; +} + +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; } - if (s->srtp_profile) { - int el; + return 1; +} - ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0); +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 ((limit - ret - 4 - el) < 0) { - return NULL; - } + if (contents == NULL) { + return 1; + } - s2n(TLSEXT_TYPE_use_srtp, ret); - s2n(el, ret); + 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; + } - 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; + 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; + } + + 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; } - 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; + 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; - } +static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; } - if (s->s3->alpn_selected) { - const uint8_t *selected = s->s3->alpn_selected; - size_t len = s->s3->alpn_selected_len; + if (CBS_len(contents) != 0) { + 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); + 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; } - extdatalen = ret - orig - 2; - if (extdatalen == 0) { - return orig; + uint8_t status_type; + if (!CBS_get_u8(contents, &status_type)) { + return 0; } - s2n(extdatalen, orig); - return ret; + /* 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; +} + +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 */); } -/* 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. + +/* Next protocol negotiation. * - * 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; + * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */ + +static void ext_npn_init(SSL *ssl) { + ssl->s3->next_proto_neg_seen = 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; + } + + if (!CBB_add_u16(out, TLSEXT_TYPE_next_proto_neg) || + !CBB_add_u16(out, 0 /* length */)) { + return 0; + } + + return 1; +} + +static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } + + /* 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); + return 0; + } + + const uint8_t *const orig_contents = CBS_data(contents); + const size_t orig_len = CBS_len(contents); + + while (CBS_len(contents) != 0) { + CBS proto; + if (!CBS_get_u8_length_prefixed(contents, &proto) || + CBS_len(&proto) == 0) { + return 0; + } + } + + uint8_t *selected; uint8_t selected_len; - int r; + 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; + } + + ssl->next_proto_negotiated_len = selected_len; + ssl->s3->next_proto_neg_seen = 1; + + return 1; +} + +static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents != NULL && CBS_len(contents) != 0) { + return 0; + } + + 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; + } + + ssl->s3->next_proto_neg_seen = 1; + return 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; + } + + const uint8_t *npa; + unsigned npa_len; + + 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; + } + + 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; + } + + return 1; +} + + +/* Signed certificate timestamps. + * + * https://tools.ietf.org/html/rfc6962#section-3.3.1 */ - if (s->ctx->alpn_select_cb == NULL) { +static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { + if (!ssl->signed_cert_timestamps_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; + if (!CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) || + !CBB_add_u16(out, 0 /* length */)) { + return 0; + } + + return 1; +} + +static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } + + /* 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_len(contents) == 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; + } + + return 1; +} + +static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + return contents == NULL || CBS_len(contents) == 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; + } + + 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); +} + + +/* 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)) { + 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) { + return 0; + } + + if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected, + &ssl->s3->alpn_selected_len)) { + *out_alert = SSL_AD_INTERNAL_ERROR; + 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. */ - protocol_name_list_copy = protocol_name_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)) { - goto parse_error; + if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) || + /* Empty protocol names are forbidden. */ + CBS_len(&protocol_name) == 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) { + 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; return 0; } - s->s3->alpn_selected_len = selected_len; + ssl->s3->alpn_selected_len = selected_len; } return 1; +} -parse_error: - *out_alert = SSL_AD_DECODE_ERROR; - return 0; +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_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; +/* Channel ID. + * + * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */ + +static void ext_channel_id_init(SSL *ssl) { + ssl->s3->tlsext_channel_id_valid = 0; +} + +static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { + if (!ssl->tlsext_channel_id_enabled || + SSL_IS_DTLS(ssl)) { + return 1; + } + + if (!CBB_add_u16(out, TLSEXT_TYPE_channel_id) || + !CBB_add_u16(out, 0 /* length */)) { + return 0; + } - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; + return 1; +} - /* 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_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } - /* Clear any shared signature algorithms */ - OPENSSL_free(s->cert->shared_sigalgs); - s->cert->shared_sigalgs = NULL; - s->cert->shared_sigalgslen = 0; + assert(!SSL_IS_DTLS(ssl)); + assert(ssl->tlsext_channel_id_enabled); - /* Clear ECC extensions */ - OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); - s->s3->tmp.peer_ecpointformatlist = NULL; - s->s3->tmp.peer_ecpointformatlist_length = 0; + if (CBS_len(contents) != 0) { + return 0; + } - OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); - s->s3->tmp.peer_ellipticcurvelist = NULL; - s->s3->tmp.peer_ellipticcurvelist_length = 0; + ssl->s3->tlsext_channel_id_valid = 1; + return 1; +} - /* There may be no extensions. */ - if (CBS_len(cbs) == 0) { - goto ri_check; +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; } - /* 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; + if (CBS_len(contents) != 0) { return 0; } - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; + ssl->s3->tlsext_channel_id_valid = 1; + return 1; +} - /* Decode the next extension. */ - if (!CBS_get_u16(&extensions, &type) || - !CBS_get_u16_length_prefixed(&extensions, &extension)) { - *out_alert = SSL_AD_DECODE_ERROR; +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; } + } - /* 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; - } + if (!CBB_add_u8(&contents, 0 /* empty use_mki value */) || + !CBB_flush(out)) { + return 0; + } - /* 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_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } - /* Only host_name is supported. */ - if (name_type != TLSEXT_NAMETYPE_host_name) { - continue; - } + /* 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 (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; - } + 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; + } - have_seen_host_name = 1; + STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); - if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) || - CBS_len(&host_name) < 1) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + /* 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 (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || - CBS_contains_zero_byte(&host_name)) { - *out_alert = SSL_AD_UNRECOGNIZED_NAME; - return 0; - } + if (profile->id == profile_id) { + ssl->srtp_profile = profile; + 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; + OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + 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; - } +static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + 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; - } + 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. */ - OPENSSL_free(s->s3->tmp.peer_ellipticcurvelist); - s->s3->tmp.peer_ellipticcurvelist_length = 0; + const STACK_OF(SRTP_PROTECTION_PROFILE) *server_profiles = + SSL_get_srtp_profiles(ssl); - s->s3->tmp.peer_ellipticcurvelist = - (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); + /* 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); - if (s->s3->tmp.peer_ellipticcurvelist == NULL) { - *out_alert = SSL_AD_INTERNAL_ERROR; + 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; } - 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; - } + if (server_profile->id == profile_id) { + ssl->srtp_profile = server_profile; + return 1; } + } + } - if (CBS_len(&elliptic_curve_list) != 0) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } + 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; +static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { + if (ssl->srtp_profile == NULL) { + return 1; + } - if (!CBS_get_u16_length_prefixed(&extension, - &supported_signature_algorithms) || - CBS_len(&extension) != 0) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + 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; + } - /* 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; - } + return 1; +} - 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; - } - 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; - } +/* EC point formats. + * + * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ - 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 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); - s->s3->tmp.extended_master_secret = 1; + 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; } } -ri_check: - /* Need RI if renegotiating */ + return 0; +} - 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); +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; } -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); +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; } - if (ssl_check_clienthello_tlsext(s) <= 0) { - OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_tlsext, - SSL_R_CLIENTHELLO_TLSEXT); + /* 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; } -/* 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; +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); - while (CBS_len(©) != 0) { - CBS proto; - if (!CBS_get_u8_length_prefixed(©, &proto) || CBS_len(&proto) == 0) { + 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 ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) { - int tlsext_servername = 0; - int renegotiate_seen = 0; - CBS extensions; +static int ext_ec_curves_parse_clienthello(SSL *ssl, uint8_t *out_alert, + CBS *contents) { + if (contents == NULL) { + return 1; + } - /* 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; + 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; + } - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; + ssl->s3->tmp.peer_ellipticcurvelist = + (uint16_t *)OPENSSL_malloc(CBS_len(&elliptic_curve_list)); - /* Clear ECC extensions */ - OPENSSL_free(s->s3->tmp.peer_ecpointformatlist); - s->s3->tmp.peer_ecpointformatlist = NULL; - s->s3->tmp.peer_ecpointformatlist_length = 0; + if (ssl->s3->tmp.peer_ellipticcurvelist == NULL) { + *out_alert = SSL_AD_INTERNAL_ERROR; + return 0; + } - /* There may be no extensions. */ - if (CBS_len(cbs) == 0) { - goto ri_check; + 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; + } } - /* 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; + 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]; + } } - while (CBS_len(&extensions) != 0) { - uint16_t type; - CBS extension; + return NULL; +} - /* 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; +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); } + } - if (type == TLSEXT_TYPE_server_name) { - /* The extension must be empty. */ - if (CBS_len(&extension) != 0) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; + 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; } - /* We must have sent it in ClientHello. */ - if (s->tlsext_hostname == NULL) { - *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; - return 0; + 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; } - tlsext_servername = 1; - } else if (type == TLSEXT_TYPE_ec_point_formats) { - CBS ec_point_format_list; + 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); - if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) || - CBS_len(&extension) != 0) { + /* 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)) { + *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)) { *out_alert = SSL_AD_DECODE_ERROR; return 0; } - 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; + unsigned ext_index; + const struct tls_extension *const ext = + tls_extension_find(&ext_index, type); + + 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; } - 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; + 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); return 0; } + } + } - if (!s->ocsp_stapling_enabled) { - *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; + 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; 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; + return 1; +} - /* We must have requested it. */ - if (s->ctx->next_proto_select_cb == NULL) { - *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; + } - /* The data must be valid. */ - if (!ssl_next_proto_validate(&extension)) { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } + if (ssl_check_clienthello_tlsext(s) <= 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT); + 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; - } + return 1; +} - s->next_proto_negotiated = BUF_memdup(selected, selected_len); - if (s->next_proto_negotiated == NULL) { - *out_alert = SSL_AD_INTERNAL_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; + } - 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; - /* We must have requested it. */ - if (s->alpn_client_proto_list == NULL) { - *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; - return 0; - } + while (CBS_len(&extensions) != 0) { + uint16_t type; + CBS 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) { + /* 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; } - 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; - } + unsigned ext_index; + const struct tls_extension *const ext = + tls_extension_find(&ext_index, type); - 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 (ext == NULL) { + if (!custom_ext_parse_serverhello(s, out_alert, type, &extension)) { + return 0; + } + continue; } - 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) { + 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); *out_alert = SSL_AD_DECODE_ERROR; return 0; } - /* 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; - } + received |= (1u << ext_index); - renegotiate_seen = 1; - } else if (type == TLSEXT_TYPE_use_srtp) { - if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) { + 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; 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; } } - 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; + 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; 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; @@ -1947,7 +2568,7 @@ static int ssl_check_clienthello_tlsext(SSL *s) { return 1; case SSL_TLSEXT_ERR_NOACK: - s->should_ack_sni = 0; + s->s3->tmp.should_ack_sni = 0; return 1; default: @@ -1956,22 +2577,9 @@ static int ssl_check_clienthello_tlsext(SSL *s) { } static int ssl_check_serverhello_tlsext(SSL *s) { - int ret = SSL_TLSEXT_ERR_NOACK; + int ret = SSL_TLSEXT_ERR_OK; 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); @@ -2007,203 +2615,131 @@ int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs) { } if (ssl_check_serverhello_tlsext(s) <= 0) { - OPENSSL_PUT_ERROR(SSL, ssl_parse_serverhello_tlsext, - SSL_R_SERVERHELLO_TLSEXT); + OPENSSL_PUT_ERROR(SSL, SSL_R_SERVERHELLO_TLSEXT); return 0; } return 1; } -/* 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 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 (len == 0) { - /* The client will accept a ticket but doesn't currently have one. */ - 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; +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; - case 3: /* ticket was decrypted */ - return r; + HMAC_CTX hmac_ctx; + HMAC_CTX_init(&hmac_ctx); + EVP_CIPHER_CTX cipher_ctx; + EVP_CIPHER_CTX_init(&cipher_ctx); - case 4: /* ticket decrypted but need to renew */ - s->tlsext_ticket_expected = 1; - return 3; + *out_send_ticket = 0; + *out_session = NULL; - default: /* fatal error */ - return -1; + if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { + goto done; } -} -/* 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; + if (ticket_len == 0) { + /* The client will accept a ticket but doesn't currently have one. */ + *out_send_ticket = 1; + goto done; + } /* 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 (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 (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 (rv == 0) { - return 2; + if (cb_ret == 0) { + goto done; } - if (rv == 2) { - renew_ticket = 1; + if (cb_ret == 2) { + *out_send_ticket = 1; } } else { - /* Check key name matches */ - if (memcmp(etick, tctx->tlsext_tick_key_name, 16)) { - return 2; + /* Check the key name matches. */ + if (memcmp(ticket, ssl_ctx->tlsext_tick_key_name, + SSL_TICKET_KEY_NAME_LEN) != 0) { + goto done; } - if (!HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16, tlsext_tick_md(), + if (!HMAC_Init_ex(&hmac_ctx, ssl_ctx->tlsext_tick_hmac_key, + sizeof(ssl_ctx->tlsext_tick_hmac_key), tlsext_tick_md(), NULL) || - !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; + !EVP_DecryptInit_ex(&cipher_ctx, EVP_aes_128_cbc(), NULL, + ssl_ctx->tlsext_tick_aes_key, iv)) { + ret = 0; + goto done; } } + size_t iv_len = EVP_CIPHER_CTX_iv_length(&cipher_ctx); - /* 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) { + /* 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) { /* The ticket must be large enough for key name, IV, data, and MAC. */ - 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; + 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; + 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; + } + + /* 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; } - ERR_clear_error(); - /* For session parse failure, indicate that we need to send a new ticket. */ - return 2; + /* 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; } /* Tables to translate from NIDs to TLS v1.2 ids */ @@ -2233,18 +2769,12 @@ static int tls12_find_id(int nid, const tls12_lookup *table, size_t tlen) { return -1; } -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_sigid(int pkey_type) { + return tls12_find_id(pkey_type, tls12_sig, + sizeof(tls12_sig) / sizeof(tls12_lookup)); } -int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) { +int tls12_get_sigandhash(SSL *ssl, uint8_t *p, const EVP_MD *md) { int sig_id, md_id; if (!md) { @@ -2257,7 +2787,7 @@ int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, const EVP_MD *md) { return 0; } - sig_id = tls12_get_sigid(pk); + sig_id = tls12_get_sigid(ssl_private_key_type(ssl)); if (sig_id == -1) { return 0; } @@ -2267,11 +2797,6 @@ int tls12_get_sigandhash(uint8_t *p, const EVP_PKEY *pk, 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: @@ -2312,256 +2837,129 @@ static int tls12_get_pkey_type(uint8_t sig_alg) { } } -/* 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; - } - - 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; - } - } - - 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; - } - } - - if (psignhash_nid) { - if (sign_nid && hash_nid) { - OBJ_find_sigid_by_algs(psignhash_nid, hash_nid, sign_nid); - } else { - *psignhash_nid = NID_undef; - } - } -} - -/* 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_COMPILE_ASSERT(sizeof(TLS_SIGALGS) == 2, + sizeof_tls_sigalgs_is_not_two); - 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); +int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { + /* Extension ignored for inappropriate versions */ + if (!SSL_USE_SIGALGS(ssl)) { + return 1; } - 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; - } + CERT *const cert = ssl->cert; + OPENSSL_free(cert->peer_sigalgs); + cert->peer_sigalgs = NULL; + cert->peer_sigalgslen = 0; - nmatch = tls12_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen); - if (!nmatch) { - return 1; - } + size_t num_sigalgs = CBS_len(in_sigalgs); - salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS)); - if (!salgs) { + if (num_sigalgs % 2 != 0) { return 0; } + num_sigalgs /= 2; - nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen); - c->shared_sigalgs = salgs; - c->shared_sigalgslen = nmatch; - return 1; -} - -/* 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)) { + /* supported_signature_algorithms in the certificate request is + * allowed to be empty. */ + if (num_sigalgs == 0) { return 1; } - if (CBS_len(sigalgs) % 2 != 0 || - !CBS_stow(sigalgs, &c->peer_sigalgs, &c->peer_sigalgslen) || - !tls1_set_shared_sigalgs(s)) { + /* 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) { return 0; } + cert->peer_sigalgslen = num_sigalgs; - return 1; -} + CBS sigalgs; + CBS_init(&sigalgs, CBS_data(in_sigalgs), CBS_len(in_sigalgs)); -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; - - /* 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 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; - - if (psig == NULL) { - return 0; - } - - if (idx >= 0) { - idx <<= 1; - if (idx >= (int)s->cert->peer_sigalgslen) { + 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; } - 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; + return 1; } -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; - } +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; + } - 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 md; + } } - return s->cert->shared_sigalgslen; + /* If no suitable digest may be found, default to SHA-1. */ + return EVP_sha1(); } -/* 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) { +int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { + int ret = 0; 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"; - if (s->s3->handshake_buffer && - !ssl3_digest_cached_records(s, free_handshake_buffer)) { - return 0; + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) { + goto err; } - EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic)); + static const char kClientIDMagic[] = "TLS Channel ID signature"; + EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic)); - if (s->hit && s->s3->tlsext_channel_id_new) { + if (ssl->hit) { static const char kResumptionMagic[] = "Resumption"; - EVP_DigestUpdate(md, kResumptionMagic, sizeof(kResumptionMagic)); - if (s->session->original_handshake_hash_len == 0) { - return 0; + 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, s->session->original_handshake_hash, - s->session->original_handshake_hash_len); + EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash, + ssl->session->original_handshake_hash_len); } - 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); + 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_cleanup(&ctx); + EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len); + unsigned len_u; + EVP_DigestFinal_ex(&ctx, out, &len_u); + *out_len = len_u; - return 1; + ret = 1; + +err: + EVP_MD_CTX_cleanup(&ctx); + return ret; } /* tls1_record_handshake_hashes_for_channel_id records the current handshake @@ -2575,12 +2973,6 @@ 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)); @@ -2592,48 +2984,3 @@ 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; -} |