From: "Qi Zhang" <qi1.zhang@intel.com>
To: devel@edk2.groups.io
Cc: Qi Zhang <qi1.zhang@intel.com>, Jiewen Yao <jiewen.yao@intel.com>,
Jian J Wang <jian.j.wang@intel.com>,
Xiaoyu Lu <xiaoyu1.lu@intel.com>,
Guomin Jiang <guomin.jiang@intel.com>
Subject: [PATCH 1/3] CryptoPkg: Add EC key retrieving and signature interface.
Date: Tue, 11 Oct 2022 14:36:53 +0800 [thread overview]
Message-ID: <eab4871f5975571e4d07e167ac5aa945792c8d56.1665469855.git.qi1.zhang@intel.com> (raw)
In-Reply-To: <cover.1665469855.git.qi1.zhang@intel.com>
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
next prev parent reply other threads:[~2022-10-11 6:37 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-11 6:36 [PATCH 0/3] CryptoPkg: Add EC key retrieving and signature interface Qi Zhang
2022-10-11 6:36 ` Qi Zhang [this message]
2022-10-11 6:36 ` [PATCH 2/3] CryptoPkg: Add EC key interface to DXE and protocol Qi Zhang
2022-10-11 6:36 ` [PATCH 3/3] CryptoPkg: add unit test for EC key interface Qi Zhang
2022-10-12 0:33 ` [PATCH 0/3] CryptoPkg: Add EC key retrieving and signature interface Yao, Jiewen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=eab4871f5975571e4d07e167ac5aa945792c8d56.1665469855.git.qi1.zhang@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox