Skip to contentSkip to conversation

tls: Drop local code to add hash OID, let kernel do it

PATCH In review Andrew Zaborowski 2 participants 7 messages Nov 30, 2018

lore
Share & tools
lore
#0 lore raw

PATCH 1/6 tls: Drop local code to add hash OID, let kernel do it

Drop tls.c code to build the PKCS#1 DigestInfo structure which basically consisted of prepending the signature hash algorithm's OID to the hash. Let the key API do it by setting the hash type in the l_key_sign and l_key_verify calls. Slightly simplify the tls_rsa_sign and tls_rsa_verify code while doing this.

---
 ell/tls.c | 169 ++++++++++++++++++------------------------------------
 1 file changed, 56 insertions(+), 113 deletions(-)
ell/tls.c +56 -113
index 018eb39..73a378c 100644
@@ -744,65 +744,6 @@ static const char *tls_handshake_type_to_str(enum tls_handshake_type type)
 	return buf;
 }
 
-static const uint8_t pkcs1_digest_info_md5_start[] = {
-	0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
-	0x02, 0x05, 0x05, 0x00, 0x04, 0x10,
-};
-static const uint8_t pkcs1_digest_info_sha1_start[] = {
-	0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05,
-	0x00, 0x04, 0x14,
-};
-static const uint8_t pkcs1_digest_info_sha256_start[] = {
-	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
-	0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20,
-};
-static const uint8_t pkcs1_digest_info_sha384_start[] = {
-	0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
-	0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30,
-};
-static const uint8_t pkcs1_digest_info_sha512_start[] = {
-	0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
-	0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40,
-};
-
-static void pkcs1_write_digest_info(enum l_checksum_type type,
-					uint8_t *out, size_t *out_len,
-					const uint8_t *hash, size_t hash_len)
-{
-	switch (type) {
-	case L_CHECKSUM_MD5:
-		memcpy(out, pkcs1_digest_info_md5_start,
-				sizeof(pkcs1_digest_info_md5_start));
-		*out_len = sizeof(pkcs1_digest_info_md5_start);
-		break;
-	case L_CHECKSUM_SHA1:
-		memcpy(out, pkcs1_digest_info_sha1_start,
-				sizeof(pkcs1_digest_info_sha1_start));
-		*out_len = sizeof(pkcs1_digest_info_sha1_start);
-		break;
-	case L_CHECKSUM_SHA256:
-		memcpy(out, pkcs1_digest_info_sha256_start,
-				sizeof(pkcs1_digest_info_sha256_start));
-		*out_len = sizeof(pkcs1_digest_info_sha256_start);
-		break;
-	case L_CHECKSUM_SHA384:
-		memcpy(out, pkcs1_digest_info_sha384_start,
-				sizeof(pkcs1_digest_info_sha384_start));
-		*out_len = sizeof(pkcs1_digest_info_sha384_start);
-		break;
-	case L_CHECKSUM_SHA512:
-		memcpy(out, pkcs1_digest_info_sha512_start,
-				sizeof(pkcs1_digest_info_sha512_start));
-		*out_len = sizeof(pkcs1_digest_info_sha512_start);
-		break;
-	default:
-		abort();
-	}
-
-	memcpy(out + *out_len, hash, hash_len);
-	*out_len += hash_len;
-}
-
 static void tls_send_alert(struct l_tls *tls, bool fatal,
 				enum l_tls_alert_desc alert_desc)
 {
@@ -1248,13 +1189,11 @@ static bool tls_send_rsa_client_key_xchg(struct l_tls *tls)
 static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
 				tls_get_hash_t get_hash)
 {
-	ssize_t result;
-	const struct tls_hash_algorithm *hash_type;
-	uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
-	uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
+	ssize_t result = -EMSGSIZE;
+	enum l_checksum_type sign_checksum_type;
+	uint8_t sign_input[HANDSHAKE_HASH_MAX_SIZE + 36];
 	size_t sign_input_len;
-	bool prepend_hash_type = false;
-	size_t expected_bytes;
+	uint8_t *ptr = out;
 
 	if (!tls->priv_key || !tls->priv_key_size) {
 		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, TLS_ALERT_BAD_CERT,
@@ -1263,56 +1202,52 @@ static ssize_t tls_rsa_sign(struct l_tls *tls, uint8_t *out, size_t len,
 		return -ENOKEY;
 	}
 
-	expected_bytes = tls->priv_key_size + 2;
-
 	if (tls->negotiated_version >= TLS_V12) {
-		hash_type = &tls_handshake_hash_data[tls->signature_hash];
-		get_hash(tls, hash_type->tls_id, hash, NULL, NULL);
+		const struct tls_hash_algorithm *hash_type =
+			&tls_handshake_hash_data[tls->signature_hash];
+
+		/* Build the DigitallySigned struct */
+		if (len < 2)	/* Is there space for the algorithm IDs */
+			goto error;
 
-		pkcs1_write_digest_info(hash_type->l_id,
-					sign_input, &sign_input_len,
-					hash, hash_type->length);
+		get_hash(tls, hash_type->tls_id, sign_input, NULL, NULL);
+		sign_checksum_type = hash_type->l_id;
+		sign_input_len = hash_type->length;
 
-		prepend_hash_type = true;
-		expected_bytes += 2;
+		*ptr++ = hash_type->tls_id;
+		*ptr++ = 1;	/* RSA_sign */
+		len -= 2;
 	} else {
 		get_hash(tls, 1, sign_input + 0, NULL, NULL);	/* MD5 */
 		get_hash(tls, 2, sign_input + 16, NULL, NULL);	/* SHA1 */
+		sign_checksum_type = L_CHECKSUM_NONE;
 		sign_input_len = 36;
 	}
 
-	result = -EMSGSIZE;
-
-	if (len >= expected_bytes) {
-		if (prepend_hash_type) {
-			*out++ = hash_type->tls_id;
-			*out++ = 1;	/* RSA_sign */
-		}
+	if (len < tls->priv_key_size + 2)
+		goto error;
 
-		l_put_be16(tls->priv_key_size, out);
-		result = l_key_sign(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
-					L_CHECKSUM_NONE, sign_input, out + 2,
-					sign_input_len, tls->priv_key_size);
+	l_put_be16(tls->priv_key_size, ptr);
+	result = l_key_sign(tls->priv_key, L_KEY_RSA_PKCS1_V1_5,
+				sign_checksum_type, sign_input, ptr + 2,
+				sign_input_len, tls->priv_key_size);
+	ptr += tls->priv_key_size + 2;
 
-		if (result == (ssize_t) tls->priv_key_size)
-			result = expected_bytes;
-	}
-
-	if (result < 0)
-		TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
-				"Signing the hash failed: %s",
-				strerror(-result));
+	if (result == (ssize_t) tls->priv_key_size)
+		return ptr - out; /* Success */
 
+error:
+	TLS_DISCONNECT(TLS_ALERT_INTERNAL_ERROR, 0,
+			"Signing the hash failed: %s",
+			strerror(-result));
 	return result;
 }
 
 static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
 				tls_get_hash_t get_hash)
 {
-	uint8_t hash[HANDSHAKE_HASH_MAX_SIZE];
-	size_t hash_len;
 	enum l_checksum_type hash_type;
-	uint8_t expected[HANDSHAKE_HASH_MAX_SIZE * 2 + 32];
+	uint8_t expected[HANDSHAKE_HASH_MAX_SIZE + 36];
 	size_t expected_len;
 	unsigned int offset;
 	bool success;
@@ -1350,7 +1285,8 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
 			return false;
 		}
 
-		if (!get_hash(tls, in[0], hash, &hash_len, &hash_type)) {
+		if (!get_hash(tls, in[0], expected, &expected_len,
+				&hash_type)) {
 			TLS_DISCONNECT(TLS_ALERT_DECRYPT_ERROR, 0,
 					"Unknown hash type %i", in[0]);
 
@@ -1358,36 +1294,43 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
 		}
 
 		/*
-		 * TODO: According to 4.7 we need to support at least two forms
-		 * of the signed content in the verification:
+		 * Note: Next we let the l_key_verify's underlying kernel
+		 * operation prepend the OID to the hash to build the
+		 * DigestInfo struct.  However according to 4.7 we need to
+		 * support at least two forms of the signed content in the
+		 * verification:
 		 *  - DigestInfo with NULL AlgorithmIdentifier.parameters,
-		 *  - DigestInfo with empty AlgorithmIdentifier.parameters.
+		 *  - DigestInfo with empty AlgorithmIdentifier.parameters,
+		 *
+		 * while the kernel only understands the former encoding.
+		 * Note PKCS#1 versions 2.0 and later section A.2.4 do
+		 * mandate NULL AlgorithmIdentifier.parameters.
 		 *
-		 * Additionally PKCS#1 now says BER is used in place of DER for
-		 * DigestInfo encoding which adds more ambiguity in the
+		 * Additionally PKCS#1 v1.5 said BER is used in place of DER
+		 * for DigestInfo encoding which adds more ambiguity in the
 		 * encoding.
 		 */
-		pkcs1_write_digest_info(hash_type, expected, &expected_len,
-					hash, hash_len);
 	} else {
 		get_hash(tls, 1, expected + 0, NULL, NULL);	/* MD5 */
 		get_hash(tls, 2, expected + 16, NULL, NULL);	/* SHA1 */
 		expected_len = 36;
+		hash_type = L_CHECKSUM_NONE;
 
 		/*
-		 * Within the RSA padding for signatures PKCS#1 1.5 allows
-		 * the block format to be either 0 or 1, while PKCS#1 2.0
-		 * mandates block type 1 making the signatures unambiguous.
-		 * The l_asymmetric_cipher_verify implementation only
-		 * accepts block type 1.
-		 * TODO: TLS 1.0 doesn't specify that block type must be 1
-		 * like TLS 1.2 does meaning that both PKCS#1 1.5 types are
-		 * probably allowed.
+		 * Note: Within the RSA padding for signatures PKCS#1 1.5
+		 * allows the block format to be either 0 or 1, while PKCS#1
+		 * v2.0+ mandates block type 1 making the signatures
+		 * unambiguous.  TLS 1.0 doesn't additionally specify which
+		 * block type is to be used (TLS 1.2 does) meaning that both
+		 * PKCS#1 v1.5 types are allowed.  The l_key_verify's
+		 * underlying kernel implementation only accepts block type
+		 * 1.  If this ever becomes an issue we'd need to go back to
+		 * using L_KEY_RSA_RAW and our own PKCS#1 v1.5 verify logic.
 		 */
 	}
 
 	success = l_key_verify(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5,
-				L_CHECKSUM_NONE, expected, in + 4,
+				hash_type, expected, in + 4,
 				expected_len, tls->peer_pubkey_size);
 
 	if (!success)
Signature · 1 line
2.19.1
#1 lore raw

PATCH 2/6 tls: Fix length in TLS 1.0 signature verification

Account for the shorter Certificate Verify message in TLS 1.0/1.1 when parsing the message to verify the signature. This fixes server side TLS 1.0/1.1 support which apparently has been broken since the migration to l_key.

---
 ell/tls.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
ell/tls.c +1 -1
index 73a378c..83128a5 100644
@@ -1330,7 +1330,7 @@ static bool tls_rsa_verify(struct l_tls *tls, const uint8_t *in, size_t len,
 	}
 
 	success = l_key_verify(tls->peer_pubkey, L_KEY_RSA_PKCS1_V1_5,
-				hash_type, expected, in + 4,
+				hash_type, expected, in + offset + 2,
 				expected_len, tls->peer_pubkey_size);
 
 	if (!success)
Signature · 1 line
2.19.1
#2 lore raw

PATCH 3/6 cert: Change l_certchain_foreach* signatures

In reply to Andrew Zaborowski

Change the "foreach" to "walk" in l_certchain_foreach_from_leaf/_ca and in l_cert_foreach_cb_t to not imply that the whole chain is always traversed because we let the callbacks interrupt the iteration by returning true. Drop the return values. Add comments for the two functions affected.

---
 ell/cert.c  | 28 ++++++++++++++++------------
 ell/cert.h  | 12 +++++-------
 ell/ell.sym |  4 ++--
 ell/tls.c   |  4 ++--
 4 files changed, 25 insertions(+), 23 deletions(-)
ell/cert.c +16 -12
index 66433c2..ae93313 100644
@@ -253,36 +253,40 @@ LIB_EXPORT struct l_cert *l_certchain_get_leaf(struct l_certchain *chain)
 	return chain->leaf;
 }
 
-LIB_EXPORT bool l_certchain_foreach_from_leaf(struct l_certchain *chain,
-						l_cert_foreach_cb_t cb,
+/*
+ * Call @cb for each certificate in the chain starting from the leaf
+ * certificate.  Stop if a call returns @true.
+ */
+LIB_EXPORT void l_certchain_walk_from_leaf(struct l_certchain *chain,
+						l_cert_walk_cb_t cb,
 						void *user_data)
 {
 	struct l_cert *cert;
 
 	if (unlikely(!chain))
-		return false;
+		return;
 
 	for (cert = chain->leaf; cert; cert = cert->issuer)
 		if (cb(cert, user_data))
-			return true;
-
-	return false;
+			break;
 }
 
-LIB_EXPORT bool l_certchain_foreach_from_ca(struct l_certchain *chain,
-						l_cert_foreach_cb_t cb,
+/*
+ * Call @cb for each certificate in the chain starting from the root
+ * certificate.  Stop if a call returns @true.
+ */
+LIB_EXPORT void l_certchain_walk_from_ca(struct l_certchain *chain,
+						l_cert_walk_cb_t cb,
 						void *user_data)
 {
 	struct l_cert *cert;
 
 	if (unlikely(!chain))
-		return false;
+		return;
 
 	for (cert = chain->ca; cert; cert = cert->issued)
 		if (cb(cert, user_data))
-			return true;
-
-	return false;
+			break;
 }
 
 LIB_EXPORT bool l_certchain_find(struct l_certchain *chain,
ell/cert.h +5 -7
index c1513f1..0c3947c 100644
@@ -38,7 +38,7 @@ enum l_cert_key_type {
 	L_CERT_KEY_UNKNOWN,
 };
 
-typedef bool (*l_cert_foreach_cb_t)(struct l_cert *cert, void *user_data);
+typedef bool (*l_cert_walk_cb_t)(struct l_cert *cert, void *user_data);
 
 struct l_cert *l_cert_new_from_der(const uint8_t *buf, size_t buf_len);
 void l_cert_free(struct l_cert *cert);
@@ -51,12 +51,10 @@ struct l_key *l_cert_get_pubkey(struct l_cert *cert);
 void l_certchain_free(struct l_certchain *chain);
 
 struct l_cert *l_certchain_get_leaf(struct l_certchain *chain);
-bool l_certchain_foreach_from_leaf(struct l_certchain *chain,
-					l_cert_foreach_cb_t cb,
-					void *user_data);
-bool l_certchain_foreach_from_ca(struct l_certchain *chain,
-					l_cert_foreach_cb_t cb,
-					void *user_data);
+void l_certchain_walk_from_leaf(struct l_certchain *chain,
+				l_cert_walk_cb_t cb, void *user_data);
+void l_certchain_walk_from_ca(struct l_certchain *chain,
+				l_cert_walk_cb_t cb, void *user_data);
 
 bool l_certchain_find(struct l_certchain *chain, struct l_queue *ca_certs);
 bool l_certchain_verify(struct l_certchain *chain, struct l_queue *ca_certs);
ell/ell.sym +2 -2
index 9cea0c1..b8f3730 100644
@@ -445,8 +445,8 @@ global:
 	l_cert_get_pubkey;
 	l_certchain_free;
 	l_certchain_get_leaf;
-	l_certchain_foreach_from_leaf;
-	l_certchain_foreach_from_ca;
+	l_certchain_walk_from_leaf;
+	l_certchain_walk_from_ca;
 	l_certchain_find;
 	l_certchain_verify;
 local:
ell/tls.c +2 -2
index 83128a5..e32b833 100644
@@ -961,7 +961,7 @@ static bool tls_send_certificate(struct l_tls *tls)
 	 */
 
 	total = 0;
-	l_certchain_foreach_from_leaf(tls->cert, tls_cert_list_add_size, &total);
+	l_certchain_walk_from_leaf(tls->cert, tls_cert_list_add_size, &total);
 
 	buf = l_malloc(128 + total);
 	ptr = buf + TLS_HANDSHAKE_HEADER_SIZE;
@@ -971,7 +971,7 @@ static bool tls_send_certificate(struct l_tls *tls)
 	*ptr++ = total >> 16;
 	*ptr++ = total >>  8;
 	*ptr++ = total >>  0;
-	l_certchain_foreach_from_leaf(tls->cert, tls_cert_list_append, &ptr);
+	l_certchain_walk_from_leaf(tls->cert, tls_cert_list_append, &ptr);
 
 	tls_tx_handshake(tls, TLS_CERTIFICATE, buf, ptr - buf);
 
Signature · 1 line
2.19.1
#3 lore raw

PATCH 4/6 cert: Optionally return error string from l_certchain_verify

In reply to Andrew Zaborowski

Return a basic error string to the l_certchain_verify caller so it can be included in debug logs.

---
 ell/cert.c | 60 +++++++++++++++++++++++++++++++++++++++++++-----------
 ell/cert.h |  3 ++-
 ell/tls.c  |  7 ++++---
 3 files changed, 54 insertions(+), 16 deletions(-)
ell/cert.c +48 -12
index ae93313..d52bfd0 100644
@@ -23,6 +23,7 @@
 #endif
 
 #include <string.h>
+#include <stdio.h>
 
 #include "private.h"
 #include "key.h"
@@ -303,17 +304,18 @@ LIB_EXPORT bool l_certchain_find(struct l_certchain *chain,
 	 * Also nothing to do if the user already supplied a working
 	 * certificate chain.
 	 */
-	if (l_certchain_verify(chain, ca_certs))
+	if (l_certchain_verify(chain, ca_certs, NULL))
 		return true;
 
 	/* Actual search for a chain to the CA cert is unimplemented, fail */
 	return false;
 }
 
-static struct l_keyring *cert_set_to_keyring(struct l_queue *certs)
+static struct l_keyring *cert_set_to_keyring(struct l_queue *certs, char *error)
 {
 	struct l_keyring *ring;
 	const struct l_queue_entry *entry;
+	int i = 1;
 
 	ring = l_keyring_new();
 	if (!ring)
@@ -323,15 +325,23 @@ static struct l_keyring *cert_set_to_keyring(struct l_queue *certs)
 		struct l_cert *cert = entry->data;
 		struct l_key *key = l_cert_get_pubkey(cert);
 
-		if (!key)
+		if (!key) {
+			sprintf(error, "Can't get public key from certificate "
+				"%i / %i in certificate set", i,
+				l_queue_length(certs));
 			goto cleanup;
+		}
 
 		if (!l_keyring_link(ring, key)) {
 			l_key_free(key);
+			sprintf(error, "Can't link the public key from "
+				"certificate %i / %i to target keyring",
+				i, l_queue_length(certs));
 			goto cleanup;
 		}
 
 		l_key_free_norevoke(key);
+		i++;
 	}
 
 	return ring;
@@ -380,21 +390,33 @@ static void cert_keyring_cleanup(struct l_keyring **p)
 	l_keyring_free(*p);
 }
 
+#define RETURN_ERROR(msg, args...)	\
+	do {	\
+		if (error) {	\
+			*error = error_buf;	\
+			snprintf(error_buf, sizeof(error_buf), msg, ## args); \
+		}	\
+		return false;	\
+	} while (0)
+
 LIB_EXPORT bool l_certchain_verify(struct l_certchain *chain,
-					struct l_queue *ca_certs)
+					struct l_queue *ca_certs,
+					const char **error)
 {
 	struct l_keyring *ca_ring = NULL;
 	L_AUTO_CLEANUP_VAR(struct l_keyring *, verify_ring,
 				cert_keyring_cleanup) = NULL;
 	struct l_cert *cert;
 	struct l_key *prev_key = NULL;
+	int verified = 0;
+	static char error_buf[200];
 
 	if (unlikely(!chain || !chain->leaf))
-		return false;
+		RETURN_ERROR("Chain empty");
 
 	verify_ring = l_keyring_new();
 	if (!verify_ring)
-		return false;
+		RETURN_ERROR("Can't create verify keyring");
 
 	cert = chain->ca;
 
@@ -416,19 +438,23 @@ LIB_EXPORT bool l_certchain_verify(struct l_certchain *chain,
 	 * extension from being linked to a keyring.
 	 */
 	if (cert_is_in_set(cert, ca_certs)) {
+		verified++;
 		cert = cert->issued;
 		if (!cert)
 			return true;
 
 		prev_key = cert_try_link(cert, verify_ring);
 	} else if (ca_certs) {
-		ca_ring = cert_set_to_keyring(ca_certs);
-		if (!ca_ring)
+		ca_ring = cert_set_to_keyring(ca_certs, error_buf);
+		if (!ca_ring) {
+			if (error)
+				*error = error_buf;
 			return false;
+		}
 
 		if (!l_keyring_link_nested(verify_ring, ca_ring)) {
 			l_keyring_free(ca_ring);
-			return false;
+			RETURN_ERROR("Can't link CA ring to verify ring");
 		}
 	} else
 		prev_key = cert_try_link(cert, verify_ring);
@@ -441,7 +467,7 @@ LIB_EXPORT bool l_certchain_verify(struct l_certchain *chain,
 				NULL)) {
 		l_key_free(prev_key);
 		l_keyring_free(ca_ring);
-		return false;
+		RETURN_ERROR("Can't restrict verify keyring");
 	}
 
 	if (ca_ring) {
@@ -468,10 +494,20 @@ LIB_EXPORT bool l_certchain_verify(struct l_certchain *chain,
 		l_key_free(prev_key);
 		prev_key = new_key;
 		cert = cert->issued;
+		verified++;
 	}
 
-	if (!prev_key)
-		return false;
+	if (!prev_key) {
+		int total = 0;
+
+		for (cert = chain->ca; cert; cert = cert->issued, total++);
+		RETURN_ERROR("Linking certificate %i / %i failed, root %s"
+				"verified against trusted CA(s) and the "
+				"following %i top certificates verified ok",
+				verified + 1, total,
+				ca_certs && verified ? "" : "not ",
+				verified ? verified - 1 : 0);
+	}
 
 	l_key_free(prev_key);
 	return true;
ell/cert.h +2 -1
index 0c3947c..0dc86a2 100644
@@ -57,7 +57,8 @@ void l_certchain_walk_from_ca(struct l_certchain *chain,
 				l_cert_walk_cb_t cb, void *user_data);
 
 bool l_certchain_find(struct l_certchain *chain, struct l_queue *ca_certs);
-bool l_certchain_verify(struct l_certchain *chain, struct l_queue *ca_certs);
+bool l_certchain_verify(struct l_certchain *chain, struct l_queue *ca_certs,
+			const char **error);
 
 #ifdef __cplusplus
 }
ell/tls.c +4 -3
index e32b833..f27f35c 100644
@@ -1781,6 +1781,7 @@ static void tls_handle_certificate(struct l_tls *tls,
 	size_t der_len;
 	const uint8_t *der;
 	bool dummy;
+	const char *error_str;
 
 	if (len < 3)
 		goto decode_error;
@@ -1824,11 +1825,11 @@ static void tls_handle_certificate(struct l_tls *tls,
 	 * Validate the certificate chain's consistency and validate it
 	 * against our CAs if we have any.
 	 */
-	if (!l_certchain_verify(certchain, tls->ca_certs)) {
+	if (!l_certchain_verify(certchain, tls->ca_certs, &error_str)) {
 		TLS_DISCONNECT(TLS_ALERT_BAD_CERT, 0,
 				"Peer certchain verification failed "
-				"consistency check%s", tls->ca_certs ?
-				" or against local CA certs" : "");
+				"consistency check%s: %s", tls->ca_certs ?
+				" or against local CA certs" : "", error_str);
 
 		goto done;
 	}
Signature · 1 line
2.19.1
#4 lore raw

PATCH 5/6 unit: Update test-tls to new l_certchain_verify params

In reply to Andrew Zaborowski
---
 unit/test-tls.c | 32 ++++++++++++++++----------------
 1 file changed, 16 insertions(+), 16 deletions(-)
unit/test-tls.c +16 -16
index e8c18f0..84dd950 100644
@@ -232,18 +232,18 @@ static void test_certificates(const void *data)
 	chain = l_pem_load_certificate_chain(CERTDIR "cert-server.pem");
 	assert(chain);
 
-	assert(!l_certchain_verify(chain, wrongca));
-	assert(l_certchain_verify(chain, cacert));
-	assert(l_certchain_verify(chain, NULL));
-	assert(l_certchain_verify(chain, twocas));
+	assert(!l_certchain_verify(chain, wrongca, NULL));
+	assert(l_certchain_verify(chain, cacert, NULL));
+	assert(l_certchain_verify(chain, NULL, NULL));
+	assert(l_certchain_verify(chain, twocas, NULL));
 
 	chain2 = l_pem_load_certificate_chain(CERTDIR "cert-chain.pem");
 	assert(chain2);
 
-	assert(!l_certchain_verify(chain2, wrongca));
-	assert(l_certchain_verify(chain2, cacert));
-	assert(l_certchain_verify(chain2, NULL));
-	assert(l_certchain_verify(chain2, twocas));
+	assert(!l_certchain_verify(chain2, wrongca, NULL));
+	assert(l_certchain_verify(chain2, cacert, NULL));
+	assert(l_certchain_verify(chain2, NULL, NULL));
+	assert(l_certchain_verify(chain2, twocas, NULL));
 
 	chain3 = certchain_new_from_leaf(
 			tls_cert_load_file(CERTDIR "cert-server.pem"));
@@ -255,10 +255,10 @@ static void test_certificates(const void *data)
 			tls_cert_load_file(CERTDIR "cert-ca.pem"));
 	assert(chain3);
 
-	assert(!l_certchain_verify(chain3, wrongca));
-	assert(!l_certchain_verify(chain3, cacert));
-	assert(!l_certchain_verify(chain3, NULL));
-	assert(!l_certchain_verify(chain3, twocas));
+	assert(!l_certchain_verify(chain3, wrongca, NULL));
+	assert(!l_certchain_verify(chain3, cacert, NULL));
+	assert(!l_certchain_verify(chain3, NULL, NULL));
+	assert(!l_certchain_verify(chain3, twocas, NULL));
 
 	chain4 = certchain_new_from_leaf(
 			tls_cert_load_file(CERTDIR "cert-entity-int.pem"));
@@ -268,10 +268,10 @@ static void test_certificates(const void *data)
 			tls_cert_load_file(CERTDIR "cert-ca.pem"));
 	assert(chain4);
 
-	assert(!l_certchain_verify(chain4, wrongca));
-	assert(l_certchain_verify(chain4, cacert));
-	assert(l_certchain_verify(chain4, NULL));
-	assert(l_certchain_verify(chain4, twocas));
+	assert(!l_certchain_verify(chain4, wrongca, NULL));
+	assert(l_certchain_verify(chain4, cacert, NULL));
+	assert(l_certchain_verify(chain4, NULL, NULL));
+	assert(l_certchain_verify(chain4, twocas, NULL));
 
 	l_certchain_free(chain);
 	l_certchain_free(chain2);
Signature · 1 line
2.19.1
#5 lore raw

PATCH 6/6 tools: Update certchain-verify to new l_certchain_verify params

In reply to Andrew Zaborowski
---
 tools/certchain-verify.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
tools/certchain-verify.c +3 -2
index 08eec90..1a1dab1 100644
@@ -98,6 +98,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *certchain;
 	struct l_queue *ca_certs;
 	int err;
+	const char *error_str;
 
 	if (argc != 3) {
 		usage(argv[0]);
@@ -122,8 +123,8 @@ int main(int argc, char *argv[])
 		goto free_certchain;
 	}
 
-	if (!l_certchain_verify(certchain, ca_certs)) {
-		fprintf(stderr, "Verification failed\n");
+	if (!l_certchain_verify(certchain, ca_certs, &error_str)) {
+		fprintf(stderr, "Verification failed: %s\n", error_str);
 		goto free_cacert;
 	}
 
Signature · 1 line
2.19.1
#6 lore raw
In reply to Andrew Zaborowski

Hi Andrew,

Quoted 9 lines · Andrew Zaborowski

Drop tls.c code to build the PKCS#1 DigestInfo structure which basically consisted of prepending the signature hash algorithm's OID to the hash. Let the key API do it by setting the hash type in the l_key_sign and l_key_verify calls. Slightly simplify the tls_rsa_sign and tls_rsa_verify code while doing this.

---
  ell/tls.c | 169 ++++++++++++++++++------------------------------------
  1 file changed, 56 insertions(+), 113 deletions(-)

All applied, thanks.

Regards,
-Denis