BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2389 Currently RSA signing scheme support is available for MD5, SHA-1 or SHA-256 algorithms.The fix is to extend this support for SHA384 and SHA512. Cc: Liming Gao <liming.gao@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Bob Feng <bob.c.feng@intel.com> Signed-off-by: Pavana.K <pavana.k@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			365 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			365 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @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
 | 
						|
                     );
 | 
						|
}
 |