Skip to contentSkip to conversation

tls: change APIs to use l_cert/l_certchain/l_key

PATCH In review James Prestwood 2 participants 5 messages Oct 1, 2019 – Oct 2, 2019

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/3 tls: change APIs to use l_cert/l_certchain/l_key

l_tls_set_auth_data/l_tls_set_cacert both expected file paths to be passed in, and the certs/keys would be loaded internally. This prevents the caller from loading certs any way but from files. This makes loading certs/keys from data impossible if using TLS. For example, a certificate may be embedded inside a file which has additional data.

To handle both file/data cases its now up to the caller to load the cert/key as an l_cert/l_certchain/l_key/l_queue and pass that structure in directly.

The structure being passed in will now be owned by l_tls, and will be freed on l_tls_free.

---
 ell/tls.c | 42 +++++++++++-------------------------------
 ell/tls.h | 27 +++++++++++++++------------
 2 files changed, 26 insertions(+), 43 deletions(-)

-v2:
* Updated API comments
* Removed debug prints

ell/tls.c +11 -31
index d0e2a66..37434c6 100644
@@ -2591,7 +2591,7 @@ LIB_EXPORT void l_tls_free(struct l_tls *tls)
 	}
 
 	l_tls_set_cacert(tls, NULL);
-	l_tls_set_auth_data(tls, NULL, NULL, NULL);
+	l_tls_set_auth_data(tls, NULL, NULL);
 	l_tls_set_domain_mask(tls, NULL);
 
 	tls_reset_handshake(tls);
@@ -2806,40 +2806,31 @@ LIB_EXPORT void l_tls_close(struct l_tls *tls)
 	TLS_DISCONNECT(TLS_ALERT_CLOSE_NOTIFY, 0, "Closing session");
 }
 
-LIB_EXPORT bool l_tls_set_cacert(struct l_tls *tls, const char *ca_cert_path)
+LIB_EXPORT bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs)
 {
-	TLS_DEBUG("ca-cert-path=%s", ca_cert_path);
-
 	if (tls->ca_certs) {
 		l_queue_destroy(tls->ca_certs,
 				(l_queue_destroy_func_t) l_cert_free);
 		tls->ca_certs = NULL;
 	}
 
-	if (ca_cert_path) {
+	if (ca_certs) {
 		if (!l_key_is_supported(L_KEY_FEATURE_RESTRICT)) {
 			TLS_DEBUG("keyctl restrict support missing, "
 					"check kernel configuration");
 			return false;
 		}
 
-		tls->ca_certs = l_pem_load_certificate_list(ca_cert_path);
-		if (!tls->ca_certs) {
-			TLS_DEBUG("Error loading %s", ca_cert_path);
-			return false;
-		}
+		tls->ca_certs = ca_certs;
 	}
 
 	return true;
 }
 
-LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
-					const char *priv_key_path,
-					const char *priv_key_passphrase)
+LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls,
+					struct l_certchain *certchain,
+					struct l_key *priv_key)
 {
-	TLS_DEBUG("cert-path=%s priv-key-path=%s priv-key-passphrase=%p",
-			cert_path, priv_key_path, priv_key_passphrase);
-
 	if (tls->cert) {
 		l_certchain_free(tls->cert);
 		tls->cert = NULL;
@@ -2851,24 +2842,13 @@ LIB_EXPORT bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
 		tls->priv_key_size = 0;
 	}
 
-	if (cert_path) {
-		tls->cert = l_pem_load_certificate_chain(cert_path);
-		if (!tls->cert) {
-			TLS_DEBUG("Error loading %s", cert_path);
-			return false;
-		}
-	}
+	if (certchain)
+		tls->cert = certchain;
 
-	if (priv_key_path) {
+	if (priv_key) {
 		bool is_public = true;
 
-		tls->priv_key = l_pem_load_private_key(priv_key_path,
-							priv_key_passphrase,
-							NULL);
-		if (!tls->priv_key) {
-			TLS_DEBUG("Error loading %s", priv_key_path);
-			return false;
-		}
+		tls->priv_key = priv_key;
 
 		if (!l_key_get_info(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
 					L_CHECKSUM_NONE, &tls->priv_key_size,
ell/tls.h +15 -12
index a361c37..0ca6def 100644
@@ -33,6 +33,9 @@ enum l_tls_version {
 };
 
 struct l_tls;
+struct l_key;
+struct l_certchain;
+struct l_queue;
 
 enum l_tls_alert_desc {
 	TLS_ALERT_CLOSE_NOTIFY		= 0,
@@ -96,22 +99,22 @@ void l_tls_write(struct l_tls *tls, const uint8_t *data, size_t len);
 void l_tls_handle_rx(struct l_tls *tls, const uint8_t *data, size_t len);
 
 /* If peer is to be authenticated, supply the CA certificates */
-bool l_tls_set_cacert(struct l_tls *tls, const char *ca_cert_path);
+bool l_tls_set_cacert(struct l_tls *tls, struct l_queue *ca_certs);
 
 /*
- * If we are to be authenticated, supply our certificate, private key and
- * private key passphrase if needed (or NULL).  On the client this is optional,
- * but if supplied, negotiation will fail if the certificate type doesn't
- * match or one of the files can't be loaded.
- * TODO: accept a callback to be used for passphrase query.
+ * If we are to be authenticated, supply our certificate and private key. On the
+ * client this is optional.
  * TODO: allow NULL private key if certificate file contains the key.
- * TODO: it may also be useful for the caller to be able to supply
- * one certificate of each type so they can be used depending on which
- * is compatible with the negotiated parameters.
+ * TODO: it may also be useful for the caller to be able to supply one
+ * certificate of each type so they can be used depending on which is compatible
+ * with the negotiated parameters.
+ *
+ * Note: Providing certchain and priv_key will move memory ownership into the
+ *       tls object. These objects should not be freed by the caller.
  */
-bool l_tls_set_auth_data(struct l_tls *tls, const char *cert_path,
-				const char *priv_key_path,
-				const char *priv_key_passphrase);
+bool l_tls_set_auth_data(struct l_tls *tls,
+				struct l_certchain *certchain,
+				struct l_key *priv_key);
 
 void l_tls_set_version_range(struct l_tls *tls,
 				enum l_tls_version min_version,
Signature · 1 line
2.17.1
#1 lore raw

PATCH v2 2/3 unit: update test-tls to use new API definition

---
 unit/test-tls.c | 32 ++++++++++++++++++++++++--------
 1 file changed, 24 insertions(+), 8 deletions(-)
unit/test-tls.c +24 -8
index 9243e16..2c0ea5c 100644
@@ -528,6 +528,13 @@ static void test_tls_with_ver(const struct tls_conn_test *test,
 		},
 	};
 
+	struct l_certchain *server_cert;
+	struct l_certchain *client_cert;
+	struct l_key *server_key;
+	struct l_key *client_key;
+	struct l_queue *server_ca;
+	struct l_queue *client_ca;
+
 	/* Server */
 	s[0].tls = l_tls_new(true, tls_test_new_data, tls_test_write,
 				tls_test_ready, tls_test_disconnected, &s[0]);
@@ -556,16 +563,25 @@ static void test_tls_with_ver(const struct tls_conn_test *test,
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(s[1].tls, tls_debug_cb, "client", NULL);
 
-	auth_ok = l_tls_set_auth_data(s[0].tls, test->server_cert_path,
-					test->server_key_path,
-					test->server_key_passphrase);
+	server_cert = l_pem_load_certificate_chain(test->server_cert_path);
+	client_cert = l_pem_load_certificate_chain(test->client_cert_path);
+
+	server_key = l_pem_load_private_key(test->server_key_path,
+						test->server_key_passphrase,
+						NULL);
+	client_key = l_pem_load_private_key(test->client_key_path,
+						test->client_key_passphrase,
+						NULL);
+
+	server_ca = l_pem_load_certificate_list(test->server_ca_cert_path);
+	client_ca = l_pem_load_certificate_list(test->client_ca_cert_path);
+
+	auth_ok = l_tls_set_auth_data(s[0].tls, server_cert, server_key);
 	assert(auth_ok);
-	auth_ok = l_tls_set_auth_data(s[1].tls, test->client_cert_path,
-					test->client_key_path,
-					test->client_key_passphrase);
+	auth_ok = l_tls_set_auth_data(s[1].tls, client_cert, client_key);
 	assert(auth_ok);
-	assert(l_tls_set_cacert(s[0].tls, test->server_ca_cert_path));
-	assert(l_tls_set_cacert(s[1].tls, test->client_ca_cert_path));
+	assert(l_tls_set_cacert(s[0].tls, server_ca));
+	assert(l_tls_set_cacert(s[1].tls, client_ca));
 
 	if (test->client_domain_mask)
 		l_tls_set_domain_mask(s[1].tls, test->client_domain_mask);
Signature · 1 line
2.17.1
#2 lore raw

Re: [PATCH v2 2/3] unit: update test-tls to use new API definition

Hi James,

Quoted 4 lines · James Prestwood
---
  unit/test-tls.c | 32 ++++++++++++++++++++++++--------
  1 file changed, 24 insertions(+), 8 deletions(-)

I ended up pushing my own version of this commit with much stricter checking of the various load operations. Can you please review.

Regards,
-Denis

#3 lore raw

PATCH v2 3/3 examples: update https server/client with new TLS APIs

In reply to James Prestwood
---
 examples/https-client-test.c | 11 +++++++++--
 examples/https-server-test.c | 11 +++++++++--
 2 files changed, 18 insertions(+), 4 deletions(-)
examples/https-client-test.c +9 -2
index 9a765c6..281bdb8 100644
@@ -134,6 +134,9 @@ int main(int argc, char *argv[])
 	struct sockaddr_in addr;
 	int fd;
 	bool auth_ok;
+	struct l_certchain *cert;
+	struct l_key *priv_key;
+	struct l_queue *ca_cert;
 
 	if (argc != 2 && argc != 3 && argc != 6) {
 		printf("Usage: %s <https-host-name> [<ca-cert-path> "
@@ -189,9 +192,13 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	auth_ok = (argc <= 2 || l_tls_set_cacert(tls, argv[2])) &&
+	ca_cert = l_pem_load_certificate_list(argv[2]);
+	cert = l_pem_load_certificate_chain(argv[3]);
+	priv_key = l_pem_load_private_key(argv[4], argv[5], NULL);
+
+	auth_ok = (argc <= 2 || l_tls_set_cacert(tls, ca_cert)) &&
 		(argc <= 5 ||
-		 l_tls_set_auth_data(tls, argv[3], argv[4], argv[5])) &&
+		 l_tls_set_auth_data(tls, cert, priv_key)) &&
 		l_tls_start(tls);
 
 	if (tls && auth_ok)
examples/https-server-test.c +9 -2
index 4f706ca..93c0bcf 100644
@@ -120,6 +120,9 @@ int main(int argc, char *argv[])
 	struct sockaddr_in addr;
 	int fd, listenfd;
 	bool auth_ok;
+	struct l_certchain *cert;
+	struct l_key *priv_key;
+	struct l_queue *ca_cert;
 
 	if (argc != 4 && argc != 5) {
 		printf("Usage: %s <server-cert-path> <server-key-path> "
@@ -174,8 +177,12 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	auth_ok = l_tls_set_auth_data(tls, argv[1], argv[2], argv[3]) &&
-		(argc <= 4 || l_tls_set_cacert(tls, argv[4])) &&
+	cert = l_pem_load_certificate_chain(argv[1]);
+	priv_key = l_pem_load_private_key(argv[2], argv[3], NULL);
+	ca_cert = l_pem_load_certificate_list(argv[4]);
+
+	auth_ok = l_tls_set_auth_data(tls, cert, priv_key) &&
+		(argc <= 4 || l_tls_set_cacert(tls, ca_cert)) &&
 		l_tls_start(tls);
 
 	if (tls && auth_ok)
Signature · 1 line
2.17.1
#4 lore raw
In reply to James Prestwood

Hi James,

Quoted 12 lines · James Prestwood

l_tls_set_auth_data/l_tls_set_cacert both expected file paths to be passed in, and the certs/keys would be loaded internally. This prevents the caller from loading certs any way but from files. This makes loading certs/keys from data impossible if using TLS. For example, a certificate may be embedded inside a file which has additional data.

To handle both file/data cases its now up to the caller to load the cert/key as an l_cert/l_certchain/l_key/l_queue and pass that structure in directly.

The structure being passed in will now be owned by l_tls, and will be freed on l_tls_free.

Quoted 9 lines
---
  ell/tls.c | 42 +++++++++++-------------------------------
  ell/tls.h | 27 +++++++++++++++------------
  2 files changed, 26 insertions(+), 43 deletions(-)

-v2:
* Updated API comments
* Removed debug prints

Patches 1 & 3 applied, thanks.

Regards,
-Denis