--- /dev/null
+/** @file\r
+ RSA Asymmetric Cipher Wrapper Implementation over OpenSSL.\r
+\r
+ This file implements following APIs which provide basic capabilities for RSA:\r
+ 1) RsaNew\r
+ 2) RsaFree\r
+ 3) RsaSetKey\r
+ 4) RsaPkcs1Verify\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
+/**\r
+ Allocates and initializes one RSA context for subsequent use.\r
+\r
+ @return Pointer to the RSA context that has been initialized.\r
+ If the allocations fails, RsaNew() returns NULL.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+RsaNew (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // Allocates & Initializes RSA Context by OpenSSL RSA_new()\r
+ //\r
+ return (VOID *)RSA_new ();\r
+}\r
+\r
+/**\r
+ Release the specified RSA context.\r
+\r
+ @param[in] RsaContext Pointer to the RSA context to be released.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+RsaFree (\r
+ IN VOID *RsaContext\r
+ )\r
+{\r
+ //\r
+ // Free OpenSSL RSA Context\r
+ //\r
+ RSA_free ((RSA *)RsaContext);\r
+}\r
+\r
+/**\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 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[in] BigNumber Pointer to octet integer buffer.\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
+ @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 BnSize\r
+ )\r
+{\r
+ RSA *RsaKey;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (RsaContext == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ RsaKey = (RSA *)RsaContext;\r
+ //\r
+ // Set RSA Key Components by converting octet string to OpenSSL BN representation.\r
+ // NOTE: For RSA public key (used in signature verification), only public components\r
+ // (N, e) are needed.\r
+ //\r
+ switch (KeyTag) {\r
+\r
+ //\r
+ // RSA Public Modulus (N)\r
+ //\r
+ case RsaKeyN:\r
+ if (RsaKey->n != NULL) {\r
+ BN_free (RsaKey->n);\r
+ }\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
+ // RSA Public Exponent (e)\r
+ //\r
+ case RsaKeyE:\r
+ if (RsaKey->e != NULL) {\r
+ BN_free (RsaKey->e);\r
+ }\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
+ // RSA Private Exponent (d)\r
+ //\r
+ case RsaKeyD:\r
+ if (RsaKey->d != NULL) {\r
+ BN_free (RsaKey->d);\r
+ }\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
+ // RSA Secret Prime Factor of Modulus (p)\r
+ //\r
+ case RsaKeyP:\r
+ if (RsaKey->p != NULL) {\r
+ BN_free (RsaKey->p);\r
+ }\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
+ // RSA Secret Prime Factor of Modules (q)\r
+ //\r
+ case RsaKeyQ:\r
+ if (RsaKey->q != NULL) {\r
+ BN_free (RsaKey->q);\r
+ }\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
+ // p's CRT Exponent (== d mod (p - 1))\r
+ //\r
+ case RsaKeyDp:\r
+ if (RsaKey->dmp1 != NULL) {\r
+ BN_free (RsaKey->dmp1);\r
+ }\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
+ // q's CRT Exponent (== d mod (q - 1))\r
+ //\r
+ case RsaKeyDq:\r
+ if (RsaKey->dmq1 != NULL) {\r
+ BN_free (RsaKey->dmq1);\r
+ }\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
+ // The CRT Coefficient (== 1/q mod p)\r
+ //\r
+ case RsaKeyQInv:\r
+ if (RsaKey->iqmp != NULL) {\r
+ BN_free (RsaKey->iqmp);\r
+ }\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
+ Verifies the RSA-SSA signature with EMSA-PKCS1-v1_5 encoding scheme defined in\r
+ RSA PKCS#1.\r
+\r
+ If RsaContext is NULL, then return FALSE.\r
+ If MessageHash is NULL, then return FALSE.\r
+ If Signature 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
+\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] 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] SigSize Size of signature in bytes.\r
+\r
+ @retval TRUE Valid signature encoded in PKCS1-v1_5.\r
+ @retval FALSE Invalid signature or invalid RSA context.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+RsaPkcs1Verify (\r
+ IN VOID *RsaContext,\r
+ IN CONST UINT8 *MessageHash,\r
+ IN UINTN HashSize,\r
+ IN UINT8 *Signature,\r
+ IN UINTN SigSize\r
+ )\r
+{\r
+ INTN Length;\r
+\r
+ //\r
+ // Check input parameters.\r
+ //\r
+ if (RsaContext == NULL || MessageHash == NULL || Signature == NULL) {\r
+ return FALSE;\r
+ }\r
+\r
+ \r
+ //\r
+ // Check for unsupported hash size:\r
+ // Only MD5, SHA-1 or SHA-256 digest size is supported\r
+ //\r
+ if (HashSize != MD5_DIGEST_SIZE && HashSize != SHA1_DIGEST_SIZE && HashSize != SHA256_DIGEST_SIZE) {\r
+ return FALSE;\r
+ }\r
+ \r
+ //\r
+ // RSA PKCS#1 Signature Decoding using OpenSSL RSA Decryption with Public Key\r
+ //\r
+ Length = RSA_public_decrypt (\r
+ (UINT32) SigSize,\r
+ Signature,\r
+ Signature,\r
+ RsaContext,\r
+ RSA_PKCS1_PADDING\r
+ );\r
+\r
+ //\r
+ // Invalid RSA Key or PKCS#1 Padding Checking Failed (if Length < 0)\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) HashSize) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Validate the MessageHash and Decoded Signature\r
+ // NOTE: The decoded Signature should be the DER encoding of the DigestInfo value\r
+ // DigestInfo ::= SEQUENCE {\r
+ // digestAlgorithm AlgorithmIdentifier\r
+ // digest OCTET STRING\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 - HashSize, HashSize) == 0) {\r
+ //\r
+ // Valid RSA PKCS#1 Signature\r
+ //\r
+ return TRUE;\r
+ } else {\r
+ //\r
+ // Failed to verification\r
+ //\r
+ return FALSE;\r
+ }\r
+}\r