Port ClientHello extensions parsing to crypto/bytestring.
Change-Id: I673c929b78bcf6952db8dfb295dd79d455bcb2a0
Reviewed-on: https://boringssl-review.googlesource.com/1070
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 43f2c3f..135cf50 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1747,7 +1747,7 @@
#ifndef OPENSSL_NO_EC
/* ssl_check_for_safari attempts to fingerprint Safari using OS X
- * SecureTransport using the TLS extension block in |d|, of length |n|.
+ * SecureTransport using the TLS extension block in |cbs|.
* Safari, since 10.6, sends exactly these extensions, in this order:
* SNI,
* elliptic_curves
@@ -1758,8 +1758,8 @@
* Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
* 10.8..10.8.3 (which don't work).
*/
-static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsigned char *d, int n) {
- unsigned short type, size;
+static void ssl_check_for_safari(SSL *s, const CBS *extensions)
+ {
static const unsigned char kSafariExtensionsBlock[] = {
0x00, 0x0a, /* elliptic_curves extension */
0x00, 0x08, /* 8 bytes */
@@ -1785,42 +1785,35 @@
0x04, 0x03, /* SHA-256/ECDSA */
0x02, 0x03, /* SHA-1/ECDSA */
};
+ CBS extensions_copy = *extensions, extension;
+ uint16_t type;
- if (data >= (d+n-2))
- return;
- data += 2;
-
- if (data > (d+n-4))
- return;
- n2s(data,type);
- n2s(data,size);
-
- if (type != TLSEXT_TYPE_server_name)
+ /* First extension is server_name. */
+ if (!CBS_get_u16(&extensions_copy, &type) ||
+ !CBS_get_u16_length_prefixed(&extensions_copy, &extension) ||
+ type != TLSEXT_TYPE_server_name)
return;
- if (data+size > d+n)
- return;
- data += size;
-
+ /* Compare the remainder of the extensions block. */
if (TLS1_get_client_version(s) >= TLS1_2_VERSION)
{
const size_t len1 = sizeof(kSafariExtensionsBlock);
const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
- if (data + len1 + len2 != d+n)
+ if (len1 + len2 != CBS_len(&extensions_copy))
return;
- if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
+ if (memcmp(CBS_data(&extensions_copy), kSafariExtensionsBlock, len1) != 0)
return;
- if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
+ if (memcmp(CBS_data(&extensions_copy) + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
return;
}
else
{
const size_t len = sizeof(kSafariExtensionsBlock);
- if (data + len != d+n)
+ if (len != CBS_len(&extensions_copy))
return;
- if (memcmp(data, kSafariExtensionsBlock, len) != 0)
+ if (memcmp(CBS_data(&extensions_copy), kSafariExtensionsBlock, len) != 0)
return;
}
@@ -1830,81 +1823,62 @@
/* 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
+ * 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.
*
- * returns: 0 on success. */
-static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
- unsigned data_len, int *al)
+ * returns: 1 on success. */
+static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert)
{
- unsigned i;
- unsigned proto_len;
+ CBS protocol_name_list;
const unsigned char *selected;
unsigned char selected_len;
int r;
if (s->ctx->alpn_select_cb == NULL)
- return 0;
+ return 1;
- if (data_len < 2)
+ if (!CBS_get_u16_length_prefixed(cbs, &protocol_name_list) ||
+ CBS_len(cbs) != 0 ||
+ CBS_len(&protocol_name_list) < 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;)
+ /* Validate the protocol list. */
+ CBS protocol_name_list_copy = protocol_name_list;
+ while (CBS_len(&protocol_name_list_copy) > 0)
{
- proto_len = data[i];
- i++;
+ CBS protocol_name;
- if (proto_len == 0)
+ if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name))
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);
+ 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) {
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;
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
}
memcpy(s->s3->alpn_selected, selected, selected_len);
s->s3->alpn_selected_len = selected_len;
}
- return 0;
+ return 1;
parse_error:
- *al = SSL_AD_DECODE_ERROR;
- return -1;
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
}
-static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
+static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
{
- unsigned short type;
- unsigned short size;
- unsigned short len;
- unsigned char *data = *p;
int renegotiate_seen = 0;
+ CBS extensions;
size_t i;
s->servername_done = 0;
@@ -1919,11 +1893,6 @@
s->s3->alpn_selected = NULL;
}
-#ifndef OPENSSL_NO_EC
- if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
- ssl_check_for_safari(s, data, d, n);
-#endif /* !OPENSSL_NO_EC */
-
/* Clear any signature algorithms extension received */
if (s->cert->peer_sigalgs)
{
@@ -1943,26 +1912,42 @@
s->cert->pkeys[i].valid_flags = 0;
}
- if (data >= (d+n-2))
- goto ri_check;
- n2s(data,len);
-
- if (data > (d+n-len))
- goto ri_check;
-
- while (data <= (d+n-4))
+ /* There may be no extensions. */
+ if (CBS_len(cbs) == 0)
{
- n2s(data,type);
- n2s(data,size);
+ goto ri_check;
+ }
- if (data+size > (d+n))
- goto ri_check;
-#if 0
- fprintf(stderr,"Received extension type %d size %d\n",type,size);
-#endif
+ if (!CBS_get_u16_length_prefixed(cbs, &extensions))
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+#ifndef OPENSSL_NO_EC
+ if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+ ssl_check_for_safari(s, &extensions);
+#endif /* !OPENSSL_NO_EC */
+
+ 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 (s->tlsext_debug_cb)
- s->tlsext_debug_cb(s, 0, type, data, size,
- s->tlsext_debug_arg);
+ {
+ s->tlsext_debug_cb(s, 0, type, (unsigned char*)CBS_data(&extension),
+ CBS_len(&extension), s->tlsext_debug_arg);
+ }
+
/* The servername extension is treated as follows:
- Only the hostname type is supported with a maximum length of 255.
@@ -1988,194 +1973,188 @@
if (type == TLSEXT_TYPE_server_name)
{
- unsigned char *sdata;
- int servname_type;
- int dsize;
-
- if (size < 2)
+ CBS server_name_list;
+
+ if (!CBS_get_u16_length_prefixed(&extension, &server_name_list) ||
+ CBS_len(&server_name_list) < 1 ||
+ CBS_len(&extension) != 0)
{
- *al = SSL_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- n2s(data,dsize);
- size -= 2;
- if (dsize > size )
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- sdata = data;
- while (dsize > 3)
+ /* Decode each ServerName in the extension. */
+ while (CBS_len(&server_name_list) > 0)
{
- servname_type = *(sdata++);
- n2s(sdata,len);
- dsize -= 3;
+ uint8_t name_type;
+ CBS host_name;
- if (len > dsize)
+ /* Decode the NameType. */
+ if (!CBS_get_u8(&server_name_list, &name_type))
{
- *al = SSL_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- if (s->servername_done == 0)
- switch (servname_type)
+
+ if (s->servername_done)
+ continue;
+
+ /* Only host_name is supported. */
+ if (name_type != TLSEXT_NAMETYPE_host_name)
+ continue;
+
+ if (!s->hit)
{
- case TLSEXT_NAMETYPE_host_name:
- if (!s->hit)
+ if (s->session->tlsext_hostname)
{
- if(s->session->tlsext_hostname)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (len > TLSEXT_MAXLEN_host_name)
- {
- *al = TLS1_AD_UNRECOGNIZED_NAME;
- return 0;
- }
- if ((s->session->tlsext_hostname = OPENSSL_malloc(len+1)) == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
- return 0;
- }
- memcpy(s->session->tlsext_hostname, sdata, len);
- s->session->tlsext_hostname[len]='\0';
- if (strlen(s->session->tlsext_hostname) != len) {
- OPENSSL_free(s->session->tlsext_hostname);
- s->session->tlsext_hostname = NULL;
- *al = TLS1_AD_UNRECOGNIZED_NAME;
- return 0;
+ /* The ServerNameList MUST NOT
+ contain more than one name of
+ the same name_type. */
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
}
- s->servername_done = 1;
+ if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name) ||
+ CBS_len(&host_name) < 1)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
}
- else
- s->servername_done = s->session->tlsext_hostname
- && strlen(s->session->tlsext_hostname) == len
- && strncmp(s->session->tlsext_hostname, (char *)sdata, len) == 0;
-
- break;
- default:
- break;
+ if (CBS_len(&host_name) > TLSEXT_MAXLEN_host_name)
+ {
+ *out_alert = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+
+ /* host_name may not contain a NUL character. */
+ if (BUF_strnlen((const char*)CBS_data(&host_name),
+ CBS_len(&host_name)) != CBS_len(&host_name))
+ {
+ *out_alert = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+
+ /* Copy the hostname as a string. */
+ s->session->tlsext_hostname = BUF_strndup(
+ (const char*)CBS_data(&host_name), CBS_len(&host_name));
+ if (s->session->tlsext_hostname == NULL)
+ {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->servername_done = 1;
}
-
- dsize -= len;
+ else
+ {
+ s->servername_done = s->session->tlsext_hostname
+ && strlen(s->session->tlsext_hostname) == CBS_len(&host_name)
+ && strncmp(s->session->tlsext_hostname,
+ (char *)CBS_data(&host_name), CBS_len(&host_name)) == 0;
+ }
}
- if (dsize != 0)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
-
}
#ifndef OPENSSL_NO_EC
else if (type == TLSEXT_TYPE_ec_point_formats)
{
- unsigned char *sdata = data;
- int ecpointformatlist_length = *(sdata++);
+ CBS ec_point_format_list;
- if (ecpointformatlist_length != size - 1 ||
- ecpointformatlist_length < 1)
+ if (!CBS_get_u8_length_prefixed(&extension, &ec_point_format_list) ||
+ CBS_len(&extension) != 0)
{
- *al = TLS1_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
+
if (!s->hit)
{
- if(s->session->tlsext_ecpointformatlist)
+ if (!CBS_stow(&ec_point_format_list,
+ &s->session->tlsext_ecpointformatlist,
+ &s->session->tlsext_ecpointformatlist_length))
{
- OPENSSL_free(s->session->tlsext_ecpointformatlist);
- s->session->tlsext_ecpointformatlist = NULL;
- }
- s->session->tlsext_ecpointformatlist_length = 0;
- if ((s->session->tlsext_ecpointformatlist = OPENSSL_malloc(ecpointformatlist_length)) == NULL)
- {
- *al = TLS1_AD_INTERNAL_ERROR;
+ *out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length;
- memcpy(s->session->tlsext_ecpointformatlist, sdata, ecpointformatlist_length);
}
-#if 0
- fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ", s->session->tlsext_ecpointformatlist_length);
- sdata = s->session->tlsext_ecpointformatlist;
- for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
- fprintf(stderr,"%i ",*(sdata++));
- fprintf(stderr,"\n");
-#endif
}
else if (type == TLSEXT_TYPE_elliptic_curves)
{
- unsigned char *sdata = data;
- int ellipticcurvelist_length = (*(sdata++) << 8);
- ellipticcurvelist_length += (*(sdata++));
+ CBS elliptic_curve_list;
- if (ellipticcurvelist_length != size - 2 ||
- ellipticcurvelist_length < 1)
+ if (!CBS_get_u16_length_prefixed(&extension, &elliptic_curve_list) ||
+ CBS_len(&extension) != 0)
{
- *al = TLS1_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
+
if (!s->hit)
{
- if(s->session->tlsext_ellipticcurvelist)
+ if (s->session->tlsext_ellipticcurvelist)
{
- *al = TLS1_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- s->session->tlsext_ellipticcurvelist_length = 0;
- if ((s->session->tlsext_ellipticcurvelist = OPENSSL_malloc(ellipticcurvelist_length)) == NULL)
+
+ if (!CBS_stow(&elliptic_curve_list,
+ &s->session->tlsext_ellipticcurvelist,
+ &s->session->tlsext_ellipticcurvelist_length))
{
- *al = TLS1_AD_INTERNAL_ERROR;
+ *out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- s->session->tlsext_ellipticcurvelist_length = ellipticcurvelist_length;
- memcpy(s->session->tlsext_ellipticcurvelist, sdata, ellipticcurvelist_length);
}
-#if 0
- fprintf(stderr,"ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ", s->session->tlsext_ellipticcurvelist_length);
- sdata = s->session->tlsext_ellipticcurvelist;
- for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
- fprintf(stderr,"%i ",*(sdata++));
- fprintf(stderr,"\n");
-#endif
}
#endif /* OPENSSL_NO_EC */
else if (type == TLSEXT_TYPE_session_ticket)
{
if (s->tls_session_ticket_ext_cb &&
- !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
+ !s->tls_session_ticket_ext_cb(s, CBS_data(&extension), CBS_len(&extension), s->tls_session_ticket_ext_cb_arg))
{
- *al = TLS1_AD_INTERNAL_ERROR;
+ *out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
}
else if (type == TLSEXT_TYPE_renegotiate)
{
- if(!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ if (!ssl_parse_clienthello_renegotiate_ext(s, &extension, out_alert))
return 0;
renegotiate_seen = 1;
}
else if (type == TLSEXT_TYPE_signature_algorithms)
{
- int dsize;
- if (s->cert->peer_sigalgs || size < 2)
+ CBS supported_signature_algorithms;
+
+ /* The extension should not appear twice. */
+ if (s->cert->peer_sigalgs)
{
- *al = SSL_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
- n2s(data,dsize);
- size -= 2;
- if (dsize != size || dsize & 1 || !dsize)
+
+ if (!CBS_get_u16_length_prefixed(&extension, &supported_signature_algorithms) ||
+ CBS_len(&extension) != 0)
{
- *al = SSL_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- if (!tls1_process_sigalgs(s, data, dsize))
+
+ /* 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)
{
- *al = SSL_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (!tls1_process_sigalgs(s,
+ CBS_data(&supported_signature_algorithms),
+ CBS_len(&supported_signature_algorithms)))
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
/* If sigalgs received and no shared algorithms fatal
@@ -2184,7 +2163,7 @@
if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs)
{
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
- *al = SSL_AD_ILLEGAL_PARAMETER;
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
return 0;
}
}
@@ -2193,114 +2172,121 @@
#if 0
else if (type == TLSEXT_TYPE_status_request)
{
-
- if (size < 5)
+ uint8_t status_type;
+ CBS responder_id_list;
+ CBS request_extensions;
+
+ /* Already seen the extension. */
+ if (s->tlsext_status_type != -1 ||
+ s->tlsext_ocsp_ids != NULL ||
+ s->tlsext_ocsp_exts != NULL)
{
- *al = SSL_AD_DECODE_ERROR;
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
- s->tlsext_status_type = *data++;
- size--;
- if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ if (!CBS_get_u8(&extension, &status_type))
{
- const unsigned char *sdata;
- int dsize;
- /* Read in responder_id_list */
- n2s(data,dsize);
- size -= 2;
- if (dsize > size )
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- while (dsize > 0)
- {
- OCSP_RESPID *id;
- int idsize;
- if (dsize < 4)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(data, idsize);
- dsize -= 2 + idsize;
- size -= 2 + idsize;
- if (dsize < 0)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- sdata = data;
- data += idsize;
- id = d2i_OCSP_RESPID(NULL,
- &sdata, idsize);
- if (!id)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (data != sdata)
- {
- OCSP_RESPID_free(id);
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- if (!s->tlsext_ocsp_ids
- && !(s->tlsext_ocsp_ids =
- sk_OCSP_RESPID_new_null()))
- {
- OCSP_RESPID_free(id);
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- if (!sk_OCSP_RESPID_push(
- s->tlsext_ocsp_ids, id))
- {
- OCSP_RESPID_free(id);
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- }
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
- /* Read in request_extensions */
- if (size < 2)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- n2s(data,dsize);
- size -= 2;
- if (dsize != size)
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
- sdata = data;
- if (dsize > 0)
- {
- if (s->tlsext_ocsp_exts)
- {
- sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
- X509_EXTENSION_free);
- }
+ /* Only OCSP is supported. */
+ if (status_type != TLSEXT_STATUSTYPE_ocsp)
+ continue;
- s->tlsext_ocsp_exts =
- d2i_X509_EXTENSIONS(NULL,
- &sdata, dsize);
- if (!s->tlsext_ocsp_exts
- || (data + dsize != sdata))
- {
- *al = SSL_AD_DECODE_ERROR;
- return 0;
- }
+ s->tlsext_status_type = status_type;
+
+ /* Extension consists of a responder_id_list and
+ * request_extensions. */
+ if (!CBS_get_u16_length_prefixed(&extension, &responder_id_list) ||
+ CBS_get_u16_length_prefixed(&extension, &request_extensions) ||
+ CBS_len(&extension) != 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (CBS_len(&responder_id_list) > 0)
+ {
+ s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null();
+ if (s->tlsext_ocsp_ids == NULL)
+ {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
}
}
- /* We don't know what to do with any other type
- * so ignore it.
- */
- else
- s->tlsext_status_type = -1;
+
+ /* Parse out the responder IDs. */
+ while (CBS_len(&responder_id_list) > 0)
+ {
+ CBS responder_id;
+ OCSP_RESPID *id;
+ const uint8_t *data;
+
+ /* Each ResponderID must have size at least 1. */
+ if (!CBS_get_u16_length_prefixed(&responder_id_list, &responder_id) ||
+ CBS_len(&responder_id) < 1)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* TODO(fork): Add CBS versions of d2i_FOO_BAR. */
+ data = CBS_data(&responder_id);
+ id = d2i_OCSP_RESPID(NULL, &data, CBS_len(&responder_id));
+ if (!id)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!CBS_skip(&responder_id, data - CBS_data(&responder_id)))
+ {
+ /* This should never happen. */
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OCSP_RESPID_free(id);
+ return 0;
+ }
+ if (CBS_len(&responder_id) != 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ OCSP_RESPID_free(id);
+ return 0;
+ }
+
+ if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id))
+ {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ OCSP_RESPID_free(id);
+ return 0;
+ }
+ }
+
+ /* Parse out request_extensions. */
+ if (CBS_len(&request_extensions) > 0)
+ {
+ const uint8_t *data;
+
+ data = CBS_data(&request_extensions);
+ s->tlsext_ocsp_exts = d2i_X509_EXTENSIONS(NULL,
+ &data, CBS_len(&request_extensions));
+ if (s->tlsext_ocsp_exts == NULL)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!CBS_skip(&request_extensions, data - CBS_data(&request_extensions)))
+ {
+ /* This should never happen. */
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ if (CBS_len(&request_extensions) != 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
}
#endif
@@ -2309,6 +2295,13 @@
s->s3->tmp.finish_md_len == 0 &&
s->s3->alpn_selected == NULL)
{
+ /* The extension must be empty. */
+ if (CBS_len(&extension) != 0)
+ {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
/* We shouldn't accept this extension on a
* renegotiation.
*
@@ -2332,7 +2325,7 @@
s->ctx->alpn_select_cb &&
s->s3->tmp.finish_md_len == 0)
{
- if (tls1_alpn_handle_client_hello(s, data, size, al) != 0)
+ if (!tls1_alpn_handle_client_hello(s, &extension, out_alert))
return 0;
#ifndef OPENSSL_NO_NEXTPROTONEG
/* ALPN takes precedence over NPN. */
@@ -2342,11 +2335,27 @@
else if (type == TLSEXT_TYPE_channel_id &&
s->tlsext_channel_id_enabled)
+ {
+ /* 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)
{
+ /* 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;
s->s3->tlsext_channel_id_new = 1;
}
@@ -2355,16 +2364,11 @@
/* session ticket processed earlier */
else if (type == TLSEXT_TYPE_use_srtp)
{
- if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
- al))
+ if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert))
return 0;
}
-
- data+=size;
}
- *p = data;
-
ri_check:
/* Need RI if renegotiating */
@@ -2372,7 +2376,7 @@
if (!renegotiate_seen && s->renegotiate &&
!(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION))
{
- *al = SSL_AD_HANDSHAKE_FAILURE;
+ *out_alert = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, ssl_add_serverhello_tlsext, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
return 0;
}
@@ -2383,12 +2387,12 @@
return 1;
}
-int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
+int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs)
{
- int al = -1;
- if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0)
+ int alert = -1;
+ if (ssl_scan_clienthello_tlsext(s, cbs, &alert) <= 0)
{
- ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ ssl3_send_alert(s, SSL3_AL_FATAL, alert);
return 0;
}