All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] tls: Print only one tls_cert_domains_match_mask debug msg
@ 2020-12-15 22:53 Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 2/5] pem: Add pem_write_certificate_chain Andrew Zaborowski
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2020-12-15 22:53 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5315 bytes --]

Change tls_cert_domains_match_mask to compile one error message string
instead of printing messages at different step.  The rest of the TLS debug
log tries to be concise when there's no errors so try to be concise here
too.
---
This is the tls_cert_domains_match_mask version I had in my tree and
thought I might just send it.
---
 ell/tls.c | 71 +++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 45 insertions(+), 26 deletions(-)

diff --git a/ell/tls.c b/ell/tls.c
index 5bf6573..1452909 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -679,8 +679,8 @@ static const struct asn1_oid dn_common_name_oid =
 
 #define SAN_DNS_NAME_ID ASN1_CONTEXT_IMPLICIT(2)
 
-static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
-						char **mask)
+static bool tls_cert_domains_match_mask(struct l_cert *cert, char **mask,
+					char **error_msg)
 {
 	const uint8_t *san, *dn, *end;
 	size_t san_len, dn_len;
@@ -688,7 +688,8 @@ static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
 	const char *cn = NULL;
 	size_t cn_len;
 	char **i;
-	bool dns_name_present = false;
+	struct l_string *dns_names = NULL;
+	int dns_name_count = 0;
 
 	/*
 	 * Locate SubjectAltName (RFC5280 Section 4.2.1.6) and descend into
@@ -698,7 +699,7 @@ static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
 	if (san) {
 		san = asn1_der_find_elem(san, san_len, 0, &san_tag, &san_len);
 		if (unlikely(!san || san_tag != ASN1_ID_SEQUENCE))
-			return false;
+			goto parse_error;
 
 		end = san + san_len;
 		while (san < end) {
@@ -714,18 +715,26 @@ static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
 
 			/* Type is implicitly IA5STRING */
 
-			for (i = mask; *i; i++) {
-				TLS_DEBUG("Trying to match DNSName: '%.*s'"
-						" against mask: '%s'",
-						(int) len, value, *i);
-
+			for (i = mask; *i; i++)
 				if (tls_domain_match_mask((const char *) value,
-							len, *i, strlen(*i)))
+							len, *i, strlen(*i))) {
+					l_string_free(dns_names);
 					return true;
+				}
+
+			if (!dns_names) {
+				dns_names = l_string_new(128);
+				l_string_append(dns_names, "tried DNSName(s) ");
+				l_string_append_fixed(dns_names,
+							(char *) value, len);
+			} else if (dns_name_count < 20) {
+				l_string_append(dns_names, ", ");
+				l_string_append_fixed(dns_names,
+							(char *) value, len);
 			}
 
 			san = value + len;
-			dns_name_present = true;
+			dns_name_count++;
 		}
 	}
 
@@ -744,12 +753,17 @@ static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
 	 * SubjectName. If neither of these conditions holds, then
 	 * verification fails."
 	 */
-	if (unlikely(dns_name_present))
-		return false;
+	if (dns_name_count) {
+		if (dns_name_count > 20)
+			l_string_append_printf(dns_names, " and %i other",
+						dns_name_count - 20);
+
+		*error_msg = l_string_unwrap(dns_names);
+	}
 
 	dn = l_cert_get_dn(cert, &dn_len);
 	if (unlikely(!dn))
-		return false;
+		goto parse_error;
 
 	end = dn + dn_len;
 	while (dn < end) {
@@ -759,17 +773,17 @@ static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
 
 		set = asn1_der_find_elem(dn, end - dn, 0, &tag, &len);
 		if (unlikely(!set || tag != ASN1_ID_SET))
-			return false;
+			goto parse_error;
 
 		dn = set + len;
 
 		seq = asn1_der_find_elem(set, len, 0, &tag, &len);
 		if (unlikely(!seq || tag != ASN1_ID_SEQUENCE))
-			return false;
+			goto parse_error;
 
 		oid = asn1_der_find_elem(seq, len, 0, &tag, &oid_len);
 		if (unlikely(!oid || tag != ASN1_ID_OID))
-			return false;
+			goto parse_error;
 
 		name = asn1_der_find_elem(seq, len, 1, &tag, &name_len);
 		if (unlikely(!name || (tag != ASN1_ID_PRINTABLESTRING &&
@@ -785,15 +799,17 @@ static bool tls_cert_domains_match_mask(struct l_tls *tls, struct l_cert *cert,
 	}
 
 	if (unlikely(!cn))
-		return false;
-
-	for (i = mask; *i; i++) {
-		TLS_DEBUG("Trying to match CN: '%.*s' against mask: '%s'",
-				(int) cn_len, cn, *i);
+		goto parse_error;
 
+	for (i = mask; *i; i++)
 		if (tls_domain_match_mask(cn, cn_len, *i, strlen(*i)))
 			return true;
-	}
+
+	*error_msg = l_strdup_printf("tried CommonName %.*s", (int) cn_len, cn);
+	return false;
+
+parse_error:
+	*error_msg = l_strdup("couldn't locate DNSName or CommonName");
 
 	return false;
 }
@@ -1886,6 +1902,7 @@ static void tls_handle_certificate(struct l_tls *tls,
 	const uint8_t *der;
 	bool dummy;
 	const char *error_str;
+	char *subject_str;
 
 	if (len < 3)
 		goto decode_error;
@@ -1955,14 +1972,16 @@ static void tls_handle_certificate(struct l_tls *tls,
 		goto done;
 	}
 
-	if (tls->subject_mask && !tls_cert_domains_match_mask(tls, leaf,
-							tls->subject_mask)) {
+	if (tls->subject_mask && !tls_cert_domains_match_mask(leaf,
+							tls->subject_mask,
+							&subject_str)) {
 		char *mask = l_strjoinv(tls->subject_mask, '|');
 
 		TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0,
 				"Peer certificate's subject domain "
-				"doesn't match %s", mask);
+				"doesn't match mask %s: %s", mask, subject_str);
 		l_free(mask);
+		l_free(subject_str);
 
 		goto done;
 	}
-- 
2.27.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] pem: Add pem_write_certificate_chain
  2020-12-15 22:53 [PATCH 1/5] tls: Print only one tls_cert_domains_match_mask debug msg Andrew Zaborowski
@ 2020-12-15 22:53 ` Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 3/5] tls: Add l_tls_set_cert_dump_path Andrew Zaborowski
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2020-12-15 22:53 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2504 bytes --]

---
 ell/pem-private.h |  5 +++++
 ell/pem.c         | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+)

diff --git a/ell/pem-private.h b/ell/pem-private.h
index 6e9458d..10f918f 100644
--- a/ell/pem-private.h
+++ b/ell/pem-private.h
@@ -27,6 +27,8 @@
 #define _GNU_SOURCE
 #include <sys/types.h>
 
+struct l_certchain;
+
 const char *pem_next(const void *buf, size_t buf_len, char **type_label,
 				size_t *base64_len,
 				const char **endp, bool strict);
@@ -37,3 +39,6 @@ struct l_key *pem_key_from_pkcs8_private_key_info(const uint8_t *der,
 struct l_key *pem_key_from_pkcs8_encrypted_private_key_info(const uint8_t *der,
 							size_t der_len,
 							const char *passphrase);
+
+int pem_write_certificate_chain(const struct l_certchain *cert,
+				const char *filename);
diff --git a/ell/pem.c b/ell/pem.c
index 1b995d5..321bc3e 100644
--- a/ell/pem.c
+++ b/ell/pem.c
@@ -45,6 +45,7 @@
 #include "cipher.h"
 #include "cert-private.h"
 #include "missing.h"
+#include "io.h"
 #include "pem-private.h"
 
 #define PEM_START_BOUNDARY	"-----BEGIN "
@@ -364,6 +365,55 @@ LIB_EXPORT struct l_certchain *l_pem_load_certificate_chain(
 	return pem_list_to_chain(list);
 }
 
+static bool pem_write_one_cert(struct l_cert *cert, void *user_data)
+{
+	int *fd = user_data;
+	const uint8_t *der;
+	size_t der_len;
+	struct iovec iov[3];
+	ssize_t r;
+
+	der = l_cert_get_der_data(cert, &der_len);
+
+	iov[0].iov_base = "-----BEGIN CERTIFICATE-----\n";
+	iov[0].iov_len = strlen(iov[0].iov_base);
+	iov[1].iov_base = l_base64_encode(der, der_len, 64, &iov[1].iov_len);
+	iov[2].iov_base = "\n-----END CERTIFICATE-----\n";
+	iov[2].iov_len = strlen(iov[2].iov_base);
+	r = L_TFR(writev(*fd, iov, 3));
+
+	if (r == (ssize_t) (iov[0].iov_len + iov[1].iov_len + iov[2].iov_len))
+		return false;
+
+	close(*fd);
+
+	if (r < 0)
+		*fd = -errno;
+	else
+		*fd = -EIO;
+
+	return true;
+}
+
+int pem_write_certificate_chain(const struct l_certchain *chain,
+				const char *filename)
+{
+	int fd = L_TFR(open(filename, O_CREAT | O_WRONLY | O_CLOEXEC, 0600));
+	int err = fd;
+
+	if (err < 0)
+		return -errno;
+
+	l_certchain_walk_from_leaf((struct l_certchain *) chain,
+					pem_write_one_cert, &err);
+
+	if (err < 0)
+		return err;
+
+	close(fd);
+	return 0;
+}
+
 LIB_EXPORT struct l_queue *l_pem_load_certificate_list_from_data(
 						const void *buf, size_t len)
 {
-- 
2.27.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] tls: Add l_tls_set_cert_dump_path
  2020-12-15 22:53 [PATCH 1/5] tls: Print only one tls_cert_domains_match_mask debug msg Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 2/5] pem: Add pem_write_certificate_chain Andrew Zaborowski
@ 2020-12-15 22:53 ` Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 4/5] examples: Fix arguments check in https-client-test Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 5/5] examples: Use l_tls_set_cert_dump_path in https examples Andrew Zaborowski
  3 siblings, 0 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2020-12-15 22:53 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2982 bytes --]

If this function is used to set a file path, l_tls will write the peer's
certificate chain received in the TLS Certificate message if it is used
(on the server side we may receive no client certificate).  This can be
used to diagnose 802.1x connection configurations for example.
---
 ell/ell.sym       |  1 +
 ell/tls-private.h |  1 +
 ell/tls.c         | 22 ++++++++++++++++++++++
 ell/tls.h         |  1 +
 4 files changed, 25 insertions(+)

diff --git a/ell/ell.sym b/ell/ell.sym
index d94b585..c98bd8c 100644
--- a/ell/ell.sym
+++ b/ell/ell.sym
@@ -498,6 +498,7 @@ global:
 	l_tls_set_domain_mask;
 	l_tls_alert_to_str;
 	l_tls_set_debug;
+	l_tls_set_cert_dump_path;
 	/* uintset */
 	l_uintset_new_from_range;
 	l_uintset_new;
diff --git a/ell/tls-private.h b/ell/tls-private.h
index 908c622..8d0540a 100644
--- a/ell/tls-private.h
+++ b/ell/tls-private.h
@@ -205,6 +205,7 @@ struct l_tls {
 	l_tls_debug_cb_t debug_handler;
 	l_tls_destroy_cb_t debug_destroy;
 	void *debug_data;
+	char *cert_dump_path;
 	enum l_tls_version min_version;
 	enum l_tls_version max_version;
 
diff --git a/ell/tls.c b/ell/tls.c
index 1452909..4eaa66d 100644
--- a/ell/tls.c
+++ b/ell/tls.c
@@ -37,6 +37,7 @@
 #include "random.h"
 #include "queue.h"
 #include "pem.h"
+#include "pem-private.h"
 #include "cert.h"
 #include "cert-private.h"
 #include "tls-private.h"
@@ -1942,6 +1943,19 @@ static void tls_handle_certificate(struct l_tls *tls,
 		goto done;
 	}
 
+	if (tls->cert_dump_path) {
+		int r = pem_write_certificate_chain(certchain,
+							tls->cert_dump_path);
+
+		if (r < 0)
+			TLS_DEBUG("Error %i (%s) writing the peer certchain "
+					"to %s",
+					-r, strerror(-r), tls->cert_dump_path);
+		else
+			TLS_DEBUG("Peer certchain written to %s",
+					tls->cert_dump_path);
+	}
+
 	/*
 	 * Validate the certificate chain's consistency and validate it
 	 * against our CAs if we have any.
@@ -2614,6 +2628,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);
 	l_tls_set_domain_mask(tls, NULL);
+	l_tls_set_cert_dump_path(tls, NULL);
 
 	tls_reset_handshake(tls);
 	tls_cleanup_handshake(tls);
@@ -3104,3 +3119,10 @@ LIB_EXPORT bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function,
 
 	return true;
 }
+
+LIB_EXPORT bool l_tls_set_cert_dump_path(struct l_tls *tls, const char *path)
+{
+	l_free(tls->cert_dump_path);
+	tls->cert_dump_path = path ? l_strdup(path) : NULL;
+	return true;
+}
diff --git a/ell/tls.h b/ell/tls.h
index b67492b..683c54c 100644
--- a/ell/tls.h
+++ b/ell/tls.h
@@ -133,6 +133,7 @@ bool l_tls_prf_get_bytes(struct l_tls *tls, bool use_master_secret,
 
 bool l_tls_set_debug(struct l_tls *tls, l_tls_debug_cb_t function,
 			void *user_data, l_tls_destroy_cb_t destroy);
+bool l_tls_set_cert_dump_path(struct l_tls *tls, const char *path);
 
 #ifdef __cplusplus
 }
-- 
2.27.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] examples: Fix arguments check in https-client-test
  2020-12-15 22:53 [PATCH 1/5] tls: Print only one tls_cert_domains_match_mask debug msg Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 2/5] pem: Add pem_write_certificate_chain Andrew Zaborowski
  2020-12-15 22:53 ` [PATCH 3/5] tls: Add l_tls_set_cert_dump_path Andrew Zaborowski
@ 2020-12-15 22:53 ` Andrew Zaborowski
  2020-12-16 20:27   ` Denis Kenzior
  2020-12-15 22:53 ` [PATCH 5/5] examples: Use l_tls_set_cert_dump_path in https examples Andrew Zaborowski
  3 siblings, 1 reply; 6+ messages in thread
From: Andrew Zaborowski @ 2020-12-15 22:53 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 532 bytes --]

---
 examples/https-client-test.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/https-client-test.c b/examples/https-client-test.c
index 2c8d020..e17b271 100644
--- a/examples/https-client-test.c
+++ b/examples/https-client-test.c
@@ -195,7 +195,7 @@ int main(int argc, char *argv[])
 
 	if (argc >= 3) {
 		ca_cert = l_pem_load_certificate_list(argv[2]);
-		if (!cert) {
+		if (!ca_cert) {
 			fprintf(stderr, "Couldn't load the CA certificates\n");
 			return -1;
 		}
-- 
2.27.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] examples: Use l_tls_set_cert_dump_path in https examples
  2020-12-15 22:53 [PATCH 1/5] tls: Print only one tls_cert_domains_match_mask debug msg Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2020-12-15 22:53 ` [PATCH 4/5] examples: Fix arguments check in https-client-test Andrew Zaborowski
@ 2020-12-15 22:53 ` Andrew Zaborowski
  3 siblings, 0 replies; 6+ messages in thread
From: Andrew Zaborowski @ 2020-12-15 22:53 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2608 bytes --]

---
 examples/https-client-test.c |  9 ++++++++-
 examples/https-server-test.c | 18 ++++++++++++++----
 2 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/examples/https-client-test.c b/examples/https-client-test.c
index e17b271..b0c24b4 100644
--- a/examples/https-client-test.c
+++ b/examples/https-client-test.c
@@ -190,9 +190,16 @@ int main(int argc, char *argv[])
 	tls = l_tls_new(false, https_new_data, https_tls_write,
 			https_tls_ready, https_tls_disconnected, NULL);
 
-	if (getenv("TLS_DEBUG"))
+	if (getenv("TLS_DEBUG")) {
+		char *str;
+
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
+		str = l_strdup_printf("/tmp/ell-certchain-%s.pem", hostname);
+		l_tls_set_cert_dump_path(tls, str);
+		l_free(str);
+	}
+
 	if (argc >= 3) {
 		ca_cert = l_pem_load_certificate_list(argv[2]);
 		if (!ca_cert) {
diff --git a/examples/https-server-test.c b/examples/https-server-test.c
index 8f3cb3c..6362722 100644
--- a/examples/https-server-test.c
+++ b/examples/https-server-test.c
@@ -117,7 +117,9 @@ static void https_tls_debug_cb(const char *str, void *user_data)
 
 int main(int argc, char *argv[])
 {
-	struct sockaddr_in addr;
+	struct sockaddr_in addr = {};
+	struct sockaddr_in client_addr = {};
+	socklen_t client_addr_len = sizeof(client_addr);
 	int fd, listenfd;
 	bool auth_ok;
 	struct l_certchain *cert;
@@ -141,7 +143,6 @@ int main(int argc, char *argv[])
 	setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &(int) { 1 },
 			sizeof(int));
 
-	memset(&addr, 0, sizeof(addr));
 	addr.sin_family = AF_INET;
 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
 	addr.sin_port = htons(1234);
@@ -157,7 +158,8 @@ int main(int argc, char *argv[])
 
 	printf("Try https://localhost:1234/ now\n");
 
-	fd = accept(listenfd, NULL, NULL);
+	fd = accept(listenfd, (struct sockaddr *) &client_addr,
+			&client_addr_len);
 	close(listenfd);
 	if (fd == -1) {
 		fprintf(stderr, "accept: %s\n", strerror(errno));
@@ -196,9 +198,17 @@ int main(int argc, char *argv[])
 	tls = l_tls_new(true, https_new_data, https_tls_write,
 			https_tls_ready, https_tls_disconnected, NULL);
 
-	if (getenv("TLS_DEBUG"))
+	if (getenv("TLS_DEBUG")) {
+		char *str;
+
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
+		str = l_strdup_printf("/tmp/ell-certchain-%s.pem",
+					inet_ntoa(client_addr.sin_addr));
+		l_tls_set_cert_dump_path(tls, str);
+		l_free(str);
+	}
+
 	auth_ok = l_tls_set_auth_data(tls, cert, priv_key) &&
 		(argc <= 4 || l_tls_set_cacert(tls, ca_cert)) &&
 		l_tls_start(tls);
-- 
2.27.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 4/5] examples: Fix arguments check in https-client-test
  2020-12-15 22:53 ` [PATCH 4/5] examples: Fix arguments check in https-client-test Andrew Zaborowski
@ 2020-12-16 20:27   ` Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2020-12-16 20:27 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 259 bytes --]

Hi Andrew,

On 12/15/20 4:53 PM, Andrew Zaborowski wrote:
> ---
>   examples/https-client-test.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 

Applied, thanks.

By the way, I'm missing patches 1-3 in this series.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-12-16 20:27 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-15 22:53 [PATCH 1/5] tls: Print only one tls_cert_domains_match_mask debug msg Andrew Zaborowski
2020-12-15 22:53 ` [PATCH 2/5] pem: Add pem_write_certificate_chain Andrew Zaborowski
2020-12-15 22:53 ` [PATCH 3/5] tls: Add l_tls_set_cert_dump_path Andrew Zaborowski
2020-12-15 22:53 ` [PATCH 4/5] examples: Fix arguments check in https-client-test Andrew Zaborowski
2020-12-16 20:27   ` Denis Kenzior
2020-12-15 22:53 ` [PATCH 5/5] examples: Use l_tls_set_cert_dump_path in https examples Andrew Zaborowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.