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>
		
			
				
	
	
		
			328 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			328 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.
 | 
						|
 | 
						|
  This file implements following APIs which provide basic capabilities for RSA:
 | 
						|
  1) RsaNew
 | 
						|
  2) RsaFree
 | 
						|
  3) RsaSetKey
 | 
						|
  4) RsaPkcs1Verify
 | 
						|
 | 
						|
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/objects.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 by OpenSSL RSA_new()
 | 
						|
  //
 | 
						|
  return (VOID *) RSA_new ();
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Release the specified RSA context.
 | 
						|
 | 
						|
  @param[in]  RsaContext  Pointer to the RSA context to be released.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
RsaFree (
 | 
						|
  IN  VOID  *RsaContext
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Free OpenSSL RSA Context
 | 
						|
  //
 | 
						|
  RSA_free ((RSA *) 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
 | 
						|
  )
 | 
						|
{
 | 
						|
  RSA     *RsaKey;
 | 
						|
  BIGNUM  *BnN;
 | 
						|
  BIGNUM  *BnE;
 | 
						|
  BIGNUM  *BnD;
 | 
						|
  BIGNUM  *BnP;
 | 
						|
  BIGNUM  *BnQ;
 | 
						|
  BIGNUM  *BnDp;
 | 
						|
  BIGNUM  *BnDq;
 | 
						|
  BIGNUM  *BnQInv;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if (RsaContext == NULL || BnSize > INT_MAX) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  BnN    = NULL;
 | 
						|
  BnE    = NULL;
 | 
						|
  BnD    = NULL;
 | 
						|
  BnP    = NULL;
 | 
						|
  BnQ    = NULL;
 | 
						|
  BnDp   = NULL;
 | 
						|
  BnDq   = NULL;
 | 
						|
  BnQInv = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Retrieve the components from RSA object.
 | 
						|
  //
 | 
						|
  RsaKey = (RSA *) RsaContext;
 | 
						|
  RSA_get0_key (RsaKey, (const BIGNUM **)&BnN, (const BIGNUM **)&BnE, (const BIGNUM **)&BnD);
 | 
						|
  RSA_get0_factors (RsaKey, (const BIGNUM **)&BnP, (const BIGNUM **)&BnQ);
 | 
						|
  RSA_get0_crt_params (RsaKey, (const BIGNUM **)&BnDp, (const BIGNUM **)&BnDq, (const BIGNUM **)&BnQInv);
 | 
						|
 | 
						|
  //
 | 
						|
  // Set RSA Key Components by converting octet string to OpenSSL BN representation.
 | 
						|
  // NOTE: For RSA public key (used in signature verification), only public components
 | 
						|
  //       (N, e) are needed.
 | 
						|
  //
 | 
						|
  switch (KeyTag) {
 | 
						|
 | 
						|
  //
 | 
						|
  // RSA Public Modulus (N), Public Exponent (e) and Private Exponent (d)
 | 
						|
  //
 | 
						|
  case RsaKeyN:
 | 
						|
  case RsaKeyE:
 | 
						|
  case RsaKeyD:
 | 
						|
    if (BnN == NULL) {
 | 
						|
      BnN = BN_new ();
 | 
						|
    }
 | 
						|
    if (BnE == NULL) {
 | 
						|
      BnE = BN_new ();
 | 
						|
    }
 | 
						|
    if (BnD == NULL) {
 | 
						|
      BnD = BN_new ();
 | 
						|
    }
 | 
						|
 | 
						|
    if ((BnN == NULL) || (BnE == NULL) || (BnD == NULL)) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (KeyTag) {
 | 
						|
    case RsaKeyN:
 | 
						|
      BnN = BN_bin2bn (BigNumber, (UINT32)BnSize, BnN);
 | 
						|
      break;
 | 
						|
    case RsaKeyE:
 | 
						|
      BnE = BN_bin2bn (BigNumber, (UINT32)BnSize, BnE);
 | 
						|
      break;
 | 
						|
    case RsaKeyD:
 | 
						|
      BnD = BN_bin2bn (BigNumber, (UINT32)BnSize, BnD);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
    if (RSA_set0_key (RsaKey, BN_dup(BnN), BN_dup(BnE), BN_dup(BnD)) == 0) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // RSA Secret Prime Factor of Modulus (p and q)
 | 
						|
  //
 | 
						|
  case RsaKeyP:
 | 
						|
  case RsaKeyQ:
 | 
						|
    if (BnP == NULL) {
 | 
						|
      BnP = BN_new ();
 | 
						|
    }
 | 
						|
    if (BnQ == NULL) {
 | 
						|
      BnQ = BN_new ();
 | 
						|
    }
 | 
						|
    if ((BnP == NULL) || (BnQ == NULL)) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (KeyTag) {
 | 
						|
    case RsaKeyP:
 | 
						|
      BnP = BN_bin2bn (BigNumber, (UINT32)BnSize, BnP);
 | 
						|
      break;
 | 
						|
    case RsaKeyQ:
 | 
						|
      BnQ = BN_bin2bn (BigNumber, (UINT32)BnSize, BnQ);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
    if (RSA_set0_factors (RsaKey, BN_dup(BnP), BN_dup(BnQ)) == 0) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  //
 | 
						|
  // p's CRT Exponent (== d mod (p - 1)),  q's CRT Exponent (== d mod (q - 1)),
 | 
						|
  // and CRT Coefficient (== 1/q mod p)
 | 
						|
  //
 | 
						|
  case RsaKeyDp:
 | 
						|
  case RsaKeyDq:
 | 
						|
  case RsaKeyQInv:
 | 
						|
    if (BnDp == NULL) {
 | 
						|
      BnDp = BN_new ();
 | 
						|
    }
 | 
						|
    if (BnDq == NULL) {
 | 
						|
      BnDq = BN_new ();
 | 
						|
    }
 | 
						|
    if (BnQInv == NULL) {
 | 
						|
      BnQInv = BN_new ();
 | 
						|
    }
 | 
						|
    if ((BnDp == NULL) || (BnDq == NULL) || (BnQInv == NULL)) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (KeyTag) {
 | 
						|
    case RsaKeyDp:
 | 
						|
      BnDp = BN_bin2bn (BigNumber, (UINT32)BnSize, BnDp);
 | 
						|
      break;
 | 
						|
    case RsaKeyDq:
 | 
						|
      BnDq = BN_bin2bn (BigNumber, (UINT32)BnSize, BnDq);
 | 
						|
      break;
 | 
						|
    case RsaKeyQInv:
 | 
						|
      BnQInv = BN_bin2bn (BigNumber, (UINT32)BnSize, BnQInv);
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
    if (RSA_set0_crt_params (RsaKey, BN_dup(BnDp), BN_dup(BnDq), BN_dup(BnQInv)) == 0) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    break;
 | 
						|
 | 
						|
  default:
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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    DigestType;
 | 
						|
  UINT8    *SigBuf;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check input parameters.
 | 
						|
  //
 | 
						|
  if (RsaContext == NULL || MessageHash == NULL || Signature == NULL) {
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (SigSize > INT_MAX || SigSize == 0) {
 | 
						|
    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;
 | 
						|
  }
 | 
						|
 | 
						|
  SigBuf = (UINT8 *) Signature;
 | 
						|
  return (BOOLEAN) RSA_verify (
 | 
						|
                     DigestType,
 | 
						|
                     MessageHash,
 | 
						|
                     (UINT32) HashSize,
 | 
						|
                     SigBuf,
 | 
						|
                     (UINT32) SigSize,
 | 
						|
                     (RSA *) RsaContext
 | 
						|
                     );
 | 
						|
}
 |