]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Added SSL_CTX_get0_alpn_protos() and SSL_get0_alpn_protos()
authorDaniel Kubec <kubec@openssl.org>
Thu, 15 Jan 2026 14:18:31 +0000 (14:18 +0000)
committerTomas Mraz <tomas@openssl.org>
Mon, 26 Jan 2026 15:26:14 +0000 (16:26 +0100)
Fixes #4952

Co-authored-by: Pauli <ppzgs1@gmail.com>
Co-authored-by: Tomáš Mráz <tm@t8m.info>
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
MergeDate: Mon Jan 26 15:26:21 2026
(Merged from https://github.com/openssl/openssl/pull/29646)

CHANGES.md
doc/man3/SSL_CTX_set_alpn_select_cb.pod
include/openssl/ssl.h.in
ssl/ssl_lib.c
test/sslapitest.c
util/libssl.num

index fbf06a10294d415b79360303bddade3a4cac3b0e..c2193abbd328f753ec212d4e3c2b56438a574203 100644 (file)
@@ -127,6 +127,10 @@ OpenSSL 4.0
 
    *Igor Ustinov*
 
+ * Added SSL_CTX_get0_alpn_protos() and SSL_get0_alpn_protos().
+
+   *Daniel Kubec*
+
  * Enabled Server verification by default in `s_server` when option
    verify_return_error is enabled.
 
index dd5517df4d32227b4e1c68289f5400fd7d3d4f6d..b97ebd1a5aafd52848932252cfcc5e3b6b8770b6 100644 (file)
@@ -2,7 +2,8 @@
 
 =head1 NAME
 
-SSL_CTX_set_alpn_protos, SSL_set_alpn_protos, SSL_CTX_set_alpn_select_cb,
+SSL_CTX_set_alpn_protos, SSL_set_alpn_protos, SSL_CTX_get0_alpn_protos,
+SSL_get0_alpn_protos, SSL_CTX_set_alpn_select_cb,
 SSL_CTX_set_next_proto_select_cb, SSL_CTX_set_next_protos_advertised_cb,
 SSL_select_next_proto, SSL_get0_alpn_selected, SSL_get0_next_proto_negotiated
 - handle application layer protocol negotiation (ALPN)
@@ -47,6 +48,11 @@ SSL_select_next_proto, SSL_get0_alpn_selected, SSL_get0_next_proto_negotiated
  void SSL_get0_next_proto_negotiated(const SSL *s, const unsigned char **data,
                              unsigned *len);
 
+ void SSL_CTX_get0_alpn_protos(SSL_CTX *ctx, const unsigned char **protos,
+    unsigned int *protos_len);
+ void SSL_get0_alpn_protos(SSL *ssl, const unsigned char **protos,
+    unsigned int *protos_len);
+
 =head1 DESCRIPTION
 
 SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() are used by the client to
@@ -55,6 +61,12 @@ protocol-list format, described below. The length of B<protos> is specified in
 B<protos_len>. Setting B<protos_len> to 0 clears any existing list of ALPN
 protocols and no ALPN extension will be sent to the server.
 
+SSL_CTX_get0_alpn_protos() and SSL_get0_alpn_protos() are used by the client to
+get the list of protocols available to be negotiated. The B<protos> are in
+protocol-list format, described below. Returns a pointer to protocol list in
+B<protos> with length B<protos_len>. It is not NUL-terminated. B<protos> must
+not be freed.
+
 SSL_CTX_set_alpn_select_cb() sets the application callback B<cb> used by a
 server to select which protocol to use for the incoming connection. When B<cb>
 is NULL, ALPN is not used. The B<arg> value is a pointer which is passed to
index 83d72e6fa8c1863770f3bc17a403f0ec4c527ead..529c2b71daad256aaae6252dcb685dd37ad3c3d7 100644 (file)
@@ -825,6 +825,10 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx,
     void *arg);
 void SSL_get0_alpn_selected(const SSL *ssl, const unsigned char **data,
     unsigned int *len);
+void SSL_CTX_get0_alpn_protos(SSL_CTX *ctx, const unsigned char **protos,
+    unsigned int *protos_len);
+void SSL_get0_alpn_protos(SSL *ssl, const unsigned char **protos,
+    unsigned int *protos_len);
 
 #ifndef OPENSSL_NO_PSK
 /*
index 43ca1e46d732e7de6d954ae68cd7bb3e18d6069e..9efda38100d8c6f8f53deb86f1c56f7f74cca85f 100644 (file)
@@ -3778,6 +3778,47 @@ int SSL_set_alpn_protos(SSL *ssl, const unsigned char *protos,
     return 0;
 }
 
+/*
+ * SSL_CTX_set_get0_protos gets the ALPN protocol list on |ctx| to |protos|.
+ */
+void SSL_CTX_get0_alpn_protos(SSL_CTX *ctx, const unsigned char **protos,
+    unsigned int *protos_len)
+{
+    unsigned char *p = NULL;
+    unsigned int len = 0;
+
+    if (ctx != NULL) {
+        p = ctx->ext.alpn;
+        len = (unsigned int)ctx->ext.alpn_len;
+    }
+
+    if (protos != NULL)
+        *protos = p;
+    if (protos_len != NULL)
+        *protos_len = len;
+}
+
+/*
+ * SSL_get0_alpn_protos gets the ALPN protocol list on |ssl| to |protos|.
+ */
+void SSL_get0_alpn_protos(SSL *ssl, const unsigned char **protos,
+    unsigned int *protos_len)
+{
+    SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(ssl);
+    unsigned char *p = NULL;
+    unsigned int len = 0;
+
+    if (sc != NULL) {
+        p = sc->ext.alpn;
+        len = (unsigned int)sc->ext.alpn_len;
+    }
+
+    if (protos != NULL)
+        *protos = p;
+    if (protos_len != NULL)
+        *protos_len = len;
+}
+
 /*
  * 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
index 1fb0477a8c54fc345976096f5fbcb2461d216417..07a101313c87d5d2a9e913e988955d9ea01f363c 100644 (file)
@@ -11623,6 +11623,57 @@ end:
     return testresult;
 }
 
+static int test_get_alpn(void)
+{
+    SSL_CTX *ctx = NULL;
+    SSL *ssl = NULL;
+    int testresult = 0;
+    unsigned char good[] = { 0x04, 'g', 'o', 'o', 'd' };
+    const unsigned char *expect;
+    unsigned int expect_len;
+
+    /* Create an initial SSL_CTX with no certificate configured */
+    ctx = SSL_CTX_new_ex(libctx, NULL, TLS_server_method());
+    if (!TEST_ptr(ctx))
+        goto end;
+
+    SSL_CTX_get0_alpn_protos(NULL, &expect, &expect_len);
+    if (!TEST_ptr_null(expect))
+        goto end;
+    if (!TEST_int_eq(expect_len, 0))
+        goto end;
+    if (!TEST_false(SSL_CTX_set_alpn_protos(ctx, good, sizeof(good))))
+        goto end;
+
+    SSL_CTX_get0_alpn_protos(ctx, &expect, &expect_len);
+    if (!TEST_mem_eq(expect, expect_len, good, sizeof(good)))
+        goto end;
+
+    ssl = SSL_new(ctx);
+    if (!TEST_ptr(ssl))
+        goto end;
+
+    SSL_get0_alpn_protos(NULL, &expect, &expect_len);
+    if (!TEST_ptr_null(expect))
+        goto end;
+    if (!TEST_int_eq(expect_len, 0))
+        goto end;
+
+    if (!TEST_false(SSL_set_alpn_protos(ssl, good, sizeof(good))))
+        goto end;
+
+    SSL_get0_alpn_protos(ssl, &expect, &expect_len);
+    if (!TEST_mem_eq(expect, expect_len, good, sizeof(good)))
+        goto end;
+
+    testresult = 1;
+
+end:
+    SSL_free(ssl);
+    SSL_CTX_free(ctx);
+    return testresult;
+}
+
 #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLS1_2)
 /*
  * Complete a connection with legacy EC point format configuration
@@ -14154,6 +14205,7 @@ int setup_tests(void)
 #endif
     ADD_TEST(test_inherit_verify_param);
     ADD_TEST(test_set_alpn);
+    ADD_TEST(test_get_alpn);
 #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_TLS1_2)
     ADD_TEST(test_legacy_ec_point_formats);
 #endif
index f8ca36f67dfdec3035ce57b244fed52e7520e591..86083e5133511ccb35877f9030a0d14c777788c0 100644 (file)
@@ -54,6 +54,8 @@ SSL_get0_next_proto_negotiated          ?     4_0_0   EXIST::FUNCTION:NEXTPROTONEG
 SSL_select_next_proto                   ?      4_0_0   EXIST::FUNCTION:
 SSL_CTX_set_alpn_protos                 ?      4_0_0   EXIST::FUNCTION:
 SSL_set_alpn_protos                     ?      4_0_0   EXIST::FUNCTION:
+SSL_CTX_get0_alpn_protos                ?      4_0_0   EXIST::FUNCTION:
+SSL_get0_alpn_protos                    ?      4_0_0   EXIST::FUNCTION:
 SSL_CTX_set_alpn_select_cb              ?      4_0_0   EXIST::FUNCTION:
 SSL_get0_alpn_selected                  ?      4_0_0   EXIST::FUNCTION:
 SSL_CTX_set_psk_client_callback         ?      4_0_0   EXIST::FUNCTION:PSK