/** @file | |
RSA Asymmetric Cipher Wrapper Implementation over MbedTLS. | |
This file implements following APIs which provide more capabilities for RSA: | |
1) RsaGetKey | |
2) RsaGenerateKey | |
3) RsaCheckKey | |
4) RsaPkcs1Sign | |
RFC 8017 - PKCS #1: RSA Cryptography Specifications Version 2.2 | |
Copyright (c) 2024, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "InternalCryptLib.h" | |
#include <mbedtls/rsa.h> | |
/** | |
Gets the tag-designated RSA key component from the established RSA context. | |
This function retrieves the tag-designated RSA key component from the | |
established RSA context as a non-negative integer (octet string format | |
represented in RSA PKCS#1). | |
If specified key component has not been set or has been cleared, then returned | |
BnSize is set to 0. | |
If the BigNumber buffer is too small to hold the contents of the key, FALSE | |
is returned and BnSize is set to the required buffer size to obtain the key. | |
If RsaContext is NULL, then return FALSE. | |
If BnSize is NULL, then return FALSE. | |
If BnSize is large enough but BigNumber is NULL, then return FALSE. | |
@param[in, out] RsaContext Pointer to RSA context being set. | |
@param[in] KeyTag Tag of RSA key component being set. | |
@param[out] BigNumber Pointer to octet integer buffer. | |
@param[in, out] BnSize On input, the size of big number buffer in bytes. | |
On output, the size of data returned in big number buffer in bytes. | |
@retval TRUE RSA key component was retrieved successfully. | |
@retval FALSE Invalid RSA key component tag. | |
@retval FALSE BnSize is too small. | |
**/ | |
BOOLEAN | |
EFIAPI | |
RsaGetKey ( | |
IN OUT VOID *RsaContext, | |
IN RSA_KEY_TAG KeyTag, | |
OUT UINT8 *BigNumber, | |
IN OUT UINTN *BnSize | |
) | |
{ | |
mbedtls_rsa_context *RsaKey; | |
INT32 Ret; | |
mbedtls_mpi Value; | |
UINTN Size; | |
// | |
// Check input parameters. | |
// | |
if ((RsaContext == NULL) || (*BnSize > INT_MAX)) { | |
return FALSE; | |
} | |
// | |
// Init mbedtls_mpi | |
// | |
mbedtls_mpi_init (&Value); | |
Size = *BnSize; | |
*BnSize = 0; | |
RsaKey = (mbedtls_rsa_context *)RsaContext; | |
switch (KeyTag) { | |
case RsaKeyN: | |
Ret = mbedtls_rsa_export (RsaKey, &Value, NULL, NULL, NULL, NULL); | |
break; | |
case RsaKeyE: | |
Ret = mbedtls_rsa_export (RsaKey, NULL, NULL, NULL, NULL, &Value); | |
break; | |
case RsaKeyD: | |
Ret = mbedtls_rsa_export (RsaKey, NULL, NULL, NULL, &Value, NULL); | |
break; | |
case RsaKeyQ: | |
Ret = mbedtls_rsa_export (RsaKey, NULL, NULL, &Value, NULL, NULL); | |
break; | |
case RsaKeyP: | |
Ret = mbedtls_rsa_export (RsaKey, NULL, &Value, NULL, NULL, NULL); | |
break; | |
case RsaKeyDp: | |
case RsaKeyDq: | |
case RsaKeyQInv: | |
default: | |
Ret = -1; | |
break; | |
} | |
if (Ret != 0) { | |
goto End; | |
} | |
if (mbedtls_mpi_size (&Value) == 0) { | |
Ret = 0; | |
goto End; | |
} | |
*BnSize = Size; | |
Size = mbedtls_mpi_size (&Value); | |
if (*BnSize < Size) { | |
Ret = 1; | |
*BnSize = Size; | |
goto End; | |
} | |
if (BigNumber == NULL) { | |
Ret = 0; | |
*BnSize = Size; | |
goto End; | |
} | |
if ((BigNumber != NULL) && (Ret == 0)) { | |
Ret = mbedtls_mpi_write_binary (&Value, BigNumber, Size); | |
*BnSize = Size; | |
} | |
End: | |
mbedtls_mpi_free (&Value); | |
return Ret == 0; | |
} | |
/** | |
Generates RSA key components. | |
This function generates RSA key components. It takes RSA public exponent Pe and | |
length in bits of RSA modulus N as input, and generates all key components. | |
If PublicExponent is NULL, the default RSA public exponent (0x10001) will be used. | |
Before this function can be invoked, pseudorandom number generator must be correctly | |
initialized by RandomSeed(). | |
If RsaContext is NULL, then return FALSE. | |
@param[in, out] RsaContext Pointer to RSA context being set. | |
@param[in] ModulusLength Length of RSA modulus N in bits. | |
@param[in] PublicExponent Pointer to RSA public exponent. | |
@param[in] PublicExponentSize Size of RSA public exponent buffer in bytes. | |
@retval TRUE RSA key component was generated successfully. | |
@retval FALSE Invalid RSA key component tag. | |
**/ | |
BOOLEAN | |
EFIAPI | |
RsaGenerateKey ( | |
IN OUT VOID *RsaContext, | |
IN UINTN ModulusLength, | |
IN CONST UINT8 *PublicExponent, | |
IN UINTN PublicExponentSize | |
) | |
{ | |
INT32 Ret; | |
mbedtls_rsa_context *Rsa; | |
INT32 Pe; | |
// | |
// Check input parameters. | |
// | |
if ((RsaContext == NULL) || (ModulusLength > INT_MAX) || (PublicExponentSize > INT_MAX)) { | |
return FALSE; | |
} | |
Rsa = (mbedtls_rsa_context *)RsaContext; | |
if (PublicExponent == NULL) { | |
Pe = 0x10001; | |
} else { | |
if (PublicExponentSize == 0) { | |
return FALSE; | |
} | |
switch (PublicExponentSize) { | |
case 1: | |
Pe = PublicExponent[0]; | |
break; | |
case 2: | |
Pe = PublicExponent[0] << 8 | PublicExponent[1]; | |
break; | |
case 3: | |
Pe = PublicExponent[0] << 16 | PublicExponent[1] << 8 | | |
PublicExponent[2]; | |
break; | |
case 4: | |
Pe = PublicExponent[0] << 24 | PublicExponent[1] << 16 | | |
PublicExponent[2] << 8 | PublicExponent[3]; | |
break; | |
default: | |
return FALSE; | |
} | |
} | |
Ret = mbedtls_rsa_gen_key ( | |
Rsa, | |
MbedtlsRand, | |
NULL, | |
(UINT32)ModulusLength, | |
Pe | |
); | |
return Ret == 0; | |
} | |
/** | |
Validates key components of RSA context. | |
NOTE: This function performs integrity checks on all the RSA key material, so | |
the RSA key structure must contain all the private key data. | |
This function validates key components of RSA context in following aspects: | |
- Whether p is a prime | |
- Whether q is a prime | |
- Whether n = p * q | |
- Whether d*e = 1 mod lcm(p-1,q-1) | |
If RsaContext is NULL, then return FALSE. | |
@param[in] RsaContext Pointer to RSA context to check. | |
@retval TRUE RSA key components are valid. | |
@retval FALSE RSA key components are not valid. | |
**/ | |
BOOLEAN | |
EFIAPI | |
RsaCheckKey ( | |
IN VOID *RsaContext | |
) | |
{ | |
if (RsaContext == NULL) { | |
return FALSE; | |
} | |
UINT32 Ret; | |
Ret = mbedtls_rsa_complete (RsaContext); | |
if (Ret == 0) { | |
Ret = mbedtls_rsa_check_privkey (RsaContext); | |
} | |
return Ret == 0; | |
} | |
/** | |
Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme. | |
This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in | |
RSA PKCS#1. | |
If the Signature buffer is too small to hold the contents of signature, FALSE | |
is returned and SigSize is set to the required buffer size to obtain the signature. | |
If RsaContext is NULL, then return FALSE. | |
If MessageHash is NULL, then return FALSE. | |
If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-384 or SHA-512 digest, then return FALSE. | |
If SigSize is large enough but Signature is NULL, then return FALSE. | |
@param[in] RsaContext Pointer to RSA context for signature generation. | |
@param[in] MessageHash Pointer to octet message hash to be signed. | |
@param[in] HashSize Size of the message hash in bytes. | |
@param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature. | |
@param[in, out] SigSize On input, the size of Signature buffer in bytes. | |
On output, the size of data returned in Signature buffer in bytes. | |
@retval TRUE Signature successfully generated in PKCS1-v1_5. | |
@retval FALSE Signature generation failed. | |
@retval FALSE SigSize is too small. | |
**/ | |
BOOLEAN | |
EFIAPI | |
RsaPkcs1Sign ( | |
IN VOID *RsaContext, | |
IN CONST UINT8 *MessageHash, | |
IN UINTN HashSize, | |
OUT UINT8 *Signature, | |
IN OUT UINTN *SigSize | |
) | |
{ | |
INT32 Ret; | |
mbedtls_md_type_t MdAlg; | |
if ((RsaContext == NULL) || (MessageHash == NULL)) { | |
return FALSE; | |
} | |
if (mbedtls_rsa_complete ((mbedtls_rsa_context *)RsaContext) != 0) { | |
return FALSE; | |
} | |
switch (HashSize) { | |
#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES | |
case SHA1_DIGEST_SIZE: | |
MdAlg = MBEDTLS_MD_SHA1; | |
break; | |
#endif | |
case SHA256_DIGEST_SIZE: | |
MdAlg = MBEDTLS_MD_SHA256; | |
break; | |
case SHA384_DIGEST_SIZE: | |
MdAlg = MBEDTLS_MD_SHA384; | |
break; | |
case SHA512_DIGEST_SIZE: | |
MdAlg = MBEDTLS_MD_SHA512; | |
break; | |
default: | |
return FALSE; | |
} | |
if (mbedtls_rsa_get_len (RsaContext) > *SigSize) { | |
*SigSize = mbedtls_rsa_get_len (RsaContext); | |
return FALSE; | |
} | |
if (Signature == NULL) { | |
return FALSE; | |
} | |
Ret = mbedtls_rsa_set_padding (RsaContext, MBEDTLS_RSA_PKCS_V15, MdAlg); | |
if (Ret != 0) { | |
return FALSE; | |
} | |
Ret = mbedtls_rsa_pkcs1_sign ( | |
RsaContext, | |
MbedtlsRand, | |
NULL, | |
MdAlg, | |
(UINT32)HashSize, | |
MessageHash, | |
Signature | |
); | |
if (Ret != 0) { | |
return FALSE; | |
} | |
*SigSize = mbedtls_rsa_get_len (RsaContext); | |
return TRUE; | |
} |