CryptoPkg: Add RSA functions based on Mbedtls

Add RSA APIs.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4177

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Yi Li <yi1.li@intel.com>
Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Signed-off-by: Wenxing Hou <wenxing.hou@intel.com>
Reviewed-by: Yi Li <yi1.li@intel.com>
This commit is contained in:
Wenxing Hou 2023-08-16 12:39:51 +08:00 committed by mergify[bot]
parent 60222e7eb9
commit 97f51f2e9b
8 changed files with 831 additions and 0 deletions

View File

@ -0,0 +1,25 @@
/** @file
Internal include file for BaseCryptLib.
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#ifndef INTERNAL_CRYPT_LIB_H_
#define INTERNAL_CRYPT_LIB_H_
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseCryptLib.h>
#include <stdio.h>
//
// We should alwasy add mbedtls/config.h here
// to ensure the config override takes effect.
//
#include <mbedtls/mbedtls_config.h>
#endif

View File

@ -0,0 +1,278 @@
/** @file
RSA Asymmetric Cipher Wrapper Implementation over MbedTLS.
This file implements following APIs which provide basic capabilities for RSA:
1) RsaNew
2) RsaFree
3) RsaSetKey
4) RsaPkcs1Verify
RFC 8017 - PKCS #1: RSA Cryptography Specifications Version 2.2
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalCryptLib.h"
#include <mbedtls/rsa.h>
/**
Allocates and initializes one RSA context for subsequent use.
@return Pointer to the RSA context that has been initialized.
If the allocations fails, RsaNew() returns NULL.
**/
VOID *
EFIAPI
RsaNew (
VOID
)
{
VOID *RsaContext;
RsaContext = AllocateZeroPool (sizeof (mbedtls_rsa_context));
if (RsaContext == NULL) {
return RsaContext;
}
mbedtls_rsa_init (RsaContext);
if (mbedtls_rsa_set_padding (RsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE) != 0) {
return NULL;
}
return RsaContext;
}
/**
Release the specified RSA context.
@param[in] RsaContext Pointer to the RSA context to be released.
**/
VOID
EFIAPI
RsaFree (
IN VOID *RsaContext
)
{
mbedtls_rsa_free (RsaContext);
if (RsaContext != NULL) {
FreePool (RsaContext);
}
}
/**
Sets the tag-designated key component into the established RSA context.
This function sets the tag-designated RSA key component into the established
RSA context from the user-specified non-negative integer (octet string format
represented in RSA PKCS#1).
If BigNumber is NULL, then the specified key component in RSA context is cleared.
If RsaContext 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[in] BigNumber Pointer to octet integer buffer.
If NULL, then the specified key component in RSA
context is cleared.
@param[in] BnSize Size of big number buffer in bytes.
If BigNumber is NULL, then it is ignored.
@retval TRUE RSA key component was set successfully.
@retval FALSE Invalid RSA key component tag.
**/
BOOLEAN
EFIAPI
RsaSetKey (
IN OUT VOID *RsaContext,
IN RSA_KEY_TAG KeyTag,
IN CONST UINT8 *BigNumber,
IN UINTN BnSize
)
{
mbedtls_rsa_context *RsaKey;
INT32 Ret;
mbedtls_mpi Value;
//
// Check input parameters.
//
if ((RsaContext == NULL) || (BnSize > INT_MAX)) {
return FALSE;
}
mbedtls_mpi_init (&Value);
RsaKey = (mbedtls_rsa_context *)RsaContext;
// if BigNumber is Null clear
if (BigNumber != NULL) {
Ret = mbedtls_mpi_read_binary (&Value, BigNumber, BnSize);
if (Ret != 0) {
mbedtls_mpi_free (&Value);
return FALSE;
}
}
switch (KeyTag) {
case RsaKeyN:
Ret = mbedtls_rsa_import (
RsaKey,
&Value,
NULL,
NULL,
NULL,
NULL
);
break;
case RsaKeyE:
Ret = mbedtls_rsa_import (
RsaKey,
NULL,
NULL,
NULL,
NULL,
&Value
);
break;
case RsaKeyD:
Ret = mbedtls_rsa_import (
RsaKey,
NULL,
NULL,
NULL,
&Value,
NULL
);
break;
case RsaKeyQ:
Ret = mbedtls_rsa_import (
RsaKey,
NULL,
NULL,
&Value,
NULL,
NULL
);
break;
case RsaKeyP:
Ret = mbedtls_rsa_import (
RsaKey,
NULL,
&Value,
NULL,
NULL,
NULL
);
break;
case RsaKeyDp:
case RsaKeyDq:
case RsaKeyQInv:
default:
Ret = -1;
break;
}
mbedtls_mpi_free (&Value);
return Ret == 0;
}
/**
Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in
RSA PKCS#1.
If RsaContext is NULL, then return FALSE.
If MessageHash is NULL, then return FALSE.
If Signature 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.
@param[in] RsaContext Pointer to RSA context for signature verification.
@param[in] MessageHash Pointer to octet message hash to be checked.
@param[in] HashSize Size of the message hash in bytes.
@param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified.
@param[in] SigSize Size of signature in bytes.
@retval TRUE Valid signature encoded in PKCS1-v1_5.
@retval FALSE Invalid signature or invalid RSA context.
**/
BOOLEAN
EFIAPI
RsaPkcs1Verify (
IN VOID *RsaContext,
IN CONST UINT8 *MessageHash,
IN UINTN HashSize,
IN CONST UINT8 *Signature,
IN UINTN SigSize
)
{
INT32 Ret;
mbedtls_md_type_t md_alg;
mbedtls_rsa_context *RsaKey;
if ((RsaContext == NULL) || (MessageHash == NULL) || (Signature == NULL)) {
return FALSE;
}
if ((SigSize > INT_MAX) || (SigSize == 0)) {
return FALSE;
}
RsaKey = (mbedtls_rsa_context *)RsaContext;
if (mbedtls_rsa_complete (RsaKey) != 0) {
return FALSE;
}
switch (HashSize) {
#ifdef ENABLE_MD5_DEPRECATED_INTERFACES
case MD5_DIGEST_SIZE:
md_alg = MBEDTLS_MD_MD5;
break;
#endif
#ifndef DISABLE_SHA1_DEPRECATED_INTERFACES
case SHA1_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA1;
break;
#endif
case SHA256_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA256;
break;
case SHA384_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA384;
break;
case SHA512_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA512;
break;
default:
return FALSE;
}
if (mbedtls_rsa_get_len (RsaContext) != SigSize) {
return FALSE;
}
mbedtls_rsa_set_padding (RsaContext, MBEDTLS_RSA_PKCS_V15, md_alg);
Ret = mbedtls_rsa_pkcs1_verify (
RsaContext,
md_alg,
(UINT32)HashSize,
MessageHash,
Signature
);
if (Ret != 0) {
return FALSE;
}
return TRUE;
}

View File

@ -0,0 +1,121 @@
/** @file
RSA Asymmetric Cipher Wrapper Null Implementation.
This file implements following APIs which provide basic capabilities for RSA:
1) RsaNew
2) RsaFree
3) RsaSetKey
4) RsaPkcs1Verify
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalCryptLib.h"
/**
Allocates and initializes one RSA context for subsequent use.
@return Pointer to the RSA context that has been initialized.
If the allocations fails, RsaNew() returns NULL.
**/
VOID *
EFIAPI
RsaNew (
VOID
)
{
//
// Allocates & Initializes RSA Context
//
ASSERT (FALSE);
return NULL;
}
/**
Release the specified RSA context.
@param[in] RsaContext Pointer to the RSA context to be released.
**/
VOID
EFIAPI
RsaFree (
IN VOID *RsaContext
)
{
//
// Free RSA Context
//
ASSERT (FALSE);
}
/**
Sets the tag-designated key component into the established RSA context.
This function sets the tag-designated RSA key component into the established
RSA context from the user-specified non-negative integer (octet string format
represented in RSA PKCS#1).
If BigNumber is NULL, then the specified key component in RSA context is cleared.
If RsaContext 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[in] BigNumber Pointer to octet integer buffer.
If NULL, then the specified key component in RSA
context is cleared.
@param[in] BnSize Size of big number buffer in bytes.
If BigNumber is NULL, then it is ignored.
@retval TRUE RSA key component was set successfully.
@retval FALSE Invalid RSA key component tag.
**/
BOOLEAN
EFIAPI
RsaSetKey (
IN OUT VOID *RsaContext,
IN RSA_KEY_TAG KeyTag,
IN CONST UINT8 *BigNumber,
IN UINTN BnSize
)
{
ASSERT (FALSE);
return FALSE;
}
/**
Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in
RSA PKCS#1.
If RsaContext is NULL, then return FALSE.
If MessageHash is NULL, then return FALSE.
If Signature is NULL, then return FALSE.
If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.
@param[in] RsaContext Pointer to RSA context for signature verification.
@param[in] MessageHash Pointer to octet message hash to be checked.
@param[in] HashSize Size of the message hash in bytes.
@param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified.
@param[in] SigSize Size of signature in bytes.
@retval TRUE Valid signature encoded in PKCS1-v1_5.
@retval FALSE Invalid signature or invalid RSA context.
**/
BOOLEAN
EFIAPI
RsaPkcs1Verify (
IN VOID *RsaContext,
IN CONST UINT8 *MessageHash,
IN UINTN HashSize,
IN CONST UINT8 *Signature,
IN UINTN SigSize
)
{
ASSERT (FALSE);
return FALSE;
}

View File

@ -0,0 +1,117 @@
/** @file
RSA Asymmetric Cipher Wrapper Implementation over MbedTLS.
This file does not provide real capabilities for following APIs in RSA handling:
1) RsaGetKey
2) RsaGenerateKey
3) RsaCheckKey
4) RsaPkcs1Sign
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalCryptLib.h"
/**
Gets the tag-designated RSA key component from the established RSA context.
Return FALSE to indicate this interface is not supported.
@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 FALSE This interface is not supported.
**/
BOOLEAN
EFIAPI
RsaGetKey (
IN OUT VOID *RsaContext,
IN RSA_KEY_TAG KeyTag,
OUT UINT8 *BigNumber,
IN OUT UINTN *BnSize
)
{
ASSERT (FALSE);
return FALSE;
}
/**
Generates RSA key components.
Return FALSE to indicate this interface is not supported.
@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 FALSE This interface is not supported.
**/
BOOLEAN
EFIAPI
RsaGenerateKey (
IN OUT VOID *RsaContext,
IN UINTN ModulusLength,
IN CONST UINT8 *PublicExponent,
IN UINTN PublicExponentSize
)
{
ASSERT (FALSE);
return FALSE;
}
/**
Validates key components of RSA context.
Return FALSE to indicate this interface is not supported.
@param[in] RsaContext Pointer to RSA context to check.
@retval FALSE This interface is not supported.
**/
BOOLEAN
EFIAPI
RsaCheckKey (
IN VOID *RsaContext
)
{
ASSERT (FALSE);
return FALSE;
}
/**
Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.
Return FALSE to indicate this interface is not supported.
@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 FALSE This interface is not supported.
**/
BOOLEAN
EFIAPI
RsaPkcs1Sign (
IN VOID *RsaContext,
IN CONST UINT8 *MessageHash,
IN UINTN HashSize,
OUT UINT8 *Signature,
IN OUT UINTN *SigSize
)
{
ASSERT (FALSE);
return FALSE;
}

View File

@ -0,0 +1,174 @@
/** @file
RSA Asymmetric Cipher Wrapper Implementation over MbedTLS.
This file implements following APIs which provide basic capabilities for RSA:
1) RsaPssVerify
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalCryptLib.h"
#include <mbedtls/rsa.h>
/**
Verifies the RSA signature with RSASSA-PSS signature scheme defined in RFC 8017.
Implementation determines salt length automatically from the signature encoding.
Mask generation function is the same as the message digest algorithm.
Salt length should be equal to digest length.
@param[in] RsaContext Pointer to RSA context for signature verification.
@param[in] Message Pointer to octet message to be verified.
@param[in] MsgSize Size of the message in bytes.
@param[in] Signature Pointer to RSASSA-PSS signature to be verified.
@param[in] SigSize Size of signature in bytes.
@param[in] DigestLen Length of digest for RSA operation.
@param[in] SaltLen Salt length for PSS encoding.
@retval TRUE Valid signature encoded in RSASSA-PSS.
@retval FALSE Invalid signature or invalid RSA context.
**/
BOOLEAN
EFIAPI
RsaPssVerify (
IN VOID *RsaContext,
IN CONST UINT8 *Message,
IN UINTN MsgSize,
IN CONST UINT8 *Signature,
IN UINTN SigSize,
IN UINT16 DigestLen,
IN UINT16 SaltLen
)
{
INT32 Ret;
mbedtls_md_type_t md_alg;
UINT8 HashValue[SHA512_DIGEST_SIZE];
BOOLEAN Status;
UINTN ShaCtxSize;
VOID *ShaCtx;
mbedtls_rsa_context *RsaKey;
if (RsaContext == NULL) {
return FALSE;
}
if ((Message == NULL) || (MsgSize == 0) || (MsgSize > INT_MAX)) {
return FALSE;
}
if (SaltLen != DigestLen) {
return FALSE;
}
if ((Signature == NULL) || (SigSize == 0) || (SigSize > INT_MAX)) {
return FALSE;
}
RsaKey = (mbedtls_rsa_context *)RsaContext;
if (mbedtls_rsa_complete (RsaKey) != 0) {
return FALSE;
}
ZeroMem (HashValue, DigestLen);
switch (DigestLen) {
case SHA256_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA256;
ShaCtxSize = Sha256GetContextSize ();
ShaCtx = AllocateZeroPool (ShaCtxSize);
Status = Sha256Init (ShaCtx);
if (!Status) {
return FALSE;
}
Status = Sha256Update (ShaCtx, Message, MsgSize);
if (!Status) {
FreePool (ShaCtx);
return FALSE;
}
Status = Sha256Final (ShaCtx, HashValue);
if (!Status) {
FreePool (ShaCtx);
return FALSE;
}
FreePool (ShaCtx);
break;
case SHA384_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA384;
ShaCtxSize = Sha384GetContextSize ();
ShaCtx = AllocateZeroPool (ShaCtxSize);
Status = Sha384Init (ShaCtx);
if (!Status) {
return FALSE;
}
Status = Sha384Update (ShaCtx, Message, MsgSize);
if (!Status) {
FreePool (ShaCtx);
return FALSE;
}
Status = Sha384Final (ShaCtx, HashValue);
if (!Status) {
FreePool (ShaCtx);
return FALSE;
}
FreePool (ShaCtx);
break;
case SHA512_DIGEST_SIZE:
md_alg = MBEDTLS_MD_SHA512;
ShaCtxSize = Sha512GetContextSize ();
ShaCtx = AllocateZeroPool (ShaCtxSize);
Status = Sha512Init (ShaCtx);
if (!Status) {
return FALSE;
}
Status = Sha512Update (ShaCtx, Message, MsgSize);
if (!Status) {
FreePool (ShaCtx);
return FALSE;
}
Status = Sha512Final (ShaCtx, HashValue);
if (!Status) {
FreePool (ShaCtx);
return FALSE;
}
FreePool (ShaCtx);
break;
default:
return FALSE;
}
if (mbedtls_rsa_get_len (RsaContext) != SigSize) {
return FALSE;
}
mbedtls_rsa_set_padding (RsaContext, MBEDTLS_RSA_PKCS_V21, md_alg);
Ret = mbedtls_rsa_rsassa_pss_verify (
RsaContext,
md_alg,
(UINT32)DigestLen,
HashValue,
Signature
);
if (Ret != 0) {
return FALSE;
}
return TRUE;
}

View File

@ -0,0 +1,46 @@
/** @file
RSA-PSS Asymmetric Cipher Wrapper Implementation over MbedTLS.
This file does not provide real capabilities for following APIs in RSA handling:
1) RsaPssVerify
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalCryptLib.h"
/**
Verifies the RSA signature with RSASSA-PSS signature scheme defined in RFC 8017.
Implementation determines salt length automatically from the signature encoding.
Mask generation function is the same as the message digest algorithm.
Salt length should be equal to digest length.
@param[in] RsaContext Pointer to RSA context for signature verification.
@param[in] Message Pointer to octet message to be verified.
@param[in] MsgSize Size of the message in bytes.
@param[in] Signature Pointer to RSASSA-PSS signature to be verified.
@param[in] SigSize Size of signature in bytes.
@param[in] DigestLen Length of digest for RSA operation.
@param[in] SaltLen Salt length for PSS encoding.
@retval TRUE Valid signature encoded in RSASSA-PSS.
@retval FALSE Invalid signature or invalid RSA context.
**/
BOOLEAN
EFIAPI
RsaPssVerify (
IN VOID *RsaContext,
IN CONST UINT8 *Message,
IN UINTN MsgSize,
IN CONST UINT8 *Signature,
IN UINTN SigSize,
IN UINT16 DigestLen,
IN UINT16 SaltLen
)
{
ASSERT (FALSE);
return FALSE;
}

View File

@ -0,0 +1,60 @@
/** @file
RSA-PSS Asymmetric Cipher Wrapper Implementation over MbedTLS.
This file does not provide real capabilities for following APIs in RSA handling:
1) RsaPssSign
Copyright (c) 2023, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "InternalCryptLib.h"
/**
Carries out the RSA-SSA signature generation with EMSA-PSS encoding scheme.
This function carries out the RSA-SSA signature generation with EMSA-PSS encoding scheme defined in
RFC 8017.
Mask generation function is the same as the message digest algorithm.
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 Message is NULL, then return FALSE.
If MsgSize is zero or > INT_MAX, then return FALSE.
If DigestLen is NOT 32, 48 or 64, return FALSE.
If SaltLen is not equal to DigestLen, then return FALSE.
If SigSize is large enough but Signature is NULL, then return FALSE.
If this interface is not supported, then return FALSE.
@param[in] RsaContext Pointer to RSA context for signature generation.
@param[in] Message Pointer to octet message to be signed.
@param[in] MsgSize Size of the message in bytes.
@param[in] DigestLen Length of the digest in bytes to be used for RSA signature operation.
@param[in] SaltLen Length of the salt in bytes to be used for PSS encoding.
@param[out] Signature Pointer to buffer to receive RSA PSS 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 RSASSA-PSS.
@retval FALSE Signature generation failed.
@retval FALSE SigSize is too small.
@retval FALSE This interface is not supported.
**/
BOOLEAN
EFIAPI
RsaPssSign (
IN VOID *RsaContext,
IN CONST UINT8 *Message,
IN UINTN MsgSize,
IN UINT16 DigestLen,
IN UINT16 SaltLen,
OUT UINT8 *Signature,
IN OUT UINTN *SigSize
)
{
ASSERT (FALSE);
return FALSE;
}

View File

@ -194,6 +194,9 @@ TestVerifyRsaGenerateKeyComponents (
BOOLEAN Status;
UINTN KeySize;
UINT8 *KeyBuffer;
UINT8 TestPublicExponent1[] = { 0x03 };
UINT8 TestPublicExponent2[] = { 0x01, 0x01 };
UINT8 TestPublicExponent3[] = { 0x01, 0x00, 0x01 };
//
// Generate RSA Key Components
@ -202,6 +205,13 @@ TestVerifyRsaGenerateKeyComponents (
Status = RsaGenerateKey (mRsa, RSA_MODULUS_LENGTH, NULL, 0);
UT_ASSERT_TRUE (Status);
Status = RsaGenerateKey (mRsa, RSA_MODULUS_LENGTH, TestPublicExponent1, sizeof (TestPublicExponent1));
UT_ASSERT_TRUE (Status);
Status = RsaGenerateKey (mRsa, RSA_MODULUS_LENGTH, TestPublicExponent2, sizeof (TestPublicExponent2));
UT_ASSERT_TRUE (Status);
Status = RsaGenerateKey (mRsa, RSA_MODULUS_LENGTH, TestPublicExponent3, sizeof (TestPublicExponent3));
UT_ASSERT_TRUE (Status);
KeySize = RSA_MODULUS_LENGTH / 8;
KeyBuffer = AllocatePool (KeySize);
Status = RsaGetKey (mRsa, RsaKeyE, KeyBuffer, &KeySize);