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. Cherry-picked from 6f017a8f9db3a79f3a3406cf8d493ccd346db691. [1] https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-00
This commit is contained in:
parent
0338648426
commit
b0d6f3c58f
@ -368,6 +368,7 @@ static void sc_usage(void)
|
|||||||
BIO_printf(bio_err," -proof_debug - request an audit proof and print its hex dump\n");
|
BIO_printf(bio_err," -proof_debug - request an audit proof and print its hex dump\n");
|
||||||
# ifndef OPENSSL_NO_NEXTPROTONEG
|
# 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," -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
|
# endif
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
BIO_printf(bio_err," -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n");
|
BIO_printf(bio_err," -serverinfo types - send empty ClientHello extensions (comma-separated numbers)\n");
|
||||||
@ -640,6 +641,7 @@ int MAIN(int argc, char **argv)
|
|||||||
{NULL,0};
|
{NULL,0};
|
||||||
# ifndef OPENSSL_NO_NEXTPROTONEG
|
# ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
const char *next_proto_neg_in = NULL;
|
const char *next_proto_neg_in = NULL;
|
||||||
|
const char *alpn_in = NULL;
|
||||||
# endif
|
# endif
|
||||||
# define MAX_SI_TYPES 100
|
# define MAX_SI_TYPES 100
|
||||||
unsigned short serverinfo_types[MAX_SI_TYPES];
|
unsigned short serverinfo_types[MAX_SI_TYPES];
|
||||||
@ -988,6 +990,11 @@ static char *jpake_secret = NULL;
|
|||||||
if (--argc < 1) goto bad;
|
if (--argc < 1) goto bad;
|
||||||
next_proto_neg_in = *(++argv);
|
next_proto_neg_in = *(++argv);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(*argv,"-alpn") == 0)
|
||||||
|
{
|
||||||
|
if (--argc < 1) goto bad;
|
||||||
|
alpn_in = *(++argv);
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
else if (strcmp(*argv,"-serverinfo") == 0)
|
else if (strcmp(*argv,"-serverinfo") == 0)
|
||||||
{
|
{
|
||||||
@ -1301,9 +1308,24 @@ bad:
|
|||||||
*/
|
*/
|
||||||
if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1);
|
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)
|
if (next_proto.data)
|
||||||
SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto);
|
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);
|
||||||
|
OPENSSL_free(alpn);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifndef OPENSSL_NO_TLSEXT
|
#ifndef OPENSSL_NO_TLSEXT
|
||||||
if (serverinfo_types_count)
|
if (serverinfo_types_count)
|
||||||
@ -2262,7 +2284,8 @@ static void print_stuff(BIO *bio, SSL *s, int full)
|
|||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (next_proto.status != -1) {
|
||||||
const unsigned char *proto;
|
const unsigned char *proto;
|
||||||
unsigned int proto_len;
|
unsigned int proto_len;
|
||||||
@ -2271,6 +2294,20 @@ static void print_stuff(BIO *bio, SSL *s, int full)
|
|||||||
BIO_write(bio, proto, proto_len);
|
BIO_write(bio, proto, proto_len);
|
||||||
BIO_write(bio, "\n", 1);
|
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
|
#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");
|
BIO_printf(bio_err," -nextprotoneg arg - set the advertised protocols for the NPN extension (comma-separated list)\n");
|
||||||
# endif
|
# endif
|
||||||
BIO_printf(bio_err," -use_srtp profiles - Offer SRTP key management with a colon-separated profile list\n");
|
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
|
#endif
|
||||||
BIO_printf(bio_err," -keymatexport label - Export keying material using label\n");
|
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");
|
BIO_printf(bio_err," -keymatexportlen len - Export len bytes of keying material (default 20)\n");
|
||||||
@ -933,8 +934,47 @@ static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
|
|||||||
}
|
}
|
||||||
# endif /* ndef OPENSSL_NO_NEXTPROTONEG */
|
# 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;
|
||||||
|
|
||||||
#endif
|
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 */
|
||||||
|
|
||||||
int MAIN(int, char **);
|
int MAIN(int, char **);
|
||||||
|
|
||||||
@ -984,6 +1024,8 @@ int MAIN(int argc, char *argv[])
|
|||||||
# ifndef OPENSSL_NO_NEXTPROTONEG
|
# ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
const char *next_proto_neg_in = NULL;
|
const char *next_proto_neg_in = NULL;
|
||||||
tlsextnextprotoctx next_proto;
|
tlsextnextprotoctx next_proto;
|
||||||
|
const char *alpn_in = NULL;
|
||||||
|
tlsextalpnctx alpn_ctx = { NULL, 0};
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef OPENSSL_NO_PSK
|
#ifndef OPENSSL_NO_PSK
|
||||||
@ -1424,6 +1466,11 @@ int MAIN(int argc, char *argv[])
|
|||||||
if (--argc < 1) goto bad;
|
if (--argc < 1) goto bad;
|
||||||
next_proto_neg_in = *(++argv);
|
next_proto_neg_in = *(++argv);
|
||||||
}
|
}
|
||||||
|
else if (strcmp(*argv,"-alpn") == 0)
|
||||||
|
{
|
||||||
|
if (--argc < 1) goto bad;
|
||||||
|
alpn_in = *(++argv);
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
|
#if !defined(OPENSSL_NO_JPAKE) && !defined(OPENSSL_NO_PSK)
|
||||||
@ -1551,7 +1598,8 @@ bad:
|
|||||||
#endif /* OPENSSL_NO_TLSEXT */
|
#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)
|
if (next_proto_neg_in)
|
||||||
{
|
{
|
||||||
unsigned short len;
|
unsigned short len;
|
||||||
@ -1564,6 +1612,16 @@ bad:
|
|||||||
{
|
{
|
||||||
next_proto.data = NULL;
|
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
|
#endif
|
||||||
|
|
||||||
if (crl_file)
|
if (crl_file)
|
||||||
@ -1801,6 +1859,8 @@ bad:
|
|||||||
if (next_proto.data)
|
if (next_proto.data)
|
||||||
SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto);
|
SSL_CTX_set_next_protos_advertised_cb(ctx, next_proto_cb, &next_proto);
|
||||||
# endif
|
# endif
|
||||||
|
if (alpn_ctx.data)
|
||||||
|
SSL_CTX_set_alpn_select_cb(ctx, alpn_cb, &alpn_ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_DH
|
#ifndef OPENSSL_NO_DH
|
||||||
@ -2027,6 +2087,10 @@ end:
|
|||||||
BIO_free(authz_in);
|
BIO_free(authz_in);
|
||||||
if (serverinfo_in != NULL)
|
if (serverinfo_in != NULL)
|
||||||
BIO_free(serverinfo_in);
|
BIO_free(serverinfo_in);
|
||||||
|
if (next_proto.data)
|
||||||
|
OPENSSL_free(next_proto.data);
|
||||||
|
if (alpn_ctx.data)
|
||||||
|
OPENSSL_free(alpn_ctx.data);
|
||||||
#endif
|
#endif
|
||||||
ssl_excert_free(exc);
|
ssl_excert_free(exc);
|
||||||
if (ssl_args)
|
if (ssl_args)
|
||||||
|
13
ssl/s3_lib.c
13
ssl/s3_lib.c
@ -3002,6 +3002,11 @@ void ssl3_free(SSL *s)
|
|||||||
BIO_free(s->s3->handshake_buffer);
|
BIO_free(s->s3->handshake_buffer);
|
||||||
}
|
}
|
||||||
if (s->s3->handshake_dgst) ssl3_free_digest_list(s);
|
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
|
#ifndef OPENSSL_NO_SRP
|
||||||
SSL_SRP_CTX_free(s);
|
SSL_SRP_CTX_free(s);
|
||||||
#endif
|
#endif
|
||||||
@ -3080,6 +3085,14 @@ void ssl3_clear(SSL *s)
|
|||||||
if (s->s3->handshake_dgst) {
|
if (s->s3->handshake_dgst) {
|
||||||
ssl3_free_digest_list(s);
|
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);
|
memset(s->s3,0,sizeof *s->s3);
|
||||||
s->s3->rbuf.buf = rp;
|
s->s3->rbuf.buf = rp;
|
||||||
s->s3->wbuf.buf = wp;
|
s->s3->wbuf.buf = wp;
|
||||||
|
45
ssl/ssl.h
45
ssl/ssl.h
@ -1097,6 +1097,31 @@ struct ssl_ctx_st
|
|||||||
void *arg);
|
void *arg);
|
||||||
void *next_proto_select_cb_arg;
|
void *next_proto_select_cb_arg;
|
||||||
# endif
|
# 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 */
|
/* SRTP profiles we are willing to do from RFC 5764 */
|
||||||
STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
|
STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles;
|
||||||
# ifndef OPENSSL_NO_EC
|
# ifndef OPENSSL_NO_EC
|
||||||
@ -1195,6 +1220,21 @@ void SSL_get0_next_proto_negotiated(const SSL *s,
|
|||||||
#define OPENSSL_NPN_NO_OVERLAP 2
|
#define OPENSSL_NPN_NO_OVERLAP 2
|
||||||
#endif
|
#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
|
#ifndef OPENSSL_NO_PSK
|
||||||
/* the maximum length of the buffer given to callbacks containing the
|
/* the maximum length of the buffer given to callbacks containing the
|
||||||
* resulting identity/psk */
|
* resulting identity/psk */
|
||||||
@ -1501,6 +1541,11 @@ struct ssl_st
|
|||||||
*/
|
*/
|
||||||
unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */
|
unsigned int tlsext_hb_pending; /* Indicates if a HeartbeatRequest is in flight */
|
||||||
unsigned int tlsext_hb_seq; /* HeartbeatRequest sequence number */
|
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
|
#else
|
||||||
#define session_ctx ctx
|
#define session_ctx ctx
|
||||||
#endif /* OPENSSL_NO_TLSEXT */
|
#endif /* OPENSSL_NO_TLSEXT */
|
||||||
|
12
ssl/ssl3.h
12
ssl/ssl3.h
@ -580,7 +580,17 @@ typedef struct ssl3_state_st
|
|||||||
* as the types were received in the client hello. */
|
* as the types were received in the client hello. */
|
||||||
unsigned short *tlsext_custom_types;
|
unsigned short *tlsext_custom_types;
|
||||||
size_t tlsext_custom_types_count; /* how many 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;
|
} SSL3_STATE;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -381,6 +381,17 @@ SSL *SSL_new(SSL_CTX *ctx)
|
|||||||
# ifndef OPENSSL_NO_NEXTPROTONEG
|
# ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
s->next_proto_negotiated = NULL;
|
s->next_proto_negotiated = NULL;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
if (s->ctx->alpn_client_proto_list)
|
||||||
|
{
|
||||||
|
s->alpn_client_proto_list =
|
||||||
|
OPENSSL_malloc(s->ctx->alpn_client_proto_list_len);
|
||||||
|
if (s->alpn_client_proto_list == NULL)
|
||||||
|
goto err;
|
||||||
|
memcpy(s->alpn_client_proto_list, s->ctx->alpn_client_proto_list,
|
||||||
|
s->ctx->alpn_client_proto_list_len);
|
||||||
|
s->alpn_client_proto_list_len = s->ctx->alpn_client_proto_list_len;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
s->verify_result=X509_V_OK;
|
s->verify_result=X509_V_OK;
|
||||||
@ -605,6 +616,8 @@ void SSL_free(SSL *s)
|
|||||||
sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
|
sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free);
|
||||||
if (s->tlsext_ocsp_resp)
|
if (s->tlsext_ocsp_resp)
|
||||||
OPENSSL_free(s->tlsext_ocsp_resp);
|
OPENSSL_free(s->tlsext_ocsp_resp);
|
||||||
|
if (s->alpn_client_proto_list)
|
||||||
|
OPENSSL_free(s->alpn_client_proto_list);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s->client_CA != NULL)
|
if (s->client_CA != NULL)
|
||||||
@ -1769,7 +1782,78 @@ int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|.
|
||||||
|
* |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
|
||||||
|
* length-prefixed strings).
|
||||||
|
*
|
||||||
|
* Returns 0 on success. */
|
||||||
|
int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char* protos,
|
||||||
|
unsigned protos_len)
|
||||||
|
{
|
||||||
|
if (ctx->alpn_client_proto_list)
|
||||||
|
OPENSSL_free(ctx->alpn_client_proto_list);
|
||||||
|
|
||||||
|
ctx->alpn_client_proto_list = OPENSSL_malloc(protos_len);
|
||||||
|
if (!ctx->alpn_client_proto_list)
|
||||||
|
return 1;
|
||||||
|
memcpy(ctx->alpn_client_proto_list, protos, protos_len);
|
||||||
|
ctx->alpn_client_proto_list_len = protos_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|.
|
||||||
|
* |protos| must be in wire-format (i.e. a series of non-empty, 8-bit
|
||||||
|
* length-prefixed strings).
|
||||||
|
*
|
||||||
|
* Returns 0 on success. */
|
||||||
|
int SSL_set_alpn_protos(SSL *ssl, const unsigned char* protos,
|
||||||
|
unsigned protos_len)
|
||||||
|
{
|
||||||
|
if (ssl->alpn_client_proto_list)
|
||||||
|
OPENSSL_free(ssl->alpn_client_proto_list);
|
||||||
|
|
||||||
|
ssl->alpn_client_proto_list = OPENSSL_malloc(protos_len);
|
||||||
|
if (!ssl->alpn_client_proto_list)
|
||||||
|
return 1;
|
||||||
|
memcpy(ssl->alpn_client_proto_list, protos, protos_len);
|
||||||
|
ssl->alpn_client_proto_list_len = protos_len;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSL_CTX_set_alpn_select_cb sets a callback function on |ctx| that is called
|
||||||
|
* during ClientHello processing in order to select an ALPN protocol from the
|
||||||
|
* client's list of offered protocols. */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
ctx->alpn_select_cb = cb;
|
||||||
|
ctx->alpn_select_cb_arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SSL_get0_alpn_selected gets the selected ALPN protocol (if any) from |ssl|.
|
||||||
|
* On return it sets |*data| to point to |*len| bytes of protocol name (not
|
||||||
|
* including the leading length-prefix byte). If the server didn't respond with
|
||||||
|
* a negotiated protocol then |*len| will be zero. */
|
||||||
|
void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
|
||||||
|
unsigned *len)
|
||||||
|
{
|
||||||
|
*data = NULL;
|
||||||
|
if (ssl->s3)
|
||||||
|
*data = ssl->s3->alpn_selected;
|
||||||
|
if (*data == NULL)
|
||||||
|
*len = 0;
|
||||||
|
else
|
||||||
|
*len = ssl->s3->alpn_selected_len;
|
||||||
|
}
|
||||||
|
#endif /* !OPENSSL_NO_TLSEXT */
|
||||||
|
|
||||||
int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
|
int SSL_export_keying_material(SSL *s, unsigned char *out, size_t olen,
|
||||||
const char *label, size_t llen, const unsigned char *p, size_t plen,
|
const char *label, size_t llen, const unsigned char *p, size_t plen,
|
||||||
@ -2132,6 +2216,8 @@ void SSL_CTX_free(SSL_CTX *a)
|
|||||||
if (a->tlsext_ellipticcurvelist)
|
if (a->tlsext_ellipticcurvelist)
|
||||||
OPENSSL_free(a->tlsext_ellipticcurvelist);
|
OPENSSL_free(a->tlsext_ellipticcurvelist);
|
||||||
# endif /* OPENSSL_NO_EC */
|
# endif /* OPENSSL_NO_EC */
|
||||||
|
if (a->alpn_client_proto_list != NULL)
|
||||||
|
OPENSSL_free(a->alpn_client_proto_list);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
OPENSSL_free(a);
|
OPENSSL_free(a);
|
||||||
|
168
ssl/t1_lib.c
168
ssl/t1_lib.c
@ -1371,6 +1371,18 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len)
|
||||||
|
{
|
||||||
|
if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
|
||||||
|
return NULL;
|
||||||
|
s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
|
||||||
|
s2n(2 + s->alpn_client_proto_list_len,ret);
|
||||||
|
s2n(s->alpn_client_proto_list_len,ret);
|
||||||
|
memcpy(ret, s->alpn_client_proto_list,
|
||||||
|
s->alpn_client_proto_list_len);
|
||||||
|
ret += s->alpn_client_proto_list_len;
|
||||||
|
}
|
||||||
|
|
||||||
if(SSL_get_srtp_profiles(s))
|
if(SSL_get_srtp_profiles(s))
|
||||||
{
|
{
|
||||||
int el;
|
int el;
|
||||||
@ -1753,6 +1765,21 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (s->s3->alpn_selected)
|
||||||
|
{
|
||||||
|
const unsigned char *selected = s->s3->alpn_selected;
|
||||||
|
unsigned len = s->s3->alpn_selected_len;
|
||||||
|
|
||||||
|
if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
|
||||||
|
return NULL;
|
||||||
|
s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
|
||||||
|
s2n(3 + len,ret);
|
||||||
|
s2n(1 + len,ret);
|
||||||
|
*ret++ = len;
|
||||||
|
memcpy(ret, selected, len);
|
||||||
|
ret += len;
|
||||||
|
}
|
||||||
|
|
||||||
if ((extdatalen = ret-p-2)== 0)
|
if ((extdatalen = ret-p-2)== 0)
|
||||||
return p;
|
return p;
|
||||||
|
|
||||||
@ -1760,6 +1787,76 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a
|
||||||
|
* ClientHello.
|
||||||
|
* data: the contents of the extension, not including the type and length.
|
||||||
|
* data_len: the number of bytes in |data|
|
||||||
|
* al: a pointer to the alert value to send in the event of a non-zero
|
||||||
|
* return.
|
||||||
|
*
|
||||||
|
* returns: 0 on success. */
|
||||||
|
static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data,
|
||||||
|
unsigned data_len, int *al)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
unsigned proto_len;
|
||||||
|
const unsigned char *selected;
|
||||||
|
unsigned char selected_len;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (s->ctx->alpn_select_cb == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (data_len < 2)
|
||||||
|
goto parse_error;
|
||||||
|
|
||||||
|
/* data should contain a uint16 length followed by a series of 8-bit,
|
||||||
|
* length-prefixed strings. */
|
||||||
|
i = ((unsigned) data[0]) << 8 |
|
||||||
|
((unsigned) data[1]);
|
||||||
|
data_len -= 2;
|
||||||
|
data += 2;
|
||||||
|
if (data_len != i)
|
||||||
|
goto parse_error;
|
||||||
|
|
||||||
|
if (data_len < 2)
|
||||||
|
goto parse_error;
|
||||||
|
|
||||||
|
for (i = 0; i < data_len;)
|
||||||
|
{
|
||||||
|
proto_len = data[i];
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (proto_len == 0)
|
||||||
|
goto parse_error;
|
||||||
|
|
||||||
|
if (i + proto_len < i || i + proto_len > data_len)
|
||||||
|
goto parse_error;
|
||||||
|
|
||||||
|
i += proto_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = s->ctx->alpn_select_cb(s, &selected, &selected_len, data, data_len,
|
||||||
|
s->ctx->alpn_select_cb_arg);
|
||||||
|
if (r == SSL_TLSEXT_ERR_OK) {
|
||||||
|
if (s->s3->alpn_selected)
|
||||||
|
OPENSSL_free(s->s3->alpn_selected);
|
||||||
|
s->s3->alpn_selected = OPENSSL_malloc(selected_len);
|
||||||
|
if (!s->s3->alpn_selected)
|
||||||
|
{
|
||||||
|
*al = SSL_AD_INTERNAL_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memcpy(s->s3->alpn_selected, selected, selected_len);
|
||||||
|
s->s3->alpn_selected_len = selected_len;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
parse_error:
|
||||||
|
*al = SSL_AD_DECODE_ERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
|
static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n, int *al)
|
||||||
{
|
{
|
||||||
unsigned short type;
|
unsigned short type;
|
||||||
@ -1775,6 +1872,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
|
|||||||
s->s3->next_proto_neg_seen = 0;
|
s->s3->next_proto_neg_seen = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (s->s3->alpn_selected)
|
||||||
|
{
|
||||||
|
OPENSSL_free(s->s3->alpn_selected);
|
||||||
|
s->s3->alpn_selected = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_HEARTBEATS
|
#ifndef OPENSSL_NO_HEARTBEATS
|
||||||
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
|
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
|
||||||
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
|
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
|
||||||
@ -2233,7 +2336,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
|
|||||||
#endif
|
#endif
|
||||||
#ifndef OPENSSL_NO_NEXTPROTONEG
|
#ifndef OPENSSL_NO_NEXTPROTONEG
|
||||||
else if (type == TLSEXT_TYPE_next_proto_neg &&
|
else if (type == TLSEXT_TYPE_next_proto_neg &&
|
||||||
s->s3->tmp.finish_md_len == 0)
|
s->s3->tmp.finish_md_len == 0 &&
|
||||||
|
s->s3->alpn_selected == NULL)
|
||||||
{
|
{
|
||||||
/* We shouldn't accept this extension on a
|
/* We shouldn't accept this extension on a
|
||||||
* renegotiation.
|
* renegotiation.
|
||||||
@ -2254,6 +2358,16 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
|
||||||
|
s->ctx->alpn_select_cb &&
|
||||||
|
s->s3->tmp.finish_md_len == 0)
|
||||||
|
{
|
||||||
|
if (tls1_alpn_handle_client_hello(s, data, size, al) != 0)
|
||||||
|
return 0;
|
||||||
|
/* ALPN takes precedence over NPN. */
|
||||||
|
s->s3->next_proto_neg_seen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* session ticket processed earlier */
|
/* session ticket processed earlier */
|
||||||
else if (type == TLSEXT_TYPE_use_srtp)
|
else if (type == TLSEXT_TYPE_use_srtp)
|
||||||
{
|
{
|
||||||
@ -2443,6 +2557,12 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
|
|||||||
s->s3->next_proto_neg_seen = 0;
|
s->s3->next_proto_neg_seen = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (s->s3->alpn_selected)
|
||||||
|
{
|
||||||
|
OPENSSL_free(s->s3->alpn_selected);
|
||||||
|
s->s3->alpn_selected = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef OPENSSL_NO_HEARTBEATS
|
#ifndef OPENSSL_NO_HEARTBEATS
|
||||||
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
|
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
|
||||||
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
|
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
|
||||||
@ -2608,6 +2728,52 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
|
|||||||
s->s3->next_proto_neg_seen = 1;
|
s->s3->next_proto_neg_seen = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation)
|
||||||
|
{
|
||||||
|
unsigned len;
|
||||||
|
|
||||||
|
/* We must have requested it. */
|
||||||
|
if (s->alpn_client_proto_list == NULL)
|
||||||
|
{
|
||||||
|
*al = TLS1_AD_UNSUPPORTED_EXTENSION;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (size < 4)
|
||||||
|
{
|
||||||
|
*al = TLS1_AD_DECODE_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* The extension data consists of:
|
||||||
|
* uint16 list_length
|
||||||
|
* uint8 proto_length;
|
||||||
|
* uint8 proto[proto_length]; */
|
||||||
|
len = data[0];
|
||||||
|
len <<= 8;
|
||||||
|
len |= data[1];
|
||||||
|
if (len != (unsigned) size - 2)
|
||||||
|
{
|
||||||
|
*al = TLS1_AD_DECODE_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
len = data[2];
|
||||||
|
if (len != (unsigned) size - 3)
|
||||||
|
{
|
||||||
|
*al = TLS1_AD_DECODE_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (s->s3->alpn_selected)
|
||||||
|
OPENSSL_free(s->s3->alpn_selected);
|
||||||
|
s->s3->alpn_selected = OPENSSL_malloc(len);
|
||||||
|
if (!s->s3->alpn_selected)
|
||||||
|
{
|
||||||
|
*al = TLS1_AD_INTERNAL_ERROR;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(s->s3->alpn_selected, data + 3, len);
|
||||||
|
s->s3->alpn_selected_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
else if (type == TLSEXT_TYPE_renegotiate)
|
else if (type == TLSEXT_TYPE_renegotiate)
|
||||||
{
|
{
|
||||||
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
|
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
|
||||||
|
@ -230,6 +230,9 @@ extern "C" {
|
|||||||
/* ExtensionType value from RFC5620 */
|
/* ExtensionType value from RFC5620 */
|
||||||
#define TLSEXT_TYPE_heartbeat 15
|
#define TLSEXT_TYPE_heartbeat 15
|
||||||
|
|
||||||
|
/* ExtensionType value from draft-ietf-tls-applayerprotoneg-00 */
|
||||||
|
#define TLSEXT_TYPE_application_layer_protocol_negotiation 16
|
||||||
|
|
||||||
/* ExtensionType value from RFC4507 */
|
/* ExtensionType value from RFC4507 */
|
||||||
#define TLSEXT_TYPE_session_ticket 35
|
#define TLSEXT_TYPE_session_ticket 35
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user