Add tests for ALPN functionality.
Conflicts: ssl/ssltest.c
This commit is contained in:
parent
a108f841ba
commit
a898936218
@ -1329,6 +1329,7 @@ bad:
|
||||
goto end;
|
||||
}
|
||||
SSL_CTX_set_alpn_protos(ctx, alpn, alpn_len);
|
||||
OPENSSL_free(alpn);
|
||||
}
|
||||
#endif
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
|
161
ssl/ssltest.c
161
ssl/ssltest.c
@ -370,6 +370,127 @@ static int verify_npn(SSL *client, SSL *server)
|
||||
}
|
||||
#endif
|
||||
|
||||
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
|
||||
@ -689,6 +810,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)
|
||||
@ -1118,6 +1242,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);
|
||||
@ -1487,6 +1626,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);
|
||||
|
||||
@ -1949,6 +2105,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)
|
||||
{
|
||||
|
12
test/testssl
12
test/testssl
@ -195,6 +195,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
|
||||
|
Loading…
x
Reference in New Issue
Block a user