Commit 6f017a8f authored by Adam Langley's avatar Adam Langley Committed by Ben Laurie
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
parent 584ac221
Loading
Loading
Loading
Loading
+38 −2
Original line number Diff line number Diff line
@@ -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

 	{
+68 −2
Original line number Diff line number Diff line
@@ -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;
@@ -1579,6 +1629,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)
+13 −0
Original line number Diff line number Diff line
@@ -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;
+45 −0
Original line number Diff line number Diff line
@@ -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 */
+11 −1
Original line number Diff line number Diff line
@@ -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
Loading