From d273f50ec2ad98288d496077c9e6989f46f526b3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20H=C3=A1k?= <jan.hak@nic.cz>
Date: Mon, 2 May 2022 13:31:47 +0200
Subject: [PATCH] utils: small change of common API for TLS in kdig and
 knsupdate

Move ALPN and settings in context initialization
---
 src/utils/common/https.c | 13 ++++----
 src/utils/common/https.h |  4 ++-
 src/utils/common/netio.c | 29 ++++++++++++------
 src/utils/common/tls.c   | 64 ++++++++++++++++++++++++----------------
 src/utils/common/tls.h   | 11 ++++---
 5 files changed, 75 insertions(+), 46 deletions(-)

diff --git a/src/utils/common/https.c b/src/utils/common/https.c
index bc7912bfea..e432b0524f 100644
--- a/src/utils/common/https.c
+++ b/src/utils/common/https.c
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -76,14 +76,15 @@ void https_params_clean(https_params_t *params)
 static const char default_path[] = "/dns-query";
 static const char default_query[] = "?dns=";
 
-static const gnutls_datum_t https_protocols[] = {
-	{ (unsigned char *)"h2", 2 }
-};
-
 static const nghttp2_settings_entry settings[] = {
 	{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, HTTPS_MAX_STREAMS }
 };
 
+const gnutls_datum_t doh_alpn = {
+	.data = (unsigned char *)"h2",
+	.size = 2
+};
+
 static bool https_status_is_redirect(unsigned long status)
 {
 	switch (status) {
@@ -326,7 +327,7 @@ int https_ctx_connect(https_ctx_t *ctx, int sockfd, const char *remote,
 	}
 
 	// Create TLS connection
-	int ret = tls_ctx_connect(ctx->tls, sockfd, remote, fastopen, addr, https_protocols);
+	int ret = tls_ctx_connect(ctx->tls, sockfd, remote, fastopen, addr);
 	if (ret != KNOT_EOK) {
 		return ret;
 	}
diff --git a/src/utils/common/https.h b/src/utils/common/https.h
index 1ab42642ab..6c54baee15 100644
--- a/src/utils/common/https.h
+++ b/src/utils/common/https.h
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -46,6 +46,8 @@ void https_params_clean(https_params_t *params);
 
 #include "utils/common/tls.h"
 
+extern const gnutls_datum_t doh_alpn;
+
 /*! \brief Structure that stores data source for DATA frames. */
 typedef struct {
 	const uint8_t *buf;
diff --git a/src/utils/common/netio.c b/src/utils/common/netio.c
index bd7ec1aea1..233b5d8d02 100644
--- a/src/utils/common/netio.c
+++ b/src/utils/common/netio.c
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -218,22 +218,33 @@ int net_init(const srv_info_t     *local,
 
 	// Prepare for TLS.
 	if (tls_params != NULL && tls_params->enable) {
-		int ret = tls_ctx_init(&net->tls, tls_params, net->wait);
-		if (ret != KNOT_EOK) {
-			net_clean(net);
-			return ret;
-		}
-
+		int ret = 0;
 #ifdef LIBNGHTTP2
 		// Prepare for HTTPS.
 		if (https_params != NULL && https_params->enable) {
+			ret = tls_ctx_init(&net->tls, tls_params,
+			                   GNUTLS_NONBLOCK, net->wait,
+			                   &doh_alpn, 1, NULL);
+			if (ret != KNOT_EOK) {
+				net_clean(net);
+				return ret;
+			}
 			ret = https_ctx_init(&net->https, &net->tls, https_params);
 			if (ret != KNOT_EOK) {
 				net_clean(net);
 				return ret;
 			}
-		}
+		} else
 #endif //LIBNGHTTP2
+		{
+			ret = tls_ctx_init(&net->tls, tls_params,
+			                   GNUTLS_NONBLOCK, net->wait,
+			                   &dot_alpn, 1, NULL);
+			if (ret != KNOT_EOK) {
+				net_clean(net);
+				return ret;
+			}
+		}
 	}
 
 	return KNOT_EOK;
@@ -392,7 +403,7 @@ int net_connect(net_t *net)
 #endif //LIBNGHTTP2
 				// Establish TLS connection.
 				ret = tls_ctx_connect(&net->tls, sockfd, net->tls.params->sni, fastopen,
-				                      (struct sockaddr_storage *)net->srv->ai_addr, &dot_alpn);
+				                      (struct sockaddr_storage *)net->srv->ai_addr);
 #ifdef LIBNGHTTP2
 			}
 #endif //LIBNGHTTP2
diff --git a/src/utils/common/tls.c b/src/utils/common/tls.c
index 5cbbb420ea..b792b0df4a 100644
--- a/src/utils/common/tls.c
+++ b/src/utils/common/tls.c
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -421,7 +421,10 @@ static int verify_certificate(gnutls_session_t session)
 	return GNUTLS_E_SUCCESS;
 }
 
-int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, int wait)
+int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params,
+        unsigned int flags, int wait, const gnutls_datum_t *alpn,
+        size_t alpn_size, const char *priority)
+
 {
 	if (ctx == NULL || params == NULL || !params->enable) {
 		return KNOT_EINVAL;
@@ -465,7 +468,7 @@ int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, int wait)
 		}
 	}
 
-	gnutls_certificate_set_verify_function(ctx->credentials, verify_certificate);
+	// gnutls_certificate_set_verify_function(ctx->credentials, verify_certificate);
 
 	// Setup client keypair if specified. Both key and cert files must be provided.
 	if (params->keyfile != NULL && params->certfile != NULL) {
@@ -494,34 +497,48 @@ int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, int wait)
 		return KNOT_ERROR;
 	}
 
-	return KNOT_EOK;
-}
-
-int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote, bool fastopen,
-                    struct sockaddr_storage *addr, const gnutls_datum_t *protocol)
-{
-	if (ctx == NULL) {
-		return KNOT_EINVAL;
+	ret = gnutls_init(&ctx->session, GNUTLS_CLIENT | flags);
+	if (ret != GNUTLS_E_SUCCESS) {
+		return KNOT_ENOMEM;
 	}
 
-	int ret = gnutls_init(&ctx->session, GNUTLS_CLIENT | GNUTLS_NONBLOCK);
-	if (ret != GNUTLS_E_SUCCESS) {
-		return KNOT_NET_ECONNECT;
+	if (alpn != NULL) {
+		ret = gnutls_alpn_set_protocols(ctx->session, alpn, alpn_size, 0);
+		if (ret != GNUTLS_E_SUCCESS) {
+			gnutls_deinit(ctx->session);
+			return KNOT_NET_ECONNECT;
+		}
 	}
 
-	ret = gnutls_set_default_priority(ctx->session);
+	if (priority != NULL) {
+		ret = gnutls_priority_set_direct(ctx->session, priority, NULL);
+	} else {
+		ret = gnutls_set_default_priority(ctx->session);
+	}
 	if (ret != GNUTLS_E_SUCCESS) {
 		gnutls_deinit(ctx->session);
-		return KNOT_NET_ECONNECT;
+		return KNOT_EINVAL;
 	}
 
 	ret = gnutls_credentials_set(ctx->session, GNUTLS_CRD_CERTIFICATE,
 	                             ctx->credentials);
 	if (ret != GNUTLS_E_SUCCESS) {
 		gnutls_deinit(ctx->session);
-		return KNOT_NET_ECONNECT;
+		return KNOT_ERROR;
+	}
+
+	return KNOT_EOK;
+}
+
+int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote, bool fastopen,
+                    struct sockaddr_storage *addr)
+{
+	if (ctx == NULL) {
+		return KNOT_EINVAL;
 	}
 
+	int ret = 0;
+	// TODO mayble also move to `tls_ctx_init`
 	if (remote != NULL) {
 		ret = gnutls_server_name_set(ctx->session, GNUTLS_NAME_DNS, remote,
 		                             strlen(remote));
@@ -547,14 +564,6 @@ int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote, bool fastope
 
 	gnutls_handshake_set_timeout(ctx->session, 1000 * ctx->wait);
 
-	if (protocol != NULL) {
-		ret = gnutls_alpn_set_protocols(ctx->session, protocol, 1, 0);
-		if (ret != GNUTLS_E_SUCCESS) {
-			gnutls_deinit(ctx->session);
-			return KNOT_NET_ECONNECT;
-		}
-	}
-
 	// Initialize poll descriptor structure.
 	struct pollfd pfd = {
 		.fd = sockfd,
@@ -688,7 +697,6 @@ void tls_ctx_close(tls_ctx_t *ctx)
 	}
 
 	gnutls_bye(ctx->session, GNUTLS_SHUT_RDWR);
-	gnutls_deinit(ctx->session);
 }
 
 void tls_ctx_deinit(tls_ctx_t *ctx)
@@ -701,6 +709,10 @@ void tls_ctx_deinit(tls_ctx_t *ctx)
 		gnutls_certificate_free_credentials(ctx->credentials);
 		ctx->credentials = NULL;
 	}
+	if (ctx->session != NULL) {
+		gnutls_deinit(ctx->session);
+		ctx->session = NULL;
+	}
 }
 
 void print_tls(const tls_ctx_t *ctx)
diff --git a/src/utils/common/tls.h b/src/utils/common/tls.h
index c6014f4988..ddf3d4f5e1 100644
--- a/src/utils/common/tls.h
+++ b/src/utils/common/tls.h
@@ -1,4 +1,4 @@
-/*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
 
     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -65,9 +65,12 @@ void tls_params_init(tls_params_t *params);
 int tls_params_copy(tls_params_t *dst, const tls_params_t *src);
 void tls_params_clean(tls_params_t *params);
 
-int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params, int wait);
-int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote, bool fastopen,
-                    struct sockaddr_storage *addr, const gnutls_datum_t *protocol);
+int tls_ctx_init(tls_ctx_t *ctx, const tls_params_t *params,
+        unsigned int flags, int wait, const gnutls_datum_t *alpn,
+        size_t alpn_size, const char *priority);
+int tls_ctx_connect(tls_ctx_t *ctx, int sockfd, const char *remote,
+        bool fastopen, struct sockaddr_storage *addr);
+
 int tls_ctx_send(tls_ctx_t *ctx, const uint8_t *buf, const size_t buf_len);
 int tls_ctx_receive(tls_ctx_t *ctx, uint8_t *buf, const size_t buf_len);
 void tls_ctx_close(tls_ctx_t *ctx);
-- 
GitLab