summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authorAdam Langley <agl@chromium.org>2013-04-15 18:07:47 -0400
committerBen Laurie <ben@links.org>2013-07-22 15:28:20 +0100
commit6f017a8f9db3a79f3a3406cf8d493ccd346db691 (patch)
tree68d7c91646105cb2e1fe65852c09458108ea2e01 /apps
parent584ac22110b2ff367d3632a89cf7b15c015903b8 (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.c40
-rw-r--r--apps/s_server.c70
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)