ell.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] pem: Parse PKCS#1 formatted private keys
@ 2020-11-21  2:48 Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 2/5] pem: Decrypt PKCS#1 encrypted " Andrew Zaborowski
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-21  2:48 UTC (permalink / raw)
  To: ell

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

The PKCS#1 RSAPrivateKey format is used within the PKCS#8 PrivateKey
structure so we just need to wrap it in some extra ASN.1 data to get a
format understood by the pkcs8-key-parse module.

Improve some comments with the right RFC references.
---
 ell/asn1-private.h |   1 +
 ell/pem.c          | 106 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 98 insertions(+), 9 deletions(-)

diff --git a/ell/asn1-private.h b/ell/asn1-private.h
index e34f977..2a31241 100644
--- a/ell/asn1-private.h
+++ b/ell/asn1-private.h
@@ -29,6 +29,7 @@
 #define ASN1_ID_INTEGER		ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x02)
 #define ASN1_ID_BIT_STRING	ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x03)
 #define ASN1_ID_OCTET_STRING	ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x04)
+#define ASN1_ID_NULL		ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x05)
 #define ASN1_ID_OID		ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x06)
 #define ASN1_ID_UTF8STRING	ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x0c)
 #define ASN1_ID_PRINTABLESTRING	ASN1_ID(ASN1_CLASS_UNIVERSAL, 0, 0x13)
diff --git a/ell/pem.c b/ell/pem.c
index b54270e..99020b1 100644
--- a/ell/pem.c
+++ b/ell/pem.c
@@ -400,14 +400,21 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 	struct l_key *pkey = NULL;
 
 	/*
-	 * RFC7469- and PKCS#8-compatible label (default in OpenSSL 1.0.1+)
-	 * and the older (OpenSSL <= 0.9.8 default) label.
+	 * RFC7468 Section 10-compatible unencrypted private key label
+	 * (also mentioned in PKCS#8/RFC5958 Section 5), encodes
+	 * the PKCS#8/RFC5958 PrivateKeyInfo structure -- supported
+	 * directly by the pkcs8-key-parser kernel module.
 	 */
-	if (!strcmp(label, "PRIVATE KEY") ||
-			!strcmp(label, "RSA PRIVATE KEY"))
+	if (!strcmp(label, "PRIVATE KEY"))
 		goto done;
 
-	/* RFC5958 (PKCS#8) section 3 type encrypted key label */
+	/*
+	 * RFC7468 Section 11-compatible encrypted private key label
+	 * (also mentioned in PKCS#8/RFC5958 Section 5), encodes
+	 * the PKCS#8/RFC5958 EncryptedPrivateKeyInfo structure.  We
+	 * decrypt it into a plain PrivateKeyInfo for the
+	 * pkcs8-key-parser module.
+	 */
 	if (!strcmp(label, "ENCRYPTED PRIVATE KEY")) {
 		const uint8_t *key_info, *alg_id, *data;
 		uint8_t tag;
@@ -479,11 +486,92 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 	}
 
 	/*
-	 * TODO: handle RSA PRIVATE KEY format encrypted keys
-	 * (as produced by "openssl rsa" commands), incompatible with
-	 * RFC7468 parsing because of the headers present before
-	 * base64-encoded data.
+	 * Legacy RSA private key label aka. SSLeay format label, created
+	 * by most software but not documented in an RFC.  Encodes the
+	 * PKCS#1/RFC8017 RSAPrivateKey structure.  We wrap it in a PKCS#8
+	 * PrivateKeyInfo for the pkcs8-key-parser module.
+	 *
+	 * TODO: decrypt RSA PRIVATE KEY format encrypted keys
+	 * as produced by "openssl rsa" commands.  These are incompatible
+	 * with RFC7468 parsing because of the RFC822 headers present
+	 * before base64-encoded data.  The format is documented in
+	 * RFC1421 and the encryption algorithms in RFC1423 although
+	 * openssl allows many more algorithms than those documented.
+	 * Then wrap in a PrivateKeyInfo like above.
 	 */
+	if (!strcmp(label, "RSA PRIVATE KEY")) {
+		const uint8_t *data;
+		uint8_t tag;
+		size_t data_len;
+		const uint8_t *key_data;
+		size_t key_data_len;
+		int i;
+		uint8_t *private_key;
+		size_t private_key_len;
+		uint8_t *one_asymmetric_key;
+		uint8_t *ptr;
+
+		static const uint8_t version0[] = {
+			ASN1_ID_INTEGER, 0x01, 0x00
+		};
+		static const uint8_t pkcs1_rsa_encryption[] = {
+			ASN1_ID_SEQUENCE, 0x0d,
+			ASN1_ID_OID, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
+			0x01, 0x01, 0x01,
+			ASN1_ID_NULL, 0x00,
+		};
+
+		/*
+		 * Sanity check that it's a version 0 or 1 RSAPrivateKey
+		 * structure with the 8 integers, if it's not, make a last
+		 * ditch attempt to load it into the kernel directly.
+		 */
+		key_data = asn1_der_find_elem(content, len, 0, &tag,
+						&key_data_len);
+		if (!key_data || tag != ASN1_ID_SEQUENCE)
+			goto done;
+
+		data = asn1_der_find_elem(key_data, key_data_len, 0, &tag,
+						&data_len);
+		if (!data || tag != ASN1_ID_INTEGER || data_len != 1 ||
+				(data[0] != 0x00 && data[0] != 0x01))
+			goto done;
+
+		for (i = 1; i < 9; i++) {
+			data = asn1_der_find_elem(key_data, key_data_len,
+							i, &tag, &data_len);
+			if (!data || tag != ASN1_ID_INTEGER || data_len < 1)
+				goto done;
+		}
+
+		private_key = l_malloc(10 + len);
+		ptr = private_key;
+		*ptr++ = ASN1_ID_OCTET_STRING;
+		asn1_write_definite_length(&ptr, len);
+		memcpy(ptr, content, len);
+		ptr += len;
+		private_key_len = ptr - private_key;
+
+		one_asymmetric_key = l_malloc(32 + private_key_len);
+		ptr = one_asymmetric_key;
+		*ptr++ = ASN1_ID_SEQUENCE;
+		asn1_write_definite_length(&ptr,
+						sizeof(version0) +
+						sizeof(pkcs1_rsa_encryption) +
+						private_key_len);
+		memcpy(ptr, version0, sizeof(version0));
+		ptr += sizeof(version0);
+		memcpy(ptr, pkcs1_rsa_encryption, sizeof(pkcs1_rsa_encryption));
+		ptr += sizeof(pkcs1_rsa_encryption);
+		memcpy(ptr, private_key, private_key_len);
+		ptr += private_key_len;
+		l_free(private_key);
+
+		l_free(content);
+		content = one_asymmetric_key;
+		len = ptr - one_asymmetric_key;
+		goto done;
+	}
 
 	/* Label not known */
 	goto err;
-- 
2.25.1

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

* [PATCH 2/5] pem: Decrypt PKCS#1 encrypted private keys
  2020-11-21  2:48 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
@ 2020-11-21  2:48 ` Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 3/5] examples: More error messages in https-{client, server}-test Andrew Zaborowski
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-21  2:48 UTC (permalink / raw)
  To: ell

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

---
 ell/pem.c | 306 ++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 284 insertions(+), 22 deletions(-)

diff --git a/ell/pem.c b/ell/pem.c
index 99020b1..c76af1b 100644
--- a/ell/pem.c
+++ b/ell/pem.c
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <strings.h>
+#include <ctype.h>
 
 #include "util.h"
 #include "private.h"
@@ -194,7 +195,8 @@ const char *pem_next(const void *buf, size_t buf_len, char **type_label,
 }
 
 static uint8_t *pem_load_buffer(const void *buf, size_t buf_len,
-				char **type_label, size_t *len)
+				char **out_type_label, size_t *out_len,
+				char **out_headers)
 {
 	size_t base64_len;
 	const char *base64;
@@ -206,9 +208,50 @@ static uint8_t *pem_load_buffer(const void *buf, size_t buf_len,
 	if (!base64)
 		return NULL;
 
-	ret = l_base64_decode(base64, base64_len, len);
+	if (memchr(base64, ':', base64_len)) {
+		const char *start;
+		const char *end;
+
+		while (base64_len && isspace(*base64)) {
+			base64++;
+			base64_len--;
+		}
+
+		start = base64;
+
+		if (!(end = memmem(start, base64_len, "\n\n", 2)) &&
+				!(end = memmem(start, base64_len, "\n\r\n", 3)))
+			return NULL;
+
+		/* Check that each header line has a key and a colon */
+		while (start < end) {
+			const char *lf = rawmemchr(start, '\n');
+			const char *colon = memchr(start, ':', lf - start);
+
+			if (!colon)
+				return NULL;
+
+			for (; start < colon; start++)
+				if (isalnum(*start))
+					break;
+
+			if (start == colon)
+				return NULL;
+
+			start = lf + 1;
+		}
+
+		if (out_headers)
+			*out_headers = l_strndup(base64, end - base64);
+
+		base64_len -= end + 2 - base64;
+		base64 = end + 2;
+	} else if (out_headers)
+		*out_headers = NULL;
+
+	ret = l_base64_decode(base64, base64_len, out_len);
 	if (ret) {
-		*type_label = label;
+		*out_type_label = label;
 		return ret;
 	}
 
@@ -220,7 +263,7 @@ static uint8_t *pem_load_buffer(const void *buf, size_t buf_len,
 LIB_EXPORT uint8_t *l_pem_load_buffer(const void *buf, size_t buf_len,
 					char **type_label, size_t *out_len)
 {
-	return pem_load_buffer(buf, buf_len, type_label, out_len);
+	return pem_load_buffer(buf, buf_len, type_label, out_len, NULL);
 }
 
 struct pem_file_info {
@@ -260,8 +303,8 @@ static void pem_file_close(struct pem_file_info *info)
 	close(info->fd);
 }
 
-LIB_EXPORT uint8_t *l_pem_load_file(const char *filename,
-					char **type_label, size_t *len)
+static uint8_t *pem_load_file(const char *filename, char **out_type_label,
+				size_t *out_len, char **out_headers)
 {
 	struct pem_file_info file;
 	uint8_t *result;
@@ -273,11 +316,17 @@ LIB_EXPORT uint8_t *l_pem_load_file(const char *filename,
 		return NULL;
 
 	result = pem_load_buffer(file.data, file.st.st_size,
-					type_label, len);
+					out_type_label, out_len, out_headers);
 	pem_file_close(&file);
 	return result;
 }
 
+LIB_EXPORT uint8_t *l_pem_load_file(const char *filename,
+					char **out_type_label, size_t *out_len)
+{
+	return pem_load_file(filename, out_type_label, out_len, NULL);
+}
+
 static struct l_certchain *pem_list_to_chain(struct l_queue *list)
 {
 	struct l_certchain *chain;
@@ -391,10 +440,167 @@ LIB_EXPORT struct l_queue *l_pem_load_certificate_list(const char *filename)
 	return list;
 }
 
+#define SKIP_WHITESPACE(str)	\
+	while (isspace(*(str)))	\
+		(str)++;
+
+static const char *parse_rfc1421_dek_info(char *headers,
+						const char **out_params)
+{
+	const char *proc_type = NULL;
+	char *dek_info = NULL;
+	char *comma;
+
+	while (headers) {
+		char *lf = strchrnul(headers, '\n');
+		char *key;
+
+		key = headers;
+		SKIP_WHITESPACE(key);
+		headers = (*lf == '\n') ? lf + 1 : NULL;
+
+		if (!memcmp(key, "X-", 2))
+			key += 2;
+
+		if (!memcmp(key, "Proc-Type:", 10)) {
+			if (proc_type)
+				return NULL;
+
+			proc_type = key + 10;
+			SKIP_WHITESPACE(proc_type);
+		} else if (!memcmp(key, "DEK-Info:", 9)) {
+			if (dek_info)
+				return NULL;
+
+			dek_info = key + 9;
+			SKIP_WHITESPACE(dek_info);
+		} else
+			continue;
+
+		while (isspace(lf[-1]))
+			lf--;
+
+		*lf = '\0';
+	}
+
+	if (!proc_type || !dek_info)
+		return NULL;
+
+	/* Skip the version field (should be 3 or 4) */
+	proc_type = strchr(proc_type, ',');
+	if (!proc_type)
+		return NULL;
+
+	proc_type++;
+	SKIP_WHITESPACE(proc_type);
+
+	/* Section 4.6.1.1 */
+	if (strcmp(proc_type, "ENCRYPTED"))
+		return NULL;
+
+	comma = strchr(dek_info, ',');
+	if (comma) {
+		*out_params = comma + 1;
+		SKIP_WHITESPACE(*out_params);
+
+		while (comma > dek_info && isspace(comma[-1]))
+			comma--;
+
+		*comma = '\0';
+	} else
+		*out_params = NULL;
+
+	return dek_info;
+}
+
+static struct l_cipher *cipher_from_dek_info(const char *algid, const char *params,
+						const char *passphrase,
+						size_t *block_len)
+{
+	enum l_cipher_type type;
+	struct l_cipher *cipher;
+	struct l_checksum *md5;
+	uint8_t key[32];
+	size_t key_len;
+	bool ok;
+	L_AUTO_FREE_VAR(uint8_t *, iv) = NULL;
+	size_t iv_len;
+
+	if (!strcmp(algid, "DES-CBC")) {
+		type = L_CIPHER_DES_CBC;
+		key_len = 8;
+		iv_len = 8;
+	} else if (!strcmp(algid, "DES-EDE3-CBC")) {
+		type = L_CIPHER_DES3_EDE_CBC;
+		key_len = 24;
+		iv_len = 8;
+	} else if (!strcmp(algid, "AES-128-CBC")) {
+		type = L_CIPHER_AES_CBC;
+		key_len = 16;
+		iv_len = 16;
+	} else if (!strcmp(algid, "AES-192-CBC")) {
+		type = L_CIPHER_AES_CBC;
+		key_len = 24;
+		iv_len = 16;
+	} else if (!strcmp(algid, "AES-256-CBC")) {
+		type = L_CIPHER_AES_CBC;
+		key_len = 32;
+		iv_len = 16;
+	} else
+		return NULL;
+
+	if (!params || strlen(params) != 2 * iv_len)
+		return NULL;
+
+	*block_len = iv_len;
+
+	iv = l_util_from_hexstring(params, &iv_len);
+	if (!iv)
+		return NULL;
+
+	/*
+	 * The encryption key is the MD5(password | IV[:8]), this comes from
+	 * opessl's crypto/evp/evp_key.c:EVP_BytesToKey() and doesn't seem to
+	 * be backed by any standard:
+	 * https://web.archive.org/web/20190528100132/https://latacora.singles/2018/08/03/the-default-openssh.html
+	 */
+	md5 = l_checksum_new(L_CHECKSUM_MD5);
+	if (!md5)
+		return NULL;
+
+	ok = l_checksum_update(md5, passphrase, strlen(passphrase)) &&
+		l_checksum_update(md5, iv, 8) &&
+		l_checksum_get_digest(md5, key, 16) == 16;
+
+	if (ok && key_len > 16) {
+		l_checksum_reset(md5);
+		ok = l_checksum_update(md5, key, 16) &&
+			l_checksum_update(md5, passphrase, strlen(passphrase)) &&
+			l_checksum_update(md5, iv, 8) &&
+			l_checksum_get_digest(md5, key + 16, 16) == 16;
+	}
+
+	l_checksum_free(md5);
+
+	if (!ok)
+		return NULL;
+
+	cipher  = l_cipher_new(type, key, key_len);
+	if (!cipher)
+		return NULL;
+
+	if (l_cipher_set_iv(cipher, iv, iv_len))
+		return cipher;
+
+	l_cipher_free(cipher);
+	return NULL;
+}
+
 static struct l_key *pem_load_private_key(uint8_t *content,
 						size_t len,
 						char *label,
 						const char *passphrase,
+						char *headers,
 						bool *encrypted)
 {
 	struct l_key *pkey = NULL;
@@ -405,8 +611,13 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 	 * the PKCS#8/RFC5958 PrivateKeyInfo structure -- supported
 	 * directly by the pkcs8-key-parser kernel module.
 	 */
-	if (!strcmp(label, "PRIVATE KEY"))
+	if (!strcmp(label, "PRIVATE KEY")) {
+		/* RFC822 Headers explicitly disallowed in RFC7468 */
+		if (headers)
+			goto err;
+
 		goto done;
+	}
 
 	/*
 	 * RFC7468 Section 11-compatible encrypted private key label
@@ -429,6 +640,10 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 		if (!passphrase)
 			goto err;
 
+		/* RFC822 Headers explicitly disallowed in RFC7468 */
+		if (headers)
+			goto err;
+
 		/* Technically this is BER, not limited to DER */
 		key_info = asn1_der_find_elem(content, len, 0, &tag,
 						&key_info_len);
@@ -486,18 +701,10 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 	}
 
 	/*
-	 * Legacy RSA private key label aka. SSLeay format label, created
-	 * by most software but not documented in an RFC.  Encodes the
+	 * Legacy RSA private key label aka. SSLeay format, understood by
+	 * most software but not documented in an RFC.  Encodes the
 	 * PKCS#1/RFC8017 RSAPrivateKey structure.  We wrap it in a PKCS#8
 	 * PrivateKeyInfo for the pkcs8-key-parser module.
-	 *
-	 * TODO: decrypt RSA PRIVATE KEY format encrypted keys
-	 * as produced by "openssl rsa" commands.  These are incompatible
-	 * with RFC7468 parsing because of the RFC822 headers present
-	 * before base64-encoded data.  The format is documented in
-	 * RFC1421 and the encryption algorithms in RFC1423 although
-	 * openssl allows many more algorithms than those documented.
-	 * Then wrap in a PrivateKeyInfo like above.
 	 */
 	if (!strcmp(label, "RSA PRIVATE KEY")) {
 		const uint8_t *data;
@@ -510,6 +717,8 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 		size_t private_key_len;
 		uint8_t *one_asymmetric_key;
 		uint8_t *ptr;
+		const char *dekalgid;
+		const char *dekparameters;
 
 		static const uint8_t version0[] = {
 			ASN1_ID_INTEGER, 0x01, 0x00
@@ -521,6 +730,54 @@ static struct l_key *pem_load_private_key(uint8_t *content,
 			ASN1_ID_NULL, 0x00,
 		};
 
+		/*
+		 * "openssl rsa ..." can produce encrypted PKCS#1-formatted
+		 * keys.  These are incompatible with RFC7468 parsing because
+		 * of the RFC822 headers present but the format is the same
+		 * as documented in RFC1421.  The encryption algorithms are
+		 * supposed to be the ones defined in RFC1423 but that would
+		 * be only DES-CBC while openssl allows other algorithms.
+		 * When decrypted we get the RSAPrivateKey struct and proceed
+		 * like with the unencrypted format.
+		 */
+		dekalgid = parse_rfc1421_dek_info(headers, &dekparameters);
+		if (dekalgid) {
+			struct l_cipher *alg;
+			bool r;
+			int i;
+			size_t block_len;
+
+			if (encrypted)
+				*encrypted = true;
+
+			if (!passphrase)
+				goto err;
+
+			alg = cipher_from_dek_info(dekalgid, dekparameters,
+							passphrase, &block_len);
+			if (!alg)
+				goto err;
+
+			if (len % block_len || !len)
+				goto err;
+
+			r = l_cipher_decrypt(alg, content, content, len);
+			l_cipher_free(alg);
+
+			if (!r)
+				goto err;
+
+			/* Remove padding like in RFC1423 Section 1.1 */
+			if (content[len - 1] > block_len)
+				goto err;
+
+			for (i = 1; i < content[len - 1]; i++)
+				if (content[len - 1 - i] != content[len - 1])
+					goto err;
+
+			len -= content[len - 1];
+		}
+
 		/*
 		 * Sanity check that it's a version 0 or 1 RSAPrivateKey
 		 * structure with the 8 integers, if it's not, make a last
@@ -586,6 +843,7 @@ err:
 	}
 
 	l_free(label);
+	l_free(headers);
 	return pkey;
 }
 
@@ -597,16 +855,18 @@ LIB_EXPORT struct l_key *l_pem_load_private_key_from_data(const void *buf,
 	uint8_t *content;
 	char *label;
 	size_t len;
+	char *headers;
 
 	if (encrypted)
 		*encrypted = false;
 
-	content = pem_load_buffer(buf, buf_len, &label, &len);
+	content = pem_load_buffer(buf, buf_len, &label, &len, &headers);
 
 	if (!content)
 		return NULL;
 
-	return pem_load_private_key(content, len, label, passphrase, encrypted);
+	return pem_load_private_key(content, len, label, passphrase, headers,
+					encrypted);
 }
 
 /**
@@ -632,14 +892,16 @@ LIB_EXPORT struct l_key *l_pem_load_private_key(const char *filename,
 	uint8_t *content;
 	char *label;
 	size_t len;
+	char *headers;
 
 	if (encrypted)
 		*encrypted = false;
 
-	content = l_pem_load_file(filename, &label, &len);
+	content = pem_load_file(filename, &label, &len, &headers);
 
 	if (!content)
 		return NULL;
 
-	return pem_load_private_key(content, len, label, passphrase, encrypted);
+	return pem_load_private_key(content, len, label, passphrase, headers,
+					encrypted);
 }
-- 
2.25.1

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

* [PATCH 3/5] examples: More error messages in https-{client, server}-test
  2020-11-21  2:48 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 2/5] pem: Decrypt PKCS#1 encrypted " Andrew Zaborowski
@ 2020-11-21  2:48 ` Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 4/5] treewide: Rename test private keys to include format Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 5/5] unit: Test loading PKCS#1 PEM private key files Andrew Zaborowski
  3 siblings, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-21  2:48 UTC (permalink / raw)
  To: ell

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

Change the error messages to go to stderr and add messages on
certificate and key loading errors.
---
 examples/https-client-test.c | 39 ++++++++++++++++++++++++--------
 examples/https-server-test.c | 44 ++++++++++++++++++++++++------------
 2 files changed, 59 insertions(+), 24 deletions(-)

diff --git a/examples/https-client-test.c b/examples/https-client-test.c
index eaa7900..2c8d020 100644
--- a/examples/https-client-test.c
+++ b/examples/https-client-test.c
@@ -67,7 +67,7 @@ static void https_tls_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
 	if (reason)
-		printf("TLS error: %s\n", l_tls_alert_to_str(reason));
+		fprintf(stderr, "TLS error: %s\n", l_tls_alert_to_str(reason));
 	l_main_quit();
 }
 
@@ -137,6 +137,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *cert = NULL;
 	struct l_key *priv_key = NULL;
 	struct l_queue *ca_cert = NULL;
+	bool encrypted;
 
 	if (argc != 2 && argc != 3 && argc != 6) {
 		printf("Usage: %s <https-host-name> [<ca-cert-path> "
@@ -153,19 +154,19 @@ int main(int argc, char *argv[])
 	hostname = argv[1];
 	he = gethostbyname(hostname);
 	if (!he) {
-		printf("gethostbyname: %s\n", strerror(errno));
+		fprintf(stderr, "gethostbyname: %s\n", strerror(errno));
 		return -1;
 	}
 
 	addr_list = (struct in_addr **) he->h_addr_list;
 	if (!addr_list) {
-		printf("No host addresses found\n");
+		fprintf(stderr, "No host addresses found\n");
 		return -1;
 	}
 
 	fd = socket(AF_INET, SOCK_STREAM, 0);
 	if (fd < 0) {
-		printf("socket: %s\n", strerror(errno));
+		fprintf(stderr, "socket: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -174,7 +175,7 @@ int main(int argc, char *argv[])
 	addr.sin_port = htons(443);
 	memcpy(&addr.sin_addr, addr_list[0], sizeof(addr.sin_addr));
 	if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		printf("connect: %s\n", strerror(errno));
+		fprintf(stderr, "connect: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -192,14 +193,32 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	if (argc >= 3)
+	if (argc >= 3) {
 		ca_cert = l_pem_load_certificate_list(argv[2]);
+		if (!cert) {
+			fprintf(stderr, "Couldn't load the CA certificates\n");
+			return -1;
+		}
+	}
 
-	if (argc >= 4)
+	if (argc >= 4) {
 		cert = l_pem_load_certificate_chain(argv[3]);
+		if (!cert) {
+			fprintf(stderr,
+				"Couldn't load the server certificate\n");
+			return -1;
+		}
+	}
 
-	if (argc >= 6)
-		priv_key = l_pem_load_private_key(argv[4], argv[5], NULL);
+	if (argc >= 6) {
+		priv_key = l_pem_load_private_key(argv[4], argv[5], &encrypted);
+		if (!priv_key) {
+			fprintf(stderr,
+				"Couldn't load the client private key%s\n",
+				encrypted ? " (encrypted)" : "");
+			return -1;
+		}
+	}
 
 	auth_ok = (argc <= 2 || l_tls_set_cacert(tls, ca_cert)) &&
 		(argc <= 5 ||
@@ -209,7 +228,7 @@ int main(int argc, char *argv[])
 	if (tls && auth_ok)
 		l_main_run();
 	else {
-		printf("TLS setup failed\n");
+		fprintf(stderr, "TLS setup failed\n");
 		l_queue_destroy(ca_cert, (l_queue_destroy_func_t) l_cert_free);
 		l_certchain_free(cert);
 		l_key_free(priv_key);
diff --git a/examples/https-server-test.c b/examples/https-server-test.c
index 2512601..8f3cb3c 100644
--- a/examples/https-server-test.c
+++ b/examples/https-server-test.c
@@ -42,7 +42,7 @@ bool served;
 static void https_io_disconnect(struct l_io *io, void *user_data)
 {
 	if (!served)
-		printf("Disconnected before serving a page\n");
+		fprintf(stderr, "Disconnected before serving a page\n");
 	l_main_quit();
 }
 
@@ -54,7 +54,7 @@ static bool https_io_read(struct l_io *io, void *user_data)
 	l = read(l_io_get_fd(io), buf, sizeof(buf));
 	if (l == 0) {
 		if (!served)
-			printf("EOF before serving a page\n");
+			fprintf(stderr, "EOF before serving a page\n");
 		l_main_quit();
 	} else if (l > 0)
 		l_tls_handle_rx(tls, buf, l);
@@ -66,7 +66,7 @@ static void https_tls_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
 	if (reason)
-		printf("TLS error: %s\n", l_tls_alert_to_str(reason));
+		fprintf(stderr, "TLS error: %s\n", l_tls_alert_to_str(reason));
 	l_main_quit();
 }
 
@@ -93,7 +93,7 @@ static void https_tls_write(const uint8_t *data, size_t len, void *user_data)
 	while (len) {
 		r = send(l_io_get_fd(io), data, len, MSG_NOSIGNAL);
 		if (r < 0) {
-			printf("send: %s\n", strerror(errno));
+			fprintf(stderr, "send: %s\n", strerror(errno));
 			l_main_quit();
 			break;
 		}
@@ -123,6 +123,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *cert;
 	struct l_key *priv_key;
 	struct l_queue *ca_cert = NULL;
+	bool encrypted;
 
 	if (argc != 4 && argc != 5) {
 		printf("Usage: %s <server-cert-path> <server-key-path> "
@@ -146,11 +147,11 @@ int main(int argc, char *argv[])
 	addr.sin_port = htons(1234);
 
 	if (bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
-		printf("bind: %s\n", strerror(errno));
+		fprintf(stderr, "bind: %s\n", strerror(errno));
 		return -1;
 	}
 	if (listen(listenfd, 1) == -1) {
-		printf("listen: %s\n", strerror(errno));
+		fprintf(stderr, "listen: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -159,13 +160,34 @@ int main(int argc, char *argv[])
 	fd = accept(listenfd, NULL, NULL);
 	close(listenfd);
 	if (fd == -1) {
-		printf("accept: %s\n", strerror(errno));
+		fprintf(stderr, "accept: %s\n", strerror(errno));
 		return -1;
 	}
 
 	if (!l_main_init())
 		return -1;
 
+	cert = l_pem_load_certificate_chain(argv[1]);
+	if (!cert) {
+		fprintf(stderr, "Couldn't load the server certificate\n");
+		return -1;
+	}
+
+	priv_key = l_pem_load_private_key(argv[2], argv[3], &encrypted);
+	if (!priv_key) {
+		fprintf(stderr, "Couldn't load the server private key%s\n",
+			encrypted ? " (encrypted)" : "");
+		return -1;
+	}
+
+	if (argc >= 5) {
+		ca_cert = l_pem_load_certificate_list(argv[4]);
+		if (!ca_cert) {
+			fprintf(stderr, "Couldn't load the CA certificates\n");
+			return -1;
+		}
+	}
+
 	io = l_io_new(fd);
 	l_io_set_close_on_destroy(io, true);
 	l_io_set_read_handler(io, https_io_read, tls, NULL);
@@ -177,12 +199,6 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	cert = l_pem_load_certificate_chain(argv[1]);
-	priv_key = l_pem_load_private_key(argv[2], argv[3], NULL);
-
-	if (argc >= 5)
-		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);
@@ -190,7 +206,7 @@ int main(int argc, char *argv[])
 	if (tls && auth_ok)
 		l_main_run();
 	else {
-		printf("TLS setup failed\n");
+		fprintf(stderr, "TLS setup failed\n");
 		l_queue_destroy(ca_cert, (l_queue_destroy_func_t) l_cert_free);
 		l_certchain_free(cert);
 		l_key_free(priv_key);
-- 
2.25.1

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

* [PATCH 4/5] treewide: Rename test private keys to include format
  2020-11-21  2:48 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 2/5] pem: Decrypt PKCS#1 encrypted " Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 3/5] examples: More error messages in https-{client, server}-test Andrew Zaborowski
@ 2020-11-21  2:48 ` Andrew Zaborowski
  2020-11-21  2:48 ` [PATCH 5/5] unit: Test loading PKCS#1 PEM private key files Andrew Zaborowski
  3 siblings, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-21  2:48 UTC (permalink / raw)
  To: ell

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

Include pkcs1 or pkcs8 in the names of the test client private keys.
---
 Makefile.am     | 39 ++++++++++++++++++++-------------------
 unit/test-pem.c | 17 +++++++++--------
 2 files changed, 29 insertions(+), 27 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index e358546..546a6aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,15 +211,16 @@ cert_tests = unit/test-pem \
 cert_files = unit/cert-chain.pem \
 			unit/cert-entity-int.pem \
 			unit/cert-server.pem \
-			unit/cert-client.pem \
 			unit/cert-server-key-pkcs8.pem \
+			unit/cert-client.pem \
+			unit/cert-client-key-pkcs1.pem \
 			unit/cert-client-key-pkcs8.pem \
-			unit/cert-client-key-md5-des.pem \
-			unit/cert-client-key-sha1-des.pem \
-			unit/cert-client-key-v2-des.pem \
-			unit/cert-client-key-v2-des-ede3.pem \
-			unit/cert-client-key-v2-aes128.pem \
-			unit/cert-client-key-v2-aes256.pem \
+			unit/cert-client-key-pkcs8-md5-des.pem \
+			unit/cert-client-key-pkcs8-sha1-des.pem \
+			unit/cert-client-key-pkcs8-v2-des.pem \
+			unit/cert-client-key-pkcs8-v2-des-ede3.pem \
+			unit/cert-client-key-pkcs8-v2-aes128.pem \
+			unit/cert-client-key-pkcs8-v2-aes256.pem \
 			unit/cert-no-keyid.pem
 
 cert_checks = unit/cert-intca \
@@ -416,37 +417,37 @@ unit/cert-server.pem: unit/cert-server.csr unit/cert-ca.pem unit/gencerts.cnf
 unit/cert-server: unit/cert-server.pem unit/cert-ca.pem
 	$(AM_V_GEN)openssl verify -CAfile $(builddir)/unit/cert-ca.pem $<
 
-unit/cert-client-key.pem:
+unit/cert-client-key-pkcs1.pem:
 	$(AM_V_GEN)openssl genrsa -out $@ $($(AM_V_P)_redirect_openssl)
 
-unit/cert-client-key-pkcs8.pem: unit/cert-client-key.pem
+unit/cert-client-key-pkcs8.pem: unit/cert-client-key-pkcs1.pem
 	$(AM_V_GEN)openssl pkcs8 -topk8 -nocrypt -in $< -out $@
 
-unit/cert-client-key-md5-des.pem: unit/cert-client-key-pkcs8.pem
+unit/cert-client-key-pkcs8-md5-des.pem: unit/cert-client-key-pkcs8.pem
 	$(AM_V_GEN)openssl pkcs8 -in $< -out $@ \
 			-topk8 -v1 PBE-MD5-DES -passout pass:abc
 
-unit/cert-client-key-sha1-des.pem: unit/cert-client-key-pkcs8.pem
+unit/cert-client-key-pkcs8-sha1-des.pem: unit/cert-client-key-pkcs8.pem
 	$(AM_V_GEN)openssl pkcs8 -in $< -out $@ \
 			-topk8 -v1 PBE-SHA1-DES -passout pass:abc
 
-unit/cert-client-key-v2-des.pem: unit/cert-client-key-pkcs8.pem
+unit/cert-client-key-pkcs8-v2-des.pem: unit/cert-client-key-pkcs8.pem
 	$(AM_V_GEN)openssl pkcs8 -in $< -out $@ \
 			-topk8 -v2 des-cbc -v2prf hmacWithSHA1 -passout pass:abc
 
-unit/cert-client-key-v2-des-ede3.pem: unit/cert-client-key-pkcs8.pem
+unit/cert-client-key-pkcs8-v2-des-ede3.pem: unit/cert-client-key-pkcs8.pem
 	$(AM_V_GEN)openssl pkcs8 -in $< -out $@ \
 			-topk8 -v2 des-ede3-cbc -v2prf hmacWithSHA224 -passout pass:abc
 
-unit/cert-client-key-v2-aes128.pem: unit/cert-client-key-pkcs8.pem
+unit/cert-client-key-pkcs8-v2-aes128.pem: unit/cert-client-key-pkcs8.pem
 	$(AM_V_GEN)openssl pkcs8 -in $< -out $@ \
 			-topk8 -v2 aes128 -v2prf hmacWithSHA256 -passout pass:abc
 
-unit/cert-client-key-v2-aes256.pem: unit/cert-client-key-pkcs8.pem
+unit/cert-client-key-pkcs8-v2-aes256.pem: unit/cert-client-key-pkcs8.pem
 	$(AM_V_GEN)openssl pkcs8 -in $< -out $@ \
 			-topk8 -v2 aes256 -v2prf hmacWithSHA512 -passout pass:abc
 
-unit/cert-client.csr: unit/cert-client-key.pem unit/gencerts.cnf
+unit/cert-client.csr: unit/cert-client-key-pkcs1.pem unit/gencerts.cnf
 	$(AM_V_GEN)openssl req -new -extensions cert_ext \
 			-config $(srcdir)/unit/gencerts.cnf \
 			-subj '/O=Bar Example Organization/CN=Bar Example Organization/emailAddress=bar(a)mail.example' \
@@ -512,7 +513,7 @@ unit/cert-ca2.pem: unit/cert-ca-key.pem unit/gencerts.cnf
 			-subj '/O=International Union of Example Organizations/CN=Certificate issuer guy/emailAddress=ca-no-akid(a)mail.example' \
 			-key $< -sha256 -days 10000 -out $@
 
-unit/cert-no-keyid.csr: unit/cert-client-key.pem unit/gencerts.cnf
+unit/cert-no-keyid.csr: unit/cert-client-key-pkcs1.pem unit/gencerts.cnf
 	$(AM_V_GEN)openssl req -new \
 			-config $(srcdir)/unit/gencerts.cnf \
 			-subj '/O=Baz Example Organization/CN=Baz Example Organization/emailAddress=baz@mail.example' \
@@ -539,9 +540,9 @@ unit/key-ciphertext.dat: unit/plaintext.txt unit/cert-client.pem
 unit/key-ciphertext.h: unit/key-ciphertext.dat
 	$(AM_V_GEN)xxd -i < $< > $@
 
-unit/key-signature.dat: unit/plaintext.txt unit/cert-client-key.pem
+unit/key-signature.dat: unit/plaintext.txt unit/cert-client-key-pkcs1.pem
 	$(AM_V_GEN)openssl rsautl -sign -pkcs -in $< \
-			-inkey $(builddir)/unit/cert-client-key.pem -out $@
+			-inkey $(builddir)/unit/cert-client-key-pkcs1.pem -out $@
 
 unit/key-signature.h: unit/key-signature.dat
 	$(AM_V_GEN)xxd -i < $< > $@
diff --git a/unit/test-pem.c b/unit/test-pem.c
index a1e8110..e81ddde 100644
--- a/unit/test-pem.c
+++ b/unit/test-pem.c
@@ -326,18 +326,19 @@ int main(int argc, char *argv[])
 
 	l_test_add("pem/v1 MD5AndDES encrypted Private Key",
 			test_encrypted_pkey,
-			CERTDIR "cert-client-key-md5-des.pem");
+			CERTDIR "cert-client-key-pkcs8-md5-des.pem");
 	l_test_add("pem/v1 SHA1AndDES encrypted Private Key",
 			test_encrypted_pkey,
-			CERTDIR "cert-client-key-sha1-des.pem");
+			CERTDIR "cert-client-key-pkcs8-sha1-des.pem");
 	l_test_add("pem/v2 DES encrypted Private Key", test_encrypted_pkey,
-			CERTDIR "cert-client-key-v2-des.pem");
+			CERTDIR "cert-client-key-pkcs8-v2-des.pem");
 
 	if (l_cipher_is_supported(L_CIPHER_DES3_EDE_CBC) &&
-			l_checksum_is_supported(L_CHECKSUM_SHA224, false))
+			l_checksum_is_supported(L_CHECKSUM_SHA224, false)) {
 		l_test_add("pem/v2 DES EDE3 encrypted Private Key",
-				test_encrypted_pkey,
-				CERTDIR "cert-client-key-v2-des-ede3.pem");
+				test_encrypted_pkey, CERTDIR
+				"cert-client-key-pkcs8-v2-des-ede3.pem");
+	}
 
 	if (!l_cipher_is_supported(L_CIPHER_AES))
 		goto done;
@@ -345,12 +346,12 @@ int main(int argc, char *argv[])
 	if (l_checksum_is_supported(L_CHECKSUM_SHA256, false))
 		l_test_add("pem/v2 AES128 encrypted Private Key",
 				test_encrypted_pkey,
-				CERTDIR "cert-client-key-v2-aes128.pem");
+				CERTDIR "cert-client-key-pkcs8-v2-aes128.pem");
 
 	if (l_checksum_is_supported(L_CHECKSUM_SHA512, false))
 		l_test_add("pem/v2 AES256 encrypted Private Key",
 				test_encrypted_pkey,
-				CERTDIR "cert-client-key-v2-aes256.pem");
+				CERTDIR "cert-client-key-pkcs8-v2-aes256.pem");
 
 done:
 	return l_test_run();
-- 
2.25.1

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

* [PATCH 5/5] unit: Test loading PKCS#1 PEM private key files
  2020-11-21  2:48 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
                   ` (2 preceding siblings ...)
  2020-11-21  2:48 ` [PATCH 4/5] treewide: Rename test private keys to include format Andrew Zaborowski
@ 2020-11-21  2:48 ` Andrew Zaborowski
  3 siblings, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-21  2:48 UTC (permalink / raw)
  To: ell

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

---
 Makefile.am     | 20 ++++++++++++++
 unit/test-pem.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 546a6aa..28082aa 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -214,6 +214,11 @@ cert_files = unit/cert-chain.pem \
 			unit/cert-server-key-pkcs8.pem \
 			unit/cert-client.pem \
 			unit/cert-client-key-pkcs1.pem \
+			unit/cert-client-key-pkcs1-des.pem \
+			unit/cert-client-key-pkcs1-des3.pem \
+			unit/cert-client-key-pkcs1-aes128.pem \
+			unit/cert-client-key-pkcs1-aes192.pem \
+			unit/cert-client-key-pkcs1-aes256.pem \
 			unit/cert-client-key-pkcs8.pem \
 			unit/cert-client-key-pkcs8-md5-des.pem \
 			unit/cert-client-key-pkcs8-sha1-des.pem \
@@ -420,6 +425,21 @@ unit/cert-server: unit/cert-server.pem unit/cert-ca.pem
 unit/cert-client-key-pkcs1.pem:
 	$(AM_V_GEN)openssl genrsa -out $@ $($(AM_V_P)_redirect_openssl)
 
+unit/cert-client-key-pkcs1-des.pem: unit/cert-client-key-pkcs1.pem
+	$(AM_V_GEN)openssl rsa -in $< -out $@ -des -passout pass:abc
+
+unit/cert-client-key-pkcs1-des3.pem: unit/cert-client-key-pkcs1.pem
+	$(AM_V_GEN)openssl rsa -in $< -out $@ -des3 -passout pass:abc
+
+unit/cert-client-key-pkcs1-aes128.pem: unit/cert-client-key-pkcs1.pem
+	$(AM_V_GEN)openssl rsa -in $< -out $@ -aes128 -passout pass:abc
+
+unit/cert-client-key-pkcs1-aes192.pem: unit/cert-client-key-pkcs1.pem
+	$(AM_V_GEN)openssl rsa -in $< -out $@ -aes192 -passout pass:abc
+
+unit/cert-client-key-pkcs1-aes256.pem: unit/cert-client-key-pkcs1.pem
+	$(AM_V_GEN)openssl rsa -in $< -out $@ -aes256 -passout pass:abc
+
 unit/cert-client-key-pkcs8.pem: unit/cert-client-key-pkcs1.pem
 	$(AM_V_GEN)openssl pkcs8 -topk8 -nocrypt -in $< -out $@
 
diff --git a/unit/test-pem.c b/unit/test-pem.c
index e81ddde..2702665 100644
--- a/unit/test-pem.c
+++ b/unit/test-pem.c
@@ -257,6 +257,39 @@ static void test_pem(const void *data)
 	l_free(decoded);
 }
 
+static void test_unencrypted_pkey(const void *data)
+{
+	const char *pkcs1_pem = CERTDIR "cert-client-key-pkcs1.pem";
+	const char *pkcs8_pem = CERTDIR "cert-client-key-pkcs8.pem";
+	bool is_encrypted;
+	size_t size;
+	uint8_t encrypted1[256], encrypted2[256], plaintext[256];
+	struct l_key *pkey1, *pkey2;
+	bool is_public;
+
+	pkey1 = l_pem_load_private_key(pkcs1_pem, NULL, &is_encrypted);
+	assert(pkey1);
+	assert(!is_encrypted);
+
+	pkey2 = l_pem_load_private_key(pkcs8_pem, NULL, &is_encrypted);
+	assert(pkey2);
+	assert(!is_encrypted);
+
+	memset(plaintext, 42, 256);
+	assert(l_key_get_info(pkey1, L_KEY_RSA_RAW, L_CHECKSUM_NONE,
+				&size, &is_public));
+	assert(size == 2048);
+	assert(!is_public);
+	assert(l_key_encrypt(pkey1, L_KEY_RSA_RAW, L_CHECKSUM_NONE,
+				plaintext, encrypted1, 256, 256) == 256);
+	assert(l_key_encrypt(pkey2, L_KEY_RSA_RAW, L_CHECKSUM_NONE,
+				plaintext, encrypted2, 256, 256) == 256);
+	assert(!memcmp(encrypted1, encrypted2, 256));
+
+	l_key_free(pkey1);
+	l_key_free(pkey2);
+}
+
 static void test_encrypted_pkey(const void *data)
 {
 	const char *encrypted_pem = data;
@@ -324,6 +357,9 @@ int main(int argc, char *argv[])
 			!l_key_is_supported(L_KEY_FEATURE_CRYPTO))
 		goto done;
 
+	l_test_add("pem/PKCS#1 vs. PKCS#8 unenecrypted Private Key",
+			test_unencrypted_pkey, NULL);
+
 	l_test_add("pem/v1 MD5AndDES encrypted Private Key",
 			test_encrypted_pkey,
 			CERTDIR "cert-client-key-pkcs8-md5-des.pem");
@@ -340,18 +376,38 @@ int main(int argc, char *argv[])
 				"cert-client-key-pkcs8-v2-des-ede3.pem");
 	}
 
-	if (!l_cipher_is_supported(L_CIPHER_AES))
-		goto done;
-
-	if (l_checksum_is_supported(L_CHECKSUM_SHA256, false))
-		l_test_add("pem/v2 AES128 encrypted Private Key",
+	if (l_cipher_is_supported(L_CIPHER_AES)) {
+		if (l_checksum_is_supported(L_CHECKSUM_SHA256, false))
+			l_test_add("pem/v2 AES128-encrypted Private Key",
 				test_encrypted_pkey,
 				CERTDIR "cert-client-key-pkcs8-v2-aes128.pem");
 
-	if (l_checksum_is_supported(L_CHECKSUM_SHA512, false))
-		l_test_add("pem/v2 AES256 encrypted Private Key",
+		if (l_checksum_is_supported(L_CHECKSUM_SHA512, false))
+			l_test_add("pem/v2 AES256-encrypted Private Key",
 				test_encrypted_pkey,
 				CERTDIR "cert-client-key-pkcs8-v2-aes256.pem");
+	}
+
+	l_test_add("pem/PKCS#1 DES-encrypted RSA Private Key",
+			test_encrypted_pkey,
+			CERTDIR "cert-client-key-pkcs1-des.pem");
+
+	if (l_cipher_is_supported(L_CIPHER_DES3_EDE_CBC))
+		l_test_add("pem/PKCS#1 DES-EDE3-encrypted RSA Private Key",
+				test_encrypted_pkey,
+				CERTDIR "cert-client-key-pkcs1-des3.pem");
+
+	if (l_cipher_is_supported(L_CIPHER_AES_CBC)) {
+		l_test_add("pem/PKCS#1 AES128-encrypted RSA Private Key",
+				test_encrypted_pkey,
+				CERTDIR "cert-client-key-pkcs1-aes128.pem");
+		l_test_add("pem/PKCS#1 AES192-encrypted RSA Private Key",
+				test_encrypted_pkey,
+				CERTDIR "cert-client-key-pkcs1-aes192.pem");
+		l_test_add("pem/PKCS#1 AES256-encrypted RSA Private Key",
+				test_encrypted_pkey,
+				CERTDIR "cert-client-key-pkcs1-aes256.pem");
+	}
 
 done:
 	return l_test_run();
-- 
2.25.1

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

* [PATCH 3/5] examples: More error messages in https-{client, server}-test
  2020-11-23 11:54 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
@ 2020-11-23 11:54 ` Andrew Zaborowski
  0 siblings, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-23 11:54 UTC (permalink / raw)
  To: ell

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

Change the error messages to go to stderr and add messages on
certificate and key loading errors.
---
 examples/https-client-test.c | 39 ++++++++++++++++++++++++--------
 examples/https-server-test.c | 44 ++++++++++++++++++++++++------------
 2 files changed, 59 insertions(+), 24 deletions(-)

diff --git a/examples/https-client-test.c b/examples/https-client-test.c
index eaa7900..2c8d020 100644
--- a/examples/https-client-test.c
+++ b/examples/https-client-test.c
@@ -67,7 +67,7 @@ static void https_tls_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
 	if (reason)
-		printf("TLS error: %s\n", l_tls_alert_to_str(reason));
+		fprintf(stderr, "TLS error: %s\n", l_tls_alert_to_str(reason));
 	l_main_quit();
 }
 
@@ -137,6 +137,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *cert = NULL;
 	struct l_key *priv_key = NULL;
 	struct l_queue *ca_cert = NULL;
+	bool encrypted;
 
 	if (argc != 2 && argc != 3 && argc != 6) {
 		printf("Usage: %s <https-host-name> [<ca-cert-path> "
@@ -153,19 +154,19 @@ int main(int argc, char *argv[])
 	hostname = argv[1];
 	he = gethostbyname(hostname);
 	if (!he) {
-		printf("gethostbyname: %s\n", strerror(errno));
+		fprintf(stderr, "gethostbyname: %s\n", strerror(errno));
 		return -1;
 	}
 
 	addr_list = (struct in_addr **) he->h_addr_list;
 	if (!addr_list) {
-		printf("No host addresses found\n");
+		fprintf(stderr, "No host addresses found\n");
 		return -1;
 	}
 
 	fd = socket(AF_INET, SOCK_STREAM, 0);
 	if (fd < 0) {
-		printf("socket: %s\n", strerror(errno));
+		fprintf(stderr, "socket: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -174,7 +175,7 @@ int main(int argc, char *argv[])
 	addr.sin_port = htons(443);
 	memcpy(&addr.sin_addr, addr_list[0], sizeof(addr.sin_addr));
 	if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		printf("connect: %s\n", strerror(errno));
+		fprintf(stderr, "connect: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -192,14 +193,32 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	if (argc >= 3)
+	if (argc >= 3) {
 		ca_cert = l_pem_load_certificate_list(argv[2]);
+		if (!cert) {
+			fprintf(stderr, "Couldn't load the CA certificates\n");
+			return -1;
+		}
+	}
 
-	if (argc >= 4)
+	if (argc >= 4) {
 		cert = l_pem_load_certificate_chain(argv[3]);
+		if (!cert) {
+			fprintf(stderr,
+				"Couldn't load the server certificate\n");
+			return -1;
+		}
+	}
 
-	if (argc >= 6)
-		priv_key = l_pem_load_private_key(argv[4], argv[5], NULL);
+	if (argc >= 6) {
+		priv_key = l_pem_load_private_key(argv[4], argv[5], &encrypted);
+		if (!priv_key) {
+			fprintf(stderr,
+				"Couldn't load the client private key%s\n",
+				encrypted ? " (encrypted)" : "");
+			return -1;
+		}
+	}
 
 	auth_ok = (argc <= 2 || l_tls_set_cacert(tls, ca_cert)) &&
 		(argc <= 5 ||
@@ -209,7 +228,7 @@ int main(int argc, char *argv[])
 	if (tls && auth_ok)
 		l_main_run();
 	else {
-		printf("TLS setup failed\n");
+		fprintf(stderr, "TLS setup failed\n");
 		l_queue_destroy(ca_cert, (l_queue_destroy_func_t) l_cert_free);
 		l_certchain_free(cert);
 		l_key_free(priv_key);
diff --git a/examples/https-server-test.c b/examples/https-server-test.c
index 2512601..8f3cb3c 100644
--- a/examples/https-server-test.c
+++ b/examples/https-server-test.c
@@ -42,7 +42,7 @@ bool served;
 static void https_io_disconnect(struct l_io *io, void *user_data)
 {
 	if (!served)
-		printf("Disconnected before serving a page\n");
+		fprintf(stderr, "Disconnected before serving a page\n");
 	l_main_quit();
 }
 
@@ -54,7 +54,7 @@ static bool https_io_read(struct l_io *io, void *user_data)
 	l = read(l_io_get_fd(io), buf, sizeof(buf));
 	if (l == 0) {
 		if (!served)
-			printf("EOF before serving a page\n");
+			fprintf(stderr, "EOF before serving a page\n");
 		l_main_quit();
 	} else if (l > 0)
 		l_tls_handle_rx(tls, buf, l);
@@ -66,7 +66,7 @@ static void https_tls_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
 	if (reason)
-		printf("TLS error: %s\n", l_tls_alert_to_str(reason));
+		fprintf(stderr, "TLS error: %s\n", l_tls_alert_to_str(reason));
 	l_main_quit();
 }
 
@@ -93,7 +93,7 @@ static void https_tls_write(const uint8_t *data, size_t len, void *user_data)
 	while (len) {
 		r = send(l_io_get_fd(io), data, len, MSG_NOSIGNAL);
 		if (r < 0) {
-			printf("send: %s\n", strerror(errno));
+			fprintf(stderr, "send: %s\n", strerror(errno));
 			l_main_quit();
 			break;
 		}
@@ -123,6 +123,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *cert;
 	struct l_key *priv_key;
 	struct l_queue *ca_cert = NULL;
+	bool encrypted;
 
 	if (argc != 4 && argc != 5) {
 		printf("Usage: %s <server-cert-path> <server-key-path> "
@@ -146,11 +147,11 @@ int main(int argc, char *argv[])
 	addr.sin_port = htons(1234);
 
 	if (bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
-		printf("bind: %s\n", strerror(errno));
+		fprintf(stderr, "bind: %s\n", strerror(errno));
 		return -1;
 	}
 	if (listen(listenfd, 1) == -1) {
-		printf("listen: %s\n", strerror(errno));
+		fprintf(stderr, "listen: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -159,13 +160,34 @@ int main(int argc, char *argv[])
 	fd = accept(listenfd, NULL, NULL);
 	close(listenfd);
 	if (fd == -1) {
-		printf("accept: %s\n", strerror(errno));
+		fprintf(stderr, "accept: %s\n", strerror(errno));
 		return -1;
 	}
 
 	if (!l_main_init())
 		return -1;
 
+	cert = l_pem_load_certificate_chain(argv[1]);
+	if (!cert) {
+		fprintf(stderr, "Couldn't load the server certificate\n");
+		return -1;
+	}
+
+	priv_key = l_pem_load_private_key(argv[2], argv[3], &encrypted);
+	if (!priv_key) {
+		fprintf(stderr, "Couldn't load the server private key%s\n",
+			encrypted ? " (encrypted)" : "");
+		return -1;
+	}
+
+	if (argc >= 5) {
+		ca_cert = l_pem_load_certificate_list(argv[4]);
+		if (!ca_cert) {
+			fprintf(stderr, "Couldn't load the CA certificates\n");
+			return -1;
+		}
+	}
+
 	io = l_io_new(fd);
 	l_io_set_close_on_destroy(io, true);
 	l_io_set_read_handler(io, https_io_read, tls, NULL);
@@ -177,12 +199,6 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	cert = l_pem_load_certificate_chain(argv[1]);
-	priv_key = l_pem_load_private_key(argv[2], argv[3], NULL);
-
-	if (argc >= 5)
-		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);
@@ -190,7 +206,7 @@ int main(int argc, char *argv[])
 	if (tls && auth_ok)
 		l_main_run();
 	else {
-		printf("TLS setup failed\n");
+		fprintf(stderr, "TLS setup failed\n");
 		l_queue_destroy(ca_cert, (l_queue_destroy_func_t) l_cert_free);
 		l_certchain_free(cert);
 		l_key_free(priv_key);
-- 
2.27.0

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

* [PATCH 3/5] examples: More error messages in https-{client, server}-test
  2020-11-20 20:28 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
@ 2020-11-20 20:28 ` Andrew Zaborowski
  0 siblings, 0 replies; 7+ messages in thread
From: Andrew Zaborowski @ 2020-11-20 20:28 UTC (permalink / raw)
  To: ell

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

Change the error messages to go to stderr and add messages on
certificate and key loading errors.
---
 examples/https-client-test.c | 39 ++++++++++++++++++++++++--------
 examples/https-server-test.c | 44 ++++++++++++++++++++++++------------
 2 files changed, 59 insertions(+), 24 deletions(-)

diff --git a/examples/https-client-test.c b/examples/https-client-test.c
index eaa7900..2c8d020 100644
--- a/examples/https-client-test.c
+++ b/examples/https-client-test.c
@@ -67,7 +67,7 @@ static void https_tls_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
 	if (reason)
-		printf("TLS error: %s\n", l_tls_alert_to_str(reason));
+		fprintf(stderr, "TLS error: %s\n", l_tls_alert_to_str(reason));
 	l_main_quit();
 }
 
@@ -137,6 +137,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *cert = NULL;
 	struct l_key *priv_key = NULL;
 	struct l_queue *ca_cert = NULL;
+	bool encrypted;
 
 	if (argc != 2 && argc != 3 && argc != 6) {
 		printf("Usage: %s <https-host-name> [<ca-cert-path> "
@@ -153,19 +154,19 @@ int main(int argc, char *argv[])
 	hostname = argv[1];
 	he = gethostbyname(hostname);
 	if (!he) {
-		printf("gethostbyname: %s\n", strerror(errno));
+		fprintf(stderr, "gethostbyname: %s\n", strerror(errno));
 		return -1;
 	}
 
 	addr_list = (struct in_addr **) he->h_addr_list;
 	if (!addr_list) {
-		printf("No host addresses found\n");
+		fprintf(stderr, "No host addresses found\n");
 		return -1;
 	}
 
 	fd = socket(AF_INET, SOCK_STREAM, 0);
 	if (fd < 0) {
-		printf("socket: %s\n", strerror(errno));
+		fprintf(stderr, "socket: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -174,7 +175,7 @@ int main(int argc, char *argv[])
 	addr.sin_port = htons(443);
 	memcpy(&addr.sin_addr, addr_list[0], sizeof(addr.sin_addr));
 	if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		printf("connect: %s\n", strerror(errno));
+		fprintf(stderr, "connect: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -192,14 +193,32 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	if (argc >= 3)
+	if (argc >= 3) {
 		ca_cert = l_pem_load_certificate_list(argv[2]);
+		if (!cert) {
+			fprintf(stderr, "Couldn't load the CA certificates\n");
+			return -1;
+		}
+	}
 
-	if (argc >= 4)
+	if (argc >= 4) {
 		cert = l_pem_load_certificate_chain(argv[3]);
+		if (!cert) {
+			fprintf(stderr,
+				"Couldn't load the server certificate\n");
+			return -1;
+		}
+	}
 
-	if (argc >= 6)
-		priv_key = l_pem_load_private_key(argv[4], argv[5], NULL);
+	if (argc >= 6) {
+		priv_key = l_pem_load_private_key(argv[4], argv[5], &encrypted);
+		if (!priv_key) {
+			fprintf(stderr,
+				"Couldn't load the client private key%s\n",
+				encrypted ? " (encrypted)" : "");
+			return -1;
+		}
+	}
 
 	auth_ok = (argc <= 2 || l_tls_set_cacert(tls, ca_cert)) &&
 		(argc <= 5 ||
@@ -209,7 +228,7 @@ int main(int argc, char *argv[])
 	if (tls && auth_ok)
 		l_main_run();
 	else {
-		printf("TLS setup failed\n");
+		fprintf(stderr, "TLS setup failed\n");
 		l_queue_destroy(ca_cert, (l_queue_destroy_func_t) l_cert_free);
 		l_certchain_free(cert);
 		l_key_free(priv_key);
diff --git a/examples/https-server-test.c b/examples/https-server-test.c
index 2512601..53a11e2 100644
--- a/examples/https-server-test.c
+++ b/examples/https-server-test.c
@@ -42,7 +42,7 @@ bool served;
 static void https_io_disconnect(struct l_io *io, void *user_data)
 {
 	if (!served)
-		printf("Disconnected before serving a page\n");
+		fprintf(stderr, "Disconnected before serving a page\n");
 	l_main_quit();
 }
 
@@ -54,7 +54,7 @@ static bool https_io_read(struct l_io *io, void *user_data)
 	l = read(l_io_get_fd(io), buf, sizeof(buf));
 	if (l == 0) {
 		if (!served)
-			printf("EOF before serving a page\n");
+			fprintf(stderr, "EOF before serving a page\n");
 		l_main_quit();
 	} else if (l > 0)
 		l_tls_handle_rx(tls, buf, l);
@@ -66,7 +66,7 @@ static void https_tls_disconnected(enum l_tls_alert_desc reason, bool remote,
 					void *user_data)
 {
 	if (reason)
-		printf("TLS error: %s\n", l_tls_alert_to_str(reason));
+		fprintf(stderr, "TLS error: %s\n", l_tls_alert_to_str(reason));
 	l_main_quit();
 }
 
@@ -93,7 +93,7 @@ static void https_tls_write(const uint8_t *data, size_t len, void *user_data)
 	while (len) {
 		r = send(l_io_get_fd(io), data, len, MSG_NOSIGNAL);
 		if (r < 0) {
-			printf("send: %s\n", strerror(errno));
+			fprintf(stderr, "send: %s\n", strerror(errno));
 			l_main_quit();
 			break;
 		}
@@ -123,6 +123,7 @@ int main(int argc, char *argv[])
 	struct l_certchain *cert;
 	struct l_key *priv_key;
 	struct l_queue *ca_cert = NULL;
+	bool encrypted;
 
 	if (argc != 4 && argc != 5) {
 		printf("Usage: %s <server-cert-path> <server-key-path> "
@@ -146,11 +147,11 @@ int main(int argc, char *argv[])
 	addr.sin_port = htons(1234);
 
 	if (bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
-		printf("bind: %s\n", strerror(errno));
+		fprintf(stderr, "bind: %s\n", strerror(errno));
 		return -1;
 	}
 	if (listen(listenfd, 1) == -1) {
-		printf("listen: %s\n", strerror(errno));
+		fprintf(stderr, "listen: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -159,13 +160,34 @@ int main(int argc, char *argv[])
 	fd = accept(listenfd, NULL, NULL);
 	close(listenfd);
 	if (fd == -1) {
-		printf("accept: %s\n", strerror(errno));
+		fprintf(stderr, "accept: %s\n", strerror(errno));
 		return -1;
 	}
 
 	if (!l_main_init())
 		return -1;
 
+	cert = l_pem_load_certificate_chain(argv[1]);
+	if (!cert) {
+		fprintf(stderr, "Couldn't load the server certificate\n");
+		return -1;
+	}
+
+	priv_key = l_pem_load_private_key(argv[2], argv[3], &encrypted);
+	if (!priv_key) {
+		fprintf(stderr, "Couldn't load the server private key%s\n",
+			encrypted ? " (encrypted)" : "");
+		return -1;
+	}
+
+	if (argc >= 5) {
+		ca_cert = l_pem_load_certificate_list(argv[4]);
+		if (!cert) {
+			fprintf(stderr, "Couldn't load the CA certificates\n");
+			return -1;
+		}
+	}
+
 	io = l_io_new(fd);
 	l_io_set_close_on_destroy(io, true);
 	l_io_set_read_handler(io, https_io_read, tls, NULL);
@@ -177,12 +199,6 @@ int main(int argc, char *argv[])
 	if (getenv("TLS_DEBUG"))
 		l_tls_set_debug(tls, https_tls_debug_cb, NULL, NULL);
 
-	cert = l_pem_load_certificate_chain(argv[1]);
-	priv_key = l_pem_load_private_key(argv[2], argv[3], NULL);
-
-	if (argc >= 5)
-		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);
@@ -190,7 +206,7 @@ int main(int argc, char *argv[])
 	if (tls && auth_ok)
 		l_main_run();
 	else {
-		printf("TLS setup failed\n");
+		fprintf(stderr, "TLS setup failed\n");
 		l_queue_destroy(ca_cert, (l_queue_destroy_func_t) l_cert_free);
 		l_certchain_free(cert);
 		l_key_free(priv_key);
-- 
2.25.1

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

end of thread, other threads:[~2020-11-23 11:54 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-21  2:48 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
2020-11-21  2:48 ` [PATCH 2/5] pem: Decrypt PKCS#1 encrypted " Andrew Zaborowski
2020-11-21  2:48 ` [PATCH 3/5] examples: More error messages in https-{client, server}-test Andrew Zaborowski
2020-11-21  2:48 ` [PATCH 4/5] treewide: Rename test private keys to include format Andrew Zaborowski
2020-11-21  2:48 ` [PATCH 5/5] unit: Test loading PKCS#1 PEM private key files Andrew Zaborowski
  -- strict thread matches above, loose matches on Subject: below --
2020-11-23 11:54 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
2020-11-23 11:54 ` [PATCH 3/5] examples: More error messages in https-{client, server}-test Andrew Zaborowski
2020-11-20 20:28 [PATCH 1/5] pem: Parse PKCS#1 formatted private keys Andrew Zaborowski
2020-11-20 20:28 ` [PATCH 3/5] examples: More error messages in https-{client, server}-test Andrew Zaborowski

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).