From 7b2f3298f7eb7ce5cfd1c3eb55b1ecc89118f52c Mon Sep 17 00:00:00 2001 From: jsing <> Date: Wed, 10 Dec 2014 15:24:01 +0000 Subject: Add ALPN support to openssl(1). Based on OpenSSL. --- src/usr.bin/openssl/s_server.c | 74 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 9 deletions(-) (limited to 'src/usr.bin/openssl/s_server.c') diff --git a/src/usr.bin/openssl/s_server.c b/src/usr.bin/openssl/s_server.c index b3cdb30a61..35ed6d169c 100644 --- a/src/usr.bin/openssl/s_server.c +++ b/src/usr.bin/openssl/s_server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: s_server.c,v 1.7 2014/12/02 19:44:49 deraadt Exp $ */ +/* $OpenBSD: s_server.c,v 1.8 2014/12/10 15:24:01 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -351,6 +351,7 @@ sv_usage(void) #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"); #ifndef OPENSSL_NO_SRTP BIO_printf(bio_err, " -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n"); #endif @@ -545,6 +546,45 @@ next_proto_cb(SSL * s, const unsigned char **data, unsigned int *len, void *arg) #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; + +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); +} int s_server_main(int, char **); @@ -583,8 +623,10 @@ s_server_main(int argc, char *argv[]) tlsextctx tlsextcbp = {NULL, NULL, SSL_TLSEXT_ERR_ALERT_WARNING}; #ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; - tlsextnextprotoctx next_proto; + tlsextnextprotoctx next_proto = { NULL, 0 }; #endif + const char *alpn_in = NULL; + tlsextalpnctx alpn_ctx = { NULL, 0 }; meth = SSLv23_server_method(); local_argc = argc; @@ -838,6 +880,11 @@ s_server_main(int argc, char *argv[]) next_proto_neg_in = *(++argv); } #endif + else if (strcmp(*argv,"-alpn") == 0) { + if (--argc < 1) + goto bad; + alpn_in = *(++argv); + } #ifndef OPENSSL_NO_SRTP else if (strcmp(*argv, "-use_srtp") == 0) { if (--argc < 1) @@ -916,7 +963,7 @@ bad: } } } -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto_neg_in) { unsigned short len; next_proto.data = next_protos_parse(&len, next_proto_neg_in); @@ -927,7 +974,14 @@ 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; + } if (s_dcert_file) { @@ -957,8 +1011,7 @@ bad: bio_s_out = BIO_new_fp(stdout, BIO_NOCLOSE); } } - if (nocert) - { + if (nocert) { s_cert_file = NULL; s_key_file = NULL; s_dcert_file = NULL; @@ -1076,6 +1129,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); #ifndef OPENSSL_NO_DH if (!no_dhe) { @@ -1241,6 +1296,8 @@ end: X509_free(s_cert2); if (s_key2) EVP_PKEY_free(s_key2); + free(next_proto.data); + free(alpn_ctx.data); if (bio_s_out != NULL) { BIO_free(bio_s_out); bio_s_out = NULL; @@ -1603,13 +1660,12 @@ init_ssl_connection(SSL * con) X509 *peer; long verify_error; char buf[BUFSIZ]; -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_NEXTPROTONEG) const unsigned char *next_proto_neg; unsigned next_proto_neg_len; #endif unsigned char *exportedkeymat; - i = SSL_accept(con); if (i <= 0) { if (BIO_sock_should_retry(i)) { @@ -1642,7 +1698,7 @@ init_ssl_connection(SSL * con) str = SSL_CIPHER_get_name(SSL_get_current_cipher(con)); BIO_printf(bio_s_out, "CIPHER is %s\n", (str != NULL) ? str : "(NONE)"); -#if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) +#if !defined(OPENSSL_NO_NEXTPROTONEG) SSL_get0_next_proto_negotiated(con, &next_proto_neg, &next_proto_neg_len); if (next_proto_neg) { BIO_printf(bio_s_out, "NEXTPROTO is "); -- cgit v1.2.3-55-g6feb