| /** @file | |
| RSA Asymmetric Cipher Wrapper Implementation over OpenSSL. | |
| This file implements following APIs which provide more capabilities for RSA: | |
| 1) RsaGetKey | |
| 2) RsaGenerateKey | |
| 3) RsaCheckKey | |
| 4) RsaPkcs1Sign | |
| Copyright (c) 2009 - 2020, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "InternalCryptLib.h" | |
| #include <openssl/bn.h> | |
| #include <openssl/rsa.h> | |
| #include <openssl/err.h> | |
| #include <openssl/objects.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 | |
| ) | |
| { | |
| RSA *RsaKey; | |
| BIGNUM *BnKey; | |
| UINTN Size; | |
| // | |
| // Check input parameters. | |
| // | |
| if ((RsaContext == NULL) || (BnSize == NULL)) { | |
| return FALSE; | |
| } | |
| RsaKey = (RSA *)RsaContext; | |
| Size = *BnSize; | |
| *BnSize = 0; | |
| BnKey = NULL; | |
| switch (KeyTag) { | |
| // | |
| // RSA Public Modulus (N) | |
| // | |
| case RsaKeyN: | |
| RSA_get0_key (RsaKey, (const BIGNUM **)&BnKey, NULL, NULL); | |
| break; | |
| // | |
| // RSA Public Exponent (e) | |
| // | |
| case RsaKeyE: | |
| RSA_get0_key (RsaKey, NULL, (const BIGNUM **)&BnKey, NULL); | |
| break; | |
| // | |
| // RSA Private Exponent (d) | |
| // | |
| case RsaKeyD: | |
| RSA_get0_key (RsaKey, NULL, NULL, (const BIGNUM **)&BnKey); | |
| break; | |
| // | |
| // RSA Secret Prime Factor of Modulus (p) | |
| // | |
| case RsaKeyP: | |
| RSA_get0_factors (RsaKey, (const BIGNUM **)&BnKey, NULL); | |
| break; | |
| // | |
| // RSA Secret Prime Factor of Modules (q) | |
| // | |
| case RsaKeyQ: | |
| RSA_get0_factors (RsaKey, NULL, (const BIGNUM **)&BnKey); | |
| break; | |
| // | |
| // p's CRT Exponent (== d mod (p - 1)) | |
| // | |
| case RsaKeyDp: | |
| RSA_get0_crt_params (RsaKey, (const BIGNUM **)&BnKey, NULL, NULL); | |
| break; | |
| // | |
| // q's CRT Exponent (== d mod (q - 1)) | |
| // | |
| case RsaKeyDq: | |
| RSA_get0_crt_params (RsaKey, NULL, (const BIGNUM **)&BnKey, NULL); | |
| break; | |
| // | |
| // The CRT Coefficient (== 1/q mod p) | |
| // | |
| case RsaKeyQInv: | |
| RSA_get0_crt_params (RsaKey, NULL, NULL, (const BIGNUM **)&BnKey); | |
| break; | |
| default: | |
| return FALSE; | |
| } | |
| if (BnKey == NULL) { | |
| return FALSE; | |
| } | |
| *BnSize = Size; | |
| Size = BN_num_bytes (BnKey); | |
| if (*BnSize < Size) { | |
| *BnSize = Size; | |
| return FALSE; | |
| } | |
| if (BigNumber == NULL) { | |
| *BnSize = Size; | |
| return TRUE; | |
| } | |
| *BnSize = BN_bn2bin (BnKey, BigNumber); | |
| return TRUE; | |
| } | |
| /** | |
| Generates RSA key components. | |
| This function generates RSA key components. It takes RSA public exponent E 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 | |
| ) | |
| { | |
| BIGNUM *KeyE; | |
| BOOLEAN RetVal; | |
| // | |
| // Check input parameters. | |
| // | |
| if ((RsaContext == NULL) || (ModulusLength > INT_MAX) || (PublicExponentSize > INT_MAX)) { | |
| return FALSE; | |
| } | |
| KeyE = BN_new (); | |
| if (KeyE == NULL) { | |
| return FALSE; | |
| } | |
| RetVal = FALSE; | |
| if (PublicExponent == NULL) { | |
| if (BN_set_word (KeyE, 0x10001) == 0) { | |
| goto _Exit; | |
| } | |
| } else { | |
| if (BN_bin2bn (PublicExponent, (UINT32)PublicExponentSize, KeyE) == NULL) { | |
| goto _Exit; | |
| } | |
| } | |
| if (RSA_generate_key_ex ((RSA *)RsaContext, (UINT32)ModulusLength, KeyE, NULL) == 1) { | |
| RetVal = TRUE; | |
| } | |
| _Exit: | |
| BN_free (KeyE); | |
| return RetVal; | |
| } | |
| /** | |
| 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 | |
| ) | |
| { | |
| UINTN Reason; | |
| // | |
| // Check input parameters. | |
| // | |
| if (RsaContext == NULL) { | |
| return FALSE; | |
| } | |
| if (RSA_check_key ((RSA *)RsaContext) != 1) { | |
| Reason = ERR_GET_REASON (ERR_peek_last_error ()); | |
| if ((Reason == RSA_R_P_NOT_PRIME) || | |
| (Reason == RSA_R_Q_NOT_PRIME) || | |
| (Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q) || | |
| (Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1)) | |
| { | |
| return FALSE; | |
| } | |
| } | |
| return TRUE; | |
| } | |
| /** | |
| 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 | |
| ) | |
| { | |
| RSA *Rsa; | |
| UINTN Size; | |
| INT32 DigestType; | |
| // | |
| // Check input parameters. | |
| // | |
| if ((RsaContext == NULL) || (MessageHash == NULL)) { | |
| return FALSE; | |
| } | |
| Rsa = (RSA *)RsaContext; | |
| Size = RSA_size (Rsa); | |
| if (*SigSize < Size) { | |
| *SigSize = Size; | |
| return FALSE; | |
| } | |
| if (Signature == NULL) { | |
| return FALSE; | |
| } | |
| // | |
| // Determine the message digest algorithm according to digest size. | |
| // Only MD5, SHA-1, SHA-256, SHA-384 or SHA-512 algorithm is supported. | |
| // | |
| switch (HashSize) { | |
| case MD5_DIGEST_SIZE: | |
| DigestType = NID_md5; | |
| break; | |
| case SHA1_DIGEST_SIZE: | |
| DigestType = NID_sha1; | |
| break; | |
| case SHA256_DIGEST_SIZE: | |
| DigestType = NID_sha256; | |
| break; | |
| case SHA384_DIGEST_SIZE: | |
| DigestType = NID_sha384; | |
| break; | |
| case SHA512_DIGEST_SIZE: | |
| DigestType = NID_sha512; | |
| break; | |
| default: | |
| return FALSE; | |
| } | |
| return (BOOLEAN)RSA_sign ( | |
| DigestType, | |
| MessageHash, | |
| (UINT32)HashSize, | |
| Signature, | |
| (UINT32 *)SigSize, | |
| (RSA *)RsaContext | |
| ); | |
| } |