diff --git a/src/internal.c b/src/internal.c index 46ecb217f..c5b99086f 100644 --- a/src/internal.c +++ b/src/internal.c @@ -6255,6 +6255,20 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup) ssl->alpnSelect = ctx->alpnSelect; ssl->alpnSelectArg = ctx->alpnSelectArg; #endif + #if !defined(NO_BIO) && defined(OPENSSL_EXTRA) + if (ctx->alpn_cli_protos != NULL && ctx->alpn_cli_protos_len > 0) { + ret = wolfSSL_set_alpn_protos(ssl, ctx->alpn_cli_protos, + ctx->alpn_cli_protos_len); + #if defined(WOLFSSL_ERROR_CODE_OPENSSL) + if (ret) { + #else + if (!ret) { + #endif + WOLFSSL_MSG("failed to set alpn protos to ssl object"); + return ret; + } + } + #endif #endif #ifdef HAVE_SUPPORTED_CURVES ssl->options.userCurves = ctx->userCurves; diff --git a/src/tls.c b/src/tls.c index d03540e01..dcbdf3562 100644 --- a/src/tls.c +++ b/src/tls.c @@ -1623,13 +1623,16 @@ static int TLSX_ALPN_ParseAndSet(WOLFSSL *ssl, const byte *input, word16 length, TLSX_APPLICATION_LAYER_PROTOCOL); #if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) - if (ssl->alpnSelect != NULL) { + if (ssl->alpnSelect != NULL && ssl->options.side == WOLFSSL_SERVER_END) { const byte* out; unsigned char outLen; if (ssl->alpnSelect(ssl, &out, &outLen, input + offset, size, ssl->alpnSelectArg) == 0) { WOLFSSL_MSG("ALPN protocol match"); + /* clears out all current ALPN extensions set */ + TLSX_Remove(&ssl->extensions, TLSX_APPLICATION_LAYER_PROTOCOL, ssl->heap); + if (TLSX_UseALPN(&ssl->extensions, (char*)out, outLen, 0, ssl->heap) == WOLFSSL_SUCCESS) { if (extension == NULL) { diff --git a/tests/api.c b/tests/api.c index 9ea681c65..60c4a4123 100644 --- a/tests/api.c +++ b/tests/api.c @@ -6449,6 +6449,102 @@ static void test_wolfSSL_UseALPN_params(void) } #endif /* HAVE_ALPN */ +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)) && \ + (defined(HAVE_ALPN) && defined(HAVE_SNI)) &&\ + defined(HAVE_IO_TESTS_DEPENDENCIES) + +static void CTX_set_alpn_protos(SSL_CTX *ctx) +{ + unsigned char p[] = { + 8, 'h', 't', 't', 'p', '/', '1', '.', '1', + 6, 's', 'p', 'd', 'y', '/', '2', + 6, 's', 'p', 'd', 'y', '/', '1', + }; + + unsigned char p_len = sizeof(p); + int ret; + + ret = SSL_CTX_set_alpn_protos(ctx, p, p_len); + +#ifdef WOLFSSL_ERROR_CODE_OPENSSL + AssertIntEQ(ret, 0); +#else + AssertIntEQ(ret, SSL_SUCCESS); +#endif + +} + +static void set_alpn_protos(SSL* ssl) +{ + unsigned char p[] = { + 6, 's', 'p', 'd', 'y', '/', '3', + 8, 'h', 't', 't', 'p', '/', '1', '.', '1', + 6, 's', 'p', 'd', 'y', '/', '2', + 6, 's', 'p', 'd', 'y', '/', '1', + }; + + unsigned char p_len = sizeof(p); + int ret; + + ret = SSL_set_alpn_protos(ssl, p, p_len); + +#ifdef WOLFSSL_ERROR_CODE_OPENSSL + AssertIntEQ(ret, 0); +#else + AssertIntEQ(ret, SSL_SUCCESS); +#endif + +} + +static void verify_alpn_matching_spdy3(WOLFSSL* ssl) +{ + /* "spdy/3" */ + char nego_proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x33}; + const unsigned char *proto; + unsigned int protoSz = 0; + + SSL_get0_alpn_selected(ssl, &proto, &protoSz); + + /* check value */ + AssertIntEQ(1, sizeof(nego_proto) == protoSz); + AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz)); +} + +static void verify_alpn_matching_http1(WOLFSSL* ssl) +{ + /* "http/1.1" */ + char nego_proto[] = {0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31}; + const unsigned char *proto; + unsigned int protoSz = 0; + + SSL_get0_alpn_selected(ssl, &proto, &protoSz); + + /* check value */ + AssertIntEQ(1, sizeof(nego_proto) == protoSz); + AssertIntEQ(0, XMEMCMP(nego_proto, proto, protoSz)); +} + +static void test_wolfSSL_set_alpn_protos() +{ + unsigned long i; + callback_functions callbacks[] = { + /* use CTX_alpn_protos */ + {0, CTX_set_alpn_protos, 0, 0, 0, 0}, + {0, CTX_set_alpn_protos, 0, verify_alpn_matching_http1, 0, 0}, + /* use set_alpn_protos */ + {0, 0, set_alpn_protos, 0, 0, 0}, + {0, 0, set_alpn_protos, verify_alpn_matching_spdy3, 0, 0}, + }; + + for (i = 0; i < sizeof(callbacks) / sizeof(callback_functions); i += 2) { + callbacks[i ].method = wolfSSLv23_client_method; + callbacks[i + 1].method = wolfSSLv23_server_method; + test_wolfSSL_client_server(&callbacks[i], &callbacks[i + 1]); + } +} +#endif + static void test_wolfSSL_UseALPN(void) { #if defined(HAVE_ALPN) && !defined(NO_WOLFSSL_SERVER) &&\ @@ -6456,6 +6552,18 @@ static void test_wolfSSL_UseALPN(void) test_wolfSSL_UseALPN_connection(); test_wolfSSL_UseALPN_params(); #endif + +#if !defined(NO_WOLFSSL_SERVER) && !defined(NO_BIO) + +#if (defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY)) && \ + (defined(HAVE_ALPN) && defined(HAVE_SNI)) && \ + defined(HAVE_IO_TESTS_DEPENDENCIES) + + test_wolfSSL_set_alpn_protos(); +#endif + +#endif } static void test_wolfSSL_DisableExtendedMasterSecret(void)