--- /dev/null
+/** @file\r
+ RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.\r
+\r
+ This file implements following APIs which provide more capabilities for RSA:\r
+ 1) RsaGetKey\r
+ 2) RsaGenerateKey\r
+ 3) RsaCheckKey\r
+ 4) RsaPkcs1Sign\r
+\r
+Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "InternalCryptLib.h"\r
+\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
+ 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 return FALSE.\r
+ If BnSize is NULL, then return FALSE.\r
+ If BnSize is large enough but BigNumber is NULL, then return FALSE.\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
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (RsaContext == NULL || BnSize == NULL) {\r
+ return FALSE;\r
+ }\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
+ if (BigNumber == NULL) {\r
+ return FALSE;\r
+ }\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 return FALSE.\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
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (RsaContext == NULL) {\r
+ return FALSE;\r
+ }\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 return FALSE.\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
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (RsaContext == NULL) {\r
+ return FALSE;\r
+ }\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
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (Message == NULL || DigestInfo == NULL) {\r
+ return FALSE;\r
+ }\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 return FALSE.\r
+ If MessageHash is NULL, then return FALSE.\r
+ If HashSize is not equal to the size of MD5, SHA-1 or SHA-256 digest, then return FALSE.\r
+ If SigSize is large enough but Signature is NULL, then return FALSE.\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
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (RsaContext == NULL || MessageHash == NULL ||\r
+ (HashSize != MD5_DIGEST_SIZE && HashSize != SHA1_DIGEST_SIZE && HashSize != SHA256_DIGEST_SIZE)) {\r
+ return FALSE;\r
+ }\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
+ if (Signature == NULL) {\r
+ return FALSE;\r
+ }\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