TcgTpmPkg: openssl layer for TCG TPM v2.0 implementation

The TCG TPM v2.0 implementation relies on OpenSSL for cryptographic
operations and big number support.
However,directly including public OpenSSL headers is not permitted
in EDKII. Instead, the implementation must use the BaseCryptoLib APIs.

To redirect OpenSSL API usage to the corresponding BaseCryptoLib APIs
within the TCG TPM v2.0 implementation [0], this patch adds
the necessary wrapper headers.

Link: https://github.com/TrustedComputingGroup/TPM [0]
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
This commit is contained in:
Levi Yun 2025-12-19 09:54:02 +00:00 committed by mergify[bot]
parent 641a32bd4a
commit abf4467708
5 changed files with 1172 additions and 0 deletions

View file

@ -0,0 +1,135 @@
/** @file
This file connects TCG TPM openssl usage to EDKII's crypto library.
The original reference was taken from
- https://github.com/TrustedComputingGroup/TPM/blob/main/TPMCmd/tpm/cryptolibs/Ossl/include/Ossl/BnToOsslMath.h
and has been modified to use the EDK2 crypto library interfaces.
**/
#pragma once
#define MATH_LIB_OSSL
// Require TPM Big Num types
#if !defined (MATH_LIB_TPMBIGNUM) && !defined (_BNOSSL_H_)
#error this OpenSSL Interface expects to be used from TpmBigNum
#endif
#include <BnValues.h>
#include <CrtLibSupport.h>
#include <Library/BaseCryptLib.h>
// ***************************************************************
// ** OpenSSL structures for Big Number
// ***************************************************************
/*
* 64-bit processor with LP64 ABI
*/
#ifdef SIXTY_FOUR_BIT_LONG
#define BN_ULONG unsigned long
#define BN_BYTES 8
#endif
/*
* 64-bit processor other than LP64 ABI
*/
#ifdef SIXTY_FOUR_BIT
#define BN_ULONG unsigned long long
#define BN_BYTES 8
#endif
#ifdef THIRTY_TWO_BIT
#define BN_ULONG unsigned int
#define BN_BYTES 4
#endif
struct bignum_st {
// d is a pointer to an array of |width| |BN_BITS2|-bit chunks in
// little-endian order. This stores the absolute value of the number.
BN_ULONG *d;
// width is the number of elements of |d| which are valid. This value is not
// necessarily minimal; the most-significant words of |d| may be zero.
// |width| determines a potentially loose upper-bound on the absolute value
// of the |BIGNUM|.
//
// Functions taking |BIGNUM| inputs must compute the same answer for all
// possible widths. |bn_minimal_width|, |bn_set_minimal_width|, and other
// helpers may be used to recover the minimal width, provided it is not
// secret. If it is secret, use a different algorithm. Functions may output
// minimal or non-minimal |BIGNUM|s depending on secrecy requirements, but
// those which cause widths to unboundedly grow beyond the minimal value
// should be documented such.
//
// Note this is different from historical |BIGNUM| semantics.
int top; /**< width */
// dmax is number of elements of |d| which are allocated.
int dmax;
// neg is one if the number if negative and zero otherwise.
int neg;
// flags is a bitmask of |BN_FLG_*| values
int flags;
};
typedef struct bignum_st BIGNUM;
typedef void BN_CTX;
typedef void EC_GROUP;
typedef void EC_POINT;
// ** Macros and Defines
// Make sure that the library is using the correct size for a crypt word
#if defined THIRTY_TWO_BIT && (RADIX_BITS != 32) \
|| ((defined SIXTY_FOUR_BIT_LONG || defined SIXTY_FOUR_BIT) \
&& (RADIX_BITS != 64))
#error Ossl library is using different radix
#endif
// Allocate a local BIGNUM value. For the allocation, a bigNum structure is created
// as is a local BIGNUM. The bigNum is initialized and then the BIGNUM is
// set to reference the local value.
#define BIG_VAR(name, bits) \
BN_VAR(name##Bn, (bits)); \
BIGNUM _##name; \
BIGNUM* name = BigInitialized( \
&_##name, BnInit(name##Bn, BYTES_TO_CRYPT_WORDS(sizeof(_##name##Bn.d))))
// Allocate a BIGNUM and initialize with the values in a bigNum initializer
#define BIG_INITIALIZED(name, initializer) \
BIGNUM _##name; \
BIGNUM* name = BigInitialized(&_##name, initializer)
typedef struct {
const TPMBN_ECC_CURVE_CONSTANTS *C; // the TPM curve values
EC_GROUP *G; // group parameters
BN_CTX *CTX; // the context for the math (this might not be
// the context in which the curve was created>;
} OSSL_CURVE_DATA;
// Define the curve data type expected by the TpmBigNum library:
typedef OSSL_CURVE_DATA bigCurveData;
TPM_INLINE const TPMBN_ECC_CURVE_CONSTANTS *
AccessCurveConstants (
const bigCurveData *E
)
{
return E->C;
}
#include <Ossl/TpmToOsslSupport_fp.h>
// Start and end a context within which the OpenSSL memory management works
#define OSSL_ENTER() BN_CTX* CTX = OsslContextEnter()
#define OSSL_LEAVE() OsslContextLeave(CTX)
// Start and end a local stack frame within the context of the curve frame
#define ECC_ENTER() BN_CTX* CTX = OsslPushContext(E->CTX)
#define ECC_LEAVE() OsslPopContext(CTX)
#define BN_NEW() BnNewVariable(CTX)
// This definition would change if there were something to report
#define MathLibSimulationEnd()

View file

@ -0,0 +1,190 @@
/** @file
This file connects TCG TPM openssl usage to EDKII's crypto library.
The original reference was taken from
- https://github.com/TrustedComputingGroup/TPM/blob/main/TPMCmd/tpm/cryptolibs/Ossl/include/Ossl/TpmToOsslHash.h
and has been modified to use the EDK2 crypto library interfaces.
**/
#pragma once
#define HASH_LIB_OSSL
#include <Library/BaseCryptLib.h>
// ***************************************************************
// ** OpenSSL structures for HASH
// ***************************************************************
#if ALG_SM3_256
#define SM3_DIGEST_LENGTH 32
#define SM3_WORD UINT32
#define SM3_CBLOCK 64
#define SM3_LBLOCK (SM3_CBLOCK / 4)
typedef struct SM3state_st {
SM3_WORD A, B, C, D, E, F, G, H;
SM3_WORD Nl, Nh;
SM3_WORD data[SM3_LBLOCK];
unsigned int num;
} SM3_CTX;
#endif // ALG_SM3_256
#define SHA_LONG UINT32
#define SHA_LONG64 UINT64
#define SHA_LBLOCK 16
#define SHA512_CBLOCK (SHA_LBLOCK * 8)
typedef struct SHAstate_st {
SHA_LONG h0, h1, h2, h3, h4;
SHA_LONG Nl, Nh;
SHA_LONG data[SHA_LBLOCK];
unsigned int num;
} SHA_CTX;
typedef struct SHA256state_st {
SHA_LONG h[8];
SHA_LONG Nl, Nh;
SHA_LONG data[SHA_LBLOCK];
unsigned int num, md_len;
} SHA256_CTX;
typedef struct SHA512state_st {
SHA_LONG64 h[8];
SHA_LONG64 Nl, Nh;
union {
SHA_LONG64 d[SHA_LBLOCK];
unsigned char p[SHA512_CBLOCK];
} u;
unsigned int num, md_len;
} SHA512_CTX;
typedef struct SM3state_st SM3_CTX;
typedef struct SHAstate_st SHA_CTX;
typedef struct SHA256state_st SHA256_CTX;
typedef struct SHA512state_st SHA512_CTX;
// ***************************************************************
// ** Links to the OpenSSL HASH code
// ***************************************************************
// Redefine the internal name used for each of the hash state structures to the
// name used by the library.
// These defines need to be known in all parts of the TPM so that the structure
// sizes can be properly computed when needed.
#define tpmHashStateSHA1_t SHA_CTX
#define tpmHashStateSHA256_t SHA256_CTX
#define tpmHashStateSHA384_t SHA512_CTX
#define tpmHashStateSHA512_t SHA512_CTX
#define tpmHashStateSM3_256_t SM3_CTX
// The defines below are only needed when compiling CryptHash.c or CryptSmac.c.
// This isolation is primarily to avoid name space collision. However, if there
// is a real collision, it will likely show up when the linker tries to put things
// together.
#ifdef _CRYPT_HASH_C_
typedef UINT8 *PBYTE;
typedef CONST VOID *PCBYTE;
// Define the interface between CryptHash.c to the functions provided by the
// library. For each method, define the calling parameters of the method and then
// define how the method is invoked in CryptHash.c.
//
// All hashes are required to have the same calling sequence. If they don't, create
// a simple adaptation function that converts from the "standard" form of the call
// to the form used by the specific hash (and then send a nasty letter to the
// person who wrote the hash function for the library).
//
// The macro that calls the method also defines how the
// parameters get swizzled between the default form (in CryptHash.c)and the
// library form.
//
// Initialize the hash context
#define HASH_START_METHOD_DEF BOOLEAN (HASH_START_METHOD)(PANY_HASH_STATE state)
#define HASH_START(hashState) ((hashState)->def->method.start)(&(hashState)->state);
// Add data to the hash
#define HASH_DATA_METHOD_DEF \
BOOLEAN (HASH_DATA_METHOD)(PANY_HASH_STATE state, PCBYTE buffer, UINTN size)
#define HASH_DATA(hashState, dInSize, dIn) \
((hashState)->def->method.data)(&(hashState)->state, dIn, dInSize)
// Finalize the hash and get the digest
#define HASH_END_METHOD_DEF \
BOOLEAN (HASH_END_METHOD)(PANY_HASH_STATE state, PBYTE buffer)
#define HASH_END(hashState, buffer) \
((hashState)->def->method.end)(&(hashState)->state, buffer)
// Copy the hash context
// Note: For import, export, and copy, memcpy() is used since there is no
// reformatting necessary between the internal and external forms.
#define HASH_STATE_COPY_METHOD_DEF \
void(HASH_STATE_COPY_METHOD)( \
PANY_HASH_STATE to, PCANY_HASH_STATE from, size_t size)
#define HASH_STATE_COPY(hashStateOut, hashStateIn) \
((hashStateIn)->def->method.copy)(&(hashStateOut)->state, \
&(hashStateIn)->state, \
(hashStateIn)->def->contextSize)
// Copy (with reformatting when necessary) an internal hash structure to an
// external blob
#define HASH_STATE_EXPORT_METHOD_DEF \
void(HASH_STATE_EXPORT_METHOD)(BYTE * to, PCANY_HASH_STATE from, size_t size)
#define HASH_STATE_EXPORT(to, hashStateFrom) \
((hashStateFrom)->def->method.copyOut)( \
&(((BYTE*)(to))[offsetof(HASH_STATE, state)]), \
&(hashStateFrom)->state, \
(hashStateFrom)->def->contextSize)
// Copy from an external blob to an internal formate (with reformatting when
// necessary
#define HASH_STATE_IMPORT_METHOD_DEF \
void(HASH_STATE_IMPORT_METHOD)( \
PANY_HASH_STATE to, const BYTE* from, size_t size)
#define HASH_STATE_IMPORT(hashStateTo, from) \
((hashStateTo)->def->method.copyIn)( \
&(hashStateTo)->state, \
&(((const BYTE*)(from))[offsetof(HASH_STATE, state)]), \
(hashStateTo)->def->contextSize)
// Function aliases. The code in CryptHash.c uses the internal designation for the
// functions. These need to be translated to the function names of the library.
#define tpmHashStart_SHA1 Sha1Init
#define tpmHashData_SHA1 Sha1Update
#define tpmHashEnd_SHA1 Sha1Final
#define tpmHashStateCopy_SHA1 memcpy
#define tpmHashStateExport_SHA1 memcpy
#define tpmHashStateImport_SHA1 memcpy
#define tpmHashStart_SHA256 Sha256Init
#define tpmHashData_SHA256 Sha256Update
#define tpmHashEnd_SHA256 Sha256Final
#define tpmHashStateCopy_SHA256 memcpy
#define tpmHashStateExport_SHA256 memcpy
#define tpmHashStateImport_SHA256 memcpy
#define tpmHashStart_SHA384 Sha384Init
#define tpmHashData_SHA384 Sha384Update
#define tpmHashEnd_SHA384 Sha384Final
#define tpmHashStateCopy_SHA384 memcpy
#define tpmHashStateExport_SHA384 memcpy
#define tpmHashStateImport_SHA384 memcpy
#define tpmHashStart_SHA512 Sha512Init
#define tpmHashData_SHA512 Sha512Update
#define tpmHashEnd_SHA512 Sha512Final
#define tpmHashStateCopy_SHA512 memcpy
#define tpmHashStateExport_SHA512 memcpy
#define tpmHashStateImport_SHA512 memcpy
#define tpmHashStart_SM3_256 Sm3Init
#define tpmHashData_SM3_256 Sm3Update
#define tpmHashEnd_SM3_256 Sm3Final
#define tpmHashStateCopy_SM3_256 memcpy
#define tpmHashStateExport_SM3_256 memcpy
#define tpmHashStateImport_SM3_256 memcpy
#endif // _CRYPT_HASH_C_
#define LibHashInit()
// This definition would change if there were something to report
#define HashLibSimulationEnd()

View file

@ -0,0 +1,130 @@
/** @file
This file connects TCG TPM openssl usage to EDKII's crypto library.
The original reference was taken from
- https://github.com/TrustedComputingGroup/TPM/blob/main/TPMCmd/tpm/cryptolibs/Ossl/include/Ossl/TpmToOsslSym.h
and has been modified to use the EDK2 crypto library interfaces.
**/
#pragma once
#define SYM_LIB_OSSL
#include <Library/BaseCryptLib.h>
// ***************************************************************
// ** OpenSSL structures for Cipher
// ***************************************************************
#define AES_MAXNR 14
struct aes_key_st {
#ifdef AES_LONG
unsigned long rd_key[4 * (AES_MAXNR + 1)];
#else
unsigned int rd_key[4 * (AES_MAXNR + 1)];
#endif
int rounds;
};
struct edkii_aes_key_st {
struct aes_key_st aes_key[2];
};
#define CAMELLIA_TABLE_BYTE_LEN 272
#define CAMELLIA_TABLE_WORD_LEN (CAMELLIA_TABLE_BYTE_LEN / 4)
typedef unsigned int KEY_TABLE_TYPE[CAMELLIA_TABLE_WORD_LEN]; /* to match
* with WORD */
struct camellia_key_st {
union {
double d; /* ensures 64-bit align */
KEY_TABLE_TYPE rd_key;
} u;
int grand_rounds;
};
typedef struct edkii_aes_key_st AES_KEY;
typedef struct camellia_key_st CAMELLIA_KEY;
// ***************************************************************
// ** Links to the OpenSSL symmetric algorithms.
// ***************************************************************
// The Crypt functions that call the block encryption function use the parameters
// in the order:
// 1) keySchedule
// 2) in buffer
// 3) out buffer
// Since open SSL uses the order in encryptoCall_t above, need to swizzle the
// values to the order required by the library.
#define SWIZZLE(keySchedule, in, out) \
(VOID *)(keySchedule), (CONST UINT8 *)(in), (UINT8 *)(out)
// Define the order of parameters to the library functions that do block encryption
// and decryption.
typedef BOOLEAN (*TpmCryptSetSymKeyCall_t)(
VOID *keySchedule,
CONST UINT8 *in,
UINT8 *out
);
// ***************************************************************
// ** Links to the OpenSSL AES code
// ***************************************************************
// Macros to set up the encryption/decryption key schedules
//
// AES:
/*
* TCG TPM v2.0 implementation wants to receive 0 when it success.
* But AesInit() returns TRUE on success.
*/
#define TpmCryptSetEncryptKeyAES(key, keySizeInBits, schedule) \
!AesInit((tpmKeyScheduleAES *)(schedule), (key), (keySizeInBits))
#define TpmCryptSetDecryptKeyAES(key, keySizeInBits, schedule) \
!AesInit((tpmKeyScheduleAES *)(schedule), (key), (keySizeInBits))
// Macros to alias encryption calls to specific algorithms. This should be used
// sparingly. Currently, only used by CryptSym.c and CryptRand.c
//
// When using these calls, to call the AES block encryption code, the caller
// should use:
// TpmCryptEncryptAES(SWIZZLE(keySchedule, in, out));
#define TpmCryptEncryptAES AesEncrypt
#define TpmCryptDecryptAES AesDecrypt
#define tpmKeyScheduleAES AES_KEY
// ***************************************************************
// ** Links to the OpenSSL SM4 code
// ***************************************************************
// Macros to set up the encryption/decryption key schedules
/* SM4 unsupported by EDKII */
// ***************************************************************
// ** Links to the OpenSSL CAMELLIA code
// ***************************************************************
// Macros to set up the encryption/decryption key schedules
/*
* TCG TPM v2.0 implementation wants to receive 0 when it success.
* But CamelliaInit() returns TRUE on success.
*/
#define TpmCryptSetEncryptKeyCAMELLIA(key, keySizeInBits, schedule) \
!CamelliaInit((tpmKeyScheduleCAMELLIA*)(schedule), (key), (keySizeInBits))
#define TpmCryptSetDecryptKeyCAMELLIA(key, keySizeInBits, schedule) \
!CamelliaInit((tpmKeyScheduleCAMELLIA*)(schedule), (key), (keySizeInBits))
// Macros to alias encryption calls to specific algorithms. This should be used
// sparingly.
#define TpmCryptEncryptCAMELLIA CamelliaEncrypt
#define TpmCryptDecryptCAMELLIA CamelliaDecrypt
#define tpmKeyScheduleCAMELLIA CAMELLIA_KEY
// Forward reference
typedef union tpmCryptKeySchedule_t tpmCryptKeySchedule_t;
// This definition would change if there were something to report
#define SymLibSimulationEnd()

View file

@ -0,0 +1,633 @@
/** @file
This file connects TCG TPM openssl usage to EDKII's crypto library.
The original reference was taken from
- https://github.com/TrustedComputingGroup/TPM/blob/main/TPMCmd/tpm/cryptolibs/Ossl/BnToOsslMath.c
and has been modified to use the EDK2 crypto library interfaces.
**/
#include "BnOssl.h"
#ifdef MATH_LIB_OSSL
#include <Ossl/BnToOsslMath_fp.h>
// ** Functions
// *** OsslToTpmBn()
// This function converts an OpenSSL BIGNUM to a TPM bigNum. In this implementation
// it is assumed that OpenSSL uses a different control structure but the same data
// layout -- an array of native-endian words in little-endian order.
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure because value will not fit or OpenSSL variable doesn't
// exist
BOOL
OsslToTpmBn (
bigNum bn,
BIGNUM *osslBn
)
{
GOTO_ERROR_UNLESS (osslBn != NULL);
// If the bn is NULL, it means that an output value pointer was NULL meaning that
// the results is simply to be discarded.
if (bn != NULL) {
int i;
//
GOTO_ERROR_UNLESS ((unsigned)osslBn->top <= BnGetAllocated (bn));
for (i = 0; i < osslBn->top; i++) {
bn->d[i] = osslBn->d[i];
}
BnSetTop (bn, osslBn->top);
}
return TRUE;
Error:
return FALSE;
}
// *** BigInitialized()
// This function initializes an OSSL BIGNUM from a TPM bigConst. Do not use this for
// values that are passed to OpenSLL when they are not declared as const in the
// function prototype. Instead, use BnNewVariable().
BIGNUM *
BigInitialized (
BIGNUM *toInit,
bigConst initializer
)
{
if (initializer == NULL) {
FAIL (FATAL_ERROR_PARAMETER);
}
if ((toInit == NULL) || (initializer == NULL)) {
return NULL;
}
toInit->d = (BN_ULONG *)&initializer->d[0];
toInit->dmax = (int)initializer->allocated;
toInit->top = (int)initializer->size;
toInit->neg = 0;
toInit->flags = 0;
return toInit;
}
#ifndef OSSL_DEBUG
#define BIGNUM_PRINT(label, bn, eol)
#define DEBUG_PRINT(x)
#else
#define DEBUG_PRINT(x) TPM_DEBUG_PRINTF("%s", x)
#define BIGNUM_PRINT(label, bn, eol) BIGNUM_print((label), (bn), (eol))
// *** BIGNUM_print()
static void
BIGNUM_print (
const char *label,
const BIGNUM *a,
BOOL eol
)
{
BN_ULONG *d;
int i;
int notZero = FALSE;
if (label != NULL) {
DEBUG_PRINT ("%s", label);
}
if (a == NULL) {
DEBUG_PRINT ("NULL");
goto done;
}
if (a->neg) {
DEBUG_PRINT ("-");
}
for (i = a->top, d = &a->d[i - 1]; i > 0; i--) {
int j;
BN_ULONG l = *d--;
for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
BYTE b = (BYTE)((l >> j) & 0xFF);
notZero = notZero || (b != 0);
if (notZero) {
DEBUG_PRINT ("%02x", b);
}
}
if (!notZero) {
DEBUG_PRINT ("0");
}
}
done:
if (eol) {
DEBUG_PRINT ("\n");
}
return;
}
#endif
// *** BnNewVariable()
// This function allocates a new variable in the provided context. If the context
// does not exist or the allocation fails, it is a catastrophic failure.
static BIGNUM *
BnNewVariable (
BN_CTX *CTX
)
{
BIGNUM *new;
//
// This check is intended to protect against calling this function without
// having initialized the CTX.
if ((CTX == NULL) || ((new = BigNumContextGet (CTX)) == NULL)) {
FAIL_NULL (FATAL_ERROR_ALLOCATION);
}
return new;
}
#if LIBRARY_COMPATIBILITY_CHECK
// *** MathLibraryCompatibilityCheck()
BOOL
BnMathLibraryCompatibilityCheck (
void
)
{
OSSL_ENTER ();
BOOLEAN OK = FALSE;
BIGNUM *osslTemp;
crypt_uword_t i;
BYTE test[] = {
0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x19, 0x18, 0x17, 0x16, 0x15,
0x14, 0x13, 0x12, 0x11, 0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A,
0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00
};
BN_VAR (tpmTemp, sizeof (test) * 8); // allocate some space for a test value
// Convert the test data to a bigNum
BnFromBytes (tpmTemp, test, sizeof (test));
// Convert the test data to an OpenSSL BIGNUM
osslTemp = BigNumFromBin (test, sizeof (test));
// Make sure the values are consistent
GOTO_ERROR_UNLESS (osslTemp->top == (int)tpmTemp->size);
for (i = 0; i < tpmTemp->size; i++) {
GOTO_ERROR_UNLESS (osslTemp->d[i] == tpmTemp->d[i]);
}
OK = TRUE;
Error:
BigNumFree (osslTemp, FALSE);
OSSL_LEAVE ();
return OK;
}
#endif
// *** BnModMult()
// This function does a modular multiply. It first does a multiply and then a divide
// and returns the remainder of the divide.
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
LIB_EXPORT BOOL
BnModMult (
bigNum result,
bigConst op1,
bigConst op2,
bigConst modulus
)
{
OSSL_ENTER ();
BOOL OK = FALSE;
BIGNUM *bnResult = BN_NEW ();
BIG_INITIALIZED (bnOp1, op1);
BIG_INITIALIZED (bnOp2, op2);
BIG_INITIALIZED (bnMod, modulus);
GOTO_ERROR_UNLESS (BigNumMulMod (bnOp1, bnOp2, bnMod, bnResult));
GOTO_ERROR_UNLESS (OsslToTpmBn (result, bnResult));
OK = TRUE;
Error:
OSSL_LEAVE ();
return OK;
}
// *** BnMult()
// Multiplies two numbers
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
LIB_EXPORT BOOL
BnMult (
bigNum result,
bigConst multiplicand,
bigConst multiplier
)
{
OSSL_ENTER ();
BIGNUM *bnResult = BN_NEW ();
BOOL OK = FALSE;
BIG_INITIALIZED (bnA, multiplicand);
BIG_INITIALIZED (bnB, multiplier);
GOTO_ERROR_UNLESS (BigNumMul (bnA, bnB, bnResult));
GOTO_ERROR_UNLESS (OsslToTpmBn (result, bnResult));
OK = TRUE;
Error:
OSSL_LEAVE ();
return OK;
}
// *** BnDiv()
// This function divides two bigNum values. The function returns FALSE if
// there is an error in the operation.
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
LIB_EXPORT BOOL
BnDiv (
bigNum quotient,
bigNum remainder,
bigConst dividend,
bigConst divisor
)
{
OSSL_ENTER ();
BIGNUM *bnQ = BN_NEW ();
BIGNUM *bnR = BN_NEW ();
BOOL OK = FALSE;
BIG_INITIALIZED (bnDend, dividend);
BIG_INITIALIZED (bnSor, divisor);
if (BnEqualZero (divisor)) {
FAIL (FATAL_ERROR_DIVIDE_ZERO);
}
GOTO_ERROR_UNLESS (BigNumDiv2 (bnDend, bnSor, bnQ, bnR));
GOTO_ERROR_UNLESS (OsslToTpmBn (quotient, bnQ));
GOTO_ERROR_UNLESS (OsslToTpmBn (remainder, bnR));
OK = TRUE;
DEBUG_PRINT ("In BnDiv:\n");
BIGNUM_PRINT (" bnDividend: ", bnDend, TRUE);
BIGNUM_PRINT (" bnDivisor: ", bnSor, TRUE);
BIGNUM_PRINT (" bnQuotient: ", bnQ, TRUE);
BIGNUM_PRINT (" bnRemainder: ", bnR, TRUE);
Error:
OSSL_LEAVE ();
return OK;
}
#if ALG_RSA
// *** BnGcd()
// Get the greatest common divisor of two numbers
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
LIB_EXPORT BOOL
BnGcd (
bigNum gcd, // OUT: the common divisor
bigConst number1, // IN:
bigConst number2 // IN:
)
{
OSSL_ENTER ();
BIGNUM *bnGcd = BN_NEW ();
BOOL OK = FALSE;
BIG_INITIALIZED (bn1, number1);
BIG_INITIALIZED (bn2, number2);
GOTO_ERROR_UNLESS (BigNumGcd (bn1, bn2, bnGcd));
GOTO_ERROR_UNLESS (OsslToTpmBn (gcd, bnGcd));
OK = TRUE;
Error:
OSSL_LEAVE ();
return OK;
}
// ***BnModExp()
// Do modular exponentiation using bigNum values. The conversion from a bignum_t to
// a bigNum is trivial as they are based on the same structure
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
LIB_EXPORT BOOL
BnModExp (
bigNum result, // OUT: the result
bigConst number, // IN: number to exponentiate
bigConst exponent, // IN:
bigConst modulus // IN:
)
{
OSSL_ENTER ();
BIGNUM *bnResult = BN_NEW ();
BOOL OK = FALSE;
BIG_INITIALIZED (bnN, number);
BIG_INITIALIZED (bnE, exponent);
BIG_INITIALIZED (bnM, modulus);
GOTO_ERROR_UNLESS (BigNumExpMod (bnN, bnE, bnM, bnResult));
GOTO_ERROR_UNLESS (OsslToTpmBn (result, bnResult));
OK = TRUE;
Error:
OSSL_LEAVE ();
return OK;
}
// *** BnModInverse()
// Modular multiplicative inverse
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
LIB_EXPORT BOOL
BnModInverse (
bigNum result,
bigConst number,
bigConst modulus
)
{
OSSL_ENTER ();
BIGNUM *bnResult = BN_NEW ();
BOOL OK = FALSE;
BIG_INITIALIZED (bnN, number);
BIG_INITIALIZED (bnM, modulus);
GOTO_ERROR_UNLESS (BigNumInverseMod (bnN, bnM, bnResult));
GOTO_ERROR_UNLESS (OsslToTpmBn (result, bnResult));
OK = TRUE;
Error:
OSSL_LEAVE ();
return OK;
}
#endif // ALG_RSA
#if ALG_ECC
// *** PointFromOssl()
// Function to copy the point result from an OSSL function to a bigNum
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation
static BOOL
PointFromOssl (
bigPoint pOut, // OUT: resulting point
EC_POINT *pIn, // IN: the point to return
const bigCurveData *E // IN: the curve
)
{
BIGNUM *x = NULL;
BIGNUM *y = NULL;
BOOL OK;
BigNumContextStart (E->CTX);
x = BigNumContextGet (E->CTX);
y = BigNumContextGet (E->CTX);
if (y == NULL) {
FAIL (FATAL_ERROR_ALLOCATION);
}
// If this returns false, then the point is at infinity
OK = EcPointGetAffineCoordinates (E->G, pIn, x, y, E->CTX);
if (OK) {
OsslToTpmBn (pOut->x, x);
OsslToTpmBn (pOut->y, y);
BnSetWord (pOut->z, 1);
} else {
BnSetWord (pOut->z, 0);
}
BigNumContextEnd (E->CTX);
return OK;
}
// *** EcPointInitialized()
// Allocate and initialize a point.
static EC_POINT *
EcPointInitialized (
pointConst initializer,
const bigCurveData *E
)
{
EC_POINT *P = NULL;
if (initializer != NULL) {
BIG_INITIALIZED (bnX, initializer->x);
BIG_INITIALIZED (bnY, initializer->y);
if (E == NULL) {
FAIL (FATAL_ERROR_ALLOCATION);
}
P = EcPointInit (E->G);
if (!EcPointSetAffineCoordinates (E->G, P, bnX, bnY, E->CTX)) {
P = NULL;
}
}
return P;
}
// *** BnCurveInitialize()
// This function initializes the OpenSSL curve information structure. This
// structure points to the TPM-defined values for the curve, to the context for the
// number values in the frame, and to the OpenSSL-defined group values.
// Return Type: bigCurveData*
// NULL the TPM_ECC_CURVE is not valid or there was a problem in
// in initializing the curve data
// non-NULL points to 'E'
LIB_EXPORT bigCurveData *
BnCurveInitialize (
bigCurveData *E, // IN: curve structure to initialize
TPM_ECC_CURVE curveId // IN: curve identifier
)
{
const TPMBN_ECC_CURVE_CONSTANTS *C = BnGetCurveData (curveId);
if (C == NULL) {
E = NULL;
}
if (E != NULL) {
// This creates the OpenSSL memory context that stays in effect as long as the
// curve (E) is defined.
OSSL_ENTER (); // if the allocation fails, the TPM fails
EC_POINT *P = NULL;
BIG_INITIALIZED (bnP, C->prime);
BIG_INITIALIZED (bnA, C->a);
BIG_INITIALIZED (bnB, C->b);
BIG_INITIALIZED (bnX, C->base.x);
BIG_INITIALIZED (bnY, C->base.y);
BIG_INITIALIZED (bnN, C->order);
BIG_INITIALIZED (bnH, C->h);
//
E->C = C;
E->CTX = CTX;
// initialize EC group, associate a generator point and initialize the point
// from the parameter data
// Create a group structure
E->G = EcGroupInitGFp (bnP, bnA, bnB, CTX);
GOTO_ERROR_UNLESS (E->G != NULL);
// Allocate a point in the group that will be used in setting the
// generator. This is not needed after the generator is set.
P = EcPointInit (E->G);
GOTO_ERROR_UNLESS (P != NULL);
// Need to use this in case Montgomery method is being used
GOTO_ERROR_UNLESS (EcPointSetAffineCoordinates (E->G, P, bnX, bnY, CTX));
// Now set the generator
GOTO_ERROR_UNLESS (EcGroupSetGenerator (E->G, P, bnN, bnH));
EcPointDeInit (P, FALSE);
goto Exit;
Error:
EcPointDeInit (P, FALSE);
BnCurveFree (E);
E = NULL;
}
Exit:
return E;
}
// *** BnCurveFree()
// This function will free the allocated components of the curve and end the
// frame in which the curve data exists
LIB_EXPORT void
BnCurveFree (
bigCurveData *E
)
{
if (E) {
EcGroupFree (E->G);
OsslContextLeave (E->CTX);
}
}
// *** BnEccModMult()
// This function does a point multiply of the form R = [d]S
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation; treat as result being point at infinity
LIB_EXPORT BOOL
BnEccModMult (
bigPoint R, // OUT: computed point
pointConst S, // IN: point to multiply by 'd' (optional)
bigConst d, // IN: scalar for [d]S
const bigCurveData *E
)
{
EC_POINT *pR = EcPointInit (E->G);
EC_POINT *pS = EcPointInitialized (S, E);
BIG_INITIALIZED (bnD, d);
if (S == NULL) {
EcPointMul2 (E->G, pR, bnD, NULL, NULL, E->CTX);
} else {
EcPointMul (E->G, pR, pS, bnD, E->CTX);
}
PointFromOssl (R, pR, E);
EcPointDeInit (pR, FALSE);
EcPointDeInit (pS, FALSE);
return !BnEqualZero (R->z);
}
// *** BnEccModMult2()
// This function does a point multiply of the form R = [d]G + [u]Q
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation; treat as result being point at infinity
LIB_EXPORT BOOL
BnEccModMult2 (
bigPoint R, // OUT: computed point
pointConst S, // IN: optional point
bigConst d, // IN: scalar for [d]S or [d]G
pointConst Q, // IN: second point
bigConst u, // IN: second scalar
const bigCurveData *E // IN: curve
)
{
EC_POINT *pR = EcPointInit (E->G);
EC_POINT *pS = EcPointInitialized (S, E);
BIG_INITIALIZED (bnD, d);
EC_POINT *pQ = EcPointInitialized (Q, E);
BIG_INITIALIZED (bnU, u);
if ((S == NULL) || (S == (pointConst) & (AccessCurveConstants (E)->base))) {
EcPointMul2 (E->G, pR, bnD, pQ, bnU, E->CTX);
} else {
const EC_POINT *points[2];
const BIGNUM *scalars[2];
points[0] = pS;
points[1] = pQ;
scalars[0] = bnD;
scalars[1] = bnU;
EcPointsMul (E->G, pR, NULL, 2, (CONST VOID **)points, (CONST VOID **)scalars, E->CTX);
}
PointFromOssl (R, pR, E);
EcPointDeInit (pR, FALSE);
EcPointDeInit (pS, FALSE);
EcPointDeInit (pQ, FALSE);
return !BnEqualZero (R->z);
}
// ** BnEccAdd()
// This function does addition of two points.
// Return Type: BOOL
// TRUE(1) success
// FALSE(0) failure in operation; treat as result being point at infinity
LIB_EXPORT BOOL
BnEccAdd (
bigPoint R, // OUT: computed point
pointConst S, // IN: first point to add
pointConst Q, // IN: second point
const bigCurveData *E // IN: curve
)
{
EC_POINT *pR = EcPointInit (E->G);
EC_POINT *pS = EcPointInitialized (S, E);
EC_POINT *pQ = EcPointInitialized (Q, E);
EcPointAdd (E->G, pR, pS, pQ, E->CTX);
PointFromOssl (R, pR, E);
EcPointDeInit (pR, FALSE);
EcPointDeInit (pS, FALSE);
EcPointDeInit (pQ, FALSE);
return !BnEqualZero (R->z);
}
#endif // ALG_ECC
#endif // MATHLIB OSSL

View file

@ -0,0 +1,84 @@
/** @file
This file connects TCG TPM openssl usage to EDKII's crypto library.
The original reference was taken from
- https://github.com/TrustedComputingGroup/TPM/blob/main/TPMCmd/tpm/cryptolibs/Ossl/TpmToOsslSupport.c
and has been modified to use the EDK2 crypto library interfaces.
**/
#include "BnOssl.h"
#include <CryptoInterface.h>
#include <Ossl/TpmToOsslSym.h>
#include <Ossl/TpmToOsslHash.h>
#include <stdio.h>
#if defined (HASH_LIB_OSSL) || defined (MATH_LIB_OSSL) || defined (SYM_LIB_OSSL)
// Used to pass the pointers to the correct sub-keys
typedef const BYTE *desKeyPointers[3];
// *** BnSupportLibInit()
// This does any initialization required by the support library.
LIB_EXPORT int
BnSupportLibInit (
void
)
{
return TRUE;
}
// *** OsslContextEnter()
// This function is used to initialize an OpenSSL context at the start of a function
// that will call to an OpenSSL math function.
BN_CTX *
OsslContextEnter (
void
)
{
BN_CTX *CTX = BigNumNewContext ();
//
return OsslPushContext (CTX);
}
// *** OsslContextLeave()
// This is the companion function to OsslContextEnter().
void
OsslContextLeave (
BN_CTX *CTX
)
{
OsslPopContext (CTX);
BigNumContextFree (CTX);
}
// *** OsslPushContext()
// This function is used to create a frame in a context. All values allocated within
// this context after the frame is started will be automatically freed when the
// context (OsslPopContext()
BN_CTX *
OsslPushContext (
BN_CTX *CTX
)
{
if (CTX == NULL) {
FAIL (FATAL_ERROR_ALLOCATION);
}
BigNumContextStart (CTX);
return CTX;
}
// *** OsslPopContext()
// This is the companion function to OsslPushContext().
void
OsslPopContext (
BN_CTX *CTX
)
{
// BN_CTX_end can't be called with NULL. It will blow up.
if (CTX != NULL) {
BigNumContextEnd (CTX);
}
}
#endif // HASH_LIB_OSSL || MATH_LIB_OSSL || SYM_LIB_OSSL