Skip to content
Permalink
Browse files

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
  • Loading branch information...
Adam Langley authored and benlaurie committed Apr 15, 2013
1 parent 584ac22 commit 6f017a8f9db3a79f3a3406cf8d493ccd346db691
Showing with 432 additions and 7 deletions.
  1. +38 −2 apps/s_client.c
  2. +68 −2 apps/s_server.c
  3. +13 −0 ssl/s3_lib.c
  4. +45 −0 ssl/ssl.h
  5. +11 −1 ssl/ssl3.h
  6. +87 −1 ssl/ssl_lib.c
  7. +167 −1 ssl/t1_lib.c
  8. +3 −0 ssl/tls1.h
@@ -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 @@ static char *jpake_secret = NULL;
*/
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

{
@@ -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 @@ int MAIN(int argc, char *argv[])
#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 @@ int MAIN(int argc, char *argv[])
{
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 @@ int MAIN(int argc, char *argv[])
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 @@ int MAIN(int argc, char *argv[])
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)
@@ -3020,6 +3020,11 @@ void ssl3_free(SSL *s)
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
@@ -3098,6 +3103,14 @@ void ssl3_clear(SSL *s)
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;
@@ -1100,6 +1100,31 @@ struct ssl_ctx_st
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
@@ -1202,6 +1227,21 @@ void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,

#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 */
@@ -1508,6 +1548,11 @@ struct ssl_st
*/
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 */
@@ -586,7 +586,17 @@ typedef struct ssl3_state_st
* as the types were received in the client hello. */
unsigned short *tlsext_custom_types;
size_t tlsext_custom_types_count; /* how many tlsext_custom_types */
#endif

/* 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

0 comments on commit 6f017a8

Please sign in to comment.
You can’t perform that action at this time.