Merge remote-tracking branch 'agl/1.0.2alpn' into agl-alpn

Conflicts:
	ssl/ssl3.h
	ssl/t1_lib.c
This commit is contained in:
Ben Laurie 2013-10-01 12:20:02 +01:00
commit 63fe322160
10 changed files with 604 additions and 9 deletions

View file

@ -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");
# 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");
@ -641,6 +642,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];
@ -999,6 +1001,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)
{
@ -1312,9 +1319,24 @@ 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);
OPENSSL_free(alpn);
}
#endif
#ifndef OPENSSL_NO_TLSEXT
if (serverinfo_types_count)
@ -2273,7 +2295,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;
@ -2282,6 +2305,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
{

View file

@ -579,6 +579,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");
@ -934,8 +935,47 @@ static int next_proto_cb(SSL *s, const unsigned char **data, unsigned int *len,
}
# 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 **);
@ -984,7 +1024,9 @@ int 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};
const char *alpn_in = NULL;
tlsextalpnctx alpn_ctx = { NULL, 0};
# endif
#endif
#ifndef OPENSSL_NO_PSK
@ -1435,6 +1477,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)
@ -1562,7 +1609,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;
@ -1575,6 +1623,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 +1870,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
@ -2041,6 +2101,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)

View file

@ -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
@ -3101,6 +3106,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;

View file

@ -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;
# ifndef OPENSSL_NO_EC
@ -1198,6 +1223,21 @@ void SSL_get0_next_proto_negotiated(const SSL *s,
#define OPENSSL_NPN_NO_OVERLAP 2
#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 */
@ -1504,6 +1544,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 */

View file

@ -590,7 +590,16 @@ typedef struct ssl3_state_st
char is_probably_safari;
#endif /* !OPENSSL_NO_EC */
#endif /* !OPENSSL_NO_TLSEXT */
/* 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

View file

@ -381,6 +381,17 @@ SSL *SSL_new(SSL_CTX *ctx)
# ifndef OPENSSL_NO_NEXTPROTONEG
s->next_proto_negotiated = NULL;
# 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
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);
if (s->tlsext_ocsp_resp)
OPENSSL_free(s->tlsext_ocsp_resp);
if (s->alpn_client_proto_list)
OPENSSL_free(s->alpn_client_proto_list);
#endif
if (s->client_CA != NULL)
@ -1768,7 +1781,78 @@ int SSL_CTX_set_custom_srv_ext(SSL_CTX *ctx, unsigned short ext_type,
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,
const char *label, size_t llen, const unsigned char *p, size_t plen,
@ -2131,6 +2215,8 @@ void SSL_CTX_free(SSL_CTX *a)
if (a->tlsext_ellipticcurvelist)
OPENSSL_free(a->tlsext_ellipticcurvelist);
# endif /* OPENSSL_NO_EC */
if (a->alpn_client_proto_list != NULL)
OPENSSL_free(a->alpn_client_proto_list);
#endif
OPENSSL_free(a);

View file

@ -295,6 +295,127 @@ static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg)
static BIO *bio_err=NULL;
static BIO *bio_stdout=NULL;
static const char *alpn_client;
static const char *alpn_server;
static const char *alpn_expected;
static unsigned char *alpn_selected;
/* next_protos_parse parses a comma separated list of strings into a string
* in a format suitable for passing to SSL_CTX_set_next_protos_advertised.
* outlen: (output) set to the length of the resulting buffer on success.
* err: (maybe NULL) on failure, an error message line is written to this BIO.
* in: a NUL termianted string like "abc,def,ghi"
*
* returns: a malloced buffer or NULL on failure.
*/
static unsigned char *next_protos_parse(unsigned short *outlen, const char *in)
{
size_t len;
unsigned char *out;
size_t i, start = 0;
len = strlen(in);
if (len >= 65535)
return NULL;
out = OPENSSL_malloc(strlen(in) + 1);
if (!out)
return NULL;
for (i = 0; i <= len; ++i)
{
if (i == len || in[i] == ',')
{
if (i - start > 255)
{
OPENSSL_free(out);
return NULL;
}
out[start] = i - start;
start = i + 1;
}
else
out[i+1] = in[i];
}
*outlen = len + 1;
return out;
}
static int cb_server_alpn(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
{
unsigned char *protos;
unsigned short protos_len;
protos = next_protos_parse(&protos_len, alpn_server);
if (protos == NULL)
{
fprintf(stderr, "failed to parser ALPN server protocol string: %s\n", alpn_server);
abort();
}
if (SSL_select_next_proto((unsigned char**) out, outlen, protos, protos_len, in, inlen) !=
OPENSSL_NPN_NEGOTIATED)
{
OPENSSL_free(protos);
return SSL_TLSEXT_ERR_NOACK;
}
/* Make a copy of the selected protocol which will be freed in verify_alpn. */
alpn_selected = OPENSSL_malloc(*outlen);
memcpy(alpn_selected, *out, *outlen);
*out = alpn_selected;
OPENSSL_free(protos);
return SSL_TLSEXT_ERR_OK;
}
static int verify_alpn(SSL *client, SSL *server)
{
const unsigned char *client_proto, *server_proto;
unsigned int client_proto_len = 0, server_proto_len = 0;
SSL_get0_alpn_selected(client, &client_proto, &client_proto_len);
SSL_get0_alpn_selected(server, &server_proto, &server_proto_len);
if (alpn_selected != NULL)
{
OPENSSL_free(alpn_selected);
alpn_selected = NULL;
}
if (client_proto_len != server_proto_len ||
memcmp(client_proto, server_proto, client_proto_len) != 0)
{
BIO_printf(bio_stdout, "ALPN selected protocols differ!\n");
goto err;
}
if (client_proto_len > 0 && alpn_expected == NULL)
{
BIO_printf(bio_stdout, "ALPN unexpectedly negotiated\n");
goto err;
}
if (alpn_expected != NULL &&
(client_proto_len != strlen(alpn_expected) ||
memcmp(client_proto, alpn_expected, client_proto_len) != 0))
{
BIO_printf(bio_stdout, "ALPN selected protocols not equal to expected protocol: %s\n", alpn_expected);
goto err;
}
return 0;
err:
BIO_printf(bio_stdout, "ALPN results: client: '");
BIO_write(bio_stdout, client_proto, client_proto_len);
BIO_printf(bio_stdout, "', server: '");
BIO_write(bio_stdout, server_proto, server_proto_len);
BIO_printf(bio_stdout, "'\n");
BIO_printf(bio_stdout, "ALPN configured: client: '%s', server: '%s'\n", alpn_client, alpn_server);
return -1;
}
#define SCT_EXT_TYPE 18
/* WARNING : below extension types are *NOT* IETF assigned, and
@ -614,6 +735,9 @@ static void sv_usage(void)
fprintf(stderr," -serverinfo_sct - have client offer and expect SCT\n");
fprintf(stderr," -serverinfo_tack - have client offer and expect TACK\n");
fprintf(stderr," -custom_ext - try various custom extension callbacks\n");
fprintf(stderr," -alpn_client <string> - have client side offer ALPN\n");
fprintf(stderr," -alpn_server <string> - have server side offer ALPN\n");
fprintf(stderr," -alpn_expected <string> - the ALPN protocol that should be negotiated\n");
}
static void print_details(SSL *c_ssl, const char *prefix)
@ -1102,6 +1226,21 @@ int main(int argc, char *argv[])
{
custom_ext = 1;
}
else if (strcmp(*argv,"-alpn_client") == 0)
{
if (--argc < 1) goto bad;
alpn_client = *(++argv);
}
else if (strcmp(*argv,"-alpn_server") == 0)
{
if (--argc < 1) goto bad;
alpn_server = *(++argv);
}
else if (strcmp(*argv,"-alpn_expected") == 0)
{
if (--argc < 1) goto bad;
alpn_expected = *(++argv);
}
else
{
fprintf(stderr,"unknown option %s\n",*argv);
@ -1488,6 +1627,23 @@ bad:
custom_ext_3_srv_second_cb, NULL);
}
if (alpn_server)
SSL_CTX_set_alpn_select_cb(s_ctx, cb_server_alpn, NULL);
if (alpn_client)
{
unsigned short alpn_len;
unsigned char *alpn = next_protos_parse(&alpn_len, alpn_client);
if (alpn == NULL)
{
BIO_printf(bio_err, "Error parsing -alpn_client argument\n");
goto end;
}
SSL_CTX_set_alpn_protos(c_ctx, alpn, alpn_len);
OPENSSL_free(alpn);
}
c_ssl=SSL_new(c_ctx);
s_ssl=SSL_new(s_ctx);
@ -1948,6 +2104,11 @@ int doit_biopair(SSL *s_ssl, SSL *c_ssl, long count,
ret = 1;
goto err;
}
if (verify_alpn(c_ssl, s_ssl) < 0)
{
ret = 1;
goto err;
}
if (custom_ext_error)
{

View file

@ -1414,6 +1414,18 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha
}
#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))
{
int el;
@ -1795,6 +1807,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)
return p;
@ -1883,7 +1910,76 @@ static void ssl_check_for_safari(SSL *s, const unsigned char *data, const unsign
s->s3->is_probably_safari = 1;
}
#endif /* !OPENSSL_NO_EC */
/* 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)
{
@ -1908,6 +2004,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
s->s3->tlsext_custom_types = NULL;
}
if (s->s3->alpn_selected)
{
OPENSSL_free(s->s3->alpn_selected);
s->s3->alpn_selected = NULL;
}
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
@ -2369,7 +2471,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
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
* renegotiation.
@ -2390,6 +2493,16 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char
}
#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 */
else if (type == TLSEXT_TYPE_use_srtp)
{
@ -2579,6 +2692,12 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
s->s3->next_proto_neg_seen = 0;
#endif
if (s->s3->alpn_selected)
{
OPENSSL_free(s->s3->alpn_selected);
s->s3->alpn_selected = NULL;
}
#ifndef OPENSSL_NO_HEARTBEATS
s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
@ -2741,6 +2860,52 @@ static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char
s->s3->next_proto_neg_seen = 1;
}
#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)
{
if(!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))

View file

@ -230,6 +230,9 @@ extern "C" {
/* ExtensionType value from RFC5620 */
#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 */
#define TLSEXT_TYPE_session_ticket 35

View file

@ -184,6 +184,18 @@ $ssltest -bio_pair -tls1 -serverinfo_file $serverinfo -serverinfo_sct -serverinf
$ssltest -bio_pair -tls1 -custom_ext -serverinfo_file $serverinfo -serverinfo_sct -serverinfo_tack || exit 1
#############################################################################
# ALPN tests
$ssltest -bio_pair -tls1 -alpn_client foo -alpn_server bar || exit 1
$ssltest -bio_pair -tls1 -alpn_client foo -alpn_server foo -alpn_expected foo || exit 1
$ssltest -bio_pair -tls1 -alpn_client foo,bar -alpn_server foo -alpn_expected foo || exit 1
$ssltest -bio_pair -tls1 -alpn_client bar,foo -alpn_server foo -alpn_expected foo || exit 1
$ssltest -bio_pair -tls1 -alpn_client bar,foo -alpn_server foo,bar -alpn_expected foo || exit 1
$ssltest -bio_pair -tls1 -alpn_client bar,foo -alpn_server bar,foo -alpn_expected bar || exit 1
$ssltest -bio_pair -tls1 -alpn_client foo,bar -alpn_server bar,foo -alpn_expected bar || exit 1
$ssltest -bio_pair -tls1 -alpn_client baz -alpn_server bar,foo || exit 1
if ../util/shlib_wrap.sh ../apps/openssl no-srp; then
echo skipping SRP tests
else