mbedcrypto: Refactor PEM parsing

Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
(cherry picked from commit aca482a5a5)
This commit is contained in:
Jakub Jelen
2022-07-04 19:23:06 +02:00
committed by Andreas Schneider
parent 146d1a620d
commit 2564246024

View File

@@ -85,10 +85,8 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase,
ssh_auth_callback auth_fn, void *auth_data) ssh_auth_callback auth_fn, void *auth_data)
{ {
ssh_key key = NULL; ssh_key key = NULL;
mbedtls_pk_context *rsa = NULL; mbedtls_pk_context *pk = NULL;
mbedtls_pk_context *ecdsa = NULL; mbedtls_pk_type_t mbed_type;
ed25519_privkey *ed25519 = NULL;
enum ssh_keytypes_e type;
int valid; int valid;
/* mbedtls pk_parse_key expects strlen to count the 0 byte */ /* mbedtls pk_parse_key expects strlen to count the 0 byte */
size_t b64len = strlen(b64_key) + 1; size_t b64len = strlen(b64_key) + 1;
@@ -97,159 +95,100 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase,
mbedtls_ctr_drbg_context *ctr_drbg = ssh_get_mbedtls_ctr_drbg_context(); mbedtls_ctr_drbg_context *ctr_drbg = ssh_get_mbedtls_ctr_drbg_context();
#endif #endif
type = pki_privatekey_type_from_string(b64_key); pk = malloc(sizeof(mbedtls_pk_context));
if (type == SSH_KEYTYPE_UNKNOWN) { if (pk == NULL) {
SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key."); goto fail;
return NULL;
} }
mbedtls_pk_init(pk);
switch (type) { if (passphrase == NULL) {
case SSH_KEYTYPE_RSA: if (auth_fn) {
rsa = malloc(sizeof(mbedtls_pk_context)); valid = auth_fn("Passphrase for private key:",
if (rsa == NULL) { (char *)tmp,
return NULL; MAX_PASSPHRASE_SIZE,
} 0,
0,
mbedtls_pk_init(rsa); auth_data);
if (valid < 0) {
if (passphrase == NULL) {
if (auth_fn) {
valid = auth_fn("Passphrase for private key:", (char *) tmp,
MAX_PASSPHRASE_SIZE, 0, 0, auth_data);
if (valid < 0) {
goto fail;
}
/* TODO fix signedness and strlen */
#if MBEDTLS_VERSION_MAJOR > 2
valid = mbedtls_pk_parse_key(rsa,
(const unsigned char *) b64_key,
b64len, tmp,
strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE),
mbedtls_ctr_drbg_random, ctr_drbg);
#else
valid = mbedtls_pk_parse_key(rsa,
(const unsigned char *) b64_key,
b64len, tmp,
strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE));
#endif
} else {
#if MBEDTLS_VERSION_MAJOR > 2
valid = mbedtls_pk_parse_key(rsa,
(const unsigned char *) b64_key,
b64len, NULL,
0, mbedtls_ctr_drbg_random, ctr_drbg);
#else
valid = mbedtls_pk_parse_key(rsa,
(const unsigned char *) b64_key,
b64len, NULL,
0);
#endif
}
} else {
#if MBEDTLS_VERSION_MAJOR > 2
valid = mbedtls_pk_parse_key(rsa,
(const unsigned char *) b64_key, b64len,
(const unsigned char *) passphrase,
strnlen(passphrase, MAX_PASSPHRASE_SIZE),
mbedtls_ctr_drbg_random, ctr_drbg);
#else
valid = mbedtls_pk_parse_key(rsa,
(const unsigned char *) b64_key, b64len,
(const unsigned char *) passphrase,
strnlen(passphrase, MAX_PASSPHRASE_SIZE));
#endif
}
if (valid != 0) {
char error_buf[100];
mbedtls_strerror(valid, error_buf, 100);
SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf);
goto fail; goto fail;
} }
break;
case SSH_KEYTYPE_ECDSA_P256:
case SSH_KEYTYPE_ECDSA_P384:
case SSH_KEYTYPE_ECDSA_P521:
#if MBEDTLS_VERSION_MAJOR > 2 #if MBEDTLS_VERSION_MAJOR > 2
ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); valid = mbedtls_pk_parse_key(
pk,
(const unsigned char *)b64_key,
b64len,
tmp,
strnlen((const char *)tmp, MAX_PASSPHRASE_SIZE),
mbedtls_ctr_drbg_random,
ctr_drbg);
#else #else
ecdsa = malloc(sizeof(mbedtls_pk_context)); valid = mbedtls_pk_parse_key(
pk,
(const unsigned char *)b64_key,
b64len,
tmp,
strnlen((const char *)tmp, MAX_PASSPHRASE_SIZE));
#endif #endif
if (ecdsa == NULL) { } else {
return NULL;
}
mbedtls_pk_init(ecdsa);
if (passphrase == NULL) {
if (auth_fn) {
valid = auth_fn("Passphrase for private key:", (char *) tmp,
MAX_PASSPHRASE_SIZE, 0, 0, auth_data);
if (valid < 0) {
goto fail;
}
#if MBEDTLS_VERSION_MAJOR > 2 #if MBEDTLS_VERSION_MAJOR > 2
valid = mbedtls_pk_parse_key(ecdsa, valid = mbedtls_pk_parse_key(pk,
(const unsigned char *) b64_key, (const unsigned char *)b64_key,
b64len, tmp, b64len,
strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE), NULL,
mbedtls_ctr_drbg_random, ctr_drbg); 0,
mbedtls_ctr_drbg_random,
ctr_drbg);
#else #else
valid = mbedtls_pk_parse_key(ecdsa, valid = mbedtls_pk_parse_key(pk,
(const unsigned char *) b64_key, (const unsigned char *)b64_key,
b64len, tmp, b64len,
strnlen((const char *) tmp, MAX_PASSPHRASE_SIZE)); NULL,
0);
#endif #endif
} else { }
} else {
#if MBEDTLS_VERSION_MAJOR > 2 #if MBEDTLS_VERSION_MAJOR > 2
valid = mbedtls_pk_parse_key(ecdsa, valid = mbedtls_pk_parse_key(pk,
(const unsigned char *) b64_key, (const unsigned char *)b64_key,
b64len, NULL, b64len,
0, mbedtls_ctr_drbg_random, ctr_drbg); (const unsigned char *)passphrase,
strnlen(passphrase, MAX_PASSPHRASE_SIZE),
mbedtls_ctr_drbg_random,
ctr_drbg);
#else #else
valid = mbedtls_pk_parse_key(ecdsa, valid = mbedtls_pk_parse_key(pk,
(const unsigned char *) b64_key, (const unsigned char *)b64_key,
b64len, NULL, b64len,
0); (const unsigned char *)passphrase,
strnlen(passphrase, MAX_PASSPHRASE_SIZE));
#endif #endif
}
} else {
#if MBEDTLS_VERSION_MAJOR > 2
valid = mbedtls_pk_parse_key(ecdsa,
(const unsigned char *) b64_key, b64len,
(const unsigned char *) passphrase,
strnlen(passphrase, MAX_PASSPHRASE_SIZE),
mbedtls_ctr_drbg_random, ctr_drbg);
#else
valid = mbedtls_pk_parse_key(ecdsa,
(const unsigned char *) b64_key, b64len,
(const unsigned char *) passphrase,
strnlen(passphrase, MAX_PASSPHRASE_SIZE));
#endif
}
if (valid != 0) {
char error_buf[100];
mbedtls_strerror(valid, error_buf, 100);
SSH_LOG(SSH_LOG_WARN,"Parsing private key %s", error_buf);
goto fail;
}
break;
case SSH_KEYTYPE_ED25519:
/* Cannot open ed25519 keys with libmbedcrypto */
default:
SSH_LOG(SSH_LOG_WARN, "Unknown or invalid private key type %d",
type);
return NULL;
} }
if (valid != 0) {
char error_buf[100];
mbedtls_strerror(valid, error_buf, 100);
SSH_LOG(SSH_LOG_WARN, "Parsing private key %s", error_buf);
goto fail;
}
mbed_type = mbedtls_pk_get_type(pk);
key = ssh_key_new(); key = ssh_key_new();
if (key == NULL) { if (key == NULL) {
goto fail; goto fail;
} }
if (ecdsa != NULL) { switch (mbed_type) {
mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(*ecdsa); case MBEDTLS_PK_RSA:
case MBEDTLS_PK_RSA_ALT:
key->rsa = pk;
pk = NULL;
key->type = SSH_KEYTYPE_RSA;
break;
case MBEDTLS_PK_ECKEY:
case MBEDTLS_PK_ECDSA: {
/* type will be set later */
mbedtls_ecp_keypair *keypair = mbedtls_pk_ec(*pk);
pk = NULL;
key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context)); key->ecdsa = malloc(sizeof(mbedtls_ecdsa_context));
if (key->ecdsa == NULL) { if (key->ecdsa == NULL) {
@@ -258,40 +197,36 @@ ssh_key pki_private_key_from_base64(const char *b64_key, const char *passphrase,
mbedtls_ecdsa_init(key->ecdsa); mbedtls_ecdsa_init(key->ecdsa);
mbedtls_ecdsa_from_keypair(key->ecdsa, keypair); mbedtls_ecdsa_from_keypair(key->ecdsa, keypair);
mbedtls_pk_free(ecdsa); mbedtls_pk_free(pk);
SAFE_FREE(ecdsa); SAFE_FREE(pk);
key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa); key->ecdsa_nid = pki_key_ecdsa_to_nid(key->ecdsa);
/* pki_privatekey_type_from_string always returns P256 for ECDSA /* pki_privatekey_type_from_string always returns P256 for ECDSA
* keys, so we need to figure out the correct type here */ * keys, so we need to figure out the correct type here */
type = pki_key_ecdsa_to_key_type(key->ecdsa); key->type = pki_key_ecdsa_to_key_type(key->ecdsa);
if (type == SSH_KEYTYPE_UNKNOWN) { if (key->type == SSH_KEYTYPE_UNKNOWN) {
SSH_LOG(SSH_LOG_WARN, "Invalid private key."); SSH_LOG(SSH_LOG_WARN, "Invalid private key.");
goto fail; goto fail;
} }
} else { break;
key->ecdsa = NULL; }
default:
SSH_LOG(SSH_LOG_WARN,
"Unknown or invalid private key type %d",
mbed_type);
return NULL;
} }
key->type = type; key->type_c = ssh_key_type_to_char(key->type);
key->type_c = ssh_key_type_to_char(type);
key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC; key->flags = SSH_KEY_FLAG_PRIVATE | SSH_KEY_FLAG_PUBLIC;
key->rsa = rsa;
key->ed25519_privkey = ed25519;
rsa = NULL;
ecdsa = NULL;
return key; return key;
fail: fail:
ssh_key_free(key); ssh_key_free(key);
if (rsa != NULL) { if (pk != NULL) {
mbedtls_pk_free(rsa); mbedtls_pk_free(pk);
SAFE_FREE(rsa); SAFE_FREE(pk);
}
if (ecdsa != NULL) {
mbedtls_pk_free(ecdsa);
SAFE_FREE(ecdsa);
} }
return NULL; return NULL;
} }