diff options
Diffstat (limited to 'thirdparty/mbedtls/library/pkparse.c')
-rw-r--r-- | thirdparty/mbedtls/library/pkparse.c | 979 |
1 files changed, 417 insertions, 562 deletions
diff --git a/thirdparty/mbedtls/library/pkparse.c b/thirdparty/mbedtls/library/pkparse.c index 37d501640d..4f6ee13986 100644 --- a/thirdparty/mbedtls/library/pkparse.c +++ b/thirdparty/mbedtls/library/pkparse.c @@ -13,19 +13,25 @@ #include "mbedtls/asn1.h" #include "mbedtls/oid.h" #include "mbedtls/platform_util.h" +#include "mbedtls/platform.h" #include "mbedtls/error.h" +#include "mbedtls/ecp.h" +#include "pk_internal.h" #include <string.h> +#if defined(MBEDTLS_USE_PSA_CRYPTO) +#include "mbedtls/psa_util.h" +#include "psa/crypto.h" +#endif + +/* Key types */ #if defined(MBEDTLS_RSA_C) #include "mbedtls/rsa.h" +#include "rsa_internal.h" #endif -#if defined(MBEDTLS_ECP_C) -#include "mbedtls/ecp.h" -#endif -#if defined(MBEDTLS_ECDSA_C) -#include "mbedtls/ecdsa.h" -#endif + +/* Extended formats */ #if defined(MBEDTLS_PEM_PARSE_C) #include "mbedtls/pem.h" #endif @@ -36,175 +42,55 @@ #include "mbedtls/pkcs12.h" #endif -#include "mbedtls/platform.h" - -/* Parameter validation macros based on platform_util.h */ -#define PK_VALIDATE_RET(cond) \ - MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_PK_BAD_INPUT_DATA) -#define PK_VALIDATE(cond) \ - MBEDTLS_INTERNAL_VALIDATE(cond) +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) -#if defined(MBEDTLS_FS_IO) -/* - * Load all data from a file into a given buffer. +/*********************************************************************** * - * The file is expected to contain either PEM or DER encoded data. - * A terminating null byte is always appended. It is included in the announced - * length only if the data looks like it is PEM encoded. - */ -int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n) -{ - FILE *f; - long size; - - PK_VALIDATE_RET(path != NULL); - PK_VALIDATE_RET(buf != NULL); - PK_VALIDATE_RET(n != NULL); - - if ((f = fopen(path, "rb")) == NULL) { - return MBEDTLS_ERR_PK_FILE_IO_ERROR; - } - - fseek(f, 0, SEEK_END); - if ((size = ftell(f)) == -1) { - fclose(f); - return MBEDTLS_ERR_PK_FILE_IO_ERROR; - } - fseek(f, 0, SEEK_SET); - - *n = (size_t) size; - - if (*n + 1 == 0 || - (*buf = mbedtls_calloc(1, *n + 1)) == NULL) { - fclose(f); - return MBEDTLS_ERR_PK_ALLOC_FAILED; - } - - if (fread(*buf, 1, *n, f) != *n) { - fclose(f); - - mbedtls_platform_zeroize(*buf, *n); - mbedtls_free(*buf); - - return MBEDTLS_ERR_PK_FILE_IO_ERROR; - } - - fclose(f); - - (*buf)[*n] = '\0'; - - if (strstr((const char *) *buf, "-----BEGIN ") != NULL) { - ++*n; - } + * Low-level ECC parsing: optional support for SpecifiedECDomain + * + * There are two functions here that are used by the rest of the code: + * - pk_ecc_tag_is_speficied_ec_domain() + * - pk_ecc_group_id_from_specified() + * + * All the other functions are internal to this section. + * + * The two "public" functions have a dummy variant provided + * in configs without MBEDTLS_PK_PARSE_EC_EXTENDED. This acts as an + * abstraction layer for this macro, which should not appear outside + * this section. + * + **********************************************************************/ +#if !defined(MBEDTLS_PK_PARSE_EC_EXTENDED) +/* See the "real" version for documentation */ +static int pk_ecc_tag_is_specified_ec_domain(int tag) +{ + (void) tag; return 0; } -/* - * Load and parse a private key - */ -int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, - const char *path, const char *pwd) +/* See the "real" version for documentation */ +static int pk_ecc_group_id_from_specified(const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *grp_id) { - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t n; - unsigned char *buf; - - PK_VALIDATE_RET(ctx != NULL); - PK_VALIDATE_RET(path != NULL); - - if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { - return ret; - } - - if (pwd == NULL) { - ret = mbedtls_pk_parse_key(ctx, buf, n, NULL, 0); - } else { - ret = mbedtls_pk_parse_key(ctx, buf, n, - (const unsigned char *) pwd, strlen(pwd)); - } - - mbedtls_platform_zeroize(buf, n); - mbedtls_free(buf); - - return ret; + (void) params; + (void) grp_id; + return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; } - +#else /* MBEDTLS_PK_PARSE_EC_EXTENDED */ /* - * Load and parse a public key + * Tell if the passed tag might be the start of SpecifiedECDomain + * (that is, a sequence). */ -int mbedtls_pk_parse_public_keyfile(mbedtls_pk_context *ctx, const char *path) +static int pk_ecc_tag_is_specified_ec_domain(int tag) { - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - size_t n; - unsigned char *buf; - - PK_VALIDATE_RET(ctx != NULL); - PK_VALIDATE_RET(path != NULL); - - if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { - return ret; - } - - ret = mbedtls_pk_parse_public_key(ctx, buf, n); - - mbedtls_platform_zeroize(buf, n); - mbedtls_free(buf); - - return ret; + return tag == (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); } -#endif /* MBEDTLS_FS_IO */ -#if defined(MBEDTLS_ECP_C) -/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf - * - * ECParameters ::= CHOICE { - * namedCurve OBJECT IDENTIFIER - * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } - * -- implicitCurve NULL - * } - */ -static int pk_get_ecparams(unsigned char **p, const unsigned char *end, - mbedtls_asn1_buf *params) -{ - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - if (end - *p < 1) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, - MBEDTLS_ERR_ASN1_OUT_OF_DATA); - } - - /* Tag may be either OID or SEQUENCE */ - params->tag = **p; - if (params->tag != MBEDTLS_ASN1_OID -#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) - && params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) -#endif - ) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, - MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); - } - - if ((ret = mbedtls_asn1_get_tag(p, end, ¶ms->len, params->tag)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); - } - - params->p = *p; - *p += params->len; - - if (*p != end) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - - return 0; -} - -#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) /* * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. * WARNING: the resulting group should only be used with - * pk_group_id_from_specified(), since its base point may not be set correctly + * pk_ecc_group_id_from_specified(), since its base point may not be set correctly * if it was encoded compressed. * * SpecifiedECDomain ::= SEQUENCE { @@ -224,7 +110,7 @@ static int pk_group_from_specified(const mbedtls_asn1_buf *params, mbedtls_ecp_g { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; unsigned char *p = params->p; - const unsigned char * const end = params->p + params->len; + const unsigned char *const end = params->p + params->len; const unsigned char *end_field, *end_curve; size_t len; int ver; @@ -396,7 +282,6 @@ static int pk_group_id_from_group(const mbedtls_ecp_group *grp, mbedtls_ecp_grou mbedtls_mpi_get_bit(&grp->G.Y, 0) == mbedtls_mpi_get_bit(&ref.G.Y, 0)) { break; } - } cleanup: @@ -414,8 +299,8 @@ cleanup: /* * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID */ -static int pk_group_id_from_specified(const mbedtls_asn1_buf *params, - mbedtls_ecp_group_id *grp_id) +static int pk_ecc_group_id_from_specified(const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *grp_id) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_ecp_group grp; @@ -429,12 +314,70 @@ static int pk_group_id_from_specified(const mbedtls_asn1_buf *params, ret = pk_group_id_from_group(&grp, grp_id); cleanup: - mbedtls_ecp_group_free(&grp); + /* The API respecting lifecycle for mbedtls_ecp_group struct is + * _init(), _load() and _free(). In pk_ecc_group_id_from_specified() the + * temporary grp breaks that flow and it's members are populated + * by pk_group_id_from_group(). As such mbedtls_ecp_group_free() + * which is assuming a group populated by _setup() may not clean-up + * properly -> Manually free it's members. + */ + mbedtls_mpi_free(&grp.N); + mbedtls_mpi_free(&grp.P); + mbedtls_mpi_free(&grp.A); + mbedtls_mpi_free(&grp.B); + mbedtls_ecp_point_free(&grp.G); return ret; } #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ +/*********************************************************************** + * + * Unsorted (yet!) from this point on until the next section header + * + **********************************************************************/ + +/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + * } + */ +static int pk_get_ecparams(unsigned char **p, const unsigned char *end, + mbedtls_asn1_buf *params) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if (end - *p < 1) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, + MBEDTLS_ERR_ASN1_OUT_OF_DATA); + } + + /* Acceptable tags: OID for namedCurve, or specifiedECDomain */ + params->tag = **p; + if (params->tag != MBEDTLS_ASN1_OID && + !pk_ecc_tag_is_specified_ec_domain(params->tag)) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG); + } + + if ((ret = mbedtls_asn1_get_tag(p, end, ¶ms->len, params->tag)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); + } + + params->p = *p; + *p += params->len; + + if (*p != end) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + + return 0; +} + /* * Use EC parameters to initialise an EC group * @@ -443,7 +386,7 @@ cleanup: * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } * -- implicitCurve NULL */ -static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp) +static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_pk_context *pk) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_ecp_group_id grp_id; @@ -453,116 +396,71 @@ static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_ecp_group *gr return MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE; } } else { -#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) - if ((ret = pk_group_id_from_specified(params, &grp_id)) != 0) { + ret = pk_ecc_group_id_from_specified(params, &grp_id); + if (ret != 0) { return ret; } -#else - return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; -#endif } - /* - * grp may already be initialized; if so, make sure IDs match - */ - if (grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id) { - return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; - } - - if ((ret = mbedtls_ecp_group_load(grp, grp_id)) != 0) { - return ret; - } - - return 0; + return mbedtls_pk_ecc_set_group(pk, grp_id); } +#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES) + /* - * EC public key is an EC point - * - * The caller is responsible for clearing the structure upon failure if - * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE - * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. + * Load an RFC8410 EC key, which doesn't have any parameters */ -static int pk_get_ecpubkey(unsigned char **p, const unsigned char *end, - mbedtls_ecp_keypair *key) +static int pk_use_ecparams_rfc8410(const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id grp_id, + mbedtls_pk_context *pk) { - int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; - - if ((ret = mbedtls_ecp_point_read_binary(&key->grp, &key->Q, - (const unsigned char *) *p, end - *p)) == 0) { - ret = mbedtls_ecp_check_pubkey(&key->grp, &key->Q); + if (params->tag != 0 || params->len != 0) { + return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; } - /* - * We know mbedtls_ecp_point_read_binary consumed all bytes or failed - */ - *p = (unsigned char *) end; - - return ret; + return mbedtls_pk_ecc_set_group(pk, grp_id); } -#endif /* MBEDTLS_ECP_C */ -#if defined(MBEDTLS_RSA_C) /* - * RSAPublicKey ::= SEQUENCE { - * modulus INTEGER, -- n - * publicExponent INTEGER -- e - * } + * Parse an RFC 8410 encoded private EC key + * + * CurvePrivateKey ::= OCTET STRING */ -static int pk_get_rsapubkey(unsigned char **p, - const unsigned char *end, - mbedtls_rsa_context *rsa) +static int pk_parse_key_rfc8410_der(mbedtls_pk_context *pk, + unsigned char *key, size_t keylen, const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; size_t len; - if ((ret = mbedtls_asn1_get_tag(p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret); - } - - if (*p + len != end) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - - /* Import N */ - if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret); - } - - if ((ret = mbedtls_rsa_import_raw(rsa, *p, len, NULL, 0, NULL, 0, - NULL, 0, NULL, 0)) != 0) { - return MBEDTLS_ERR_PK_INVALID_PUBKEY; - } - - *p += len; - - /* Import E */ - if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret); + if ((ret = mbedtls_asn1_get_tag(&key, (key + keylen), &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); } - if ((ret = mbedtls_rsa_import_raw(rsa, NULL, 0, NULL, 0, NULL, 0, - NULL, 0, *p, len)) != 0) { - return MBEDTLS_ERR_PK_INVALID_PUBKEY; + if (key + len != end) { + return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; } - *p += len; - - if (mbedtls_rsa_complete(rsa) != 0 || - mbedtls_rsa_check_pubkey(rsa) != 0) { - return MBEDTLS_ERR_PK_INVALID_PUBKEY; + /* + * Load the private key + */ + ret = mbedtls_pk_ecc_set_key(pk, key, len); + if (ret != 0) { + return ret; } - if (*p != end) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + /* pk_parse_key_pkcs8_unencrypted_der() only supports version 1 PKCS8 keys, + * which never contain a public key. As such, derive the public key + * unconditionally. */ + if ((ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, key, len, f_rng, p_rng)) != 0) { + return ret; } return 0; } -#endif /* MBEDTLS_RSA_C */ +#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */ + +#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ /* Get a PK algorithm identifier * @@ -572,7 +470,8 @@ static int pk_get_rsapubkey(unsigned char **p, */ static int pk_get_pk_alg(unsigned char **p, const unsigned char *end, - mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params) + mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *ec_grp_id) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; mbedtls_asn1_buf alg_oid; @@ -583,7 +482,18 @@ static int pk_get_pk_alg(unsigned char **p, return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_ALG, ret); } - if (mbedtls_oid_get_pk_alg(&alg_oid, pk_alg) != 0) { + ret = mbedtls_oid_get_pk_alg(&alg_oid, pk_alg); +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) + if (ret == MBEDTLS_ERR_OID_NOT_FOUND) { + ret = mbedtls_oid_get_ec_grp_algid(&alg_oid, ec_grp_id); + if (ret == 0) { + *pk_alg = MBEDTLS_PK_ECKEY; + } + } +#else + (void) ec_grp_id; +#endif + if (ret != 0) { return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; } @@ -611,13 +521,9 @@ int mbedtls_pk_parse_subpubkey(unsigned char **p, const unsigned char *end, size_t len; mbedtls_asn1_buf alg_params; mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE; const mbedtls_pk_info_t *pk_info; - PK_VALIDATE_RET(p != NULL); - PK_VALIDATE_RET(*p != NULL); - PK_VALIDATE_RET(end != NULL); - PK_VALIDATE_RET(pk != NULL); - if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); @@ -625,7 +531,7 @@ int mbedtls_pk_parse_subpubkey(unsigned char **p, const unsigned char *end, end = *p + len; - if ((ret = pk_get_pk_alg(p, end, &pk_alg, &alg_params)) != 0) { + if ((ret = pk_get_pk_alg(p, end, &pk_alg, &alg_params, &ec_grp_id)) != 0) { return ret; } @@ -648,17 +554,35 @@ int mbedtls_pk_parse_subpubkey(unsigned char **p, const unsigned char *end, #if defined(MBEDTLS_RSA_C) if (pk_alg == MBEDTLS_PK_RSA) { - ret = pk_get_rsapubkey(p, end, mbedtls_pk_rsa(*pk)); + ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*pk), *p, (size_t) (end - *p)); + if (ret == 0) { + /* On success all the input has been consumed by the parsing function. */ + *p += end - *p; + } else if ((ret <= MBEDTLS_ERR_ASN1_OUT_OF_DATA) && + (ret >= MBEDTLS_ERR_ASN1_BUF_TOO_SMALL)) { + /* In case of ASN1 error codes add MBEDTLS_ERR_PK_INVALID_PUBKEY. */ + ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret); + } else { + ret = MBEDTLS_ERR_PK_INVALID_PUBKEY; + } } else #endif /* MBEDTLS_RSA_C */ -#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) if (pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY) { - ret = pk_use_ecparams(&alg_params, &mbedtls_pk_ec(*pk)->grp); +#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES) + if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) { + ret = pk_use_ecparams_rfc8410(&alg_params, ec_grp_id, pk); + } else +#endif + { + ret = pk_use_ecparams(&alg_params, pk); + } if (ret == 0) { - ret = pk_get_ecpubkey(p, end, mbedtls_pk_ec(*pk)); + ret = mbedtls_pk_ecc_set_pubkey(pk, *p, (size_t) (end - *p)); + *p += end - *p; } } else -#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; if (ret == 0 && *p != end) { @@ -673,208 +597,20 @@ int mbedtls_pk_parse_subpubkey(unsigned char **p, const unsigned char *end, return ret; } -#if defined(MBEDTLS_RSA_C) -/* - * Wrapper around mbedtls_asn1_get_mpi() that rejects zero. - * - * The value zero is: - * - never a valid value for an RSA parameter - * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete(). - * - * Since values can't be omitted in PKCS#1, passing a zero value to - * rsa_complete() would be incorrect, so reject zero values early. - */ -static int asn1_get_nonzero_mpi(unsigned char **p, - const unsigned char *end, - mbedtls_mpi *X) -{ - int ret; - - ret = mbedtls_asn1_get_mpi(p, end, X); - if (ret != 0) { - return ret; - } - - if (mbedtls_mpi_cmp_int(X, 0) == 0) { - return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; - } - - return 0; -} - -/* - * Parse a PKCS#1 encoded private RSA key - */ -static int pk_parse_key_pkcs1_der(mbedtls_rsa_context *rsa, - const unsigned char *key, - size_t keylen) -{ - int ret, version; - size_t len; - unsigned char *p, *end; - - mbedtls_mpi T; - mbedtls_mpi_init(&T); - - p = (unsigned char *) key; - end = p + keylen; - - /* - * This function parses the RSAPrivateKey (PKCS#1) - * - * RSAPrivateKey ::= SEQUENCE { - * version Version, - * modulus INTEGER, -- n - * publicExponent INTEGER, -- e - * privateExponent INTEGER, -- d - * prime1 INTEGER, -- p - * prime2 INTEGER, -- q - * exponent1 INTEGER, -- d mod (p-1) - * exponent2 INTEGER, -- d mod (q-1) - * coefficient INTEGER, -- (inverse of q) mod p - * otherPrimeInfos OtherPrimeInfos OPTIONAL - * } - */ - if ((ret = mbedtls_asn1_get_tag(&p, end, &len, - MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); - } - - end = p + len; - - if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) { - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); - } - - if (version != 0) { - return MBEDTLS_ERR_PK_KEY_INVALID_VERSION; - } - - /* Import N */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_rsa_import(rsa, &T, NULL, NULL, - NULL, NULL)) != 0) { - goto cleanup; - } - - /* Import E */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_rsa_import(rsa, NULL, NULL, NULL, - NULL, &T)) != 0) { - goto cleanup; - } - - /* Import D */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_rsa_import(rsa, NULL, NULL, NULL, - &T, NULL)) != 0) { - goto cleanup; - } - - /* Import P */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_rsa_import(rsa, NULL, &T, NULL, - NULL, NULL)) != 0) { - goto cleanup; - } - - /* Import Q */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_rsa_import(rsa, NULL, NULL, &T, - NULL, NULL)) != 0) { - goto cleanup; - } - -#if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT) - /* - * The RSA CRT parameters DP, DQ and QP are nominally redundant, in - * that they can be easily recomputed from D, P and Q. However by - * parsing them from the PKCS1 structure it is possible to avoid - * recalculating them which both reduces the overhead of loading - * RSA private keys into memory and also avoids side channels which - * can arise when computing those values, since all of D, P, and Q - * are secret. See https://eprint.iacr.org/2020/055 for a - * description of one such attack. - */ - - /* Import DP */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_mpi_copy(&rsa->DP, &T)) != 0) { - goto cleanup; - } - - /* Import DQ */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_mpi_copy(&rsa->DQ, &T)) != 0) { - goto cleanup; - } - - /* Import QP */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = mbedtls_mpi_copy(&rsa->QP, &T)) != 0) { - goto cleanup; - } - -#else - /* Verify existence of the CRT params */ - if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 || - (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0) { - goto cleanup; - } -#endif - - /* rsa_complete() doesn't complete anything with the default - * implementation but is still called: - * - for the benefit of alternative implementation that may want to - * pre-compute stuff beyond what's provided (eg Montgomery factors) - * - as is also sanity-checks the key - * - * Furthermore, we also check the public part for consistency with - * mbedtls_pk_parse_pubkey(), as it includes size minima for example. - */ - if ((ret = mbedtls_rsa_complete(rsa)) != 0 || - (ret = mbedtls_rsa_check_pubkey(rsa)) != 0) { - goto cleanup; - } - - if (p != end) { - ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, - MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); - } - -cleanup: - - mbedtls_mpi_free(&T); - - if (ret != 0) { - /* Wrap error code if it's coming from a lower level */ - if ((ret & 0xff80) == 0) { - ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); - } else { - ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; - } - - mbedtls_rsa_free(rsa); - } - - return ret; -} -#endif /* MBEDTLS_RSA_C */ - -#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) /* * Parse a SEC1 encoded private EC key */ -static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck, - const unsigned char *key, - size_t keylen) +static int pk_parse_key_sec1_der(mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; int version, pubkey_done; - size_t len; - mbedtls_asn1_buf params; + size_t len, d_len; + mbedtls_asn1_buf params = { 0, 0, NULL }; unsigned char *p = (unsigned char *) key; + unsigned char *d; unsigned char *end = p + keylen; unsigned char *end2; @@ -907,10 +643,10 @@ static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck, return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); } - if ((ret = mbedtls_mpi_read_binary(&eck->d, p, len)) != 0) { - mbedtls_ecp_keypair_free(eck); - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); - } + /* Keep a reference to the position fo the private key. It will be used + * later in this function. */ + d = p; + d_len = len; p += len; @@ -923,16 +659,22 @@ static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0)) == 0) { if ((ret = pk_get_ecparams(&p, p + len, ¶ms)) != 0 || - (ret = pk_use_ecparams(¶ms, &eck->grp)) != 0) { - mbedtls_ecp_keypair_free(eck); + (ret = pk_use_ecparams(¶ms, pk)) != 0) { return ret; } } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { - mbedtls_ecp_keypair_free(eck); return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); } } + /* + * Load the private key + */ + ret = mbedtls_pk_ecc_set_key(pk, d, d_len); + if (ret != 0) { + return ret; + } + if (p != end) { /* * Is 'publickey' present? If not, or if we can't read it (eg because it @@ -952,11 +694,11 @@ static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck, MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); } - if ((ret = pk_get_ecpubkey(&p, end2, eck)) == 0) { + if ((ret = mbedtls_pk_ecc_set_pubkey(pk, p, (size_t) (end2 - p))) == 0) { pubkey_done = 1; } else { /* - * The only acceptable failure mode of pk_get_ecpubkey() above + * The only acceptable failure mode of mbedtls_pk_ecc_set_pubkey() above * is if the point format is not recognized. */ if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) { @@ -964,26 +706,25 @@ static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck, } } } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { - mbedtls_ecp_keypair_free(eck); return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); } } - if (!pubkey_done && - (ret = mbedtls_ecp_mul(&eck->grp, &eck->Q, &eck->d, &eck->grp.G, - NULL, NULL)) != 0) { - mbedtls_ecp_keypair_free(eck); - return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret); - } - - if ((ret = mbedtls_ecp_check_privkey(&eck->grp, &eck->d)) != 0) { - mbedtls_ecp_keypair_free(eck); - return ret; + if (!pubkey_done) { + if ((ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, d, d_len, f_rng, p_rng)) != 0) { + return ret; + } } return 0; } -#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ + +/*********************************************************************** + * + * PKCS#8 parsing functions + * + **********************************************************************/ /* * Parse an unencrypted PKCS#8 encoded private key @@ -1000,8 +741,8 @@ static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck, */ static int pk_parse_key_pkcs8_unencrypted_der( mbedtls_pk_context *pk, - const unsigned char *key, - size_t keylen) + const unsigned char *key, size_t keylen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { int ret, version; size_t len; @@ -1009,8 +750,14 @@ static int pk_parse_key_pkcs8_unencrypted_der( unsigned char *p = (unsigned char *) key; unsigned char *end = p + keylen; mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE; const mbedtls_pk_info_t *pk_info; +#if !defined(MBEDTLS_PK_HAVE_ECC_KEYS) + (void) f_rng; + (void) p_rng; +#endif + /* * This function parses the PrivateKeyInfo object (PKCS#8 v1.2 = RFC 5208) * @@ -1042,7 +789,7 @@ static int pk_parse_key_pkcs8_unencrypted_der( return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_VERSION, ret); } - if ((ret = pk_get_pk_alg(&p, end, &pk_alg, ¶ms)) != 0) { + if ((ret = pk_get_pk_alg(&p, end, &pk_alg, ¶ms, &ec_grp_id)) != 0) { return ret; } @@ -1065,23 +812,43 @@ static int pk_parse_key_pkcs8_unencrypted_der( #if defined(MBEDTLS_RSA_C) if (pk_alg == MBEDTLS_PK_RSA) { - if ((ret = pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), p, len)) != 0) { + if ((ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), p, len)) != 0) { mbedtls_pk_free(pk); return ret; } } else #endif /* MBEDTLS_RSA_C */ -#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) if (pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH) { - if ((ret = pk_use_ecparams(¶ms, &mbedtls_pk_ec(*pk)->grp)) != 0 || - (ret = pk_parse_key_sec1_der(mbedtls_pk_ec(*pk), p, len)) != 0) { - mbedtls_pk_free(pk); - return ret; +#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES) + if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) { + if ((ret = + pk_use_ecparams_rfc8410(¶ms, ec_grp_id, pk)) != 0 || + (ret = + pk_parse_key_rfc8410_der(pk, p, len, end, f_rng, + p_rng)) != 0) { + mbedtls_pk_free(pk); + return ret; + } + } else +#endif + { + if ((ret = pk_use_ecparams(¶ms, pk)) != 0 || + (ret = pk_parse_key_sec1_der(pk, p, len, f_rng, p_rng)) != 0) { + mbedtls_pk_free(pk); + return ret; + } } } else -#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; + end = p + len; + if (end != (key + keylen)) { + return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH); + } + return 0; } @@ -1095,20 +862,22 @@ static int pk_parse_key_pkcs8_unencrypted_der( * */ #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) -static int pk_parse_key_pkcs8_encrypted_der( +MBEDTLS_STATIC_TESTABLE int mbedtls_pk_parse_key_pkcs8_encrypted_der( mbedtls_pk_context *pk, unsigned char *key, size_t keylen, - const unsigned char *pwd, size_t pwdlen) + const unsigned char *pwd, size_t pwdlen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { int ret, decrypted = 0; size_t len; unsigned char *buf; unsigned char *p, *end; mbedtls_asn1_buf pbe_alg_oid, pbe_params; -#if defined(MBEDTLS_PKCS12_C) +#if defined(MBEDTLS_PKCS12_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C) mbedtls_cipher_type_t cipher_alg; mbedtls_md_type_t md_alg; #endif + size_t outlen = 0; p = key; end = p + keylen; @@ -1152,11 +921,11 @@ static int pk_parse_key_pkcs8_encrypted_der( /* * Decrypt EncryptedData with appropriate PBE */ -#if defined(MBEDTLS_PKCS12_C) +#if defined(MBEDTLS_PKCS12_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C) if (mbedtls_oid_get_pkcs12_pbe_alg(&pbe_alg_oid, &md_alg, &cipher_alg) == 0) { - if ((ret = mbedtls_pkcs12_pbe(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, - cipher_alg, md_alg, - pwd, pwdlen, p, len, buf)) != 0) { + if ((ret = mbedtls_pkcs12_pbe_ext(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, + cipher_alg, md_alg, + pwd, pwdlen, p, len, buf, len, &outlen)) != 0) { if (ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) { return MBEDTLS_ERR_PK_PASSWORD_MISMATCH; } @@ -1165,28 +934,12 @@ static int pk_parse_key_pkcs8_encrypted_der( } decrypted = 1; - } else if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid) == 0) { - if ((ret = mbedtls_pkcs12_pbe_sha1_rc4_128(&pbe_params, - MBEDTLS_PKCS12_PBE_DECRYPT, - pwd, pwdlen, - p, len, buf)) != 0) { - return ret; - } - - // Best guess for password mismatch when using RC4. If first tag is - // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE - // - if (*buf != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) { - return MBEDTLS_ERR_PK_PASSWORD_MISMATCH; - } - - decrypted = 1; } else -#endif /* MBEDTLS_PKCS12_C */ -#if defined(MBEDTLS_PKCS5_C) +#endif /* MBEDTLS_PKCS12_C && MBEDTLS_CIPHER_PADDING_PKCS7 && MBEDTLS_CIPHER_C */ +#if defined(MBEDTLS_PKCS5_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C) if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid) == 0) { - if ((ret = mbedtls_pkcs5_pbes2(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, - p, len, buf)) != 0) { + if ((ret = mbedtls_pkcs5_pbes2_ext(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, + p, len, buf, len, &outlen)) != 0) { if (ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) { return MBEDTLS_ERR_PK_PASSWORD_MISMATCH; } @@ -1196,7 +949,7 @@ static int pk_parse_key_pkcs8_encrypted_der( decrypted = 1; } else -#endif /* MBEDTLS_PKCS5_C */ +#endif /* MBEDTLS_PKCS5_C && MBEDTLS_CIPHER_PADDING_PKCS7 && MBEDTLS_CIPHER_C */ { ((void) pwd); } @@ -1204,17 +957,23 @@ static int pk_parse_key_pkcs8_encrypted_der( if (decrypted == 0) { return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE; } - - return pk_parse_key_pkcs8_unencrypted_der(pk, buf, len); + return pk_parse_key_pkcs8_unencrypted_der(pk, buf, outlen, f_rng, p_rng); } #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ +/*********************************************************************** + * + * Top-level functions, with format auto-discovery + * + **********************************************************************/ + /* * Parse a private key */ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, const unsigned char *key, size_t keylen, - const unsigned char *pwd, size_t pwdlen) + const unsigned char *pwd, size_t pwdlen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; const mbedtls_pk_info_t *pk_info; @@ -1223,13 +982,9 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, mbedtls_pem_context pem; #endif - (void) pk_info; - - PK_VALIDATE_RET(pk != NULL); if (keylen == 0) { return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; } - PK_VALIDATE_RET(key != NULL); #if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_init(&pem); @@ -1240,16 +995,15 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = mbedtls_pem_read_buffer(&pem, - "-----BEGIN RSA PRIVATE KEY-----", - "-----END RSA PRIVATE KEY-----", + PEM_BEGIN_PRIVATE_KEY_RSA, PEM_END_PRIVATE_KEY_RSA, key, pwd, pwdlen, &len); } if (ret == 0) { pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 || - (ret = pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), - pem.buf, pem.buflen)) != 0) { + (ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), + pem.buf, pem.buflen)) != 0) { mbedtls_pk_free(pk); } @@ -1264,22 +1018,23 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, } #endif /* MBEDTLS_RSA_C */ -#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if (key[keylen - 1] != '\0') { ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = mbedtls_pem_read_buffer(&pem, - "-----BEGIN EC PRIVATE KEY-----", - "-----END EC PRIVATE KEY-----", + PEM_BEGIN_PRIVATE_KEY_EC, + PEM_END_PRIVATE_KEY_EC, key, pwd, pwdlen, &len); } if (ret == 0) { pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 || - (ret = pk_parse_key_sec1_der(mbedtls_pk_ec(*pk), - pem.buf, pem.buflen)) != 0) { + (ret = pk_parse_key_sec1_der(pk, + pem.buf, pem.buflen, + f_rng, p_rng)) != 0) { mbedtls_pk_free(pk); } @@ -1292,20 +1047,19 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { return ret; } -#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ if (key[keylen - 1] != '\0') { ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = mbedtls_pem_read_buffer(&pem, - "-----BEGIN PRIVATE KEY-----", - "-----END PRIVATE KEY-----", + PEM_BEGIN_PRIVATE_KEY_PKCS8, PEM_END_PRIVATE_KEY_PKCS8, key, NULL, 0, &len); } if (ret == 0) { if ((ret = pk_parse_key_pkcs8_unencrypted_der(pk, - pem.buf, pem.buflen)) != 0) { + pem.buf, pem.buflen, f_rng, p_rng)) != 0) { mbedtls_pk_free(pk); } @@ -1321,14 +1075,13 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = mbedtls_pem_read_buffer(&pem, - "-----BEGIN ENCRYPTED PRIVATE KEY-----", - "-----END ENCRYPTED PRIVATE KEY-----", + PEM_BEGIN_ENCRYPTED_PRIVATE_KEY_PKCS8, + PEM_END_ENCRYPTED_PRIVATE_KEY_PKCS8, key, NULL, 0, &len); } if (ret == 0) { - if ((ret = pk_parse_key_pkcs8_encrypted_der(pk, - pem.buf, pem.buflen, - pwd, pwdlen)) != 0) { + if ((ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen, + pwd, pwdlen, f_rng, p_rng)) != 0) { mbedtls_pk_free(pk); } @@ -1351,7 +1104,7 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, * error */ #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) - { + if (pwdlen != 0) { unsigned char *key_copy; if ((key_copy = mbedtls_calloc(1, keylen)) == NULL) { @@ -1360,11 +1113,10 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, memcpy(key_copy, key, keylen); - ret = pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen, - pwd, pwdlen); + ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen, + pwd, pwdlen, f_rng, p_rng); - mbedtls_platform_zeroize(key_copy, keylen); - mbedtls_free(key_copy); + mbedtls_zeroize_and_free(key_copy, keylen); } if (ret == 0) { @@ -1379,7 +1131,7 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, } #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ - ret = pk_parse_key_pkcs8_unencrypted_der(pk, key, keylen); + ret = pk_parse_key_pkcs8_unencrypted_der(pk, key, keylen, f_rng, p_rng); if (ret == 0) { return 0; } @@ -1391,7 +1143,7 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); if (mbedtls_pk_setup(pk, pk_info) == 0 && - pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), key, keylen) == 0) { + mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), key, keylen) == 0) { return 0; } @@ -1399,21 +1151,21 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk, mbedtls_pk_init(pk); #endif /* MBEDTLS_RSA_C */ -#if defined(MBEDTLS_ECP_C) +#if defined(MBEDTLS_PK_HAVE_ECC_KEYS) pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY); if (mbedtls_pk_setup(pk, pk_info) == 0 && - pk_parse_key_sec1_der(mbedtls_pk_ec(*pk), - key, keylen) == 0) { + pk_parse_key_sec1_der(pk, + key, keylen, f_rng, p_rng) == 0) { return 0; } mbedtls_pk_free(pk); -#endif /* MBEDTLS_ECP_C */ +#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ - /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't, + /* If MBEDTLS_RSA_C is defined but MBEDTLS_PK_HAVE_ECC_KEYS isn't, * it is ok to leave the PK context initialized but not * freed: It is the caller's responsibility to call pk_init() * before calling this function, and to call pk_free() - * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C + * when it fails. If MBEDTLS_PK_HAVE_ECC_KEYS is defined but MBEDTLS_RSA_C * isn't, this leads to mbedtls_pk_free() being called * twice, once here and once by the caller, but this is * also ok and in line with the mbedtls_pk_free() calls @@ -1438,11 +1190,9 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, mbedtls_pem_context pem; #endif - PK_VALIDATE_RET(ctx != NULL); if (keylen == 0) { return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT; } - PK_VALIDATE_RET(key != NULL || keylen == 0); #if defined(MBEDTLS_PEM_PARSE_C) mbedtls_pem_init(&pem); @@ -1452,8 +1202,7 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = mbedtls_pem_read_buffer(&pem, - "-----BEGIN RSA PUBLIC KEY-----", - "-----END RSA PUBLIC KEY-----", + PEM_BEGIN_PUBLIC_KEY_RSA, PEM_END_PUBLIC_KEY_RSA, key, NULL, 0, &len); } @@ -1469,7 +1218,7 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, return ret; } - if ((ret = pk_get_rsapubkey(&p, p + pem.buflen, mbedtls_pk_rsa(*ctx))) != 0) { + if ((ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*ctx), p, pem.buflen)) != 0) { mbedtls_pk_free(ctx); } @@ -1486,8 +1235,7 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = mbedtls_pem_read_buffer(&pem, - "-----BEGIN PUBLIC KEY-----", - "-----END PUBLIC KEY-----", + PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, key, NULL, 0, &len); } @@ -1497,7 +1245,7 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, */ p = pem.buf; - ret = mbedtls_pk_parse_subpubkey(&p, p + pem.buflen, ctx); + ret = mbedtls_pk_parse_subpubkey(&p, p + pem.buflen, ctx); mbedtls_pem_free(&pem); return ret; } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { @@ -1517,13 +1265,12 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, } p = (unsigned char *) key; - ret = pk_get_rsapubkey(&p, p + keylen, mbedtls_pk_rsa(*ctx)); + ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*ctx), p, keylen); if (ret == 0) { return ret; } mbedtls_pk_free(ctx); - if (ret != (MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, - MBEDTLS_ERR_ASN1_UNEXPECTED_TAG))) { + if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { return ret; } #endif /* MBEDTLS_RSA_C */ @@ -1534,4 +1281,112 @@ int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, return ret; } +/*********************************************************************** + * + * Top-level functions, with filesystem support + * + **********************************************************************/ + +#if defined(MBEDTLS_FS_IO) +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n) +{ + FILE *f; + long size; + + if ((f = fopen(path, "rb")) == NULL) { + return MBEDTLS_ERR_PK_FILE_IO_ERROR; + } + + /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */ + mbedtls_setbuf(f, NULL); + + fseek(f, 0, SEEK_END); + if ((size = ftell(f)) == -1) { + fclose(f); + return MBEDTLS_ERR_PK_FILE_IO_ERROR; + } + fseek(f, 0, SEEK_SET); + + *n = (size_t) size; + + if (*n + 1 == 0 || + (*buf = mbedtls_calloc(1, *n + 1)) == NULL) { + fclose(f); + return MBEDTLS_ERR_PK_ALLOC_FAILED; + } + + if (fread(*buf, 1, *n, f) != *n) { + fclose(f); + + mbedtls_zeroize_and_free(*buf, *n); + + return MBEDTLS_ERR_PK_FILE_IO_ERROR; + } + + fclose(f); + + (*buf)[*n] = '\0'; + + if (strstr((const char *) *buf, "-----BEGIN ") != NULL) { + ++*n; + } + + return 0; +} + +/* + * Load and parse a private key + */ +int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx, + const char *path, const char *pwd, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n; + unsigned char *buf; + + if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { + return ret; + } + + if (pwd == NULL) { + ret = mbedtls_pk_parse_key(ctx, buf, n, NULL, 0, f_rng, p_rng); + } else { + ret = mbedtls_pk_parse_key(ctx, buf, n, + (const unsigned char *) pwd, strlen(pwd), f_rng, p_rng); + } + + mbedtls_zeroize_and_free(buf, n); + + return ret; +} + +/* + * Load and parse a public key + */ +int mbedtls_pk_parse_public_keyfile(mbedtls_pk_context *ctx, const char *path) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + size_t n; + unsigned char *buf; + + if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) { + return ret; + } + + ret = mbedtls_pk_parse_public_key(ctx, buf, n); + + mbedtls_zeroize_and_free(buf, n); + + return ret; +} +#endif /* MBEDTLS_FS_IO */ + #endif /* MBEDTLS_PK_PARSE_C */ |