summaryrefslogtreecommitdiffstats
path: root/lib/libssl/src/ssl/t1_lib.c
diff options
context:
space:
mode:
authorjsing <jsing@openbsd.org>2014-12-10 14:58:56 +0000
committerjsing <jsing@openbsd.org>2014-12-10 14:58:56 +0000
commitd436807c3fafcdd2569d3d41472f012dd477b2a9 (patch)
treea15b7e477ed8ba85a84f131c7324004133d3ba7b /lib/libssl/src/ssl/t1_lib.c
parentadd stdint.h to ssl.h. (diff)
downloadwireguard-openbsd-d436807c3fafcdd2569d3d41472f012dd477b2a9.tar.xz
wireguard-openbsd-d436807c3fafcdd2569d3d41472f012dd477b2a9.zip
Add support for ALPN.
Based on OpenSSL and BoringSSL. ok bcook@
Diffstat (limited to 'lib/libssl/src/ssl/t1_lib.c')
-rw-r--r--lib/libssl/src/ssl/t1_lib.c155
1 files changed, 152 insertions, 3 deletions
diff --git a/lib/libssl/src/ssl/t1_lib.c b/lib/libssl/src/ssl/t1_lib.c
index 8a7553e3e73..5df45ab3598 100644
--- a/lib/libssl/src/ssl/t1_lib.c
+++ b/lib/libssl/src/ssl/t1_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: t1_lib.c,v 1.71 2014/12/06 13:51:06 jsing Exp $ */
+/* $OpenBSD: t1_lib.c,v 1.72 2014/12/10 14:58:56 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@@ -878,6 +878,18 @@ skip_ext:
}
#endif
+ if (s->alpn_client_proto_list != NULL &&
+ s->s3->tmp.finish_md_len == 0) {
+ 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_IS_DTLS(s) && SSL_get_srtp_profiles(s)) {
int el;
@@ -1107,6 +1119,20 @@ ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
}
#endif
+ if (s->s3->alpn_selected != NULL) {
+ const unsigned char *selected = s->s3->alpn_selected;
+ unsigned int 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;
@@ -1114,6 +1140,76 @@ ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
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: 1 on success.
+ */
+static int
+tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
+ unsigned int data_len, int *al)
+{
+ const unsigned char *selected;
+ unsigned char selected_len;
+ unsigned int proto_len;
+ unsigned int i;
+ int r;
+
+ if (s->ctx->alpn_select_cb == NULL)
+ return (1);
+
+ 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 int)data[0]) << 8 | ((unsigned int)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) {
+ free(s->s3->alpn_selected);
+ if ((s->s3->alpn_selected = malloc(selected_len)) == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return (-1);
+ }
+ memcpy(s->s3->alpn_selected, selected, selected_len);
+ s->s3->alpn_selected_len = selected_len;
+ }
+
+ return (1);
+
+parse_error:
+ *al = SSL_AD_DECODE_ERROR;
+ return (0);
+}
+
/* ssl_check_for_safari attempts to fingerprint Safari using OS X
* SecureTransport using the TLS extension block in |d|, of length |n|.
* Safari, since 10.6, sends exactly these extensions, in this order:
@@ -1211,6 +1307,8 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
#ifndef OPENSSL_NO_NEXTPROTONEG
s->s3->next_proto_neg_seen = 0;
#endif
+ free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
ssl_check_for_safari(s, data, d, n);
@@ -1520,7 +1618,8 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
}
#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.
*
@@ -1539,6 +1638,16 @@ ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
s->s3->next_proto_neg_seen = 1;
}
#endif
+ else if (type ==
+ TLSEXT_TYPE_application_layer_protocol_negotiation &&
+ s->ctx->alpn_select_cb != NULL &&
+ s->s3->tmp.finish_md_len == 0) {
+ if (tls1_alpn_handle_client_hello(s, data,
+ size, al) != 1)
+ return (0);
+ /* ALPN takes precedence over NPN. */
+ s->s3->next_proto_neg_seen = 0;
+ }
/* session ticket processed earlier */
#ifndef OPENSSL_NO_SRTP
@@ -1601,6 +1710,8 @@ ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
#ifndef OPENSSL_NO_NEXTPROTONEG
s->s3->next_proto_neg_seen = 0;
#endif
+ free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
if (data >= (d + n - 2))
goto ri_check;
@@ -1716,7 +1827,45 @@ ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
s->s3->next_proto_neg_seen = 1;
}
#endif
- else if (type == TLSEXT_TYPE_renegotiate) {
+ else if (type ==
+ TLSEXT_TYPE_application_layer_protocol_negotiation) {
+ unsigned int 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 = ((unsigned int)data[0]) << 8 |
+ ((unsigned int)data[1]);
+ if (len != (unsigned int)size - 2) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return (0);
+ }
+ len = data[2];
+ if (len != (unsigned int)size - 3) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return (0);
+ }
+ free(s->s3->alpn_selected);
+ s->s3->alpn_selected = malloc(len);
+ if (s->s3->alpn_selected == NULL) {
+ *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))
return 0;
renegotiate_seen = 1;