Convert the ALPN extension to the new system
Change-Id: I5777b73f485da6534b407e6c531f8293898b9c06
Reviewed-on: https://boringssl-review.googlesource.com/5461
Reviewed-by: David Benjamin <davidben@chromium.org>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 6adc874..24f64a6 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1564,6 +1564,134 @@
}
+/* 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);
+
+ /* 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. */
+ CBS protocol_name_list_copy = protocol_name_list;
+ while (CBS_len(&protocol_name_list_copy) > 0) {
+ CBS protocol_name;
+
+ if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
+ /* Empty protocol names are forbidden. */
+ CBS_len(&protocol_name) == 0) {
+ return 0;
+ }
+ }
+
+ 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;
+ }
+ ssl->s3->alpn_selected_len = selected_len;
+ }
+
+ return 1;
+}
+
+static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) {
+ if (ssl->s3->alpn_selected == NULL) {
+ return 1;
+ }
+
+ CBB contents, proto_list, proto;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_application_layer_protocol_negotiation) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16_length_prefixed(&contents, &proto_list) ||
+ !CBB_add_u8_length_prefixed(&proto_list, &proto) ||
+ !CBB_add_bytes(&proto, ssl->s3->alpn_selected, ssl->s3->alpn_selected_len) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+
/* kExtensions contains all the supported extensions. */
static const struct tls_extension kExtensions[] = {
{
@@ -1633,6 +1761,14 @@
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,
+ },
};
#define kNumExtensions (sizeof(kExtensions) / sizeof(struct tls_extension))
@@ -1729,17 +1865,6 @@
ret += CBB_len(&cbb);
CBB_cleanup(&cbb);
- if (s->alpn_client_proto_list && !s->s3->initial_handshake_complete) {
- if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) {
- return NULL;
- }
- s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
- s2n(2 + s->alpn_client_proto_list_len, ret);
- s2n(s->alpn_client_proto_list_len, ret);
- memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len);
- ret += s->alpn_client_proto_list_len;
- }
-
if (s->tlsext_channel_id_enabled && !SSL_IS_DTLS(s)) {
/* The client advertises an emtpy extension to indicate its support for
* Channel ID. */
@@ -1965,21 +2090,6 @@
ret += el;
}
- if (s->s3->alpn_selected) {
- const uint8_t *selected = s->s3->alpn_selected;
- size_t 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 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) {
@@ -2003,68 +2113,11 @@
return ret;
}
-/* 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.
- *
- * returns: 1 on success. */
-static int tls1_alpn_handle_client_hello(SSL *s, CBS *cbs, int *out_alert) {
- CBS protocol_name_list, protocol_name_list_copy;
- const uint8_t *selected;
- uint8_t selected_len;
- int r;
-
- if (s->ctx->alpn_select_cb == NULL) {
- 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;
- }
-
- /* Validate the protocol list. */
- protocol_name_list_copy = protocol_name_list;
- while (CBS_len(&protocol_name_list_copy) > 0) {
- CBS protocol_name;
-
- if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
- /* Empty protocol names are forbidden. */
- CBS_len(&protocol_name) == 0) {
- goto parse_error;
- }
- }
-
- r = s->ctx->alpn_select_cb(
- s, &selected, &selected_len, CBS_data(&protocol_name_list),
- CBS_len(&protocol_name_list), s->ctx->alpn_select_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = BUF_memdup(selected, selected_len);
- if (!s->s3->alpn_selected) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- s->s3->alpn_selected_len = selected_len;
- }
-
- return 1;
-
-parse_error:
- *out_alert = SSL_AD_DECODE_ERROR;
- return 0;
-}
-
static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) {
CBS extensions;
s->srtp_profile = NULL;
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
-
/* Clear ECC extensions */
OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
s->s3->tmp.peer_ecpointformatlist = NULL;
@@ -2177,13 +2230,6 @@
}
s->s3->tmp.peer_ellipticcurvelist_length = num_curves;
- } 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. */
@@ -2249,9 +2295,6 @@
* time so it's not even kept around post-handshake. */
s->srtp_profile = NULL;
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = NULL;
-
/* Clear ECC extensions */
OPENSSL_free(s->s3->tmp.peer_ecpointformatlist);
s->s3->tmp.peer_ecpointformatlist = NULL;
@@ -2325,33 +2368,6 @@
*out_alert = SSL_AD_INTERNAL_ERROR;
return 0;
}
- } 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;
- }
-
- /* 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) ||
- /* Empty protocol names are forbidden. */
- CBS_len(&protocol_name) == 0 ||
- CBS_len(&protocol_name_list) != 0) {
- *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;