Merge pull request #8740 from valeriosetti/issue8647

Move RSA basic key parsing/writing to rsa.c
This commit is contained in:
Manuel Pégourié-Gonnard 2024-02-08 08:35:42 +00:00 committed by GitHub
commit 7bf1e98f44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 731 additions and 572 deletions

View file

@ -32,6 +32,7 @@
#if defined(MBEDTLS_RSA_C)
#include "pkwrite.h"
#include "rsa_internal.h"
#endif
#if defined(MBEDTLS_PK_CAN_ECDSA_SOME)
@ -69,9 +70,9 @@ static int rsa_verify_wrap(mbedtls_pk_context *pk, mbedtls_md_type_t md_alg,
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
psa_status_t status;
mbedtls_pk_context key;
int key_len;
unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
unsigned char *p = buf + sizeof(buf);
psa_algorithm_t psa_alg_md =
PSA_ALG_RSA_PKCS1V15_SIGN(mbedtls_md_psa_alg_from_type(md_alg));
size_t rsa_len = mbedtls_rsa_get_len(rsa);
@ -86,11 +87,7 @@ static int rsa_verify_wrap(mbedtls_pk_context *pk, mbedtls_md_type_t md_alg,
return MBEDTLS_ERR_RSA_VERIFY_FAILED;
}
/* mbedtls_pk_write_pubkey_der() expects a full PK context;
* re-construct one to make it happy */
key.pk_info = &mbedtls_rsa_info;
key.pk_ctx = rsa;
key_len = mbedtls_pk_write_pubkey_der(&key, buf, sizeof(buf));
key_len = mbedtls_rsa_write_pubkey(rsa, buf, &p);
if (key_len <= 0) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
@ -172,14 +169,15 @@ int mbedtls_pk_psa_rsa_sign_ext(psa_algorithm_t alg,
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
psa_status_t status;
mbedtls_pk_context key;
int key_len;
unsigned char *buf = NULL;
unsigned char *p;
buf = mbedtls_calloc(1, MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES);
if (buf == NULL) {
return MBEDTLS_ERR_PK_ALLOC_FAILED;
}
mbedtls_pk_info_t pk_info = mbedtls_rsa_info;
p = buf + MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES;
*sig_len = mbedtls_rsa_get_len(rsa_ctx);
if (sig_size < *sig_len) {
@ -187,11 +185,7 @@ int mbedtls_pk_psa_rsa_sign_ext(psa_algorithm_t alg,
return MBEDTLS_ERR_PK_BUFFER_TOO_SMALL;
}
/* mbedtls_pk_write_key_der() expects a full PK context;
* re-construct one to make it happy */
key.pk_info = &pk_info;
key.pk_ctx = rsa_ctx;
key_len = mbedtls_pk_write_key_der(&key, buf, MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES);
key_len = mbedtls_rsa_write_key(rsa_ctx, buf, &p);
if (key_len <= 0) {
mbedtls_free(buf);
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
@ -282,9 +276,9 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
psa_status_t status;
mbedtls_pk_context key;
int key_len;
unsigned char buf[MBEDTLS_PK_RSA_PRV_DER_MAX_BYTES];
unsigned char *p = buf + sizeof(buf);
((void) f_rng);
((void) p_rng);
@ -299,11 +293,7 @@ static int rsa_decrypt_wrap(mbedtls_pk_context *pk,
return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
}
/* mbedtls_pk_write_key_der() expects a full PK context;
* re-construct one to make it happy */
key.pk_info = &mbedtls_rsa_info;
key.pk_ctx = rsa;
key_len = mbedtls_pk_write_key_der(&key, buf, sizeof(buf));
key_len = mbedtls_rsa_write_key(rsa, buf, &p);
if (key_len <= 0) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}
@ -368,9 +358,9 @@ static int rsa_encrypt_wrap(mbedtls_pk_context *pk,
psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
mbedtls_svc_key_id_t key_id = MBEDTLS_SVC_KEY_ID_INIT;
psa_status_t status;
mbedtls_pk_context key;
int key_len;
unsigned char buf[MBEDTLS_PK_RSA_PUB_DER_MAX_BYTES];
unsigned char *p = buf + sizeof(buf);
((void) f_rng);
((void) p_rng);
@ -385,11 +375,7 @@ static int rsa_encrypt_wrap(mbedtls_pk_context *pk,
return MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE;
}
/* mbedtls_pk_write_pubkey_der() expects a full PK context;
* re-construct one to make it happy */
key.pk_info = &mbedtls_rsa_info;
key.pk_ctx = rsa;
key_len = mbedtls_pk_write_pubkey_der(&key, buf, sizeof(buf));
key_len = mbedtls_rsa_write_pubkey(rsa, buf, &p);
if (key_len <= 0) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
}

View file

@ -28,6 +28,7 @@
/* Key types */
#if defined(MBEDTLS_RSA_C)
#include "mbedtls/rsa.h"
#include "rsa_internal.h"
#endif
/* Extended formats */
@ -757,68 +758,6 @@ static int pk_parse_key_rfc8410_der(mbedtls_pk_context *pk,
#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
#if defined(MBEDTLS_RSA_C)
/*
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
*/
static int pk_get_rsapubkey(unsigned char **p,
const unsigned char *end,
mbedtls_rsa_context *rsa)
{
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_rsa_import_raw(rsa, NULL, 0, NULL, 0, NULL, 0,
NULL, 0, *p, len)) != 0) {
return MBEDTLS_ERR_PK_INVALID_PUBKEY;
}
*p += len;
if (mbedtls_rsa_complete(rsa) != 0 ||
mbedtls_rsa_check_pubkey(rsa) != 0) {
return MBEDTLS_ERR_PK_INVALID_PUBKEY;
}
if (*p != end) {
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
}
return 0;
}
#endif /* MBEDTLS_RSA_C */
/* Get a PK algorithm identifier
*
* AlgorithmIdentifier ::= SEQUENCE {
@ -911,7 +850,17 @@ 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_PK_HAVE_ECC_KEYS)
@ -944,195 +893,6 @@ 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_PK_HAVE_ECC_KEYS)
/*
* Parse a SEC1 encoded private EC key
@ -1348,7 +1108,7 @@ 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;
}
@ -1538,8 +1298,8 @@ int mbedtls_pk_parse_key(mbedtls_pk_context *pk,
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);
}
@ -1679,7 +1439,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;
}
@ -1754,7 +1514,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);
}
@ -1801,13 +1561,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 */

View file

@ -32,6 +32,9 @@
#if defined(MBEDTLS_PEM_WRITE_C)
#include "mbedtls/pem.h"
#endif
#if defined(MBEDTLS_RSA_C)
#include "rsa_internal.h"
#endif
#if defined(MBEDTLS_USE_PSA_CRYPTO)
#include "psa/crypto.h"
@ -56,60 +59,13 @@
* Internal functions for RSA keys.
******************************************************************************/
#if defined(MBEDTLS_RSA_C)
/*
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
*/
static int pk_write_rsa_pubkey(unsigned char **p, unsigned char *start,
const mbedtls_pk_context *pk)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
mbedtls_mpi T;
mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
mbedtls_mpi_init(&T);
/* Export E */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &T)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export N */
if ((ret = mbedtls_rsa_export(rsa, &T, NULL, NULL, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
end_of_export:
mbedtls_mpi_free(&T);
if (ret < 0) {
return ret;
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE));
return (int) len;
}
static int pk_write_rsa_der(unsigned char **p, unsigned char *buf,
const mbedtls_pk_context *pk)
{
size_t len = 0;
int ret;
#if defined(MBEDTLS_USE_PSA_CRYPTO)
if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_OPAQUE) {
uint8_t tmp[PSA_EXPORT_KEY_PAIR_MAX_SIZE];
size_t tmp_len = 0;
size_t len = 0, tmp_len = 0;
if (psa_export_key(pk->priv_id, tmp, sizeof(tmp), &tmp_len) != PSA_SUCCESS) {
return MBEDTLS_ERR_PK_BAD_INPUT_DATA;
@ -118,94 +74,11 @@ static int pk_write_rsa_der(unsigned char **p, unsigned char *buf,
memcpy(*p, tmp, tmp_len);
len += tmp_len;
mbedtls_platform_zeroize(tmp, sizeof(tmp));
} else
#endif /* MBEDTLS_USE_PSA_CRYPTO */
{
mbedtls_mpi T; /* Temporary holding the exported parameters */
mbedtls_rsa_context *rsa = mbedtls_pk_rsa(*pk);
/*
* Export the parameters one after another to avoid simultaneous copies.
*/
mbedtls_mpi_init(&T);
/* Export QP */
if ((ret = mbedtls_rsa_export_crt(rsa, NULL, NULL, &T)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export DQ */
if ((ret = mbedtls_rsa_export_crt(rsa, NULL, &T, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export DP */
if ((ret = mbedtls_rsa_export_crt(rsa, &T, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export Q */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
&T, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export P */
if ((ret = mbedtls_rsa_export(rsa, NULL, &T,
NULL, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export D */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
NULL, &T, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export E */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL,
NULL, NULL, &T)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export N */
if ((ret = mbedtls_rsa_export(rsa, &T, NULL,
NULL, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, buf, &T)) < 0) {
goto end_of_export;
}
len += ret;
end_of_export:
mbedtls_mpi_free(&T);
if (ret < 0) {
return ret;
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, buf, 0));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, buf, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p,
buf, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE));
return (int) len;
}
return (int) len;
#endif /* MBEDTLS_USE_PSA_CRYPTO */
return mbedtls_rsa_write_key(mbedtls_pk_rsa(*pk), buf, p);
}
#endif /* MBEDTLS_RSA_C */
@ -543,7 +416,7 @@ int mbedtls_pk_write_pubkey(unsigned char **p, unsigned char *start,
#if defined(MBEDTLS_RSA_C)
if (mbedtls_pk_get_type(key) == MBEDTLS_PK_RSA) {
MBEDTLS_ASN1_CHK_ADD(len, pk_write_rsa_pubkey(p, start, key));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_rsa_write_pubkey(mbedtls_pk_rsa(*key), start, p));
} else
#endif
#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)

View file

@ -24,8 +24,7 @@
#include <mbedtls/rsa.h>
#include <mbedtls/error.h>
#include <mbedtls/pk.h>
#include "pk_wrap.h"
#include "rsa_internal.h"
#if defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) || \
defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_OAEP) || \
@ -62,50 +61,38 @@ psa_status_t mbedtls_psa_rsa_load_representation(
mbedtls_rsa_context **p_rsa)
{
psa_status_t status;
mbedtls_pk_context ctx;
size_t bits;
mbedtls_pk_init(&ctx);
*p_rsa = mbedtls_calloc(1, sizeof(mbedtls_rsa_context));
if (*p_rsa == NULL) {
return PSA_ERROR_INSUFFICIENT_MEMORY;
}
mbedtls_rsa_init(*p_rsa);
/* Parse the data. */
if (PSA_KEY_TYPE_IS_KEY_PAIR(type)) {
status = mbedtls_to_psa_error(
mbedtls_pk_parse_key(&ctx, data, data_length, NULL, 0,
mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE));
status = mbedtls_to_psa_error(mbedtls_rsa_parse_key(*p_rsa, data, data_length));
} else {
status = mbedtls_to_psa_error(
mbedtls_pk_parse_public_key(&ctx, data, data_length));
status = mbedtls_to_psa_error(mbedtls_rsa_parse_pubkey(*p_rsa, data, data_length));
}
if (status != PSA_SUCCESS) {
goto exit;
}
/* We have something that the pkparse module recognizes. If it is a
* valid RSA key, store it. */
if (mbedtls_pk_get_type(&ctx) != MBEDTLS_PK_RSA) {
status = PSA_ERROR_INVALID_ARGUMENT;
goto exit;
}
/* The size of an RSA key doesn't have to be a multiple of 8. Mbed TLS
* supports non-byte-aligned key sizes, but not well. For example,
* mbedtls_rsa_get_len() returns the key size in bytes, not in bits. */
bits = PSA_BYTES_TO_BITS(mbedtls_rsa_get_len(mbedtls_pk_rsa(ctx)));
bits = PSA_BYTES_TO_BITS(mbedtls_rsa_get_len(*p_rsa));
if (bits > PSA_VENDOR_RSA_MAX_KEY_BITS) {
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
}
status = psa_check_rsa_key_byte_aligned(mbedtls_pk_rsa(ctx));
status = psa_check_rsa_key_byte_aligned(*p_rsa);
if (status != PSA_SUCCESS) {
goto exit;
}
/* Copy out the pointer to the RSA context, and reset the PK context
* such that pk_free doesn't free the RSA context we just grabbed. */
*p_rsa = mbedtls_pk_rsa(ctx);
ctx.pk_info = NULL;
exit:
mbedtls_pk_free(&ctx);
return status;
}
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_RSA_PKCS1V15_CRYPT) ||
@ -168,20 +155,15 @@ psa_status_t mbedtls_psa_rsa_export_key(psa_key_type_t type,
size_t *data_length)
{
int ret;
mbedtls_pk_context pk;
uint8_t *pos = data + data_size;
mbedtls_pk_init(&pk);
pk.pk_info = &mbedtls_rsa_info;
pk.pk_ctx = rsa;
uint8_t *end = data + data_size;
/* PSA Crypto API defines the format of an RSA key as a DER-encoded
* representation of the non-encrypted PKCS#1 RSAPrivateKey for a
* private key and of the RFC3279 RSAPublicKey for a public key. */
if (PSA_KEY_TYPE_IS_KEY_PAIR(type)) {
ret = mbedtls_pk_write_key_der(&pk, data, data_size);
ret = mbedtls_rsa_write_key(rsa, data, &end);
} else {
ret = mbedtls_pk_write_pubkey(&pos, data, &pk);
ret = mbedtls_rsa_write_pubkey(rsa, data, &end);
}
if (ret < 0) {

View file

@ -32,6 +32,7 @@
#include "rsa_alt_helpers.h"
#include "rsa_internal.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/platform_util.h"
#include "mbedtls/error.h"
#include "constant_time_internal.h"
@ -46,6 +47,367 @@
#include "mbedtls/platform.h"
/*
* 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_RSA_BAD_INPUT_DATA;
}
return 0;
}
int mbedtls_rsa_parse_key(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 ret;
}
/* mbedtls_asn1_get_tag() already ensures that len is valid (i.e. p+len <= end)*/
end = p + len;
if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
return ret;
}
if (version != 0) {
return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
}
/* 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_ERR_ASN1_LENGTH_MISMATCH;
}
cleanup:
mbedtls_mpi_free(&T);
if (ret != 0) {
mbedtls_rsa_free(rsa);
}
return ret;
}
int mbedtls_rsa_parse_pubkey(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen)
{
unsigned char *p = (unsigned char *) key;
unsigned char *end = (unsigned char *) (key + keylen);
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len;
/*
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
*/
if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
return ret;
}
/* mbedtls_asn1_get_tag() already ensures that len is valid (i.e. p+len <= end)*/
end = p + len;
/* Import N */
if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
return ret;
}
if ((ret = mbedtls_rsa_import_raw(rsa, p, len, NULL, 0, NULL, 0,
NULL, 0, NULL, 0)) != 0) {
return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
}
p += len;
/* Import E */
if ((ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
return ret;
}
if ((ret = mbedtls_rsa_import_raw(rsa, NULL, 0, NULL, 0, NULL, 0,
NULL, 0, p, len)) != 0) {
return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
}
p += len;
if (mbedtls_rsa_complete(rsa) != 0 ||
mbedtls_rsa_check_pubkey(rsa) != 0) {
return MBEDTLS_ERR_RSA_BAD_INPUT_DATA;
}
if (p != end) {
return MBEDTLS_ERR_ASN1_LENGTH_MISMATCH;
}
return 0;
}
int mbedtls_rsa_write_key(const mbedtls_rsa_context *rsa, unsigned char *start,
unsigned char **p)
{
size_t len = 0;
int ret;
mbedtls_mpi T; /* Temporary holding the exported parameters */
/*
* Export the parameters one after another to avoid simultaneous copies.
*/
mbedtls_mpi_init(&T);
/* Export QP */
if ((ret = mbedtls_rsa_export_crt(rsa, NULL, NULL, &T)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export DQ */
if ((ret = mbedtls_rsa_export_crt(rsa, NULL, &T, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export DP */
if ((ret = mbedtls_rsa_export_crt(rsa, &T, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export Q */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, &T, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export P */
if ((ret = mbedtls_rsa_export(rsa, NULL, &T, NULL, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export D */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, &T, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export E */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &T)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export N */
if ((ret = mbedtls_rsa_export(rsa, &T, NULL, NULL, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
end_of_export:
mbedtls_mpi_free(&T);
if (ret < 0) {
return ret;
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_int(p, start, 0));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE));
return (int) len;
}
/*
* RSAPublicKey ::= SEQUENCE {
* modulus INTEGER, -- n
* publicExponent INTEGER -- e
* }
*/
int mbedtls_rsa_write_pubkey(const mbedtls_rsa_context *rsa, unsigned char *start,
unsigned char **p)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
mbedtls_mpi T;
mbedtls_mpi_init(&T);
/* Export E */
if ((ret = mbedtls_rsa_export(rsa, NULL, NULL, NULL, NULL, &T)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
/* Export N */
if ((ret = mbedtls_rsa_export(rsa, &T, NULL, NULL, NULL, NULL)) != 0 ||
(ret = mbedtls_asn1_write_mpi(p, start, &T)) < 0) {
goto end_of_export;
}
len += ret;
end_of_export:
mbedtls_mpi_free(&T);
if (ret < 0) {
return ret;
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE));
return (int) len;
}
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
@ -660,7 +1022,6 @@ size_t mbedtls_rsa_get_len(const mbedtls_rsa_context *ctx)
return ctx->len;
}
#if defined(MBEDTLS_GENPRIME)
/*

View file

@ -15,6 +15,85 @@
#define MBEDTLS_RSA_INTERNAL_H
#include "mbedtls/rsa.h"
#include "mbedtls/asn1.h"
/**
* \brief Parse a PKCS#1 (ASN.1) encoded private RSA key.
*
* \param rsa The RSA context where parsed data will be stored.
* \param key The buffer that contains the key.
* \param keylen The length of the key buffer in bytes.
*
* \return 0 on success.
* \return MBEDTLS_ERR_ASN1_xxx in case of ASN.1 parsing errors.
* \return MBEDTLS_ERR_RSA_xxx in case of RSA internal failures while
* parsing data.
* \return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if validity checks on the
* provided key fail.
*/
int mbedtls_rsa_parse_key(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen);
/**
* \brief Parse a PKCS#1 (ASN.1) encoded public RSA key.
*
* \param rsa The RSA context where parsed data will be stored.
* \param key The buffer that contains the key.
* \param keylen The length of the key buffer in bytes.
*
* \return 0 on success.
* \return MBEDTLS_ERR_ASN1_xxx in case of ASN.1 parsing errors.
* \return MBEDTLS_ERR_RSA_xxx in case of RSA internal failures while
* parsing data.
* \return MBEDTLS_ERR_RSA_KEY_CHECK_FAILED if validity checks on the
* provided key fail.
*/
int mbedtls_rsa_parse_pubkey(mbedtls_rsa_context *rsa, const unsigned char *key, size_t keylen);
/**
* \brief Write a PKCS#1 (ASN.1) encoded private RSA key.
*
* \param rsa The RSA context which contains the data to be written.
* \param start Beginning of the buffer that will be filled with the
* private key.
* \param p End of the buffer that will be filled with the private key.
* On successful return, the referenced pointer will be
* updated in order to point to the beginning of written data.
*
* \return On success, the number of bytes written to the output buffer
* (i.e. a value > 0).
* \return MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the RSA context does not
* contain a valid key pair.
* \return MBEDTLS_ERR_ASN1_xxx in case of failure while writing to the
* output buffer.
*
* \note The output buffer is filled backward, i.e. starting from its
* end and moving toward its start.
*/
int mbedtls_rsa_write_key(const mbedtls_rsa_context *rsa, unsigned char *start,
unsigned char **p);
/**
* \brief Parse a PKCS#1 (ASN.1) encoded public RSA key.
*
* \param rsa The RSA context which contains the data to be written.
* \param start Beginning of the buffer that will be filled with the
* private key.
* \param p End of the buffer that will be filled with the private key.
* On successful return, the referenced pointer will be
* updated in order to point to the beginning of written data.
*
* \return On success, the number of bytes written to the output buffer
* (i.e. a value > 0).
* \return MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the RSA context does not
* contain a valid public key.
* \return MBEDTLS_ERR_ASN1_xxx in case of failure while writing to the
* output buffer.
*
* \note The output buffer is filled backward, i.e. starting from its
* end and moving toward its start.
*/
int mbedtls_rsa_write_pubkey(const mbedtls_rsa_context *rsa, unsigned char *start,
unsigned char **p);
#if defined(MBEDTLS_PKCS1_V21)
/**