core/crypto/rsa_mbedtls.c (395 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#include <stdlib.h>
#include <string.h>
#include "crypto_logging.h"
#include "platform_api.h"
#include "rsa_mbedtls.h"
#include "logging/debug_log.h"
#include "mbedtls/pk.h"
#include "mbedtls/pk_internal.h"
#include "mbedtls/rsa.h"
#define RSA_PRIV_DER_MAX_SIZE 47 + (3 * MBEDTLS_MPI_MAX_SIZE) + \
(5 * ((MBEDTLS_MPI_MAX_SIZE / 2) + (MBEDTLS_MPI_MAX_SIZE % 2)))
#define RSA_PUB_DER_MAX_SIZE 38 + (2 * MBEDTLS_MPI_MAX_SIZE)
/**
* Get the mbedTLS RSA key instance for a private key instance.
*
* @return The mbedTLS RSA key.
*/
#define rsa_mbedtls_get_rsa_key(x) mbedtls_pk_rsa (*((mbedtls_pk_context*) x->context))
#if (defined RSA_ENABLE_PRIVATE_KEY || defined RSA_ENABLE_DER_PUBLIC_KEY)
/**
* Allocate and initialize a context for an RSA key.
*
* @return The initialized key context or null.
*/
static mbedtls_pk_context* rsa_mbedtls_alloc_key_context ()
{
mbedtls_pk_context *key = platform_malloc (sizeof (mbedtls_pk_context));
if (key != NULL) {
mbedtls_pk_init (key);
}
return key;
}
/**
* Zeroize an RSA key context and free the memory.
*
* @param context The context to free.
*/
static void rsa_mbedtls_free_key_context (void *context)
{
mbedtls_pk_free ((mbedtls_pk_context*) context);
platform_free (context);
}
#endif
#ifdef RSA_ENABLE_PRIVATE_KEY
int rsa_mbedtls_generate_key (const struct rsa_engine *engine, struct rsa_private_key *key,
int bits)
{
const struct rsa_engine_mbedtls *mbedtls = (const struct rsa_engine_mbedtls*) engine;
mbedtls_pk_context *rsa;
uint8_t msg_code;
int status;
if ((mbedtls == NULL) || (key == NULL)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
rsa = rsa_mbedtls_alloc_key_context ();
if (rsa == NULL) {
return RSA_ENGINE_NO_MEMORY;
}
status = mbedtls_pk_setup (rsa, mbedtls_pk_info_from_type (MBEDTLS_PK_RSA));
if (status != 0) {
msg_code = CRYPTO_LOG_MSG_MBEDTLS_PK_INIT_EC;
goto error;
}
status = mbedtls_rsa_gen_key (mbedtls_pk_rsa (*rsa), mbedtls_ctr_drbg_random,
&mbedtls->state->ctr_drbg, bits, 65537);
if (status != 0) {
msg_code = CRYPTO_LOG_MSG_MBEDTLS_RSA_GEN_KEY_EC;
goto error;
}
mbedtls_rsa_set_padding (mbedtls_pk_rsa (*rsa), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
key->context = rsa;
return 0;
error:
rsa_mbedtls_free_key_context (rsa);
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, msg_code, status,
0);
return status;
}
int rsa_mbedtls_init_private_key (const struct rsa_engine *engine, struct rsa_private_key *key,
const uint8_t *der, size_t length)
{
mbedtls_pk_context *rsa;
int status;
if ((engine == NULL) || (key == NULL) || (der == NULL) || (length == 0)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
memset (key, 0, sizeof (struct rsa_private_key));
rsa = rsa_mbedtls_alloc_key_context ();
if (rsa == NULL) {
return RSA_ENGINE_NO_MEMORY;
}
status = mbedtls_pk_parse_key (rsa, der, length, NULL, 0);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_PK_PARSE_EC, status, 0);
goto error;
}
if (mbedtls_pk_get_type (rsa) != MBEDTLS_PK_RSA) {
status = RSA_ENGINE_NOT_RSA_KEY;
goto error;
}
mbedtls_rsa_set_padding (mbedtls_pk_rsa (*rsa), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
key->context = rsa;
return 0;
error:
rsa_mbedtls_free_key_context (rsa);
return status;
}
void rsa_mbedtls_release_key (const struct rsa_engine *engine, struct rsa_private_key *key)
{
if (engine && key) {
rsa_mbedtls_free_key_context (key->context);
}
}
int rsa_mbedtls_get_private_key_der (const struct rsa_engine *engine,
const struct rsa_private_key *key, uint8_t **der, size_t *length)
{
int status;
if (der == NULL) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
*der = NULL;
if ((engine == NULL) || (key == NULL) || (length == NULL)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
*der = platform_malloc (RSA_PRIV_DER_MAX_SIZE);
if (*der == NULL) {
return RSA_ENGINE_NO_MEMORY;
}
status = mbedtls_pk_write_key_der ((mbedtls_pk_context*) key->context, *der,
RSA_PRIV_DER_MAX_SIZE);
if (status >= 0) {
memmove (*der, &(*der)[RSA_PRIV_DER_MAX_SIZE - status], status);
*length = status;
status = 0;
}
else {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_PK_WRITE_KEY_DER_EC, status, 0);
platform_free (*der);
*der = NULL;
}
return status;
}
int rsa_mbedtls_decrypt (const struct rsa_engine *engine, const struct rsa_private_key *key,
const uint8_t *encrypted, size_t in_length, const uint8_t *label, size_t label_length,
enum hash_type pad_hash, uint8_t *decrypted, size_t out_length)
{
const struct rsa_engine_mbedtls *mbedtls = (const struct rsa_engine_mbedtls*) engine;
int status;
size_t length;
if ((mbedtls == NULL) || (key == NULL) || (encrypted == NULL) || (in_length == 0) ||
(decrypted == NULL)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
if (pad_hash > HASH_TYPE_SHA256) {
return RSA_ENGINE_UNSUPPORTED_HASH_TYPE;
}
#ifndef MBEDTLS_SHA1_C
if (pad_hash == HASH_TYPE_SHA1) {
return RSA_ENGINE_UNSUPPORTED_HASH_TYPE;
}
#endif
#ifndef MBEDTLS_SHA256_C
if (pad_hash == HASH_TYPE_SHA256) {
return RSA_ENGINE_UNSUPPORTED_HASH_TYPE;
}
#endif
if (pad_hash == HASH_TYPE_SHA256) {
mbedtls_rsa_set_padding (rsa_mbedtls_get_rsa_key (key), MBEDTLS_RSA_PKCS_V21,
MBEDTLS_MD_SHA256);
}
status = mbedtls_rsa_rsaes_oaep_decrypt (rsa_mbedtls_get_rsa_key (key), mbedtls_ctr_drbg_random,
&mbedtls->state->ctr_drbg, MBEDTLS_RSA_PRIVATE, label, label_length, &length, encrypted,
decrypted, out_length);
if (status == 0) {
status = length;
}
else {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_RSA_OAEP_DECRYPT_EC, status, 0);
if (status == MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE) {
status = RSA_ENGINE_OUT_BUFFER_TOO_SMALL;
}
}
/* Restore the padding hash algorithm to the default. */
mbedtls_rsa_set_padding (rsa_mbedtls_get_rsa_key (key), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);
return status;
}
#endif
#ifdef RSA_ENABLE_DER_PUBLIC_KEY
int rsa_mbedtls_init_public_key (const struct rsa_engine *engine, struct rsa_public_key *key,
const uint8_t *der, size_t length)
{
mbedtls_pk_context *pk;
mbedtls_rsa_context *rsa;
uint8_t exp[4];
int status;
if ((engine == NULL) || (key == NULL) || (der == NULL) || (length == 0)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
memset (key, 0, sizeof (struct rsa_public_key));
pk = rsa_mbedtls_alloc_key_context ();
if (pk == NULL) {
return RSA_ENGINE_NO_MEMORY;
}
status = mbedtls_pk_parse_public_key (pk, der, length);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_PK_PARSE_PUB_EC, status, 0);
goto exit;
}
if (mbedtls_pk_get_type (pk) != MBEDTLS_PK_RSA) {
status = RSA_ENGINE_NOT_RSA_KEY;
goto exit;
}
rsa = (mbedtls_rsa_context*) pk->pk_ctx;
status = mbedtls_rsa_check_pubkey (rsa);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_RSA_PUBKEY_CHECK_EC, status, 0);
goto exit;
}
key->mod_length = mbedtls_mpi_size (&rsa->N);
if (key->mod_length > sizeof (key->modulus)) {
status = RSA_ENGINE_UNSUPPORTED_KEY_LENGTH;
goto exit;
}
status = mbedtls_mpi_write_binary (&rsa->N, key->modulus, key->mod_length);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_MPI_WRITE_BIN_EC, status, 0);
goto exit;
}
status = mbedtls_mpi_write_binary (&rsa->E, exp, sizeof (exp));
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_MPI_WRITE_BIN_EC, status, 0);
if (status == MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) {
status = RSA_ENGINE_UNSUPPORTED_KEY_LENGTH;
}
goto exit;
}
key->exponent = (exp[0] << 24) | (exp[1] << 16) | (exp[2] << 8) | exp[3];
exit:
rsa_mbedtls_free_key_context (pk);
return status;
}
int rsa_mbedtls_get_public_key_der (const struct rsa_engine *engine,
const struct rsa_private_key *key, uint8_t **der, size_t *length)
{
int status;
if (der == NULL) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
*der = NULL;
if ((engine == NULL) || (key == NULL) || (length == NULL)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
*der = platform_malloc (RSA_PUB_DER_MAX_SIZE);
if (*der == NULL) {
return RSA_ENGINE_NO_MEMORY;
}
status = mbedtls_pk_write_pubkey_der ((mbedtls_pk_context*) key->context, *der,
RSA_PUB_DER_MAX_SIZE);
if (status >= 0) {
memmove (*der, &(*der)[RSA_PUB_DER_MAX_SIZE - status], status);
*length = status;
status = 0;
}
else {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_PK_WRITE_PUBKEY_DER_EC, status, 0);
platform_free (*der);
*der = NULL;
}
return status;
}
#endif
/**
* Initialize an RSA context with a specified public key.
*
* @param rsa The RSA context to initialize.
* @param key The key to use for context initialization.
*
* @return 0 if the operation was successful or an error code.
*/
static int rsa_mbedtls_load_pubkey (mbedtls_rsa_context *rsa, const struct rsa_public_key *key)
{
int status;
uint8_t exp[4];
uint8_t msg_code;
mbedtls_rsa_init (rsa, MBEDTLS_RSA_PKCS_V15, 0);
exp[0] = key->exponent >> 24;
exp[1] = key->exponent >> 16;
exp[2] = key->exponent >> 8;
exp[3] = key->exponent;
status = mbedtls_mpi_read_binary (&rsa->N, key->modulus, key->mod_length);
if (status != 0) {
msg_code = CRYPTO_LOG_MSG_MBEDTLS_MPI_READ_BIN_EC;
goto exit;
}
status = mbedtls_mpi_read_binary (&rsa->E, exp, sizeof (exp));
if (status != 0) {
msg_code = CRYPTO_LOG_MSG_MBEDTLS_MPI_READ_BIN_EC;
goto exit;
}
rsa->len = mbedtls_mpi_size (&rsa->N);
status = mbedtls_rsa_check_pubkey (rsa);
if (status != 0) {
msg_code = CRYPTO_LOG_MSG_MBEDTLS_RSA_PUBKEY_CHECK_EC;
goto exit;
}
return 0;
exit:
mbedtls_rsa_free (rsa);
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, msg_code, status,
0);
return status;
}
int rsa_mbedtls_sig_verify (const struct rsa_engine *engine, const struct rsa_public_key *key,
const uint8_t *signature, size_t sig_length, enum hash_type sig_hash, const uint8_t *match,
size_t match_length)
{
mbedtls_rsa_context rsa;
mbedtls_md_type_t match_type;
int status;
if ((engine == NULL) || (key == NULL) || (signature == NULL) || (match == NULL) ||
(sig_length == 0) || (match_length == 0)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
switch (sig_hash) {
case HASH_TYPE_SHA256:
match_type = MBEDTLS_MD_SHA256;
break;
case HASH_TYPE_SHA384:
match_type = MBEDTLS_MD_SHA384;
break;
case HASH_TYPE_SHA512:
match_type = MBEDTLS_MD_SHA512;
break;
default:
return RSA_ENGINE_UNSUPPORTED_SIG_TYPE;
}
if (sig_length != key->mod_length) {
return RSA_ENGINE_BAD_SIGNATURE;
}
status = rsa_mbedtls_load_pubkey (&rsa, key);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_RSA_PUBKEY_LOAD_EC, status, 0);
return status;
}
status = mbedtls_rsa_pkcs1_verify (&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, match_type,
match_length, match, signature);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_RSA_PKCS1_VERIFY_EC, status, 0);
if ((status == MBEDTLS_ERR_MPI_ALLOC_FAILED) ||
(status == (MBEDTLS_ERR_MPI_ALLOC_FAILED + MBEDTLS_ERR_RSA_PUBLIC_FAILED))) {
status = RSA_ENGINE_NO_MEMORY;
}
else {
status = RSA_ENGINE_BAD_SIGNATURE;
}
}
mbedtls_rsa_free (&rsa);
return status;
}
/**
* Initialize an mbedTLS RSA engine.
*
* @param engine The RSA engine to initialize.
* @param state Variable context for RSA operations. This must be uninitialized.
*
* @return 0 if the RSA engine was successfully initialize or an error code.
*/
int rsa_mbedtls_init (struct rsa_engine_mbedtls *engine, struct rsa_engine_mbedtls_state *state)
{
if (engine == NULL) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
memset (engine, 0, sizeof (struct rsa_engine_mbedtls));
#ifdef RSA_ENABLE_PRIVATE_KEY
engine->base.generate_key = rsa_mbedtls_generate_key;
engine->base.init_private_key = rsa_mbedtls_init_private_key;
engine->base.release_key = rsa_mbedtls_release_key;
engine->base.get_private_key_der = rsa_mbedtls_get_private_key_der;
engine->base.decrypt = rsa_mbedtls_decrypt;
#endif
#ifdef RSA_ENABLE_DER_PUBLIC_KEY
engine->base.init_public_key = rsa_mbedtls_init_public_key;
engine->base.get_public_key_der = rsa_mbedtls_get_public_key_der;
#endif
engine->base.sig_verify = rsa_mbedtls_sig_verify;
engine->state = state;
return rsa_mbedtls_init_state (engine);
}
/**
* Initialize only the variable state of an mbedTLS RSA engine. The rest of the instance is assumed
* to already have been initialized.
*
* This would generally be used with a statically initialized instance.
*
* @param engine The RSA engine that contains the state to initialize.
*
* @return 0 if the state was successfully initialized or an error code.
*/
int rsa_mbedtls_init_state (const struct rsa_engine_mbedtls *engine)
{
int status;
if ((engine == NULL) || (engine->state == NULL)) {
return RSA_ENGINE_INVALID_ARGUMENT;
}
memset (engine->state, 0, sizeof (*engine->state));
mbedtls_ctr_drbg_init (&engine->state->ctr_drbg);
mbedtls_entropy_init (&engine->state->entropy);
status = mbedtls_ctr_drbg_seed (&engine->state->ctr_drbg, mbedtls_entropy_func,
&engine->state->entropy, NULL, 0);
if (status != 0) {
debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO,
CRYPTO_LOG_MSG_MBEDTLS_CTR_DRBG_SEED_EC, status, 0);
goto exit;
}
return 0;
exit:
mbedtls_entropy_free (&engine->state->entropy);
mbedtls_ctr_drbg_free (&engine->state->ctr_drbg);
return status;
}
/**
* Release the resources used by an mbedTLS RSA engine.
*
* @param engine The RSA engine to release.
*/
void rsa_mbedtls_release (const struct rsa_engine_mbedtls *engine)
{
if (engine) {
mbedtls_entropy_free (&engine->state->entropy);
mbedtls_ctr_drbg_free (&engine->state->ctr_drbg);
}
}