ell.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
From: Marcel Holtmann <marcel@holtmann.org>
To: ell@lists.linux.dev
Cc: andrew.zaborowski@intel.com
Subject: [PATCH 3/3] tls: Add support l_tls_set_alpn_list() and ALPN extension
Date: Tue,  3 Jan 2023 23:02:50 +0100	[thread overview]
Message-ID: <20230103220250.717876-3-marcel@holtmann.org> (raw)

Add support for application layer protocol negotiation (ALPN) and
provide API for setting the list of client protocols and for getting the
server selected protocol.
---
 ell/ell.sym          |  2 ++
 ell/tls-extensions.c | 73 ++++++++++++++++++++++++++++++++++++++++++++
 ell/tls-private.h    |  2 ++
 ell/tls.c            | 21 +++++++++++++
 ell/tls.h            |  3 ++
 5 files changed, 101 insertions(+)

diff --git a/ell/ell.sym b/ell/ell.sym
index f8148f257eb1..81c0cb7f5b94 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -515,6 +515,8 @@ global:
 	l_tls_close;
 	l_tls_reset;
 	l_tls_set_server_name;
+	l_tls_set_alpn_list;
+	l_tls_get_alpn;
 	l_tls_set_cacert;
 	l_tls_set_auth_data;
 	l_tls_set_version_range;
diff --git a/ell/tls-extensions.c b/ell/tls-extensions.c
index 75f47f6ba548..e5a7c7994b7d 100644
--- a/ell/tls-extensions.c
+++ b/ell/tls-extensions.c
@@ -52,6 +52,70 @@ static ssize_t tls_server_name_client_write(struct l_tls *tls,
 	return hlen + 5;
 }
 
+static ssize_t tls_alpn_client_write(struct l_tls *tls,
+						uint8_t *buf, size_t len)
+{
+	uint8_t *ptr = buf + 2;
+	uint16_t ext_len = 0;
+	int i;
+
+	if (!tls->alpn_list)
+		return -ENOMSG;
+
+	if (len < 2)
+		return -ENOMEM;
+
+	for (i = 0; tls->alpn_list[i]; i++) {
+		uint8_t str_len = strlen(tls->alpn_list[i]);
+		l_put_u8(str_len, ptr);
+		memcpy(ptr + 1, tls->alpn_list[i], str_len);
+		ptr += str_len + 1;
+		ext_len += str_len + 1;
+	}
+
+	l_put_be16(ext_len, buf);
+
+	return ext_len + 2;
+}
+
+static bool tls_alpn_server_handle(struct l_tls *tls,
+						const uint8_t *buf, size_t len)
+{
+	uint16_t ext_len;
+	uint8_t str_len;
+
+	if (len < 2)
+		return false;
+
+	ext_len = l_get_be16(buf);
+	if (ext_len != len - 2)
+		return false;
+
+	str_len = l_get_u8(buf + 2);
+	if (str_len != len - 3)
+		return false;
+
+	l_free(tls->selected_alpn);
+	tls->selected_alpn = l_strndup((const char *) buf + 3, str_len);
+
+	TLS_DEBUG("Negotiated ALPN %s", tls->selected_alpn);
+
+	return true;
+}
+
+static bool tls_alpn_server_absent(struct l_tls *tls)
+{
+	if (!tls->alpn_list)
+		return false;
+
+	l_free(tls->selected_alpn);
+	tls->selected_alpn = NULL;
+
+	TLS_DEBUG("ALPN not supported");
+
+	return true;
+}
+
 /* Most extensions are not used when resuming a cached session */
 #define SKIP_ON_RESUMPTION()	\
 	do {	\
@@ -1025,6 +1089,15 @@ const struct tls_hello_extension tls_extensions[] = {
 		tls_signature_algorithms_client_absent,
 		NULL, NULL, NULL,
 	},
+	{
+		"ALPN", "application_layer_protocol_negotiation", 16,
+		tls_alpn_client_write,
+		NULL,
+		NULL,
+		NULL,
+		tls_alpn_server_handle,
+		tls_alpn_server_absent,
+	},
 	{
 		"Secure Renegotiation", "renegotiation_info", 0xff01,
 		tls_renegotiation_info_client_write,
diff --git a/ell/tls-private.h b/ell/tls-private.h
index ac477885c5f7..dbc5457ef091 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -218,6 +218,8 @@ struct l_tls {
 
 	struct tls_cipher_suite **cipher_suite_pref_list;
 	char *server_name;
+	char **alpn_list;
+	char *selected_alpn;
 
 	struct l_settings *session_settings;
 	char *session_prefix;
diff --git a/ell/tls.c b/ell/tls.c
index 9556efd932bc..8c1c9040ff89 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -3421,6 +3421,8 @@ LIB_EXPORT void l_tls_free(struct l_tls *tls)
 		l_free(tls->cipher_suite_pref_list);
 
 	l_free(tls->server_name);
+	l_strv_free(tls->alpn_list);
+	l_free(tls->selected_alpn);
 	l_free(tls);
 }
 
@@ -3668,6 +3670,25 @@ LIB_EXPORT bool l_tls_set_server_name(struct l_tls *tls, const char *name)
 	return true;
 }
 
+LIB_EXPORT bool l_tls_set_alpn_list(struct l_tls *tls, const char **list)
+{
+	if (!tls)
+		return false;
+
+	l_strv_free(tls->alpn_list);
+	tls->alpn_list = l_strv_copy((char **) list);
+
+	return true;
+}
+
+LIB_EXPORT const char *l_tls_get_alpn(struct l_tls *tls)
+{
+	if (!tls)
+		return NULL;
+
+	return tls->selected_alpn;
+}
+
 LIB_EXPORT bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs)
 {
 	if (tls->ca_certs) {
diff --git a/ell/tls.h b/ell/tls.h
index c931b5db0a54..e33f7c070008 100644
--- a/ell/tls.h
+++ b/ell/tls.h
@@ -105,6 +105,9 @@ void l_tls_handle_rx(struct l_tls *tls, const uint8_t *data, size_t len);
 
 bool l_tls_set_server_name(struct l_tls *tls, const char *name);
 
+bool l_tls_set_alpn_list(struct l_tls *tls, const char **list);
+const char *l_tls_get_alpn(struct l_tls *tls);
+
 /*
  * If peer is to be authenticated, supply the CA certificates.  On success
  * the l_tls object takes ownership of the queue and the individual l_cert
-- 
2.39.0


             reply	other threads:[~2023-01-03 22:02 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-03 22:02 Marcel Holtmann [this message]
2023-01-04 21:08 ` [PATCH 3/3] tls: Add support l_tls_set_alpn_list() and ALPN extension Andrew Zaborowski
2023-01-05 15:15   ` Marcel Holtmann
2023-01-09 12:21     ` Andrew Zaborowski

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230103220250.717876-3-marcel@holtmann.org \
    --to=marcel@holtmann.org \
    --cc=andrew.zaborowski@intel.com \
    --cc=ell@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).