public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface.
@ 2022-10-12  2:47 Qi Zhang
  2022-10-12  2:47 ` [PATCH V2 1/3] " Qi Zhang
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Qi Zhang @ 2022-10-12  2:47 UTC (permalink / raw)
  To: devel; +Cc: Qi Zhang, Jiewen Yao, Jian J Wang, Xiaoyu Lu, Guomin Jiang

This patch is used to retrieve EC key from PEM and X509 and
carry out the EC-DSA signature and verify it.

The interface was tested by:
1. DeviceSecurity on edk2-staging
https://github.com/tianocore/edk2-staging/tree/DeviceSecurity.
2. Unit test in CryptoPkg/Test

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4102
PR: https://github.com/tianocore/edk2/pull/3464

V2 change: change the protocol version.

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Signed-off-by: Qi Zhang <qi1.zhang@intel.com>

Qi Zhang (3):
  CryptoPkg: Add EC key retrieving and signature interface.
  CryptoPkg: Add EC key interface to DXE and protocol
  CryptoPkg: add unit test for EC key interface.

 CryptoPkg/Driver/Crypto.c                     | 143 +++++++++-
 CryptoPkg/Include/Library/BaseCryptLib.h      | 129 +++++++++
 .../Pcd/PcdCryptoServiceFamilyEnable.h        |   4 +
 CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c |  87 ++++++
 .../Library/BaseCryptLib/Pem/CryptPemNull.c   |  30 ++
 CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c   | 258 ++++++++++++++++++
 .../Library/BaseCryptLib/Pk/CryptEcNull.c     |  82 ++++++
 CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c |  83 ++++++
 .../Library/BaseCryptLib/Pk/CryptX509Null.c   |  28 ++
 .../BaseCryptLibNull/Pem/CryptPemNull.c       |  30 ++
 .../Library/BaseCryptLibNull/Pk/CryptEcNull.c |  82 ++++++
 .../BaseCryptLibNull/Pk/CryptX509Null.c       |  28 ++
 .../BaseCryptLibOnProtocolPpi/CryptLib.c      | 136 +++++++++
 CryptoPkg/Private/Protocol/Crypto.h           | 131 ++++++++-
 .../UnitTest/Library/BaseCryptLib/EcTests.c   | 156 +++++++++++
 15 files changed, 1405 insertions(+), 2 deletions(-)

-- 
2.26.2.windows.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH V2 1/3] CryptoPkg: Add EC key retrieving and signature interface.
  2022-10-12  2:47 [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Qi Zhang
@ 2022-10-12  2:47 ` Qi Zhang
  2022-10-12  2:47 ` [PATCH V2 2/3] CryptoPkg: Add EC key interface to DXE and protocol Qi Zhang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Qi Zhang @ 2022-10-12  2:47 UTC (permalink / raw)
  To: devel; +Cc: Qi Zhang, Jiewen Yao, Jian J Wang, Xiaoyu Lu, Guomin Jiang

This patch is used to retrieve EC key from PEM and X509 and
carry out the EC-DSA signature and verify it.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4102

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Signed-off-by: Qi Zhang <qi1.zhang@intel.com>
---
 CryptoPkg/Include/Library/BaseCryptLib.h      | 129 +++++++++
 CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c |  87 ++++++
 .../Library/BaseCryptLib/Pem/CryptPemNull.c   |  30 ++
 CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c   | 258 ++++++++++++++++++
 .../Library/BaseCryptLib/Pk/CryptEcNull.c     |  82 ++++++
 CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c |  83 ++++++
 .../Library/BaseCryptLib/Pk/CryptX509Null.c   |  28 ++
 .../BaseCryptLibNull/Pem/CryptPemNull.c       |  30 ++
 .../Library/BaseCryptLibNull/Pk/CryptEcNull.c |  82 ++++++
 .../BaseCryptLibNull/Pk/CryptX509Null.c       |  28 ++
 10 files changed, 837 insertions(+)

diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h b/CryptoPkg/Include/Library/BaseCryptLib.h
index 63c6228368..dfeb8c7d55 100644
--- a/CryptoPkg/Include/Library/BaseCryptLib.h
+++ b/CryptoPkg/Include/Library/BaseCryptLib.h
@@ -16,6 +16,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 
 #define CRYPTO_NID_NULL  0x0000
 
+// Hash
+#define CRYPTO_NID_SHA256  0x0001
+#define CRYPTO_NID_SHA384  0x0002
+#define CRYPTO_NID_SHA512  0x0003
+
 // Key Exchange
 #define CRYPTO_NID_SECP256R1  0x0204
 #define CRYPTO_NID_SECP384R1  0x0205
@@ -3678,4 +3683,128 @@ EcDhComputeKey (
   IN OUT  UINTN        *KeySize
   );
 
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPrivateKeyFromPem (
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  );
+
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  );
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaSign (
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  );
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaVerify (
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  );
+
 #endif // __BASE_CRYPT_LIB_H__
diff --git a/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c b/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c
index 7733d772f4..559a6b4df0 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c
@@ -126,3 +126,90 @@ _Exit:
 
   return Status;
 }
+
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPrivateKeyFromPem (
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  )
+{
+ #if FixedPcdGetBool (PcdOpensslEcEnabled)
+  BOOLEAN  Status;
+  BIO      *PemBio;
+
+  //
+  // Check input parameters.
+  //
+  if ((PemData == NULL) || (EcContext == NULL) || (PemSize > INT_MAX)) {
+    return FALSE;
+  }
+
+  //
+  // Add possible block-cipher descriptor for PEM data decryption.
+  // NOTE: Only support most popular ciphers AES for the encrypted PEM.
+  //
+  if (EVP_add_cipher (EVP_aes_128_cbc ()) == 0) {
+    return FALSE;
+  }
+
+  if (EVP_add_cipher (EVP_aes_192_cbc ()) == 0) {
+    return FALSE;
+  }
+
+  if (EVP_add_cipher (EVP_aes_256_cbc ()) == 0) {
+    return FALSE;
+  }
+
+  Status = FALSE;
+
+  //
+  // Read encrypted PEM Data.
+  //
+  PemBio = BIO_new (BIO_s_mem ());
+  if (PemBio == NULL) {
+    goto _Exit;
+  }
+
+  if (BIO_write (PemBio, PemData, (int)PemSize) <= 0) {
+    goto _Exit;
+  }
+
+  //
+  // Retrieve EC Private Key from encrypted PEM data.
+  //
+  *EcContext = PEM_read_bio_ECPrivateKey (PemBio, NULL, (pem_password_cb *)&PasswordCallback, (void *)Password);
+  if (*EcContext != NULL) {
+    Status = TRUE;
+  }
+
+_Exit:
+  //
+  // Release Resources.
+  //
+  BIO_free (PemBio);
+
+  return Status;
+ #else
+  return FALSE;
+ #endif
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c b/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c
index 4eeabd91ad..4ca9357c96 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pem/CryptPemNull.c
@@ -36,3 +36,33 @@ RsaGetPrivateKeyFromPem (
   ASSERT (FALSE);
   return FALSE;
 }
+
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPrivateKeyFromPem (
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
index 396c819834..d8cc9ba0e8 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
@@ -763,3 +763,261 @@ fail:
   EC_KEY_free (PeerEcKey);
   return RetVal;
 }
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaSign (
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  )
+{
+  EC_KEY     *EcKey;
+  ECDSA_SIG  *EcDsaSig;
+  INT32      OpenSslNid;
+  UINT8      HalfSize;
+  BIGNUM     *R;
+  BIGNUM     *S;
+  INTN       RSize;
+  INTN       SSize;
+
+  if ((EcContext == NULL) || (MessageHash == NULL)) {
+    return FALSE;
+  }
+
+  if (Signature == NULL) {
+    return FALSE;
+  }
+
+  EcKey      = (EC_KEY *)EcContext;
+  OpenSslNid = EC_GROUP_get_curve_name (EC_KEY_get0_group (EcKey));
+  switch (OpenSslNid) {
+    case NID_X9_62_prime256v1:
+      HalfSize = 32;
+      break;
+    case NID_secp384r1:
+      HalfSize = 48;
+      break;
+    case NID_secp521r1:
+      HalfSize = 66;
+      break;
+    default:
+      return FALSE;
+  }
+
+  if (*SigSize < (UINTN)(HalfSize * 2)) {
+    *SigSize = HalfSize * 2;
+    return FALSE;
+  }
+
+  *SigSize = HalfSize * 2;
+  ZeroMem (Signature, *SigSize);
+
+  switch (HashNid) {
+    case CRYPTO_NID_SHA256:
+      if (HashSize != SHA256_DIGEST_SIZE) {
+        return FALSE;
+      }
+
+      break;
+
+    case CRYPTO_NID_SHA384:
+      if (HashSize != SHA384_DIGEST_SIZE) {
+        return FALSE;
+      }
+
+      break;
+
+    case CRYPTO_NID_SHA512:
+      if (HashSize != SHA512_DIGEST_SIZE) {
+        return FALSE;
+      }
+
+      break;
+
+    default:
+      return FALSE;
+  }
+
+  EcDsaSig = ECDSA_do_sign (
+               MessageHash,
+               (UINT32)HashSize,
+               (EC_KEY *)EcContext
+               );
+  if (EcDsaSig == NULL) {
+    return FALSE;
+  }
+
+  ECDSA_SIG_get0 (EcDsaSig, (CONST BIGNUM **)&R, (CONST BIGNUM **)&S);
+
+  RSize = BN_num_bytes (R);
+  SSize = BN_num_bytes (S);
+  if ((RSize <= 0) || (SSize <= 0)) {
+    ECDSA_SIG_free (EcDsaSig);
+    return FALSE;
+  }
+
+  ASSERT ((UINTN)RSize <= HalfSize && (UINTN)SSize <= HalfSize);
+
+  BN_bn2bin (R, &Signature[0 + HalfSize - RSize]);
+  BN_bn2bin (S, &Signature[HalfSize + HalfSize - SSize]);
+
+  ECDSA_SIG_free (EcDsaSig);
+
+  return TRUE;
+}
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaVerify (
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  )
+{
+  INT32      Result;
+  EC_KEY     *EcKey;
+  ECDSA_SIG  *EcDsaSig;
+  INT32      OpenSslNid;
+  UINT8      HalfSize;
+  BIGNUM     *R;
+  BIGNUM     *S;
+
+  if ((EcContext == NULL) || (MessageHash == NULL) || (Signature == NULL)) {
+    return FALSE;
+  }
+
+  if ((SigSize > INT_MAX) || (SigSize == 0)) {
+    return FALSE;
+  }
+
+  EcKey      = (EC_KEY *)EcContext;
+  OpenSslNid = EC_GROUP_get_curve_name (EC_KEY_get0_group (EcKey));
+  switch (OpenSslNid) {
+    case NID_X9_62_prime256v1:
+      HalfSize = 32;
+      break;
+    case NID_secp384r1:
+      HalfSize = 48;
+      break;
+    case NID_secp521r1:
+      HalfSize = 66;
+      break;
+    default:
+      return FALSE;
+  }
+
+  if (SigSize != (UINTN)(HalfSize * 2)) {
+    return FALSE;
+  }
+
+  switch (HashNid) {
+    case CRYPTO_NID_SHA256:
+      if (HashSize != SHA256_DIGEST_SIZE) {
+        return FALSE;
+      }
+
+      break;
+
+    case CRYPTO_NID_SHA384:
+      if (HashSize != SHA384_DIGEST_SIZE) {
+        return FALSE;
+      }
+
+      break;
+
+    case CRYPTO_NID_SHA512:
+      if (HashSize != SHA512_DIGEST_SIZE) {
+        return FALSE;
+      }
+
+      break;
+
+    default:
+      return FALSE;
+  }
+
+  EcDsaSig = ECDSA_SIG_new ();
+  if (EcDsaSig == NULL) {
+    ECDSA_SIG_free (EcDsaSig);
+    return FALSE;
+  }
+
+  R = BN_bin2bn (Signature, (UINT32)HalfSize, NULL);
+  S = BN_bin2bn (Signature + HalfSize, (UINT32)HalfSize, NULL);
+  if ((R == NULL) || (S == NULL)) {
+    ECDSA_SIG_free (EcDsaSig);
+    return FALSE;
+  }
+
+  ECDSA_SIG_set0 (EcDsaSig, R, S);
+
+  Result = ECDSA_do_verify (
+             MessageHash,
+             (UINT32)HashSize,
+             EcDsaSig,
+             (EC_KEY *)EcContext
+             );
+
+  ECDSA_SIG_free (EcDsaSig);
+
+  return (Result == 1);
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
index d9f1004f6c..1129fa7696 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
@@ -494,3 +494,85 @@ EcDhComputeKey (
   ASSERT (FALSE);
   return FALSE;
 }
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaSign (
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaVerify (
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c
index e6bb45e641..58d3f27b11 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c
@@ -842,3 +842,86 @@ X509GetTBSCert (
 
   return TRUE;
 }
+
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  )
+{
+ #if FixedPcdGetBool (PcdOpensslEcEnabled)
+  BOOLEAN   Status;
+  EVP_PKEY  *Pkey;
+  X509      *X509Cert;
+
+  //
+  // Check input parameters.
+  //
+  if ((Cert == NULL) || (EcContext == NULL)) {
+    return FALSE;
+  }
+
+  Pkey     = NULL;
+  X509Cert = NULL;
+
+  //
+  // Read DER-encoded X509 Certificate and Construct X509 object.
+  //
+  Status = X509ConstructCertificate (Cert, CertSize, (UINT8 **)&X509Cert);
+  if ((X509Cert == NULL) || (!Status)) {
+    Status = FALSE;
+    goto _Exit;
+  }
+
+  Status = FALSE;
+
+  //
+  // Retrieve and check EVP_PKEY data from X509 Certificate.
+  //
+  Pkey = X509_get_pubkey (X509Cert);
+  if ((Pkey == NULL) || (EVP_PKEY_id (Pkey) != EVP_PKEY_EC)) {
+    goto _Exit;
+  }
+
+  //
+  // Duplicate EC Context from the retrieved EVP_PKEY.
+  //
+  if ((*EcContext = EC_KEY_dup (EVP_PKEY_get0_EC_KEY (Pkey))) != NULL) {
+    Status = TRUE;
+  }
+
+_Exit:
+  //
+  // Release Resources.
+  //
+  if (X509Cert != NULL) {
+    X509_free (X509Cert);
+  }
+
+  if (Pkey != NULL) {
+    EVP_PKEY_free (Pkey);
+  }
+
+  return Status;
+ #else
+  return FALSE;
+ #endif
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c b/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c
index 38819723c7..c6718e6aeb 100644
--- a/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptX509Null.c
@@ -292,3 +292,31 @@ X509GetTBSCert (
   ASSERT (FALSE);
   return FALSE;
 }
+
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibNull/Pem/CryptPemNull.c b/CryptoPkg/Library/BaseCryptLibNull/Pem/CryptPemNull.c
index 4eeabd91ad..4ca9357c96 100644
--- a/CryptoPkg/Library/BaseCryptLibNull/Pem/CryptPemNull.c
+++ b/CryptoPkg/Library/BaseCryptLibNull/Pem/CryptPemNull.c
@@ -36,3 +36,33 @@ RsaGetPrivateKeyFromPem (
   ASSERT (FALSE);
   return FALSE;
 }
+
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPrivateKeyFromPem (
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c b/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c
index d9f1004f6c..1129fa7696 100644
--- a/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c
+++ b/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c
@@ -494,3 +494,85 @@ EcDhComputeKey (
   ASSERT (FALSE);
   return FALSE;
 }
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaSign (
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaVerify (
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptX509Null.c b/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptX509Null.c
index 38819723c7..c6718e6aeb 100644
--- a/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptX509Null.c
+++ b/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptX509Null.c
@@ -292,3 +292,31 @@ X509GetTBSCert (
   ASSERT (FALSE);
   return FALSE;
 }
+
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  )
+{
+  ASSERT (FALSE);
+  return FALSE;
+}
-- 
2.26.2.windows.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH V2 2/3] CryptoPkg: Add EC key interface to DXE and protocol
  2022-10-12  2:47 [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Qi Zhang
  2022-10-12  2:47 ` [PATCH V2 1/3] " Qi Zhang
@ 2022-10-12  2:47 ` Qi Zhang
  2022-10-12  2:48 ` [PATCH V2 3/3] CryptoPkg: add unit test for EC key interface Qi Zhang
  2022-10-12  5:57 ` [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Yao, Jiewen
  3 siblings, 0 replies; 5+ messages in thread
From: Qi Zhang @ 2022-10-12  2:47 UTC (permalink / raw)
  To: devel; +Cc: Qi Zhang, Jiewen Yao, Jian J Wang, Xiaoyu Lu, Guomin Jiang

The implementation provide EC key interface for EFI
 driver nad EFI BaseCrypt protocol.

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4102

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Signed-off-by: Qi Zhang <qi1.zhang@intel.com>
---
 CryptoPkg/Driver/Crypto.c                     | 143 +++++++++++++++++-
 .../Pcd/PcdCryptoServiceFamilyEnable.h        |   4 +
 .../BaseCryptLibOnProtocolPpi/CryptLib.c      | 136 +++++++++++++++++
 CryptoPkg/Private/Protocol/Crypto.h           | 131 +++++++++++++++-
 4 files changed, 412 insertions(+), 2 deletions(-)

diff --git a/CryptoPkg/Driver/Crypto.c b/CryptoPkg/Driver/Crypto.c
index f1ff77855c..1928adbff7 100644
--- a/CryptoPkg/Driver/Crypto.c
+++ b/CryptoPkg/Driver/Crypto.c
@@ -6137,6 +6137,142 @@ CryptoServiceEcDhComputeKey (
   return CALL_BASECRYPTLIB (Ec.Services.DhComputeKey, EcDhComputeKey, (EcContext, PeerPublic, PeerPublicSize, CompressFlag, Key, KeySize), FALSE);
 }
 
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+CryptoServiceEcGetPublicKeyFromX509 (
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  )
+{
+  return CALL_BASECRYPTLIB (Ec.Services.GetPublicKeyFromX509, EcGetPublicKeyFromX509, (Cert, CertSize, EcContext), FALSE);
+}
+
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+CryptoServiceEcGetPrivateKeyFromPem (
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  )
+{
+  return CALL_BASECRYPTLIB (Ec.Services.GetPrivateKeyFromPem, EcGetPrivateKeyFromPem, (PemData, PemSize, Password, EcContext), FALSE);
+}
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+CryptoServiceEcDsaSign (
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  )
+{
+  return CALL_BASECRYPTLIB (Ec.Services.DsaSign, EcDsaSign, (EcContext, HashNid, MessageHash, HashSize, Signature, SigSize), FALSE);
+}
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+BOOLEAN
+EFIAPI
+CryptoServiceEcDsaVerify (
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  )
+{
+  return CALL_BASECRYPTLIB (Ec.Services.DsaVerify, EcDsaVerify, (EcContext, HashNid, MessageHash, HashSize, Signature, SigSize), FALSE);
+}
+
 const EDKII_CRYPTO_PROTOCOL  mEdkiiCrypto = {
   /// Version
   CryptoServiceGetCryptoVersion,
@@ -6416,5 +6552,10 @@ const EDKII_CRYPTO_PROTOCOL  mEdkiiCrypto = {
   CryptoServiceTlsSetSignatureAlgoList,
   CryptoServiceTlsSetEcCurve,
   /// TLS Get (continued)
-  CryptoServiceTlsGetExportKey
+  CryptoServiceTlsGetExportKey,
+  /// Ec (Continued)
+  CryptoServiceEcGetPublicKeyFromX509,
+  CryptoServiceEcGetPrivateKeyFromPem,
+  CryptoServiceEcDsaSign,
+  CryptoServiceEcDsaVerify
 };
diff --git a/CryptoPkg/Include/Pcd/PcdCryptoServiceFamilyEnable.h b/CryptoPkg/Include/Pcd/PcdCryptoServiceFamilyEnable.h
index 4740589417..12b0c0583e 100644
--- a/CryptoPkg/Include/Pcd/PcdCryptoServiceFamilyEnable.h
+++ b/CryptoPkg/Include/Pcd/PcdCryptoServiceFamilyEnable.h
@@ -383,6 +383,10 @@ typedef struct {
       UINT8    GenerateKey                   : 1;
       UINT8    GetPubKey                     : 1;
       UINT8    DhComputeKey                  : 1;
+      UINT8    GetPublicKeyFromX509          : 1;
+      UINT8    GetPrivateKeyFromPem          : 1;
+      UINT8    DsaSign                       : 1;
+      UINT8    DsaVerify                     : 1;
     } Services;
     UINT32    Family;
   } Ec;
diff --git a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c
index 52b934a545..48ec6d3528 100644
--- a/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c
+++ b/CryptoPkg/Library/BaseCryptLibOnProtocolPpi/CryptLib.c
@@ -5164,3 +5164,139 @@ EcDhComputeKey (
 {
   CALL_CRYPTO_SERVICE (EcDhComputeKey, (EcContext, PeerPublic, PeerPublicSize, CompressFlag, Key, KeySize), FALSE);
 }
+
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPublicKeyFromX509 (
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  )
+{
+  CALL_CRYPTO_SERVICE (EcGetPublicKeyFromX509, (Cert, CertSize, EcContext), FALSE);
+}
+
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+BOOLEAN
+EFIAPI
+EcGetPrivateKeyFromPem (
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  )
+{
+  CALL_CRYPTO_SERVICE (EcGetPrivateKeyFromPem, (PemData, PemSize, Password, EcContext), FALSE);
+}
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaSign (
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  )
+{
+  CALL_CRYPTO_SERVICE (EcDsaSign, (EcContext, HashNid, MessageHash, HashSize, Signature, SigSize), FALSE);
+}
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+BOOLEAN
+EFIAPI
+EcDsaVerify (
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  )
+{
+  CALL_CRYPTO_SERVICE (EcDsaVerify, (EcContext, HashNid, MessageHash, HashSize, Signature, SigSize), FALSE);
+}
diff --git a/CryptoPkg/Private/Protocol/Crypto.h b/CryptoPkg/Private/Protocol/Crypto.h
index 6293efa36b..bfb278d388 100644
--- a/CryptoPkg/Private/Protocol/Crypto.h
+++ b/CryptoPkg/Private/Protocol/Crypto.h
@@ -21,7 +21,7 @@
 /// the EDK II Crypto Protocol is extended, this version define must be
 /// increased.
 ///
-#define EDKII_CRYPTO_VERSION  14
+#define EDKII_CRYPTO_VERSION  15
 
 ///
 /// EDK II Crypto Protocol forward declaration
@@ -4821,6 +4821,130 @@ BOOLEAN
   IN OUT  UINTN        *KeySize
   );
 
+/**
+  Retrieve the EC Public Key from one DER-encoded X509 certificate.
+
+  @param[in]  Cert         Pointer to the DER-encoded X509 certificate.
+  @param[in]  CertSize     Size of the X509 certificate in bytes.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC public key component. Use EcFree() function to free the
+                           resource.
+
+  If Cert is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Public Key was retrieved successfully.
+  @retval  FALSE  Fail to retrieve EC public key from X509 certificate.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EDKII_CRYPTO_EC_GET_PUBLIC_KEY_FROM_X509)(
+  IN   CONST UINT8  *Cert,
+  IN   UINTN        CertSize,
+  OUT  VOID         **EcContext
+  );
+
+/**
+  Retrieve the EC Private Key from the password-protected PEM key data.
+
+  @param[in]  PemData      Pointer to the PEM-encoded key data to be retrieved.
+  @param[in]  PemSize      Size of the PEM key data in bytes.
+  @param[in]  Password     NULL-terminated passphrase used for encrypted PEM key data.
+  @param[out] EcContext    Pointer to new-generated EC DSA context which contain the retrieved
+                           EC private key component. Use EcFree() function to free the
+                           resource.
+
+  If PemData is NULL, then return FALSE.
+  If EcContext is NULL, then return FALSE.
+
+  @retval  TRUE   EC Private Key was retrieved successfully.
+  @retval  FALSE  Invalid PEM key data or incorrect password.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EDKII_CRYPTO_EC_GET_PRIVATE_KEY_FROM_PEM)(
+  IN   CONST UINT8  *PemData,
+  IN   UINTN        PemSize,
+  IN   CONST CHAR8  *Password,
+  OUT  VOID         **EcContext
+  );
+
+/**
+  Carries out the EC-DSA signature.
+
+  This function carries out the EC-DSA signature.
+  If the Signature buffer is too small to hold the contents of signature, FALSE
+  is returned and SigSize is set to the required buffer size to obtain the signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+  If SigSize is large enough but Signature is NULL, then return FALSE.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]       EcContext    Pointer to EC context for signature generation.
+  @param[in]       HashNid      hash NID
+  @param[in]       MessageHash  Pointer to octet message hash to be signed.
+  @param[in]       HashSize     Size of the message hash in bytes.
+  @param[out]      Signature    Pointer to buffer to receive EC-DSA signature.
+  @param[in, out]  SigSize      On input, the size of Signature buffer in bytes.
+                                On output, the size of data returned in Signature buffer in bytes.
+
+  @retval  TRUE   Signature successfully generated in EC-DSA.
+  @retval  FALSE  Signature generation failed.
+  @retval  FALSE  SigSize is too small.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EDKII_CRYPTO_EC_DSA_SIGN)(
+  IN      VOID         *EcContext,
+  IN      UINTN        HashNid,
+  IN      CONST UINT8  *MessageHash,
+  IN      UINTN        HashSize,
+  OUT     UINT8        *Signature,
+  IN OUT  UINTN        *SigSize
+  );
+
+/**
+  Verifies the EC-DSA signature.
+
+  If EcContext is NULL, then return FALSE.
+  If MessageHash is NULL, then return FALSE.
+  If Signature is NULL, then return FALSE.
+  If HashSize need match the HashNid. HashNid could be SHA256, SHA384, SHA512, SHA3_256, SHA3_384, SHA3_512.
+
+  For P-256, the SigSize is 64. First 32-byte is R, Second 32-byte is S.
+  For P-384, the SigSize is 96. First 48-byte is R, Second 48-byte is S.
+  For P-521, the SigSize is 132. First 66-byte is R, Second 66-byte is S.
+
+  @param[in]  EcContext    Pointer to EC context for signature verification.
+  @param[in]  HashNid      hash NID
+  @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 EC-DSA signature to be verified.
+  @param[in]  SigSize      Size of signature in bytes.
+
+  @retval  TRUE   Valid signature encoded in EC-DSA.
+  @retval  FALSE  Invalid signature or invalid EC context.
+
+**/
+typedef
+BOOLEAN
+(EFIAPI *EDKII_CRYPTO_EC_DSA_VERIFY)(
+  IN  VOID         *EcContext,
+  IN  UINTN        HashNid,
+  IN  CONST UINT8  *MessageHash,
+  IN  UINTN        HashSize,
+  IN  CONST UINT8  *Signature,
+  IN  UINTN        SigSize
+  );
+
 ///
 /// EDK II Crypto Protocol
 ///
@@ -5084,6 +5208,11 @@ struct _EDKII_CRYPTO_PROTOCOL {
   EDKII_CRYPTO_TLS_SET_EC_CURVE                       TlsSetEcCurve;
   /// TLS Get (continued)
   EDKII_CRYPTO_TLS_GET_EXPORT_KEY                     TlsGetExportKey;
+  /// Ec (Continued)
+  EDKII_CRYPTO_EC_GET_PUBLIC_KEY_FROM_X509            EcGetPublicKeyFromX509;
+  EDKII_CRYPTO_EC_GET_PRIVATE_KEY_FROM_PEM            EcGetPrivateKeyFromPem;
+  EDKII_CRYPTO_EC_DSA_SIGN                            EcDsaSign;
+  EDKII_CRYPTO_EC_DSA_VERIFY                          EcDsaVerify;
 };
 
 extern GUID  gEdkiiCryptoProtocolGuid;
-- 
2.26.2.windows.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH V2 3/3] CryptoPkg: add unit test for EC key interface.
  2022-10-12  2:47 [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Qi Zhang
  2022-10-12  2:47 ` [PATCH V2 1/3] " Qi Zhang
  2022-10-12  2:47 ` [PATCH V2 2/3] CryptoPkg: Add EC key interface to DXE and protocol Qi Zhang
@ 2022-10-12  2:48 ` Qi Zhang
  2022-10-12  5:57 ` [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Yao, Jiewen
  3 siblings, 0 replies; 5+ messages in thread
From: Qi Zhang @ 2022-10-12  2:48 UTC (permalink / raw)
  To: devel; +Cc: Qi Zhang, Jiewen Yao, Jian J Wang, Xiaoyu Lu, Guomin Jiang

REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4102

Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com>
Cc: Guomin Jiang <guomin.jiang@intel.com>
Signed-off-by: Qi Zhang <qi1.zhang@intel.com>
---
 .../UnitTest/Library/BaseCryptLib/EcTests.c   | 156 ++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/CryptoPkg/Test/UnitTest/Library/BaseCryptLib/EcTests.c b/CryptoPkg/Test/UnitTest/Library/BaseCryptLib/EcTests.c
index 54ce0b22df..ee1e6e870b 100644
--- a/CryptoPkg/Test/UnitTest/Library/BaseCryptLib/EcTests.c
+++ b/CryptoPkg/Test/UnitTest/Library/BaseCryptLib/EcTests.c
@@ -60,6 +60,89 @@ struct Generator  EcCurveGenerator[EC_CURVE_NUM_SUPPORTED] =
   }
 };
 
+//
+// Root CA X509 Certificate for X509 Verification Routine (Generated by OpenSSL utility).
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8  mEccTestRootCer[] = {
+  0x30, 0x82, 0x01, 0xd2, 0x30, 0x82, 0x01, 0x77, 0xa0, 0x03, 0x02, 0x01,
+  0x02, 0x02, 0x09, 0x00, 0xcc, 0x10, 0x45, 0x50, 0xaf, 0x50, 0x1b, 0xe2,
+  0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
+  0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
+  0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
+  0x0c, 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65,
+  0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49,
+  0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67,
+  0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30,
+  0x1e, 0x17, 0x0d, 0x32, 0x30, 0x30, 0x32, 0x32, 0x37, 0x31, 0x32, 0x30,
+  0x32, 0x31, 0x30, 0x5a, 0x17, 0x0d, 0x33, 0x30, 0x30, 0x32, 0x32, 0x34,
+  0x31, 0x32, 0x30, 0x32, 0x31, 0x30, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30,
+  0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13,
+  0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x53, 0x6f, 0x6d,
+  0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06,
+  0x03, 0x55, 0x04, 0x0a, 0x0c, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e,
+  0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50,
+  0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+  0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+  0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x11, 0xa4, 0x06,
+  0x65, 0xb6, 0x79, 0x6e, 0x72, 0xb6, 0xd8, 0x09, 0x84, 0x92, 0x86, 0x11,
+  0x09, 0xde, 0xea, 0xd0, 0x0c, 0x60, 0xf1, 0x8a, 0xff, 0x7c, 0xde, 0xce,
+  0xec, 0x07, 0xba, 0xa5, 0xb8, 0xd5, 0x17, 0xe5, 0x62, 0x33, 0x2d, 0x88,
+  0xb1, 0x9a, 0xe6, 0xf3, 0x09, 0x43, 0x0e, 0xa9, 0xf7, 0x3c, 0xe9, 0x20,
+  0xba, 0xbd, 0xb1, 0x3c, 0x03, 0x89, 0x1e, 0x2a, 0xff, 0x6e, 0x08, 0xff,
+  0x2e, 0xa3, 0x50, 0x30, 0x4e, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
+  0x04, 0x16, 0x04, 0x14, 0x62, 0xe6, 0xd9, 0xa0, 0xee, 0x38, 0x18, 0x83,
+  0xfa, 0xe3, 0xed, 0x44, 0xa4, 0x37, 0xfd, 0x4a, 0x04, 0xdf, 0xe1, 0xd5,
+  0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
+  0x14, 0x62, 0xe6, 0xd9, 0xa0, 0xee, 0x38, 0x18, 0x83, 0xfa, 0xe3, 0xed,
+  0x44, 0xa4, 0x37, 0xfd, 0x4a, 0x04, 0xdf, 0xe1, 0xd5, 0x30, 0x0c, 0x06,
+  0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30,
+  0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03,
+  0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x99, 0x2f, 0x43, 0xeb, 0xdc,
+  0x4e, 0x53, 0xc7, 0xc1, 0xbd, 0xed, 0x95, 0xdc, 0xae, 0xd3, 0x75, 0xfa,
+  0xc4, 0xf7, 0xa4, 0x61, 0x00, 0x57, 0xce, 0xf3, 0xe0, 0x23, 0xf6, 0xf0,
+  0x41, 0x6f, 0xb5, 0x02, 0x21, 0x00, 0xf3, 0x97, 0x11, 0x06, 0x61, 0x10,
+  0xc7, 0x35, 0xe9, 0xf8, 0x3b, 0x59, 0xec, 0xf5, 0x51, 0xa0, 0xa6, 0x64,
+  0x6e, 0xe1, 0x44, 0xc7, 0xe1, 0xa2, 0xce, 0x90, 0x7f, 0xae, 0xad, 0xf4,
+  0xa9, 0xfa,
+};
+
+//
+// PEM key data for EC Private key Retrieving. (Generated by OpenSSL utility).
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT8  mEccTestPemKey[] = {
+  0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x45,
+  0x43, 0x20, 0x50, 0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x53,
+  0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b,
+  0x6a, 0x4f, 0x50, 0x51, 0x4d, 0x42, 0x42, 0x77, 0x3d, 0x3d, 0x0a, 0x2d,
+  0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50,
+  0x41, 0x52, 0x41, 0x4d, 0x45, 0x54, 0x45, 0x52, 0x53, 0x2d, 0x2d, 0x2d,
+  0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49,
+  0x4e, 0x20, 0x45, 0x43, 0x20, 0x50, 0x52, 0x49, 0x56, 0x41, 0x54, 0x45,
+  0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x48,
+  0x63, 0x43, 0x41, 0x51, 0x45, 0x45, 0x49, 0x4d, 0x4a, 0x54, 0x69, 0x75,
+  0x34, 0x56, 0x54, 0x54, 0x57, 0x68, 0x78, 0x4b, 0x62, 0x51, 0x65, 0x78,
+  0x6e, 0x30, 0x43, 0x58, 0x41, 0x77, 0x33, 0x44, 0x57, 0x6b, 0x6f, 0x78,
+  0x79, 0x77, 0x6b, 0x7a, 0x46, 0x50, 0x62, 0x32, 0x48, 0x68, 0x5a, 0x6e,
+  0x5a, 0x52, 0x6f, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d,
+  0x34, 0x39, 0x0a, 0x41, 0x77, 0x45, 0x48, 0x6f, 0x55, 0x51, 0x44, 0x51,
+  0x67, 0x41, 0x45, 0x45, 0x61, 0x51, 0x47, 0x5a, 0x62, 0x5a, 0x35, 0x62,
+  0x6e, 0x4b, 0x32, 0x32, 0x41, 0x6d, 0x45, 0x6b, 0x6f, 0x59, 0x52, 0x43,
+  0x64, 0x37, 0x71, 0x30, 0x41, 0x78, 0x67, 0x38, 0x59, 0x72, 0x2f, 0x66,
+  0x4e, 0x37, 0x4f, 0x37, 0x41, 0x65, 0x36, 0x70, 0x62, 0x6a, 0x56, 0x46,
+  0x2b, 0x56, 0x69, 0x4d, 0x79, 0x32, 0x49, 0x0a, 0x73, 0x5a, 0x72, 0x6d,
+  0x38, 0x77, 0x6c, 0x44, 0x44, 0x71, 0x6e, 0x33, 0x50, 0x4f, 0x6b, 0x67,
+  0x75, 0x72, 0x32, 0x78, 0x50, 0x41, 0x4f, 0x4a, 0x48, 0x69, 0x72, 0x2f,
+  0x62, 0x67, 0x6a, 0x2f, 0x4c, 0x67, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d,
+  0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x45, 0x43, 0x20, 0x50, 0x52, 0x49,
+  0x56, 0x41, 0x54, 0x45, 0x20, 0x4b, 0x45, 0x59, 0x2d, 0x2d, 0x2d, 0x2d,
+  0x2d, 0x0a,
+};
+
+//
+// Payload for PKCS#7 Signing & Verification Validation.
+//
+CONST CHAR8  *mEcPayload = "payload data for PKCS#7 EC Signing";
+
 VOID  *Ec1;
 VOID  *Ec2;
 VOID  *Group;
@@ -279,12 +362,85 @@ TestVerifyEcDh (
   return UNIT_TEST_PASSED;
 }
 
+UNIT_TEST_STATUS
+EFIAPI
+TestVerifyEcKey (
+  UNIT_TEST_CONTEXT  Context
+  )
+{
+  BOOLEAN  Status;
+  VOID     *EcPrivKey;
+  VOID     *EcPubKey;
+  UINT8    HashValue[SHA256_DIGEST_SIZE];
+  UINTN    HashSize;
+  UINT8    Signature[66 * 2];
+  UINTN    SigSize;
+
+  //
+  // Retrieve EC private key from PEM data.
+  //
+  Status = EcGetPrivateKeyFromPem (
+             mEccTestPemKey,
+             sizeof (mEccTestPemKey),
+             NULL,
+             &EcPrivKey
+             );
+  UT_ASSERT_TRUE (Status);
+
+  //
+  // Retrieve EC public key from X509 Certificate.
+  //
+  Status = EcGetPublicKeyFromX509 (
+             mEccTestRootCer,
+             sizeof (mEccTestRootCer),
+             &EcPubKey
+             );
+  UT_ASSERT_TRUE (Status);
+
+  //
+  // Verify EC-DSA
+  //
+  HashSize = sizeof (HashValue);
+  SigSize  = sizeof (Signature);
+  //
+  // EC-DSA Signing ...
+  //
+  Status = EcDsaSign (
+             EcPrivKey,
+             CRYPTO_NID_SHA256,
+             HashValue,
+             HashSize,
+             Signature,
+             &SigSize
+             );
+  UT_ASSERT_TRUE (Status);
+
+  //
+  // EC-DSA Verification ...
+  //
+  Status = EcDsaVerify (
+             EcPubKey,
+             CRYPTO_NID_SHA256,
+             HashValue,
+             HashSize,
+             Signature,
+             SigSize
+             );
+  UT_ASSERT_TRUE (Status);
+
+  EcFree (EcPrivKey);
+  EcFree (EcPubKey);
+
+  return UNIT_TEST_PASSED;
+}
+
 TEST_DESC  mEcTest[] = {
   //
   // -----Description-----------------Class------------------Function----Pre----Post----Context
   //
   { "TestVerifyEcBasic()", "CryptoPkg.BaseCryptLib.Ec", TestVerifyEcBasic, TestVerifyEcPreReq, TestVerifyEcCleanUp, NULL },
   { "TestVerifyEcDh()",    "CryptoPkg.BaseCryptLib.Ec", TestVerifyEcDh,    TestVerifyEcPreReq, TestVerifyEcCleanUp, NULL },
+  { "TestVerifyEcKey()",   "CryptoPkg.BaseCryptLib.Ec", TestVerifyEcKey,   NULL,               NULL,                NULL },
 };
 
 UINTN  mEcTestNum = ARRAY_SIZE (mEcTest);
-- 
2.26.2.windows.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface.
  2022-10-12  2:47 [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Qi Zhang
                   ` (2 preceding siblings ...)
  2022-10-12  2:48 ` [PATCH V2 3/3] CryptoPkg: add unit test for EC key interface Qi Zhang
@ 2022-10-12  5:57 ` Yao, Jiewen
  3 siblings, 0 replies; 5+ messages in thread
From: Yao, Jiewen @ 2022-10-12  5:57 UTC (permalink / raw)
  To: Zhang, Qi1, devel@edk2.groups.io; +Cc: Wang, Jian J, Lu, Xiaoyu1, Jiang, Guomin

Reviewed-by: Jiewen Yao <Jiewen.yao@intel.com>

Merged https://github.com/tianocore/edk2/pull/3469

> -----Original Message-----
> From: Zhang, Qi1 <qi1.zhang@intel.com>
> Sent: Wednesday, October 12, 2022 10:48 AM
> To: devel@edk2.groups.io
> Cc: Zhang, Qi1 <qi1.zhang@intel.com>; Yao, Jiewen
> <jiewen.yao@intel.com>; Wang, Jian J <jian.j.wang@intel.com>; Lu, Xiaoyu1
> <xiaoyu1.lu@intel.com>; Jiang, Guomin <guomin.jiang@intel.com>
> Subject: [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature
> interface.
> 
> This patch is used to retrieve EC key from PEM and X509 and
> carry out the EC-DSA signature and verify it.
> 
> The interface was tested by:
> 1. DeviceSecurity on edk2-staging
> https://github.com/tianocore/edk2-staging/tree/DeviceSecurity.
> 2. Unit test in CryptoPkg/Test
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=4102
> PR: https://github.com/tianocore/edk2/pull/3464
> 
> V2 change: change the protocol version.
> 
> Cc: Jiewen Yao <jiewen.yao@intel.com>
> Cc: Jian J Wang <jian.j.wang@intel.com>
> Cc: Xiaoyu Lu <xiaoyu1.lu@intel.com>
> Cc: Guomin Jiang <guomin.jiang@intel.com>
> Signed-off-by: Qi Zhang <qi1.zhang@intel.com>
> 
> Qi Zhang (3):
>   CryptoPkg: Add EC key retrieving and signature interface.
>   CryptoPkg: Add EC key interface to DXE and protocol
>   CryptoPkg: add unit test for EC key interface.
> 
>  CryptoPkg/Driver/Crypto.c                     | 143 +++++++++-
>  CryptoPkg/Include/Library/BaseCryptLib.h      | 129 +++++++++
>  .../Pcd/PcdCryptoServiceFamilyEnable.h        |   4 +
>  CryptoPkg/Library/BaseCryptLib/Pem/CryptPem.c |  87 ++++++
>  .../Library/BaseCryptLib/Pem/CryptPemNull.c   |  30 ++
>  CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c   | 258
> ++++++++++++++++++
>  .../Library/BaseCryptLib/Pk/CryptEcNull.c     |  82 ++++++
>  CryptoPkg/Library/BaseCryptLib/Pk/CryptX509.c |  83 ++++++
>  .../Library/BaseCryptLib/Pk/CryptX509Null.c   |  28 ++
>  .../BaseCryptLibNull/Pem/CryptPemNull.c       |  30 ++
>  .../Library/BaseCryptLibNull/Pk/CryptEcNull.c |  82 ++++++
>  .../BaseCryptLibNull/Pk/CryptX509Null.c       |  28 ++
>  .../BaseCryptLibOnProtocolPpi/CryptLib.c      | 136 +++++++++
>  CryptoPkg/Private/Protocol/Crypto.h           | 131 ++++++++-
>  .../UnitTest/Library/BaseCryptLib/EcTests.c   | 156 +++++++++++
>  15 files changed, 1405 insertions(+), 2 deletions(-)
> 
> --
> 2.26.2.windows.1


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-10-12  5:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-12  2:47 [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Qi Zhang
2022-10-12  2:47 ` [PATCH V2 1/3] " Qi Zhang
2022-10-12  2:47 ` [PATCH V2 2/3] CryptoPkg: Add EC key interface to DXE and protocol Qi Zhang
2022-10-12  2:48 ` [PATCH V2 3/3] CryptoPkg: add unit test for EC key interface Qi Zhang
2022-10-12  5:57 ` [PATCH V2 0/3] CryptoPkg: Add EC key retrieving and signature interface Yao, Jiewen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox