\r
**/\r
\r
-#include <Library/BaseLib.h>\r
-#include <Library/DebugLib.h>\r
-#include <Library/BaseMemoryLib.h>\r
+#include "InternalCryptLib.h"\r
\r
-#include <Library/BaseCryptLib.h>\r
#include <openssl/rsa.h>\r
+#include <openssl/err.h>\r
+\r
+//\r
+// ASN.1 value for Hash Algorithm ID with the Distringuished Encoding Rules (DER)\r
+// Refer to Section 9.2 of PKCS#1 v2.1\r
+// \r
+CONST UINT8 Asn1IdMd5[] = {\r
+ 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,\r
+ 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10\r
+ };\r
+\r
+CONST UINT8 Asn1IdSha1[] = {\r
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,\r
+ 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14\r
+ };\r
+\r
+CONST UINT8 Asn1IdSha256[] = {\r
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,\r
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,\r
+ 0x00, 0x04, 0x20\r
+ };\r
\r
\r
/**\r
- Allocates and Initializes one RSA Context for subsequent use.\r
+ Allocates and initializes one RSA context for subsequent use.\r
\r
- @return Pointer to the RSA Context that has been initialized.\r
+ @return Pointer to the RSA context that has been initialized.\r
If the allocations fails, RsaNew() returns NULL.\r
\r
**/\r
return (VOID *)RSA_new ();\r
}\r
\r
-\r
/**\r
- Release the specified RSA Context.\r
+ Release the specified RSA context.\r
+\r
+ If RsaContext is NULL, then ASSERT().\r
\r
@param[in] RsaContext Pointer to the RSA context to be released.\r
\r
IN VOID *RsaContext\r
)\r
{\r
+ ASSERT (RsaContext != NULL);\r
+\r
//\r
// Free OpenSSL RSA Context\r
//\r
RSA_free ((RSA *)RsaContext);\r
}\r
\r
-\r
/**\r
- Sets the tag-designated RSA key component into the established RSA context from\r
- the user-specified nonnegative integer (octet string format represented in RSA\r
- PKCS#1).\r
+ Sets the tag-designated key component into the established RSA context.\r
+\r
+ This function sets the tag-designated RSA key component into the established\r
+ RSA context from the user-specified non-negative integer (octet string format\r
+ represented in RSA PKCS#1).\r
+ If BigNumber is NULL, then the specified key componenet in RSA context is cleared.\r
\r
If RsaContext is NULL, then ASSERT().\r
\r
@param[in, out] RsaContext Pointer to RSA context being set.\r
@param[in] KeyTag Tag of RSA key component being set.\r
@param[in] BigNumber Pointer to octet integer buffer.\r
- @param[in] BnLength Length of big number buffer in bytes.\r
+ If NULL, then the specified key componenet in RSA\r
+ context is cleared.\r
+ @param[in] BnSize Size of big number buffer in bytes.\r
+ If BigNumber is NULL, then it is ignored.\r
\r
- @return TRUE RSA key component was set successfully.\r
- @return FALSE Invalid RSA key component tag.\r
+ @retval TRUE RSA key component was set successfully.\r
+ @retval FALSE Invalid RSA key component tag.\r
\r
**/\r
BOOLEAN\r
EFIAPI\r
RsaSetKey (\r
- IN OUT VOID *RsaContext,\r
- IN RSA_KEY_TAG KeyTag,\r
- IN CONST UINT8 *BigNumber,\r
- IN UINTN BnLength\r
+ IN OUT VOID *RsaContext,\r
+ IN RSA_KEY_TAG KeyTag,\r
+ IN CONST UINT8 *BigNumber,\r
+ IN UINTN BnSize\r
)\r
{\r
RSA *RsaKey;\r
if (RsaKey->n != NULL) {\r
BN_free (RsaKey->n);\r
}\r
- RsaKey->n = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->n);\r
+ RsaKey->n = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->n = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->n);\r
break;\r
\r
//\r
if (RsaKey->e != NULL) {\r
BN_free (RsaKey->e);\r
}\r
- RsaKey->e = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->e);\r
+ RsaKey->e = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->e = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->e);\r
break;\r
\r
//\r
if (RsaKey->d != NULL) {\r
BN_free (RsaKey->d);\r
}\r
- RsaKey->d = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->d);\r
+ RsaKey->d = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->d = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->d);\r
break;\r
\r
//\r
if (RsaKey->p != NULL) {\r
BN_free (RsaKey->p);\r
}\r
- RsaKey->p = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->p);\r
+ RsaKey->p = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->p = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->p);\r
break;\r
\r
//\r
if (RsaKey->q != NULL) {\r
BN_free (RsaKey->q);\r
}\r
- RsaKey->q = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->q);\r
+ RsaKey->q = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->q = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->q);\r
break;\r
\r
//\r
if (RsaKey->dmp1 != NULL) {\r
BN_free (RsaKey->dmp1);\r
}\r
- RsaKey->dmp1 = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->dmp1);\r
+ RsaKey->dmp1 = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->dmp1 = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->dmp1);\r
break;\r
\r
//\r
if (RsaKey->dmq1 != NULL) {\r
BN_free (RsaKey->dmq1);\r
}\r
- RsaKey->dmq1 = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->dmq1);\r
+ RsaKey->dmq1 = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->dmq1 = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->dmq1);\r
break;\r
\r
//\r
if (RsaKey->iqmp != NULL) {\r
BN_free (RsaKey->iqmp);\r
}\r
- RsaKey->iqmp = BN_bin2bn (BigNumber, (int)BnLength, RsaKey->iqmp);\r
+ RsaKey->iqmp = NULL;\r
+ if (BigNumber == NULL) {\r
+ break;\r
+ }\r
+ RsaKey->iqmp = BN_bin2bn (BigNumber, (UINT32) BnSize, RsaKey->iqmp);\r
+ break;\r
+\r
+ default:\r
+ return FALSE;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Gets the tag-designated RSA key component from the established RSA context.\r
+\r
+ This function retrieves the tag-designated RSA key component from the\r
+ established RSA context as a non-negative integer (octet string format\r
+ represented in RSA PKCS#1).\r
+ If specified key component has not been set or has been cleared, then returned\r
+ BnSize is set to 0.\r
+ If the BigNumber buffer is too small to hold the contents of the key, FALSE\r
+ is returned and BnSize is set to the required buffer size to obtain the key.\r
+\r
+ If RsaContext is NULL, then ASSERT().\r
+ If BnSize is NULL, then ASSERT().\r
+ If BnSize is large enough but BigNumber is NULL, then ASSERT().\r
+\r
+ @param[in, out] RsaContext Pointer to RSA context being set.\r
+ @param[in] KeyTag Tag of RSA key component being set.\r
+ @param[out] BigNumber Pointer to octet integer buffer.\r
+ @param[in, out] BnSize On input, the size of big number buffer in bytes.\r
+ On output, the size of data returned in big number buffer in bytes.\r
+\r
+ @retval TRUE RSA key component was retrieved successfully.\r
+ @retval FALSE Invalid RSA key component tag.\r
+ @retval FALSE BnSize is too small.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+RsaGetKey (\r
+ IN OUT VOID *RsaContext,\r
+ IN RSA_KEY_TAG KeyTag,\r
+ OUT UINT8 *BigNumber,\r
+ IN OUT UINTN *BnSize\r
+ )\r
+{\r
+ RSA *RsaKey;\r
+ BIGNUM *BnKey;\r
+ UINTN Size;\r
+\r
+ ASSERT (RsaContext != NULL);\r
+ ASSERT (BnSize != NULL);\r
+\r
+ RsaKey = (RSA *) RsaContext;\r
+ Size = *BnSize;\r
+ *BnSize = 0;\r
+\r
+ switch (KeyTag) {\r
+\r
+ //\r
+ // RSA Public Modulus (N)\r
+ //\r
+ case RsaKeyN:\r
+ if (RsaKey->n == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->n;\r
+ break;\r
+\r
+ //\r
+ // RSA Public Exponent (e)\r
+ //\r
+ case RsaKeyE:\r
+ if (RsaKey->e == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->e;\r
+ break;\r
+\r
+ //\r
+ // RSA Private Exponent (d)\r
+ //\r
+ case RsaKeyD:\r
+ if (RsaKey->d == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->d;\r
+ break;\r
+\r
+ //\r
+ // RSA Secret Prime Factor of Modulus (p)\r
+ //\r
+ case RsaKeyP:\r
+ if (RsaKey->p == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->p;\r
+ break;\r
+\r
+ //\r
+ // RSA Secret Prime Factor of Modules (q)\r
+ //\r
+ case RsaKeyQ:\r
+ if (RsaKey->q == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->q;\r
+ break;\r
+\r
+ //\r
+ // p's CRT Exponent (== d mod (p - 1))\r
+ //\r
+ case RsaKeyDp:\r
+ if (RsaKey->dmp1 == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->dmp1;\r
+ break;\r
+\r
+ //\r
+ // q's CRT Exponent (== d mod (q - 1))\r
+ //\r
+ case RsaKeyDq:\r
+ if (RsaKey->dmq1 == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->dmq1;\r
+ break;\r
+\r
+ //\r
+ // The CRT Coefficient (== 1/q mod p)\r
+ //\r
+ case RsaKeyQInv:\r
+ if (RsaKey->iqmp == NULL) {\r
+ return TRUE;\r
+ }\r
+ BnKey = RsaKey->iqmp;\r
break;\r
\r
default:\r
return FALSE;\r
}\r
\r
+ *BnSize = Size;\r
+ Size = BN_num_bytes (BnKey);\r
+\r
+ if (*BnSize < Size) {\r
+ *BnSize = Size;\r
+ return FALSE;\r
+ }\r
+\r
+ ASSERT (BigNumber != NULL);\r
+ *BnSize = BN_bn2bin (BnKey, BigNumber) ;\r
+ \r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Generates RSA key components.\r
+\r
+ This function generates RSA key components. It takes RSA public exponent E and\r
+ length in bits of RSA modulus N as input, and generates all key components.\r
+ If PublicExponent is NULL, the default RSA public exponent (0x10001) will be used.\r
+\r
+ Before this function can be invoked, pseudorandom number generator must be correctly\r
+ initialized by RandomSeed().\r
+\r
+ If RsaContext is NULL, then ASSERT().\r
+\r
+ @param[in, out] RsaContext Pointer to RSA context being set.\r
+ @param[in] ModulusLength Length of RSA modulus N in bits.\r
+ @param[in] PublicExponent Pointer to RSA public exponent.\r
+ @param[in] PublicExponentSize Size of RSA public exponent buffer in bytes. \r
+\r
+ @retval TRUE RSA key component was generated successfully.\r
+ @retval FALSE Invalid RSA key component tag.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+RsaGenerateKey (\r
+ IN OUT VOID *RsaContext,\r
+ IN UINTN ModulusLength,\r
+ IN CONST UINT8 *PublicExponent,\r
+ IN UINTN PublicExponentSize\r
+ )\r
+{\r
+ BIGNUM *KeyE;\r
+ BOOLEAN RetVal;\r
+\r
+ ASSERT (RsaContext != NULL);\r
+\r
+ KeyE = BN_new ();\r
+ if (PublicExponent == NULL) {\r
+ BN_set_word (KeyE, 0x10001);\r
+ } else {\r
+ BN_bin2bn (PublicExponent, (UINT32) PublicExponentSize, KeyE);\r
+ }\r
+\r
+ RetVal = FALSE;\r
+ if (RSA_generate_key_ex ((RSA *) RsaContext, (UINT32) ModulusLength, KeyE, NULL) == 1) {\r
+ RetVal = TRUE;\r
+ }\r
+\r
+ BN_free (KeyE);\r
+ return RetVal;\r
+}\r
+\r
+/**\r
+ Validates key components of RSA context.\r
+\r
+ This function validates key compoents of RSA context in following aspects:\r
+ - Whether p is a prime\r
+ - Whether q is a prime\r
+ - Whether n = p * q\r
+ - Whether d*e = 1 mod lcm(p-1,q-1)\r
+\r
+ If RsaContext is NULL, then ASSERT().\r
+\r
+ @param[in] RsaContext Pointer to RSA context to check.\r
+\r
+ @retval TRUE RSA key components are valid.\r
+ @retval FALSE RSA key components are not valid.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+RsaCheckKey (\r
+ IN VOID *RsaContext\r
+ )\r
+{\r
+ UINTN Reason;\r
+\r
+ ASSERT (RsaContext != NULL);\r
+\r
+ if (RSA_check_key ((RSA *) RsaContext) != 1) {\r
+ Reason = ERR_GET_REASON (ERR_peek_last_error ());\r
+ if (Reason == RSA_R_P_NOT_PRIME ||\r
+ Reason == RSA_R_Q_NOT_PRIME ||\r
+ Reason == RSA_R_N_DOES_NOT_EQUAL_P_Q ||\r
+ Reason == RSA_R_D_E_NOT_CONGRUENT_TO_1) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
return TRUE;\r
}\r
\r
+/**\r
+ Performs the PKCS1-v1_5 encoding methods defined in RSA PKCS #1.\r
+\r
+ @param Message Message buffer to be encoded.\r
+ @param MessageSize Size of message buffer in bytes.\r
+ @param DigestInfo Pointer to buffer of digest info for output.\r
+\r
+ @return Size of DigestInfo in bytes.\r
+\r
+**/ \r
+UINTN\r
+DigestInfoEncoding (\r
+ IN CONST UINT8 *Message,\r
+ IN UINTN MessageSize,\r
+ OUT UINT8 *DigestInfo\r
+ )\r
+{\r
+ CONST UINT8 *HashDer;\r
+ UINTN DerSize;\r
+\r
+ ASSERT (Message != NULL);\r
+ ASSERT (DigestInfo != NULL);\r
+\r
+ //\r
+ // The original message length is used to determine the hash algorithm since\r
+ // message is digest value hashed by the specified algorithm.\r
+ //\r
+ switch (MessageSize) {\r
+ case MD5_DIGEST_SIZE:\r
+ HashDer = Asn1IdMd5;\r
+ DerSize = sizeof (Asn1IdMd5);\r
+ break;\r
+ \r
+ case SHA1_DIGEST_SIZE:\r
+ HashDer = Asn1IdSha1;\r
+ DerSize = sizeof (Asn1IdSha1);\r
+ break;\r
+ \r
+ case SHA256_DIGEST_SIZE:\r
+ HashDer = Asn1IdSha256;\r
+ DerSize = sizeof (Asn1IdSha256);\r
+ break;\r
+ \r
+ default:\r
+ return FALSE;\r
+ }\r
+\r
+ CopyMem (DigestInfo, HashDer, DerSize);\r
+ CopyMem (DigestInfo + DerSize, Message, MessageSize);\r
+\r
+ return (DerSize + MessageSize);\r
+}\r
+\r
+/**\r
+ Carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme.\r
+\r
+ This function carries out the RSA-SSA signature generation with EMSA-PKCS1-v1_5 encoding scheme defined in\r
+ RSA PKCS#1.\r
+ If the Signature buffer is too small to hold the contents of signature, FALSE\r
+ is returned and SigSize is set to the required buffer size to obtain the signature.\r
+\r
+ If RsaContext is NULL, then ASSERT().\r
+ If MessageHash is NULL, then ASSERT().\r
+ If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-224, SHA-512 or SHA-384 digest, then ASSERT().\r
+ If SigSize is large enough but Signature is NULL, then ASSERT().\r
+\r
+ @param[in] RsaContext Pointer to RSA context for signature generation.\r
+ @param[in] MessageHash Pointer to octet message hash to be signed.\r
+ @param[in] HashSize Size of the message hash in bytes.\r
+ @param[out] Signature Pointer to buffer to receive RSA PKCS1-v1_5 signature.\r
+ @param[in, out] SigSize On input, the size of Signature buffer in bytes.\r
+ On output, the size of data returned in Signature buffer in bytes.\r
+\r
+ @retval TRUE Signature successfully generated in PKCS1-v1_5.\r
+ @retval FALSE Signature generation failed.\r
+ @retval FALSE SigSize is too small.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+RsaPkcs1Sign (\r
+ IN VOID *RsaContext,\r
+ IN CONST UINT8 *MessageHash,\r
+ IN UINTN HashSize,\r
+ OUT UINT8 *Signature,\r
+ IN OUT UINTN *SigSize\r
+ )\r
+{\r
+ RSA *Rsa;\r
+ UINTN Size;\r
+ INTN ReturnVal;\r
+\r
+ ASSERT (RsaContext != NULL);\r
+ ASSERT (MessageHash != NULL);\r
+ ASSERT ((HashSize == MD5_DIGEST_SIZE) ||\r
+ (HashSize == SHA1_DIGEST_SIZE) ||\r
+ (HashSize == SHA256_DIGEST_SIZE));\r
+\r
+ Rsa = (RSA *) RsaContext;\r
+ Size = BN_num_bytes (Rsa->n);\r
+\r
+ if (*SigSize < Size) {\r
+ *SigSize = Size;\r
+ return FALSE;\r
+ }\r
+\r
+ ASSERT (Signature != NULL);\r
+\r
+ Size = DigestInfoEncoding (MessageHash, HashSize, Signature);\r
+\r
+ ReturnVal = RSA_private_encrypt (\r
+ (UINT32) Size,\r
+ Signature,\r
+ Signature,\r
+ Rsa,\r
+ RSA_PKCS1_PADDING\r
+ );\r
+\r
+ if (ReturnVal < (INTN) Size) {\r
+ return FALSE;\r
+ }\r
+\r
+ *SigSize = (UINTN)ReturnVal;\r
+ return TRUE;\r
+}\r
\r
/**\r
Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in\r
If RsaContext is NULL, then ASSERT().\r
If MessageHash is NULL, then ASSERT().\r
If Signature is NULL, then ASSERT().\r
- If HashLength is not equal to the size of MD5, SHA-1 or SHA-256 digest, then ASSERT().\r
+ If HashSize is not equal to the size of MD5, SHA-1, SHA-256, SHA-224, SHA-512 or SHA-384 digest, then ASSERT().\r
\r
@param[in] RsaContext Pointer to RSA context for signature verification.\r
@param[in] MessageHash Pointer to octet message hash to be checked.\r
- @param[in] HashLength Length of the message hash in bytes.\r
+ @param[in] HashSize Size of the message hash in bytes.\r
@param[in] Signature Pointer to RSA PKCS1-v1_5 signature to be verified.\r
- @param[in] SigLength Length of signature in bytes.\r
+ @param[in] SigSize Size of signature in bytes.\r
\r
- @return TRUE Valid signature encoded in PKCS1-v1_5.\r
- @return FALSE Invalid signature or invalid RSA context.\r
+ @retval TRUE Valid signature encoded in PKCS1-v1_5.\r
+ @retval FALSE Invalid signature or invalid RSA context.\r
\r
**/\r
BOOLEAN\r
RsaPkcs1Verify (\r
IN VOID *RsaContext,\r
IN CONST UINT8 *MessageHash,\r
- IN UINTN HashLength,\r
+ IN UINTN HashSize,\r
IN UINT8 *Signature,\r
- IN UINTN SigLength\r
+ IN UINTN SigSize\r
)\r
{\r
INTN Length;\r
ASSERT (Signature != NULL);\r
\r
//\r
- // ASSERT if unsupported hash length:\r
+ // ASSERT if unsupported hash size:\r
// Only MD5, SHA-1 or SHA-256 digest size is supported\r
//\r
- ASSERT ((HashLength == MD5_DIGEST_SIZE) || (HashLength == SHA1_DIGEST_SIZE) ||\r
- (HashLength == SHA256_DIGEST_SIZE));\r
+ ASSERT ((HashSize == MD5_DIGEST_SIZE) || (HashSize == SHA1_DIGEST_SIZE) ||\r
+ (HashSize == SHA256_DIGEST_SIZE));\r
\r
//\r
// RSA PKCS#1 Signature Decoding using OpenSSL RSA Decryption with Public Key\r
//\r
Length = RSA_public_decrypt (\r
- (int)SigLength,\r
+ (UINT32) SigSize,\r
Signature,\r
Signature,\r
RsaContext,\r
\r
//\r
// Invalid RSA Key or PKCS#1 Padding Checking Failed (if Length < 0)\r
- // NOTE: Length should be the addition of HashLength and some DER value.\r
+ // NOTE: Length should be the addition of HashSize and some DER value.\r
// Ignore more strict length checking here.\r
//\r
- if (Length < (INTN) HashLength) {\r
+ if (Length < (INTN) HashSize) {\r
return FALSE;\r
}\r
\r
// Then Memory Comparing should skip the DER value of the underlying SEQUENCE\r
// type and AlgorithmIdentifier.\r
//\r
- if (CompareMem (MessageHash, Signature + Length - HashLength, HashLength) == 0) {\r
+ if (CompareMem (MessageHash, Signature + Length - HashSize, HashSize) == 0) {\r
//\r
// Valid RSA PKCS#1 Signature\r
//\r