Re: [PATCH V2 1/3] CryptoPkg: Add EC support


Yao, Jiewen
 

Hi Mike
This has been investigated before, but we don’t have better solution than PcdOpensslEcEnabled.

Given the fact that this PCD is introduced before (not in this patch set), do you think we can merge this first, then do enhancement for PCD related stuff later?

Or if you have any other idea, please let us know.

Thank you
Yao Jiewen

-----Original Message-----
From: Li, Yi1 <yi1.li@...>
Sent: Friday, September 23, 2022 3:09 PM
To: Kinney, Michael D <michael.d.kinney@...>;
devel@edk2.groups.io; Chen, Christine <yuwei.chen@...>; Feng, Bob
C <bob.c.feng@...>
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>; Luo, Heng <heng.luo@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Hi Mike,

I did make some attempts with it, but it doesn't work, two troubles here:

Bob and Yuwei, please point out if I'm wrong:
1. Using member of structure PCD in INF isn’t supported by Basetools
currently,
At least it cannot be used as FeatureFlag Expression.

2. As far as I know, structure PCD actually is a const array in code,
I afraid it will not work fine with precompile but we do have this need:
#if !FixedPcdGetBool (PcdOpensslEcEnabled)
# ifndef OPENSSL_NO_EC
# define OPENSSL_NO_EC
# endif
#endif

This is really caused by the bad structure of openssl,
maybe we use more detailed comments to remind developers to sync the
two PCDs?

Thanks,
Yi

-----Original Message-----
From: Kinney, Michael D <michael.d.kinney@...>
Sent: Friday, September 23, 2022 1:25 PM
To: Li, Yi1 <yi1.li@...>; devel@edk2.groups.io; Chen, Christine
<yuwei.chen@...>; Feng, Bob C <bob.c.feng@...>; Kinney,
Michael D <michael.d.kinney@...>
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Hi Yi,

I agree there are some complex interactions in the opensll sources.

Since you are defining a family for EC, can we use the EC Family != 0 instead
of
PcdOpensslEcEnabled and remove PcdOpensslEcEnabled.

I want to make sure developers do not run into strange build failures if
they do not keep the 2 different PCDs aligned. I prefer a single PCD
setting to enable use of EC services.

I also noticed that the use of a PCD expression in an INF to select source
files does not work if the PCD value is specified with the --pcd flag on
the build command line. This looks like a significant bug with the PCD
expression in an INF file. This also needs to be fixed.

Mike

-----Original Message-----
From: Li, Yi1 <yi1.li@...>
Sent: Thursday, September 22, 2022 8:02 PM
To: Kinney, Michael D <michael.d.kinney@...>;
devel@edk2.groups.io
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Hi Mike,

1. Yes, it matches.
By Intel side, 100+kb(20%+) FV size increase will be a big concern, please
refer to another internal email.

2. Additional size is coming from modules may consumed EC APIs, eg. TLS
PEM X509 ...

If we added EC source to OpensslLib.inf and disabled macro
OPENSSL_NO_EC, those modules will link EC APIs and increase binary
size,
This an example from x509/x_pubkey.c , other modules is similar:
#ifndef OPENSSL_NO_EC
EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long
length)
{
EVP_PKEY *pkey;
EC_KEY *key = NULL;
//.... call EC functions
}
#endif

If we added EC source to OpensslLib.inf and enable macro
OPENSSL_NO_EC, EC module will throw build error,
Since some EC internal APIs or structs have been disabled by
OPENSSL_NO_EC but not another.
This an example from ec/ec_local.h , other error is similar:

#ifndef OPENSSL_NO_EC
typedef struct ec_group_st EC_GROUP;
typedef struct ec_point_st EC_POINT;
#endif

// but this function not been enclosed by OPENSSL_NO_EC, and will
throw build error
int (*point_set_Jprojective_coordinates_GFp) (const EC_GROUP *,
EC_POINT *, const BIGNUM *x,
const BIGNUM *y,
const BIGNUM *z, BN_CTX *);

To avoid this annoying openssl error, we introduced conditional EC.

Thanks,
Yi

-----Original Message-----
From: Kinney, Michael D <michael.d.kinney@...>
Sent: Friday, September 23, 2022 6:47 AM
To: Li, Yi1 <yi1.li@...>; devel@edk2.groups.io; Kinney, Michael D
<michael.d.kinney@...>
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Hi Yi,

I agree EC is an important feature.

I did some analysis of the size impact to the CryptoPkg modules on
current trunk
with EC on and off. Uncompressed size is important for PEI Phase. For
DXE and
SMM phase, the Crypto services can always be compressed. From the
table below,
building all the EC services in the OpensslLib has no size impact to the
NONE
profile and the MIN_PEI profile. It has ~105 KB impact to compressed
DXE/SMM
usages that may use the MIN_DXE_MIN_SMM or ALL profiles.

Uncompressed LZMA Compressed
CPU CRYPTO_SERVICES Module EC=FALSE EC=TRUE EC=FALSE
EC=TRUE Increase
==== =============== ======== ======== ======= ========
======= ========
IA32 NONE CryptoPei 21536 21568 0 KB
IA32 NONE CryptoDxe 21632 21696 0 KB
IA32 NONE CryptoSmm 22976 23072 0 KB
IA32 MIN_PEI CryptoPei 248992 249120 0 KB
IA32 MIN_DXE_MIN_SMM CryptoDxe 636672 829568 288520
401034 113 KB
IA32 MIN_DXE_MIN_SMM CryptoSmm 426048 601472 191517
296022 105 KB
IA32 ALL CryptoPei 423840 598976 189047 293759 104
KB
IA32 ALL CryptoDxe 645280 838144 292955 405277 113
KB
IA32 ALL CryptoSmm 441888 617184 198779 303628 105
KB
X64 NONE CryptoPei 29632 29664 0 KB
X64 NONE CryptoDxe 29792 29792 0 KB
X64 NONE CryptoSmm 31296 31296 0 KB
X64 MIN_PEI CryptoPei 310784 310848 0 KB
X64 MIN_DXE_MIN_SMM CryptoDxe 804288 1016256 311436
426596 115 KB
X64 MIN_DXE_MIN_SMM CryptoSmm 543776 733920 204483
310775 106 KB
X64 ALL CryptoPei 540384 730240 202494 308467 106
KB
X64 ALL CryptoDxe 815392 1027296 316228 431321 115
KB
X64 ALL CryptoSmm 563648 753696 213488 319644 106
KB

NOTE: Even if multiple modules in an FV use static linking of Crypto libs, if
the
entire FV is compressed, the total size impact is typically the size of a
single instance of a compressed CryptoLib. The sizes of the Crypto*
modules
in the table above should be a close approximation of the size impact
to a
single FV.

Does this match your previous size analysis?

The critical issue to evaluate here is why adding the EC sources to
OpensllLib.inf
causes the modules that do not use any EC services to grow by ~105KB.
Has any
detailed analysis of the final linked images been performed to see where
this
additional size is coming from?

Thanks,

Mike

-----Original Message-----
From: Li, Yi1 <yi1.li@...>
Sent: Thursday, September 22, 2022 5:54 AM
To: Kinney, Michael D <michael.d.kinney@...>;
devel@edk2.groups.io; Kishore, Shelly <shelly.kishore@...>
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Hi Mike,
I have did some POC that seems existed structured PCD is hard to
control binary size,
Here is the previous discussion for reference.
https://bugzilla.tianocore.org/show_bug.cgi?id=3679
https://edk2.groups.io/g/devel/topic/86257810#81814
https://bugzilla.tianocore.org/show_bug.cgi?id=1446

Anyway EC is an important feature which consumed by vary modern
security features such WPA3 , SPDM, TLS1.3 etc.
Hope it can be added to edk2, and I am glad to take the code and test
work if there are other ways to control the size.

Thanks,
Yi

-----Original Message-----
From: Kinney, Michael D <michael.d.kinney@...>
Sent: Thursday, September 22, 2022 11:56 AM
To: Li, Yi1 <yi1.li@...>; devel@edk2.groups.io; Kishore, Shelly
<shelly.kishore@...>
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

That change to OpensslLib.inf should not have been done either.

Looks like this EC feature needs more evaluation to fit into the
structured PCD control of the lib sizes.

Mike

-----Original Message-----
From: Li, Yi1 <yi1.li@...>
Sent: Wednesday, September 21, 2022 7:16 PM
To: Kinney, Michael D <michael.d.kinney@...>;
devel@edk2.groups.io
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Hi Mike,
Thanks for review.

Even PCD_CRYPTO_SERVICE_FAMILY_ENABLE is set to 0, CryptoEc.c
will also be compiled and throw build error:

d:\workspace\tianocore\edk2\CryptoPkg\Library\BaseCryptLib\Pk\CryptEc.
c(77): error C2220: the following warning is treated
as
an error
1 file(s) copied.
d:\workspace\tianocore\edk2\CryptoPkg\Library\BaseCryptLib\Pk\CryptEc.
c(77): warning C4013: 'EC_GROUP_new_by_curve_name'
undefined; assuming extern returning int
d:\workspace\tianocore\edk2\CryptoPkg\Library\BaseCryptLib\Pk\CryptEc.
c(77): warning C4047: 'return': 'void *' differs in
levels of indirection from 'int'
d:\workspace\tianocore\edk2\CryptoPkg\Library\BaseCryptLib\Pk\CryptEc.
c(105): warning C4013: 'EC_GROUP_get_curve'
undefined;
assuming extern returning int

I think the root cause is that we have enabled conditional ec in
OpensslLib.inf before by PcdOpensslEcEnabled,
https://github.com/tianocore/edk2/blob/2c17d676e402d75a3a67449934
2f7ddaccf387bd/CryptoPkg/Library/OpensslLib/OpensslLib.inf#L2
02-L238
if PcdOpensslEcEnabled not true, all ec files will not be compiled.
This will save 200+kb memory on platforms which use dxe driver but
do not need ec feature.

So I add this PCD to BaseCryptLib.inf also to avoid build error, Not
sure if there is any other way, other better ideas
are
welcome.

Thanks,
Yi

-----Original Message-----
From: Kinney, Michael D <michael.d.kinney@...>
Sent: Thursday, September 22, 2022 12:22 AM
To: devel@edk2.groups.io; Li, Yi1 <yi1.li@...>; Kinney, Michael
D <michael.d.kinney@...>
Cc: Yao, Jiewen <jiewen.yao@...>; Wang, Jian J
<jian.j.wang@...>; Lu, Xiaoyu1 <xiaoyu1.lu@...>; Jiang,
Guomin <guomin.jiang@...>
Subject: RE: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

Comments embedded below.

Mike

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of
yi1 li
Sent: Tuesday, September 20, 2022 9:55 PM
To: devel@edk2.groups.io
Cc: Li, Yi1 <yi1.li@...>; Yao, Jiewen <jiewen.yao@...>;
Wang, Jian J <jian.j.wang@...>; Lu, Xiaoyu1
<xiaoyu1.lu@...>; Jiang, Guomin <guomin.jiang@...>
Subject: [edk2-devel] [PATCH V2 1/3] CryptoPkg: Add EC support

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

This patch is used to add CryptEc library, which is wrapped
over OpenSSL.

Cc: Jiewen Yao <jiewen.yao@...>
Cc: Jian J Wang <jian.j.wang@...>
Cc: Xiaoyu Lu <xiaoyu1.lu@...>
Cc: Guomin Jiang <guomin.jiang@...>

Signed-off-by: Yi Li <yi1.li@...>
---
CryptoPkg/Include/Library/BaseCryptLib.h | 424 ++++++++++
.../Library/BaseCryptLib/BaseCryptLib.inf | 2 +
.../Library/BaseCryptLib/PeiCryptLib.inf | 1 +
CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c | 765
++++++++++++++++++
.../Library/BaseCryptLib/Pk/CryptEcNull.c | 496 ++++++++++++
.../Library/BaseCryptLib/SmmCryptLib.inf | 1 +
.../BaseCryptLibNull/BaseCryptLibNull.inf | 1 +
.../Library/BaseCryptLibNull/Pk/CryptEcNull.c | 496 ++++++++++++
8 files changed, 2186 insertions(+)
create mode 100644 CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
create mode 100644
CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
create mode 100644
CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c

diff --git a/CryptoPkg/Include/Library/BaseCryptLib.h
b/CryptoPkg/Include/Library/BaseCryptLib.h
index b253923dd8..d74fc21c1e 100644
--- a/CryptoPkg/Include/Library/BaseCryptLib.h
+++ b/CryptoPkg/Include/Library/BaseCryptLib.h
@@ -14,6 +14,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent

#include <Uefi/UefiBaseType.h>

+#define CRYPTO_NID_NULL 0x0000
+
+// Key Exchange
+#define CRYPTO_NID_SECP256R1 0x0204
+#define CRYPTO_NID_SECP384R1 0x0205
+#define CRYPTO_NID_SECP521R1 0x0206
+
///
/// MD5 digest size in bytes
///
@@ -2850,4 +2857,421 @@ BigNumAddMod (
OUT VOID *BnRes
);

+//
==========================================================
===========================
+// Basic Elliptic Curve Primitives
+//
==========================================================
===========================
+
+/**
+ Initialize new opaque EcGroup object. This object represents an EC
curve and
+ and is used for calculation within this group. This object should be
freed
+ using EcGroupFree() function.
+
+ @param[in] CryptoNid Identifying number for the ECC curve
(Defined in
+ BaseCryptLib.h).
+
+ @retval EcGroup object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcGroupInit (
+ IN UINTN CryptoNid
+ );
+
+/**
+ Get EC curve parameters. While elliptic curve equation is Y^2 mod
P = (X^3 + AX + B) Mod P.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnPrime Group prime number.
+ @param[out] BnA A coefficient.
+ @param[out] BnB B coefficient.
+ @param[in] BnCtx BN context.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetCurve (
+ IN CONST VOID *EcGroup,
+ OUT VOID *BnPrime,
+ OUT VOID *BnA,
+ OUT VOID *BnB,
+ IN VOID *BnCtx
+ );
+
+/**
+ Get EC group order.
+ This function will set the provided Big Number object to the
corresponding
+ value. The caller needs to make sure that the "out" BigNumber
parameter
+ is properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnOrder Group prime number.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetOrder (
+ IN VOID *EcGroup,
+ OUT VOID *BnOrder
+ );
+
+/**
+ Free previously allocated EC group object using EcGroupInit().
+
+ @param[in] EcGroup EC group object to free.
+**/
+VOID
+EFIAPI
+EcGroupFree (
+ IN VOID *EcGroup
+ );
+
+/**
+ Initialize new opaque EC Point object. This object represents an EC
point
+ within the given EC group (curve).
+
+ @param[in] EC Group, properly initialized using EcGroupInit().
+
+ @retval EC Point object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcPointInit (
+ IN CONST VOID *EcGroup
+ );
+
+/**
+ Free previously allocated EC Point object using EcPointInit().
+
+ @param[in] EcPoint EC Point to free.
+ @param[in] Clear TRUE iff the memory should be cleared.
+**/
+VOID
+EFIAPI
+EcPointDeInit (
+ IN VOID *EcPoint,
+ IN BOOLEAN Clear
+ );
+
+/**
+ Get EC point affine (x,y) coordinates.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[out] BnX X coordinate.
+ @param[out] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointGetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ OUT VOID *BnX,
+ OUT VOID *BnY,
+ IN VOID *BnCtx
+ );
+
+/**
+ Set EC point affine (x,y) coordinates.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[in] BnX X coordinate.
+ @param[in] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN CONST VOID *BnY,
+ IN VOID *BnCtx
+ );
+
+/**
+ EC Point addition. EcPointResult = EcPointA + EcPointB.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPointA EC Point.
+ @param[in] EcPointB EC Point.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointAdd (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ );
+
+/**
+ Variable EC point multiplication. EcPointResult = EcPoint *
BnPScalar.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPoint EC Point.
+ @param[in] BnPScalar P Scalar.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointMul (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPoint,
+ IN CONST VOID *BnPScalar,
+ IN VOID *BnCtx
+ );
+
+/**
+ Calculate the inverse of the supplied EC point.
+
+ @param[in] EcGroup EC group object.
+ @param[in,out] EcPoint EC point to invert.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointInvert (
+ IN CONST VOID *EcGroup,
+ IN OUT VOID *EcPoint,
+ IN VOID *BnCtx
+ );
+
+/**
+ Check if the supplied point is on EC curve.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On curve.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsOnCurve (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ IN VOID *BnCtx
+ );
+
+/**
+ Check if the supplied point is at infinity.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+
+ @retval TRUE At infinity.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsAtInfinity (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint
+ );
+
+/**
+ Check if EC points are equal.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPointA EC point A.
+ @param[in] EcPointB EC point B.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE A == B.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointEqual (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ );
+
+/**
+ Set EC point compressed coordinates. Points can be described in
terms of
+ their compressed coordinates. For a point (x, y), for any given
value for x
+ such that the point is on the curve there will only ever be two
possible
+ values for y. Therefore, a point can be set using this function
where BnX is
+ the x coordinate and YBit is a value 0 or 1 to identify which of the
two
+ possible values for y should be used.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC Point.
+ @param[in] BnX X coordinate.
+ @param[in] YBit 0 or 1 to identify which Y value is used.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetCompressedCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN UINT8 YBit,
+ IN VOID *BnCtx
+ );
+
+//
==========================================================
===========================
+// Elliptic Curve Diffie Hellman Primitives
+//
==========================================================
===========================
+
+/**
+ Allocates and Initializes one Elliptic Curve Context for subsequent
use
+ with the NID.
+
+ @param[in] Nid cipher NID
+ @return Pointer to the Elliptic Curve Context that has been
initialized.
+ If the allocations fails, EcNewByNid() returns NULL.
+**/
+VOID *
+EFIAPI
+EcNewByNid (
+ IN UINTN Nid
+ );
+
+/**
+ Release the specified EC context.
+
+ @param[in] EcContext Pointer to the EC context to be released.
+**/
+VOID
+EFIAPI
+EcFree (
+ IN VOID *EcContext
+ );
+
+/**
+ Generates EC key and returns EC public key (X, Y), Please note,
this function uses
+ pseudo random number generator. The caller must make sure
RandomSeed()
+ function was properly called before.
+ The Ec context should be correctly initialized by EcNewByNid.
+ This function generates random secret, and computes the public
key (X, Y), which is
+ returned via parameter Public, PublicSize.
+ X is the first half of Public with size being PublicSize / 2,
+ Y is the second half of Public with size being PublicSize / 2.
+ EC context is updated accordingly.
+ If the Public buffer is too small to hold the public X, Y, FALSE is
returned and
+ PublicSize is set to the required buffer size to obtain the public X,
Y.
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ If EcContext is NULL, then return FALSE.
+ If PublicSize is NULL, then return FALSE.
+ If PublicSize is large enough but Public is NULL, then return FALSE.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC public X,Y generation succeeded.
+ @retval FALSE EC public X,Y generation failed.
+ @retval FALSE PublicKeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcGenerateKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ );
+
+/**
+ Gets the public key component from the established EC context.
+ The Ec context should be correctly initialized by EcNewByNid, and
successfully
+ generate key pair from EcGenerateKey().
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ @param[in, out] EcContext Pointer to EC context being set.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC key component was retrieved successfully.
+ @retval FALSE Invalid EC key component.
+**/
+BOOLEAN
+EFIAPI
+EcGetPubKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ );
+
+/**
+ Computes exchanged common key.
+ Given peer's public key (X, Y), this function computes the
exchanged common key,
+ based on its own context including value of curve parameter and
random secret.
+ X is the first half of PeerPublic with size being PeerPublicSize / 2,
+ Y is the second half of PeerPublic with size being PeerPublicSize /
2.
+ If EcContext is NULL, then return FALSE.
+ If PeerPublic is NULL, then return FALSE.
+ If PeerPublicSize is 0, then return FALSE.
+ If Key is NULL, then return FALSE.
+ If KeySize is not large enough, then return FALSE.
+ For P-256, the PeerPublicSize is 64. First 32-byte is X, Second 32-
byte is Y.
+ For P-384, the PeerPublicSize is 96. First 48-byte is X, Second 48-
byte is Y.
+ For P-521, the PeerPublicSize is 132. First 66-byte is X, Second 66-
byte is Y.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[in] PeerPublic Pointer to the peer's public X,Y.
+ @param[in] PeerPublicSize Size of peer's public X,Y in bytes.
+ @param[in] CompressFlag Flag of PeerPublic is
compressed or not.
+ @param[out] Key Pointer to the buffer to receive
generated key.
+ @param[in, out] KeySize On input, the size of Key buffer in
bytes.
+ On output, the size of data returned in Key
buffer in bytes.
+ @retval TRUE EC exchanged key generation succeeded.
+ @retval FALSE EC exchanged key generation failed.
+ @retval FALSE KeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcDhComputeKey (
+ IN OUT VOID *EcContext,
+ IN CONST UINT8 *PeerPublic,
+ IN UINTN PeerPublicSize,
+ IN CONST INT32 *CompressFlag,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ );
+
#endif // __BASE_CRYPT_LIB_H__
diff --git a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
index 9e4be2fb0d..ade6ee3fdd 100644
--- a/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
+++ b/CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
@@ -52,6 +52,8 @@
Pk/CryptTs.c
Pk/CryptRsaPss.c
Pk/CryptRsaPssSign.c
+ Pk/CryptEcNull.c
|*|*|*|!gEfiCryptoPkgTokenSpaceGuid.PcdOpensslEcEnabled
+ Pk/CryptEc.c
|*|*|*|gEfiCryptoPkgTokenSpaceGuid.PcdOpensslEcEnabled

The use of the PCD to select the file should not be needed here. The
Ec Family and individual service enable/disable fields in the
PCD_CRYPTO_SERVICE_FAMILY_ENABLE structured PCD are all that is
needed to
disable the Ec services.

The PCD gEfiCryptoPkgTokenSpaceGuid.PcdOpensslEcEnabled should
be removed
completely as part of this patch series.

Pem/CryptPem.c
Bn/CryptBn.c

diff --git a/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
b/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
index 65ad23fb81..383df2b23c 100644
--- a/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
+++ b/CryptoPkg/Library/BaseCryptLib/PeiCryptLib.inf
@@ -58,6 +58,7 @@
Pk/CryptTsNull.c
Pk/CryptRsaPss.c
Pk/CryptRsaPssSignNull.c
+ Pk/CryptEcNull.c
Pem/CryptPemNull.c
Rand/CryptRandNull.c
Bn/CryptBnNull.c
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
new file mode 100644
index 0000000000..396c819834
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEc.c
@@ -0,0 +1,765 @@
+/** @file
+ Elliptic Curve and ECDH API implementation based on OpenSSL
+
+ Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCryptLib.h"
+#include <openssl/objects.h>
+#include <openssl/bn.h>
+#include <openssl/ec.h>
+
+//
==========================================================
===========================
+// Basic Elliptic Curve Primitives
+//
==========================================================
===========================
+
+/**
+ Return the Nid of certain ECC curve.
+
+ @param[in] CryptoNid Identifying number for the ECC curve
(Defined in
+ BaseCryptLib.h).
+
+ @retval !=-1 On success.
+ @retval -1 ECC curve not supported.
+**/
+STATIC
+INT32
+CryptoNidToOpensslNid (
+ IN UINTN CryptoNid
+ )
+{
+ INT32 Nid;
+
+ switch (CryptoNid) {
+ case CRYPTO_NID_SECP256R1:
+ Nid = NID_X9_62_prime256v1;
+ break;
+ case CRYPTO_NID_SECP384R1:
+ Nid = NID_secp384r1;
+ break;
+ case CRYPTO_NID_SECP521R1:
+ Nid = NID_secp521r1;
+ break;
+ default:
+ return -1;
+ }
+
+ return Nid;
+}
+
+/**
+ Initialize new opaque EcGroup object. This object represents an EC
curve and
+ and is used for calculation within this group. This object should be
freed
+ using EcGroupFree() function.
+
+ @param[in] CryptoNid Identifying number for the ECC curve
(Defined in
+ BaseCryptLib.h).
+
+ @retval EcGroup object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcGroupInit (
+ IN UINTN CryptoNid
+ )
+{
+ INT32 Nid;
+
+ Nid = CryptoNidToOpensslNid (CryptoNid);
+
+ if (Nid < 0) {
+ return NULL;
+ }
+
+ return EC_GROUP_new_by_curve_name (Nid);
+}
+
+/**
+ Get EC curve parameters. While elliptic curve equation is Y^2 mod
P = (X^3 + AX + B) Mod P.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnPrime Group prime number.
+ @param[out] BnA A coefficient.
+ @param[out] BnB B coefficient..
+ @param[in] BnCtx BN context.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetCurve (
+ IN CONST VOID *EcGroup,
+ OUT VOID *BnPrime,
+ OUT VOID *BnA,
+ OUT VOID *BnB,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_GROUP_get_curve (EcGroup, BnPrime, BnA,
BnB, BnCtx);
+}
+
+/**
+ Get EC group order.
+ This function will set the provided Big Number object to the
corresponding
+ value. The caller needs to make sure that the "out" BigNumber
parameter
+ is properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnOrder Group prime number.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetOrder (
+ IN VOID *EcGroup,
+ OUT VOID *BnOrder
+ )
+{
+ return (BOOLEAN)EC_GROUP_get_order (EcGroup, BnOrder,
NULL);
+}
+
+/**
+ Free previously allocated EC group object using EcGroupInit().
+
+ @param[in] EcGroup EC group object to free.
+**/
+VOID
+EFIAPI
+EcGroupFree (
+ IN VOID *EcGroup
+ )
+{
+ EC_GROUP_free (EcGroup);
+}
+
+/**
+ Initialize new opaque EC Point object. This object represents an EC
point
+ within the given EC group (curve).
+
+ @param[in] EC Group, properly initialized using EcGroupInit().
+
+ @retval EC Point object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcPointInit (
+ IN CONST VOID *EcGroup
+ )
+{
+ return EC_POINT_new (EcGroup);
+}
+
+/**
+ Free previously allocated EC Point object using EcPointInit().
+
+ @param[in] EcPoint EC Point to free.
+ @param[in] Clear TRUE iff the memory should be cleared.
+**/
+VOID
+EFIAPI
+EcPointDeInit (
+ IN VOID *EcPoint,
+ IN BOOLEAN Clear
+ )
+{
+ if (Clear) {
+ EC_POINT_clear_free (EcPoint);
+ } else {
+ EC_POINT_free (EcPoint);
+ }
+}
+
+/**
+ Get EC point affine (x,y) coordinates.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[out] BnX X coordinate.
+ @param[out] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointGetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ OUT VOID *BnX,
+ OUT VOID *BnY,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_POINT_get_affine_coordinates (EcGroup,
EcPoint, BnX, BnY, BnCtx);
+}
+
+/**
+ Set EC point affine (x,y) coordinates.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[in] BnX X coordinate.
+ @param[in] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN CONST VOID *BnY,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_POINT_set_affine_coordinates (EcGroup,
EcPoint, BnX, BnY, BnCtx);
+}
+
+/**
+ EC Point addition. EcPointResult = EcPointA + EcPointB.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPointA EC Point.
+ @param[in] EcPointB EC Point.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointAdd (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_POINT_add (EcGroup, EcPointResult,
EcPointA, EcPointB, BnCtx);
+}
+
+/**
+ Variable EC point multiplication. EcPointResult = EcPoint *
BnPScalar.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPoint EC Point.
+ @param[in] BnPScalar P Scalar.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointMul (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPoint,
+ IN CONST VOID *BnPScalar,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_POINT_mul (EcGroup, EcPointResult, NULL,
EcPoint, BnPScalar, BnCtx);
+}
+
+/**
+ Calculate the inverse of the supplied EC point.
+
+ @param[in] EcGroup EC group object.
+ @param[in,out] EcPoint EC point to invert.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointInvert (
+ IN CONST VOID *EcGroup,
+ IN OUT VOID *EcPoint,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_POINT_invert (EcGroup, EcPoint, BnCtx);
+}
+
+/**
+ Check if the supplied point is on EC curve.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On curve.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsOnCurve (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ IN VOID *BnCtx
+ )
+{
+ return EC_POINT_is_on_curve (EcGroup, EcPoint, BnCtx) == 1;
+}
+
+/**
+ Check if the supplied point is at infinity.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+
+ @retval TRUE At infinity.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsAtInfinity (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint
+ )
+{
+ return EC_POINT_is_at_infinity (EcGroup, EcPoint) == 1;
+}
+
+/**
+ Check if EC points are equal.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPointA EC point A.
+ @param[in] EcPointB EC point B.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE A == B.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointEqual (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ )
+{
+ return EC_POINT_cmp (EcGroup, EcPointA, EcPointB, BnCtx) == 0;
+}
+
+/**
+ Set EC point compressed coordinates. Points can be described in
terms of
+ their compressed coordinates. For a point (x, y), for any given
value for x
+ such that the point is on the curve there will only ever be two
possible
+ values for y. Therefore, a point can be set using this function
where BnX is
+ the x coordinate and YBit is a value 0 or 1 to identify which of the
two
+ possible values for y should be used.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC Point.
+ @param[in] BnX X coordinate.
+ @param[in] YBit 0 or 1 to identify which Y value is used.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetCompressedCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN UINT8 YBit,
+ IN VOID *BnCtx
+ )
+{
+ return (BOOLEAN)EC_POINT_set_compressed_coordinates
(EcGroup, EcPoint, BnX, YBit, BnCtx);
+}
+
+//
==========================================================
===========================
+// Elliptic Curve Diffie Hellman Primitives
+//
==========================================================
===========================
+
+/**
+ Allocates and Initializes one Elliptic Curve Context for subsequent
use
+ with the NID.
+
+ @param[in] Nid Identifying number for the ECC curve (Defined
in
+ BaseCryptLib.h).
+ @return Pointer to the Elliptic Curve Context that has been
initialized.
+ If the allocations fails, EcNewByNid() returns NULL.
+**/
+VOID *
+EFIAPI
+EcNewByNid (
+ IN UINTN Nid
+ )
+{
+ INT32 OpenSslNid;
+
+ OpenSslNid = CryptoNidToOpensslNid (Nid);
+ if (OpenSslNid < 0) {
+ return NULL;
+ }
+
+ return (VOID *)EC_KEY_new_by_curve_name (OpenSslNid);
+}
+
+/**
+ Release the specified EC context.
+
+ @param[in] EcContext Pointer to the EC context to be released.
+**/
+VOID
+EFIAPI
+EcFree (
+ IN VOID *EcContext
+ )
+{
+ EC_KEY_free ((EC_KEY *)EcContext);
+}
+
+/**
+ Generates EC key and returns EC public key (X, Y), Please note,
this function uses
+ pseudo random number generator. The caller must make sure
RandomSeed()
+ function was properly called before.
+ The Ec context should be correctly initialized by EcNewByNid.
+ This function generates random secret, and computes the public
key (X, Y), which is
+ returned via parameter Public, PublicSize.
+ X is the first half of Public with size being PublicSize / 2,
+ Y is the second half of Public with size being PublicSize / 2.
+ EC context is updated accordingly.
+ If the Public buffer is too small to hold the public X, Y, FALSE is
returned and
+ PublicSize is set to the required buffer size to obtain the public X,
Y.
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ If EcContext is NULL, then return FALSE.
+ If PublicSize is NULL, then return FALSE.
+ If PublicSize is large enough but Public is NULL, then return FALSE.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC public X,Y generation succeeded.
+ @retval FALSE EC public X,Y generation failed.
+ @retval FALSE PublicKeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcGenerateKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ EC_KEY *EcKey;
+ CONST EC_GROUP *Group;
+ CONST EC_POINT *EcPoint;
+ BOOLEAN RetVal;
+ BIGNUM *BnX;
+ BIGNUM *BnY;
+ UINTN HalfSize;
+ INTN XSize;
+ INTN YSize;
+
+ if ((EcContext == NULL) || (PublicKeySize == NULL)) {
+ return FALSE;
+ }
+
+ if ((PublicKey == NULL) && (*PublicKeySize != 0)) {
+ return FALSE;
+ }
+
+ EcKey = (EC_KEY *)EcContext;
+ Group = EC_KEY_get0_group (EcKey);
+ HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;
+
+ // Assume RAND_seed was called
+ if (EC_KEY_generate_key (EcKey) != 1) {
+ return FALSE;
+ }
+
+ if (*PublicKeySize < HalfSize * 2) {
+ *PublicKeySize = HalfSize * 2;
+ return FALSE;
+ }
+
+ *PublicKeySize = HalfSize * 2;
+
+ EcPoint = EC_KEY_get0_public_key (EcKey);
+ if (EcPoint == NULL) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
+ BnX = BN_new ();
+ BnY = BN_new ();
+ if ((BnX == NULL) || (BnY == NULL)) {
+ goto fail;
+ }
+
+ if (EC_POINT_get_affine_coordinates (Group, EcPoint, BnX, BnY,
NULL) != 1) {
+ goto fail;
+ }
+
+ XSize = BN_num_bytes (BnX);
+ YSize = BN_num_bytes (BnY);
+ if ((XSize <= 0) || (YSize <= 0)) {
+ goto fail;
+ }
+
+ ASSERT ((UINTN)XSize <= HalfSize && (UINTN)YSize <= HalfSize);
+
+ ZeroMem (PublicKey, *PublicKeySize);
+ BN_bn2bin (BnX, &PublicKey[0 + HalfSize - XSize]);
+ BN_bn2bin (BnY, &PublicKey[HalfSize + HalfSize - YSize]);
+
+ RetVal = TRUE;
+
+fail:
+ BN_free (BnX);
+ BN_free (BnY);
+ return RetVal;
+}
+
+/**
+ Gets the public key component from the established EC context.
+ The Ec context should be correctly initialized by EcNewByNid, and
successfully
+ generate key pair from EcGenerateKey().
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ @param[in, out] EcContext Pointer to EC context being set.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC key component was retrieved successfully.
+ @retval FALSE Invalid EC key component.
+**/
+BOOLEAN
+EFIAPI
+EcGetPubKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ EC_KEY *EcKey;
+ CONST EC_GROUP *Group;
+ CONST EC_POINT *EcPoint;
+ BIGNUM *BnX;
+ BIGNUM *BnY;
+ UINTN HalfSize;
+ INTN XSize;
+ INTN YSize;
+ BOOLEAN RetVal;
+
+ if ((EcContext == NULL) || (PublicKeySize == NULL)) {
+ return FALSE;
+ }
+
+ if ((PublicKey == NULL) && (*PublicKeySize != 0)) {
+ return FALSE;
+ }
+
+ EcKey = (EC_KEY *)EcContext;
+ Group = EC_KEY_get0_group (EcKey);
+ HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;
+ if (*PublicKeySize < HalfSize * 2) {
+ *PublicKeySize = HalfSize * 2;
+ return FALSE;
+ }
+
+ *PublicKeySize = HalfSize * 2;
+
+ EcPoint = EC_KEY_get0_public_key (EcKey);
+ if (EcPoint == NULL) {
+ return FALSE;
+ }
+
+ RetVal = FALSE;
+ BnX = BN_new ();
+ BnY = BN_new ();
+ if ((BnX == NULL) || (BnY == NULL)) {
+ goto fail;
+ }
+
+ if (EC_POINT_get_affine_coordinates (Group, EcPoint, BnX, BnY,
NULL) != 1) {
+ goto fail;
+ }
+
+ XSize = BN_num_bytes (BnX);
+ YSize = BN_num_bytes (BnY);
+ if ((XSize <= 0) || (YSize <= 0)) {
+ goto fail;
+ }
+
+ ASSERT ((UINTN)XSize <= HalfSize && (UINTN)YSize <= HalfSize);
+
+ if (PublicKey != NULL) {
+ ZeroMem (PublicKey, *PublicKeySize);
+ BN_bn2bin (BnX, &PublicKey[0 + HalfSize - XSize]);
+ BN_bn2bin (BnY, &PublicKey[HalfSize + HalfSize - YSize]);
+ }
+
+ RetVal = TRUE;
+
+fail:
+ BN_free (BnX);
+ BN_free (BnY);
+ return RetVal;
+}
+
+/**
+ Computes exchanged common key.
+ Given peer's public key (X, Y), this function computes the
exchanged common key,
+ based on its own context including value of curve parameter and
random secret.
+ X is the first half of PeerPublic with size being PeerPublicSize / 2,
+ Y is the second half of PeerPublic with size being PeerPublicSize /
2.
+ If public key is compressed, the PeerPublic will only contain half
key (X).
+ If EcContext is NULL, then return FALSE.
+ If PeerPublic is NULL, then return FALSE.
+ If PeerPublicSize is 0, then return FALSE.
+ If Key is NULL, then return FALSE.
+ If KeySize is not large enough, then return FALSE.
+ For P-256, the PeerPublicSize is 64. First 32-byte is X, Second 32-
byte is Y.
+ For P-384, the PeerPublicSize is 96. First 48-byte is X, Second 48-
byte is Y.
+ For P-521, the PeerPublicSize is 132. First 66-byte is X, Second 66-
byte is Y.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[in] PeerPublic Pointer to the peer's public X,Y.
+ @param[in] PeerPublicSize Size of peer's public X,Y in bytes.
+ @param[in] CompressFlag Flag of PeerPublic is
compressed or not.
+ @param[out] Key Pointer to the buffer to receive
generated key.
+ @param[in, out] KeySize On input, the size of Key buffer in
bytes.
+ On output, the size of data returned in Key
buffer in bytes.
+ @retval TRUE EC exchanged key generation succeeded.
+ @retval FALSE EC exchanged key generation failed.
+ @retval FALSE KeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcDhComputeKey (
+ IN OUT VOID *EcContext,
+ IN CONST UINT8 *PeerPublic,
+ IN UINTN PeerPublicSize,
+ IN CONST INT32 *CompressFlag,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ )
+{
+ EC_KEY *EcKey;
+ EC_KEY *PeerEcKey;
+ CONST EC_GROUP *Group;
+ BOOLEAN RetVal;
+ BIGNUM *BnX;
+ BIGNUM *BnY;
+ EC_POINT *Point;
+ INT32 OpenSslNid;
+ UINTN HalfSize;
+
+ if ((EcContext == NULL) || (PeerPublic == NULL) || (KeySize ==
NULL)) {
+ return FALSE;
+ }
+
+ if ((Key == NULL) && (*KeySize != 0)) {
+ return FALSE;
+ }
+
+ if (PeerPublicSize > INT_MAX) {
+ return FALSE;
+ }
+
+ EcKey = (EC_KEY *)EcContext;
+ Group = EC_KEY_get0_group (EcKey);
+ HalfSize = (EC_GROUP_get_degree (Group) + 7) / 8;
+ if ((CompressFlag == NULL) && (PeerPublicSize != HalfSize * 2)) {
+ return FALSE;
+ }
+
+ if ((CompressFlag != NULL) && (PeerPublicSize != HalfSize)) {
+ return FALSE;
+ }
+
+ if (*KeySize < HalfSize) {
+ *KeySize = HalfSize;
+ return FALSE;
+ }
+
+ *KeySize = HalfSize;
+
+ RetVal = FALSE;
+ Point = NULL;
+ BnX = BN_bin2bn (PeerPublic, (INT32)HalfSize, NULL);
+ BnY = NULL;
+ Point = EC_POINT_new (Group);
+ PeerEcKey = NULL;
+ if ((BnX == NULL) || (Point == NULL)) {
+ goto fail;
+ }
+
+ if (CompressFlag == NULL) {
+ BnY = BN_bin2bn (PeerPublic + HalfSize, (INT32)HalfSize, NULL);
+ if (BnY == NULL) {
+ goto fail;
+ }
+
+ if (EC_POINT_set_affine_coordinates (Group, Point, BnX, BnY,
NULL) != 1) {
+ goto fail;
+ }
+ } else {
+ if (EC_POINT_set_compressed_coordinates (Group, Point, BnX,
*CompressFlag, NULL) != 1) {
+ goto fail;
+ }
+ }
+
+ // Validate NIST ECDH public key
+ OpenSslNid = EC_GROUP_get_curve_name (Group);
+ PeerEcKey = EC_KEY_new_by_curve_name (OpenSslNid);
+ if (PeerEcKey == NULL) {
+ goto fail;
+ }
+
+ if (EC_KEY_set_public_key (PeerEcKey, Point) != 1) {
+ goto fail;
+ }
+
+ if (EC_KEY_check_key (PeerEcKey) != 1) {
+ goto fail;
+ }
+
+ if (ECDH_compute_key (Key, *KeySize, Point, EcKey, NULL) <= 0) {
+ goto fail;
+ }
+
+ RetVal = TRUE;
+
+fail:
+ BN_free (BnX);
+ BN_free (BnY);
+ EC_POINT_free (Point);
+ EC_KEY_free (PeerEcKey);
+ return RetVal;
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
new file mode 100644
index 0000000000..d9f1004f6c
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLib/Pk/CryptEcNull.c
@@ -0,0 +1,496 @@
+/** @file
+ Elliptic Curve and ECDH API implementation based on OpenSSL
+
+ Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseCryptLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Initialize new opaque EcGroup object. This object represents an EC
curve and
+ and is used for calculation within this group. This object should be
freed
+ using EcGroupFree() function.
+
+ @param[in] CryptoNid Identifying number for the ECC curve
(Defined in
+ BaseCryptLib.h).
+
+ @retval EcGroup object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcGroupInit (
+ IN UINTN CryptoNid
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Get EC curve parameters. While elliptic curve equation is Y^2 mod
P = (X^3 + AX + B) Mod P.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnPrime Group prime number.
+ @param[out] BnA A coefficient.
+ @param[out] BnB B coefficient..
+ @param[in] BnCtx BN context.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetCurve (
+ IN CONST VOID *EcGroup,
+ OUT VOID *BnPrime,
+ OUT VOID *BnA,
+ OUT VOID *BnB,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Get EC group order.
+ This function will set the provided Big Number object to the
corresponding
+ value. The caller needs to make sure that the "out" BigNumber
parameter
+ is properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnOrder Group prime number.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetOrder (
+ IN VOID *EcGroup,
+ OUT VOID *BnOrder
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Free previously allocated EC group object using EcGroupInit().
+
+ @param[in] EcGroup EC group object to free.
+**/
+VOID
+EFIAPI
+EcGroupFree (
+ IN VOID *EcGroup
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Initialize new opaque EC Point object. This object represents an EC
point
+ within the given EC group (curve).
+
+ @param[in] EC Group, properly initialized using EcGroupInit().
+
+ @retval EC Point object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcPointInit (
+ IN CONST VOID *EcGroup
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Free previously allocated EC Point object using EcPointInit().
+
+ @param[in] EcPoint EC Point to free.
+ @param[in] Clear TRUE iff the memory should be cleared.
+**/
+VOID
+EFIAPI
+EcPointDeInit (
+ IN VOID *EcPoint,
+ IN BOOLEAN Clear
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Get EC point affine (x,y) coordinates.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[out] BnX X coordinate.
+ @param[out] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointGetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ OUT VOID *BnX,
+ OUT VOID *BnY,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Set EC point affine (x,y) coordinates.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[in] BnX X coordinate.
+ @param[in] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN CONST VOID *BnY,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ EC Point addition. EcPointResult = EcPointA + EcPointB.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPointA EC Point.
+ @param[in] EcPointB EC Point.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointAdd (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Variable EC point multiplication. EcPointResult = EcPoint *
BnPScalar.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPoint EC Point.
+ @param[in] BnPScalar P Scalar.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointMul (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPoint,
+ IN CONST VOID *BnPScalar,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Calculate the inverse of the supplied EC point.
+
+ @param[in] EcGroup EC group object.
+ @param[in,out] EcPoint EC point to invert.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointInvert (
+ IN CONST VOID *EcGroup,
+ IN OUT VOID *EcPoint,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Check if the supplied point is on EC curve.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On curve.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsOnCurve (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Check if the supplied point is at infinity.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+
+ @retval TRUE At infinity.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsAtInfinity (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Check if EC points are equal.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPointA EC point A.
+ @param[in] EcPointB EC point B.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE A == B.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointEqual (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Set EC point compressed coordinates. Points can be described in
terms of
+ their compressed coordinates. For a point (x, y), for any given
value for x
+ such that the point is on the curve there will only ever be two
possible
+ values for y. Therefore, a point can be set using this function
where BnX is
+ the x coordinate and YBit is a value 0 or 1 to identify which of the
two
+ possible values for y should be used.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC Point.
+ @param[in] BnX X coordinate.
+ @param[in] YBit 0 or 1 to identify which Y value is used.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetCompressedCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN UINT8 YBit,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Allocates and Initializes one Elliptic Curve Context for subsequent
use
+ with the NID.
+
+ @param[in] Nid cipher NID
+ @return Pointer to the Elliptic Curve Context that has been
initialized.
+ If the allocations fails, EcNewByNid() returns NULL.
+**/
+VOID *
+EFIAPI
+EcNewByNid (
+ IN UINTN Nid
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Release the specified EC context.
+
+ @param[in] EcContext Pointer to the EC context to be released.
+**/
+VOID
+EFIAPI
+EcFree (
+ IN VOID *EcContext
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Generates EC key and returns EC public key (X, Y), Please note,
this function uses
+ pseudo random number generator. The caller must make sure
RandomSeed()
+ function was properly called before.
+ The Ec context should be correctly initialized by EcNewByNid.
+ This function generates random secret, and computes the public
key (X, Y), which is
+ returned via parameter Public, PublicSize.
+ X is the first half of Public with size being PublicSize / 2,
+ Y is the second half of Public with size being PublicSize / 2.
+ EC context is updated accordingly.
+ If the Public buffer is too small to hold the public X, Y, FALSE is
returned and
+ PublicSize is set to the required buffer size to obtain the public X,
Y.
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ If EcContext is NULL, then return FALSE.
+ If PublicSize is NULL, then return FALSE.
+ If PublicSize is large enough but Public is NULL, then return FALSE.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC public X,Y generation succeeded.
+ @retval FALSE EC public X,Y generation failed.
+ @retval FALSE PublicKeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcGenerateKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Gets the public key component from the established EC context.
+ The Ec context should be correctly initialized by EcNewByNid, and
successfully
+ generate key pair from EcGenerateKey().
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ @param[in, out] EcContext Pointer to EC context being set.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC key component was retrieved successfully.
+ @retval FALSE Invalid EC key component.
+**/
+BOOLEAN
+EFIAPI
+EcGetPubKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Computes exchanged common key.
+ Given peer's public key (X, Y), this function computes the
exchanged common key,
+ based on its own context including value of curve parameter and
random secret.
+ X is the first half of PeerPublic with size being PeerPublicSize / 2,
+ Y is the second half of PeerPublic with size being PeerPublicSize /
2.
+ If EcContext is NULL, then return FALSE.
+ If PeerPublic is NULL, then return FALSE.
+ If PeerPublicSize is 0, then return FALSE.
+ If Key is NULL, then return FALSE.
+ If KeySize is not large enough, then return FALSE.
+ For P-256, the PeerPublicSize is 64. First 32-byte is X, Second 32-
byte is Y.
+ For P-384, the PeerPublicSize is 96. First 48-byte is X, Second 48-
byte is Y.
+ For P-521, the PeerPublicSize is 132. First 66-byte is X, Second 66-
byte is Y.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[in] PeerPublic Pointer to the peer's public X,Y.
+ @param[in] PeerPublicSize Size of peer's public X,Y in bytes.
+ @param[in] CompressFlag Flag of PeerPublic is
compressed or not.
+ @param[out] Key Pointer to the buffer to receive
generated key.
+ @param[in, out] KeySize On input, the size of Key buffer in
bytes.
+ On output, the size of data returned in Key
buffer in bytes.
+ @retval TRUE EC exchanged key generation succeeded.
+ @retval FALSE EC exchanged key generation failed.
+ @retval FALSE KeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcDhComputeKey (
+ IN OUT VOID *EcContext,
+ IN CONST UINT8 *PeerPublic,
+ IN UINTN PeerPublicSize,
+ IN CONST INT32 *CompressFlag,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
diff --git a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
index ce6a789dfd..4bc3063485 100644
--- a/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
+++ b/CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf
@@ -59,6 +59,7 @@
Pk/CryptTsNull.c
Pk/CryptRsaPss.c
Pk/CryptRsaPssSignNull.c
+ Pk/CryptEcNull.c
Pem/CryptPem.c
Bn/CryptBnNull.c

diff --git a/CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf
b/CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf
index 354f3d80aa..e1a57ef09f 100644
--- a/CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf
+++ b/CryptoPkg/Library/BaseCryptLibNull/BaseCryptLibNull.inf
@@ -49,6 +49,7 @@
Pk/CryptX509Null.c
Pk/CryptAuthenticodeNull.c
Pk/CryptTsNull.c
+ Pk/CryptEcNull.c
Pem/CryptPemNull.c
Rand/CryptRandNull.c
Pk/CryptRsaPssNull.c
diff --git a/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c
b/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c
new file mode 100644
index 0000000000..d9f1004f6c
--- /dev/null
+++ b/CryptoPkg/Library/BaseCryptLibNull/Pk/CryptEcNull.c
@@ -0,0 +1,496 @@
+/** @file
+ Elliptic Curve and ECDH API implementation based on OpenSSL
+
+ Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/BaseCryptLib.h>
+#include <Library/DebugLib.h>
+
+/**
+ Initialize new opaque EcGroup object. This object represents an EC
curve and
+ and is used for calculation within this group. This object should be
freed
+ using EcGroupFree() function.
+
+ @param[in] CryptoNid Identifying number for the ECC curve
(Defined in
+ BaseCryptLib.h).
+
+ @retval EcGroup object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcGroupInit (
+ IN UINTN CryptoNid
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Get EC curve parameters. While elliptic curve equation is Y^2 mod
P = (X^3 + AX + B) Mod P.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnPrime Group prime number.
+ @param[out] BnA A coefficient.
+ @param[out] BnB B coefficient..
+ @param[in] BnCtx BN context.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetCurve (
+ IN CONST VOID *EcGroup,
+ OUT VOID *BnPrime,
+ OUT VOID *BnA,
+ OUT VOID *BnB,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Get EC group order.
+ This function will set the provided Big Number object to the
corresponding
+ value. The caller needs to make sure that the "out" BigNumber
parameter
+ is properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[out] BnOrder Group prime number.
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcGroupGetOrder (
+ IN VOID *EcGroup,
+ OUT VOID *BnOrder
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Free previously allocated EC group object using EcGroupInit().
+
+ @param[in] EcGroup EC group object to free.
+**/
+VOID
+EFIAPI
+EcGroupFree (
+ IN VOID *EcGroup
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Initialize new opaque EC Point object. This object represents an EC
point
+ within the given EC group (curve).
+
+ @param[in] EC Group, properly initialized using EcGroupInit().
+
+ @retval EC Point object On success.
+ @retval NULL On failure.
+**/
+VOID *
+EFIAPI
+EcPointInit (
+ IN CONST VOID *EcGroup
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Free previously allocated EC Point object using EcPointInit().
+
+ @param[in] EcPoint EC Point to free.
+ @param[in] Clear TRUE iff the memory should be cleared.
+**/
+VOID
+EFIAPI
+EcPointDeInit (
+ IN VOID *EcPoint,
+ IN BOOLEAN Clear
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Get EC point affine (x,y) coordinates.
+ This function will set the provided Big Number objects to the
corresponding
+ values. The caller needs to make sure all the "out" BigNumber
parameters
+ are properly initialized.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[out] BnX X coordinate.
+ @param[out] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointGetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ OUT VOID *BnX,
+ OUT VOID *BnY,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Set EC point affine (x,y) coordinates.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point object.
+ @param[in] BnX X coordinate.
+ @param[in] BnY Y coordinate.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetAffineCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN CONST VOID *BnY,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ EC Point addition. EcPointResult = EcPointA + EcPointB.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPointA EC Point.
+ @param[in] EcPointB EC Point.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointAdd (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Variable EC point multiplication. EcPointResult = EcPoint *
BnPScalar.
+
+ @param[in] EcGroup EC group object.
+ @param[out] EcPointResult EC point to hold the result. The
point should
+ be properly initialized.
+ @param[in] EcPoint EC Point.
+ @param[in] BnPScalar P Scalar.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointMul (
+ IN CONST VOID *EcGroup,
+ OUT VOID *EcPointResult,
+ IN CONST VOID *EcPoint,
+ IN CONST VOID *BnPScalar,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Calculate the inverse of the supplied EC point.
+
+ @param[in] EcGroup EC group object.
+ @param[in,out] EcPoint EC point to invert.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointInvert (
+ IN CONST VOID *EcGroup,
+ IN OUT VOID *EcPoint,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Check if the supplied point is on EC curve.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On curve.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsOnCurve (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Check if the supplied point is at infinity.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC point to check.
+
+ @retval TRUE At infinity.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointIsAtInfinity (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPoint
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Check if EC points are equal.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPointA EC point A.
+ @param[in] EcPointB EC point B.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE A == B.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointEqual (
+ IN CONST VOID *EcGroup,
+ IN CONST VOID *EcPointA,
+ IN CONST VOID *EcPointB,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Set EC point compressed coordinates. Points can be described in
terms of
+ their compressed coordinates. For a point (x, y), for any given
value for x
+ such that the point is on the curve there will only ever be two
possible
+ values for y. Therefore, a point can be set using this function
where BnX is
+ the x coordinate and YBit is a value 0 or 1 to identify which of the
two
+ possible values for y should be used.
+
+ @param[in] EcGroup EC group object.
+ @param[in] EcPoint EC Point.
+ @param[in] BnX X coordinate.
+ @param[in] YBit 0 or 1 to identify which Y value is used.
+ @param[in] BnCtx BN context, created with
BigNumNewContext().
+
+ @retval TRUE On success.
+ @retval FALSE Otherwise.
+**/
+BOOLEAN
+EFIAPI
+EcPointSetCompressedCoordinates (
+ IN CONST VOID *EcGroup,
+ IN VOID *EcPoint,
+ IN CONST VOID *BnX,
+ IN UINT8 YBit,
+ IN VOID *BnCtx
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Allocates and Initializes one Elliptic Curve Context for subsequent
use
+ with the NID.
+
+ @param[in] Nid cipher NID
+ @return Pointer to the Elliptic Curve Context that has been
initialized.
+ If the allocations fails, EcNewByNid() returns NULL.
+**/
+VOID *
+EFIAPI
+EcNewByNid (
+ IN UINTN Nid
+ )
+{
+ ASSERT (FALSE);
+ return NULL;
+}
+
+/**
+ Release the specified EC context.
+
+ @param[in] EcContext Pointer to the EC context to be released.
+**/
+VOID
+EFIAPI
+EcFree (
+ IN VOID *EcContext
+ )
+{
+ ASSERT (FALSE);
+}
+
+/**
+ Generates EC key and returns EC public key (X, Y), Please note,
this function uses
+ pseudo random number generator. The caller must make sure
RandomSeed()
+ function was properly called before.
+ The Ec context should be correctly initialized by EcNewByNid.
+ This function generates random secret, and computes the public
key (X, Y), which is
+ returned via parameter Public, PublicSize.
+ X is the first half of Public with size being PublicSize / 2,
+ Y is the second half of Public with size being PublicSize / 2.
+ EC context is updated accordingly.
+ If the Public buffer is too small to hold the public X, Y, FALSE is
returned and
+ PublicSize is set to the required buffer size to obtain the public X,
Y.
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ If EcContext is NULL, then return FALSE.
+ If PublicSize is NULL, then return FALSE.
+ If PublicSize is large enough but Public is NULL, then return FALSE.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC public X,Y generation succeeded.
+ @retval FALSE EC public X,Y generation failed.
+ @retval FALSE PublicKeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcGenerateKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Gets the public key component from the established EC context.
+ The Ec context should be correctly initialized by EcNewByNid, and
successfully
+ generate key pair from EcGenerateKey().
+ For P-256, the PublicSize is 64. First 32-byte is X, Second 32-byte
is Y.
+ For P-384, the PublicSize is 96. First 48-byte is X, Second 48-byte
is Y.
+ For P-521, the PublicSize is 132. First 66-byte is X, Second 66-byte
is Y.
+ @param[in, out] EcContext Pointer to EC context being set.
+ @param[out] PublicKey Pointer to t buffer to receive
generated public X,Y.
+ @param[in, out] PublicKeySize On input, the size of Public buffer
in bytes.
+ On output, the size of data returned in Public
buffer in bytes.
+ @retval TRUE EC key component was retrieved successfully.
+ @retval FALSE Invalid EC key component.
+**/
+BOOLEAN
+EFIAPI
+EcGetPubKey (
+ IN OUT VOID *EcContext,
+ OUT UINT8 *PublicKey,
+ IN OUT UINTN *PublicKeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Computes exchanged common key.
+ Given peer's public key (X, Y), this function computes the
exchanged common key,
+ based on its own context including value of curve parameter and
random secret.
+ X is the first half of PeerPublic with size being PeerPublicSize / 2,
+ Y is the second half of PeerPublic with size being PeerPublicSize /
2.
+ If EcContext is NULL, then return FALSE.
+ If PeerPublic is NULL, then return FALSE.
+ If PeerPublicSize is 0, then return FALSE.
+ If Key is NULL, then return FALSE.
+ If KeySize is not large enough, then return FALSE.
+ For P-256, the PeerPublicSize is 64. First 32-byte is X, Second 32-
byte is Y.
+ For P-384, the PeerPublicSize is 96. First 48-byte is X, Second 48-
byte is Y.
+ For P-521, the PeerPublicSize is 132. First 66-byte is X, Second 66-
byte is Y.
+ @param[in, out] EcContext Pointer to the EC context.
+ @param[in] PeerPublic Pointer to the peer's public X,Y.
+ @param[in] PeerPublicSize Size of peer's public X,Y in bytes.
+ @param[in] CompressFlag Flag of PeerPublic is
compressed or not.
+ @param[out] Key Pointer to the buffer to receive
generated key.
+ @param[in, out] KeySize On input, the size of Key buffer in
bytes.
+ On output, the size of data returned in Key
buffer in bytes.
+ @retval TRUE EC exchanged key generation succeeded.
+ @retval FALSE EC exchanged key generation failed.
+ @retval FALSE KeySize is not large enough.
+**/
+BOOLEAN
+EFIAPI
+EcDhComputeKey (
+ IN OUT VOID *EcContext,
+ IN CONST UINT8 *PeerPublic,
+ IN UINTN PeerPublicSize,
+ IN CONST INT32 *CompressFlag,
+ OUT UINT8 *Key,
+ IN OUT UINTN *KeySize
+ )
+{
+ ASSERT (FALSE);
+ return FALSE;
+}
--
2.31.1.windows.1




Join devel@edk2.groups.io to automatically receive all group messages.