]> git.proxmox.com Git - mirror_edk2.git/blobdiff - CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c
Add interfaces to several library instances of BaseCryptLib.
[mirror_edk2.git] / CryptoPkg / Library / BaseCryptLib / Pk / CryptRsaBasic.c
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptRsaBasic.c
new file mode 100644 (file)
index 0000000..6bf95de
--- /dev/null
@@ -0,0 +1,319 @@
+/** @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