diff options
Diffstat (limited to 'ssl/t1_lib.c')
-rw-r--r-- | ssl/t1_lib.c | 271 |
1 files changed, 203 insertions, 68 deletions
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 28d45b3..f170056 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -659,6 +659,18 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(0,ret); } + if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) + { + 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; + } + #ifndef OPENSSL_NO_SRTP if(SSL_get_srtp_profiles(s)) { @@ -879,6 +891,21 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(0,ret); } + if (s->s3->alpn_selected) + { + const unsigned char *selected = s->s3->alpn_selected; + unsigned len = s->s3->alpn_selected_len; + + 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 ((extdatalen = ret-p-2)== 0) return p; @@ -886,6 +913,76 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha return ret; } +/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a + * ClientHello. + * data: the contents of the extension, not including the type and length. + * data_len: the number of bytes in |data| + * al: a pointer to the alert value to send in the event of a non-zero + * return. + * + * returns: 0 on success. */ +static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data, + unsigned data_len, int *al) + { + unsigned i; + unsigned proto_len; + const unsigned char *selected; + unsigned char selected_len; + int r; + + if (s->ctx->alpn_select_cb == NULL) + return 0; + + if (data_len < 2) + goto parse_error; + + /* data should contain a uint16 length followed by a series of 8-bit, + * length-prefixed strings. */ + i = ((unsigned) data[0]) << 8 | + ((unsigned) data[1]); + data_len -= 2; + data += 2; + if (data_len != i) + goto parse_error; + + if (data_len < 2) + goto parse_error; + + for (i = 0; i < data_len;) + { + proto_len = data[i]; + i++; + + if (proto_len == 0) + goto parse_error; + + if (i + proto_len < i || i + proto_len > data_len) + goto parse_error; + + i += proto_len; + } + + r = s->ctx->alpn_select_cb(s, &selected, &selected_len, data, data_len, + s->ctx->alpn_select_cb_arg); + if (r == SSL_TLSEXT_ERR_OK) { + if (s->s3->alpn_selected) + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = OPENSSL_malloc(selected_len); + if (!s->s3->alpn_selected) + { + *al = SSL_AD_INTERNAL_ERROR; + return -1; + } + memcpy(s->s3->alpn_selected, selected, selected_len); + s->s3->alpn_selected_len = selected_len; + } + return 0; + +parse_error: + *al = SSL_AD_DECODE_ERROR; + return -1; + } + int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al) { unsigned short type; @@ -897,10 +994,23 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in s->servername_done = 0; s->tlsext_status_type = -1; + + /* Reset TLS 1.2 digest functions to defaults because they don't carry + * over to a renegotiation. */ + s->s3->digest_rsa = NULL; + s->s3->digest_dsa = NULL; + s->s3->digest_ecdsa = NULL; + #ifndef OPENSSL_NO_NEXTPROTONEG s->s3->next_proto_neg_seen = 0; #endif + if (s->s3->alpn_selected) + { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + } + #ifndef OPENSSL_NO_HEARTBEATS s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED | SSL_TLSEXT_HB_DONT_SEND_REQUESTS); @@ -1194,11 +1304,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in *al = SSL_AD_DECODE_ERROR; return 0; } - if (!tls1_process_sigalgs(s, data, dsize)) - { - *al = SSL_AD_DECODE_ERROR; - return 0; - } + tls1_process_sigalgs(s, data, dsize); } else if (type == TLSEXT_TYPE_status_request && s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb) @@ -1331,7 +1437,8 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in #endif #ifndef OPENSSL_NO_NEXTPROTONEG else if (type == TLSEXT_TYPE_next_proto_neg && - s->s3->tmp.finish_md_len == 0) + s->s3->tmp.finish_md_len == 0 && + s->s3->alpn_selected == NULL) { /* We shouldn't accept this extension on a * renegotiation. @@ -1355,6 +1462,16 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in else if (type == TLSEXT_TYPE_channel_id && s->tlsext_channel_id_enabled) s->s3->tlsext_channel_id_valid = 1; + else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && + s->ctx->alpn_select_cb && + s->s3->tmp.finish_md_len == 0) + { + if (tls1_alpn_handle_client_hello(s, data, size, al) != 0) + return 0; + /* ALPN takes precedence over NPN. */ + s->s3->next_proto_neg_seen = 0; + } + /* session ticket processed earlier */ #ifndef OPENSSL_NO_SRTP else if (type == TLSEXT_TYPE_use_srtp) @@ -1419,6 +1536,12 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in s->s3->next_proto_neg_seen = 0; #endif + if (s->s3->alpn_selected) + { + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + } + #ifndef OPENSSL_NO_HEARTBEATS s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED | SSL_TLSEXT_HB_DONT_SEND_REQUESTS); @@ -1588,6 +1711,51 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in else if (type == TLSEXT_TYPE_channel_id) s->s3->tlsext_channel_id_valid = 1; + else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation) + { + unsigned len; + + /* We must have requested it. */ + if (s->alpn_client_proto_list == NULL) + { + *al = TLS1_AD_UNSUPPORTED_EXTENSION; + return 0; + } + if (size < 4) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + /* The extension data consists of: + * uint16 list_length + * uint8 proto_length; + * uint8 proto[proto_length]; */ + len = data[0]; + len <<= 8; + len |= data[1]; + if (len != (unsigned) size - 2) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + len = data[2]; + if (len != (unsigned) size - 3) + { + *al = TLS1_AD_DECODE_ERROR; + return 0; + } + if (s->s3->alpn_selected) + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = OPENSSL_malloc(len); + if (!s->s3->alpn_selected) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + memcpy(s->s3->alpn_selected, data + 3, len); + s->s3->alpn_selected_len = len; + } + else if (type == TLSEXT_TYPE_renegotiate) { if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al)) @@ -2350,18 +2518,6 @@ static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen) } return -1; } -#if 0 -static int tls12_find_nid(int id, 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 -1; - } -#endif int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md) { @@ -2380,6 +2536,8 @@ int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md) return 1; } +/* tls12_get_sigid returns the TLS 1.2 SignatureAlgorithm value corresponding + * to the given public key, or -1 if not known. */ int tls12_get_sigid(const EVP_PKEY *pk) { return tls12_find_id(pk->type, tls12_sig, @@ -2399,47 +2557,49 @@ const EVP_MD *tls12_get_hash(unsigned char hash_alg) return EVP_md5(); #endif #ifndef OPENSSL_NO_SHA - case TLSEXT_hash_sha1: + case TLSEXT_hash_sha1: return EVP_sha1(); #endif #ifndef OPENSSL_NO_SHA256 - case TLSEXT_hash_sha224: + case TLSEXT_hash_sha224: return EVP_sha224(); - case TLSEXT_hash_sha256: + case TLSEXT_hash_sha256: return EVP_sha256(); #endif #ifndef OPENSSL_NO_SHA512 - case TLSEXT_hash_sha384: + case TLSEXT_hash_sha384: return EVP_sha384(); - case TLSEXT_hash_sha512: + case TLSEXT_hash_sha512: return EVP_sha512(); #endif - default: + default: return NULL; } } -/* Set preferred digest for each key type */ - -int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) +/* tls1_process_sigalgs processes a signature_algorithms extension and sets the + * digest functions accordingly for each key type. + * + * See RFC 5246, section 7.4.1.4.1. + * + * data: points to the content of the extension, not including type and length + * headers. + * dsize: the number of bytes of |data|. Must be even. + */ +void tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) { - int i, idx; - const EVP_MD *md; - CERT *c = s->cert; + int i; + const EVP_MD *md, **digest_ptr; /* Extension ignored for TLS versions below 1.2 */ if (TLS1_get_version(s) < TLS1_2_VERSION) - return 1; - /* Should never happen */ - if (!c) - return 0; + return; - c->pkeys[SSL_PKEY_DSA_SIGN].digest = NULL; - c->pkeys[SSL_PKEY_RSA_SIGN].digest = NULL; - c->pkeys[SSL_PKEY_RSA_ENC].digest = NULL; - c->pkeys[SSL_PKEY_ECC].digest = NULL; + s->s3->digest_rsa = NULL; + s->s3->digest_dsa = NULL; + s->s3->digest_ecdsa = NULL; for (i = 0; i < dsize; i += 2) { @@ -2449,56 +2609,31 @@ int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize) { #ifndef OPENSSL_NO_RSA case TLSEXT_signature_rsa: - idx = SSL_PKEY_RSA_SIGN; + digest_ptr = &s->s3->digest_rsa; break; #endif #ifndef OPENSSL_NO_DSA case TLSEXT_signature_dsa: - idx = SSL_PKEY_DSA_SIGN; + digest_ptr = &s->s3->digest_dsa; break; #endif #ifndef OPENSSL_NO_ECDSA case TLSEXT_signature_ecdsa: - idx = SSL_PKEY_ECC; + digest_ptr = &s->s3->digest_ecdsa; break; #endif default: continue; } - if (c->pkeys[idx].digest == NULL) + if (*digest_ptr == NULL) { md = tls12_get_hash(hash_alg); if (md) - { - c->pkeys[idx].digest = md; - if (idx == SSL_PKEY_RSA_SIGN) - c->pkeys[SSL_PKEY_RSA_ENC].digest = md; - } + *digest_ptr = md; } } - - - /* Set any remaining keys to default values. NOTE: if alg is not - * supported it stays as NULL. - */ -#ifndef OPENSSL_NO_DSA - if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest) - c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1(); -#endif -#ifndef OPENSSL_NO_RSA - if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest) - { - c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1(); - c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1(); - } -#endif -#ifndef OPENSSL_NO_ECDSA - if (!c->pkeys[SSL_PKEY_ECC].digest) - c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1(); -#endif - return 1; } #endif |