* [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 5/5] unit: Test loading PKCS#1 PEM private key files
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: 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..f875adc 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.27.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/5] unit: Test loading PKCS#1 PEM private key files
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: 5225 bytes --]
---
Makefile.am | 20 ++++++++++++++
unit/test-pem.c | 71 ++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 84 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..95315fc 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,39 @@ 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
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 5/5] unit: Test loading PKCS#1 PEM private key files 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 5/5] unit: Test loading PKCS#1 PEM private key files 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).