summaryrefslogtreecommitdiffstats
path: root/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
diff options
context:
space:
mode:
Diffstat (limited to 'CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c')
-rw-r--r--CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c258
1 files changed, 258 insertions, 0 deletions
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);
+}