diff options
author | Adam Langley <agl@chromium.org> | 2013-04-15 18:07:47 -0400 |
---|---|---|
committer | Ben Laurie <ben@links.org> | 2013-07-22 15:28:20 +0100 |
commit | 6f017a8f9db3a79f3a3406cf8d493ccd346db691 (patch) | |
tree | 68d7c91646105cb2e1fe65852c09458108ea2e01 /apps | |
parent | 584ac22110b2ff367d3632a89cf7b15c015903b8 (diff) |
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
Conflicts:
ssl/ssl3.h
ssl/t1_lib.c
Diffstat (limited to 'apps')
-rw-r--r-- | apps/s_client.c | 40 | ||||
-rw-r--r-- | apps/s_server.c | 70 |
2 files changed, 106 insertions, 4 deletions
diff --git a/apps/s_client.c b/apps/s_client.c index 5fb5dffda7..b7e4fbb408 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -364,6 +364,7 @@ static void sc_usage(void) BIO_printf(bio_err," -proof_debug - request an audit proof and print its hex dump\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 #ifndef OPENSSL_NO_TLSEXT BIO_printf(bio_err," -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n"); @@ -636,6 +637,7 @@ int MAIN(int argc, char **argv) {NULL,0}; # ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; + const char *alpn_in = NULL; # endif # define MAX_SI_TYPES 100 unsigned short serverinfo_types[MAX_SI_TYPES]; @@ -993,6 +995,11 @@ static char *jpake_secret = NULL; 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 else if (strcmp(*argv,"-serverinfo") == 0) { @@ -1306,9 +1313,23 @@ bad: */ 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 #ifndef OPENSSL_NO_TLSEXT if (serverinfo_types_count) @@ -2265,7 +2286,8 @@ static void print_stuff(BIO *bio, SSL *s, int full) } #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; @@ -2274,6 +2296,20 @@ static void print_stuff(BIO *bio, SSL *s, int full) 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 { diff --git a/apps/s_server.c b/apps/s_server.c index bf61a8d09e..f5c26dc605 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -578,6 +578,7 @@ static void sv_usage(void) BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n"); # endif BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); + BIO_printf(bio_err," -alpn arg - set the advertised protocols for the ALPN extension (comma-separated list)\n"); #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"); @@ -932,7 +933,48 @@ static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len, return SSL_TLSEXT_ERR_OK; } # endif /* ndef OPENSSL_NO_NEXTPROTONEG */ -#endif + +/* This the context that we pass to alpn_cb */ +typedef struct tlsextalpnctx_st { + unsigned char *data; + unsigned short len; +} tlsextalpnctx; + +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 */ static int not_resumable_sess_cb(SSL *s, int is_forward_secure) { @@ -988,6 +1030,8 @@ int MAIN(int argc, char *argv[]) # 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 @@ -1438,6 +1482,11 @@ int MAIN(int argc, char *argv[]) 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) @@ -1565,7 +1614,8 @@ bad: #endif /* OPENSSL_NO_TLSEXT */ } -#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; @@ -1578,6 +1628,16 @@ bad: { 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 (crl_file) @@ -1812,6 +1872,8 @@ bad: 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 @@ -2047,6 +2109,10 @@ end: BIO_free(authz_in); if (serverinfo_in != NULL) BIO_free(serverinfo_in); + if (next_proto.data) + OPENSSL_free(next_proto.data); + if (alpn_ctx.data) + OPENSSL_free(alpn_ctx.data); #endif ssl_excert_free(exc); if (ssl_args) |