diff --git a/src/ssl.c b/src/ssl.c index 1f7976a30..64bddbea0 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -30233,6 +30233,20 @@ int wolfSSL_select_next_proto(unsigned char **out, unsigned char *outLen, return OPENSSL_NPN_NO_OVERLAP; } +void wolfSSL_set_alpn_select_cb(WOLFSSL *ssl, + int (*cb) (WOLFSSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg) +{ + if (ssl != NULL) { + ssl->alpnSelect = cb; + ssl->alpnSelectArg = arg; + } +} + void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, int (*cb) (WOLFSSL *ssl, const unsigned char **out, diff --git a/tests/api.c b/tests/api.c index 939924444..7d719548e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -10670,6 +10670,60 @@ static void verify_ALPN_client_list(WOLFSSL* ssl) AssertIntEQ(WOLFSSL_SUCCESS, wolfSSL_ALPN_FreePeerProtocol(ssl, &clist)); } +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) + +/* ALPN select callback, success with spdy/2 */ +static int select_ALPN_spdy2(WOLFSSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) +{ + /* spdy/2 */ + const char proto[] = {0x73, 0x70, 0x64, 0x79, 0x2f, 0x32}; + + (void)ssl; + (void)arg; + + /* adding +1 since LEN byte comes first */ + if (inlen < sizeof(proto) + 1) { + return SSL_TLSEXT_ERR_ALERT_FATAL; + } + + if (XMEMCMP(in + 1, proto, sizeof(proto)) == 0) { + *out = in + 1; + *outlen = (unsigned char)sizeof(proto); + return SSL_TLSEXT_ERR_OK; + } + + return SSL_TLSEXT_ERR_ALERT_FATAL; +} + +/* ALPN select callback, force failure */ +static int select_ALPN_failure(WOLFSSL *ssl, const unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg) +{ + (void)ssl; + (void)out; + (void)outlen; + (void)in; + (void)inlen; + (void)arg; + + return SSL_TLSEXT_ERR_ALERT_FATAL; +} + +static void use_ALPN_spdy2_callback(WOLFSSL* ssl) +{ + wolfSSL_set_alpn_select_cb(ssl, select_ALPN_spdy2, NULL); +} + +static void use_ALPN_failure_callback(WOLFSSL* ssl) +{ + wolfSSL_set_alpn_select_cb(ssl, select_ALPN_failure, NULL); +} +#endif /* OPENSSL_ALL | NGINX | HAPROXY | LIGHTY | QUIC */ + static int test_wolfSSL_UseALPN_connection(void) { int res = TEST_SKIPPED; @@ -10725,6 +10779,30 @@ static int test_wolfSSL_UseALPN_connection(void) server_cb.ctx_ready = NULL; server_cb.ssl_ready = use_ALPN_unknown; server_cb.on_result = verify_ALPN_FATAL_ERROR_on_client; test_wolfSSL_client_server(&client_cb, &server_cb); +#if defined(OPENSSL_ALL) || defined(WOLFSSL_NGINX) || \ + defined(WOLFSSL_HAPROXY) || defined(HAVE_LIGHTY) + + /* WOLFSSL-level ALPN select callback tests */ + /* Callback: success (one protocol, spdy/2) */ + client_cb.ctx_ready = NULL; + client_cb.ssl_ready = use_ALPN_one; + client_cb.on_result = verify_ALPN_matching_spdy2; + server_cb.ctx_ready = NULL; + server_cb.ssl_ready = use_ALPN_spdy2_callback; + server_cb.on_result = verify_ALPN_matching_spdy2; + test_wolfSSL_client_server(&client_cb, &server_cb); + + /* Callback: failure (one client protocol, spdy/2) */ + client_cb.ctx_ready = NULL; + client_cb.ssl_ready = use_ALPN_one; + client_cb.on_result = NULL; + server_cb.ctx_ready = NULL; + server_cb.ssl_ready = use_ALPN_failure_callback; + server_cb.on_result = verify_ALPN_FATAL_ERROR_on_client; + test_wolfSSL_client_server(&client_cb, &server_cb); + +#endif /* OPENSSL_ALL | NGINX | HAPROXY | LIGHTY */ + res = TEST_RES_CHECK(1); #endif /* !NO_WOLFSSL_CLIENT && !NO_WOLFSSL_SERVER */ return res; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index c78d6b6f7..097ea1bcb 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -5025,6 +5025,13 @@ WOLFSSL_API int wolfSSL_select_next_proto(unsigned char **out, const unsigned char *in, unsigned int inlen, const unsigned char *client, unsigned int client_len); +WOLFSSL_API void wolfSSL_set_alpn_select_cb(WOLFSSL *ssl, + int (*cb) (WOLFSSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), void *arg); WOLFSSL_API void wolfSSL_CTX_set_alpn_select_cb(WOLFSSL_CTX *ctx, int (*cb) (WOLFSSL *ssl, const unsigned char **out,