Bugzilla – Attachment 661347 Details for
Bug 960082
Backport ALPN support to openssl-1.0.1i
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Forgot Password
[patch]
openssl-ALPN.patch
openssl-ALPN.patch (text/plain), 25.09 KB, created by
Marcus Meissner
on 2016-01-11 15:34:08 UTC
(
hide
)
Description:
openssl-ALPN.patch
Filename:
MIME Type:
Creator:
Marcus Meissner
Created:
2016-01-11 15:34:08 UTC
Size:
25.09 KB
patch
obsolete
>commit 83a5efedecbcde6530005f5857698de61a32ee26 >Author: Adam Langley <agl@chromium.org> >Date: Sun Dec 20 04:06:47 2015 -0800 > > Support ALPN. > > This change adds support for ALPN[1] in OpenSSL. ALPN is the IETF > blessed version of NPN and we'll be supporting both ALPN and NPN for > some time yet. > > [1] https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-00 > >diff --git a/apps/s_client.c b/apps/s_client.c >index a2e158b264b0..36a2859050a9 100644 >--- a/apps/s_client.c >+++ b/apps/s_client.c >@@ -360,10 +360,11 @@ static void sc_usage(void) > BIO_printf(bio_err," -tlsextdebug - hex dump of all TLS extensions received\n"); > BIO_printf(bio_err," -status - request certificate status from server\n"); > BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); > # ifndef OPENSSL_NO_NEXTPROTONEG > BIO_printf(bio_err," -nextprotoneg arg - enable NPN extension, considering named protocols supported (comma-separated list)\n"); >+ BIO_printf(bio_err," -alpn arg - enable ALPN extension, considering named protocols supported (comma-separated list)\n"); > # endif > #endif > BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); > #ifndef OPENSSL_NO_SRTP > BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); >@@ -610,10 +611,11 @@ int MAIN(int argc, char **argv) > char *servername = NULL; > tlsextctx tlsextcbp = > {NULL,0}; > # ifndef OPENSSL_NO_NEXTPROTONEG > const char *next_proto_neg_in = NULL; >+ const char *alpn_in = NULL; > # endif > #endif > char *sess_in = NULL; > char *sess_out = NULL; > struct sockaddr peer; >@@ -886,10 +888,15 @@ int MAIN(int argc, char **argv) > else if (strcmp(*argv,"-nextprotoneg") == 0) > { > if (--argc < 1) goto bad; > next_proto_neg_in = *(++argv); > } >+ else if (strcmp(*argv,"-alpn") == 0) >+ { >+ if (--argc < 1) goto bad; >+ alpn_in = *(++argv); >+ } > # endif > #endif > else if (strcmp(*argv,"-serverpref") == 0) > off|=SSL_OP_CIPHER_SERVER_PREFERENCE; > else if (strcmp(*argv,"-legacy_renegotiation") == 0) >@@ -1158,13 +1165,27 @@ bad: > /* DTLS: partial reads end up discarding unread UDP bytes :-( > * Setting read ahead solves this problem. > */ > if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); > >-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) >+#if !defined(OPENSSL_NO_TLSEXT) >+# if !defined(OPENSSL_NO_NEXTPROTONEG) > if (next_proto.data) > SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); >+# endif >+ if (alpn_in) >+ { >+ unsigned short alpn_len; >+ unsigned char *alpn = next_protos_parse(&alpn_len, alpn_in); >+ >+ if (alpn == NULL) >+ { >+ BIO_printf(bio_err, "Error parsing -alpn argument\n"); >+ goto end; >+ } >+ SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len); >+ } > #endif > > if (state) SSL_CTX_set_info_callback(ctx,apps_ssl_info_callback); > if (cipher != NULL) > if(!SSL_CTX_set_cipher_list(ctx,cipher)) { >@@ -2080,19 +2101,34 @@ static void print_stuff(BIO *bio, SSL *s, int full) > getsockname(sock, (struct sockaddr *)&ladd, &ladd_size); > BIO_printf(bio_c_out, "LOCAL PORT is %u\n", ntohs(ladd.sin_port)); > } > #endif > >-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) >+#if !defined(OPENSSL_NO_TLSEXT) >+# if !defined(OPENSSL_NO_NEXTPROTONEG) > if (next_proto.status != -1) { > const unsigned char *proto; > unsigned int proto_len; > SSL_get0_next_proto_negotiated(s, &proto, &proto_len); > BIO_printf(bio, "Next protocol: (%d) ", next_proto.status); > BIO_write(bio, proto, proto_len); > BIO_write(bio, "\n", 1); > } >+ { >+ const unsigned char *proto; >+ unsigned int proto_len; >+ SSL_get0_alpn_selected(s, &proto, &proto_len); >+ if (proto_len > 0) >+ { >+ BIO_printf(bio, "ALPN protocol: "); >+ BIO_write(bio, proto, proto_len); >+ BIO_write(bio, "\n", 1); >+ } >+ else >+ BIO_printf(bio, "No ALPN negotiated\n"); >+ } >+# endif > #endif > > #ifndef OPENSSL_NO_SRTP > { > SRTP_PROTECTION_PROFILE *srtp_profile=SSL_get_selected_srtp_profile(s); >diff --git a/apps/s_server.c b/apps/s_server.c >index e4157cf84ea4..12282424bdc4 100644 >--- a/apps/s_server.c >+++ b/apps/s_server.c >@@ -574,13 +574,14 @@ static void sv_usage(void) > BIO_printf(bio_err," -no_ticket - disable use of RFC4507bis session tickets\n"); > BIO_printf(bio_err," -legacy_renegotiation - enable use of legacy renegotiation (dangerous)\n"); > # ifndef OPENSSL_NO_NEXTPROTONEG > BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n"); > # endif >+ BIO_printf(bio_err," -alpn arg - set the advertised protocols for the ALPN extension (comma-separated list)\n"); >+#endif > # ifndef OPENSSL_NO_SRTP > BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); >-# endif > #endif > BIO_printf(bio_err," -keymatexport label - Export keying material using label\n"); > BIO_printf(bio_err," -keymatexportlen len - Export len bytes of keying material (default 20)\n"); > BIO_printf(bio_err," -status - respond to certificate status requests\n"); > BIO_printf(bio_err," -status_verbose - enable status request verbose printout\n"); >@@ -936,12 +937,51 @@ static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, > > return SSL_TLSEXT_ERR_OK; > } > # endif /* ndef OPENSSL_NO_NEXTPROTONEG */ > >+/* This the context that we pass to alpn_cb */ >+typedef struct tlsextalpnctx_st { >+ unsigned char *data; >+ unsigned short len; >+} tlsextalpnctx; > >-#endif >+static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) >+ { >+ tlsextalpnctx *alpn_ctx = arg; >+ >+ if (!s_quiet) >+ { >+ /* We can assume that |in| is syntactically valid. */ >+ unsigned i; >+ BIO_printf(bio_s_out, "ALPN protocols advertised by the client: "); >+ for (i = 0; i < inlen; ) >+ { >+ if (i) >+ BIO_write(bio_s_out, ", ", 2); >+ BIO_write(bio_s_out, &in[i + 1], in[i]); >+ i += in[i] + 1; >+ } >+ BIO_write(bio_s_out, "\n", 1); >+ } >+ >+ if (SSL_select_next_proto((unsigned char**) out, outlen, alpn_ctx->data, alpn_ctx->len, in, inlen) != >+ OPENSSL_NPN_NEGOTIATED) >+ { >+ return SSL_TLSEXT_ERR_NOACK; >+ } >+ >+ if (!s_quiet) >+ { >+ BIO_printf(bio_s_out, "ALPN protocols selected: "); >+ BIO_write(bio_s_out, *out, *outlen); >+ BIO_write(bio_s_out, "\n", 1); >+ } >+ >+ return SSL_TLSEXT_ERR_OK; >+ } >+#endif /* ndef OPENSSL_NO_TLSEXT */ > > int MAIN(int, char **); > > #ifndef OPENSSL_NO_JPAKE > static char *jpake_secret = NULL; >@@ -985,10 +1025,12 @@ int MAIN(int argc, char *argv[]) > X509 *s_cert2 = NULL; > tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; > # ifndef OPENSSL_NO_NEXTPROTONEG > const char *next_proto_neg_in = NULL; > tlsextnextprotoctx next_proto; >+ const char *alpn_in = NULL; >+ tlsextalpnctx alpn_ctx = { NULL, 0}; > # endif > #endif > #ifndef OPENSSL_NO_PSK > /* by default do not send a PSK identity hint */ > static char *psk_identity_hint=NULL; >@@ -1335,10 +1377,15 @@ int MAIN(int argc, char *argv[]) > else if (strcmp(*argv,"-nextprotoneg") == 0) > { > if (--argc < 1) goto bad; > next_proto_neg_in = *(++argv); > } >+ else if (strcmp(*argv,"-alpn") == 0) >+ { >+ if (--argc < 1) goto bad; >+ alpn_in = *(++argv); >+ } > # endif > #endif > #if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK) > else if (strcmp(*argv,"-jpake") == 0) > { >@@ -1469,11 +1516,12 @@ bad: > } > } > #endif > } > >-#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) >+#if !defined(OPENSSL_NO_TLSEXT) >+# if !defined(OPENSSL_NO_NEXTPROTONEG) > if (next_proto_neg_in) > { > unsigned short len; > next_proto.data = next_protos_parse(&len, next_proto_neg_in); > if (next_proto.data == NULL) >@@ -1482,10 +1530,20 @@ bad: > } > else > { > next_proto.data = NULL; > } >+# endif >+ alpn_ctx.data = NULL; >+ if (alpn_in) >+ { >+ unsigned short len; >+ alpn_ctx.data = next_protos_parse(&len, alpn_in); >+ if (alpn_ctx.data == NULL) >+ goto end; >+ alpn_ctx.len = len; >+ } > #endif > > > if (s_dcert_file) > { >@@ -1682,10 +1740,12 @@ bad: > > # ifndef OPENSSL_NO_NEXTPROTONEG > if (next_proto.data) > SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto); > # endif >+ if (alpn_ctx.data) >+ SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx); > #endif > > #ifndef OPENSSL_NO_DH > if (!no_dhe) > { >@@ -1892,10 +1952,14 @@ bad: > SSL_CTX_set_tlsext_servername_callback(ctx2, ssl_servername_cb); > SSL_CTX_set_tlsext_servername_arg(ctx2, &tlsextcbp); > SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); > SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); > } >+ if (next_proto.data) >+ OPENSSL_free(next_proto.data); >+ if (alpn_ctx.data) >+ OPENSSL_free(alpn_ctx.data); > #endif > > #ifndef OPENSSL_NO_SRP > if (srp_verifier_file != NULL) > { >diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c >index 9d06232367d9..607159ae2fbb 100644 >--- a/ssl/s3_lib.c >+++ b/ssl/s3_lib.c >@@ -2988,10 +2988,15 @@ void ssl3_free(SSL *s) > sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free); > if (s->s3->handshake_buffer) { > BIO_free(s->s3->handshake_buffer); > } > if (s->s3->handshake_dgst) ssl3_free_digest_list(s); >+#ifndef OPENSSL_NO_TLSEXT >+ if (s->s3->alpn_selected) >+ OPENSSL_free(s->s3->alpn_selected); >+#endif >+ > #ifndef OPENSSL_NO_SRP > SSL_SRP_CTX_free(s); > #endif > OPENSSL_cleanse(s->s3,sizeof *s->s3); > OPENSSL_free(s->s3); >@@ -3052,10 +3057,18 @@ void ssl3_clear(SSL *s) > s->s3->handshake_buffer = NULL; > } > if (s->s3->handshake_dgst) { > ssl3_free_digest_list(s); > } >+ >+#if !defined(OPENSSL_NO_TLSEXT) >+ if (s->s3->alpn_selected) >+ { >+ free(s->s3->alpn_selected); >+ s->s3->alpn_selected = NULL; >+ } >+#endif > memset(s->s3,0,sizeof *s->s3); > s->s3->rbuf.buf = rp; > s->s3->wbuf.buf = wp; > s->s3->rbuf.len = rlen; > s->s3->wbuf.len = wlen; >diff --git a/ssl/ssl.h b/ssl/ssl.h >index 5a06b7584c79..63abee49ef1b 100644 >--- a/ssl/ssl.h >+++ b/ssl/ssl.h >@@ -992,10 +992,35 @@ struct ssl_ctx_st > const unsigned char *in, > unsigned int inlen, > void *arg); > void *next_proto_select_cb_arg; > # endif >+ >+ /* ALPN information >+ * (we are in the process of transitioning from NPN to ALPN.) */ >+ >+ /* For a server, this contains a callback function that allows the >+ * server to select the protocol for the connection. >+ * out: on successful return, this must point to the raw protocol >+ * name (without the length prefix). >+ * outlen: on successful return, this contains the length of |*out|. >+ * in: points to the client's list of supported protocols in >+ * wire-format. >+ * inlen: the length of |in|. */ >+ int (*alpn_select_cb)(SSL *s, >+ const unsigned char **out, >+ unsigned char *outlen, >+ const unsigned char* in, >+ unsigned int inlen, >+ void *arg); >+ void *alpn_select_cb_arg; >+ >+ /* For a client, this contains the list of supported protocols in wire >+ * format. */ >+ unsigned char* alpn_client_proto_list; >+ unsigned alpn_client_proto_list_len; >+ > /* SRTP profiles we are willing to do from RFC 5764 */ > STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; > #endif > }; > >@@ -1078,10 +1103,25 @@ void SSL_get0_next_proto_negotiated(const SSL *s, > #define OPENSSL_NPN_UNSUPPORTED 0 > #define OPENSSL_NPN_NEGOTIATED 1 > #define OPENSSL_NPN_NO_OVERLAP 2 > #endif > >+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char* protos, >+ unsigned protos_len); >+int SSL_set_alpn_protos(SSL *ssl, const unsigned char* protos, >+ unsigned protos_len); >+void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx, >+ int (*cb) (SSL *ssl, >+ const unsigned char **out, >+ unsigned char *outlen, >+ const unsigned char *in, >+ unsigned int inlen, >+ void *arg), >+ void *arg); >+void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, >+ unsigned *len); >+ > #ifndef OPENSSL_NO_PSK > /* the maximum length of the buffer given to callbacks containing the > * resulting identity/psk */ > #define PSK_MAX_IDENTITY_LEN 128 > #define PSK_MAX_PSK_LEN 256 >@@ -1358,10 +1398,15 @@ struct ssl_st > 1: enabled > 2: enabled, but not allowed to send Requests > */ > unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */ > unsigned int tlsext_hb_seq; /* HeartbeatRequest sequence number */ >+ >+ /* For a client, this contains the list of supported protocols in wire >+ * format. */ >+ unsigned char* alpn_client_proto_list; >+ unsigned alpn_client_proto_list_len; > #else > #define session_ctx ctx > #endif /* OPENSSL_NO_TLSEXT */ > > int renegotiate;/* 1 if we are renegotiating. >diff --git a/ssl/ssl3.h b/ssl/ssl3.h >index 85f150409d21..a4d93e686a32 100644 >--- a/ssl/ssl3.h >+++ b/ssl/ssl3.h >@@ -551,10 +551,20 @@ typedef struct ssl3_state_st > /* This is set to true if we believe that this is a version of Safari > * running on OS X 10.6 or newer. We wish to know this because Safari > * on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */ > char is_probably_safari; > #endif /* !OPENSSL_NO_EC */ >+ >+ /* ALPN information >+ * (we are in the process of transitioning from NPN to ALPN.) */ >+ >+ /* In a server these point to the selected ALPN protocol after the >+ * ClientHello has been processed. In a client these contain the >+ * protocol that the server selected once the ServerHello has been >+ * processed. */ >+ unsigned char *alpn_selected; >+ unsigned alpn_selected_len; > #endif /* !OPENSSL_NO_TLSEXT */ > } SSL3_STATE; > > #endif > >diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c >index 666e9879993f..c24e9b6c40f8 100644 >--- a/ssl/ssl_lib.c >+++ b/ssl/ssl_lib.c >@@ -356,10 +356,21 @@ SSL *SSL_new(SSL_CTX *ctx) > CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); > s->initial_ctx=ctx; > # ifndef OPENSSL_NO_NEXTPROTONEG > s->next_proto_negotiated = NULL; > # endif >+ >+ if (s->ctx->alpn_client_proto_list) >+ { >+ s->alpn_client_proto_list = >+ OPENSSL_malloc(s->ctx->alpn_client_proto_list_len); >+ if (s->alpn_client_proto_list == NULL) >+ goto err; >+ memcpy(s->alpn_client_proto_list, s->ctx->alpn_client_proto_list, >+ s->ctx->alpn_client_proto_list_len); >+ s->alpn_client_proto_list_len = s->ctx->alpn_client_proto_list_len; >+ } > #endif > > s->verify_result=X509_V_OK; > > s->method=ctx->method; >@@ -575,10 +586,12 @@ void SSL_free(SSL *s) > X509_EXTENSION_free); > if (s->tlsext_ocsp_ids) > sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); > if (s->tlsext_ocsp_resp) > OPENSSL_free(s->tlsext_ocsp_resp); >+ if (s->alpn_client_proto_list) >+ OPENSSL_free(s->alpn_client_proto_list); > #endif > > if (s->client_CA != NULL) > sk_X509_NAME_pop_free(s->client_CA,X509_NAME_free); > >@@ -1667,11 +1680,83 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, int (*cb) (SSL *s, unsigned > { > ctx->next_proto_select_cb = cb; > ctx->next_proto_select_cb_arg = arg; > } > # endif >-#endif >+ >+/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|. >+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit >+ * length-prefixed strings). >+ * >+ * Returns 0 on success. */ >+int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char* protos, >+ unsigned protos_len) >+ { >+ if (ctx->alpn_client_proto_list) >+ OPENSSL_free(ctx->alpn_client_proto_list); >+ >+ ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len); >+ if (!ctx->alpn_client_proto_list) >+ return 1; >+ memcpy(ctx->alpn_client_proto_list, protos, protos_len); >+ ctx->alpn_client_proto_list_len = protos_len; >+ >+ return 0; >+ } >+ >+/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|. >+ * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit >+ * length-prefixed strings). >+ * >+ * Returns 0 on success. */ >+int SSL_set_alpn_protos(SSL *ssl, const unsigned char* protos, >+ unsigned protos_len) >+ { >+ if (ssl->alpn_client_proto_list) >+ OPENSSL_free(ssl->alpn_client_proto_list); >+ >+ ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len); >+ if (!ssl->alpn_client_proto_list) >+ return 1; >+ memcpy(ssl->alpn_client_proto_list, protos, protos_len); >+ ssl->alpn_client_proto_list_len = protos_len; >+ >+ return 0; >+ } >+ >+/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called >+ * during ClientHello processing in order to select an ALPN protocol from the >+ * client's list of offered protocols. */ >+void SSL_CTX_set_alpn_select_cb(SSL_CTX* ctx, >+ int (*cb) (SSL *ssl, >+ const unsigned char **out, >+ unsigned char *outlen, >+ const unsigned char *in, >+ unsigned int inlen, >+ void *arg), >+ void *arg) >+ { >+ ctx->alpn_select_cb = cb; >+ ctx->alpn_select_cb_arg = arg; >+ } >+ >+/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|. >+ * On return it sets |*data| to point to |*len| bytes of protocol name (not >+ * including the leading length-prefix byte). If the server didn't respond with >+ * a negotiated protocol then |*len| will be zero. */ >+void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data, >+ unsigned *len) >+ { >+ *data = NULL; >+ if (ssl->s3) >+ *data = ssl->s3->alpn_selected; >+ if (*data == NULL) >+ *len = 0; >+ else >+ *len = ssl->s3->alpn_selected_len; >+ } >+#endif /* !OPENSSL_NO_TLSEXT */ > > int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen, > const char *label, size_t llen, const unsigned char *p, size_t plen, > int use_context) > { >@@ -2017,10 +2102,14 @@ void SSL_CTX_free(SSL_CTX *a) > if (a->wbuf_freelist) > ssl_buf_freelist_free(a->wbuf_freelist); > if (a->rbuf_freelist) > ssl_buf_freelist_free(a->rbuf_freelist); > #endif >+#ifndef OPENSSL_NO_TLSEXT >+ if (a->alpn_client_proto_list != NULL) >+ OPENSSL_free(a->alpn_client_proto_list); >+#endif > > OPENSSL_free(a); > } > > void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) >diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c >index e92c5f2e1766..a249fd14efc0 100644 >--- a/ssl/t1_lib.c >+++ b/ssl/t1_lib.c >@@ -646,10 +646,22 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned c > s2n(TLSEXT_TYPE_next_proto_neg,ret); > s2n(0,ret); > } > #endif > >+ 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_IS_DTLS(s) && SSL_get_srtp_profiles(s)) > { > int el; > >@@ -887,17 +899,102 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned c > s->s3->next_proto_neg_seen = 1; > } > } > #endif > >+ 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-orig-2)== 0) > return orig; > > s2n(extdatalen, orig); > 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; >+ } >+ > #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|. > * Safari, since 10.6, sends exactly these extensions, in this order: > * SNI, >@@ -992,10 +1089,16 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in > s->tlsext_status_type = -1; > #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); > #endif > >@@ -1425,11 +1528,12 @@ 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. > * > * s->new_session will be set on renegotiation, but we >@@ -1446,10 +1550,20 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in > * Finished message could have been computed.) */ > s->s3->next_proto_neg_seen = 1; > } > #endif > >+ 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 (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s) > && type == TLSEXT_TYPE_use_srtp) > { >@@ -1511,10 +1625,16 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in > > #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); > #endif > >@@ -1679,10 +1799,56 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in > memcpy(s->next_proto_negotiated, selected, selected_len); > s->next_proto_negotiated_len = selected_len; > s->s3->next_proto_neg_seen = 1; > } > #endif >+ >+ 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)) > return 0; > renegotiate_seen = 1; >diff --git a/ssl/tls1.h b/ssl/tls1.h >index 6ae887646253..619e71eb7cb4 100644 >--- a/ssl/tls1.h >+++ b/ssl/tls1.h >@@ -237,10 +237,13 @@ extern "C" { > * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml > * http://tools.ietf.org/html/draft-agl-tls-padding-03 > */ > #define TLSEXT_TYPE_padding 21 > >+/* ExtensionType value from draft-ietf-tls-applayerprotoneg-00 */ >+#define TLSEXT_TYPE_application_layer_protocol_negotiation 16 >+ > /* ExtensionType value from RFC4507 */ > #define TLSEXT_TYPE_session_ticket 35 > > /* ExtensionType value from draft-rescorla-tls-opaque-prf-input-00.txt */ > #if 0 /* will have to be provided externally for now ,
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 960082
:
661345
|
661346
| 661347