diff options
Diffstat (limited to 'src/tpm2/crypto')
54 files changed, 14822 insertions, 0 deletions
diff --git a/src/tpm2/crypto/CryptCmac_fp.h b/src/tpm2/crypto/CryptCmac_fp.h new file mode 100644 index 0000000..f1df646 --- /dev/null +++ b/src/tpm2/crypto/CryptCmac_fp.h @@ -0,0 +1,86 @@ +/********************************************************************************/ +/* Message Authentication Codes Based on a Symmetric Block Cipher */ +/* Implementation of cryptographic functions for hashing. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptCmac_fp.h 1490 2019-07-26 21:13:22Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2018 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTCMAC_FP_H +#define CRYPTCMAC_FP_H +#include "Tpm.h" + +UINT16 +CryptCmacStart( + SMAC_STATE *state, + TPMU_PUBLIC_PARMS *keyParms, + TPM_ALG_ID macAlg, + TPM2B *key + ); +void +CryptCmacData( + SMAC_STATES *state, + UINT32 size, + const BYTE *buffer + ); +UINT16 +CryptCmacEnd( + SMAC_STATES *state, + UINT32 outSize, + BYTE *outBuffer + ); + +#endif diff --git a/src/tpm2/crypto/CryptDes_fp.h b/src/tpm2/crypto/CryptDes_fp.h new file mode 100644 index 0000000..1c1c3cd --- /dev/null +++ b/src/tpm2/crypto/CryptDes_fp.h @@ -0,0 +1,82 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptDes_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTDES_FP_H +#define CRYPTDES_FP_H + +UINT64 +CryptSetOddByteParity( + UINT64 k + ); +BOOL +CryptDesValidateKey( + TPM2B_SYM_KEY *desKey // IN: key to validate + ); +TPM_RC +CryptGenerateKeyDes( + TPMT_PUBLIC *publicArea, // IN/OUT: The public area template + // for the new key. + TPMT_SENSITIVE *sensitive, // OUT: sensitive area + RAND_STATE *rand // IN: the "entropy" source for + ); + + +#endif diff --git a/src/tpm2/crypto/CryptEcc.h b/src/tpm2/crypto/CryptEcc.h new file mode 100644 index 0000000..282e12f --- /dev/null +++ b/src/tpm2/crypto/CryptEcc.h @@ -0,0 +1,103 @@ +/********************************************************************************/ +/* */ +/* Structure definitions used for ECC */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEcc.h 1594 2020-03-26 22:15:48Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +/* 10.1.2 CryptEcc.h */ +/* 10.1.2.1 Introduction */ +/* This file contains structure definitions used for ECC. The structures in this file are only used + internally. The ECC-related structures that cross the TPM interface are defined in TpmTypes.h */ +#ifndef _CRYPT_ECC_H +#define _CRYPT_ECC_H + +/* 10.1.2.2 Structures */ +typedef struct ECC_CURVE +{ + const TPM_ECC_CURVE curveId; + const UINT16 keySizeBits; + const TPMT_KDF_SCHEME kdf; + const TPMT_ECC_SCHEME sign; + const ECC_CURVE_DATA *curveData; // the address of the curve data + const BYTE *OID; +} ECC_CURVE; + + +/* 10.1.2.2.1 Macros */ +/* This macro is used to instance an ECC_CURVE_DATA structure for the curve. This structure is + referenced by the ECC_CURVE structure */ +#define CURVE_DATA_DEF(CURVE) \ + const ECC_CURVE_DATA CURVE = { \ + (bigNum)&CURVE##_p_DATA, (bigNum)&CURVE##_n_DATA, (bigNum)&CURVE##_h_DATA, \ + (bigNum)&CURVE##_a_DATA, (bigNum)&CURVE##_b_DATA, \ + {(bigNum)&CURVE##_gX_DATA, (bigNum)&CURVE##_gY_DATA, (bigNum)&BN_ONE} }; + +extern const ECC_CURVE eccCurves[ECC_CURVE_COUNT]; + +#define CURVE_DEF(CURVE) \ + { \ + TPM_ECC_##CURVE, \ + CURVE##_KEY_SIZE, \ + CURVE##_KDF, \ + CURVE##_SIGN, \ + &##CURVE, \ + OID_ECC_##CURVE \ + } +#define CURVE_NAME(N) + +#endif diff --git a/src/tpm2/crypto/CryptEccCrypt_fp.h b/src/tpm2/crypto/CryptEccCrypt_fp.h new file mode 100644 index 0000000..3bb52ce --- /dev/null +++ b/src/tpm2/crypto/CryptEccCrypt_fp.h @@ -0,0 +1,67 @@ +/********************************************************************************/ +/* */ +/* Include Headers for Internal Routines */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccCrypt_fp.h 1594 2020-03-26 22:15:48Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2020 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTECCCRYPT_FP_H +#define CRYPTECCCRYPT_FP_H + + + +#endif diff --git a/src/tpm2/crypto/CryptEccKeyExchange_fp.h b/src/tpm2/crypto/CryptEccKeyExchange_fp.h new file mode 100644 index 0000000..e4f0b5a --- /dev/null +++ b/src/tpm2/crypto/CryptEccKeyExchange_fp.h @@ -0,0 +1,78 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccKeyExchange_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTECCKEYEXCHANGE_FP_H +#define CRYPTECCKEYEXCHANGE_FP_H + +LIB_EXPORT TPM_RC +CryptEcc2PhaseKeyExchange( + TPMS_ECC_POINT *outZ1, // OUT: a computed point + TPMS_ECC_POINT *outZ2, // OUT: and optional second point + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPM_ALG_ID scheme, // IN: the key exchange scheme + TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key + TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key + TPMS_ECC_POINT *QsB, // IN: static public party B key + TPMS_ECC_POINT *QeB // IN: ephemeral public party B key + ); + + +#endif diff --git a/src/tpm2/crypto/CryptEccMain_fp.h b/src/tpm2/crypto/CryptEccMain_fp.h new file mode 100644 index 0000000..2c04fc1 --- /dev/null +++ b/src/tpm2/crypto/CryptEccMain_fp.h @@ -0,0 +1,232 @@ +/********************************************************************************/ +/* */ +/* ECC Main */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccMain_fp.h 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTECCMAIN_FP_H +#define CRYPTECCMAIN_FP_H + +void +EccSimulationEnd( + void + ); +BOOL +CryptEccInit( + void + ); +BOOL +CryptEccStartup( + void + ); +void +ClearPoint2B( + TPMS_ECC_POINT *p // IN: the point + ); +LIB_EXPORT const ECC_CURVE * +CryptEccGetParametersByCurveId( + TPM_ECC_CURVE curveId // IN: the curveID + ); +LIB_EXPORT UINT16 +CryptEccGetKeySizeForCurve( + TPM_ECC_CURVE curveId // IN: the curve + ); +const ECC_CURVE_DATA * +GetCurveData( + TPM_ECC_CURVE curveId // IN: the curveID + ); +const BYTE * +CryptEccGetOID( + TPM_ECC_CURVE curveId + ); +LIB_EXPORT TPM_ECC_CURVE +CryptEccGetCurveByIndex( + UINT16 i + ); +LIB_EXPORT BOOL +CryptEccGetParameter( + TPM2B_ECC_PARAMETER *out, // OUT: place to put parameter + char p, // IN: the parameter selector + TPM_ECC_CURVE curveId // IN: the curve id + ); +TPMI_YES_NO +CryptCapGetECCCurve( + TPM_ECC_CURVE curveID, // IN: the starting ECC curve + UINT32 maxCount, // IN: count of returned curves + TPML_ECC_CURVE *curveList // OUT: ECC curve list + ); +const TPMT_ECC_SCHEME * +CryptGetCurveSignScheme( + TPM_ECC_CURVE curveId // IN: The curve selector + ); +BOOL +CryptGenerateR( + TPM2B_ECC_PARAMETER *r, // OUT: the generated random value + UINT16 *c, // IN/OUT: count value. + TPMI_ECC_CURVE curveID, // IN: the curve for the value + TPM2B_NAME *name // IN: optional name of a key to + // associate with 'r' + ); +UINT16 +CryptCommit( + void + ); +void +CryptEndCommit( + UINT16 c // IN: the counter value of the commitment + ); +BOOL +CryptEccGetParameters( + TPM_ECC_CURVE curveId, // IN: ECC curve ID + TPMS_ALGORITHM_DETAIL_ECC *parameters // OUT: ECC parameters + ); +const bignum_t * +BnGetCurvePrime( + TPM_ECC_CURVE curveId + ); +const bignum_t * +BnGetCurveOrder( + TPM_ECC_CURVE curveId + ); +BOOL +BnIsOnCurve( + pointConst Q, + const ECC_CURVE_DATA *C + ); +BOOL +BnIsValidPrivateEcc( + bigConst x, // IN: private key to check + bigCurve E // IN: the curve to check + ); +LIB_EXPORT BOOL +CryptEccIsValidPrivateKey( + TPM2B_ECC_PARAMETER *d, + TPM_ECC_CURVE curveId + ); +TPM_RC +BnPointMult( + bigPoint R, // OUT: computed point + pointConst S, // IN: optional point to multiply by 'd' + bigConst d, // IN: scalar for [d]S or [d]G + pointConst Q, // IN: optional second point + bigConst u, // IN: optional second scalar + bigCurve E // IN: curve parameters + ); +BOOL +BnEccGetPrivate( + bigNum dOut, // OUT: the qualified random value + const ECC_CURVE_DATA *C, // IN: curve for which the private key +#if USE_OPENSSL_FUNCTIONS_EC + const EC_GROUP *G, // IN: the EC_GROUP to use; must be != NULL for rand == NULL + BOOL noLeadingZeros, // IN: require that all bytes in the private key be set + // result may not have leading zero bytes +#endif + // needs to be appropriate + RAND_STATE *rand // IN: state for DRBG + ); +BOOL +BnEccGenerateKeyPair( + bigNum bnD, // OUT: private scalar + bn_point_t *ecQ, // OUT: public point + bigCurve E, // IN: curve for the point + RAND_STATE *rand // IN: DRBG state to use + ); +LIB_EXPORT TPM_RC +CryptEccNewKeyPair( + TPMS_ECC_POINT *Qout, // OUT: the public point + TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar + TPM_ECC_CURVE curveId // IN: the curve for the key + ); +LIB_EXPORT TPM_RC +CryptEccPointMultiply( + TPMS_ECC_POINT *Rout, // OUT: the product point R + TPM_ECC_CURVE curveId, // IN: the curve to use + TPMS_ECC_POINT *Pin, // IN: first point (can be null) + TPM2B_ECC_PARAMETER *dIn, // IN: scalar value for [dIn]Qin + // the Pin + TPMS_ECC_POINT *Qin, // IN: point Q + TPM2B_ECC_PARAMETER *uIn // IN: scalar value for the multiplier + // of Q + ); +LIB_EXPORT BOOL +CryptEccIsPointOnCurve( + TPM_ECC_CURVE curveId, // IN: the curve selector + TPMS_ECC_POINT *Qin // IN: the point. + ); +LIB_EXPORT TPM_RC +CryptEccGenerateKey( + TPMT_PUBLIC *publicArea, // IN/OUT: The public area template for + // the new key. The public key + // area will be replaced computed + // ECC public key + TPMT_SENSITIVE *sensitive, // OUT: the sensitive area will be + // updated to contain the private + // ECC key and the symmetric + // encryption key + RAND_STATE *rand // IN: if not NULL, the deterministic + // RNG state + ); + +// libtpms added begin +LIB_EXPORT BOOL +CryptEccIsCurveRuntimeUsable( + TPMI_ECC_CURVE curveId + ); +// libtpms added end + +#endif diff --git a/src/tpm2/crypto/CryptEccSignature_fp.h b/src/tpm2/crypto/CryptEccSignature_fp.h new file mode 100644 index 0000000..5ee813e --- /dev/null +++ b/src/tpm2/crypto/CryptEccSignature_fp.h @@ -0,0 +1,111 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccSignature_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTECCSIGNATURE_FP_H +#define CRYPTECCSIGNATURE_FP_H + +TPM_RC +BnSignEcdsa( + bigNum bnR, // OUT: r component of the signature + bigNum bnS, // OUT: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bigNum bnD, // IN: private signing key + const TPM2B_DIGEST *digest, // IN: the digest to sign + RAND_STATE *rand // IN: used in debug of signing + ); +LIB_EXPORT TPM_RC +CryptEccSign( + TPMT_SIGNATURE *signature, // OUT: signature + OBJECT *signKey, // IN: ECC key to sign the hash + const TPM2B_DIGEST *digest, // IN: digest to sign + TPMT_ECC_SCHEME *scheme, // IN: signing scheme + RAND_STATE *rand + ); +TPM_RC +BnValidateSignatureEcdsa( + bigNum bnR, // IN: r component of the signature + bigNum bnS, // IN: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bn_point_t *ecQ, // IN: the public point of the key + const TPM2B_DIGEST *digest // IN: the digest that was signed + ); +LIB_EXPORT TPM_RC +CryptEccValidateSignature( + TPMT_SIGNATURE *signature, // IN: signature to be verified + OBJECT *signKey, // IN: ECC key signed the hash + const TPM2B_DIGEST *digest // IN: digest that was signed + ); +LIB_EXPORT TPM_RC +CryptEccCommitCompute( + TPMS_ECC_POINT *K, // OUT: [d]B or [r]Q + TPMS_ECC_POINT *L, // OUT: [r]B + TPMS_ECC_POINT *E, // OUT: [r]M + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPMS_ECC_POINT *M, // IN: M (optional) + TPMS_ECC_POINT *B, // IN: B (optional) + TPM2B_ECC_PARAMETER *d, // IN: d (optional) + TPM2B_ECC_PARAMETER *r // IN: the computed r value (required) + ); + + +#endif diff --git a/src/tpm2/crypto/CryptHash.h b/src/tpm2/crypto/CryptHash.h new file mode 100644 index 0000000..20f52e8 --- /dev/null +++ b/src/tpm2/crypto/CryptHash.h @@ -0,0 +1,343 @@ +/********************************************************************************/ +/* */ +/* Hash structure definitions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptHash.h 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTHASH_H +#define CRYPTHASH_H + +/* 10.1.3.1 Introduction */ + +/* This header contains the hash structure definitions used in the TPM code to define the amount of + space to be reserved for the hash state. This allows the TPM code to not have to import all of + the symbols used by the hash computations. This lets the build environment of the TPM code not to + have include the header files associated with the CryptoEngine() code. */ + +/* 10.1.3.2 Hash-related Structures */ + +union SMAC_STATES; + +/* These definitions add the high-level methods for processing state that may be an SMAC */ +typedef void(* SMAC_DATA_METHOD)( + union SMAC_STATES *state, + UINT32 size, + const BYTE *buffer + ); +typedef UINT16(* SMAC_END_METHOD)( + union SMAC_STATES *state, + UINT32 size, + BYTE *buffer + ); +typedef struct sequenceMethods { + SMAC_DATA_METHOD data; + SMAC_END_METHOD end; +} SMAC_METHODS; +#define SMAC_IMPLEMENTED (CC_MAC || CC_MAC_Start) + +/* These definitions are here because the SMAC state is in the union of hash states. */ + +typedef struct tpmCmacState { + TPM_ALG_ID symAlg; + UINT16 keySizeBits; + INT16 bcount; // current count of bytes accumulated in IV + TPM2B_IV iv; // IV buffer + TPM2B_SYM_KEY symKey; +} tpmCmacState_t; + +typedef union SMAC_STATES { +#if ALG_CMAC + tpmCmacState_t cmac; +#endif + UINT64 pad; +} SMAC_STATES; + +typedef struct SMAC_STATE { + SMAC_METHODS smacMethods; + SMAC_STATES state; +} SMAC_STATE; + +#if ALG_SHA1 +# define IF_IMPLEMENTED_SHA1(op) op(SHA1, Sha1) +#else +# define IF_IMPLEMENTED_SHA1(op) +#endif +#if ALG_SHA256 +# define IF_IMPLEMENTED_SHA256(op) op(SHA256, Sha256) +#else +# define IF_IMPLEMENTED_SHA256(op) +#endif +#if ALG_SHA384 +# define IF_IMPLEMENTED_SHA384(op) op(SHA384, Sha384) +#else +# define IF_IMPLEMENTED_SHA384(op) +#endif +#if ALG_SHA512 +# define IF_IMPLEMENTED_SHA512(op) op(SHA512, Sha512) +#else +# define IF_IMPLEMENTED_SHA512(op) +#endif +#if ALG_SM3_256 +# define IF_IMPLEMENTED_SM3_256(op) op(SM3_256, Sm3_256) +#else +# define IF_IMPLEMENTED_SM3_256(op) +#endif +#if ALG_SHA3_256 +# define IF_IMPLEMENTED_SHA3_256(op) op(SHA3_256, Sha3_256) +#else +# define IF_IMPLEMENTED_SHA3_256(op) +#endif +#if ALG_SHA3_384 +# define IF_IMPLEMENTED_SHA3_384(op) op(SHA3_384, Sha3_384) +#else +# define IF_IMPLEMENTED_SHA3_384(op) +#endif +#if ALG_SHA3_512 +# define IF_IMPLEMENTED_SHA3_512(op) op(SHA3_512, Sha3_512) +#else +# define IF_IMPLEMENTED_SHA3_512(op) +#endif + +/* SHA512 added kgold */ +#define FOR_EACH_HASH(op) \ + IF_IMPLEMENTED_SHA1(op) \ + IF_IMPLEMENTED_SHA256(op) \ + IF_IMPLEMENTED_SHA384(op) \ + IF_IMPLEMENTED_SHA512(op) \ + IF_IMPLEMENTED_SM3_256(op) \ + IF_IMPLEMENTED_SHA3_256(op) \ + IF_IMPLEMENTED_SHA3_384(op) \ + IF_IMPLEMENTED_SHA3_512(op) + +#define HASH_TYPE(HASH, Hash) tpmHashState##HASH##_t Hash; + +typedef union +{ + FOR_EACH_HASH(HASH_TYPE) + // Additions for symmetric block cipher MAC +#if SMAC_IMPLEMENTED + SMAC_STATE smac; +#endif + // to force structure alignment to be no worse than HASH_ALIGNMENT +#if HASH_ALIGNMENT == 8 + uint64_t align; +#else + uint32_t align; +#endif +} ANY_HASH_STATE; + +typedef ANY_HASH_STATE *PANY_HASH_STATE; +typedef const ANY_HASH_STATE *PCANY_HASH_STATE; +#define ALIGNED_SIZE(x, b) ((((x) + (b) - 1) / (b)) * (b)) +/* MAX_HASH_STATE_SIZE will change with each implementation. It is assumed that a hash state will + not be larger than twice the block size plus some overhead (in this case, 16 bytes). The overall + size needs to be as large as any of the hash contexts. The structure needs to start on an + alignment boundary and be an even multiple of the alignment */ +#define MAX_HASH_STATE_SIZE ((2 * MAX_HASH_BLOCK_SIZE) + 16) +#define MAX_HASH_STATE_SIZE_ALIGNED \ + ALIGNED_SIZE(MAX_HASH_STATE_SIZE, HASH_ALIGNMENT) +/* This is an aligned byte array that will hold any of the hash contexts. */ +typedef ANY_HASH_STATE ALIGNED_HASH_STATE; +/* The header associated with the hash library is expected to define the methods which include the + calling sequence. When not compiling CryptHash.c, the methods are not defined so we need + placeholder functions for the structures */ +#ifndef HASH_START_METHOD_DEF +# define HASH_START_METHOD_DEF void (HASH_START_METHOD)(void) +#endif +#ifndef HASH_DATA_METHOD_DEF +# define HASH_DATA_METHOD_DEF void (HASH_DATA_METHOD)(void) +#endif +#ifndef HASH_END_METHOD_DEF +# define HASH_END_METHOD_DEF void (HASH_END_METHOD)(void) +#endif +#ifndef HASH_STATE_COPY_METHOD_DEF +# define HASH_STATE_COPY_METHOD_DEF void (HASH_STATE_COPY_METHOD)(void) +#endif +#ifndef HASH_STATE_EXPORT_METHOD_DEF +# define HASH_STATE_EXPORT_METHOD_DEF void (HASH_STATE_EXPORT_METHOD)(void) +#endif +#ifndef HASH_STATE_IMPORT_METHOD_DEF +# define HASH_STATE_IMPORT_METHOD_DEF void (HASH_STATE_IMPORT_METHOD)(void) +#endif +/* Define the prototypical function call for each of the methods. This defines the order in which + the parameters are passed to the underlying function. */ +typedef HASH_START_METHOD_DEF; +typedef HASH_DATA_METHOD_DEF; +typedef HASH_END_METHOD_DEF; +typedef HASH_STATE_COPY_METHOD_DEF; +typedef HASH_STATE_EXPORT_METHOD_DEF; +typedef HASH_STATE_IMPORT_METHOD_DEF; +typedef struct _HASH_METHODS +{ + HASH_START_METHOD *start; + HASH_DATA_METHOD *data; + HASH_END_METHOD *end; + HASH_STATE_COPY_METHOD *copy; // Copy a hash block + HASH_STATE_EXPORT_METHOD *copyOut; // Copy a hash block from a hash + // context + HASH_STATE_IMPORT_METHOD *copyIn; // Copy a hash block to a proper hash + // context +} HASH_METHODS, *PHASH_METHODS; + +#define HASH_TPM2B(HASH, Hash) TPM2B_TYPE(HASH##_DIGEST, HASH##_DIGEST_SIZE); + +FOR_EACH_HASH(HASH_TPM2B) + +/* When the TPM implements RSA, the hash-dependent OID pointers are part of the HASH_DEF. These + macros conditionally add the OID reference to the HASH_DEF and the HASH_DEF_TEMPLATE. */ +#if ALG_RSA +#define PKCS1_HASH_REF const BYTE *PKCS1; +#define PKCS1_OID(NAME) , OID_PKCS1_##NAME +#else +#define PKCS1_HASH_REF +#define PKCS1_OID(NAME) +#endif + +/* When the TPM implements ECC, the hash-dependent OID pointers are part of the HASH_DEF. These + macros conditionally add the OID reference to the HASH_DEF and the HASH_DEF_TEMPLATE. */ +#if ALG_ECDSA +#define ECDSA_HASH_REF const BYTE *ECDSA; +#define ECDSA_OID(NAME) , OID_ECDSA_##NAME +#else +#define ECDSA_HASH_REF +#define ECDSA_OID(NAME) +#endif + +typedef const struct +{ + HASH_METHODS method; + uint16_t blockSize; + uint16_t digestSize; + uint16_t contextSize; + uint16_t hashAlg; + const BYTE *OID; + PKCS1_HASH_REF // PKCS1 OID + ECDSA_HASH_REF // ECDSA OID +} HASH_DEF, *PHASH_DEF; + +/* Macro to fill in the HASH_DEF for an algorithm. For SHA1, the instance would be: + HASH_DEF_TEMPLATE(Sha1, SHA1) This handles the difference in capitalization for the various + pieces. */ + +#define HASH_DEF_TEMPLATE(HASH, Hash) \ + HASH_DEF Hash##_Def= { \ + {(HASH_START_METHOD *)&tpmHashStart_##HASH, \ + (HASH_DATA_METHOD *)&tpmHashData_##HASH, \ + (HASH_END_METHOD *)&tpmHashEnd_##HASH, \ + (HASH_STATE_COPY_METHOD *)&tpmHashStateCopy_##HASH, \ + (HASH_STATE_EXPORT_METHOD *)&tpmHashStateExport_##HASH, \ + (HASH_STATE_IMPORT_METHOD *)&tpmHashStateImport_##HASH, \ + }, \ + HASH##_BLOCK_SIZE, /*block size */ \ + HASH##_DIGEST_SIZE, /*data size */ \ + sizeof(tpmHashState##HASH##_t), \ + TPM_ALG_##HASH, OID_##HASH \ + PKCS1_OID(HASH) ECDSA_OID(HASH)}; + +/* These definitions are for the types that can be in a hash state structure. These types are used + in the cryptographic utilities. This is a define rather than an enum so that the size of this + field can be explicit. */ +typedef BYTE HASH_STATE_TYPE; +#define HASH_STATE_EMPTY ((HASH_STATE_TYPE) 0) +#define HASH_STATE_HASH ((HASH_STATE_TYPE) 1) +#define HASH_STATE_HMAC ((HASH_STATE_TYPE) 2) +#if CC_MAC || CC_MAC_Start +#define HASH_STATE_SMAC ((HASH_STATE_TYPE) 3) +#endif +/* This is the structure that is used for passing a context into the hashing functions. It should be + the same size as the function context used within the hashing functions. This is checked when the + hash function is initialized. This version uses a new layout for the contexts and a different + definition. The state buffer is an array of HASH_UNIT values so that a decent compiler will put + the structure on a HASH_UNIT boundary. If the structure is not properly aligned, the code that + manipulates the structure will copy to a properly aligned structure before it is used and copy + the result back. This just makes things slower. */ +/* NOTE: This version of the state had the pointer to the update method in the state. This is to + allow the SMAC functions to use the same structure without having to replicate the entire + HASH_DEF structure. */ +typedef struct _HASH_STATE +{ + HASH_STATE_TYPE type; // type of the context + TPM_ALG_ID hashAlg; + PHASH_DEF def; + ANY_HASH_STATE state; +} HASH_STATE, *PHASH_STATE; +typedef const HASH_STATE *PCHASH_STATE; + +/* 10.1.3.3 HMAC State Structures */ +/* This header contains the hash structure definitions used in the TPM code to define the amount of + space to be reserved for the hash state. This allows the TPM code to not have to import all of + the symbols used by the hash computations. This lets the build environment of the TPM code not to + have include the header files associated with the CryptoEngine() code. */ + +/* An HMAC_STATE structure contains an opaque HMAC stack state. A caller would use this structure + when performing incremental HMAC operations. This structure contains a hash state and an HMAC key + and allows slightly better stack optimization than adding an HMAC key to each hash state. */ +typedef struct hmacState +{ + HASH_STATE hashState; // the hash state + TPM2B_HASH_BLOCK hmacKey; // the HMAC key +} HMAC_STATE, *PHMAC_STATE; +/* This is for the external hash state. This implementation assumes that the size of the exported + hash state is no larger than the internal hash state. */ +typedef struct +{ + BYTE buffer[sizeof(HASH_STATE)]; +} EXPORT_HASH_STATE, *PEXPORT_HASH_STATE; +typedef const EXPORT_HASH_STATE *PCEXPORT_HASH_STATE; + +#endif // _CRYPT_HASH_H diff --git a/src/tpm2/crypto/CryptHash_fp.h b/src/tpm2/crypto/CryptHash_fp.h new file mode 100644 index 0000000..adf1ba9 --- /dev/null +++ b/src/tpm2/crypto/CryptHash_fp.h @@ -0,0 +1,219 @@ +/********************************************************************************/ +/* */ +/* Implementation of cryptographic functions for hashing. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptHash_fp.h 1594 2020-03-26 22:15:48Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTHASH_FP_H +#define CRYPTHASH_FP_H + +BOOL +CryptHashInit( + void + ); +BOOL +CryptHashStartup( + void + ); +PHASH_DEF +CryptGetHashDef( + TPM_ALG_ID hashAlg + ); +BOOL +CryptHashIsValidAlg( + TPM_ALG_ID hashAlg, + BOOL flag + ); +LIB_EXPORT TPM_ALG_ID +CryptHashGetAlgByIndex( + UINT32 index // IN: the index + ); +LIB_EXPORT UINT16 +CryptHashGetDigestSize( + TPM_ALG_ID hashAlg // IN: hash algorithm to look up + ); +LIB_EXPORT UINT16 +CryptHashGetBlockSize( + TPM_ALG_ID hashAlg // IN: hash algorithm to look up + ); +LIB_EXPORT const BYTE * +CryptHashGetOid( + TPM_ALG_ID hashAlg + ); +TPM_ALG_ID +CryptHashGetContextAlg( + PHASH_STATE state // IN: the context to check + ); +LIB_EXPORT void +CryptHashCopyState( + HASH_STATE *out, // OUT: destination of the state + const HASH_STATE *in // IN: source of the state + ); +void +CryptHashExportState( + PCHASH_STATE internalFmt, // IN: the hash state formatted for use by + // library + PEXPORT_HASH_STATE externalFmt // OUT: the exported hash state + ); +void +CryptHashImportState( + PHASH_STATE internalFmt, // OUT: the hash state formatted for use by + // the library + PCEXPORT_HASH_STATE externalFmt // IN: the exported hash state + ); +LIB_EXPORT UINT16 +CryptHashStart( + PHASH_STATE hashState, // OUT: the running hash state + TPM_ALG_ID hashAlg // IN: hash algorithm + ); +LIB_EXPORT void +CryptDigestUpdate( + PHASH_STATE hashState, // IN: the hash context information + UINT32 dataSize, // IN: the size of data to be added + const BYTE *data // IN: data to be hashed + ); +LIB_EXPORT UINT16 +CryptHashEnd( + PHASH_STATE hashState, // IN: the state of hash stack + UINT32 dOutSize, // IN: size of digest buffer + BYTE *dOut // OUT: hash digest + ); +LIB_EXPORT UINT16 +CryptHashBlock( + TPM_ALG_ID hashAlg, // IN: The hash algorithm + UINT32 dataSize, // IN: size of buffer to hash + const BYTE *data, // IN: the buffer to hash + UINT32 dOutSize, // IN: size of the digest buffer + BYTE *dOut // OUT: digest buffer + ); +LIB_EXPORT void +CryptDigestUpdate2B( + PHASH_STATE state, // IN: the digest state + const TPM2B *bIn // IN: 2B containing the data + ); +LIB_EXPORT UINT16 +CryptHashEnd2B( + PHASH_STATE state, // IN: the hash state + P2B digest // IN: the size of the buffer Out: requested + // number of bytes + ); +LIB_EXPORT void +CryptDigestUpdateInt( + void *state, // IN: the state of hash stack + UINT32 intSize, // IN: the size of 'intValue' in bytes + UINT64 intValue // IN: integer value to be hashed + ); +LIB_EXPORT UINT16 +CryptHmacStart( + PHMAC_STATE state, // IN/OUT: the state buffer + TPM_ALG_ID hashAlg, // IN: the algorithm to use + UINT16 keySize, // IN: the size of the HMAC key + const BYTE *key // IN: the HMAC key + ); +LIB_EXPORT UINT16 +CryptHmacEnd( + PHMAC_STATE state, // IN: the hash state buffer + UINT32 dOutSize, // IN: size of digest buffer + BYTE *dOut // OUT: hash digest + ); +LIB_EXPORT UINT16 +CryptHmacStart2B( + PHMAC_STATE hmacState, // OUT: the state of HMAC stack. It will be used + // in HMAC update and completion + TPMI_ALG_HASH hashAlg, // IN: hash algorithm + P2B key // IN: HMAC key + ); +LIB_EXPORT UINT16 +CryptHmacEnd2B( + PHMAC_STATE hmacState, // IN: the state of HMAC stack + P2B digest // OUT: HMAC + ); +LIB_EXPORT UINT16 +CryptMGF_KDF( + UINT32 mSize, // IN: length of the mask to be produced + BYTE *mask, // OUT: buffer to receive the mask + TPM_ALG_ID hashAlg, // IN: hash to use + UINT32 seedSize, // IN: size of the seed + BYTE *seed, // IN: seed size + UINT32 counter // IN: counter initial value + ); +LIB_EXPORT UINT16 +CryptKDFa( + TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC + const TPM2B *key, // IN: HMAC key + const TPM2B *label, // IN: a label for the KDF + const TPM2B *contextU, // IN: context U + const TPM2B *contextV, // IN: context V + UINT32 sizeInBits, // IN: size of generated key in bits + BYTE *keyStream, // OUT: key buffer + UINT32 *counterInOut, // IN/OUT: caller may provide the iteration + UINT16 blocks // IN: If non-zero, this is the maximum number + ); +LIB_EXPORT UINT16 +CryptKDFe( + TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC + TPM2B *Z, // IN: Z + const TPM2B *label, // IN: a label value for the KDF + TPM2B *partyUInfo, // IN: PartyUInfo + TPM2B *partyVInfo, // IN: PartyVInfo + UINT32 sizeInBits, // IN: size of generated key in bits + BYTE *keyStream // OUT: key buffer + ); + + +#endif diff --git a/src/tpm2/crypto/CryptPrimeSieve_fp.h b/src/tpm2/crypto/CryptPrimeSieve_fp.h new file mode 100644 index 0000000..66639a3 --- /dev/null +++ b/src/tpm2/crypto/CryptPrimeSieve_fp.h @@ -0,0 +1,101 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptPrimeSieve_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTPRIMESIEVE_FP_H +#define CRYPTPRIMESIEVE_FP_H + +LIB_EXPORT void +RsaAdjustPrimeLimit( + uint32_t requestedPrimes + ); +LIB_EXPORT uint32_t +RsaNextPrime( + uint32_t lastPrime + ); +LIB_EXPORT int +FindNthSetBit( + const UINT16 aSize, // IN: the size of the array to check + const BYTE *a, // IN: the array to check + const UINT32 n // IN, the number of the SET bit + ); +LIB_EXPORT UINT32 +PrimeSieve( + bigNum bnN, // IN/OUT: number to sieve + UINT32 fieldSize, // IN: size of the field area in bytes + BYTE *field // IN: field + ); +LIB_EXPORT uint32_t +SetFieldSize( + uint32_t newFieldSize + ); +LIB_EXPORT TPM_RC +PrimeSelectWithSieve( + bigNum candidate, // IN/OUT: The candidate to filter + UINT32 e, // IN: the exponent + RAND_STATE *rand // IN: the random number generator state + ); +void +RsaSimulationEnd( + void + ); + + +#endif diff --git a/src/tpm2/crypto/CryptPrime_fp.h b/src/tpm2/crypto/CryptPrime_fp.h new file mode 100644 index 0000000..d9acfcb --- /dev/null +++ b/src/tpm2/crypto/CryptPrime_fp.h @@ -0,0 +1,104 @@ +/********************************************************************************/ +/* */ +/* Code for prime validation */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptPrime_fp.h 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTPRIME_FP_H +#define CRYPTPRIME_FP_H + +BOOL +IsPrimeInt( + uint32_t n + ); +BOOL +BnIsProbablyPrime( + bigNum prime, // IN: + RAND_STATE *rand // IN: the random state just + // in case Miller-Rabin is required + ); +UINT32 +MillerRabinRounds( + UINT32 bits // IN: Number of bits in the RSA prime + ); +BOOL +MillerRabin( + bigNum bnW, + RAND_STATE *rand + ); +TPM_RC +RsaCheckPrime( + bigNum prime, + UINT32 exponent, + RAND_STATE *rand + ); +LIB_EXPORT void +RsaAdjustPrimeCandidate( + bigNum prime, + SEED_COMPAT_LEVEL seedCompatLevel // IN: compatibility level; libtpms added + ); +TPM_RC +BnGeneratePrimeForRSA( + bigNum prime, + UINT32 bits, + UINT32 exponent, + RAND_STATE *rand + ); + + +#endif diff --git a/src/tpm2/crypto/CryptRand.h b/src/tpm2/crypto/CryptRand.h new file mode 100644 index 0000000..d339285 --- /dev/null +++ b/src/tpm2/crypto/CryptRand.h @@ -0,0 +1,193 @@ +/********************************************************************************/ +/* */ +/* DRBG with a behavior according to SP800-90A */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptRand.h 1594 2020-03-26 22:15:48Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +/* 10.1.4 CryptRand.h */ +/* 10.1.4.1 Introduction */ +/* This file contains constant definition shared by CryptUtil() and the parts of the Crypto + Engine. */ +#ifndef _CRYPT_RAND_H +#define _CRYPT_RAND_H +/* DRBG Structures and Defines Values and structures for the random number generator. These values + are defined in this header file so that the size of the RNG state can be known to TPM.lib. This + allows the allocation of some space in NV memory for the state to be stored on an orderly + shutdown. The DRBG based on a symmetric block cipher is defined by three values, */ +/* a) the key size */ +/* b) the block size (the IV size) */ +/* c) the symmetric algorithm */ +#define DRBG_KEY_SIZE_BITS AES_MAX_KEY_SIZE_BITS +#define DRBG_IV_SIZE_BITS (AES_MAX_BLOCK_SIZE * 8) +#define DRBG_ALGORITHM TPM_ALG_AES +typedef tpmKeyScheduleAES DRBG_KEY_SCHEDULE; +#define DRBG_ENCRYPT_SETUP(key, keySizeInBits, schedule) \ + TpmCryptSetEncryptKeyAES(key, keySizeInBits, schedule) +#define DRBG_ENCRYPT(keySchedule, in, out) \ + TpmCryptEncryptAES(SWIZZLE(keySchedule, in, out)) +#if ((DRBG_KEY_SIZE_BITS % RADIX_BITS) != 0) \ + || ((DRBG_IV_SIZE_BITS % RADIX_BITS) != 0) +#error "Key size and IV for DRBG must be even multiples of the radix" +#endif +#if (DRBG_KEY_SIZE_BITS % DRBG_IV_SIZE_BITS) != 0 +#error "Key size for DRBG must be even multiple of the cypher block size" +#endif +/* Derived values */ +#define DRBG_MAX_REQUESTS_PER_RESEED (1 << 48) +#define DRBG_MAX_REQEST_SIZE (1 << 32) +#define pDRBG_KEY(seed) ((DRBG_KEY *)&(((BYTE *)(seed))[0])) +#define pDRBG_IV(seed) ((DRBG_IV *)&(((BYTE *)(seed))[DRBG_KEY_SIZE_BYTES])) +#define DRBG_KEY_SIZE_WORDS (BITS_TO_CRYPT_WORDS(DRBG_KEY_SIZE_BITS)) +#define DRBG_KEY_SIZE_BYTES (DRBG_KEY_SIZE_WORDS * RADIX_BYTES) +#define DRBG_IV_SIZE_WORDS (BITS_TO_CRYPT_WORDS(DRBG_IV_SIZE_BITS)) +#define DRBG_IV_SIZE_BYTES (DRBG_IV_SIZE_WORDS * RADIX_BYTES) +#define DRBG_SEED_SIZE_WORDS (DRBG_KEY_SIZE_WORDS + DRBG_IV_SIZE_WORDS) +#define DRBG_SEED_SIZE_BYTES (DRBG_KEY_SIZE_BYTES + DRBG_IV_SIZE_BYTES) +typedef union +{ + BYTE bytes[DRBG_KEY_SIZE_BYTES]; + crypt_uword_t words[DRBG_KEY_SIZE_WORDS]; +} DRBG_KEY; +typedef union +{ + BYTE bytes[DRBG_IV_SIZE_BYTES]; + crypt_uword_t words[DRBG_IV_SIZE_WORDS]; +} DRBG_IV; +typedef union +{ + BYTE bytes[DRBG_SEED_SIZE_BYTES]; + crypt_uword_t words[DRBG_SEED_SIZE_WORDS]; +} DRBG_SEED; +#define CTR_DRBG_MAX_REQUESTS_PER_RESEED ((UINT64)1 << 20) +#define CTR_DRBG_MAX_BYTES_PER_REQUEST (1 << 16) +# define CTR_DRBG_MIN_ENTROPY_INPUT_LENGTH DRBG_SEED_SIZE_BYTES +# define CTR_DRBG_MAX_ENTROPY_INPUT_LENGTH DRBG_SEED_SIZE_BYTES +# define CTR_DRBG_MAX_ADDITIONAL_INPUT_LENGTH DRBG_SEED_SIZE_BYTES +#define TESTING (1 << 0) +#define ENTROPY (1 << 1) +#define TESTED (1 << 2) +#define IsTestStateSet(BIT) ((g_cryptoSelfTestState.rng & BIT) != 0) +#define SetTestStateBit(BIT) (g_cryptoSelfTestState.rng |= BIT) +#define ClearTestStateBit(BIT) (g_cryptoSelfTestState.rng &= ~BIT) +#define IsSelfTest() IsTestStateSet(TESTING) +#define SetSelfTest() SetTestStateBit(TESTING) +#define ClearSelfTest() ClearTestStateBit(TESTING) +#define IsEntropyBad() IsTestStateSet(ENTROPY) +#define SetEntropyBad() SetTestStateBit(ENTROPY) +#define ClearEntropyBad() ClearTestStateBit(ENTROPY) +#define IsDrbgTested() IsTestStateSet(TESTED) +#define SetDrbgTested() SetTestStateBit(TESTED) +#define ClearDrbgTested() ClearTestStateBit(TESTED) + typedef struct + { + UINT64 reseedCounter; + UINT32 magic; + DRBG_SEED seed; // contains the key and IV for the counter mode DRBG + SEED_COMPAT_LEVEL seedCompatLevel; // libtpms added: the compatibility level for keeping backwards compatibility + UINT32 lastValue[4]; // used when the TPM does continuous self-test + // for FIPS compliance of DRBG + } DRBG_STATE, *pDRBG_STATE; +#define DRBG_MAGIC ((UINT32) 0x47425244) // "DRBG" backwards so that it displays +typedef struct KDF_STATE +{ + UINT64 counter; + UINT32 magic; + UINT32 limit; + TPM2B *seed; + const TPM2B *label; + TPM2B *context; + TPM_ALG_ID hash; + TPM_ALG_ID kdf; + UINT16 digestSize; + TPM2B_DIGEST residual; +} KDF_STATE, *pKDR_STATE; +#define KDF_MAGIC ((UINT32) 0x4048444a) // "KDF " backwards +/* Make sure that any other structures added to this union start with a 64-bit counter and a 32-bit + magic number */ +typedef union +{ + DRBG_STATE drbg; + KDF_STATE kdf; +} RAND_STATE; +/* This is the state used when the library uses a random number generator. A special function is + installed for the library to call. That function picks up the state from this location and uses + it for the generation of the random number. */ +extern RAND_STATE *s_random; +/* When instrumenting RSA key sieve */ +#if RSA_INSTRUMENT +#define PRIME_INDEX(x) ((x) == 512 ? 0 : (x) == 1024 ? 1 : 2) +# define INSTRUMENT_SET(a, b) ((a) = (b)) +# define INSTRUMENT_ADD(a, b) (a) = (a) + (b) +# define INSTRUMENT_INC(a) (a) = (a) + 1 +extern UINT32 PrimeIndex; +extern UINT32 failedAtIteration[10]; +extern UINT32 PrimeCounts[3]; +extern UINT32 MillerRabinTrials[3]; +extern UINT32 totalFieldsSieved[3]; +extern UINT32 bitsInFieldAfterSieve[3]; +extern UINT32 emptyFieldsSieved[3]; +extern UINT32 noPrimeFields[3]; +extern UINT32 primesChecked[3]; +extern UINT16 lastSievePrime; +#else +# define INSTRUMENT_SET(a, b) +# define INSTRUMENT_ADD(a, b) +# define INSTRUMENT_INC(a) +#endif +#endif // _CRYPT_RAND_H + diff --git a/src/tpm2/crypto/CryptRand_fp.h b/src/tpm2/crypto/CryptRand_fp.h new file mode 100644 index 0000000..e5dee5b --- /dev/null +++ b/src/tpm2/crypto/CryptRand_fp.h @@ -0,0 +1,158 @@ +/********************************************************************************/ +/* */ +/* DRBG with a behavior according to SP800-90A */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptRand_fp.h 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTRAND_FP_H +#define CRYPTRAND_FP_H + +BOOL +DRBG_GetEntropy( + UINT32 requiredEntropy, // IN: requested number of bytes of full + // entropy + BYTE *entropy // OUT: buffer to return collected entropy + ); +void +IncrementIv( + DRBG_IV *iv + ); +BOOL +DRBG_Reseed( + DRBG_STATE *drbgState, // IN: the state to update + DRBG_SEED *providedEntropy, // IN: entropy + DRBG_SEED *additionalData // IN: + ); +BOOL +DRBG_SelfTest( + void + ); +LIB_EXPORT TPM_RC +CryptRandomStir( + UINT16 additionalDataSize, + BYTE *additionalData + ); +LIB_EXPORT UINT16 +CryptRandomGenerate( + UINT16 randomSize, + BYTE *buffer + ); +LIB_EXPORT BOOL +DRBG_InstantiateSeededKdf( + KDF_STATE *state, // IN: buffer to hold the state + TPM_ALG_ID hashAlg, // IN: hash algorithm + TPM_ALG_ID kdf, // IN: the KDF to use + TPM2B *seed, // IN: the seed to use + const TPM2B *label, // IN: a label for the generation process. + TPM2B *context, // IN: the context value + UINT32 limit // IN: Maximum number of bits from the KDF + ); +LIB_EXPORT void +DRBG_AdditionalData( + DRBG_STATE *drbgState, // IN:OUT state to update + TPM2B *additionalData // IN: value to incorporate + ); +LIB_EXPORT TPM_RC +DRBG_InstantiateSeeded( + DRBG_STATE *drbgState, // IN: buffer to hold the state + const TPM2B *seed, // IN: the seed to use + const TPM2B *purpose, // IN: a label for the generation process. + const TPM2B *name, // IN: name of the object + const TPM2B *additional, // IN: additional data + SEED_COMPAT_LEVEL seedCompatLevel// IN: compatibility level (associated with seed); libtpms added + ); +LIB_EXPORT BOOL +CryptRandStartup( + void + ); +LIB_EXPORT BOOL +CryptRandInit( + void + ); +LIB_EXPORT UINT16 +DRBG_Generate( + RAND_STATE *state, + BYTE *random, // OUT: buffer to receive the random values + UINT16 randomSize // IN: the number of bytes to generate + ); +// libtpms added begin +LIB_EXPORT SEED_COMPAT_LEVEL +DRBG_GetSeedCompatLevel( + RAND_STATE *state // IN + ); +// libtpms added end +LIB_EXPORT BOOL +DRBG_Instantiate( + DRBG_STATE *drbgState, // OUT: the instantiated value + UINT16 pSize, // IN: Size of personalization string + BYTE *personalization // IN: The personalization string + ); +LIB_EXPORT TPM_RC +DRBG_Uninstantiate( + DRBG_STATE *drbgState // IN/OUT: working state to erase + ); +LIB_EXPORT NUMBYTES +CryptRandMinMax( + BYTE *out, + UINT32 max, + UINT32 min, + RAND_STATE *rand + ); + + +#endif diff --git a/src/tpm2/crypto/CryptRsa.h b/src/tpm2/crypto/CryptRsa.h new file mode 100644 index 0000000..f3c1fa1 --- /dev/null +++ b/src/tpm2/crypto/CryptRsa.h @@ -0,0 +1,99 @@ +/********************************************************************************/ +/* */ +/* RSA-related structures and defines */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptRsa.h 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +// 10.1.5 CryptRsa.h +// This file contains the RSA-related structures and defines. +#ifndef _CRYPT_RSA_H +#define _CRYPT_RSA_H + +/* This structure is a succinct representation of the cryptographic components of an RSA key. It is + used in testing */ +typedef struct +{ + UINT32 exponent; // The public exponent pointer + TPM2B *publicKey; // Pointer to the public modulus + TPM2B *privateKey; // The private prime +} RSA_KEY; +/* These values are used in the bigNum representation of various RSA values. */ +#define RSA_BITS (MAX_RSA_KEY_BYTES * 8) +BN_TYPE(rsa, RSA_BITS); +#define BN_RSA(name) BN_VAR(name, RSA_BITS) +#define BN_RSA_INITIALIZED(name, initializer) \ + BN_INITIALIZED(name, RSA_BITS, initializer) +#define BN_PRIME(name) BN_VAR(name, (RSA_BITS / 2)) +BN_TYPE(prime, (RSA_BITS / 2)); +#define BN_PRIME_INITIALIZED(name, initializer) \ + BN_INITIALIZED(name, RSA_BITS / 2, initializer) +typedef struct privateExponent +{ +#if CRT_FORMAT_RSA == NO + bn_rsa_t D; +#else + bn_prime_t Q; + bn_prime_t dP; + bn_prime_t dQ; + bn_prime_t qInv; +#endif // CRT_FORMAT_RSA +} privateExponent_t; +#endif // _CRYPT_RSA_H + + + diff --git a/src/tpm2/crypto/CryptRsa_fp.h b/src/tpm2/crypto/CryptRsa_fp.h new file mode 100644 index 0000000..d473b51 --- /dev/null +++ b/src/tpm2/crypto/CryptRsa_fp.h @@ -0,0 +1,139 @@ +/********************************************************************************/ +/* */ +/* Implementation of cryptographic primitives for RSA */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptRsa_fp.h 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTRSA_FP_H +#define CRYPTRSA_FP_H + +BOOL +CryptRsaInit( + void + ); +BOOL +CryptRsaStartup( + void + ); +void +RsaInitializeExponent( + privateExponent_t *pExp + ); +INT16 +CryptRsaPssSaltSize( + INT16 hashSize, + INT16 outSize + ); +TPMT_RSA_DECRYPT* +CryptRsaSelectScheme( + TPMI_DH_OBJECT rsaHandle, // IN: handle of an RSA key + TPMT_RSA_DECRYPT *scheme // IN: a sign or decrypt scheme + ); +TPM_RC +CryptRsaLoadPrivateExponent( + OBJECT *rsaKey // IN: the RSA key object + ); +LIB_EXPORT TPM_RC +CryptRsaEncrypt( + TPM2B_PUBLIC_KEY_RSA *cOut, // OUT: the encrypted data + TPM2B *dIn, // IN: the data to encrypt + OBJECT *key, // IN: the key used for encryption + TPMT_RSA_DECRYPT *scheme, // IN: the type of padding and hash + // if needed + const TPM2B *label, // IN: in case it is needed + RAND_STATE *rand // IN: random number generator + // state (mostly for testing) + ); +LIB_EXPORT TPM_RC +CryptRsaDecrypt( + TPM2B *dOut, // OUT: the decrypted data + TPM2B *cIn, // IN: the data to decrypt + OBJECT *key, // IN: the key to use for decryption + TPMT_RSA_DECRYPT *scheme, // IN: the padding scheme + const TPM2B *label // IN: in case it is needed for the scheme + ); +LIB_EXPORT TPM_RC +CryptRsaSign( + TPMT_SIGNATURE *sigOut, + OBJECT *key, // IN: key to use + TPM2B_DIGEST *hIn, // IN: the digest to sign + RAND_STATE *rand // IN: the random number generator + // to use (mostly for testing) + ); +LIB_EXPORT TPM_RC +CryptRsaValidateSignature( + TPMT_SIGNATURE *sig, // IN: signature + OBJECT *key, // IN: public modulus + TPM2B_DIGEST *digest // IN: The digest being validated + ); +LIB_EXPORT TPM_RC +CryptRsaGenerateKey( + OBJECT *rsaKey, // IN/OUT: The object structure in which + // the key is created. + RAND_STATE *rand // IN: if not NULL, the deterministic + // RNG state + ); +INT16 +MakeDerTag( + TPM_ALG_ID hashAlg, + INT16 sizeOfBuffer, + BYTE *buffer + ); + + +#endif diff --git a/src/tpm2/crypto/CryptSelfTest_fp.h b/src/tpm2/crypto/CryptSelfTest_fp.h new file mode 100644 index 0000000..8dd3822 --- /dev/null +++ b/src/tpm2/crypto/CryptSelfTest_fp.h @@ -0,0 +1,87 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptSelfTest_fp.h 1490 2019-07-26 21:13:22Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTSELFTEST_FP_H +#define CRYPTSELFTEST_FP_H + +LIB_EXPORT +TPM_RC +CryptSelfTest( + TPMI_YES_NO fullTest // IN: if full test is required + ); +TPM_RC +CryptIncrementalSelfTest( + TPML_ALG *toTest, // IN: list of algorithms to be tested + TPML_ALG *toDoList // OUT: list of algorithms needing test + ); +void +CryptInitializeToTest( + void + ); +LIB_EXPORT +TPM_RC +CryptTestAlgorithm( + TPM_ALG_ID alg, + ALGORITHM_VECTOR *toTest + ); + + +#endif diff --git a/src/tpm2/crypto/CryptSmac_fp.h b/src/tpm2/crypto/CryptSmac_fp.h new file mode 100644 index 0000000..b93e8ac --- /dev/null +++ b/src/tpm2/crypto/CryptSmac_fp.h @@ -0,0 +1,98 @@ +/********************************************************************************/ +/* Message Authentication Codes Based on a Symmetric Block Cipher */ +/* Implementation of cryptographic functions for hashing. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptSmac_fp.h 1490 2019-07-26 21:13:22Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2018 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTSMAC_FP_H +#define CRYPTSMAC_FP_H +#include "Tpm.h" + +UINT16 +CryptSmacStart( + HASH_STATE *state, + TPMU_PUBLIC_PARMS *keyParameters, + TPM_ALG_ID macAlg, + TPM2B *key + ); +UINT16 +CryptMacStart( + HMAC_STATE *state, + TPMU_PUBLIC_PARMS *keyParameters, + TPM_ALG_ID macAlg, + TPM2B *key + ); +UINT16 +CryptMacEnd( + HMAC_STATE *state, + UINT32 size, + BYTE *buffer + ); +UINT16 +CryptMacEnd( + HMAC_STATE *state, + UINT32 size, + BYTE *buffer + ); +UINT16 +CryptMacEnd2B ( + HMAC_STATE *state, + TPM2B *data + ); + +#endif diff --git a/src/tpm2/crypto/CryptSym.h b/src/tpm2/crypto/CryptSym.h new file mode 100644 index 0000000..66cfb97 --- /dev/null +++ b/src/tpm2/crypto/CryptSym.h @@ -0,0 +1,142 @@ +/********************************************************************************/ +/* */ +/* Implementation of the symmetric block cipher modes */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptSym.h 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2017 - 2021 */ +/* */ +/********************************************************************************/ + + +#ifndef CRYPTSYM_H +#define CRYPTSYM_H + +#if ALG_AES +# define IF_IMPLEMENTED_AES(op) op(AES, aes) +#else +# define IF_IMPLEMENTED_AES(op) +#endif +#if ALG_SM4 +# define IF_IMPLEMENTED_SM4(op) op(SM4, sm4) +#else +# define IF_IMPLEMENTED_SM4(op) +#endif +#if ALG_CAMELLIA +# define IF_IMPLEMENTED_CAMELLIA(op) op(CAMELLIA, camellia) +#else +# define IF_IMPLEMENTED_CAMELLIA(op) +#endif +#if ALG_TDES +# define IF_IMPLEMENTED_TDES(op) op(TDES, tdes) +#else +# define IF_IMPLEMENTED_TDES(op) +#endif + +#define FOR_EACH_SYM(op) \ + IF_IMPLEMENTED_AES(op) \ + IF_IMPLEMENTED_SM4(op) \ + IF_IMPLEMENTED_CAMELLIA(op) \ + IF_IMPLEMENTED_TDES(op) + + /* libtpms added begin */ +#define FOR_EACH_SYM_WITHOUT_TDES(op) \ + IF_IMPLEMENTED_AES(op) \ + IF_IMPLEMENTED_SM4(op) \ + IF_IMPLEMENTED_CAMELLIA(op) /* libtpms added end */ + +/* Macros for creating the key schedule union */ + +#define KEY_SCHEDULE(SYM, sym) tpmKeySchedule##SYM sym; +//#define TDES DES[3] /* libtpms commented */ +typedef union tpmCryptKeySchedule_t { + FOR_EACH_SYM_WITHOUT_TDES(KEY_SCHEDULE) /* libtpms changed from FOR_EACH_SYM */ + tpmKeyScheduleTDES tdes[3]; /* libtpms added */ + +#if SYMMETRIC_ALIGNMENT == 8 + uint64_t alignment; +#else + uint32_t alignment; +#endif +} tpmCryptKeySchedule_t; + +/* Each block cipher within a library is expected to conform to the same calling conventions with + three parameters (keySchedule, in, and out) in the same order. That means that all algorithms + would use the same order of the same parameters. The code is written assuming the (keySchedule, + in, and out) order. However, if the library uses a different order, the order can be changed with + a SWIZZLE macro that puts the parameters in the correct order. Note that all algorithms have to + use the same order and number of parameters because the code to build the calling list is common + for each call to encrypt or decrypt with the algorithm chosen by setting a function pointer to + select the algorithm that is used. */ +# define ENCRYPT(keySchedule, in, out) \ + encrypt(SWIZZLE(keySchedule, in, out)) +# define DECRYPT(keySchedule, in, out) \ + decrypt(SWIZZLE(keySchedule, in, out)) + +/* Note that the macros rely on encrypt as local values in the functions that use these + macros. Those parameters are set by the macro that set the key schedule to be used for the + call. */ + +#define ENCRYPT_CASE(ALG, alg) \ + case TPM_ALG_##ALG: \ + TpmCryptSetEncryptKey##ALG(key, keySizeInBits, &keySchedule.alg); \ + encrypt = (TpmCryptSetSymKeyCall_t)TpmCryptEncrypt##ALG; \ + break; +#define DECRYPT_CASE(ALG, alg) \ + case TPM_ALG_##ALG: \ + TpmCryptSetDecryptKey##ALG(key, keySizeInBits, &keySchedule.alg); \ + decrypt = (TpmCryptSetSymKeyCall_t)TpmCryptDecrypt##ALG; \ + break; + +#endif diff --git a/src/tpm2/crypto/CryptSym_fp.h b/src/tpm2/crypto/CryptSym_fp.h new file mode 100644 index 0000000..e78215f --- /dev/null +++ b/src/tpm2/crypto/CryptSym_fp.h @@ -0,0 +1,111 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptSym_fp.h 1047 2017-07-20 18:27:34Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTSYM_FP_H +#define CRYPTSYM_FP_H + +BOOL +CryptSymInit( + void + ); +BOOL +CryptSymStartup( + void + ); +LIB_EXPORT INT16 +CryptGetSymmetricBlockSize( + TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm + UINT16 keySizeInBits // IN: the key size + ); +LIB_EXPORT TPM_RC +CryptSymmetricEncrypt( + BYTE *dOut, // OUT: + TPM_ALG_ID algorithm, // IN: the symmetric algorithm + UINT16 keySizeInBits, // IN: key size in bits + const BYTE *key, // IN: key buffer. The size of this buffer + // in bytes is (keySizeInBits + 7) / 8 + TPM2B_IV *ivInOut, // IN/OUT: IV for decryption. + TPM_ALG_ID mode, // IN: Mode to use + INT32 dSize, // IN: data size (may need to be a + // multiple of the blockSize) + const BYTE *dIn // IN: data buffer + ); +LIB_EXPORT TPM_RC +CryptSymmetricDecrypt( + BYTE *dOut, // OUT: decrypted data + TPM_ALG_ID algorithm, // IN: the symmetric algorithm + UINT16 keySizeInBits, // IN: key size in bits + const BYTE *key, // IN: key buffer. The size of this buffer + // in bytes is (keySizeInBits + 7) / 8 + TPM2B_IV *ivInOut, // IN/OUT: IV for decryption. + TPM_ALG_ID mode, // IN: Mode to use + INT32 dSize, // IN: data size (may need to be a + // multiple of the blockSize) + const BYTE *dIn // IN: data buffer + ); +TPM_RC +CryptSymKeyValidate( + TPMT_SYM_DEF_OBJECT *symDef, + TPM2B_SYM_KEY *key + ); + + +#endif diff --git a/src/tpm2/crypto/CryptTest.h b/src/tpm2/crypto/CryptTest.h new file mode 100644 index 0000000..ce2321b --- /dev/null +++ b/src/tpm2/crypto/CryptTest.h @@ -0,0 +1,93 @@ +/********************************************************************************/ +/* */ +/* constant definitions used for self-test. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptTest.h 1594 2020-03-26 22:15:48Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTTEST_H +#define CRYPTTEST_H + +/* 10.1.7 CryptTest.h */ +/* This file contains constant definitions used for self test */ +/* This is the definition of a bit array with one bit per algorithm */ +/* NOTE: Since bit numbering starts at zero, when TPM_ALG_LAST is a multiple of 8, + ALGORITHM_VECTOR will need to have byte for the single bit in the last byte. So, for example, + when TPM_ALG_LAST is 8, ALGORITHM_VECTOR will need 2 bytes. */ +#define ALGORITHM_VECTOR_BYTES ((TPM_ALG_LAST + 8) / 8) +typedef BYTE ALGORITHM_VECTOR[ALGORITHM_VECTOR_BYTES]; +#ifdef TEST_SELF_TEST +LIB_EXPORT extern ALGORITHM_VECTOR LibToTest; +#endif +/* This structure is used to contain self-test tracking information for the cryptographic + modules. Each of the major modules is given a 32-bit value in which it may maintain its own self + test information. The convention for this state is that when all of the bits in this structure + are 0, all functions need to be tested. */ +typedef struct +{ + UINT32 rng; + UINT32 hash; + UINT32 sym; +#if ALG_RSA + UINT32 rsa; +#endif +#if ALG_ECC + UINT32 ecc; +#endif +} CRYPTO_SELF_TEST_STATE; +#endif // _CRYPT_TEST_H + diff --git a/src/tpm2/crypto/CryptUtil_fp.h b/src/tpm2/crypto/CryptUtil_fp.h new file mode 100644 index 0000000..2ca16e7 --- /dev/null +++ b/src/tpm2/crypto/CryptUtil_fp.h @@ -0,0 +1,232 @@ +/********************************************************************************/ +/* */ +/* Interfaces to the CryptoEngine */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptUtil_fp.h 1519 2019-11-15 20:43:51Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef CRYPTUTIL_FP_H +#define CRYPTUTIL_FP_H + +BOOL +CryptIsSchemeAnonymous( + TPM_ALG_ID scheme // IN: the scheme algorithm to test + ); +void +ParmDecryptSym( + TPM_ALG_ID symAlg, // IN: the symmetric algorithm + TPM_ALG_ID hash, // IN: hash algorithm for KDFa + UINT16 keySizeInBits, // IN: the key size in bits + TPM2B *key, // IN: KDF HMAC key + TPM2B *nonceCaller, // IN: nonce caller + TPM2B *nonceTpm, // IN: nonce TPM + UINT32 dataSize, // IN: size of parameter buffer + BYTE *data // OUT: buffer to be decrypted + ); +void +ParmEncryptSym( + TPM_ALG_ID symAlg, // IN: symmetric algorithm + TPM_ALG_ID hash, // IN: hash algorithm for KDFa + UINT16 keySizeInBits, // IN: AES key size in bits + TPM2B *key, // IN: KDF HMAC key + TPM2B *nonceCaller, // IN: nonce caller + TPM2B *nonceTpm, // IN: nonce TPM + UINT32 dataSize, // IN: size of parameter buffer + BYTE *data // OUT: buffer to be encrypted + ); +void +CryptXORObfuscation( + TPM_ALG_ID hash, // IN: hash algorithm for KDF + TPM2B *key, // IN: KDF key + TPM2B *contextU, // IN: contextU + TPM2B *contextV, // IN: contextV + UINT32 dataSize, // IN: size of data buffer + BYTE *data // IN/OUT: data to be XORed in place + ); +BOOL +CryptInit( + void + ); +BOOL +CryptStartup( + STARTUP_TYPE type // IN: the startup type + ); +BOOL +CryptIsAsymAlgorithm( + TPM_ALG_ID algID // IN: algorithm ID + ); +TPM_RC +CryptSecretEncrypt( + OBJECT *encryptKey, // IN: encryption key object + const TPM2B *label, // IN: a null-terminated string as L + TPM2B_DATA *data, // OUT: secret value + TPM2B_ENCRYPTED_SECRET *secret // OUT: secret structure + ); +TPM_RC +CryptSecretDecrypt( + OBJECT *decryptKey, // IN: decrypt key + TPM2B_NONCE *nonceCaller, // IN: nonceCaller. It is needed for + // symmetric decryption. For + // asymmetric decryption, this + // parameter is NULL + const TPM2B *label, // IN: a value for L + TPM2B_ENCRYPTED_SECRET *secret, // IN: input secret + TPM2B_DATA *data // OUT: decrypted secret value + ); +void +CryptParameterEncryption( + TPM_HANDLE handle, // IN: encrypt session handle + TPM2B *nonceCaller, // IN: nonce caller + UINT16 leadingSizeInByte, // IN: the size of the leading size field in + // bytes + TPM2B_AUTH *extraKey, // IN: additional key material other than + // sessionAuth + BYTE *buffer // IN/OUT: parameter buffer to be encrypted + ); +TPM_RC +CryptParameterDecryption( + TPM_HANDLE handle, // IN: encrypted session handle + TPM2B *nonceCaller, // IN: nonce caller + UINT32 bufferSize, // IN: size of parameter buffer + UINT16 leadingSizeInByte, // IN: the size of the leading size field in + // byte + TPM2B_AUTH *extraKey, // IN: the authValue + BYTE *buffer // IN/OUT: parameter buffer to be decrypted + ); +void +CryptComputeSymmetricUnique( + TPMT_PUBLIC *publicArea, // IN: the object's public area + TPMT_SENSITIVE *sensitive, // IN: the associated sensitive area + TPM2B_DIGEST *unique // OUT: unique buffer + ); +TPM_RC +CryptCreateObject( + OBJECT *object, // IN: new object structure pointer + TPMS_SENSITIVE_CREATE *sensitiveCreate, // IN: sensitive creation + RAND_STATE *rand // IN: the random number generator + // to use + ); +TPMI_ALG_HASH +CryptGetSignHashAlg( + TPMT_SIGNATURE *auth // IN: signature + ); +BOOL +CryptIsSplitSign( + TPM_ALG_ID scheme // IN: the algorithm selector + ); +BOOL +CryptIsAsymSignScheme( + TPMI_ALG_PUBLIC publicType, // IN: Type of the object + TPMI_ALG_ASYM_SCHEME scheme // IN: the scheme + ); +BOOL +CryptIsAsymDecryptScheme( + TPMI_ALG_PUBLIC publicType, // IN: Type of the object + TPMI_ALG_ASYM_SCHEME scheme // IN: the scheme + ); +BOOL +CryptSelectSignScheme( + OBJECT *signObject, // IN: signing key + TPMT_SIG_SCHEME *scheme // IN/OUT: signing scheme + ); +TPM_RC +CryptSign( + OBJECT *signKey, // IN: signing key + TPMT_SIG_SCHEME *signScheme, // IN: sign scheme. + TPM2B_DIGEST *digest, // IN: The digest being signed + TPMT_SIGNATURE *signature // OUT: signature + ); +TPM_RC +CryptValidateSignature( + TPMI_DH_OBJECT keyHandle, // IN: The handle of sign key + TPM2B_DIGEST *digest, // IN: The digest being validated + TPMT_SIGNATURE *signature // IN: signature + ); +TPM_RC +CryptGetTestResult( + TPM2B_MAX_BUFFER *outData // OUT: test result data + ); +TPM_RC +CryptValidateKeys( + TPMT_PUBLIC *publicArea, + TPMT_SENSITIVE *sensitive, + TPM_RC blamePublic, + TPM_RC blameSensitive + ); +TPM_RC +CryptSelectMac( + TPMT_PUBLIC *publicArea, + TPMI_ALG_MAC_SCHEME *inMac + ); +BOOL +CryptMacIsValidForKey( + TPM_ALG_ID keyType, + TPM_ALG_ID macAlg, + BOOL flag + ); +BOOL +CryptSmacIsValidAlg( + TPM_ALG_ID alg, + BOOL FLAG // IN: Indicates if TPM_ALG_NULL is valid + ); +BOOL +CryptSymModeIsValid( + TPM_ALG_ID mode, + BOOL flag + ); + +#endif diff --git a/src/tpm2/crypto/openssl/BnConvert_fp.h b/src/tpm2/crypto/openssl/BnConvert_fp.h new file mode 100644 index 0000000..dd60da0 --- /dev/null +++ b/src/tpm2/crypto/openssl/BnConvert_fp.h @@ -0,0 +1,108 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: BnConvert_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef BNCONVERT_FP_H +#define BNCONVERT_FP_H + +LIB_EXPORT bigNum +BnFromBytes( + bigNum bn, + const BYTE *bytes, + NUMBYTES nBytes + ); +LIB_EXPORT bigNum +BnFrom2B( + bigNum bn, // OUT: + const TPM2B *a2B // IN: number to convert + ); +LIB_EXPORT bigNum +BnFromHex( + bigNum bn, // OUT: + const char *hex // IN: + ); +LIB_EXPORT BOOL +BnToBytes( + bigConst bn, + BYTE *buffer, + NUMBYTES *size // This the number of bytes that are + // available in the buffer. The result + // should be this big. + ); +LIB_EXPORT BOOL +BnTo2B( + bigConst bn, // IN: + TPM2B *a2B, // OUT: + NUMBYTES size // IN: the desired size + ); +LIB_EXPORT bn_point_t * +BnPointFrom2B( + bigPoint ecP, // OUT: the preallocated point structure + TPMS_ECC_POINT *p // IN: the number to convert + ); +LIB_EXPORT BOOL +BnPointTo2B( + TPMS_ECC_POINT *p, // OUT: the converted 2B structure + bigPoint ecP, // IN: the values to be converted + bigCurve E // IN: curve descriptor for the point + ); + + +#endif diff --git a/src/tpm2/crypto/openssl/BnMath_fp.h b/src/tpm2/crypto/openssl/BnMath_fp.h new file mode 100644 index 0000000..62ba7b2 --- /dev/null +++ b/src/tpm2/crypto/openssl/BnMath_fp.h @@ -0,0 +1,163 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: BnMath_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef BNMATH_FP_H +#define BNMATH_FP_H + +LIB_EXPORT BOOL +BnAdd( + bigNum result, + bigConst op1, + bigConst op2 + ); +LIB_EXPORT BOOL +BnAddWord( + bigNum result, + bigConst op, + crypt_uword_t word + ); +LIB_EXPORT BOOL +BnSub( + bigNum result, + bigConst op1, + bigConst op2 + ); +LIB_EXPORT BOOL +BnSubWord( + bigNum result, + bigConst op, + crypt_uword_t word + ); +LIB_EXPORT int +BnUnsignedCmp( + bigConst op1, + bigConst op2 + ); +LIB_EXPORT int +BnUnsignedCmpWord( + bigConst op1, + crypt_uword_t word + ); +LIB_EXPORT crypt_word_t +BnModWord( + bigConst numerator, + crypt_word_t modulus + ); +LIB_EXPORT int +Msb( + crypt_uword_t word + ); +LIB_EXPORT int +BnMsb( + bigConst bn + ); +LIB_EXPORT unsigned +BnSizeInBits( + bigConst n + ); +LIB_EXPORT bigNum +BnSetWord( + bigNum n, + crypt_uword_t w + ); +LIB_EXPORT BOOL +BnSetBit( + bigNum bn, // IN/OUT: big number to modify + unsigned int bitNum // IN: Bit number to SET + ); +LIB_EXPORT BOOL +BnTestBit( + bigNum bn, // IN: number to check + unsigned int bitNum // IN: bit to test + ); +LIB_EXPORT BOOL +BnMaskBits( + bigNum bn, // IN/OUT: number to mask + crypt_uword_t maskBit // IN: the bit number for the mask. + ); +LIB_EXPORT BOOL +BnShiftRight( + bigNum result, + bigConst toShift, + uint32_t shiftAmount + ); +LIB_EXPORT BOOL +BnGetRandomBits( + bigNum n, + size_t bits, + RAND_STATE *rand + ); +LIB_EXPORT BOOL +BnGenerateRandomInRange( + bigNum dest, + bigConst limit, + RAND_STATE *rand + ); +// libtpms added begin +LIB_EXPORT BOOL +BnGenerateRandomInRangeAllBytes( + bigNum dest, + bigConst limit, + RAND_STATE *rand + ); +// libtpms added end + +#endif diff --git a/src/tpm2/crypto/openssl/BnMemory_fp.h b/src/tpm2/crypto/openssl/BnMemory_fp.h new file mode 100644 index 0000000..819a0a6 --- /dev/null +++ b/src/tpm2/crypto/openssl/BnMemory_fp.h @@ -0,0 +1,108 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: BnMemory_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef BNMEMORY_FP_H +#define BNMEMORY_FP_H + +LIB_EXPORT bigNum +BnSetTop( + bigNum bn, // IN/OUT: number to clean + crypt_uword_t top // IN: the new top + ); +#if 0 /* libtpms added */ +LIB_EXPORT bigNum +BnClearTop( + bigNum bn + ); +#endif /* libtpms added */ +LIB_EXPORT bigNum +BnInitializeWord( + bigNum bn, // IN: + crypt_uword_t allocated, // IN: + crypt_uword_t word // IN: + ); +LIB_EXPORT bigNum +BnInit( + bigNum bn, + crypt_uword_t allocated + ); +LIB_EXPORT BOOL +BnCopy( + bigNum out, + bigConst in + ); +#if 0 /* libtpms added */ +LIB_EXPORT BOOL +BnPointCopy( + bigPoint pOut, + pointConst pIn + ); +#endif /* libtpms added */ +LIB_EXPORT bn_point_t * +BnInitializePoint( + bigPoint p, // OUT: structure to receive pointers + bigNum x, // IN: x coordinate + bigNum y, // IN: y coordinate + bigNum z // IN: x coordinate + ); + + +#endif diff --git a/src/tpm2/crypto/openssl/BnValues.h b/src/tpm2/crypto/openssl/BnValues.h new file mode 100644 index 0000000..1e0164d --- /dev/null +++ b/src/tpm2/crypto/openssl/BnValues.h @@ -0,0 +1,329 @@ +/********************************************************************************/ +/* */ +/* For defining the internal BIGNUM structure */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: BnValues.h 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.1.1 BnValues.h */ +/* This file contains the definitions needed for defining the internal BIGNUM structure. A BIGNUM is + a pointer to a structure. The structure has three fields. The last field is and array (d) of + crypt_uword_t. Each word is in machine format (big- or little-endian) with the words in ascending + significance (i.e. words in little-endian order). This is the order that seems to be used in + every big number library in the worlds, so... */ +/* The first field in the structure (allocated) is the number of words in d. This is the upper limit + on the size of the number that can be held in the structure. This differs from libraries like + OpenSSL() as this is not intended to deal with numbers of arbitrary size; just numbers that are + needed to deal with the algorithms that are defined in the TPM implementation. */ +/* The second field in the structure (size) is the number of significant words in n. When this + number is zero, the number is zero. The word at used-1 should never be zero. All words between + d[size] and d[allocated-1] should be zero. */ +#ifndef _BN_NUMBERS_H +#define _BN_NUMBERS_H +#if RADIX_BITS == 64 +# define RADIX_LOG2 6 +#elif RADIX_BITS == 32 +#define RADIX_LOG2 5 +#else +# error "Unsupported radix" +#endif +#define RADIX_MOD(x) ((x) & ((1 << RADIX_LOG2) - 1)) +#define RADIX_DIV(x) ((x) >> RADIX_LOG2) +#define RADIX_MASK ((((crypt_uword_t)1) << RADIX_LOG2) - 1) +#define BITS_TO_CRYPT_WORDS(bits) RADIX_DIV((bits) + (RADIX_BITS - 1)) +#define BYTES_TO_CRYPT_WORDS(bytes) BITS_TO_CRYPT_WORDS(bytes * 8) +#define SIZE_IN_CRYPT_WORDS(thing) BYTES_TO_CRYPT_WORDS(sizeof(thing)) +#if RADIX_BITS == 64 +#define SWAP_CRYPT_WORD(x) REVERSE_ENDIAN_64(x) +typedef uint64_t crypt_uword_t; +typedef int64_t crypt_word_t; +# define TO_CRYPT_WORD_64 BIG_ENDIAN_BYTES_TO_UINT64 +# define TO_CRYPT_WORD_32(a, b, c, d) TO_CRYPT_WORD_64(0, 0, 0, 0, a, b, c, d) +#define BN_PAD 0 /* libtpms added */ +#elif RADIX_BITS == 32 +#define SWAP_CRYPT_WORD(x) REVERSE_ENDIAN_32((x)) +typedef uint32_t crypt_uword_t; +typedef int32_t crypt_word_t; +# define TO_CRYPT_WORD_64(a, b, c, d, e, f, g, h) \ + BIG_ENDIAN_BYTES_TO_UINT32(e, f, g, h), \ + BIG_ENDIAN_BYTES_TO_UINT32(a, b, c, d) +# define TO_CRYPT_WORD_32 BIG_ENDIAN_BYTES_TO_UINT32 +#define BN_PAD 1 /* libtpms added */ +#endif +#define MAX_CRYPT_UWORD (~((crypt_uword_t)0)) +#define MAX_CRYPT_WORD ((crypt_word_t)(MAX_CRYPT_UWORD >> 1)) +#define MIN_CRYPT_WORD (~MAX_CRYPT_WORD) +#define LARGEST_NUMBER (MAX((ALG_RSA * MAX_RSA_KEY_BYTES), \ + MAX((ALG_ECC * MAX_ECC_KEY_BYTES), MAX_DIGEST_SIZE))) +#define LARGEST_NUMBER_BITS (LARGEST_NUMBER * 8) +#define MAX_ECC_PARAMETER_BYTES (MAX_ECC_KEY_BYTES * ALG_ECC) +/* These are the basic big number formats. This is convertible to the library- specific format + without too much difficulty. For the math performed using these numbers, the value is always + positive. */ +#define BN_STRUCT_DEF(count) struct { \ + crypt_uword_t allocated; \ + crypt_uword_t size; \ + crypt_uword_t d[count + BN_PAD + BN_PAD + BN_PAD]; /* libtpms changed */ \ + } +typedef BN_STRUCT_DEF(1) bignum_t; +#ifndef bigNum +typedef bignum_t *bigNum; +typedef const bignum_t *bigConst; +#endif +extern const bignum_t BnConstZero; +/* The Functions to access the properties of a big number. Get number of allocated words */ +#define BnGetAllocated(x) (unsigned)((x)->allocated) +/* Get number of words used */ +#define BnGetSize(x) ((x)->size) +/* Get a pointer to the data array */ +#define BnGetArray(x) ((crypt_uword_t *)&((x)->d[0])) +/* Get the nth word of a BIGNUM (zero-based) */ +#define BnGetWord(x, i) (crypt_uword_t)((x)->d[i]) +/* Some things that are done often. Test to see if a bignum_t is equal to zero */ +#define BnEqualZero(bn) (BnGetSize(bn) == 0) +/* Test to see if a bignum_t is equal to a word type */ +#define BnEqualWord(bn, word) \ + ((BnGetSize(bn) == 1) && (BnGetWord(bn, 0) == (crypt_uword_t)word)) +/* Determine if a BIGNUM is even. A zero is even. Although the indication that a number is zero is + that its size is zero, all words of the number are 0 so this test works on zero. */ +#define BnIsEven(n) ((BnGetWord(n, 0) & 1) == 0) +/* The macros below are used to define BIGNUM values of the required size. The values are allocated + on the stack so they can be treated like simple local values. This will call the initialization + function for a defined bignum_t. This sets the allocated and used fields and clears the words of + n. */ +#define BN_INIT(name) \ + (bigNum)BnInit((bigNum)&(name), \ + BYTES_TO_CRYPT_WORDS(sizeof(name.d))) +/* In some cases, a function will need the address of the structure associated with a variable. The + structure for a BIGNUM variable of name is name_. Generally, when the structure is created, it is + initialized and a parameter is created with a pointer to the structure. The pointer has the name + and the structure it points to is name_ */ +#define BN_ADDRESS(name) (bigNum)&name##_ + +#define BN_CONST(name, words, initializer) \ + typedef const struct name##_type { \ + crypt_uword_t allocated; \ + crypt_uword_t size; \ + crypt_uword_t d[words < 1 ? 1 : words]; \ + } name##_type; \ + name##_type name = {(words < 1 ? 1 : words), words, {initializer}}; + +#define BN_STRUCT_ALLOCATION(bits) (BITS_TO_CRYPT_WORDS(bits) + 1) +/* Create a structure of the correct size. */ +#define BN_STRUCT(bits) \ + BN_STRUCT_DEF(BN_STRUCT_ALLOCATION(bits)) +/* Define a BIGNUM type with a specific allocation */ +#define BN_TYPE(name, bits) \ + typedef BN_STRUCT(bits) bn_##name##_t +/* This creates a local BIGNUM variable of a specific size and initializes it from a TPM2B input + parameter. */ +#define BN_INITIALIZED(name, bits, initializer) \ + BN_STRUCT(bits) name##_; \ + bigNum name = BnFrom2B(BN_INIT(name##_), \ + (const TPM2B *)initializer) +/* Create a local variable that can hold a number with bits */ +#define BN_VAR(name, bits) \ + BN_STRUCT(bits) _##name; \ + bigNum name = BN_INIT(_##name) +/* Create a type that can hold the largest number defined by the implementation. */ +#define BN_MAX(name) BN_VAR(name, LARGEST_NUMBER_BITS) +#define BN_MAX_INITIALIZED(name, initializer) \ + BN_INITIALIZED(name, LARGEST_NUMBER_BITS, initializer) +/* A word size value is useful */ +#define BN_WORD(name) BN_VAR(name, RADIX_BITS) +/* This is used to create a word-size BIGNUM and initialize it with an input parameter to a + function. */ +#define BN_WORD_INITIALIZED(name, initial) \ + BN_STRUCT(RADIX_BITS) name##_; \ + bigNum name = BnInitializeWord((bigNum)&name##_, \ + BN_STRUCT_ALLOCATION(RADIX_BITS), initial) +/* ECC-Specific Values This is the format for a point. It is always in affine format. The Z value is + carried as part of the point, primarily to simplify the interface to the support library. Rather + than have the interface layer have to create space for the point each time it is used... The x, + y, and z values are pointers to bigNum values and not in-line versions of the numbers. This is a + relic of the days when there was no standard TPM format for the numbers */ +typedef struct _bn_point_t +{ + bigNum x; + bigNum y; + bigNum z; +} bn_point_t; +typedef bn_point_t *bigPoint; +typedef const bn_point_t *pointConst; +typedef struct constant_point_t +{ + bigConst x; + bigConst y; + bigConst z; +} constant_point_t; +#define ECC_BITS (MAX_ECC_KEY_BYTES * 8) +BN_TYPE(ecc, ECC_BITS); +#define ECC_NUM(name) BN_VAR(name, ECC_BITS) +#define ECC_INITIALIZED(name, initializer) \ + BN_INITIALIZED(name, ECC_BITS, initializer) +#define POINT_INSTANCE(name, bits) \ + BN_STRUCT (bits) name##_x = \ + {BITS_TO_CRYPT_WORDS ( bits ), 0,{0}}; \ + BN_STRUCT ( bits ) name##_y = \ + {BITS_TO_CRYPT_WORDS ( bits ), 0,{0}}; \ + BN_STRUCT ( bits ) name##_z = \ + {BITS_TO_CRYPT_WORDS ( bits ), 0,{0}}; \ + bn_point_t name##_ +#define POINT_INITIALIZER(name) \ + BnInitializePoint(&name##_, (bigNum)&name##_x, \ + (bigNum)&name##_y, (bigNum)&name##_z) +#define POINT_INITIALIZED(name, initValue) \ + POINT_INSTANCE(name, MAX_ECC_KEY_BITS); \ + bigPoint name = BnPointFrom2B( \ + POINT_INITIALIZER(name), \ + initValue) +#define POINT_VAR(name, bits) \ + POINT_INSTANCE (name, bits); \ + bigPoint name = POINT_INITIALIZER(name) +#define POINT(name) POINT_VAR(name, MAX_ECC_KEY_BITS) +/* Structure for the curve parameters. This is an analog to the TPMS_ALGORITHM_DETAIL_ECC */ +typedef struct +{ + bigConst prime; // a prime number + bigConst order; // the order of the curve + bigConst h; // cofactor + bigConst a; // linear coefficient + bigConst b; // constant term + constant_point_t base; // base point +} ECC_CURVE_DATA; +/* Access macros for the ECC_CURVE structure. The parameter C is a pointer to an ECC_CURVE_DATA + structure. In some libraries, the curve structure contains a pointer to an ECC_CURVE_DATA + structure as well as some other bits. For those cases, the AccessCurveData() macro is used in the + code to first get the pointer to the ECC_CURVE_DATA for access. In some cases, the macro does + nothing. */ +#define CurveGetPrime(C) ((C)->prime) +#define CurveGetOrder(C) ((C)->order) +#define CurveGetCofactor(C) ((C)->h) +#define CurveGet_a(C) ((C)->a) +#define CurveGet_b(C) ((C)->b) +#define CurveGetG(C) ((pointConst)&((C)->base)) +#define CurveGetGx(C) ((C)->base.x) +#define CurveGetGy(C) ((C)->base.y) +/* Convert bytes in initializers according to the endianness of the system. This is used for + CryptEccData.c. */ +#define BIG_ENDIAN_BYTES_TO_UINT32(a, b, c, d) \ + ( ((UINT32)(a) << 24) \ + + ((UINT32)(b) << 16) \ + + ((UINT32)(c) << 8) \ + + ((UINT32)(d)) \ + ) +#define BIG_ENDIAN_BYTES_TO_UINT64(a, b, c, d, e, f, g, h) \ + ( ((UINT64)(a) << 56) \ + + ((UINT64)(b) << 48) \ + + ((UINT64)(c) << 40) \ + + ((UINT64)(d) << 32) \ + + ((UINT64)(e) << 24) \ + + ((UINT64)(f) << 16) \ + + ((UINT64)(g) << 8) \ + + ((UINT64)(h)) \ + ) + +#ifndef RADIX_BYTES +# if RADIX_BITS == 32 +# define RADIX_BYTES 4 +# elif RADIX_BITS == 64 +# define RADIX_BYTES 8 +# else +# error "RADIX_BITS must either be 32 or 64" +# endif +#endif + +/* These macros are used for data initialization of big number ECC constants These two macros + combine a macro for data definition with a macro for structure initialization. The a parameter is + a macro that gives numbers to each of the bytes of the initializer and defines where each of the + numberd bytes will show up in the final structure. The b value is a structure that contains the + requisite number of bytes in big endian order. S, the MJOIN and JOIND macros will combine a macro + defining a data layout with a macro defining the data to be places. Generally, these macros will + only need expansion when CryptEccData().c gets compiled. */ +#define JOINED(a,b) a b +#define MJOIN(a,b) a b + +#define B4_TO_BN(a, b, c, d) (((((a << 8) + b) << 8) + c) + d) +#if RADIX_BYTES == 64 +#define B8_TO_BN(a, b, c, d, e, f, g, h) \ + (UINT64)(((((((((((((((a) << 8) | b) << 8) | c) << 8) | d) << 8) \ + e) << 8) | f) << 8) | g) << 8) | h) +#define B1_TO_BN(a) B8_TO_BN(0, 0, 0, 0, 0, 0, 0, a) +#define B2_TO_BN(a, b) B8_TO_BN(0, 0, 0, 0, 0, 0, a, b) +#define B3_TO_BN(a, b, c) B8_TO_BN(0, 0, 0, 0, 0, a, b, c) +#define B4_TO_BN(a, b, c, d) B8_TO_BN(0, 0, 0, 0, a, b, c, d) +#define B5_TO_BN(a, b, c, d, e) B8_TO_BN(0, 0, 0, a, b, c, d, e) +#define B6_TO_BN(a, b, c, d, e, f) B8_TO_BN(0, 0, a, b, c, d, e, f) +#define B7_TO_BN(a, b, c, d, e, f, g) B8_TO_BN(0, a, b, c, d, e, f, g) +#else +#define B1_TO_BN(a) B4_TO_BN(0, 0, 0, a) +#define B2_TO_BN(a, b) B4_TO_BN(0, 0, a, b) +#define B3_TO_BN(a, b, c) B4_TO_BN(0, a, b, c) +#define B4_TO_BN(a, b, c, d) (((((a << 8) + b) << 8) + c) + d) +#define B5_TO_BN(a, b, c, d, e) B4_TO_BN(b, c, d, e), B1_TO_BN(a) +#define B6_TO_BN(a, b, c, d, e, f) B4_TO_BN(c, d, e, f), B2_TO_BN(a, b) +#define B7_TO_BN(a, b, c, d, e, f, g) B4_TO_BN(d, e, f, g), B3_TO_BN(a, b, c) +#define B8_TO_BN(a, b, c, d, e, f, g, h) B4_TO_BN(e, f, g, h), B4_TO_BN(a, b, c, d) + +#endif + +/* Add implementation dependent definitions for other ECC Values and for linkages */ + +#include LIB_INCLUDE(MATH_LIB, Math) + +#endif // _BN_NUMBERS_H + diff --git a/src/tpm2/crypto/openssl/ConsttimeUtils.h b/src/tpm2/crypto/openssl/ConsttimeUtils.h new file mode 100644 index 0000000..3364bee --- /dev/null +++ b/src/tpm2/crypto/openssl/ConsttimeUtils.h @@ -0,0 +1,117 @@ +/********************************************************************************/ +/* */ +/* Constant time debugging helper functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2020 */ +/* */ +/********************************************************************************/ + +#ifndef CONSTTIME_UTILS_H +#define CONSTTIME_UTILS_H + +#include <assert.h> +#include <stdio.h> + +#include "BnValues.h" + +#include <openssl/bn.h> + +static __inline__ unsigned long long rdtsc() { + unsigned long h, l; + + __asm__ __volatile__ ("rdtsc" : "=a"(l), "=d"(h)); + + return (unsigned long long)l | + ((unsigned long long)h << 32 ); +} + +// Make sure that the given BIGNUM has the given number of expected bytes. +// Skip over any leading zeros the BIGNUM may have. +static inline void assert_ossl_num_bytes(const BIGNUM *a, + unsigned int num_bytes, + int verbose, + const char *caller) { + unsigned char buffer[LARGEST_NUMBER] = { 0, }; + int len, i; + + len = BN_bn2bin(a, buffer); + for (i = 0; i < len; i++) { + if (buffer[i]) + break; + } + len -= i; + if (num_bytes != (unsigned int)len) { + printf("%s: Expected %u bytes but found %d (caller: %s)\n", __func__, num_bytes, len, caller); + } else { + if (verbose) + printf("%s: check passed; num_bytes = %d (caller: %s)\n",__func__, num_bytes, caller); + } + assert(num_bytes == (unsigned int)len); +} + +// Make sure that the bigNum has the expected number of bytes after it was +// converted to an OpenSSL BIGNUM. +static inline void assert_bn_ossl_num_bytes(bigNum tpmb, + unsigned int num_bytes, + int verbose, + const char *caller) { + BIG_INITIALIZED(osslb, tpmb); + + assert_ossl_num_bytes(osslb, num_bytes, verbose, caller); + + BN_free(osslb); +} + +#endif /* CONSTTIME_UTILS_H */ diff --git a/src/tpm2/crypto/openssl/CryptCmac.c b/src/tpm2/crypto/openssl/CryptCmac.c new file mode 100644 index 0000000..0461e78 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptCmac.c @@ -0,0 +1,210 @@ +/********************************************************************************/ +/* */ +/* Message Authentication Codes Based on a Symmetric Block Cipher */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptCmac.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2018 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.6 CryptCmac.c */ +/* 10.2.6.1 Introduction */ +/* This file contains the implementation of the message authentication codes based on a symmetric + block cipher. These functions only use the single block encryption functions of the selected + symmetric cryptographic library. */ +/* 10.2.6.2 Includes, Defines, and Typedefs */ +#define _CRYPT_HASH_C_ +#include "Tpm.h" +#include "CryptSym.h" +#if ALG_CMAC + /* 10.2.6.3 Functions */ + /* 10.2.6.3.1 CryptCmacStart() */ + /* This is the function to start the CMAC sequence operation. It initializes the dispatch + functions for the data and end operations for CMAC and initializes the parameters that are + used for the processing of data, including the key, key size and block cipher algorithm. */ +UINT16 +CryptCmacStart( + SMAC_STATE *state, + TPMU_PUBLIC_PARMS *keyParms, + TPM_ALG_ID macAlg, + TPM2B *key + ) +{ + tpmCmacState_t *cState = &state->state.cmac; + TPMT_SYM_DEF_OBJECT *def = &keyParms->symDetail.sym; + // + if(macAlg != TPM_ALG_CMAC) + return 0; + MemorySet(cState, 0, sizeof(*cState)); // libtpms bugfix + // set up the encryption algorithm and parameters + cState->symAlg = def->algorithm; + cState->keySizeBits = def->keyBits.sym; + cState->iv.t.size = CryptGetSymmetricBlockSize(def->algorithm, + def->keyBits.sym); + MemoryCopy2B(&cState->symKey.b, key, sizeof(cState->symKey.t.buffer)); + // Set up the dispatch methods for the CMAC + state->smacMethods.data = CryptCmacData; + state->smacMethods.end = CryptCmacEnd; + return cState->iv.t.size; +} + +/* 10.2.5.3.2 CryptCmacData() */ +/* This function is used to add data to the CMAC sequence computation. The function will XOR new + data into the IV. If the buffer is full, and there is additional input data, the data is + encrypted into the IV buffer, the new data is then XOR into the IV. When the data runs out, the + function returns without encrypting even if the buffer is full. The last data block of a sequence + will not be encrypted until the call to CryptCmacEnd(). This is to allow the proper subkey to be + computed and applied before the last block is encrypted. */ +void +CryptCmacData( + SMAC_STATES *state, + UINT32 size, + const BYTE *buffer + ) +{ + tpmCmacState_t *cmacState = &state->cmac; + TPM_ALG_ID algorithm = cmacState->symAlg; + BYTE *key = cmacState->symKey.t.buffer; + UINT16 keySizeInBits = cmacState->keySizeBits; + tpmCryptKeySchedule_t keySchedule; + TpmCryptSetSymKeyCall_t encrypt; + // + memset(&keySchedule, 0, sizeof(keySchedule)); /* libtpms added: coverity */ + // Set up the encryption values based on the algorithm + switch (algorithm) + { + FOR_EACH_SYM(ENCRYPT_CASE) + default: + FAIL(FATAL_ERROR_INTERNAL); + } + while(size > 0) + { + if(cmacState->bcount == cmacState->iv.t.size) + { + ENCRYPT(&keySchedule, cmacState->iv.t.buffer, cmacState->iv.t.buffer); + cmacState->bcount = 0; + } + for(;(size > 0) && (cmacState->bcount < cmacState->iv.t.size); + size--, cmacState->bcount++) + { + cmacState->iv.t.buffer[cmacState->bcount] ^= *buffer++; + } + } +} + +/* 10.2.6.3.3 CryptCmacEnd() */ +/* This is the completion function for the CMAC. It does padding, if needed, and selects the subkey + to be applied before the last block is encrypted. */ +UINT16 +CryptCmacEnd( + SMAC_STATES *state, + UINT32 outSize, + BYTE *outBuffer + ) +{ + tpmCmacState_t *cState = &state->cmac; + // Need to set algorithm, key, and keySizeInBits in the local context so that + // the SELECT and ENCRYPT macros will work here + TPM_ALG_ID algorithm = cState->symAlg; + BYTE *key = cState->symKey.t.buffer; + UINT16 keySizeInBits = cState->keySizeBits; + tpmCryptKeySchedule_t keySchedule; + TpmCryptSetSymKeyCall_t encrypt; + TPM2B_IV subkey = {{0, {0}}}; + BOOL xorVal; + UINT16 i; + memset(&keySchedule, 0, sizeof(keySchedule)); /* libtpms added: coverity */ + + subkey.t.size = cState->iv.t.size; + // Encrypt a block of zero + // Set up the encryption values based on the algorithm + switch (algorithm) + { + FOR_EACH_SYM(ENCRYPT_CASE) + default: + return 0; + } + ENCRYPT(&keySchedule, subkey.t.buffer, subkey.t.buffer); + + // shift left by 1 and XOR with 0x0...87 if the MSb was 0 + xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87; + ShiftLeft(&subkey.b); + subkey.t.buffer[subkey.t.size - 1] ^= xorVal; + // this is a sanity check to make sure that the algorithm is working properly. + // remove this check when debug is done + pAssert(cState->bcount <= cState->iv.t.size); + // If the buffer is full then no need to compute subkey 2. + if(cState->bcount < cState->iv.t.size) + { + //Pad the data + cState->iv.t.buffer[cState->bcount++] ^= 0x80; + // The rest of the data is a pad of zero which would simply be XORed + // with the iv value so nothing to do... + // Now compute K2 + xorVal = ((subkey.t.buffer[0] & 0x80) == 0) ? 0 : 0x87; + ShiftLeft(&subkey.b); + subkey.t.buffer[subkey.t.size - 1] ^= xorVal; + } + // XOR the subkey into the IV + for(i = 0; i < subkey.t.size; i++) + cState->iv.t.buffer[i] ^= subkey.t.buffer[i]; + ENCRYPT(&keySchedule, cState->iv.t.buffer, cState->iv.t.buffer); + i = (UINT16)MIN(cState->iv.t.size, outSize); + MemoryCopy(outBuffer, cState->iv.t.buffer, i); + + return i; +} + +#endif diff --git a/src/tpm2/crypto/openssl/CryptDes.c b/src/tpm2/crypto/openssl/CryptDes.c new file mode 100644 index 0000000..9efa3ce --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptDes.c @@ -0,0 +1,189 @@ +/********************************************************************************/ +/* */ +/* Functions Required for TDES */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptDes.c 1398 2018-12-17 22:37:57Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2018 */ +/* */ +/********************************************************************************/ + +/* 10.2.9 CryptDes.c */ +/* 10.2.9.1 Introduction */ +/* This file contains the extra functions required for TDES. */ +/* 10.2.9.2 Includes, Defines, and Typedefs */ +#include "Tpm.h" +#include "Helpers_fp.h" // libtpms added +#if ALG_TDES +#define DES_NUM_WEAK 64 +const UINT64 DesWeakKeys[DES_NUM_WEAK] = { + 0x0101010101010101ULL, 0xFEFEFEFEFEFEFEFEULL, 0xE0E0E0E0F1F1F1F1ULL, 0x1F1F1F1F0E0E0E0EULL, + 0x011F011F010E010EULL, 0x1F011F010E010E01ULL, 0x01E001E001F101F1ULL, 0xE001E001F101F101ULL, + 0x01FE01FE01FE01FEULL, 0xFE01FE01FE01FE01ULL, 0x1FE01FE00EF10EF1ULL, 0xE01FE01FF10EF10EULL, + 0x1FFE1FFE0EFE0EFEULL, 0xFE1FFE1FFE0EFE0EULL, 0xE0FEE0FEF1FEF1FEULL, 0xFEE0FEE0FEF1FEF1ULL, + 0x01011F1F01010E0EULL, 0x1F1F01010E0E0101ULL, 0xE0E01F1FF1F10E0EULL, 0x0101E0E00101F1F1ULL, + 0x1F1FE0E00E0EF1F1ULL, 0xE0E0FEFEF1F1FEFEULL, 0x0101FEFE0101FEFEULL, 0x1F1FFEFE0E0EFEFEULL, + 0xE0FE011FF1FE010EULL, 0x011F1F01010E0E01ULL, 0x1FE001FE0EF101FEULL, 0xE0FE1F01F1FE0E01ULL, + 0x011FE0FE010EF1FEULL, 0x1FE0E01F0EF1F10EULL, 0xE0FEFEE0F1FEFEF1ULL, 0x011FFEE0010EFEF1ULL, + 0x1FE0FE010EF1FE01ULL, 0xFE0101FEFE0101FEULL, 0x01E01FFE01F10EFEULL, 0x1FFE01E00EFE01F1ULL, + 0xFE011FE0FE010EF1ULL, 0xFE01E01FFE01F10EULL, 0x1FFEE0010EFEF101ULL, 0xFE1F01E0FE0E01F1ULL, + 0x01E0E00101F1F101ULL, 0x1FFEFE1F0EFEFE0EULL, 0xFE1FE001FE0EF101ULL, 0x01E0FE1F01F1FE0EULL, + 0xE00101E0F10101F1ULL, 0xFE1F1FFEFE0E0EFEULL, 0x01FE1FE001FE0EF1ULL, 0xE0011FFEF1010EFEULL, + 0xFEE0011FFEF1010EULL, 0x01FEE01F01FEF10EULL, 0xE001FE1FF101FE0EULL, 0xFEE01F01FEF10E01ULL, + 0x01FEFE0101FEFE01ULL, 0xE01F01FEF10E01FEULL, 0xFEE0E0FEFEF1F1FEULL, 0x1F01011F0E01010EULL, + 0xE01F1FE0F10E0EF1ULL, 0xFEFE0101FEFE0101ULL, 0x1F01E0FE0E01F1FEULL, 0xE01FFE01F10EFE01ULL, + 0xFEFE1F1FFEFE0E0EULL, 0x1F01FEE00E01FEF1ULL, 0xE0E00101F1F10101ULL, 0xFEFEE0E0FEFEF1F1ULL}; +/* 10.2.9.2.1 CryptSetOddByteParity() */ +/* This function sets the per byte parity of a 64-bit value. The least-significant bit is of each + byte is replaced with the odd parity of the other 7 bits in the byte. With odd parity, no byte + will ever be 0x00. */ +UINT64 +CryptSetOddByteParity( + UINT64 k + ) +{ +#define PMASK 0x0101010101010101ULL + UINT64 out; + k |= PMASK; // set the parity bit + out = k; + k ^= k >> 4; + k ^= k >> 2; + k ^= k >> 1; + k &= PMASK; // odd parity extracted + out ^= k; // out is now even parity because parity bit was already set + out ^= PMASK; // out is now even parity + return out; +} +/* 10.2.9.2.2 CryptDesIsWeakKey() */ +/* Check to see if a DES key is on the list of weak, semi-weak, or possibly weak keys. */ +/* Return Value Meaning */ +/* TRUE(1) DES key is weak */ +/* FALSE(0) DES key is not weak */ +static BOOL +CryptDesIsWeakKey( + UINT64 k + ) +{ + int i; + // + for(i = 0; i < DES_NUM_WEAK; i++) + { + if(k == DesWeakKeys[i]) + return TRUE; + } + return FALSE; +} +/* 10.2.9.2.3 CryptDesValidateKey() */ +/* Function to check to see if the input key is a valid DES key where the definition of valid is + that none of the elements are on the list of weak, semi-weak, or possibly weak keys; and that for + two keys, K1!=K2, and for three keys that K1!=K2 and K2!=K3. */ +BOOL +CryptDesValidateKey( + TPM2B_SYM_KEY *desKey // IN: key to validate + ) +{ + UINT64 k[3]; + int i; + int keys = (desKey->t.size + 7) / 8; + BYTE *pk = desKey->t.buffer; + BOOL ok; + // + // Note: 'keys' is the number of keys, not the maximum index for 'k' + ok = ((keys == 2) || (keys == 3)) && ((desKey->t.size % 8) == 0); + for(i = 0; ok && i < keys; pk += 8, i++) + { + k[i] = CryptSetOddByteParity(BYTE_ARRAY_TO_UINT64(pk)); + ok = !CryptDesIsWeakKey(k[i]); + } + ok = ok && k[0] != k[1]; + if(keys == 3) + ok = ok && k[1] != k[2]; + return ok; +} +/* 10.2.9.2.4 CryptGenerateKeyDes() */ +/* This function is used to create a DES key of the appropriate size. The key will have odd parity + in the bytes. */ +TPM_RC +CryptGenerateKeyDes( + TPMT_PUBLIC *publicArea, // IN/OUT: The public area template + // for the new key. + TPMT_SENSITIVE *sensitive, // OUT: sensitive area + RAND_STATE *rand // IN: the "entropy" source for + ) +{ + // Assume that the publicArea key size has been validated and is a supported + // number of bits. + sensitive->sensitive.sym.t.size = + BITS_TO_BYTES(publicArea->parameters.symDetail.sym.keyBits.sym); +#if USE_OPENSSL_FUNCTIONS_SYMMETRIC // libtpms added begin + if (rand == NULL) + return OpenSSLCryptGenerateKeyDes(sensitive); +#endif // libtpms added end + do + { + BYTE *pK = sensitive->sensitive.sym.t.buffer; + int i = (sensitive->sensitive.sym.t.size + 7) / 8; + // Use the random number generator to generate the required number of bits + if(DRBG_Generate(rand, pK, sensitive->sensitive.sym.t.size) == 0) + return TPM_RC_NO_RESULT; + for(; i > 0; pK += 8, i--) + { + UINT64 k = BYTE_ARRAY_TO_UINT64(pK); + k = CryptSetOddByteParity(k); + UINT64_TO_BYTE_ARRAY(k, pK); + } + } while(!CryptDesValidateKey(&sensitive->sensitive.sym)); + return TPM_RC_SUCCESS; +} +#endif diff --git a/src/tpm2/crypto/openssl/CryptEccKeyExchange.c b/src/tpm2/crypto/openssl/CryptEccKeyExchange.c new file mode 100644 index 0000000..4d1fccb --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptEccKeyExchange.c @@ -0,0 +1,373 @@ +/********************************************************************************/ +/* */ +/* Functions that are used for the two-phase, ECC, key-exchange protocols */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccKeyExchange.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.11 CryptEccKeyExchange.c */ +#include "Tpm.h" + +LIB_EXPORT TPM_RC +SM2KeyExchange( + TPMS_ECC_POINT *outZ, // OUT: the computed point + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPM2B_ECC_PARAMETER *dsAIn, // IN: static private TPM key + TPM2B_ECC_PARAMETER *deAIn, // IN: ephemeral private TPM key + TPMS_ECC_POINT *QsBIn, // IN: static public party B key + TPMS_ECC_POINT *QeBIn // IN: ephemeral public party B key + ); + +#if CC_ZGen_2Phase == YES +#if ALG_ECMQV +/* 10.2.11.1.1 avf1() */ +/* This function does the associated value computation required by MQV key exchange. Process: */ +/* a) Convert xQ to an integer xqi using the convention specified in Appendix C.3. */ +/* b) Calculate xqm = xqi mod 2^ceil(f/2) (where f = ceil(log2(n)). */ +/* c) Calculate the associate value function avf(Q) = xqm + 2ceil(f / 2) */ +/* Always returns TRUE(1). */ +static BOOL +avf1( + bigNum bnX, // IN/OUT: the reduced value + bigNum bnN // IN: the order of the curve + ) +{ + // compute f = 2^(ceil(ceil(log2(n)) / 2)) + int f = (BnSizeInBits(bnN) + 1) / 2; + // x' = 2^f + (x mod 2^f) + BnMaskBits(bnX, f); // This is mod 2*2^f but it doesn't matter because + // the next operation will SET the extra bit anyway + BnSetBit(bnX, f); + return TRUE; +} +/* 10.2.11.1.2 C_2_2_MQV() */ +/* This function performs the key exchange defined in SP800-56A 6.1.1.4 Full MQV, C(2, 2, ECC + MQV). */ +/* CAUTION: Implementation of this function may require use of essential claims in patents not owned + by TCG members. */ +/* Points QsB() and QeB() are required to be on the curve of inQsA. The function will fail, possibly + catastrophically, if this is not the case. */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT the value for dsA does not give a valid point on the curve */ +static TPM_RC +C_2_2_MQV( + TPMS_ECC_POINT *outZ, // OUT: the computed point + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key + TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key + TPMS_ECC_POINT *QsB, // IN: static public party B key + TPMS_ECC_POINT *QeB // IN: ephemeral public party B key + ) +{ + CURVE_INITIALIZED(E, curveId); + const ECC_CURVE_DATA *C; + POINT(pQeA); + POINT_INITIALIZED(pQeB, QeB); + POINT_INITIALIZED(pQsB, QsB); + ECC_NUM(bnTa); + ECC_INITIALIZED(bnDeA, deA); + ECC_INITIALIZED(bnDsA, dsA); + ECC_NUM(bnN); + ECC_NUM(bnXeB); + TPM_RC retVal; + // + // Parameter checks + if(E == NULL) + ERROR_RETURN(TPM_RC_VALUE); + pAssert(outZ != NULL && pQeB != NULL && pQsB != NULL && deA != NULL + && dsA != NULL); + C = AccessCurveData(E); + // Process: + // 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n. + // 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B). + // 3. If P = O, output an error indicator. + // 4. Z=xP, where xP is the x-coordinate of P. + // Compute the public ephemeral key pQeA = [de,A]G + if((retVal = BnPointMult(pQeA, CurveGetG(C), bnDeA, NULL, NULL, E)) + != TPM_RC_SUCCESS) + goto Exit; + // 1. implicitsigA = (de,A + avf(Qe,A)ds,A ) mod n. + // tA := (ds,A + de,A avf(Xe,A)) mod n (3) + // Compute 'tA' = ('deA' + 'dsA' avf('XeA')) mod n + // Ta = avf(XeA); + BnCopy(bnTa, pQeA->x); + avf1(bnTa, bnN); + // do Ta = ds,A * Ta mod n = dsA * avf(XeA) mod n + BnModMult(bnTa, bnDsA, bnTa, bnN); + // now Ta = deA + Ta mod n = deA + dsA * avf(XeA) mod n + BnAdd(bnTa, bnTa, bnDeA); + BnMod(bnTa, bnN); + // 2. P = h(implicitsigA)(Qe,B + avf(Qe,B)Qs,B). + // Put this in because almost every case of h is == 1 so skip the call when + // not necessary. + if(!BnEqualWord(CurveGetCofactor(C), 1)) + // Cofactor is not 1 so compute Ta := Ta * h mod n + BnModMult(bnTa, bnTa, CurveGetCofactor(C), CurveGetOrder(C)); + // Now that 'tA' is (h * 'tA' mod n) + // 'outZ' = (tA)(Qe,B + avf(Qe,B)Qs,B). + // first, compute XeB = avf(XeB) + avf1(bnXeB, bnN); + // QsB := [XeB]QsB + BnPointMult(pQsB, pQsB, bnXeB, NULL, NULL, E); + BnEccAdd(pQeB, pQeB, pQsB, E); + // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity + // If the result is not the point at infinity, return QeB + BnPointMult(pQeB, pQeB, bnTa, NULL, NULL, E); + if(BnEqualZero(pQeB->z)) + ERROR_RETURN(TPM_RC_NO_RESULT); + // Convert BIGNUM E to TPM2B E + BnPointTo2B(outZ, pQeB, E); + Exit: + CURVE_FREE(E); + return retVal; +} +#endif // ALG_ECMQV +/* 10.2.11.1.3 C_2_2_ECDH() */ +/* This function performs the two phase key exchange defined in SP800-56A, 6.1.1.2 Full Unified + Model, C(2, 2, ECC CDH). */ +static TPM_RC +C_2_2_ECDH( + TPMS_ECC_POINT *outZs, // OUT: Zs + TPMS_ECC_POINT *outZe, // OUT: Ze + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key + TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key + TPMS_ECC_POINT *QsB, // IN: static public party B key + TPMS_ECC_POINT *QeB // IN: ephemeral public party B key + ) +{ + CURVE_INITIALIZED(E, curveId); + ECC_INITIALIZED(bnAs, dsA); + ECC_INITIALIZED(bnAe, deA); + POINT_INITIALIZED(ecBs, QsB); + POINT_INITIALIZED(ecBe, QeB); + POINT(ecZ); + TPM_RC retVal; + // + // Parameter checks + if(E == NULL) + ERROR_RETURN(TPM_RC_CURVE); + pAssert(outZs != NULL && dsA != NULL && deA != NULL && QsB != NULL + && QeB != NULL); + // Do the point multiply for the Zs value ([dsA]QsB) + retVal = BnPointMult(ecZ, ecBs, bnAs, NULL, NULL, E); + if(retVal == TPM_RC_SUCCESS) + { + // Convert the Zs value. + BnPointTo2B(outZs, ecZ, E); + // Do the point multiply for the Ze value ([deA]QeB) + retVal = BnPointMult(ecZ, ecBe, bnAe, NULL, NULL, E); + if(retVal == TPM_RC_SUCCESS) + BnPointTo2B(outZe, ecZ, E); + } + Exit: + CURVE_FREE(E); + return retVal; +} +/* 10.2.11.1.4 CryptEcc2PhaseKeyExchange() */ +/* This function is the dispatch routine for the EC key exchange functions that use two ephemeral + and two static keys. */ +/* Error Returns Meaning */ +/* TPM_RC_SCHEME scheme is not defined */ +LIB_EXPORT TPM_RC +CryptEcc2PhaseKeyExchange( + TPMS_ECC_POINT *outZ1, // OUT: a computed point + TPMS_ECC_POINT *outZ2, // OUT: and optional second point + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPM_ALG_ID scheme, // IN: the key exchange scheme + TPM2B_ECC_PARAMETER *dsA, // IN: static private TPM key + TPM2B_ECC_PARAMETER *deA, // IN: ephemeral private TPM key + TPMS_ECC_POINT *QsB, // IN: static public party B key + TPMS_ECC_POINT *QeB // IN: ephemeral public party B key + ) +{ + pAssert(outZ1 != NULL + && dsA != NULL && deA != NULL + && QsB != NULL && QeB != NULL); + // Initialize the output points so that they are empty until one of the + // functions decides otherwise + outZ1->x.b.size = 0; + outZ1->y.b.size = 0; + if(outZ2 != NULL) + { + outZ2->x.b.size = 0; + outZ2->y.b.size = 0; + } + switch(scheme) + { + case TPM_ALG_ECDH: + return C_2_2_ECDH(outZ1, outZ2, curveId, dsA, deA, QsB, QeB); + break; +#if ALG_ECMQV + case TPM_ALG_ECMQV: + return C_2_2_MQV(outZ1, curveId, dsA, deA, QsB, QeB); + break; +#endif +#if ALG_SM2 + case TPM_ALG_SM2: + return SM2KeyExchange(outZ1, curveId, dsA, deA, QsB, QeB); + break; +#endif + default: + return TPM_RC_SCHEME; + } +} +#if ALG_SM2 +/* 10.2.11.1.5 ComputeWForSM2() */ +/* Compute the value for w used by SM2 */ +static UINT32 +ComputeWForSM2( + bigCurve E + ) +{ + // w := ceil(ceil(log2(n)) / 2) - 1 + return (BnMsb(CurveGetOrder(AccessCurveData(E))) / 2 - 1); +} +/* 10.2.11.1.6 avfSm2() */ +/* This function does the associated value computation required by SM2 key exchange. This is + different form the avf() in the international standards because it returns a value that is half + the size of the value returned by the standard avf. For example, if n is 15, Ws (w in the + standard) is 2 but the W here is 1. This means that an input value of 14 (1110b) would return a + value of 110b with the standard but 10b with the scheme in SM2. */ +static bigNum +avfSm2( + bigNum bn, // IN/OUT: the reduced value + UINT32 w // IN: the value of w + ) +{ + // a) set w := ceil(ceil(log2(n)) / 2) - 1 + // b) set x' := 2^w + ( x & (2^w - 1)) + // This is just like the avf for MQV where x' = 2^w + (x mod 2^w) + BnMaskBits(bn, w); // as with avf1, this is too big by a factor of 2 but + // it doesn't matter because we SET the extra bit + // anyway + BnSetBit(bn, w); + return bn; +} +/* SM2KeyExchange() This function performs the key exchange defined in SM2. The first step is to + compute tA = (dsA + deA avf(Xe,A)) mod n Then, compute the Z value from outZ = (h tA mod n) (QsA + + [avf(QeB().x)](QeB())). The function will compute the ephemeral public key from the ephemeral + private key. All points are required to be on the curve of inQsA. The function will fail + catastrophically if this is not the case */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT the value for dsA does not give a valid point on the curve */ +LIB_EXPORT TPM_RC +SM2KeyExchange( + TPMS_ECC_POINT *outZ, // OUT: the computed point + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPM2B_ECC_PARAMETER *dsAIn, // IN: static private TPM key + TPM2B_ECC_PARAMETER *deAIn, // IN: ephemeral private TPM key + TPMS_ECC_POINT *QsBIn, // IN: static public party B key + TPMS_ECC_POINT *QeBIn // IN: ephemeral public party B key + ) +{ + CURVE_INITIALIZED(E, curveId); + const ECC_CURVE_DATA *C; + ECC_INITIALIZED(dsA, dsAIn); + ECC_INITIALIZED(deA, deAIn); + POINT_INITIALIZED(QsB, QsBIn); + POINT_INITIALIZED(QeB, QeBIn); + BN_WORD_INITIALIZED(One, 1); + POINT(QeA); + ECC_NUM(XeB); + POINT(Z); + ECC_NUM(Ta); + UINT32 w; + TPM_RC retVal = TPM_RC_NO_RESULT; + // + // Parameter checks + if(E == NULL) + ERROR_RETURN(TPM_RC_CURVE); + C = AccessCurveData(E); + pAssert(outZ != NULL && dsA != NULL && deA != NULL && QsB != NULL + && QeB != NULL); + // Compute the value for w + w = ComputeWForSM2(E); + // Compute the public ephemeral key pQeA = [de,A]G + if(!BnEccModMult(QeA, CurveGetG(C), deA, E)) + goto Exit; + // tA := (ds,A + de,A avf(Xe,A)) mod n (3) + // Compute 'tA' = ('dsA' + 'deA' avf('XeA')) mod n + // Ta = avf(XeA); + // do Ta = de,A * Ta = deA * avf(XeA) + BnMult(Ta, deA, avfSm2(QeA->x, w)); + // now Ta = dsA + Ta = dsA + deA * avf(XeA) + BnAdd(Ta, dsA, Ta); + BnMod(Ta, CurveGetOrder(C)); + // outZ = [h tA mod n] (Qs,B + [avf(Xe,B)](Qe,B)) (4) + // Put this in because almost every case of h is == 1 so skip the call when + // not necessary. + if(!BnEqualWord(CurveGetCofactor(C), 1)) + // Cofactor is not 1 so compute Ta := Ta * h mod n + BnModMult(Ta, Ta, CurveGetCofactor(C), CurveGetOrder(C)); + // Now that 'tA' is (h * 'tA' mod n) + // 'outZ' = ['tA'](QsB + [avf(QeB.x)](QeB)). + BnCopy(XeB, QeB->x); + if(!BnEccModMult2(Z, QsB, One, QeB, avfSm2(XeB, w), E)) + goto Exit; + // QeB := [tA]QeB = [tA](QsB + [Xe,B]QeB) and check for at infinity + if(!BnEccModMult(Z, Z, Ta, E)) + goto Exit; + // Convert BIGNUM E to TPM2B E + BnPointTo2B(outZ, Z, E); + retVal = TPM_RC_SUCCESS; + Exit: + CURVE_FREE(E); + return retVal; +} +#endif +#endif // CC_ZGen_2Phase diff --git a/src/tpm2/crypto/openssl/CryptEccMain.c b/src/tpm2/crypto/openssl/CryptEccMain.c new file mode 100644 index 0000000..be92831 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptEccMain.c @@ -0,0 +1,866 @@ +/********************************************************************************/ +/* */ +/* ECC Main */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccMain.c 1519 2019-11-15 20:43:51Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +/* 10.2.11 CryptEccMain.c */ +/* 10.2.11.1 Includes and Defines */ +#include "Tpm.h" +#include "Helpers_fp.h" // libtpms added +#include "TpmToOsslMath_fp.h" // libtpms added +#if ALG_ECC +/* This version requires that the new format for ECC data be used */ +#if !USE_BN_ECC_DATA +#error "Need to SET USE_BN_ECC_DATA to YES in TpmBuildSwitches.h" +#endif +/* 10.2.11.2 Functions */ +#if SIMULATION +void +EccSimulationEnd( + void + ) +{ +#if SIMULATION + // put things to be printed at the end of the simulation here +#endif +} +#endif // SIMULATION +/* 10.2.11.2.1 CryptEccInit() */ +/* This function is called at _TPM_Init() */ +BOOL +CryptEccInit( + void + ) +{ + return TRUE; +} +/* 10.2.11.2.2 CryptEccStartup() */ +/* This function is called at TPM2_Startup(). */ +BOOL +CryptEccStartup( + void + ) +{ + return TRUE; +} +/* 10.2.11.2.3 ClearPoint2B(generic */ +/* Initialize the size values of a TPMS_ECC_POINT structure. */ +void +ClearPoint2B( + TPMS_ECC_POINT *p // IN: the point + ) +{ + if(p != NULL) + { + p->x.t.size = 0; + p->y.t.size = 0; + } +} +/* 10.2.11.2.4 CryptEccGetParametersByCurveId() */ +/* This function returns a pointer to the curve data that is associated with the indicated + curveId. If there is no curve with the indicated ID, the function returns NULL. This function is + in this module so that it can be called by GetCurve() data. */ +/* Return Values Meaning */ +/* NULL curve with the indicated TPM_ECC_CURVE is not implemented */ +/* non-NULL pointer to the curve data */ +LIB_EXPORT const ECC_CURVE * +CryptEccGetParametersByCurveId( + TPM_ECC_CURVE curveId // IN: the curveID + ) +{ + int i; + for(i = 0; i < ECC_CURVE_COUNT; i++) + { + if(eccCurves[i].curveId == curveId) + return &eccCurves[i]; + } + return NULL; +} +/* 10.2.11.2.5 CryptEccGetKeySizeForCurve() */ +/* This function returns the key size in bits of the indicated curve */ +LIB_EXPORT UINT16 +CryptEccGetKeySizeForCurve( + TPM_ECC_CURVE curveId // IN: the curve + ) +{ + const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); + UINT16 keySizeInBits; + // + keySizeInBits = (curve != NULL) ? curve->keySizeBits : 0; + return keySizeInBits; +} +/* 10.2.11.2.6 GetCurveData() */ +/* This function returns the a pointer for the parameter data associated with a curve. */ +const ECC_CURVE_DATA * +GetCurveData( + TPM_ECC_CURVE curveId // IN: the curveID + ) +{ + const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); + return (curve != NULL) ? curve->curveData : NULL; +} +/* 10.2.11.2.7 CryptEccGetOID() */ +const BYTE * +CryptEccGetOID( + TPM_ECC_CURVE curveId + ) +{ + const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); + return (curve != NULL) ? curve->OID : NULL; +} +/* 10.2.11.2.7 CryptEccGetCurveByIndex() */ +/* This function returns the number of the i-th implemented curve. The normal use would be to call + this function with i starting at 0. When the i is greater than or equal to the number of + implemented curves, TPM_ECC_NONE is returned. */ +LIB_EXPORT TPM_ECC_CURVE +CryptEccGetCurveByIndex( + UINT16 i + ) +{ + if(i >= ECC_CURVE_COUNT) + return TPM_ECC_NONE; + return eccCurves[i].curveId; +} +/* 10.2.11.2.8 CryptEccGetParameter() */ +/* This function returns an ECC curve parameter. The parameter is selected by a single character + designator from the set of {PNABXYH}. */ +/* Return Values Meaning */ +/* TRUE curve exists and parameter returned */ +/* FALSE curve does not exist or parameter selector */ +LIB_EXPORT BOOL +CryptEccGetParameter( + TPM2B_ECC_PARAMETER *out, // OUT: place to put parameter + char p, // IN: the parameter selector + TPM_ECC_CURVE curveId // IN: the curve id + ) +{ + const ECC_CURVE_DATA *curve = GetCurveData(curveId); + bigConst parameter = NULL; + if(curve != NULL) + { + switch(p) + { + case 'p': + parameter = CurveGetPrime(curve); + break; + case 'n': + parameter = CurveGetOrder(curve); + break; + case 'a': + parameter = CurveGet_a(curve); + break; + case 'b': + parameter = CurveGet_b(curve); + break; + case 'x': + parameter = CurveGetGx(curve); + break; + case 'y': + parameter = CurveGetGy(curve); + break; + case 'h': + parameter = CurveGetCofactor(curve); + break; + default: + FAIL(FATAL_ERROR_INTERNAL); + break; + } + } + // If not debugging and we get here with parameter still NULL, had better + // not try to convert so just return FALSE instead. + return (parameter != NULL) ? BnTo2B(parameter, &out->b, 0) : 0; +} +/* 10.2.11.2.9 CryptCapGetECCCurve() */ +/* This function returns the list of implemented ECC curves. */ +/* Return Values Meaning */ +/* YES if no more ECC curve is available */ +/* NO if there are more ECC curves not reported */ +TPMI_YES_NO +CryptCapGetECCCurve( + TPM_ECC_CURVE curveID, // IN: the starting ECC curve + UINT32 maxCount, // IN: count of returned curves + TPML_ECC_CURVE *curveList // OUT: ECC curve list + ) +{ + TPMI_YES_NO more = NO; + UINT16 i; + UINT32 count = ECC_CURVE_COUNT; + TPM_ECC_CURVE curve; + // Initialize output property list + curveList->count = 0; + // The maximum count of curves we may return is MAX_ECC_CURVES + if(maxCount > MAX_ECC_CURVES) maxCount = MAX_ECC_CURVES; + // Scan the eccCurveValues array + for(i = 0; i < count; i++) + { + curve = CryptEccGetCurveByIndex(i); + // If curveID is less than the starting curveID, skip it + if(curve < curveID) + continue; + if (!CryptEccIsCurveRuntimeUsable(curve)) // libtpms added: runtime filter supported curves + continue; + if(curveList->count < maxCount) + { + // If we have not filled up the return list, add more curves to + // it + curveList->eccCurves[curveList->count] = curve; + curveList->count++; + } + else + { + // If the return list is full but we still have curves + // available, report this and stop iterating + more = YES; + break; + } + } + return more; +} +/* 10.2.11.2.10 CryptGetCurveSignScheme() */ +/* This function will return a pointer to the scheme of the curve. */ +const TPMT_ECC_SCHEME * +CryptGetCurveSignScheme( + TPM_ECC_CURVE curveId // IN: The curve selector + ) +{ + const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); + if(curve != NULL) + return &(curve->sign); + else + return NULL; +} +/* 10.2.11.2.11 CryptGenerateR() */ +/* This function computes the commit random value for a split signing scheme. */ +/* If c is NULL, it indicates that r is being generated for TPM2_Commit(). If c is not NULL, the TPM + will validate that the gr.commitArray bit associated with the input value of c is SET. If not, + the TPM returns FALSE and no r value is generated. */ +/* Return Values Meaning */ +/* TRUE r value computed */ +/* FALSE no r value computed */ +BOOL +CryptGenerateR( + TPM2B_ECC_PARAMETER *r, // OUT: the generated random value + UINT16 *c, // IN/OUT: count value. + TPMI_ECC_CURVE curveID, // IN: the curve for the value + TPM2B_NAME *name // IN: optional name of a key to + // associate with 'r' + ) +{ + // This holds the marshaled g_commitCounter. + TPM2B_TYPE(8B, 8); + TPM2B_8B cntr = {{8,{0}}}; + UINT32 iterations; + TPM2B_ECC_PARAMETER n; + UINT64 currentCount = gr.commitCounter; + UINT16 t1; + // + if(!CryptEccGetParameter(&n, 'n', curveID)) + return FALSE; + // If this is the commit phase, use the current value of the commit counter + if(c != NULL) + { + // if the array bit is not set, can't use the value. + if(!TEST_BIT((*c & COMMIT_INDEX_MASK), gr.commitArray)) + return FALSE; + // If it is the sign phase, figure out what the counter value was + // when the commitment was made. + // + // When gr.commitArray has less than 64K bits, the extra + // bits of 'c' are used as a check to make sure that the + // signing operation is not using an out of range count value + t1 = (UINT16)currentCount; + // If the lower bits of c are greater or equal to the lower bits of t1 + // then the upper bits of t1 must be one more than the upper bits + // of c + if((*c & COMMIT_INDEX_MASK) >= (t1 & COMMIT_INDEX_MASK)) + // Since the counter is behind, reduce the current count + currentCount = currentCount - (COMMIT_INDEX_MASK + 1); + t1 = (UINT16)currentCount; + if((t1 & ~COMMIT_INDEX_MASK) != (*c & ~COMMIT_INDEX_MASK)) + return FALSE; + // set the counter to the value that was + // present when the commitment was made + currentCount = (currentCount & 0xffffffffffff0000ULL) | *c; /* libtpms changed */ + } + // Marshal the count value to a TPM2B buffer for the KDF + cntr.t.size = sizeof(currentCount); + UINT64_TO_BYTE_ARRAY(currentCount, cntr.t.buffer); + // Now can do the KDF to create the random value for the signing operation + // During the creation process, we may generate an r that does not meet the + // requirements of the random value. + // want to generate a new r. + r->t.size = n.t.size; + for(iterations = 1; iterations < 1000000;) + { + int i; + + CryptKDFa(CONTEXT_INTEGRITY_HASH_ALG, &gr.commitNonce.b, COMMIT_STRING, + (TPM2B *)name, &cntr.b, n.t.size * 8, // libtpms ubsan + r->t.buffer, &iterations, FALSE); // libtpms changed + + // "random" value must be less than the prime + if(UnsignedCompareB(r->b.size, r->b.buffer, n.t.size, n.t.buffer) >= 0) + continue; + + // in this implementation it is required that at least bit + // in the upper half of the number be set + for(i = n.t.size / 2; i >= 0; i--) + if(r->b.buffer[i] != 0) + return TRUE; + } + return FALSE; +} +/* 10.2.11.2.12 CryptCommit() */ +/* This function is called when the count value is committed. The gr.commitArray value associated + with the current count value is SET and g_commitCounter is incremented. The low-order 16 bits of + old value of the counter is returned. */ +UINT16 +CryptCommit( + void + ) +{ + UINT16 oldCount = (UINT16)gr.commitCounter; + gr.commitCounter++; + SET_BIT(oldCount & COMMIT_INDEX_MASK, gr.commitArray); + return oldCount; +} +/* 10.2.11.2.13 CryptEndCommit() */ +/* This function is called when the signing operation using the committed value is completed. It + clears the gr.commitArray bit associated with the count value so that it can't be used again. */ +void +CryptEndCommit( + UINT16 c // IN: the counter value of the commitment + ) +{ + ClearBit((c & COMMIT_INDEX_MASK), gr.commitArray, sizeof(gr.commitArray)); +} +/* 10.2.11.2.14 CryptEccGetParameters() */ +/* This function returns the ECC parameter details of the given curve */ +/* Return Values Meaning */ +/* TRUE success */ +/* FALSE unsupported ECC curve ID */ +BOOL +CryptEccGetParameters( + TPM_ECC_CURVE curveId, // IN: ECC curve ID + TPMS_ALGORITHM_DETAIL_ECC *parameters // OUT: ECC parameters + ) +{ + const ECC_CURVE *curve = CryptEccGetParametersByCurveId(curveId); + const ECC_CURVE_DATA *data; + BOOL found = curve != NULL; + if(found) + { + data = curve->curveData; + parameters->curveID = curve->curveId; + parameters->keySize = curve->keySizeBits; + parameters->kdf = curve->kdf; + parameters->sign = curve->sign; + /* BnTo2B(data->prime, ¶meters->p.b, 0); */ + BnTo2B(data->prime, ¶meters->p.b, parameters->p.t.size); + BnTo2B(data->a, ¶meters->a.b, parameters->p.t.size /* libtpms changed for HLK */); + BnTo2B(data->b, ¶meters->b.b, parameters->p.t.size /* libtpms changed for HLK */); + BnTo2B(data->base.x, ¶meters->gX.b, parameters->p.t.size); + BnTo2B(data->base.y, ¶meters->gY.b, parameters->p.t.size); + BnTo2B(data->order, ¶meters->n.b, 0); + BnTo2B(data->h, ¶meters->h.b, 0); + } + return found; +} +/* 10.2.11.2.15 BnGetCurvePrime() */ +/* This function is used to get just the prime modulus associated with a curve */ +const bignum_t * +BnGetCurvePrime( + TPM_ECC_CURVE curveId + ) +{ + const ECC_CURVE_DATA *C = GetCurveData(curveId); + return (C != NULL) ? CurveGetPrime(C) : NULL; +} +/* 10.2.11.2.16 BnGetCurveOrder() */ +/* This function is used to get just the curve order */ +const bignum_t * +BnGetCurveOrder( + TPM_ECC_CURVE curveId + ) +{ + const ECC_CURVE_DATA *C = GetCurveData(curveId); + return (C != NULL) ? CurveGetOrder(C) : NULL; +} +/* 10.2.11.2.17 BnIsOnCurve() */ +/* This function checks if a point is on the curve. */ +BOOL +BnIsOnCurve( + pointConst Q, + const ECC_CURVE_DATA *C + ) +{ + BN_VAR(right, (MAX_ECC_KEY_BITS * 3)); + BN_VAR(left, (MAX_ECC_KEY_BITS * 2)); + bigConst prime = CurveGetPrime(C); + // + // Show that point is on the curve y^2 = x^3 + ax + b; + // Or y^2 = x(x^2 + a) + b + // y^2 + BnMult(left, Q->y, Q->y); + BnMod(left, prime); + // x^2 + BnMult(right, Q->x, Q->x); + // x^2 + a + BnAdd(right, right, CurveGet_a(C)); + // BnMod(right, CurveGetPrime(C)); + // x(x^2 + a) + BnMult(right, right, Q->x); + // x(x^2 + a) + b + BnAdd(right, right, CurveGet_b(C)); + BnMod(right, prime); + if(BnUnsignedCmp(left, right) == 0) + return TRUE; + else + return FALSE; +} +/* 10.2.11.2.18 BnIsValidPrivateEcc() */ +/* Checks that 0 < x < q */ +BOOL +BnIsValidPrivateEcc( + bigConst x, // IN: private key to check + bigCurve E // IN: the curve to check + ) +{ + BOOL retVal; + retVal = (!BnEqualZero(x) + && (BnUnsignedCmp(x, CurveGetOrder(AccessCurveData(E))) < 0)); + return retVal; +} +LIB_EXPORT BOOL +CryptEccIsValidPrivateKey( + TPM2B_ECC_PARAMETER *d, + TPM_ECC_CURVE curveId + ) +{ + BN_INITIALIZED(bnD, MAX_ECC_PARAMETER_BYTES * 8, d); + return !BnEqualZero(bnD) && (BnUnsignedCmp(bnD, BnGetCurveOrder(curveId)) < 0); +} +/* 10.2.11.2.19 BnPointMul() */ +/* This function does a point multiply of the form R = [d]S + [u]Q where the parameters are bigNum + values. If S is NULL and d is not NULL, then it computes R = [d]G + [u]Q or just R = [d]G if u + and Q are NULL. If skipChecks is TRUE, then the function will not verify that the inputs are + correct for the domain. This would be the case when the values were created by the CryptoEngine() + code. It will return TPM_RC_NO_RESULT if the resulting point is the point at infinity. */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT result of multiplication is a point at infinity */ +/* TPM_RC_ECC_POINT S or Q is not on the curve */ +/* TPM_RC_VALUE d or u is not < n */ +TPM_RC +BnPointMult( + bigPoint R, // OUT: computed point + pointConst S, // IN: optional point to multiply by 'd' + bigConst d, // IN: scalar for [d]S or [d]G + pointConst Q, // IN: optional second point + bigConst u, // IN: optional second scalar + bigCurve E // IN: curve parameters + ) +{ + BOOL OK; + // + TEST(TPM_ALG_ECDH); + // Need one scalar + OK = (d != NULL || u != NULL); + // If S is present, then d has to be present. If S is not + // present, then d may or may not be present + OK = OK && (((S == NULL) == (d == NULL)) || (d != NULL)); + // either both u and Q have to be provided or neither can be provided (don't + // know what to do if only one is provided. + OK = OK && ((u == NULL) == (Q == NULL)); + OK = OK && (E != NULL); + if(!OK) + return TPM_RC_VALUE; + OK = (S == NULL) || BnIsOnCurve(S, AccessCurveData(E)); + OK = OK && ((Q == NULL) || BnIsOnCurve(Q, AccessCurveData(E))); + if(!OK) + return TPM_RC_ECC_POINT; + if((d != NULL) && (S == NULL)) + S = CurveGetG(AccessCurveData(E)); + // If only one scalar, don't need Shamir's trick + if((d == NULL) || (u == NULL)) + { + if(d == NULL) + OK = BnEccModMult(R, Q, u, E); + else + OK = BnEccModMult(R, S, d, E); + } + else + { + OK = BnEccModMult2(R, S, d, Q, u, E); + } + return (OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT); +} +/* 10.2.11.2.20 BnEccGetPrivate() */ +/* This function gets random values that are the size of the key plus 64 bits. The value is reduced + (mod (q - 1)) and incremented by 1 (q is the order of the curve. This produces a value (d) such + that 1 <= d < q. This is the method of FIPS 186-4 Section B.4.1 'Key Pair Generation Using Extra + Random Value Meaning */ +/* TRUE success */ +/* FALSE failure generating private key */ +#if !USE_OPENSSL_FUNCTIONS_EC // libtpms added +BOOL +BnEccGetPrivate( + bigNum dOut, // OUT: the qualified random value + const ECC_CURVE_DATA *C, // IN: curve for which the private key + // needs to be appropriate + RAND_STATE *rand // IN: state for DRBG + ) +{ + bigConst order = CurveGetOrder(C); + BOOL OK; + UINT32 orderBits = BnSizeInBits(order); + UINT32 orderBytes = BITS_TO_BYTES(orderBits); + BN_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64); + BN_VAR(nMinus1, MAX_ECC_KEY_BITS); + // + OK = BnGetRandomBits(bnExtraBits, (orderBytes * 8) + 64, rand); + OK = OK && BnSubWord(nMinus1, order, 1); + OK = OK && BnMod(bnExtraBits, nMinus1); + OK = OK && BnAddWord(dOut, bnExtraBits, 1); + return OK && !g_inFailureMode; +} +#else // libtpms added begin +BOOL +BnEccGetPrivate( + bigNum dOut, // OUT: the qualified random value + const ECC_CURVE_DATA *C, // IN: curve for which the private key + const EC_GROUP *G, // IN: the EC_GROUP to use; must be != NULL for rand == NULL + BOOL noLeadingZeros, // IN: require that all bytes in the private key be set + // result may not have leading zero bytes + // needs to be appropriate + RAND_STATE *rand // IN: state for DRBG + ) +{ + bigConst order = CurveGetOrder(C); + BOOL OK; + UINT32 orderBits = BnSizeInBits(order); + UINT32 orderBytes = BITS_TO_BYTES(orderBits); + UINT32 requestedBits = 0; + BN_VAR(bnExtraBits, MAX_ECC_KEY_BITS + 64); + BN_VAR(nMinus1, MAX_ECC_KEY_BITS); + + if (rand == NULL) { + if (noLeadingZeros) + requestedBits = orderBits; + + return OpenSSLEccGetPrivate(dOut, G, requestedBits); + } + + // + OK = BnGetRandomBits(bnExtraBits, (orderBytes * 8) + 64, rand); + OK = OK && BnSubWord(nMinus1, order, 1); + OK = OK && BnMod(bnExtraBits, nMinus1); + OK = OK && BnAddWord(dOut, bnExtraBits, 1); + return OK && !g_inFailureMode; +} +#endif // USE_OPENSSL_FUNCTIONS_EC libtpms added end +/* 10.2.11.2.21 BnEccGenerateKeyPair() */ +/* This function gets a private scalar from the source of random bits and does the point multiply to + get the public key. */ +#if !USE_OPENSSL_FUNCTIONS_EC // libtpms added + +BOOL +BnEccGenerateKeyPair( + bigNum bnD, // OUT: private scalar + bn_point_t *ecQ, // OUT: public point + bigCurve E, // IN: curve for the point + RAND_STATE *rand // IN: DRBG state to use + ) +{ + BOOL OK = FALSE; + // Get a private scalar + OK = BnEccGetPrivate(bnD, AccessCurveData(E), rand); + // Do a point multiply + OK = OK && BnEccModMult(ecQ, NULL, bnD, E); + if(!OK) + BnSetWord(ecQ->z, 0); + else + BnSetWord(ecQ->z, 1); + return OK; +} + +#else // libtpms added begin + +/* In this version of BnEccGenerateKeyPair we take a dual approach to constant + time requirements: For curves whose order is at the byte boundary, e.g. + NIST P224/P256/P384, we make sure that bnD has all bytes set (no leading zeros) + so that OpenSSL BIGNUM code will not reduce the number of bytes and the + subsequent BnEccModMult() would run faster for a shoter value. For all other + curves whose order is not at the byte boundary, e.g. NIST P521, we simply + always add the order of the curve to bnD and call BnEccModMult() with the + result bnD1, which leads to the same result. */ +BOOL +BnEccGenerateKeyPair( + bigNum bnD, // OUT: private scalar + bn_point_t *ecQ, // OUT: public point + bigCurve E, // IN: curve for the point + RAND_STATE *rand // IN: DRBG state to use + ) +{ + BOOL OK = FALSE; + bigConst order = CurveGetOrder(AccessCurveData(E)); + UINT32 orderBits = BnSizeInBits(order); + BOOL atByteBoundary = (orderBits & 7) == 0; + BOOL noLeadingZeros = atByteBoundary; + ECC_NUM(bnD1); + + // We request that bnD not have leading zeros if it is at byte-boundary, + // like for example it is the case for NIST P256. + OK = BnEccGetPrivate(bnD, AccessCurveData(E), E->G, noLeadingZeros, rand); + if (!atByteBoundary) { + // for NIST P521 we can add the order to bnD to ensure we have + // a constant amount of bytes; the result is the same as if we + // were doing the BnEccModMult() calculation with bnD. + OK = OK && BnAdd(bnD1, bnD, order); + OK = OK && BnEccModMult(ecQ, NULL, bnD1, E); + } else { + OK = OK && BnEccModMult(ecQ, NULL, bnD, E); + } + + if(!OK) + BnSetWord(ecQ->z, 0); + else + BnSetWord(ecQ->z, 1); + return OK; +} + +#endif // libtpms added end + +/* 10.2.11.2.21 CryptEccNewKeyPair */ +/* This function creates an ephemeral ECC. It is ephemeral in that is expected that the private part + of the key will be discarded */ +LIB_EXPORT TPM_RC +CryptEccNewKeyPair( + TPMS_ECC_POINT *Qout, // OUT: the public point + TPM2B_ECC_PARAMETER *dOut, // OUT: the private scalar + TPM_ECC_CURVE curveId // IN: the curve for the key + ) +{ + CURVE_INITIALIZED(E, curveId); + POINT(ecQ); + ECC_NUM(bnD); + BOOL OK; + if(E == NULL) + return TPM_RC_CURVE; + TEST(TPM_ALG_ECDH); + OK = BnEccGenerateKeyPair(bnD, ecQ, E, NULL); + if(OK) + { + BnPointTo2B(Qout, ecQ, E); + BnTo2B(bnD, &dOut->b, Qout->x.t.size); + } + else + { + Qout->x.t.size = Qout->y.t.size = dOut->t.size = 0; + } + CURVE_FREE(E); + return OK ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; +} +/* 10.2.11.2.22 CryptEccPointMultiply() */ +/* This function computes 'R := [dIn]G + [uIn]QIn. Where dIn and uIn are scalars, G and QIn are + points on the specified curve and G is the default generator of the curve. */ +/* The xOut and yOut parameters are optional and may be set to NULL if not used. */ +/* It is not necessary to provide uIn if QIn is specified but one of uIn and dIn must be + provided. If dIn and QIn are specified but uIn is not provided, then R = [dIn]QIn. */ +/* If the multiply produces the point at infinity, the TPM_RC_NO_RESULT is returned. */ +/* The sizes of xOut and yOut' will be set to be the size of the degree of the curve */ +/* It is a fatal error if dIn and uIn are both unspecified (NULL) or if Qin or Rout is + unspecified. */ +/* Error Returns Meaning */ +/* TPM_RC_ECC_POINT the point Pin or Qin is not on the curve */ +/* TPM_RC_NO_RESULT the product point is at infinity */ +/* TPM_RC_CURVE bad curve */ +/* TPM_RC_VALUE dIn or uIn out of range */ +LIB_EXPORT TPM_RC +CryptEccPointMultiply( + TPMS_ECC_POINT *Rout, // OUT: the product point R + TPM_ECC_CURVE curveId, // IN: the curve to use + TPMS_ECC_POINT *Pin, // IN: first point (can be null) + TPM2B_ECC_PARAMETER *dIn, // IN: scalar value for [dIn]Qin + // the Pin + TPMS_ECC_POINT *Qin, // IN: point Q + TPM2B_ECC_PARAMETER *uIn // IN: scalar value for the multiplier + // of Q + ) +{ + CURVE_INITIALIZED(E, curveId); + POINT_INITIALIZED(ecP, Pin); + ECC_INITIALIZED(bnD, dIn); // If dIn is null, then bnD is null + ECC_INITIALIZED(bnU, uIn); + POINT_INITIALIZED(ecQ, Qin); + POINT(ecR); + TPM_RC retVal; + // + retVal = BnPointMult(ecR, ecP, bnD, ecQ, bnU, E); + if(retVal == TPM_RC_SUCCESS) + BnPointTo2B(Rout, ecR, E); + else + ClearPoint2B(Rout); + CURVE_FREE(E); + return retVal; +} +/* 10.2.11.2.23 CryptEccIsPointOnCurve() */ +/* This function is used to test if a point is on a defined curve. It does this by checking that y^2 + mod p = x^3 + a*x + b mod p */ +/* It is a fatal error if Q is not specified (is NULL). */ +/* Return Values Meaning */ +/* TRUE point is on curve */ +/* FALSE point is not on curve or curve is not supported */ +LIB_EXPORT BOOL +CryptEccIsPointOnCurve( + TPM_ECC_CURVE curveId, // IN: the curve selector + TPMS_ECC_POINT *Qin // IN: the point. + ) +{ + const ECC_CURVE_DATA *C = GetCurveData(curveId); + POINT_INITIALIZED(ecQ, Qin); + BOOL OK; + // + pAssert(Qin != NULL); + OK = (C != NULL && (BnIsOnCurve(ecQ, C))); + return OK; +} +/* 10.2.11.2.24 CryptEccGenerateKey() */ +/* This function generates an ECC key pair based on the input parameters. This routine uses KDFa() + to produce candidate numbers. The method is according to FIPS 186-3, section B.1.2 "Key Pair + Generation by Testing Candidates." According to the method in FIPS 186-3, the resulting private + value d should be 1 <= d < n where n is the order of the base point. */ +/* It is a fatal error if Qout, dOut, is not provided (is NULL). */ +/* If the curve is not supported If seed is not provided, then a random number will be used for the + key */ +/* Error Returns Meaning */ +/* TPM_RC_CURVE curve is not supported */ +/* TPM_RC_NO_RESULT could not verify key with signature (FIPS only) */ +LIB_EXPORT TPM_RC +CryptEccGenerateKey( + TPMT_PUBLIC *publicArea, // IN/OUT: The public area template for + // the new key. The public key + // area will be replaced computed + // ECC public key + TPMT_SENSITIVE *sensitive, // OUT: the sensitive area will be + // updated to contain the private + // ECC key and the symmetric + // encryption key + RAND_STATE *rand // IN: if not NULL, the deterministic + // RNG state + ) +{ + CURVE_INITIALIZED(E, publicArea->parameters.eccDetail.curveID); + ECC_NUM(bnD); + POINT(ecQ); + BOOL OK; + TPM_RC retVal; + TEST(TPM_ALG_ECDSA); // ECDSA is used to verify each key + // Validate parameters + if(E == NULL) + ERROR_RETURN(TPM_RC_CURVE); + publicArea->unique.ecc.x.t.size = 0; + publicArea->unique.ecc.y.t.size = 0; + sensitive->sensitive.ecc.t.size = 0; + OK = BnEccGenerateKeyPair(bnD, ecQ, E, rand); + if(OK) + { + BnPointTo2B(&publicArea->unique.ecc, ecQ, E); + BnTo2B(bnD, &sensitive->sensitive.ecc.b, publicArea->unique.ecc.x.t.size); + } +#if FIPS_COMPLIANT + // See if PWCT is required + if(OK && (IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign))) + { + ECC_NUM(bnT); + ECC_NUM(bnS); + TPM2B_DIGEST digest; + TEST(TPM_ALG_ECDSA); + digest.t.size = MIN(sensitive->sensitive.ecc.t.size, sizeof(digest.t.buffer)); + // Get a random value to sign using the built in DRBG state + DRBG_Generate(NULL, digest.t.buffer, digest.t.size); + if(g_inFailureMode) + return TPM_RC_FAILURE; + BnSignEcdsa(bnT, bnS, E, bnD, &digest, NULL); + // and make sure that we can validate the signature + OK = BnValidateSignatureEcdsa(bnT, bnS, E, ecQ, &digest) == TPM_RC_SUCCESS; + } +#endif + retVal = (OK) ? TPM_RC_SUCCESS : TPM_RC_NO_RESULT; + Exit: + CURVE_FREE(E); + return retVal; +} + +// libtpms added begin +// Support for some curves may be compiled in but they may not be +// supported by openssl's crypto library. +LIB_EXPORT BOOL +CryptEccIsCurveRuntimeUsable( + TPMI_ECC_CURVE curveId + ) +{ + CURVE_INITIALIZED(E, curveId); + if (E == NULL) + return FALSE; + CURVE_FREE(E); + return TRUE; +} +// libtpms added end + +#endif // TPM_ALG_ECC diff --git a/src/tpm2/crypto/openssl/CryptEccSignature.c b/src/tpm2/crypto/openssl/CryptEccSignature.c new file mode 100644 index 0000000..a325a46 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptEccSignature.c @@ -0,0 +1,1043 @@ +/********************************************************************************/ +/* */ +/* ECC Signatures */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptEccSignature.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.12 CryptEccSignature.c */ +/* 10.2.12.1 Includes and Defines */ +#include "Tpm.h" +#include "CryptEccSignature_fp.h" +#include "TpmToOsslMath_fp.h" // libtpms added +#if ALG_ECC +/* 10.2.12.2 Utility Functions */ +/* 10.2.12.2.1 EcdsaDigest() */ +/* Function to adjust the digest so that it is no larger than the order of the curve. This is used + for ECDSA sign and verification. */ +#if !USE_OPENSSL_FUNCTIONS_ECDSA // libtpms added +static bigNum +EcdsaDigest( + bigNum bnD, // OUT: the adjusted digest + const TPM2B_DIGEST *digest, // IN: digest to adjust + bigConst max // IN: value that indicates the maximum + // number of bits in the results + ) +{ + int bitsInMax = BnSizeInBits(max); + int shift; + // + if(digest == NULL) + BnSetWord(bnD, 0); + else + { + BnFromBytes(bnD, digest->t.buffer, + (NUMBYTES)MIN(digest->t.size, BITS_TO_BYTES(bitsInMax))); + shift = BnSizeInBits(bnD) - bitsInMax; + if(shift > 0) + BnShiftRight(bnD, bnD, shift); + } + return bnD; +} +#endif // libtpms added +/* 10.2.12.2.2 BnSchnorrSign() */ +/* This contains the Schnorr signature computation. It is used by both ECDSA and Schnorr + signing. The result is computed as: [s = k + r * d (mod n)] where */ +/* a) s is the signature */ +/* b) k is a random value */ +/* c) r is the value to sign */ +/* d) d is the private EC key */ +/* e) n is the order of the curve */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT the result of the operation was zero or r (mod n) is zero */ +static TPM_RC +BnSchnorrSign( + bigNum bnS, // OUT: s component of the signature + bigConst bnK, // IN: a random value + bigNum bnR, // IN: the signature 'r' value + bigConst bnD, // IN: the private key + bigConst bnN // IN: the order of the curve + ) +{ + // Need a local temp value to store the intermediate computation because product + // size can be larger than will fit in bnS. + BN_VAR(bnT1, MAX_ECC_PARAMETER_BYTES * 2 * 8); + // + // Reduce bnR without changing the input value + BnDiv(NULL, bnT1, bnR, bnN); + if(BnEqualZero(bnT1)) + return TPM_RC_NO_RESULT; + // compute s = (k + r * d)(mod n) + // r * d + BnMult(bnT1, bnT1, bnD); + // k * r * d + BnAdd(bnT1, bnT1, bnK); + // k + r * d (mod n) + BnDiv(NULL, bnS, bnT1, bnN); + return (BnEqualZero(bnS)) ? TPM_RC_NO_RESULT : TPM_RC_SUCCESS; +} +/* 10.2.12.3 Signing Functions */ +/* 10.2.12.3.1 BnSignEcdsa() */ +/* This function implements the ECDSA signing algorithm. The method is described in the comments + below. This version works with internal numbers. */ +#if !USE_OPENSSL_FUNCTIONS_ECDSA // libtpms added +TPM_RC +BnSignEcdsa( + bigNum bnR, // OUT: r component of the signature + bigNum bnS, // OUT: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bigNum bnD, // IN: private signing key + const TPM2B_DIGEST *digest, // IN: the digest to sign + RAND_STATE *rand // IN: used in debug of signing + ) +{ + ECC_NUM(bnK); + ECC_NUM(bnIk); + BN_VAR(bnE, MAX(MAX_ECC_KEY_BYTES, MAX_DIGEST_SIZE) * 8); + POINT(ecR); + bigConst order = CurveGetOrder(AccessCurveData(E)); + TPM_RC retVal = TPM_RC_SUCCESS; + INT32 tries = 10; + BOOL OK = FALSE; + // + pAssert(digest != NULL); + // The algorithm as described in "Suite B Implementer's Guide to FIPS + // 186-3(ECDSA)" + // 1. Use one of the routines in Appendix A.2 to generate (k, k^-1), a + // per-message secret number and its inverse modulo n. Since n is prime, + // the output will be invalid only if there is a failure in the RBG. + // 2. Compute the elliptic curve point R = [k]G = (xR, yR) using EC scalar + // multiplication (see [Routines]), where G is the base point included in + // the set of domain parameters. + // 3. Compute r = xR mod n. If r = 0, then return to Step 1. 1. + // 4. Use the selected hash function to compute H = Hash(M). + // 5. Convert the bit string H to an integer e as described in Appendix B.2. + // 6. Compute s = (k^-1 * (e + d * r)) mod q. If s = 0, return to Step 1.2. + // 7. Return (r, s). + // In the code below, q is n (that it, the order of the curve is p) + do // This implements the loop at step 6. If s is zero, start over. + { + for(; tries > 0; tries--) + { + // Step 1 and 2 -- generate an ephemeral key and the modular inverse + // of the private key. + if(!BnEccGenerateKeyPair(bnK, ecR, E, rand)) + continue; + // x coordinate is mod p. Make it mod q + BnMod(ecR->x, order); + // Make sure that it is not zero; + if(BnEqualZero(ecR->x)) + continue; + // write the modular reduced version of r as part of the signature + BnCopy(bnR, ecR->x); + // Make sure that a modular inverse exists and try again if not + OK = (BnModInverse(bnIk, bnK, order)); + if(OK) + break; + } + if(!OK) + goto Exit; + EcdsaDigest(bnE, digest, order); + // now have inverse of K (bnIk), e (bnE), r (bnR), d (bnD) and + // CurveGetOrder(E) + // Compute s = k^-1 (e + r*d)(mod q) + // first do s = r*d mod q + BnModMult(bnS, bnR, bnD, order); + // s = e + s = e + r * d + BnAdd(bnS, bnE, bnS); + // s = k^(-1)s (mod n) = k^(-1)(e + r * d)(mod n) + BnModMult(bnS, bnIk, bnS, order); + // If S is zero, try again + } while(BnEqualZero(bnS)); + Exit: + return retVal; +} +#else // !USE_OPENSSL_FUNCTIONS_ECDSA libtpms added begin +TPM_RC +BnSignEcdsa( + bigNum bnR, // OUT: r component of the signature + bigNum bnS, // OUT: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bigNum bnD, // IN: private signing key + const TPM2B_DIGEST *digest, // IN: the digest to sign + RAND_STATE *rand // IN: used in debug of signing + ) +{ + ECDSA_SIG *sig = NULL; + EC_KEY *eckey; + int retVal; + const BIGNUM *r; + const BIGNUM *s; + BIGNUM *d = BN_new(); + + d = BigInitialized(d, bnD); + + eckey = EC_KEY_new(); + + if (d == NULL || eckey == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EC_KEY_set_group(eckey, E->G) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EC_KEY_set_private_key(eckey, d) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + sig = ECDSA_do_sign(digest->b.buffer, digest->b.size, eckey); + if (sig == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + ECDSA_SIG_get0(sig, &r, &s); + OsslToTpmBn(bnR, r); + OsslToTpmBn(bnS, s); + + retVal = TPM_RC_SUCCESS; + + Exit: + BN_clear_free(d); + EC_KEY_free(eckey); + ECDSA_SIG_free(sig); + + return retVal; +} +#endif // USE_OPENSSL_FUNCTIONS_ECDSA libtpms added end +#if ALG_ECDAA +/* 10.2.12.3.2 BnSignEcdaa() */ +/* This function performs s = r + T * d mod q where */ +/* a) 'r is a random, or pseudo-random value created in the commit phase */ +/* b) nonceK is a TPM-generated, random value 0 < nonceK < n */ +/* c) T is mod q of Hash(nonceK || digest), and */ +/* d) d is a private key. */ +/* The signature is the tuple (nonceK, s) */ +/* Regrettably, the parameters in this function kind of collide with the parameter names used in + ECSCHNORR making for a lot of confusion. In particular, the k value in this function is value in + this function u */ +/* Error Returns Meaning */ +/* TPM_RC_SCHEME unsupported hash algorithm */ +/* TPM_RC_NO_RESULT cannot get values from random number generator */ +static TPM_RC +BnSignEcdaa( + TPM2B_ECC_PARAMETER *nonceK, // OUT: nonce component of the signature + bigNum bnS, // OUT: s component of the signature + bigCurve E, // IN: the curve used in signing + bigNum bnD, // IN: the private key + const TPM2B_DIGEST *digest, // IN: the value to sign (mod q) + TPMT_ECC_SCHEME *scheme, // IN: signing scheme (contains the + // commit count value). + OBJECT *eccKey, // IN: The signing key + RAND_STATE *rand // IN: a random number state + ) +{ + TPM_RC retVal; + TPM2B_ECC_PARAMETER r; + HASH_STATE state; + TPM2B_DIGEST T; + BN_MAX(bnT); + // + NOT_REFERENCED(rand); + if(!CryptGenerateR(&r, &scheme->details.ecdaa.count, + eccKey->publicArea.parameters.eccDetail.curveID, + &eccKey->name)) + retVal = TPM_RC_VALUE; + else + { + // This allocation is here because 'r' doesn't have a value until + // CrypGenerateR() is done. + ECC_INITIALIZED(bnR, &r); + do + { + // generate nonceK such that 0 < nonceK < n + // use bnT as a temp. +#if USE_OPENSSL_FUNCTIONS_EC // libtpms added begin + if(!BnEccGetPrivate(bnT, AccessCurveData(E), E->G, false, rand)) +#else // libtpms added end + if(!BnEccGetPrivate(bnT, AccessCurveData(E), rand)) +#endif // libtpms added + { + retVal = TPM_RC_NO_RESULT; + break; + } + BnTo2B(bnT, &nonceK->b, 0); + T.t.size = CryptHashStart(&state, scheme->details.ecdaa.hashAlg); + if(T.t.size == 0) + { + retVal = TPM_RC_SCHEME; + } + else + { + CryptDigestUpdate2B(&state, &nonceK->b); + CryptDigestUpdate2B(&state, &digest->b); + CryptHashEnd2B(&state, &T.b); + BnFrom2B(bnT, &T.b); + // libtpms: Note: T is NOT a concern for constant-timeness + // Watch out for the name collisions in this call!! + retVal = BnSchnorrSign(bnS, bnR, bnT, bnD, + AccessCurveData(E)->order); + } + } while(retVal == TPM_RC_NO_RESULT); + // Because the rule is that internal state is not modified if the command + // fails, only end the commit if the command succeeds. + // NOTE that if the result of the Schnorr computation was zero + // it will probably not be worthwhile to run the same command again because + // the result will still be zero. This means that the Commit command will + // need to be run again to get a new commit value for the signature. + if(retVal == TPM_RC_SUCCESS) + CryptEndCommit(scheme->details.ecdaa.count); + } + return retVal; +} +#endif // ALG_ECDAA +#if ALG_ECSCHNORR +/* 10.2.12.3.3 SchnorrReduce() */ +/* Function to reduce a hash result if it's magnitude is to large. The size of number is set so that + it has no more bytes of significance than the reference value. If the resulting number can have + more bits of significance than the reference. */ +static void +SchnorrReduce( + TPM2B *number, // IN/OUT: Value to reduce + bigConst reference // IN: the reference value + ) +{ + UINT16 maxBytes = (UINT16)BITS_TO_BYTES(BnSizeInBits(reference)); + if(number->size > maxBytes) + number->size = maxBytes; +} +/* 10.2.12.3.4 SchnorrEcc() */ +/* This function is used to perform a modified Schnorr signature. */ +/* This function will generate a random value k and compute */ +/* a) (xR, yR) = [k]G */ +/* b) r = hash(xR || P)(mod q) */ +/* c) rT = truncated r */ +/* d) s= k + rT * ds (mod q) */ +/* e) return the tuple rT, s */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT failure in the Schnorr sign process */ +/* TPM_RC_SCHEME hashAlg can't produce zero-length digest */ +static TPM_RC +BnSignEcSchnorr( + bigNum bnR, // OUT: r component of the signature + bigNum bnS, // OUT: s component of the signature + bigCurve E, // IN: the curve used in signing + bigNum bnD, // IN: the signing key + const TPM2B_DIGEST *digest, // IN: the digest to sign + TPM_ALG_ID hashAlg, // IN: signing scheme (contains a hash) + RAND_STATE *rand // IN: non-NULL when testing + ) +{ + HASH_STATE hashState; + UINT16 digestSize + = CryptHashGetDigestSize(hashAlg); + TPM2B_TYPE(T, MAX(MAX_DIGEST_SIZE, MAX_ECC_KEY_BYTES)); + TPM2B_T T2b; + TPM2B *e = &T2b.b; + TPM_RC retVal = TPM_RC_NO_RESULT; + const ECC_CURVE_DATA *C; + bigConst order; + bigConst prime; + ECC_NUM(bnK); + POINT(ecR); + // + // Parameter checks + if(E == NULL) + ERROR_RETURN(TPM_RC_VALUE); + C = AccessCurveData(E); + order = CurveGetOrder(C); + prime = CurveGetOrder(C); + // If the digest does not produce a hash, then null the signature and return + // a failure. + if(digestSize == 0) + { + BnSetWord(bnR, 0); + BnSetWord(bnS, 0); + ERROR_RETURN(TPM_RC_SCHEME); + } + do + { + // Generate a random key pair + if(!BnEccGenerateKeyPair(bnK, ecR, E, rand)) + break; + // Convert R.x to a string + BnTo2B(ecR->x, e, (NUMBYTES)BITS_TO_BYTES(BnSizeInBits(prime))); + // f) compute r = Hash(e || P) (mod n) + CryptHashStart(&hashState, hashAlg); + CryptDigestUpdate2B(&hashState, e); + CryptDigestUpdate2B(&hashState, &digest->b); + e->size = CryptHashEnd(&hashState, digestSize, e->buffer); + // Reduce the hash size if it is larger than the curve order + SchnorrReduce(e, order); + // Convert hash to number + BnFrom2B(bnR, e); + // libtpms: Note: e is NOT a concern for constant-timeness + // Do the Schnorr computation + retVal = BnSchnorrSign(bnS, bnK, bnR, bnD, CurveGetOrder(C)); + } while(retVal == TPM_RC_NO_RESULT); + Exit: + return retVal; +} +#endif // ALG_ECSCHNORR +#if ALG_SM2 +#ifdef _SM2_SIGN_DEBUG +/* 10.2.12.3.5 BnHexEqual() */ +/* This function compares a bignum value to a hex string. */ +/* Return Value Meaning */ +/* TRUE(1) values equal */ +/* FALSE(0) values not equal */ +static BOOL +BnHexEqual( + bigNum bn, //IN: big number value + const char *c //IN: character string number + ) +{ + ECC_NUM(bnC); + BnFromHex(bnC, c); + return (BnUnsignedCmp(bn, bnC) == 0); +} +#endif // _SM2_SIGN_DEBUG +/* 10.2.12.3.5 BnSignEcSm2() */ +/* This function signs a digest using the method defined in SM2 Part 2. The method in the standard + will add a header to the message to be signed that is a hash of the values that define the + key. This then hashed with the message to produce a digest (e) that is signed. This function + signs e. */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE bad curve */ +static TPM_RC +BnSignEcSm2( + bigNum bnR, // OUT: r component of the signature + bigNum bnS, // OUT: s component of the signature + bigCurve E, // IN: the curve used in signing + bigNum bnD, // IN: the private key + const TPM2B_DIGEST *digest, // IN: the digest to sign + RAND_STATE *rand // IN: random number generator (mostly for + // debug) + ) +{ + BN_MAX_INITIALIZED(bnE, digest); // Don't know how big digest might be + ECC_NUM(bnN); + ECC_NUM(bnK); + ECC_NUM(bnT); // temp + POINT(Q1); + bigConst order = (E != NULL) + ? CurveGetOrder(AccessCurveData(E)) : NULL; +// libtpms added begin + UINT32 orderBits = BnSizeInBits(order); + BOOL atByteBoundary = (orderBits & 7) == 0; + ECC_NUM(bnK1); +// libtpms added end + + // +#ifdef _SM2_SIGN_DEBUG + BnFromHex(bnE, "B524F552CD82B8B028476E005C377FB1" + "9A87E6FC682D48BB5D42E3D9B9EFFE76"); + BnFromHex(bnD, "128B2FA8BD433C6C068C8D803DFF7979" + "2A519A55171B1B650C23661D15897263"); +#endif + // A3: Use random number generator to generate random number 1 <= k <= n-1; + // NOTE: Ax: numbers are from the SM2 standard + loop: + { + // Get a random number 0 < k < n + // libtpms modified begin + // + // We take a dual approach here. One for curves whose order is not at + // the byte boundary, e.g. NIST P521, we get a random number bnK and add + // the order to that number to have bnK1. This will not spill over into + // a new byte and we can then use bnK1 to do the do the BnEccModMult + // with a constant number of bytes. For curves whose order is at the + // byte boundary we require that the random number bnK comes back with + // a requested number of bytes. + if (!atByteBoundary) { + BnGenerateRandomInRange(bnK, order, rand); + BnAdd(bnK1, bnK, order); +#ifdef _SM2_SIGN_DEBUG + BnFromHex(bnK1, "6CB28D99385C175C94F94E934817663F" + "C176D925DD72B727260DBAAE1FB2F96F"); +#endif + // A4: Figure out the point of elliptic curve (x1, y1)=[k]G, and according + // to details specified in 4.2.7 in Part 1 of this document, transform the + // data type of x1 into an integer; + if(!BnEccModMult(Q1, NULL, bnK1, E)) + goto loop; + } else { + BnGenerateRandomInRangeAllBytes(bnK, order, rand); +#ifdef _SM2_SIGN_DEBUG + BnFromHex(bnK, "6CB28D99385C175C94F94E934817663F" + "C176D925DD72B727260DBAAE1FB2F96F"); +#endif + if(!BnEccModMult(Q1, NULL, bnK, E)) + goto loop; + } // libtpms modified end + // A5: Figure out r = (e + x1) mod n, + BnAdd(bnR, bnE, Q1->x); + BnMod(bnR, order); +#ifdef _SM2_SIGN_DEBUG + pAssert(BnHexEqual(bnR, "40F1EC59F793D9F49E09DCEF49130D41" + "94F79FB1EED2CAA55BACDB49C4E755D1")); +#endif + // if r=0 or r+k=n, return to A3; + if(BnEqualZero(bnR)) + goto loop; + BnAdd(bnT, bnK, bnR); + if(BnUnsignedCmp(bnT, bnN) == 0) + goto loop; + // A6: Figure out s = ((1 + dA)^-1 (k - r dA)) mod n, + // if s=0, return to A3; + // compute t = (1+dA)^-1 + BnAddWord(bnT, bnD, 1); + BnModInverse(bnT, bnT, order); +#ifdef _SM2_SIGN_DEBUG + pAssert(BnHexEqual(bnT, "79BFCF3052C80DA7B939E0C6914A18CB" + "B2D96D8555256E83122743A7D4F5F956")); +#endif + // compute s = t * (k - r * dA) mod n + BnModMult(bnS, bnR, bnD, order); + // k - r * dA mod n = k + n - ((r * dA) mod n) + BnSub(bnS, order, bnS); + BnAdd(bnS, bnK, bnS); + BnModMult(bnS, bnS, bnT, order); +#ifdef _SM2_SIGN_DEBUG + pAssert(BnHexEqual(bnS, "6FC6DAC32C5D5CF10C77DFB20F7C2EB6" + "67A457872FB09EC56327A67EC7DEEBE7")); +#endif + if(BnEqualZero(bnS)) + goto loop; + } + // A7: According to details specified in 4.2.1 in Part 1 of this document, + // transform the data type of r, s into bit strings, signature of message M + // is (r, s). + // This is handled by the common return code +#ifdef _SM2_SIGN_DEBUG + pAssert(BnHexEqual(bnR, "40F1EC59F793D9F49E09DCEF49130D41" + "94F79FB1EED2CAA55BACDB49C4E755D1")); + pAssert(BnHexEqual(bnS, "6FC6DAC32C5D5CF10C77DFB20F7C2EB6" + "67A457872FB09EC56327A67EC7DEEBE7")); +#endif + return TPM_RC_SUCCESS; +} +#endif // ALG_SM2 +/* 10.2.12.3.6 CryptEccSign() */ +/* This function is the dispatch function for the various ECC-based signing schemes. There is a bit + of ugliness to the parameter passing. In order to test this, we sometime would like to use a + deterministic RNG so that we can get the same signatures during testing. The easiest way to do + this for most schemes is to pass in a deterministic RNG and let it return canned values during + testing. There is a competing need for a canned parameter to use in ECDAA. To accommodate both + needs with minimal fuss, a special type of RAND_STATE is defined to carry the address of the + commit value. The setup and handling of this is not very different for the caller than what was + in previous versions of the code. */ +/* Error Returns Meaning */ +/* TPM_RC_SCHEME scheme is not supported */ +LIB_EXPORT TPM_RC +CryptEccSign( + TPMT_SIGNATURE *signature, // OUT: signature + OBJECT *signKey, // IN: ECC key to sign the hash + const TPM2B_DIGEST *digest, // IN: digest to sign + TPMT_ECC_SCHEME *scheme, // IN: signing scheme + RAND_STATE *rand + ) +{ + CURVE_INITIALIZED(E, signKey->publicArea.parameters.eccDetail.curveID); + ECC_INITIALIZED(bnD, &signKey->sensitive.sensitive.ecc.b); + ECC_NUM(bnR); + ECC_NUM(bnS); + const ECC_CURVE_DATA *C; + TPM_RC retVal = TPM_RC_SCHEME; + // + NOT_REFERENCED(scheme); + if(E == NULL) + ERROR_RETURN(TPM_RC_VALUE); + C = AccessCurveData(E); + signature->signature.ecdaa.signatureR.t.size + = sizeof(signature->signature.ecdaa.signatureR.t.buffer); + signature->signature.ecdaa.signatureS.t.size + = sizeof(signature->signature.ecdaa.signatureS.t.buffer); + TEST(signature->sigAlg); + switch(signature->sigAlg) + { + case TPM_ALG_ECDSA: + retVal = BnSignEcdsa(bnR, bnS, E, bnD, digest, rand); + break; +#if ALG_ECDAA + case TPM_ALG_ECDAA: + retVal = BnSignEcdaa(&signature->signature.ecdaa.signatureR, bnS, E, + bnD, digest, scheme, signKey, rand); + bnR = NULL; + break; +#endif +#if ALG_ECSCHNORR + case TPM_ALG_ECSCHNORR: + retVal = BnSignEcSchnorr(bnR, bnS, E, bnD, digest, + signature->signature.ecschnorr.hash, + rand); + break; +#endif +#if ALG_SM2 + case TPM_ALG_SM2: + retVal = BnSignEcSm2(bnR, bnS, E, bnD, digest, rand); + break; +#endif + default: + break; + } + // If signature generation worked, convert the results. + if(retVal == TPM_RC_SUCCESS) + { + NUMBYTES orderBytes = + (NUMBYTES)BITS_TO_BYTES(BnSizeInBits(CurveGetOrder(C))); + if(bnR != NULL) + BnTo2B(bnR, &signature->signature.ecdaa.signatureR.b, orderBytes); + if(bnS != NULL) + BnTo2B(bnS, &signature->signature.ecdaa.signatureS.b, orderBytes); + } + Exit: + CURVE_FREE(E); + return retVal; +} +#if ALG_ECDSA +/* 10.2.12.3.7 BnValidateSignatureEcdsa() */ +/* This function validates an ECDSA signature. rIn and sIn should have been checked to make sure + that they are in the range 0 < v < n */ +/* Error Returns Meaning */ +/* TPM_RC_SIGNATURE signature not valid */ +#if !USE_OPENSSL_FUNCTIONS_ECDSA // libtpms added +TPM_RC +BnValidateSignatureEcdsa( + bigNum bnR, // IN: r component of the signature + bigNum bnS, // IN: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bn_point_t *ecQ, // IN: the public point of the key + const TPM2B_DIGEST *digest // IN: the digest that was signed + ) +{ + // Make sure that the allocation for the digest is big enough for a maximum + // digest + BN_VAR(bnE, MAX(MAX_ECC_KEY_BYTES, MAX_DIGEST_SIZE) * 8); + POINT(ecR); + ECC_NUM(bnU1); + ECC_NUM(bnU2); + ECC_NUM(bnW); + bigConst order = CurveGetOrder(AccessCurveData(E)); + TPM_RC retVal = TPM_RC_SIGNATURE; + // Get adjusted digest + EcdsaDigest(bnE, digest, order); + // 1. If r and s are not both integers in the interval [1, n - 1], output + // INVALID. + // bnR and bnS were validated by the caller + // 2. Use the selected hash function to compute H0 = Hash(M0). + // This is an input parameter + // 3. Convert the bit string H0 to an integer e as described in Appendix B.2. + // Done at entry + // 4. Compute w = (s')^-1 mod n, using the routine in Appendix B.1. + if(!BnModInverse(bnW, bnS, order)) + goto Exit; + // 5. Compute u1 = (e' * w) mod n, and compute u2 = (r' * w) mod n. + BnModMult(bnU1, bnE, bnW, order); + BnModMult(bnU2, bnR, bnW, order); + // 6. Compute the elliptic curve point R = (xR, yR) = u1G+u2Q, using EC + // scalar multiplication and EC addition (see [Routines]). If R is equal to + // the point at infinity O, output INVALID. + if(BnPointMult(ecR, CurveGetG(AccessCurveData(E)), bnU1, ecQ, bnU2, E) + != TPM_RC_SUCCESS) + goto Exit; + // 7. Compute v = Rx mod n. + BnMod(ecR->x, order); + // 8. Compare v and r0. If v = r0, output VALID; otherwise, output INVALID + if(BnUnsignedCmp(ecR->x, bnR) != 0) + goto Exit; + retVal = TPM_RC_SUCCESS; + Exit: + return retVal; +} +#else // USE_OPENSSL_FUNCTIONS_ECDSA libtpms added begin +TPM_RC +BnValidateSignatureEcdsa( + bigNum bnR, // IN: r component of the signature + bigNum bnS, // IN: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bn_point_t *ecQ, // IN: the public point of the key + const TPM2B_DIGEST *digest // IN: the digest that was signed + ) +{ + int retVal; + int rc; + ECDSA_SIG *sig = NULL; + EC_KEY *eckey = NULL; + BIGNUM *r = BN_new(); + BIGNUM *s = BN_new(); + EC_POINT *q = EcPointInitialized(ecQ, E); + + r = BigInitialized(r, bnR); + s = BigInitialized(s, bnS); + + sig = ECDSA_SIG_new(); + eckey = EC_KEY_new(); + + if (r == NULL || s == NULL || q == NULL || sig == NULL || eckey == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EC_KEY_set_group(eckey, E->G) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EC_KEY_set_public_key(eckey, q) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + if (ECDSA_SIG_set0(sig, r, s) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + /* sig now owns r and s */ + r = NULL; + s = NULL; + + rc = ECDSA_do_verify(digest->b.buffer, digest->b.size, sig, eckey); + switch (rc) { + case 1: + retVal = TPM_RC_SUCCESS; + break; + case 0: + retVal = TPM_RC_SIGNATURE; + break; + default: + retVal = TPM_RC_FAILURE; + break; + } + + Exit: + EC_KEY_free(eckey); + ECDSA_SIG_free(sig); + EC_POINT_clear_free(q); + BN_clear_free(r); + BN_clear_free(s); + + return retVal; +} +#endif // USE_OPENSSL_FUNCTIONS_ECDSA libtpms added end +#endif // ALG_ECDSA +#if ALG_SM2 +/* 10.2.12.3.8 BnValidateSignatureEcSm2() */ +/* This function is used to validate an SM2 signature. */ +/* Error Returns Meaning */ +/* TPM_RC_SIGNATURE signature not valid */ +static TPM_RC +BnValidateSignatureEcSm2( + bigNum bnR, // IN: r component of the signature + bigNum bnS, // IN: s component of the signature + bigCurve E, // IN: the curve used in the signature + // process + bigPoint ecQ, // IN: the public point of the key + const TPM2B_DIGEST *digest // IN: the digest that was signed + ) +{ + POINT(P); + ECC_NUM(bnRp); + ECC_NUM(bnT); + BN_MAX_INITIALIZED(bnE, digest); + BOOL OK; + bigConst order = CurveGetOrder(AccessCurveData(E)); +#ifdef _SM2_SIGN_DEBUG + // Make sure that the input signature is the test signature + pAssert(BnHexEqual(bnR, + "40F1EC59F793D9F49E09DCEF49130D41" + "94F79FB1EED2CAA55BACDB49C4E755D1")); + pAssert(BnHexEqual(bnS, + "6FC6DAC32C5D5CF10C77DFB20F7C2EB6" + "67A457872FB09EC56327A67EC7DEEBE7")); +#endif + // b) compute t := (r + s) mod n + BnAdd(bnT, bnR, bnS); + BnMod(bnT, order); +#ifdef _SM2_SIGN_DEBUG + pAssert(BnHexEqual(bnT, + "2B75F07ED7ECE7CCC1C8986B991F441A" + "D324D6D619FE06DD63ED32E0C997C801")); +#endif + // c) verify that t > 0 + OK = !BnEqualZero(bnT); + if(!OK) + // set T to a value that should allow rest of the computations to run + // without trouble + BnCopy(bnT, bnS); + // d) compute (x, y) := [s]G + [t]Q + OK = BnEccModMult2(P, NULL, bnS, ecQ, bnT, E); +#ifdef _SM2_SIGN_DEBUG + pAssert(OK && BnHexEqual(P->x, + "110FCDA57615705D5E7B9324AC4B856D" + "23E6D9188B2AE47759514657CE25D112")); +#endif + // e) compute r' := (e + x) mod n (the x coordinate is in bnT) + OK = OK && BnAdd(bnRp, bnE, P->x); + OK = OK && BnMod(bnRp, order); + // f) verify that r' = r + OK = OK && (BnUnsignedCmp(bnR, bnRp) == 0); + + if(!OK) + return TPM_RC_SIGNATURE; + else + return TPM_RC_SUCCESS; +} +#endif // ALG_SM2 +#if ALG_ECSCHNORR +/* 10.2.12.3.9 BnValidateSignatureEcSchnorr() */ +/* This function is used to validate an EC Schnorr signature. */ +/* Error Returns Meaning */ +/* TPM_RC_SIGNATURE signature not valid */ +static TPM_RC +BnValidateSignatureEcSchnorr( + bigNum bnR, // IN: r component of the signature + bigNum bnS, // IN: s component of the signature + TPM_ALG_ID hashAlg, // IN: hash algorithm of the signature + bigCurve E, // IN: the curve used in the signature + // process + bigPoint ecQ, // IN: the public point of the key + const TPM2B_DIGEST *digest // IN: the digest that was signed + ) +{ + BN_MAX(bnRn); + POINT(ecE); + BN_MAX(bnEx); + const ECC_CURVE_DATA *C = AccessCurveData(E); + bigConst order = CurveGetOrder(C); + UINT16 digestSize = CryptHashGetDigestSize(hashAlg); + HASH_STATE hashState; + TPM2B_TYPE(BUFFER, MAX(MAX_ECC_PARAMETER_BYTES, MAX_DIGEST_SIZE)); + TPM2B_BUFFER Ex2 = {{sizeof(Ex2.t.buffer),{ 0 }}}; + BOOL OK; + // + // E = [s]G - [r]Q + BnMod(bnR, order); + // Make -r = n - r + BnSub(bnRn, order, bnR); + // E = [s]G + [-r]Q + OK = BnPointMult(ecE, CurveGetG(C), bnS, ecQ, bnRn, E) == TPM_RC_SUCCESS; + // // reduce the x portion of E mod q + // OK = OK && BnMod(ecE->x, order); + // Convert to byte string + OK = OK && BnTo2B(ecE->x, &Ex2.b, + (NUMBYTES)(BITS_TO_BYTES(BnSizeInBits(order)))); + if(OK) + { + // Ex = h(pE.x || digest) + CryptHashStart(&hashState, hashAlg); + CryptDigestUpdate(&hashState, Ex2.t.size, Ex2.t.buffer); + CryptDigestUpdate(&hashState, digest->t.size, digest->t.buffer); + Ex2.t.size = CryptHashEnd(&hashState, digestSize, Ex2.t.buffer); + SchnorrReduce(&Ex2.b, order); + BnFrom2B(bnEx, &Ex2.b); + // see if Ex matches R + OK = BnUnsignedCmp(bnEx, bnR) == 0; + } + return (OK) ? TPM_RC_SUCCESS : TPM_RC_SIGNATURE; +} +#endif // ALG_ECSCHNORR +/* 10.2.12.3.10 CryptEccValidateSignature() */ +/* This function validates an EcDsa() or EcSchnorr() signature. The point Qin needs to have been + validated to be on the curve of curveId. */ +/* Error Returns Meaning */ +/* TPM_RC_SIGNATURE not a valid signature */ +LIB_EXPORT TPM_RC +CryptEccValidateSignature( + TPMT_SIGNATURE *signature, // IN: signature to be verified + OBJECT *signKey, // IN: ECC key signed the hash + const TPM2B_DIGEST *digest // IN: digest that was signed + ) +{ + CURVE_INITIALIZED(E, signKey->publicArea.parameters.eccDetail.curveID); + ECC_NUM(bnR); + ECC_NUM(bnS); + POINT_INITIALIZED(ecQ, &signKey->publicArea.unique.ecc); + bigConst order; + TPM_RC retVal; + if(E == NULL) + ERROR_RETURN(TPM_RC_VALUE); + order = CurveGetOrder(AccessCurveData(E)); + // // Make sure that the scheme is valid + switch(signature->sigAlg) + { + case TPM_ALG_ECDSA: +#if ALG_ECSCHNORR + case TPM_ALG_ECSCHNORR: +#endif +#if ALG_SM2 + case TPM_ALG_SM2: +#endif + break; + default: + ERROR_RETURN(TPM_RC_SCHEME); + break; + } + // Can convert r and s after determining that the scheme is an ECC scheme. If + // this conversion doesn't work, it means that the unmarshaling code for + // an ECC signature is broken. + BnFrom2B(bnR, &signature->signature.ecdsa.signatureR.b); + BnFrom2B(bnS, &signature->signature.ecdsa.signatureS.b); + // r and s have to be greater than 0 but less than the curve order + if(BnEqualZero(bnR) || BnEqualZero(bnS)) + ERROR_RETURN(TPM_RC_SIGNATURE); + if((BnUnsignedCmp(bnS, order) >= 0) + || (BnUnsignedCmp(bnR, order) >= 0)) + ERROR_RETURN(TPM_RC_SIGNATURE); + switch(signature->sigAlg) + { + case TPM_ALG_ECDSA: + retVal = BnValidateSignatureEcdsa(bnR, bnS, E, ecQ, digest); + break; +#if ALG_ECSCHNORR + case TPM_ALG_ECSCHNORR: + retVal = BnValidateSignatureEcSchnorr(bnR, bnS, + signature->signature.any.hashAlg, + E, ecQ, digest); + break; +#endif +#if ALG_SM2 + case TPM_ALG_SM2: + retVal = BnValidateSignatureEcSm2(bnR, bnS, E, ecQ, digest); + break; +#endif + default: + FAIL(FATAL_ERROR_INTERNAL); + } + Exit: + CURVE_FREE(E); + return retVal; +} +/* 10.2.12.3.11 CryptEccCommitCompute() */ +/* This function performs the point multiply operations required by TPM2_Commit(). */ +/* If B or M is provided, they must be on the curve defined by curveId. This routine does not check + that they are on the curve and results are unpredictable if they are not. */ +/* It is a fatal error if r is NULL. If B is not NULL, then it is a fatal error if d is NULL or if K + and L are both NULL. If M is not NULL, then it is a fatal error if E is NULL. */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT if K, L or E was computed to be the point at infinity */ +/* TPM_RC_CANCELED a cancel indication was asserted during this function */ +LIB_EXPORT TPM_RC +CryptEccCommitCompute( + TPMS_ECC_POINT *K, // OUT: [d]B or [r]Q + TPMS_ECC_POINT *L, // OUT: [r]B + TPMS_ECC_POINT *E, // OUT: [r]M + TPM_ECC_CURVE curveId, // IN: the curve for the computations + TPMS_ECC_POINT *M, // IN: M (optional) + TPMS_ECC_POINT *B, // IN: B (optional) + TPM2B_ECC_PARAMETER *d, // IN: d (optional) + TPM2B_ECC_PARAMETER *r // IN: the computed r value (required) + ) +{ + CURVE_INITIALIZED(curve, curveId); // Normally initialize E as the curve, but E means + // something else in this function + ECC_INITIALIZED(bnR, r); + TPM_RC retVal = TPM_RC_SUCCESS; + // + // Validate that the required parameters are provided. + // Note: E has to be provided if computing E := [r]Q or E := [r]M. Will do + // E := [r]Q if both M and B are NULL. + pAssert(r != NULL && E != NULL); + // Initialize the output points in case they are not computed + ClearPoint2B(K); + ClearPoint2B(L); + ClearPoint2B(E); + // Sizes of the r parameter may not be zero + pAssert(r->t.size > 0); + // If B is provided, compute K=[d]B and L=[r]B + if(B != NULL) + { + ECC_INITIALIZED(bnD, d); + POINT_INITIALIZED(pB, B); + POINT(pK); + POINT(pL); + // + pAssert(d != NULL && K != NULL && L != NULL); + if(!BnIsOnCurve(pB, AccessCurveData(curve))) + ERROR_RETURN(TPM_RC_VALUE); + // do the math for K = [d]B + if((retVal = BnPointMult(pK, pB, bnD, NULL, NULL, curve)) != TPM_RC_SUCCESS) + goto Exit; + // Convert BN K to TPM2B K + BnPointTo2B(K, pK, curve); + // compute L= [r]B after checking for cancel + if(_plat__IsCanceled()) + ERROR_RETURN(TPM_RC_CANCELED); + // compute L = [r]B + if(!BnIsValidPrivateEcc(bnR, curve)) + ERROR_RETURN(TPM_RC_VALUE); + if((retVal = BnPointMult(pL, pB, bnR, NULL, NULL, curve)) != TPM_RC_SUCCESS) + goto Exit; + // Convert BN L to TPM2B L + BnPointTo2B(L, pL, curve); + } + if((M != NULL) || (B == NULL)) + { + POINT_INITIALIZED(pM, M); + POINT(pE); + // + // Make sure that a place was provided for the result + pAssert(E != NULL); + // if this is the third point multiply, check for cancel first + if((B != NULL) && _plat__IsCanceled()) + ERROR_RETURN(TPM_RC_CANCELED); + // If M provided, then pM will not be NULL and will compute E = [r]M. + // However, if M was not provided, then pM will be NULL and E = [r]G + // will be computed + if((retVal = BnPointMult(pE, pM, bnR, NULL, NULL, curve)) != TPM_RC_SUCCESS) + goto Exit; + // Convert E to 2B format + BnPointTo2B(E, pE, curve); + } + Exit: + CURVE_FREE(curve); + return retVal; +} +#endif // TPM_ALG_ECC diff --git a/src/tpm2/crypto/openssl/CryptHash.c b/src/tpm2/crypto/openssl/CryptHash.c new file mode 100644 index 0000000..cb5bd0f --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptHash.c @@ -0,0 +1,871 @@ +/********************************************************************************/ +/* */ +/* Implementation of cryptographic functions for hashing. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptHash.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.13 CryptHash.c */ +/* 10.2.13.1 Description */ +/* This file contains implementation of cryptographic functions for hashing. */ +/* 10.2.13.2 Includes, Defines, and Types */ +#define _CRYPT_HASH_C_ +#include "Tpm.h" +#include "CryptHash_fp.h" +#include "CryptHash.h" +#include "OIDs.h" + +/* Instance each of the hash descriptors based on the implemented algorithms */ + +FOR_EACH_HASH(HASH_DEF_TEMPLATE) + +/* Instance a null def. */ + + HASH_DEF NULL_Def = {{0}}; + +/* Create a table of pointers to the defined hash definitions */ + +#define HASH_DEF_ENTRY(HASH, Hash) &Hash##_Def, +PHASH_DEF HashDefArray[] = { + // for each implemented HASH, expands to: &HASH_Def, + FOR_EACH_HASH(HASH_DEF_ENTRY) + &NULL_Def +}; + +/* 10.2.13.3 Obligatory Initialization Functions */ +/* 10.2.13.3.1 CryptHashInit() */ +/* This function is called by _TPM_Init() do perform the initialization operations for the + library. */ +BOOL +CryptHashInit( + void + ) +{ + LibHashInit(); + return TRUE; +} +/* 10.2.13.3.2 CryptHashStartup() */ +/* This function is called by TPM2_Startup(). It checks that the size of the HashDefArray() is + consistent with the HASH_COUNT. */ +BOOL +CryptHashStartup( + void + ) +{ + int i = sizeof(HashDefArray) / sizeof(PHASH_DEF) - 1; + return (i == HASH_COUNT); +} +/* 10.2.13.4 Hash Information Access Functions */ +/* 10.2.13.4.1 Introduction */ +/* These functions provide access to the hash algorithm description information. */ +/* 10.2.13.4.2 CryptGetHashDef() */ +/* This function accesses the hash descriptor associated with a hash a algorithm. The function + returns a pointer to a null descriptor if hashAlg is TPM_ALG_NULL or not a defined algorithm. */ + +PHASH_DEF +CryptGetHashDef( + TPM_ALG_ID hashAlg + ) +{ +#define GET_DEF(HASH, Hash) case ALG_##HASH##_VALUE: return &Hash##_Def; + switch(hashAlg) + { + FOR_EACH_HASH(GET_DEF) + default: + return &NULL_Def; + } +#undef GET_DEF +} +/* 10.2.13.4.3 CryptHashIsValidAlg() */ +/* This function tests to see if an algorithm ID is a valid hash algorithm. If flag is true, then + TPM_ALG_NULL is a valid hash. */ +/* Return Value Meaning */ +/* TRUE(1) hashAlg is a valid, implemented hash on this TPM */ +/* FALSE(0) hashAlg is not valid for this TPM */ +BOOL +CryptHashIsValidAlg( + TPM_ALG_ID hashAlg, // IN: the algorithm to check + BOOL flag // IN: TRUE if TPM_ALG_NULL is to be treated + // as a valid hash + ) +{ + if(hashAlg == TPM_ALG_NULL) + return flag; + return CryptGetHashDef(hashAlg) != &NULL_Def; +} +/* 10.2.13.4.4 CryptHashGetAlgByIndex() */ +/* This function is used to iterate through the hashes. TPM_ALG_NULL is returned for all indexes + that are not valid hashes. If the TPM implements 3 hashes, then an index value of 0 will return + the first implemented hash and an index of 2 will return the last. All other index values will + return TPM_ALG_NULL. */ +/* Return Value Meaning */ +/* TPM_ALG_xxx a hash algorithm */ +/* TPM_ALG_NULL this can be used as a stop value */ +LIB_EXPORT TPM_ALG_ID +CryptHashGetAlgByIndex( + UINT32 index // IN: the index + ) +{ + TPM_ALG_ID hashAlg; + if(index >= HASH_COUNT) + hashAlg = TPM_ALG_NULL; + else + hashAlg = HashDefArray[index]->hashAlg; + return hashAlg; +} +/* 10.2.13.4.5 CryptHashGetDigestSize() */ +/* Returns the size of the digest produced by the hash. If hashAlg is not a hash algorithm, the TPM + will FAIL. */ +/* Return Value Meaning */ +/* 0 TPM_ALG_NULL */ +/* > 0 the digest size */ +LIB_EXPORT UINT16 +CryptHashGetDigestSize( + TPM_ALG_ID hashAlg // IN: hash algorithm to look up + ) +{ + return CryptGetHashDef(hashAlg)->digestSize; +} +/* 10.2.13.4.6 CryptHashGetBlockSize() */ +/* Returns the size of the block used by the hash. If hashAlg is not a hash algorithm, the TPM will + FAIL. */ +/* Return Value Meaning */ +/* 0 TPM_ALG_NULL */ +/* > 0 the digest size */ +LIB_EXPORT UINT16 +CryptHashGetBlockSize( + TPM_ALG_ID hashAlg // IN: hash algorithm to look up + ) +{ + return CryptGetHashDef(hashAlg)->blockSize; +} +/* 10.2.13.4.7 CryptHashGetOid() */ +/* This function returns a pointer to DER=encoded OID for a hash algorithm. All OIDs are full OID + values including the Tag (0x06) and length byte. */ +#if 0 // libtpms added +LIB_EXPORT const BYTE * +CryptHashGetOid( + TPM_ALG_ID hashAlg + ) +{ + return CryptGetHashDef(hashAlg)->OID; +} +#endif // libtpms added +/* 10.2.13.4.8 CryptHashGetContextAlg() */ +/* This function returns the hash algorithm associated with a hash context. */ +#if 0 // libtpms added +TPM_ALG_ID +CryptHashGetContextAlg( + PHASH_STATE state // IN: the context to check + ) +{ + return state->hashAlg; +} +#endif // libtpms added +/* 10.2.13.5 State Import and Export */ +/* 10.2.13.5.1 CryptHashCopyState */ +/* This function is used to clone a HASH_STATE. */ +#if 0 // libtpms added +LIB_EXPORT void +CryptHashCopyState( + HASH_STATE *out, // OUT: destination of the state + const HASH_STATE *in // IN: source of the state + ) +{ + pAssert(out->type == in->type); + out->hashAlg = in->hashAlg; + out->def = in->def; + if(in->hashAlg != TPM_ALG_NULL) + { + HASH_STATE_COPY(out, in); + } + if(in->type == HASH_STATE_HMAC) + { + const HMAC_STATE *hIn = (HMAC_STATE *)in; + HMAC_STATE *hOut = (HMAC_STATE *)out; + hOut->hmacKey = hIn->hmacKey; + } + return; +} +#endif // libtpms added +#if 0 // libtpms added +/* 10.2.13.5.2 CryptHashExportState() */ +/* This function is used to export a hash or HMAC hash state. This function would be called when + preparing to context save a sequence object. */ +void +CryptHashExportState( + PCHASH_STATE internalFmt, // IN: the hash state formatted for use by + // library + PEXPORT_HASH_STATE externalFmt // OUT: the exported hash state + ) +{ + BYTE *outBuf = (BYTE *)externalFmt; + // + cAssert(sizeof(HASH_STATE) <= sizeof(EXPORT_HASH_STATE)); + // the following #define is used to move data from an aligned internal data + // structure to a byte buffer (external format data. +#define CopyToOffset(value) \ + memcpy(&outBuf[offsetof(HASH_STATE,value)], &internalFmt->value, \ + sizeof(internalFmt->value)) + // Copy the hashAlg + CopyToOffset(hashAlg); + CopyToOffset(type); +#ifdef HASH_STATE_SMAC + if(internalFmt->type == HASH_STATE_SMAC) + { + memcpy(outBuf, internalFmt, sizeof(HASH_STATE)); + return; + + } +#endif + if(internalFmt->type == HASH_STATE_HMAC) + { + HMAC_STATE *from = (HMAC_STATE *)internalFmt; + memcpy(&outBuf[offsetof(HMAC_STATE, hmacKey)], &from->hmacKey, + sizeof(from->hmacKey)); + } + if(internalFmt->hashAlg != TPM_ALG_NULL) + HASH_STATE_EXPORT(externalFmt, internalFmt); +} +/* 10.2.13.5.3 CryptHashImportState() */ +/* This function is used to import the hash state. This function would be called to import a hash + state when the context of a sequence object was being loaded. */ +void +CryptHashImportState( + PHASH_STATE internalFmt, // OUT: the hash state formatted for use by + // the library + PCEXPORT_HASH_STATE externalFmt // IN: the exported hash state + ) +{ + BYTE *inBuf = (BYTE *)externalFmt; + // +#define CopyFromOffset(value) \ + memcpy(&internalFmt->value, &inBuf[offsetof(HASH_STATE,value)], \ + sizeof(internalFmt->value)) + + // Copy the hashAlg of the byte-aligned input structure to the structure-aligned + // internal structure. + CopyFromOffset(hashAlg); + CopyFromOffset(type); + if(internalFmt->hashAlg != TPM_ALG_NULL) + { +#ifdef HASH_STATE_SMAC + if(internalFmt->type == HASH_STATE_SMAC) + { + memcpy(internalFmt, inBuf, sizeof(HASH_STATE)); + return; + } +#endif + internalFmt->def = CryptGetHashDef(internalFmt->hashAlg); + HASH_STATE_IMPORT(internalFmt, inBuf); + if(internalFmt->type == HASH_STATE_HMAC) + { + HMAC_STATE *to = (HMAC_STATE *)internalFmt; + memcpy(&to->hmacKey, &inBuf[offsetof(HMAC_STATE, hmacKey)], + sizeof(to->hmacKey)); + } + } +} +#endif // libtpms added +/* 10.2.13.6 State Modification Functions */ +/* 10.2.13.6.1 HashEnd() */ +/* Local function to complete a hash that uses the hashDef instead of an algorithm ID. This function + is used to complete the hash and only return a partial digest. The return value is the size of + the data copied. */ +static UINT16 +HashEnd( + PHASH_STATE hashState, // IN: the hash state + UINT32 dOutSize, // IN: the size of receive buffer + PBYTE dOut // OUT: the receive buffer + ) +{ + BYTE temp[MAX_DIGEST_SIZE]; + if((hashState->hashAlg == TPM_ALG_NULL) + || (hashState->type != HASH_STATE_HASH)) + dOutSize = 0; + if(dOutSize > 0) + { + hashState->def = CryptGetHashDef(hashState->hashAlg); + // Set the final size + dOutSize = MIN(dOutSize, hashState->def->digestSize); + // Complete into the temp buffer and then copy + HASH_END(hashState, temp); + // Don't want any other functions calling the HASH_END method + // directly. +#undef HASH_END + memcpy(dOut, &temp, dOutSize); + } + hashState->type = HASH_STATE_EMPTY; + return (UINT16)dOutSize; +} +/* 10.2.13.6.2 CryptHashStart() */ +/* Functions starts a hash stack Start a hash stack and returns the digest size. As a side effect, + the value of stateSize in hashState is updated to indicate the number of bytes of state that were + saved. This function calls GetHashServer() and that function will put the TPM into failure mode + if the hash algorithm is not supported. */ +/* This function does not use the sequence parameter. If it is necessary to import or export + context, this will start the sequence in a local state and export the state to the input + buffer. Will need to add a flag to the state structure to indicate that it needs to be imported + before it can be used. (BLEH). */ +/* Return Value Meaning */ +/* 0 hash is TPM_ALG_NULL */ +/* >0 digest size */ +LIB_EXPORT UINT16 +CryptHashStart( + PHASH_STATE hashState, // OUT: the running hash state + TPM_ALG_ID hashAlg // IN: hash algorithm + ) +{ + UINT16 retVal; + + TEST(hashAlg); + + hashState->hashAlg = hashAlg; + if(hashAlg == TPM_ALG_NULL) + { + retVal = 0; + } + else + { + hashState->def = CryptGetHashDef(hashAlg); + HASH_START(hashState); + retVal = hashState->def->digestSize; + } +#undef HASH_START + hashState->type = HASH_STATE_HASH; + return retVal; +} +/* 10.2.13.6.3 CryptDigestUpdate() */ +/* Add data to a hash or HMAC, SMAC stack. */ +void +CryptDigestUpdate( + PHASH_STATE hashState, // IN: the hash context information + UINT32 dataSize, // IN: the size of data to be added + const BYTE *data // IN: data to be hashed + ) +{ + if(hashState->hashAlg != TPM_ALG_NULL) + { + if((hashState->type == HASH_STATE_HASH) + || (hashState->type == HASH_STATE_HMAC)) + HASH_DATA(hashState, dataSize, (BYTE *)data); +#if SMAC_IMPLEMENTED + else if(hashState->type == HASH_STATE_SMAC) + (hashState->state.smac.smacMethods.data)(&hashState->state.smac.state, + dataSize, data); +#endif // SMAC_IMPLEMENTED + else + FAIL(FATAL_ERROR_INTERNAL); + } + return; +} +/* 10.2.13.6.4 CryptHashEnd() */ +/* Complete a hash or HMAC computation. This function will place the smaller of digestSize or the + size of the digest in dOut. The number of bytes in the placed in the buffer is returned. If there + is a failure, the returned value is <= 0. */ +/* Return Value Meaning */ +/* 0 no data returned */ +/* > 0 the number of bytes in the digest or dOutSize, whichever is smaller */ +LIB_EXPORT UINT16 +CryptHashEnd( + PHASH_STATE hashState, // IN: the state of hash stack + UINT32 dOutSize, // IN: size of digest buffer + BYTE *dOut // OUT: hash digest + ) +{ + pAssert(hashState->type == HASH_STATE_HASH); + return HashEnd(hashState, dOutSize, dOut); +} +/* 10.2.13.6.5 CryptHashBlock() */ +/* Start a hash, hash a single block, update digest and return the size of the results. */ +/* The digestSize parameter can be smaller than the digest. If so, only the more significant + bytes are returned. */ +/* Return Value Meaning */ +/* >= 0 number of bytes placed in dOut */ +LIB_EXPORT UINT16 +CryptHashBlock( + TPM_ALG_ID hashAlg, // IN: The hash algorithm + UINT32 dataSize, // IN: size of buffer to hash + const BYTE *data, // IN: the buffer to hash + UINT32 dOutSize, // IN: size of the digest buffer + BYTE *dOut // OUT: digest buffer + ) +{ + HASH_STATE state; + CryptHashStart(&state, hashAlg); + CryptDigestUpdate(&state, dataSize, data); + return HashEnd(&state, dOutSize, dOut); +} +/* 10.2.13.6.6 CryptDigestUpdate2B() */ +/* This function updates a digest (hash or HMAC) with a TPM2B. */ +/* This function can be used for both HMAC and hash functions so the digestState is void so that + either state type can be passed. */ +LIB_EXPORT void +CryptDigestUpdate2B( + PHASH_STATE state, // IN: the digest state + const TPM2B *bIn // IN: 2B containing the data + ) +{ + // Only compute the digest if a pointer to the 2B is provided. + // In CryptDigestUpdate(), if size is zero or buffer is NULL, then no change + // to the digest occurs. This function should not provide a buffer if bIn is + // not provided. + pAssert(bIn != NULL); + CryptDigestUpdate(state, bIn->size, bIn->buffer); + return; +} +/* 10.2.13.6.7 CryptHashEnd2B() */ +/* This function is the same as CryptCompleteHash() but the digest is placed in a TPM2B. This is the + most common use and this is provided for specification clarity. digest.size should be set to + indicate the number of bytes to place in the buffer */ +/* Return Value Meaning */ +/* >=0 the number of bytes placed in digest.buffer */ +LIB_EXPORT UINT16 +CryptHashEnd2B( + PHASH_STATE state, // IN: the hash state + P2B digest // IN: the size of the buffer Out: requested + // number of bytes + ) +{ + return CryptHashEnd(state, digest->size, digest->buffer); +} +/* 10.2.13.6.8 CryptDigestUpdateInt() */ +/* This function is used to include an integer value to a hash stack. The function marshals the + integer into its canonical form before calling CryptDigestUpdate(). */ +LIB_EXPORT void +CryptDigestUpdateInt( + void *state, // IN: the state of hash stack + UINT32 intSize, // IN: the size of 'intValue' in bytes + UINT64 intValue // IN: integer value to be hashed + ) +{ +#if LITTLE_ENDIAN_TPM + intValue = REVERSE_ENDIAN_64(intValue); +#endif + CryptDigestUpdate(state, intSize, &((BYTE *)&intValue)[8 - intSize]); +} +/* 10.2.13.7 HMAC Functions */ +/* 10.2.13.7.1 CryptHmacStart() */ +/* This function is used to start an HMAC using a temp hash context. The function does the + initialization of the hash with the HMAC key XOR iPad and updates the HMAC key XOR oPad. */ +/* The function returns the number of bytes in a digest produced by hashAlg. */ +/* Return Value Meaning */ +/* >= 0 number of bytes in digest produced by hashAlg (may be zero) */ +LIB_EXPORT UINT16 +CryptHmacStart( + PHMAC_STATE state, // IN/OUT: the state buffer + TPM_ALG_ID hashAlg, // IN: the algorithm to use + UINT16 keySize, // IN: the size of the HMAC key + const BYTE *key // IN: the HMAC key + ) +{ + PHASH_DEF hashDef; + BYTE * pb; + UINT32 i; + // + hashDef = CryptGetHashDef(hashAlg); + if(hashDef->digestSize != 0) + { + // If the HMAC key is larger than the hash block size, it has to be reduced + // to fit. The reduction is a digest of the hashKey. + if(keySize > hashDef->blockSize) + { + // if the key is too big, reduce it to a digest of itself + state->hmacKey.t.size = CryptHashBlock(hashAlg, keySize, key, + hashDef->digestSize, + state->hmacKey.t.buffer); + } + else + { + memcpy(state->hmacKey.t.buffer, key, keySize); + state->hmacKey.t.size = keySize; + } + // XOR the key with iPad (0x36) + pb = state->hmacKey.t.buffer; + for(i = state->hmacKey.t.size; i > 0; i--) + *pb++ ^= 0x36; + + // if the keySize is smaller than a block, fill the rest with 0x36 + for(i = hashDef->blockSize - state->hmacKey.t.size; i > 0; i--) + *pb++ = 0x36; + + // Increase the oPadSize to a full block + state->hmacKey.t.size = hashDef->blockSize; + + // Start a new hash with the HMAC key + // This will go in the caller's state structure and may be a sequence or not + CryptHashStart((PHASH_STATE)state, hashAlg); + CryptDigestUpdate((PHASH_STATE)state, state->hmacKey.t.size, + state->hmacKey.t.buffer); + // XOR the key block with 0x5c ^ 0x36 + for(pb = state->hmacKey.t.buffer, i = hashDef->blockSize; i > 0; i--) + *pb++ ^= (0x5c ^ 0x36); + } + // Set the hash algorithm + state->hashState.hashAlg = hashAlg; + // Set the hash state type + state->hashState.type = HASH_STATE_HMAC; + + return hashDef->digestSize; +} +/* 10.2.13.7.2 CryptHmacEnd() */ +/* This function is called to complete an HMAC. It will finish the current digest, and start a new digest. It will then add the oPadKey and the completed digest and return the results in dOut. It will not return more than dOutSize bytes. */ +/* Return Value Meaning */ +/* >= 0 number of bytes in dOut (may be zero) */ +LIB_EXPORT UINT16 +CryptHmacEnd( + PHMAC_STATE state, // IN: the hash state buffer + UINT32 dOutSize, // IN: size of digest buffer + BYTE *dOut // OUT: hash digest + ) +{ + BYTE temp[MAX_DIGEST_SIZE]; + PHASH_STATE hState = (PHASH_STATE)&state->hashState; + +#if SMAC_IMPLEMENTED + if(hState->type == HASH_STATE_SMAC) + return (state->hashState.state.smac.smacMethods.end) + (&state->hashState.state.smac.state, + dOutSize, + dOut); +#endif + pAssert(hState->type == HASH_STATE_HMAC); + hState->def = CryptGetHashDef(hState->hashAlg); + // Change the state type for completion processing + hState->type = HASH_STATE_HASH; + if(hState->hashAlg == TPM_ALG_NULL) + dOutSize = 0; + else + { + + // Complete the current hash + HashEnd(hState, hState->def->digestSize, temp); + // Do another hash starting with the oPad + CryptHashStart(hState, hState->hashAlg); + CryptDigestUpdate(hState, state->hmacKey.t.size, state->hmacKey.t.buffer); + CryptDigestUpdate(hState, hState->def->digestSize, temp); + } + return HashEnd(hState, dOutSize, dOut); +} +/* 10.2.13.7.3 CryptHmacStart2B() */ +/* This function starts an HMAC and returns the size of the digest that will be produced. */ +/* This function is provided to support the most common use of starting an HMAC with a TPM2B key. */ +/* The caller must provide a block of memory in which the hash sequence state is kept. The caller + should not alter the contents of this buffer until the hash sequence is completed or + abandoned. */ +/* Return Value Meaning */ +/* > 0 the digest size of the algorithm */ +/* = 0 the hashAlg was TPM_ALG_NULL */ +LIB_EXPORT UINT16 +CryptHmacStart2B( + PHMAC_STATE hmacState, // OUT: the state of HMAC stack. It will be used + // in HMAC update and completion + TPMI_ALG_HASH hashAlg, // IN: hash algorithm + P2B key // IN: HMAC key + ) +{ + return CryptHmacStart(hmacState, hashAlg, key->size, key->buffer); +} + /* 10.2.13.7.4 CryptHmacEnd2B() */ + /* This function is the same as CryptHmacEnd() but the HMAC result is returned in a TPM2B which is the most common use. */ + /* Return Value Meaning */ + /* >=0 the number of bytes placed in digest */ +LIB_EXPORT UINT16 +CryptHmacEnd2B( + PHMAC_STATE hmacState, // IN: the state of HMAC stack + P2B digest // OUT: HMAC + ) +{ + return CryptHmacEnd(hmacState, digest->size, digest->buffer); +} +/* 10.2.13.8 Mask and Key Generation Functions */ +/* 10.2.13.8.1 CryptMGF_KDF() */ +/* This function performs MGF1/KDF1 or KDF2 using the selected hash. KDF1 and KDF2 are T(n) = T(n-1) + || H(seed || counter) with the difference being that, with KDF1, counter starts at 0 but with + KDF2, counter starts at 1. The caller determines which version by setting the initial value of + counter to either 0 or 1. */ +/* Return Value Meaning */ +/* 0 hash algorithm was TPM_ALG_NULL */ +/* > 0 should be the same as mSize */ +LIB_EXPORT UINT16 +CryptMGF_KDF( + UINT32 mSize, // IN: length of the mask to be produced + BYTE *mask, // OUT: buffer to receive the mask + TPM_ALG_ID hashAlg, // IN: hash to use + UINT32 seedSize, // IN: size of the seed + BYTE *seed, // IN: seed size + UINT32 counter // IN: counter initial value + ) +{ + HASH_STATE hashState; + PHASH_DEF hDef = CryptGetHashDef(hashAlg); + UINT32 hLen; + UINT32 bytes; + // + // If there is no digest to compute return + if((hDef->digestSize == 0) || (mSize == 0)) + return 0; + if(counter != 0) + counter = 1; + hLen = hDef->digestSize; + for(bytes = 0; bytes < mSize; bytes += hLen) + { + // Start the hash and include the seed and counter + CryptHashStart(&hashState, hashAlg); + CryptDigestUpdate(&hashState, seedSize, seed); + CryptDigestUpdateInt(&hashState, 4, counter); + // Get as much as will fit. + CryptHashEnd(&hashState, MIN((mSize - bytes), hLen), + &mask[bytes]); + counter++; + } + return (UINT16)mSize; +} +/* 10.2.13.8.2 CryptKDFa() */ +/* This function performs the key generation according to Part 1 of the TPM specification. */ +/* This function returns the number of bytes generated which may be zero. */ +/* The key and keyStream pointers are not allowed to be NULL. The other pointer values may be + NULL. The value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes). */ +/* The once parameter is set to allow incremental generation of a large value. If this flag is + TRUE, sizeInBits will be used in the HMAC computation but only one iteration of the KDF is + performed. This would be used for XOR obfuscation so that the mask value can be generated in + digest-sized chunks rather than having to be generated all at once in an arbitrarily large + buffer and then XORed into the result. If once is TRUE, then sizeInBits must be a multiple of + 8. */ +/* Any error in the processing of this command is considered fatal. */ +/* Return Value Meaning */ +/* 0 hash algorithm is not supported or is TPM_ALG_NULL */ +/* > 0 the number of bytes in the keyStream buffer */ +LIB_EXPORT UINT16 +CryptKDFa( + TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC + const TPM2B *key, // IN: HMAC key + const TPM2B *label, // IN: a label for the KDF + const TPM2B *contextU, // IN: context U + const TPM2B *contextV, // IN: context V + UINT32 sizeInBits, // IN: size of generated key in bits + BYTE *keyStream, // OUT: key buffer + UINT32 *counterInOut, // IN/OUT: caller may provide the iteration + // counter for incremental operations to + // avoid large intermediate buffers. + UINT16 blocks // IN: If non-zero, this is the maximum number + // of blocks to be returned, regardless + // of sizeInBits + ) +{ + UINT32 counter = 0; // counter value + INT16 bytes; // number of bytes to produce + UINT16 generated; // number of bytes generated + BYTE *stream = keyStream; + HMAC_STATE hState; + UINT16 digestSize = CryptHashGetDigestSize(hashAlg); + + pAssert(key != NULL && keyStream != NULL); + + TEST(TPM_ALG_KDF1_SP800_108); + + if(digestSize == 0) + return 0; + + if(counterInOut != NULL) + counter = *counterInOut; + + // If the size of the request is larger than the numbers will handle, + // it is a fatal error. + pAssert(((sizeInBits + 7) / 8) <= INT16_MAX); + + // The number of bytes to be generated is the smaller of the sizeInBits bytes or + // the number of requested blocks. The number of blocks is the smaller of the + // number requested or the number allowed by sizeInBits. A partial block is + // a full block. + bytes = (blocks > 0) ? blocks * digestSize : (UINT16)BITS_TO_BYTES(sizeInBits); + generated = bytes; + + // Generate required bytes + for(; bytes > 0; bytes -= digestSize) + { + counter++; + // Start HMAC + if(CryptHmacStart(&hState, hashAlg, key->size, key->buffer) == 0) + return 0; + // Adding counter + CryptDigestUpdateInt(&hState.hashState, 4, counter); + + // Adding label + if(label != NULL) + HASH_DATA(&hState.hashState, label->size, (BYTE *)label->buffer); + // Add a null. SP108 is not very clear about when the 0 is needed but to + // make this like the previous version that did not add an 0x00 after + // a null-terminated string, this version will only add a null byte + // if the label parameter did not end in a null byte, or if no label + // is present. + if((label == NULL) + || (label->size == 0) + || (label->buffer[label->size - 1] != 0)) + CryptDigestUpdateInt(&hState.hashState, 1, 0); + // Adding contextU + if(contextU != NULL) + HASH_DATA(&hState.hashState, contextU->size, contextU->buffer); + // Adding contextV + if(contextV != NULL) + HASH_DATA(&hState.hashState, contextV->size, contextV->buffer); + // Adding size in bits + CryptDigestUpdateInt(&hState.hashState, 4, sizeInBits); + + // Complete and put the data in the buffer + CryptHmacEnd(&hState, bytes, stream); + stream = &stream[digestSize]; + } + // Masking in the KDF is disabled. If the calling function wants something + // less than even number of bytes, then the caller should do the masking + // because there is no universal way to do it here + if(counterInOut != NULL) + *counterInOut = counter; + return generated; +} +/* 10.2.13.8.3 CryptKDFe() */ +/* This function implements KDFe() as defined in TPM specification part 1. */ +/* This function returns the number of bytes generated which may be zero. */ +/* The Z and keyStream pointers are not allowed to be NULL. The other pointer values may be + NULL. The value of sizeInBits must be no larger than (2^18)-1 = 256K bits (32385 bytes). Any + error in the processing of this command is considered fatal. */ +/* Return Value Meaning */ +/* 0 hash algorithm is not supported or is TPM_ALG_NULL */ +/* > 0 the number of bytes in the keyStream buffer */ +LIB_EXPORT UINT16 +CryptKDFe( + TPM_ALG_ID hashAlg, // IN: hash algorithm used in HMAC + TPM2B *Z, // IN: Z + const TPM2B *label, // IN: a label value for the KDF + TPM2B *partyUInfo, // IN: PartyUInfo + TPM2B *partyVInfo, // IN: PartyVInfo + UINT32 sizeInBits, // IN: size of generated key in bits + BYTE *keyStream // OUT: key buffer + ) +{ + HASH_STATE hashState; + PHASH_DEF hashDef = CryptGetHashDef(hashAlg); + + UINT32 counter = 0; // counter value + UINT16 hLen; + BYTE *stream = keyStream; + INT16 bytes; // number of bytes to generate + + pAssert(keyStream != NULL && Z != NULL && ((sizeInBits + 7) / 8) < INT16_MAX); + // + hLen = hashDef->digestSize; + bytes = (INT16)((sizeInBits + 7) / 8); + if(hashAlg == TPM_ALG_NULL || bytes == 0) + return 0; + + // Generate required bytes + //The inner loop of that KDF uses: + // Hash[i] := H(counter | Z | OtherInfo) (5) + // Where: + // Hash[i] the hash generated on the i-th iteration of the loop. + // H() an approved hash function + // counter a 32-bit counter that is initialized to 1 and incremented + // on each iteration + // Z the X coordinate of the product of a public ECC key and a + // different private ECC key. + // OtherInfo a collection of qualifying data for the KDF defined below. + // In this specification, OtherInfo will be constructed by: + // OtherInfo := Use | PartyUInfo | PartyVInfo + for(; bytes > 0; stream = &stream[hLen], bytes = bytes - hLen) + { + if(bytes < hLen) + hLen = bytes; + counter++; + // Do the hash + CryptHashStart(&hashState, hashAlg); + // Add counter + CryptDigestUpdateInt(&hashState, 4, counter); + + // Add Z + if(Z != NULL) + CryptDigestUpdate2B(&hashState, Z); + // Add label + if(label != NULL) + CryptDigestUpdate2B(&hashState, label); + // Add a null. SP108 is not very clear about when the 0 is needed but to + // make this like the previous version that did not add an 0x00 after + // a null-terminated string, this version will only add a null byte + // if the label parameter did not end in a null byte, or if no label + // is present. + if((label == NULL) + || (label->size == 0) + || (label->buffer[label->size - 1] != 0)) + CryptDigestUpdateInt(&hashState, 1, 0); + // Add PartyUInfo + if(partyUInfo != NULL) + CryptDigestUpdate2B(&hashState, partyUInfo); + + // Add PartyVInfo + if(partyVInfo != NULL) + CryptDigestUpdate2B(&hashState, partyVInfo); + + // Compute Hash. hLen was changed to be the smaller of bytes or hLen + // at the start of each iteration. + CryptHashEnd(&hashState, hLen, stream); + } + + // Mask off bits if the required bits is not a multiple of byte size + if((sizeInBits % 8) != 0) + keyStream[0] &= ((1 << (sizeInBits % 8)) - 1); + + return (UINT16)((sizeInBits + 7) / 8); +} diff --git a/src/tpm2/crypto/openssl/CryptPrime.c b/src/tpm2/crypto/openssl/CryptPrime.c new file mode 100644 index 0000000..0de9ef2 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptPrime.c @@ -0,0 +1,440 @@ +/********************************************************************************/ +/* */ +/* Code for prime validation. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptPrime.c 1529 2019-11-21 23:29:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +/* 10.2.14 CryptPrime.c */ +/* 10.2.14.1 Introduction */ +/* This file contains the code for prime validation. */ + +#include "Tpm.h" +#include "CryptPrime_fp.h" +//#define CPRI_PRIME +//#include "PrimeTable.h" +#include "CryptPrimeSieve_fp.h" +extern const uint32_t s_LastPrimeInTable; +extern const uint32_t s_PrimeTableSize; +extern const uint32_t s_PrimesInTable; +extern const unsigned char s_PrimeTable[]; +extern bigConst s_CompositeOfSmallPrimes; + +/* 10.2.14.1.1 Root2() */ +/* This finds ceil(sqrt(n)) to use as a stopping point for searching the prime table. */ +static uint32_t +Root2( + uint32_t n + ) +{ + int32_t last = (int32_t)(n >> 2); + int32_t next = (int32_t)(n >> 1); + int32_t diff; + int32_t stop = 10; + // + // get a starting point + for(; next != 0; last >>= 1, next >>= 2); + last++; + do + { + next = (last + (n / last)) >> 1; + diff = next - last; + last = next; + if(stop-- == 0) + FAIL(FATAL_ERROR_INTERNAL); + } while(diff < -1 || diff > 1); + if((n / next) > (unsigned)next) + next++; + pAssert(next != 0); + pAssert(((n / next) <= (unsigned)next) && (n / (next + 1) < (unsigned)next)); + return next; +} +/* 10.2.14.1.2 IsPrimeInt() */ +/* This will do a test of a word of up to 32-bits in size. */ +BOOL +IsPrimeInt( + uint32_t n + ) +{ + uint32_t i; + uint32_t stop; + if(n < 3 || ((n & 1) == 0)) + return (n == 2); + if(n <= s_LastPrimeInTable) + { + n >>= 1; + return ((s_PrimeTable[n >> 3] >> (n & 7)) & 1); + } + // Need to search + stop = Root2(n) >> 1; + // starting at 1 is equivalent to staring at (1 << 1) + 1 = 3 + for(i = 1; i < stop; i++) + { + if((s_PrimeTable[i >> 3] >> (i & 7)) & 1) + // see if this prime evenly divides the number + if((n % ((i << 1) + 1)) == 0) + return FALSE; + } + return TRUE; +} +#if !RSA_KEY_SIEVE // libtpms added +/* 10.2.14.1.3 BnIsProbablyPrime() */ +/* This function is used when the key sieve is not implemented. This function Will try to eliminate + some of the obvious things before going on to perform MillerRabin() as a final verification of + primeness. */ +BOOL +BnIsProbablyPrime( + bigNum prime, // IN: + RAND_STATE *rand // IN: the random state just + // in case Miller-Rabin is required + ) +{ +#if RADIX_BITS > 32 + if(BnUnsignedCmpWord(prime, UINT32_MAX) <= 0) +#else + if(BnGetSize(prime) == 1) +#endif + return IsPrimeInt((uint32_t)prime->d[0]); + if(BnIsEven(prime)) + return FALSE; + if(BnUnsignedCmpWord(prime, s_LastPrimeInTable) <= 0) + { + crypt_uword_t temp = prime->d[0] >> 1; + return ((s_PrimeTable[temp >> 3] >> (temp & 7)) & 1); + } + { + BN_VAR(n, LARGEST_NUMBER_BITS); + BnGcd(n, prime, s_CompositeOfSmallPrimes); + if(!BnEqualWord(n, 1)) + return FALSE; + } + return MillerRabin(prime, rand); +} +#endif // libtpms added +/* 10.2.14.1.4 MillerRabinRounds() */ +/* Function returns the number of Miller-Rabin rounds necessary to give an error probability equal + to the security strength of the prime. These values are from FIPS 186-3. */ +UINT32 +MillerRabinRounds( + UINT32 bits // IN: Number of bits in the RSA prime + ) +{ + if(bits < 511) return 8; // don't really expect this + if(bits < 1536) return 5; // for 512 and 1K primes + return 4; // for 3K public modulus and greater +} +/* 10.2.14.1.5 MillerRabin() */ +/* This function performs a Miller-Rabin test from FIPS 186-3. It does iterations trials on the + number. In all likelihood, if the number is not prime, the first test fails. */ +/* Return Values Meaning */ +/* TRUE probably prime */ +/* FALSE composite */ +BOOL +MillerRabin( + bigNum bnW, + RAND_STATE *rand + ) +{ + BN_MAX(bnWm1); + BN_PRIME(bnM); + BN_PRIME(bnB); + BN_PRIME(bnZ); + BOOL ret = FALSE; // Assumed composite for easy exit + unsigned int a; + unsigned int j; + int wLen; + int i; + int iterations = MillerRabinRounds(BnSizeInBits(bnW)); + // + INSTRUMENT_INC(MillerRabinTrials[PrimeIndex]); + + pAssert(bnW->size > 1); + // Let a be the largest integer such that 2^a divides w1. + BnSubWord(bnWm1, bnW, 1); + pAssert(bnWm1->size != 0); + + // Since w is odd (w-1) is even so start at bit number 1 rather than 0 + // Get the number of bits in bnWm1 so that it doesn't have to be recomputed + // on each iteration. + i = (int)(bnWm1->size * RADIX_BITS); + // Now find the largest power of 2 that divides w1 + for(a = 1; + (a < (bnWm1->size * RADIX_BITS)) && + (BnTestBit(bnWm1, a) == 0); + a++); + // 2. m = (w1) / 2^a + BnShiftRight(bnM, bnWm1, a); + // 3. wlen = len (w). + wLen = BnSizeInBits(bnW); + // 4. For i = 1 to iterations do + for(i = 0; i < iterations; i++) + { + // 4.1 Obtain a string b of wlen bits from an RBG. + // Ensure that 1 < b < w1. + // 4.2 If ((b <= 1) or (b >= w1)), then go to step 4.1. + while(BnGetRandomBits(bnB, wLen, rand) && ((BnUnsignedCmpWord(bnB, 1) <= 0) + || (BnUnsignedCmp(bnB, bnWm1) >= 0))); + if(g_inFailureMode) + return FALSE; + + // 4.3 z = b^m mod w. + // if ModExp fails, then say this is not + // prime and bail out. + BnModExp(bnZ, bnB, bnM, bnW); + + // 4.4 If ((z == 1) or (z = w == 1)), then go to step 4.7. + if((BnUnsignedCmpWord(bnZ, 1) == 0) + || (BnUnsignedCmp(bnZ, bnWm1) == 0)) + goto step4point7; + // 4.5 For j = 1 to a 1 do. + for(j = 1; j < a; j++) + { + // 4.5.1 z = z^2 mod w. + BnModMult(bnZ, bnZ, bnZ, bnW); + // 4.5.2 If (z = w1), then go to step 4.7. + if(BnUnsignedCmp(bnZ, bnWm1) == 0) + goto step4point7; + // 4.5.3 If (z = 1), then go to step 4.6. + if(BnEqualWord(bnZ, 1)) + goto step4point6; + } + // 4.6 Return COMPOSITE. + step4point6: + INSTRUMENT_INC(failedAtIteration[i]); + goto end; + // 4.7 Continue. Comment: Increment i for the do-loop in step 4. + step4point7: + continue; + } + // 5. Return PROBABLY PRIME + ret = TRUE; + end: + return ret; +} +#if ALG_RSA +/* 10.2.14.1.6 RsaCheckPrime() */ +/* This will check to see if a number is prime and appropriate for an RSA prime. */ +/* This has different functionality based on whether we are using key sieving or not. If not, the + number checked to see if it is divisible by the public exponent, then the number is adjusted + either up or down in order to make it a better candidate. It is then checked for being probably + prime. */ +/* If sieving is used, the number is used to root a sieving process. */ +TPM_RC +RsaCheckPrime( + bigNum prime, + UINT32 exponent, + RAND_STATE *rand + ) +{ +#if !RSA_KEY_SIEVE + TPM_RC retVal = TPM_RC_SUCCESS; + UINT32 modE = BnModWord(prime, exponent); + NOT_REFERENCED(rand); + if(modE == 0) + // evenly divisible so add two keeping the number odd + BnAddWord(prime, prime, 2); + // want 0 != (p - 1) mod e + // which is 1 != p mod e + else if(modE == 1) + // subtract 2 keeping number odd and insuring that + // 0 != (p - 1) mod e + BnSubWord(prime, prime, 2); + if(BnIsProbablyPrime(prime, rand) == 0) + ERROR_RETURN(g_inFailureMode ? TPM_RC_FAILURE : TPM_RC_VALUE); + Exit: + return retVal; +#else + return PrimeSelectWithSieve(prime, exponent, rand); +#endif +} +/* + * RsaAdjustPrimeCandidate_PreRev155 is the pre-rev.155 algorithm used; we + * still have to use it for old seeds to maintain backwards compatibility. + */ +static void +RsaAdjustPrimeCandidate_PreRev155( + bigNum prime + ) +{ + UINT16 highBytes; + crypt_uword_t *msw = &prime->d[prime->size - 1]; +#define MASK (MAX_CRYPT_UWORD >> (RADIX_BITS - 16)) + highBytes = *msw >> (RADIX_BITS - 16); + // This is fixed point arithmetic on 16-bit values + highBytes = ((UINT32)highBytes * (UINT32)0x4AFB) >> 16; + highBytes += 0xB505; + *msw = ((crypt_uword_t)(highBytes) << (RADIX_BITS - 16)) + (*msw & MASK); + prime->d[0] |= 1; +} + +/* 10.2.14.1.7 RsaAdjustPrimeCandidate() */ + +/* For this math, we assume that the RSA numbers are fixed-point numbers with the decimal point to + the left of the most significant bit. This approach helps make it clear what is happening with + the MSb of the values. The two RSA primes have to be large enough so that their product will be a + number with the necessary number of significant bits. For example, we want to be able to multiply + two 1024-bit numbers to produce a number with 2048 significant bits. If we accept any 1024-bit + prime that has its MSb set, then it is possible to produce a product that does not have the MSb + SET. For example, if we use tiny keys of 16 bits and have two 8-bit primes of 0x80, then the + public key would be 0x4000 which is only 15-bits. So, what we need to do is made sure that each + of the primes is large enough so that the product of the primes is twice as large as each + prime. A little arithmetic will show that the only way to do this is to make sure that each of + the primes is no less than root(2)/2. That's what this functions does. This function adjusts the + candidate prime so that it is odd and >= root(2)/2. This allows the product of these two numbers + to be .5, which, in fixed point notation means that the most significant bit is 1. For this + routine, the root(2)/2 (0.7071067811865475) approximated with 0xB505 which is, in fixed point, + 0.7071075439453125 or an error of 0.000108%. Just setting the upper two bits would give a value > + 0.75 which is an error of > 6%. Given the amount of time all the other computations take, + reducing the error is not much of a cost, but it isn't totally required either. */ +/* This function can be replaced with a function that just sets the two most significant bits of + each prime candidate without introducing any computational issues. */ + +static void +RsaAdjustPrimeCandidate_New( + bigNum prime + ) +{ + UINT32 msw; + UINT32 adjusted; + + // If the radix is 32, the compiler should turn this into a simple assignment + msw = prime->d[prime->size - 1] >> ((RADIX_BITS == 64) ? 32 : 0); + // Multiplying 0xff...f by 0x4AFB gives 0xff..f - 0xB5050...0 + adjusted = (msw >> 16) * 0x4AFB; + adjusted += ((msw & 0xFFFF) * 0x4AFB) >> 16; + adjusted += 0xB5050000UL; +#if RADIX_BITS == 64 + // Save the low-order 32 bits + prime->d[prime->size - 1] &= 0xFFFFFFFFUL; + // replace the upper 32-bits + prime->d[prime->size -1] |= ((crypt_uword_t)adjusted << 32); +#else + prime->d[prime->size - 1] = (crypt_uword_t)adjusted; +#endif + // make sure the number is odd + prime->d[0] |= 1; +} + + +LIB_EXPORT void +RsaAdjustPrimeCandidate( + bigNum prime, + SEED_COMPAT_LEVEL seedCompatLevel // IN: compatibility level; libtpms added + ) +{ + switch (seedCompatLevel) { + case SEED_COMPAT_LEVEL_ORIGINAL: + RsaAdjustPrimeCandidate_PreRev155(prime); + break; + case SEED_COMPAT_LEVEL_LAST: + /* case SEED_COMPAT_LEVEL_RSA_PRIME_ADJUST_FIX: */ + RsaAdjustPrimeCandidate_New(prime); + break; + default: + FAIL(FATAL_ERROR_INTERNAL); + } +} +/* 10.2.14.1.8 BnGeneratePrimeForRSA() */ +/* Function to generate a prime of the desired size with the proper attributes for an RSA prime. */ + +TPM_RC +BnGeneratePrimeForRSA( + bigNum prime, // IN/OUT: points to the BN that will get the + // random value + UINT32 bits, // IN: number of bits to get + UINT32 exponent, // IN: the exponent + RAND_STATE *rand // IN: the random state + ) +{ + BOOL found = FALSE; + // + // Make sure that the prime is large enough + pAssert(prime->allocated >= BITS_TO_CRYPT_WORDS(bits)); + // Only try to handle specific sizes of keys in order to save overhead + pAssert((bits % 32) == 0); + + prime->size = BITS_TO_CRYPT_WORDS(bits); + + while(!found) + { + // The change below is to make sure that all keys that are generated from the same + // seed value will be the same regardless of the endianness or word size of the CPU. + // DRBG_Generate(rand, (BYTE *)prime->d, (UINT16)BITS_TO_BYTES(bits));// old + // if(g_inFailureMode) // old + // libtpms changed begin + switch (DRBG_GetSeedCompatLevel(rand)) { + case SEED_COMPAT_LEVEL_ORIGINAL: + DRBG_Generate(rand, (BYTE *)prime->d, (UINT16)BITS_TO_BYTES(bits)); + if (g_inFailureMode) + return TPM_RC_FAILURE; + break; + case SEED_COMPAT_LEVEL_LAST: + /* case SEED_COMPAT_LEVEL_RSA_PRIME_ADJUST_FIX: */ + if(!BnGetRandomBits(prime, bits, rand)) // new + return TPM_RC_FAILURE; + break; + default: + FAIL(FATAL_ERROR_INTERNAL); + } + RsaAdjustPrimeCandidate(prime, DRBG_GetSeedCompatLevel(rand)); + // libtpms changed end + found = RsaCheckPrime(prime, exponent, rand) == TPM_RC_SUCCESS; + } + return TPM_RC_SUCCESS; +} + +#endif // TPM_ALG_RSA diff --git a/src/tpm2/crypto/openssl/CryptPrimeSieve.c b/src/tpm2/crypto/openssl/CryptPrimeSieve.c new file mode 100644 index 0000000..8c4e52b --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptPrimeSieve.c @@ -0,0 +1,554 @@ +/********************************************************************************/ +/* */ +/* CryptPrimeSieve */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptPrimeSieve.c 1519 2019-11-15 20:43:51Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +/* 10.2.17 CryptPrimeSieve.c */ +/* 10.2.17.1 Includes and defines */ +#include "Tpm.h" +#if RSA_KEY_SIEVE +#include "CryptPrimeSieve_fp.h" +/* This determines the number of bits in the largest sieve field. */ +#define MAX_FIELD_SIZE 2048 +extern const uint32_t s_LastPrimeInTable; +extern const uint32_t s_PrimeTableSize; +extern const uint32_t s_PrimesInTable; +extern const unsigned char s_PrimeTable[]; +/* This table is set of prime markers. Each entry is the prime value for the ((n + 1) * 1024) + prime. That is, the entry in s_PrimeMarkers[1] is the value for the 2,048th prime. This is used + in the PrimeSieve() to adjust the limit for the prime search. When processing smaller prime + candidates, fewer primes are checked directly before going to Miller-Rabin. As the prime grows, + it is worth spending more time eliminating primes as, a) the density is lower, and b) the cost of + Miller-Rabin is higher. */ +const uint32_t s_PrimeMarkersCount = 6; +const uint32_t s_PrimeMarkers[] = { + 8167, 17881, 28183, 38891, 49871, 60961 }; +uint32_t primeLimit; + +/* 10.2.17.1.1 RsaAdjustPrimeLimit() */ +/* This used during the sieve process. The iterator for getting the next prime (RsaNextPrime()) will + return primes until it hits the limit (primeLimit) set up by this function. This causes the sieve + process to stop when an appropriate number of primes have been sieved. */ + +void +RsaAdjustPrimeLimit( + uint32_t requestedPrimes + ) +{ + if(requestedPrimes == 0 || requestedPrimes > s_PrimesInTable) + requestedPrimes = s_PrimesInTable; + requestedPrimes = (requestedPrimes - 1) / 1024; + if(requestedPrimes < s_PrimeMarkersCount) + primeLimit = s_PrimeMarkers[requestedPrimes]; + else + primeLimit = s_LastPrimeInTable - 2; // libtpms: Fix for 3072 bit keys to avoid mark=5 + primeLimit >>= 1; +} + +/* 10.2.17.1.2 RsaNextPrime() */ +/* This the iterator used during the sieve process. The input is the last prime returned (or any + starting point) and the output is the next higher prime. The function returns 0 when the + primeLimit is reached. */ +uint32_t +RsaNextPrime( + uint32_t lastPrime + ) +{ + if(lastPrime == 0) + return 0; + lastPrime >>= 1; + for(lastPrime += 1; lastPrime <= primeLimit; lastPrime++) + { + if(((s_PrimeTable[lastPrime >> 3] >> (lastPrime & 0x7)) & 1) == 1) + return ((lastPrime << 1) + 1); + } + return 0; +} +/* This table contains a previously sieved table. It has the bits for 3, 5, and 7 removed. Because + of the factors, it needs to be aligned to 105 and has a repeat of 105. */ +const BYTE seedValues[] = { + 0x16, 0x29, 0xcb, 0xa4, 0x65, 0xda, 0x30, 0x6c, + 0x99, 0x96, 0x4c, 0x53, 0xa2, 0x2d, 0x52, 0x96, + 0x49, 0xcb, 0xb4, 0x61, 0xd8, 0x32, 0x2d, 0x99, + 0xa6, 0x44, 0x5b, 0xa4, 0x2c, 0x93, 0x96, 0x69, + 0xc3, 0xb0, 0x65, 0x5a, 0x32, 0x4d, 0x89, 0xb6, + 0x48, 0x59, 0x26, 0x2d, 0xd3, 0x86, 0x61, 0xcb, + 0xb4, 0x64, 0x9a, 0x12, 0x6d, 0x91, 0xb2, 0x4c, + 0x5a, 0xa6, 0x0d, 0xc3, 0x96, 0x69, 0xc9, 0x34, + 0x25, 0xda, 0x22, 0x65, 0x99, 0xb4, 0x4c, 0x1b, + 0x86, 0x2d, 0xd3, 0x92, 0x69, 0x4a, 0xb4, 0x45, + 0xca, 0x32, 0x69, 0x99, 0x36, 0x0c, 0x5b, 0xa6, + 0x25, 0xd3, 0x94, 0x68, 0x8b, 0x94, 0x65, 0xd2, + 0x32, 0x6d, 0x18, 0xb6, 0x4c, 0x4b, 0xa6, 0x29, + 0xd1}; +#define USE_NIBBLE +#ifndef USE_NIBBLE +static const BYTE bitsInByte[256] = { + 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, + 0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 +}; +#define BitsInByte(x) bitsInByte[(unsigned char)x] +#else +const BYTE bitsInNibble[16] = { + 0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03, + 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04}; +#define BitsInByte(x) \ + (bitsInNibble[(unsigned char)(x) & 0xf] \ + + bitsInNibble[((unsigned char)(x) >> 4) & 0xf]) +#endif + +/* 10.2.17.1.3 BitsInArry() */ +/* This function counts the number of bits set in an array of bytes. */ +static int +BitsInArray( + const unsigned char *a, // IN: A pointer to an array of bytes + unsigned int aSize // IN: the number of bytes to sum + ) +{ + int j = 0; + for(; aSize; a++, aSize--) + j += BitsInByte(*a); + return j; +} + +/* 10.2.17.1.4 FindNthSetBit() */ +/* This function finds the nth SET bit in a bit array. The n parameter is between 1 and the number + of bits in the array (always a multiple of 8). If called when the array does not have n bits set, + it will return -1 */ +/* Return Values Meaning */ +/* <0 no bit is set or no bit with the requested number is set */ +/* >=0 the number of the bit in the array that is the nth set */ +int +FindNthSetBit( + const UINT16 aSize, // IN: the size of the array to check + const BYTE *a, // IN: the array to check + const UINT32 n // IN, the number of the SET bit + ) +{ + UINT16 i; + int retValue; + UINT32 sum = 0; + BYTE sel; + //find the bit + for(i = 0; (i < (int)aSize) && (sum < n); i++) + sum += BitsInByte(a[i]); + i--; + // The chosen bit is in the byte that was just accessed + // Compute the offset to the start of that byte + retValue = i * 8 - 1; + sel = a[i]; + // Subtract the bits in the last byte added. + sum -= BitsInByte(sel); + // Now process the byte, one bit at a time. + for(; (sel != 0) && (sum != n); retValue++, sel = sel >> 1) + sum += (sel & 1) != 0; + return (sum == n) ? retValue : -1; +} +typedef struct +{ + UINT16 prime; + UINT16 count; +} SIEVE_MARKS; +const SIEVE_MARKS sieveMarks[5] = { + {31, 7}, {73, 5}, {241, 4}, {1621, 3}, {UINT16_MAX, 2}}; + +/* 10.2.17.1.5 PrimeSieve() */ +/* This function does a prime sieve over the input field which has as its starting address the value + in bnN. Since this initializes the Sieve using a precomputed field with the bits associated with + 3, 5 and 7 already turned off, the value of pnN may need to be adjusted by a few counts to allow + the precomputed field to be used without modification. */ +/* To get better performance, one could address the issue of developing the composite numbers. When + the size of the prime gets large, the time for doing the divisions goes up, noticeably. It could + be better to develop larger composite numbers even if they need to be bigNum's themselves. The + object would be to reduce the number of times that the large prime is divided into a few large + divides and then use smaller divides to get to the final 16 bit (or smaller) remainders. */ +UINT32 +PrimeSieve( + bigNum bnN, // IN/OUT: number to sieve + UINT32 fieldSize, // IN: size of the field area in bytes + BYTE *field // IN: field + ) +{ + UINT32 i; + UINT32 j; + UINT32 fieldBits = fieldSize * 8; + UINT32 r; + BYTE *pField; + INT32 iter; + UINT32 adjust; + UINT32 mark = 0; + UINT32 count = sieveMarks[0].count; + UINT32 stop = sieveMarks[0].prime; + UINT32 composite; + UINT32 pList[8]; + UINT32 next; + pAssert(field != NULL && bnN != NULL); + // If the remainder is odd, then subtracting the value will give an even number, + // but we want an odd number, so subtract the 105+rem. Otherwise, just subtract + // the even remainder. + adjust = (UINT32)BnModWord(bnN, 105); + if(adjust & 1) + adjust += 105; + // Adjust the input number so that it points to the first number in a + // aligned field. + BnSubWord(bnN, bnN, adjust); + // pAssert(BnModWord(bnN, 105) == 0); + pField = field; + for(i = fieldSize; i >= sizeof(seedValues); + pField += sizeof(seedValues), i -= sizeof(seedValues)) + { + memcpy(pField, seedValues, sizeof(seedValues)); + } + if(i != 0) + memcpy(pField, seedValues, i); + // Cycle through the primes, clearing bits + // Have already done 3, 5, and 7 + iter = 7; +#define NEXT_PRIME(iter) (iter = RsaNextPrime(iter)) + // Get the next N primes where N is determined by the mark in the sieveMarks + while((composite = NEXT_PRIME(iter)) != 0) + { + next = 0; + i = count; + pList[i--] = composite; + for(; i > 0; i--) + { + next = NEXT_PRIME(iter); + pList[i] = next; + if(next != 0) + composite *= next; + } + // Get the remainder when dividing the base field address + // by the composite + composite = (UINT32)BnModWord(bnN, composite); + // 'composite' is divisible by the composite components. for each of the + // composite components, divide 'composite'. That remainder (r) is used to + // pick a starting point for clearing the array. The stride is equal to the + // composite component. Note, the field only contains odd numbers. If the + // field were expanded to contain all numbers, then half of the bits would + // have already been cleared. We can save the trouble of clearing them a + // second time by having a stride of 2*next. Or we can take all of the even + // numbers out of the field and use a stride of 'next' + for(i = count; i > 0; i--) + { + next = pList[i]; + if(next == 0) + goto done; + r = composite % next; + // these computations deal with the fact that we have picked a field-sized + // range that is aligned to a 105 count boundary. The problem is, this field + // only contains odd numbers. If we take our prime guess and walk through all + // the numbers using that prime as the 'stride', then every other 'stride' is + // going to be an even number. So, we are actually counting by 2 * the stride + // We want the count to start on an odd number at the start of our field. That + // is, we want to assume that we have counted up to the edge of the field by + // the 'stride' and now we are going to start flipping bits in the field as we + // continue to count up by 'stride'. If we take the base of our field and + // divide by the stride, we find out how much we find out how short the last + // count was from reaching the edge of the bit field. Say we get a quotient of + // 3 and remainder of 1. This means that after 3 strides, we are 1 short of + // the start of the field and the next stride will either land within the + // field or step completely over it. The confounding factor is that our field + // only contains odd numbers and our stride is actually 2 * stride. If the + // quoitent is even, then that means that when we add 2 * stride, we are going + // to hit another even number. So, we have to know if we need to back off + // by 1 stride before we start counting by 2 * stride. + // We can tell from the remainder whether we are on an even or odd + // stride when we hit the beginning of the table. If we are on an odd stride + // (r & 1), we would start half a stride in (next - r)/2. If we are on an + // even stride, we need 0.5 strides (next - r/2) because the table only has + // odd numbers. If the remainder happens to be zero, then the start of the + // table is on stride so no adjustment is necessary. + + if(r & 1) j = (next - r) / 2; + else if(r == 0) j = 0; + else j = next - (r / 2); + for(; j < fieldBits; j += next) + ClearBit(j, field, fieldSize); + } + if(next >= stop) + { + mark++; + count = sieveMarks[mark].count; + stop = sieveMarks[mark].prime; + } + } + done: + INSTRUMENT_INC(totalFieldsSieved[PrimeIndex]); + i = BitsInArray(field, fieldSize); + INSTRUMENT_ADD(bitsInFieldAfterSieve[PrimeIndex], i); + INSTRUMENT_ADD(emptyFieldsSieved[PrimeIndex], (i == 0)); + return i; +} +#ifdef SIEVE_DEBUG +static uint32_t fieldSize = 210; + +/* 10.2.17.1.6 SetFieldSize() */ +/* Function to set the field size used for prime generation. Used for tuning. */ +uint32_t +SetFieldSize( + uint32_t newFieldSize + ) +{ + if(newFieldSize == 0 || newFieldSize > MAX_FIELD_SIZE) + fieldSize = MAX_FIELD_SIZE; + else + fieldSize = newFieldSize; + return fieldSize; +} +#endif // SIEVE_DEBUG + +/* 10.2.17.1.7 PrimeSelectWithSieve() */ +/* This function will sieve the field around the input prime candidate. If the sieve field is not + empty, one of the one bits in the field is chosen for testing with Miller-Rabin. If the value is + prime, pnP is updated with this value and the function returns success. If this value is not + prime, another pseudo-random candidate is chosen and tested. This process repeats until all + values in the field have been checked. If all bits in the field have been checked and none is + prime, the function returns FALSE and a new random value needs to be chosen. */ +/* Error Returns Meaning */ +/* TPM_RC_FAILURE TPM in failure mode, probably due to entropy source */ +/* TPM_RC_SUCCESS candidate is probably prime */ +/* TPM_RC_NO_RESULT candidate is not prime and couldn't find and alternative in the field */ +LIB_EXPORT TPM_RC +PrimeSelectWithSieve( + bigNum candidate, // IN/OUT: The candidate to filter + UINT32 e, // IN: the exponent + RAND_STATE *rand // IN: the random number generator state + ) +{ + BYTE field[MAX_FIELD_SIZE]; + UINT32 first; + UINT32 ones; + INT32 chosen; + BN_PRIME(test); + UINT32 modE; +#ifndef SIEVE_DEBUG + UINT32 fieldSize = MAX_FIELD_SIZE; +#endif + UINT32 primeSize; + // + // Adjust the field size and prime table list to fit the size of the prime + // being tested. This is done to try to optimize the trade-off between the + // dividing done for sieving and the time for Miller-Rabin. When the size + // of the prime is large, the cost of Miller-Rabin is fairly high, as is the + // cost of the sieving. However, the time for Miller-Rabin goes up considerably + // faster than the cost of dividing by a number of primes. + primeSize = BnSizeInBits(candidate); + + if(primeSize <= 512) + { + RsaAdjustPrimeLimit(1024); // Use just the first 1024 primes + } + else if(primeSize <= 1024) + { + RsaAdjustPrimeLimit(4096); // Use just the first 4K primes + } + else + { + RsaAdjustPrimeLimit(0); // Use all available + } + + // Save the low-order word to use as a search generator and make sure that + // it has some interesting range to it + first = (UINT32)(candidate->d[0] | 0x80000000); + + // Sieve the field + ones = PrimeSieve(candidate, fieldSize, field); + pAssert(ones > 0 && ones < (fieldSize * 8)); + for(; ones > 0; ones--) + { + // Decide which bit to look at and find its offset + chosen = FindNthSetBit((UINT16)fieldSize, field, ((first % ones) + 1)); + + if((chosen < 0) || (chosen >= (INT32)(fieldSize * 8))) + FAIL(FATAL_ERROR_INTERNAL); + + // Set this as the trial prime + BnAddWord(test, candidate, (crypt_uword_t)(chosen * 2)); + + // The exponent might not have been one of the tested primes so + // make sure that it isn't divisible and make sure that 0 != (p-1) mod e + // Note: This is the same as 1 != p mod e + modE = (UINT32)BnModWord(test, e); + if((modE != 0) && (modE != 1) && MillerRabin(test, rand)) + { + BnCopy(candidate, test); + return TPM_RC_SUCCESS; + } + // Clear the bit just tested + ClearBit(chosen, field, fieldSize); + } + // Ran out of bits and couldn't find a prime in this field + INSTRUMENT_INC(noPrimeFields[PrimeIndex]); + return (g_inFailureMode ? TPM_RC_FAILURE : TPM_RC_NO_RESULT); +} + +#if RSA_INSTRUMENT +static char a[256]; +char * +PrintTuple( + UINT32 *i + ) +{ + sprintf(a, "{%d, %d, %d}", i[0], i[1], i[2]); + return a; +} +#define CLEAR_VALUE(x) memset(x, 0, sizeof(x)) + +void +RsaSimulationEnd( + void + ) +{ + int i; + UINT32 averages[3]; + UINT32 nonFirst = 0; + if((PrimeCounts[0] + PrimeCounts[1] + PrimeCounts[2]) != 0) + { + printf("Primes generated = %s\n", PrintTuple(PrimeCounts)); + printf("Fields sieved = %s\n", PrintTuple(totalFieldsSieved)); + printf("Fields with no primes = %s\n", PrintTuple(noPrimeFields)); + printf("Primes checked with Miller-Rabin = %s\n", + PrintTuple(MillerRabinTrials)); + for(i = 0; i < 3; i++) + averages[i] = (totalFieldsSieved[i] + != 0 ? bitsInFieldAfterSieve[i] / totalFieldsSieved[i] + : 0); + printf("Average candidates in field %s\n", PrintTuple(averages)); + for(i = 1; i < (sizeof(failedAtIteration) / sizeof(failedAtIteration[0])); + i++) + nonFirst += failedAtIteration[i]; + printf("Miller-Rabin failures not in first round = %d\n", nonFirst); + } + CLEAR_VALUE(PrimeCounts); + CLEAR_VALUE(totalFieldsSieved); + CLEAR_VALUE(noPrimeFields); + CLEAR_VALUE(MillerRabinTrials); + CLEAR_VALUE(bitsInFieldAfterSieve); +} +void +GetSieveStats( + uint32_t *trials, + uint32_t *emptyFields, + uint32_t *averageBits + ) +{ + uint32_t totalBits; + uint32_t fields; + *trials = MillerRabinTrials[0] + MillerRabinTrials[1] + MillerRabinTrials[2]; + *emptyFields = noPrimeFields[0] + noPrimeFields[1] + noPrimeFields[2]; + fields = totalFieldsSieved[0] + totalFieldsSieved[1] + + totalFieldsSieved[2]; + totalBits = bitsInFieldAfterSieve[0] + bitsInFieldAfterSieve[1] + + bitsInFieldAfterSieve[2]; + if(fields != 0) + *averageBits = totalBits / fields; + else + *averageBits = 0; + CLEAR_VALUE(PrimeCounts); + CLEAR_VALUE(totalFieldsSieved); + CLEAR_VALUE(noPrimeFields); + CLEAR_VALUE(MillerRabinTrials); + CLEAR_VALUE(bitsInFieldAfterSieve); +} +#endif +#endif // RSA_KEY_SIEVE +#if !RSA_INSTRUMENT +//*** RsaSimulationEnd() +// Stub for call when not doing instrumentation. +#if 0 // libtpms added +void +RsaSimulationEnd( + void + ) +{ + return; +} +#endif // libtpms added +#endif diff --git a/src/tpm2/crypto/openssl/CryptRand.c b/src/tpm2/crypto/openssl/CryptRand.c new file mode 100644 index 0000000..5bf0643 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptRand.c @@ -0,0 +1,881 @@ +/********************************************************************************/ +/* */ +/* DRBG with a behavior according to SP800-90A */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptRand.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "PRNG_TestVectors.h" +const BYTE DRBG_NistTestVector_Entropy[] = {DRBG_TEST_INITIATE_ENTROPY}; +const BYTE DRBG_NistTestVector_GeneratedInterm[] = + {DRBG_TEST_GENERATED_INTERM}; +const BYTE DRBG_NistTestVector_EntropyReseed[] = + {DRBG_TEST_RESEED_ENTROPY}; +const BYTE DRBG_NistTestVector_Generated[] = {DRBG_TEST_GENERATED}; + +/* 10.2.16.2.2 Derivation Function Defines and Structures */ +#define DF_COUNT (DRBG_KEY_SIZE_WORDS / DRBG_IV_SIZE_WORDS + 1) +#if DRBG_KEY_SIZE_BITS != 128 && DRBG_KEY_SIZE_BITS != 256 +# error "CryptRand.c only written for AES with 128- or 256-bit keys." +#endif + +typedef struct +{ + DRBG_KEY_SCHEDULE keySchedule; + DRBG_IV iv[DF_COUNT]; + DRBG_IV out1; + DRBG_IV buf; + int contents; +} DF_STATE, *PDF_STATE; +/* 10.2.16.2.3 DfCompute() */ +/* This function does the incremental update of the derivation function state. It encrypts the iv + value and XOR's the results into each of the blocks of the output. This is equivalent to + processing all of input data for each output block. */ +static void +DfCompute( + PDF_STATE dfState + ) +{ + int i; + int iv; + crypt_uword_t *pIv; + crypt_uword_t temp[DRBG_IV_SIZE_WORDS] = {0}; + // + for(iv = 0; iv < DF_COUNT; iv++) + { + pIv = (crypt_uword_t *)&dfState->iv[iv].words[0]; + for(i = 0; i < DRBG_IV_SIZE_WORDS; i++) + { + temp[i] ^= pIv[i] ^ dfState->buf.words[i]; + } + DRBG_ENCRYPT(&dfState->keySchedule, &temp, pIv); + } + for(i = 0; i < DRBG_IV_SIZE_WORDS; i++) + dfState->buf.words[i] = 0; + dfState->contents = 0; +} +/* 10.2.16.2.4 DfStart() */ +/* This initializes the output blocks with an encrypted counter value and initializes the key + schedule. */ +static void +DfStart( + PDF_STATE dfState, + uint32_t inputLength + ) +{ + BYTE init[8]; + int i; + UINT32 drbgSeedSize = sizeof(DRBG_SEED); + const BYTE dfKey[DRBG_KEY_SIZE_BYTES] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f +#if DRBG_KEY_SIZE_BYTES > 16 + ,0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f +#endif + }; + memset(dfState, 0, sizeof(DF_STATE)); + DRBG_ENCRYPT_SETUP(&dfKey[0], DRBG_KEY_SIZE_BITS, &dfState->keySchedule); + // Create the first chaining values + for(i = 0; i < DF_COUNT; i++) + ((BYTE *)&dfState->iv[i])[3] = (BYTE)i; + DfCompute(dfState); + // initialize the first 64 bits of the IV in a way that doesn't depend + // on the size of the words used. + UINT32_TO_BYTE_ARRAY(inputLength, init); + UINT32_TO_BYTE_ARRAY(drbgSeedSize, &init[4]); + memcpy(&dfState->iv[0], init, 8); + dfState->contents = 4; +} +/* 10.2.16.2.5 DfUpdate() */ +/* This updates the state with the input data. A byte at a time is moved into the state buffer until + it is full and then that block is encrypted by DfCompute(). */ +static void +DfUpdate( + PDF_STATE dfState, + int size, + const BYTE *data + ) +{ + while(size > 0) + { + int toFill = DRBG_IV_SIZE_BYTES - dfState->contents; + if(size < toFill) + toFill = size; + // Copy as many bytes as there are or until the state buffer is full + memcpy(&dfState->buf.bytes[dfState->contents], data, toFill); + // Reduce the size left by the amount copied + size -= toFill; + // Advance the data pointer by the amount copied + data += toFill; + // increase the buffer contents count by the amount copied + dfState->contents += toFill; + pAssert(dfState->contents <= DRBG_IV_SIZE_BYTES); + // If we have a full buffer, do a computation pass. + if(dfState->contents == DRBG_IV_SIZE_BYTES) + DfCompute(dfState); + } +} +/* 10.2.16.2.6 DfEnd() */ +/* This function is called to get the result of the derivation function computation. If the buffer + is not full, it is padded with zeros. The output buffer is structured to be the same as a + DRBG_SEED value so that the function can return a pointer to the DRBG_SEED value in the DF_STATE + structure. */ +static DRBG_SEED * +DfEnd( + PDF_STATE dfState + ) +{ + // Since DfCompute is always called when a buffer is full, there is always + // space in the buffer for the terminator + dfState->buf.bytes[dfState->contents++] = 0x80; + // If the buffer is not full, pad with zeros + while(dfState->contents < DRBG_IV_SIZE_BYTES) + dfState->buf.bytes[dfState->contents++] = 0; + // Do a final state update + DfCompute(dfState); + return (DRBG_SEED *)&dfState->iv; +} +/* 10.2.16.2.7 DfBuffer() */ +/* Function to take an input buffer and do the derivation function to produce a DRBG_SEED value that + can be used in DRBG_Reseed(); */ +static DRBG_SEED * +DfBuffer( + DRBG_SEED *output, // OUT: receives the result + int size, // IN: size of the buffer to add + BYTE *buf // IN: address of the buffer + ) +{ + DF_STATE dfState; + if(size == 0 || buf == NULL) + return NULL; + // Initialize the derivation function + DfStart(&dfState, size); + DfUpdate(&dfState, size, buf); + DfEnd(&dfState); + memcpy(output, &dfState.iv[0], sizeof(DRBG_SEED)); + return output; +} +/* 10.2.16.2.8 DRBG_GetEntropy() */ +/* Even though this implementation never fails, it may get blocked indefinitely long in the call to + get entropy from the platform (DRBG_GetEntropy32()). This function is only used during + instantiation of the DRBG for manufacturing and on each start-up after an non-orderly + shutdown. */ +/* Return Values Meaning */ +/* TRUE Requested entropy returned */ +/* FALSE Entropy Failure */ +BOOL +DRBG_GetEntropy( + UINT32 requiredEntropy, // IN: requested number of bytes of full + // entropy + BYTE *entropy // OUT: buffer to return collected entropy + ) +{ +#if !USE_DEBUG_RNG + UINT32 obtainedEntropy; + INT32 returnedEntropy; + // If in debug mode, always use the self-test values for initialization + if(IsSelfTest()) + { +#endif + // If doing simulated DRBG, then check to see if the + // entropyFailure condition is being tested + if(!IsEntropyBad())/* This function increments the IV value by 1. It is used by EncryptDRBG(). */ + { + // In self-test, the caller should be asking for exactly the seed + // size of entropy. + pAssert(requiredEntropy == sizeof(DRBG_NistTestVector_Entropy)); + memcpy(entropy, DRBG_NistTestVector_Entropy, + sizeof(DRBG_NistTestVector_Entropy)); + } +#if !USE_DEBUG_RNG + } + else if(!IsEntropyBad()) + { + // Collect entropy + // Note: In debug mode, the only "entropy" value ever returned + // is the value of the self-test vector. + for(returnedEntropy = 1, obtainedEntropy = 0; + obtainedEntropy < requiredEntropy && !IsEntropyBad(); + obtainedEntropy += returnedEntropy) + { + returnedEntropy = _plat__GetEntropy(&entropy[obtainedEntropy], + requiredEntropy - obtainedEntropy); + if(returnedEntropy <= 0) + SetEntropyBad(); + } + } +#endif + return !IsEntropyBad(); +} + +void +IncrementIv( + DRBG_IV *iv + ) +{ + BYTE *ivP = ((BYTE *)iv) + DRBG_IV_SIZE_BYTES; + while((--ivP >= (BYTE *)iv) && ((*ivP = ((*ivP + 1) & 0xFF)) == 0)); +} +/* 10.2.16.2.10 EncryptDRBG() */ +/* This does the encryption operation for the DRBG. It will encrypt the input state counter (IV) + using the state key. Into the output buffer for as many times as it takes to generate the + required number of bytes. */ +static BOOL +EncryptDRBG( + BYTE *dOut, + UINT32 dOutBytes, + DRBG_KEY_SCHEDULE *keySchedule, + DRBG_IV *iv, + UINT32 *lastValue // Points to the last output value + ) +{ +#if FIPS_COMPLIANT + // For FIPS compliance, the DRBG has to do a continuous self-test to make sure that + // no two consecutive values are the same. This overhead is not incurred if the TPM + // is not required to be FIPS compliant + // + UINT32 temp[DRBG_IV_SIZE_BYTES / sizeof(UINT32)]; + int i; + BYTE *p; + for(; dOutBytes > 0;) + { + // Increment the IV before each encryption (this is what makes this + // different from normal counter-mode encryption + IncrementIv(iv); + DRBG_ENCRYPT(keySchedule, iv, temp); + // Expect a 16 byte block +#if DRBG_IV_SIZE_BITS != 128 +#error "Unsuppored IV size in DRBG" +#endif + if((lastValue[0] == temp[0]) + && (lastValue[1] == temp[1]) + && (lastValue[2] == temp[2]) + && (lastValue[3] == temp[3]) + ) + { + LOG_FAILURE(FATAL_ERROR_ENTROPY); + return FALSE; + } + lastValue[0] = temp[0]; + lastValue[1] = temp[1]; + lastValue[2] = temp[2]; + lastValue[3] = temp[3]; + i = MIN(dOutBytes, DRBG_IV_SIZE_BYTES); + dOutBytes -= i; + for(p = (BYTE *)temp; i > 0; i--) + *dOut++ = *p++; + } +#else // version without continuous self-test + NOT_REFERENCED(lastValue); + for(; dOutBytes >= DRBG_IV_SIZE_BYTES; + dOut = &dOut[DRBG_IV_SIZE_BYTES], dOutBytes -= DRBG_IV_SIZE_BYTES) + { + // Increment the IV + IncrementIv(iv); + DRBG_ENCRYPT(keySchedule, iv, dOut); + } + // If there is a partial, generate into a block-sized + // temp buffer and copy to the output. + if(dOutBytes != 0) + { + BYTE temp[DRBG_IV_SIZE_BYTES]; + // Increment the IV + IncrementIv(iv); + DRBG_ENCRYPT(keySchedule, iv, temp); + memcpy(dOut, temp, dOutBytes); + } +#endif + return TRUE; +} +/* 10.2.16.2.11 DRBG_Update() */ +/* This function performs the state update function. According to SP800-90A, a temp value is created + by doing CTR mode encryption of providedData and replacing the key and IV with these values. The + one difference is that, with counter mode, the IV is incremented after each block is encrypted + and in this operation, the counter is incremented before each block is encrypted. This function + implements an optimized version of the algorithm in that it does the update of the + drbgState->seed in place and then providedData is XORed into drbgState->seed to complete the + encryption of providedData. This works because the IV is the last thing that gets encrypted. */ +static BOOL +DRBG_Update( + DRBG_STATE *drbgState, // IN:OUT state to update + DRBG_KEY_SCHEDULE *keySchedule, // IN: the key schedule (optional) + DRBG_SEED *providedData // IN: additional data + ) +{ + UINT32 i; + BYTE *temp = (BYTE *)&drbgState->seed; + DRBG_KEY *key = pDRBG_KEY(&drbgState->seed); + DRBG_IV *iv = pDRBG_IV(&drbgState->seed); + DRBG_KEY_SCHEDULE localKeySchedule; + memset(&localKeySchedule, 0, sizeof(localKeySchedule)); /* libtpms added: coverity */ + // + pAssert(drbgState->magic == DRBG_MAGIC); + // If an key schedule was not provided, make one + if(keySchedule == NULL) + { + if(DRBG_ENCRYPT_SETUP((BYTE *)key, + DRBG_KEY_SIZE_BITS, &localKeySchedule) != 0) + { + LOG_FAILURE(FATAL_ERROR_INTERNAL); + return FALSE; + } + keySchedule = &localKeySchedule; + } + // Encrypt the temp value + EncryptDRBG(temp, sizeof(DRBG_SEED), keySchedule, iv, + drbgState->lastValue); + if(providedData != NULL) + { + BYTE *pP = (BYTE *)providedData; + for(i = DRBG_SEED_SIZE_BYTES; i != 0; i--) + *temp++ ^= *pP++; + } + // Since temp points to the input key and IV, we are done and + // don't need to copy the resulting 'temp' to drbgState->seed + return TRUE; +} +/* 10.2.16.2.12 DRBG_Reseed() */ +/* This function is used when reseeding of the DRBG is required. If entropy is provided, it is used + in lieu of using hardware entropy. */ +/* NOTE: the provided entropy must be the required size. */ +/* Return Values Meaning */ +/* TRUE reseed succeeded */ +/* FALSE reseed failed, probably due to the entropy generation */ +BOOL +DRBG_Reseed( + DRBG_STATE *drbgState, // IN: the state to update + DRBG_SEED *providedEntropy, // IN: entropy + DRBG_SEED *additionalData // IN: + ) +{ + DRBG_SEED seed; + pAssert((drbgState != NULL) && (drbgState->magic == DRBG_MAGIC)); + if(providedEntropy == NULL) + { + providedEntropy = &seed; + if(!DRBG_GetEntropy(sizeof(DRBG_SEED), (BYTE *)providedEntropy)) + return FALSE; + } + if(additionalData != NULL) + { + unsigned int i; + // XOR the provided data into the provided entropy + for(i = 0; i < sizeof(DRBG_SEED); i++) + ((BYTE *)providedEntropy)[i] ^= ((BYTE *)additionalData)[i]; + } + DRBG_Update(drbgState, NULL, providedEntropy); + drbgState->reseedCounter = 1; + return TRUE; +} +/* 10.2.16.2.13 DRBG_SelfTest() */ +/* This is run when the DRBG is instantiated and at startup */ +/* Return Values Meaning */ +/* FALSE test failed */ +/* TRUE test OK */ +BOOL +DRBG_SelfTest( + void + ) +{ + BYTE buf[sizeof(DRBG_NistTestVector_Generated)]; + DRBG_SEED seed; + UINT32 i; + BYTE *p; + DRBG_STATE testState; + // + pAssert(!IsSelfTest()); + SetSelfTest(); + SetDrbgTested(); + // Do an instantiate + if(!DRBG_Instantiate(&testState, 0, NULL)) + return FALSE; +#if DRBG_DEBUG_PRINT + dbgDumpMemBlock(pDRBG_KEY(&testState), DRBG_KEY_SIZE_BYTES, + "Key after Instantiate"); + dbgDumpMemBlock(pDRBG_IV(&testState), DRBG_IV_SIZE_BYTES, + "Value after Instantiate"); +#endif + if(DRBG_Generate((RAND_STATE *)&testState, buf, sizeof(buf)) == 0) + return FALSE; +#if DRBG_DEBUG_PRINT + dbgDumpMemBlock(pDRBG_KEY(&testState.seed), DRBG_KEY_SIZE_BYTES, + "Key after 1st Generate"); + dbgDumpMemBlock(pDRBG_IV(&testState.seed), DRBG_IV_SIZE_BYTES, + "Value after 1st Generate"); +#endif + if(memcmp(buf, DRBG_NistTestVector_GeneratedInterm, sizeof(buf)) != 0) + return FALSE; + memcpy(seed.bytes, DRBG_NistTestVector_EntropyReseed, sizeof(seed)); + DRBG_Reseed(&testState, &seed, NULL); +#if DRBG_DEBUG_PRINT + dbgDumpMemBlock((BYTE *)pDRBG_KEY(&testState.seed), DRBG_KEY_SIZE_BYTES, + "Key after 2nd Generate"); + dbgDumpMemBlock((BYTE *)pDRBG_IV(&testState.seed), DRBG_IV_SIZE_BYTES, + "Value after 2nd Generate"); + dbgDumpMemBlock(buf, sizeof(buf), "2nd Generated"); +#endif + if(DRBG_Generate((RAND_STATE *)&testState, buf, sizeof(buf)) == 0) + return FALSE; + if(memcmp(buf, DRBG_NistTestVector_Generated, sizeof(buf)) != 0) + return FALSE; + ClearSelfTest(); + DRBG_Uninstantiate(&testState); + for(p = (BYTE *)&testState, i = 0; i < sizeof(DRBG_STATE); i++) + { + if(*p++) + return FALSE; + } + // Simulate hardware failure to make sure that we get an error when + // trying to instantiate + SetEntropyBad(); + if(DRBG_Instantiate(&testState, 0, NULL)) + return FALSE; + ClearEntropyBad(); + return TRUE; +} +/* 10.2.16.3 Public Interface */ + +/* 10.2.16.3.1 Description */ +/* The functions in this section are the interface to the RNG. These are the functions that are used + by TPM.lib. */ + +/* 10.2.16.3.2 CryptRandomStir() */ +/* This function is used to cause a reseed. A DRBG_SEED amount of entropy is collected from the + hardware and then additional data is added. */ +/* Error Returns Meaning */ +/* TPM_RC_NO_RESULT failure of the entropy generator */ +LIB_EXPORT TPM_RC +CryptRandomStir( + UINT16 additionalDataSize, + BYTE *additionalData + ) +{ +#if !USE_DEBUG_RNG + DRBG_SEED tmpBuf; + DRBG_SEED dfResult; + // + // All reseed with outside data starts with a buffer full of entropy + if(!DRBG_GetEntropy(sizeof(tmpBuf), (BYTE *)&tmpBuf)) + return TPM_RC_NO_RESULT; + DRBG_Reseed(&drbgDefault, &tmpBuf, + DfBuffer(&dfResult, additionalDataSize, additionalData)); + drbgDefault.reseedCounter = 1; + return TPM_RC_SUCCESS; +#else + // If doing debug, use the input data as the initial setting for the RNG state + // so that the test can be reset at any time. + // Note: If this is called with a data size of 0 or less, nothing happens. The + // presumption is that, in a debug environment, the caller will have specific + // values for initialization, so this check is just a simple way to prevent + // inadvertent programming errors from screwing things up. This doesn't use an + // pAssert() because the non-debug version of this function will accept these + // parameters as meaning that there is no additionalData and only hardware + // entropy is used. + if((additionalDataSize > 0) && (additionalData != NULL)) + { + memset(drbgDefault.seed.bytes, 0, sizeof(drbgDefault.seed.bytes)); + memcpy(drbgDefault.seed.bytes, additionalData, + MIN(additionalDataSize, sizeof(drbgDefault.seed.bytes))); + } + drbgDefault.reseedCounter = 1; + return TPM_RC_SUCCESS; +#endif +} +/* 10.2.16.3.3 CryptRandomGenerate() */ +/* Generate a randomSize number or random bytes. */ +LIB_EXPORT UINT16 +CryptRandomGenerate( + UINT16 randomSize, + BYTE *buffer + ) +{ + return DRBG_Generate((RAND_STATE *)&drbgDefault, buffer, randomSize); +} +/* 10.2.16.3.4 DRBG_InstantiateSeededKdf() */ +/* Function used to instantiate a KDF-based RNG. This is used for derivations. This function always + returns TRUE. */ +LIB_EXPORT BOOL +DRBG_InstantiateSeededKdf( + KDF_STATE *state, // OUT: buffer to hold the state + TPM_ALG_ID hashAlg, // IN: hash algorithm + TPM_ALG_ID kdf, // IN: the KDF to use + TPM2B *seed, // IN: the seed to use + const TPM2B *label, // IN: a label for the generation process. + TPM2B *context, // IN: the context value + UINT32 limit // IN: Maximum number of bits from the KDF + ) +{ + state->magic = KDF_MAGIC; + state->limit = limit; + state->seed = seed; + state->hash = hashAlg; + state->kdf = kdf; + state->label = label; + state->context = context; + state->digestSize = CryptHashGetDigestSize(hashAlg); + state->counter = 0; + state->residual.t.size = 0; + return TRUE; +} +/* 10.2.16.3.5 DRBG_AdditionalData() */ +/* Function to reseed the DRBG with additional entropy. This is normally called before computing the + protection value of a primary key in the Endorsement hierarchy. */ +LIB_EXPORT void +DRBG_AdditionalData( + DRBG_STATE *drbgState, // IN:OUT state to update + TPM2B *additionalData // IN: value to incorporate + ) +{ + DRBG_SEED dfResult; + if(drbgState->magic == DRBG_MAGIC) + { + DfBuffer(&dfResult, additionalData->size, additionalData->buffer); + DRBG_Reseed(drbgState, &dfResult, NULL); + } +} +/* 10.2.16.3.6 DRBG_InstantiateSeeded() */ +/* This function is used to instantiate a random number generator from seed values. The nominal use + of this generator is to create sequences of pseudo-random numbers from a seed value. */ +/* Returns + TPM_RC_FAILURE DRBG self-test failure +*/ +LIB_EXPORT TPM_RC +DRBG_InstantiateSeeded( + DRBG_STATE *drbgState, // IN/OUT: buffer to hold the state + const TPM2B *seed, // IN: the seed to use + const TPM2B *purpose, // IN: a label for the generation process. + const TPM2B *name, // IN: name of the object + const TPM2B *additional, // IN: additional data + SEED_COMPAT_LEVEL seedCompatLevel // IN: compatibility level; libtpms added + ) +{ + DF_STATE dfState; + int totalInputSize; + // DRBG should have been tested, but... + if(!IsDrbgTested() && !DRBG_SelfTest()) + { + LOG_FAILURE(FATAL_ERROR_SELF_TEST); + return TPM_RC_FAILURE; + } + // Initialize the DRBG state + memset(drbgState, 0, sizeof(DRBG_STATE)); + drbgState->magic = DRBG_MAGIC; + drbgState->seedCompatLevel = seedCompatLevel; // libtpms added + // Size all of the values + totalInputSize = (seed != NULL) ? seed->size : 0; + totalInputSize += (purpose != NULL) ? purpose->size : 0; + totalInputSize += (name != NULL) ? name->size : 0; + totalInputSize += (additional != NULL) ? additional->size : 0; + // Initialize the derivation + DfStart(&dfState, totalInputSize); + // Run all the input strings through the derivation function + if(seed != NULL) + DfUpdate(&dfState, seed->size, seed->buffer); + if(purpose != NULL) + DfUpdate(&dfState, purpose->size, purpose->buffer); + if(name != NULL) + DfUpdate(&dfState, name->size, name->buffer); + if(additional != NULL) + DfUpdate(&dfState, additional->size, additional->buffer); + // Used the derivation function output as the "entropy" input. This is not + // how it is described in SP800-90A but this is the equivalent function + DRBG_Reseed(((DRBG_STATE *)drbgState), DfEnd(&dfState), NULL); + return TPM_RC_SUCCESS; +} +/* 10.2.16.3.7 CryptRandStartup() */ +/* This function is called when TPM_Startup() is executed. */ +/* TRUE instantiation succeeded */ /* kgold */ +/* FALSE instantiation failed */ +LIB_EXPORT BOOL +CryptRandStartup( + void + ) +{ +#if ! _DRBG_STATE_SAVE + // If not saved in NV, re-instantiate on each startup + return DRBG_Instantiate(&drbgDefault, 0, NULL); +#else + // If the running state is saved in NV, NV has to be loaded before it can + // be updated + if(go.drbgState.magic == DRBG_MAGIC) + return DRBG_Reseed(&go.drbgState, NULL, NULL); + else + return DRBG_Instantiate(&go.drbgState, 0, NULL); +#endif +} +/* 10.2.16.3.8 CryptRandInit() */ +/* This function is called when _TPM_Init() is being processed */ +LIB_EXPORT BOOL +CryptRandInit( + void + ) +{ +#if !USE_DEBUG_RNG + _plat__GetEntropy(NULL, 0); +#endif + return DRBG_SelfTest(); +} +// libtpms added begin +LIB_EXPORT SEED_COMPAT_LEVEL +DRBG_GetSeedCompatLevel( + RAND_STATE *state + ) +{ + if(state == NULL) + { + return SEED_COMPAT_LEVEL_LAST; + } + else if(state->drbg.magic == DRBG_MAGIC) + { + DRBG_STATE *drbgState = (DRBG_STATE *)state; + + return drbgState->seedCompatLevel; + } + else + { + return SEED_COMPAT_LEVEL_LAST; + } +} +// libtpms added end +/* 10.2.16.5 DRBG_Generate() */ +/* This function generates a random sequence according SP800-90A. If random is not NULL, then + randomSize bytes of random values are generated. If random is NULL or randomSize is zero, then + the function returns TRUE without generating any bits or updating the reseed counter. This + function returns 0 if a reseed is required. Otherwise, it returns the number of bytes produced + which could be less than the number requested if the request is too large.("too large" is + implementation dependent.) */ +LIB_EXPORT UINT16 +DRBG_Generate( + RAND_STATE *state, + BYTE *random, // OUT: buffer to receive the random values + UINT16 randomSize // IN: the number of bytes to generate + ) +{ + if(state == NULL) + state = (RAND_STATE *)&drbgDefault; + if(random == NULL) + return 0; + + // If the caller used a KDF state, generate a sequence from the KDF not to + // exceed the limit. + if(state->kdf.magic == KDF_MAGIC) + { + KDF_STATE *kdf = (KDF_STATE *)state; + UINT32 counter = (UINT32)kdf->counter; + INT32 bytesLeft = randomSize; + + // If the number of bytes to be returned would put the generator + // over the limit, then return 0 + if((((kdf->counter * kdf->digestSize) + randomSize) * 8) > kdf->limit) + return 0; + // Process partial and full blocks until all requested bytes provided + while(bytesLeft > 0) + { + // If there is any residual data in the buffer, copy it to the output + // buffer + if(kdf->residual.t.size > 0) + { + INT32 size; + // + // Don't use more of the residual than will fit or more than are + // available + size = MIN(kdf->residual.t.size, bytesLeft); + // Copy some or all of the residual to the output. The residual is + // at the end of the buffer. The residual might be a full buffer. + MemoryCopy(random, + &kdf->residual.t.buffer + [kdf->digestSize - kdf->residual.t.size], size); + // Advance the buffer pointer + random += size; + // Reduce the number of bytes left to get + bytesLeft -= size; + // And reduce the residual size appropriately + kdf->residual.t.size -= (UINT16)size; + } + else + { + UINT16 blocks = (UINT16)(bytesLeft / kdf->digestSize); + // + // Get the number of required full blocks + if(blocks > 0) + { + UINT16 size = blocks * kdf->digestSize; + // Get some number of full blocks and put them in the return buffer + CryptKDFa(kdf->hash, kdf->seed, kdf->label, kdf->context, NULL, + kdf->limit, random, &counter, blocks); + // reduce the size remaining to be moved and advance the pointer + bytesLeft -= size; + random += size; + } + else + { + // Fill the residual buffer with a full block and then loop to + // top to get part of it copied to the output. + kdf->residual.t.size = CryptKDFa(kdf->hash, kdf->seed, + kdf->label, kdf->context, NULL, + kdf->limit, + kdf->residual.t.buffer, + &counter, 1); + } + } + } + kdf->counter = counter; + return randomSize; + } + else if(state->drbg.magic == DRBG_MAGIC) + { + DRBG_STATE *drbgState = (DRBG_STATE *)state; + DRBG_KEY_SCHEDULE keySchedule; + DRBG_SEED *seed = &drbgState->seed; + memset(&keySchedule, 0, sizeof(keySchedule)); /* libtpms added: coverity */ + if(drbgState->reseedCounter >= CTR_DRBG_MAX_REQUESTS_PER_RESEED) + { + if(drbgState == &drbgDefault) + { + DRBG_Reseed(drbgState, NULL, NULL); + if(IsEntropyBad() && !IsSelfTest()) + return 0; + } + else + { + // If this is a PRNG then the only way to get + // here is if the SW has run away. + LOG_FAILURE(FATAL_ERROR_INTERNAL); + return 0; + } + } + // if the allowed number of bytes in a request is larger than the + // less than the number of bytes that can be requested, then check +#if UINT16_MAX >= CTR_DRBG_MAX_BYTES_PER_REQUEST + if(randomSize > CTR_DRBG_MAX_BYTES_PER_REQUEST) + randomSize = CTR_DRBG_MAX_BYTES_PER_REQUEST; +#endif + // Create encryption schedule + if(DRBG_ENCRYPT_SETUP((BYTE *)pDRBG_KEY(seed), + DRBG_KEY_SIZE_BITS, &keySchedule) != 0) + { + LOG_FAILURE(FATAL_ERROR_INTERNAL); + return 0; + } + // Generate the random data + EncryptDRBG(random, randomSize, &keySchedule, pDRBG_IV(seed), + drbgState->lastValue); + // Do a key update + DRBG_Update(drbgState, &keySchedule, NULL); + // Increment the reseed counter + drbgState->reseedCounter += 1; + } + else + { + LOG_FAILURE(FATAL_ERROR_INTERNAL); + return 0; // libtpms changed from FALSE + } + return randomSize; +} +/* 10.2.16.6 DRBG_Instantiate() */ +/* This is CTR_DRBG_Instantiate_algorithm() from [SP 800-90A 10.2.1.3.1]. This is called when a the + TPM DRBG is to be instantiated. This is called to instantiate a DRBG used by the TPM for normal + operations. */ +/* Return Values Meaning */ +/* TRUE instantiation succeeded */ +/* FALSE instantiation failed */ +LIB_EXPORT BOOL +DRBG_Instantiate( + DRBG_STATE *drbgState, // OUT: the instantiated value + UINT16 pSize, // IN: Size of personalization string + BYTE *personalization // IN: The personalization string + ) +{ + DRBG_SEED seed; + DRBG_SEED dfResult; + // + pAssert((pSize == 0) || (pSize <= sizeof(seed)) || (personalization != NULL)); + // If the DRBG has not been tested, test when doing an instantiation. Since + // Instantiation is called during self test, make sure we don't get stuck in a + // loop. + if(!IsDrbgTested() && !IsSelfTest() && !DRBG_SelfTest()) + return FALSE; + // If doing a self test, DRBG_GetEntropy will return the NIST + // test vector value. + if(!DRBG_GetEntropy(sizeof(seed), (BYTE *)&seed)) + return FALSE; + // set everything to zero + memset(drbgState, 0, sizeof(DRBG_STATE)); + drbgState->magic = DRBG_MAGIC; + // Steps 1, 2, 3, 6, 7 of SP 800-90A 10.2.1.3.1 are exactly what + // reseeding does. So, do a reduction on the personalization value (if any) + // and do a reseed. + DRBG_Reseed(drbgState, &seed, DfBuffer(&dfResult, pSize, personalization)); + return TRUE; +} +/* 10.2.16.7 DRBG_Uninstantiate() */ +/* This is Uninstantiate_function() from [SP 800-90A 9.4]. */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE not a valid state */ +LIB_EXPORT TPM_RC +DRBG_Uninstantiate( + DRBG_STATE *drbgState // IN/OUT: working state to erase + ) +{ + if((drbgState == NULL) || (drbgState->magic != DRBG_MAGIC)) + return TPM_RC_VALUE; + memset(drbgState, 0, sizeof(DRBG_STATE)); + return TPM_RC_SUCCESS; +} + diff --git a/src/tpm2/crypto/openssl/CryptRsa.c b/src/tpm2/crypto/openssl/CryptRsa.c new file mode 100644 index 0000000..4ed0438 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptRsa.c @@ -0,0 +1,1634 @@ +/********************************************************************************/ +/* */ +/* Implementation of cryptographic primitives for RSA */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptRsa.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.17 CryptRsa.c */ +/* 10.2.17.1 Introduction */ +/* This file contains implementation of cryptographic primitives for RSA. Vendors may replace the + implementation in this file with their own library functions. */ +/* 10.2.17.2 Includes */ +/* Need this define to get the private defines for this function */ +#define CRYPT_RSA_C +#include "Tpm.h" +#include "Helpers_fp.h" // libtpms added + +#include <openssl/rsa.h> // libtpms added + +#if ALG_RSA +/* 10.2.17.3 Obligatory Initialization Functions */ +/* 10.2.17.3.1 CryptRsaInit() */ +/* Function called at _TPM_Init(). */ +BOOL +CryptRsaInit( + void + ) +{ + return TRUE; +} +/* 10.2.17.3.2 CryptRsaStartup() */ +/* Function called at TPM2_Startup() */ +BOOL +CryptRsaStartup( + void + ) +{ + return TRUE; +} +/* 10.2.17.4 Internal Functions */ +void +RsaInitializeExponent( + privateExponent_t *pExp + ) +{ +#if CRT_FORMAT_RSA == NO + BN_INIT(pExp->D); +#else + BN_INIT(pExp->Q); + BN_INIT(pExp->dP); + BN_INIT(pExp->dQ); + BN_INIT(pExp->qInv); +#endif +} +/* 10.2.17.4.1 ComputePrivateExponent() */ +/* This function computes the private exponent from the primes. */ +/* Return Value Meaning */ +/* TRUE(1) success */ +/* FALSE(0) failure */ +static BOOL +ComputePrivateExponent( + bigNum P, // IN: first prime (size is 1/2 of bnN) + bigNum Q, // IN: second prime (size is 1/2 of bnN) + bigNum E, // IN: the public exponent + bigNum N, // IN: the public modulus + privateExponent_t *pExp // OUT: + ) +{ + BOOL pOK; + BOOL qOK; +#if CRT_FORMAT_RSA == NO + BN_RSA(bnPhi); + // + RsaInitializeExponent(pExp); + // Get compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1 + pOK = BnCopy(bnPhi, N); + pOK = pOK && BnSub(bnPhi, bnPhi, P); + pOK = pOK && BnSub(bnPhi, bnPhi, Q); + pOK = pOK && BnAddWord(bnPhi, bnPhi, 1); + // Compute the multiplicative inverse d = 1/e mod Phi + pOK = pOK && BnModInverse((bigNum)&pExp->D, E, bnPhi); + qOK = pOK; +#else + BN_PRIME(temp); + bigNum pT; + // + NOT_REFERENCED(N); + RsaInitializeExponent(pExp); + BnCopy((bigNum)&pExp->Q, Q); + // make p the larger value so that m2 is always less than p + if(BnUnsignedCmp(P, Q) < 0) + { + pT = P; + P = Q; + Q = pT; + } + //dP = (1/e) mod (p-1) = d mod (p-1) + pOK = BnSubWord(temp, P, 1); + pOK = pOK && BnModInverse((bigNum)&pExp->dP, E, temp); + //dQ = (1/e) mod (q-1) = d mod (q-1) + qOK = BnSubWord(temp, Q, 1); + qOK = qOK && BnModInverse((bigNum)&pExp->dQ, E, temp); + // qInv = (1/q) mod p + if(pOK && qOK) + pOK = qOK = BnModInverse((bigNum)&pExp->qInv, Q, P); +#endif + if(!pOK) + BnSetWord(P, 0); + if(!qOK) + BnSetWord(Q, 0); + return pOK && qOK; +} +/* 10.2.17.4.2 RsaPrivateKeyOp() */ +/* This function is called to do the exponentiation with the private key. Compile options allow use + of the simple (but slow) private exponent, or the more complex but faster CRT method. */ +/* Return Value Meaning */ +/* TRUE(1) success */ +/* FALSE(0) failure */ +static BOOL +RsaPrivateKeyOp( + bigNum inOut, // IN/OUT: number to be exponentiated + bigNum N, // IN: public modulus (can be NULL if CRT) + bigNum P, // IN: one of the primes (can be NULL if not CRT) + privateExponent_t *pExp + ) +{ + BOOL OK; +#if CRT_FORMAT_RSA == NO + (P); + OK = BnModExp(inOut, inOut, (bigNum)&pExp->D, N); +#else + BN_RSA(M1); + BN_RSA(M2); + BN_RSA(M); + BN_RSA(H); + bigNum Q = (bigNum)&pExp->Q; + NOT_REFERENCED(N); + // Make P the larger prime. + // NOTE that when the CRT form of the private key is created, dP will always + // be computed using the larger of p and q so the only thing needed here is that + // the primes be selected so that they agree with dP. + if(BnUnsignedCmp(P, Q) < 0) + { + bigNum T = P; + P = Q; + Q = T; + } + // m1 = cdP mod p + OK = BnModExp(M1, inOut, (bigNum)&pExp->dP, P); + // m2 = cdQ mod q + OK = OK && BnModExp(M2, inOut, (bigNum)&pExp->dQ, Q); + // h = qInv * (m1 - m2) mod p = qInv * (m1 + P - m2) mod P because Q < P + // so m2 < P + OK = OK && BnSub(H, P, M2); + OK = OK && BnAdd(H, H, M1); + OK = OK && BnModMult(H, H, (bigNum)&pExp->qInv, P); + // m = m2 + h * q + OK = OK && BnMult(M, H, Q); + OK = OK && BnAdd(inOut, M2, M); +#endif + return OK; +} +/* 10.2.17.4.3 RSAEP() */ +/* This function performs the RSAEP operation defined in PKCS#1v2.1. It is an exponentiation of a + value (m) with the public exponent (e), modulo the public (n). */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE number to exponentiate is larger than the modulus */ +#if !USE_OPENSSL_FUNCTIONS_RSA // libtpms added +static TPM_RC +RSAEP( + TPM2B *dInOut, // IN: size of the encrypted block and the size of + // the encrypted value. It must be the size of + // the modulus. + // OUT: the encrypted data. Will receive the + // decrypted value + OBJECT *key // IN: the key to use + ) +{ + TPM2B_TYPE(4BYTES, 4); + TPM2B_4BYTES(e) = {{4, {(BYTE)((RSA_DEFAULT_PUBLIC_EXPONENT >> 24) & 0xff), + (BYTE)((RSA_DEFAULT_PUBLIC_EXPONENT >> 16) & 0xff), + (BYTE)((RSA_DEFAULT_PUBLIC_EXPONENT >> 8) & 0xff), + (BYTE)((RSA_DEFAULT_PUBLIC_EXPONENT)& 0xff)}}}; + // + if(key->publicArea.parameters.rsaDetail.exponent != 0) + UINT32_TO_BYTE_ARRAY(key->publicArea.parameters.rsaDetail.exponent, + e.t.buffer); + return ModExpB(dInOut->size, dInOut->buffer, dInOut->size, dInOut->buffer, + e.t.size, e.t.buffer, key->publicArea.unique.rsa.t.size, + key->publicArea.unique.rsa.t.buffer); +} +/* 10.2.17.4.4 RSADP() */ +/* This function performs the RSADP operation defined in PKCS#1v2.1. It is an exponentiation of a + value (c) with the private exponent (d), modulo the public modulus (n). The decryption is in + place. */ +/* This function also checks the size of the private key. If the size indicates that only a prime + value is present, the key is converted to being a private exponent. */ +/* Error Returns Meaning */ +/* TPM_RC_SIZE the value to decrypt is larger than the modulus */ +static TPM_RC +RSADP( + TPM2B *inOut, // IN/OUT: the value to encrypt + OBJECT *key // IN: the key + ) +{ + BN_RSA_INITIALIZED(bnM, inOut); + BN_RSA_INITIALIZED(bnN, &key->publicArea.unique.rsa); + BN_RSA_INITIALIZED(bnP, &key->sensitive.sensitive.rsa); + if(BnUnsignedCmp(bnM, bnN) >= 0) + return TPM_RC_SIZE; + // private key operation requires that private exponent be loaded + // During self-test, this might not be the case so load it up if it hasn't + // already done + // been done + if(!key->attributes.privateExp) + CryptRsaLoadPrivateExponent(key); + if(!RsaPrivateKeyOp(bnM, bnN, bnP, &key->privateExponent)) + FAIL(FATAL_ERROR_INTERNAL); + BnTo2B(bnM, inOut, inOut->size); + return TPM_RC_SUCCESS; +} +/* 10.2.17.4.5 OaepEncode() */ +/* This function performs OAEP padding. The size of the buffer to receive the OAEP padded data must + equal the size of the modulus */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE hashAlg is not valid or message size is too large */ +static TPM_RC +OaepEncode( + TPM2B *padded, // OUT: the pad data + TPM_ALG_ID hashAlg, // IN: algorithm to use for padding + const TPM2B *label, // IN: null-terminated string (may be NULL) + TPM2B *message, // IN: the message being padded + RAND_STATE *rand // IN: the random number generator to use + ) +{ + INT32 padLen; + INT32 dbSize; + INT32 i; + BYTE mySeed[MAX_DIGEST_SIZE]; + BYTE *seed = mySeed; + UINT16 hLen = CryptHashGetDigestSize(hashAlg); + BYTE mask[MAX_RSA_KEY_BYTES]; + BYTE *pp; + BYTE *pm; + TPM_RC retVal = TPM_RC_SUCCESS; + pAssert(padded != NULL && message != NULL); + // A value of zero is not allowed because the KDF can't produce a result + // if the digest size is zero. + if(hLen == 0) + return TPM_RC_VALUE; + // Basic size checks + // make sure digest isn't too big for key size + if(padded->size < (2 * hLen) + 2) + ERROR_RETURN(TPM_RC_HASH); + // and that message will fit messageSize <= k - 2hLen - 2 + if(message->size > (padded->size - (2 * hLen) - 2)) + ERROR_RETURN(TPM_RC_VALUE); + // Hash L even if it is null + // Offset into padded leaving room for masked seed and byte of zero + pp = &padded->buffer[hLen + 1]; + if(CryptHashBlock(hashAlg, label->size, (BYTE *)label->buffer, + hLen, pp) != hLen) + ERROR_RETURN(TPM_RC_FAILURE); + // concatenate PS of k mLen 2hLen 2 + padLen = padded->size - message->size - (2 * hLen) - 2; + MemorySet(&pp[hLen], 0, padLen); + pp[hLen + padLen] = 0x01; + padLen += 1; + memcpy(&pp[hLen + padLen], message->buffer, message->size); + // The total size of db = hLen + pad + mSize; + dbSize = hLen + padLen + message->size; + // If testing, then use the provided seed. Otherwise, use values + // from the RNG + CryptRandomGenerate(hLen, mySeed); + DRBG_Generate(rand, mySeed, (UINT16)hLen); + // mask = MGF1 (seed, nSize hLen 1) + CryptMGF_KDF(dbSize, mask, hashAlg, hLen, seed, 0); + // Create the masked db + pm = mask; + for(i = dbSize; i > 0; i--) + *pp++ ^= *pm++; + pp = &padded->buffer[hLen + 1]; + // Run the masked data through MGF1 + if(CryptMGF_KDF(hLen, &padded->buffer[1], hashAlg, dbSize, pp, 0) != (unsigned)hLen) + ERROR_RETURN(TPM_RC_VALUE); + // Now XOR the seed to create masked seed + pp = &padded->buffer[1]; + pm = seed; + for(i = hLen; i > 0; i--) + *pp++ ^= *pm++; + // Set the first byte to zero + padded->buffer[0] = 0x00; + Exit: + return retVal; +} +/* 10.2.17.4.6 OaepDecode() */ +/* This function performs OAEP padding checking. The size of the buffer to receive the recovered + data. If the padding is not valid, the dSize size is set to zero and the function returns + TPM_RC_VALUE. */ +/* The dSize parameter is used as an input to indicate the size available in the buffer. If + insufficient space is available, the size is not changed and the return code is TPM_RC_VALUE. */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE the value to decode was larger than the modulus, or the padding is wrong or the + buffer to receive the results is too small */ +static TPM_RC +OaepDecode( + TPM2B *dataOut, // OUT: the recovered data + TPM_ALG_ID hashAlg, // IN: algorithm to use for padding + const TPM2B *label, // IN: null-terminated string (may be NULL) + TPM2B *padded // IN: the padded data + ) +{ + UINT32 i; + BYTE seedMask[MAX_DIGEST_SIZE]; + UINT32 hLen = CryptHashGetDigestSize(hashAlg); + BYTE mask[MAX_RSA_KEY_BYTES]; + BYTE *pp; + BYTE *pm; + TPM_RC retVal = TPM_RC_SUCCESS; + // Strange size (anything smaller can't be an OAEP padded block) + // Also check for no leading 0 + if((padded->size < (unsigned)((2 * hLen) + 2)) || (padded->buffer[0] != 0)) + ERROR_RETURN(TPM_RC_VALUE); + // Use the hash size to determine what to put through MGF1 in order + // to recover the seedMask + CryptMGF_KDF(hLen, seedMask, hashAlg, padded->size - hLen - 1, + &padded->buffer[hLen + 1], 0); + // Recover the seed into seedMask + pAssert(hLen <= sizeof(seedMask)); + pp = &padded->buffer[1]; + pm = seedMask; + for(i = hLen; i > 0; i--) + *pm++ ^= *pp++; + // Use the seed to generate the data mask + CryptMGF_KDF(padded->size - hLen - 1, mask, hashAlg, hLen, seedMask, 0); + // Use the mask generated from seed to recover the padded data + pp = &padded->buffer[hLen + 1]; + pm = mask; + for(i = (padded->size - hLen - 1); i > 0; i--) + *pm++ ^= *pp++; + // Make sure that the recovered data has the hash of the label + // Put trial value in the seed mask + if((CryptHashBlock(hashAlg, label->size, (BYTE *)label->buffer, + hLen, seedMask)) != hLen) + FAIL(FATAL_ERROR_INTERNAL); + if(memcmp(seedMask, mask, hLen) != 0) + ERROR_RETURN(TPM_RC_VALUE); + // find the start of the data + pm = &mask[hLen]; + for(i = (UINT32)padded->size - (2 * hLen) - 1; i > 0; i--) + { + if(*pm++ != 0) + break; + } + // If we ran out of data or didn't end with 0x01, then return an error + if(i == 0 || pm[-1] != 0x01) + ERROR_RETURN(TPM_RC_VALUE); + // pm should be pointing at the first part of the data + // and i is one greater than the number of bytes to move + i--; + if(i > dataOut->size) + // Special exit to preserve the size of the output buffer + return TPM_RC_VALUE; + memcpy(dataOut->buffer, pm, i); + dataOut->size = (UINT16)i; + Exit: + if(retVal != TPM_RC_SUCCESS) + dataOut->size = 0; + return retVal; +} +/* 10.2.17.4.7 PKCS1v1_5Encode() */ +/* This function performs the encoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1 */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE message size is too large */ +static TPM_RC +RSAES_PKCS1v1_5Encode( + TPM2B *padded, // OUT: the pad data + TPM2B *message, // IN: the message being padded + RAND_STATE *rand + ) +{ + UINT32 ps = padded->size - message->size - 3; + // + if(message->size > padded->size - 11) + return TPM_RC_VALUE; + // move the message to the end of the buffer + memcpy(&padded->buffer[padded->size - message->size], message->buffer, + message->size); + // Set the first byte to 0x00 and the second to 0x02 + padded->buffer[0] = 0; + padded->buffer[1] = 2; + // Fill with random bytes + DRBG_Generate(rand, &padded->buffer[2], (UINT16)ps); + // Set the delimiter for the random field to 0 + padded->buffer[2 + ps] = 0; + // Now, the only messy part. Make sure that all the 'ps' bytes are non-zero + // In this implementation, use the value of the current index + for(ps++; ps > 1; ps--) + { + if(padded->buffer[ps] == 0) + padded->buffer[ps] = 0x55; // In the < 0.5% of the cases that the + // random value is 0, just pick a value to + // put into the spot. + } + return TPM_RC_SUCCESS; +} +/* 10.2.17.4.8 RSAES_Decode() */ +/* This function performs the decoding for RSAES-PKCS1-V1_5-ENCRYPT as defined in PKCS#1V2.1 */ +/* Error Returns Meaning */ +/* TPM_RC_FAIL decoding error or results would no fit into provided buffer */ +static TPM_RC +RSAES_Decode( + TPM2B *message, // OUT: the recovered message + TPM2B *coded // IN: the encoded message + ) +{ + BOOL fail = FALSE; + UINT16 pSize; + fail = (coded->size < 11); + fail = (coded->buffer[0] != 0x00) | fail; + fail = (coded->buffer[1] != 0x02) | fail; + for(pSize = 2; pSize < coded->size; pSize++) + { + if(coded->buffer[pSize] == 0) + break; + } + pSize++; + // Make sure that pSize has not gone over the end and that there are at least 8 + // bytes of pad data. + fail = (pSize > coded->size) | fail; + fail = ((pSize - 2) <= 8) | fail; + if((message->size < (UINT16)(coded->size - pSize)) || fail) + return TPM_RC_VALUE; + message->size = coded->size - pSize; + memcpy(message->buffer, &coded->buffer[pSize], coded->size - pSize); + return TPM_RC_SUCCESS; +} +#endif // libtpms added +/* 10.2.17.4.13 CryptRsaPssSaltSize() */ +/* This function computes the salt size used in PSS. It is broken out so that the X509 code can get + the same value that is used by the encoding function in this module. */ +INT16 +CryptRsaPssSaltSize( + INT16 hashSize, + INT16 outSize +) +{ + INT16 saltSize; + // + // (Mask Length) = (outSize - hashSize - 1); + // Max saltSize is (Mask Length) - 1 + saltSize = (outSize - hashSize - 1) - 1; + // Use the maximum salt size allowed by FIPS 186-4 + if (saltSize > hashSize) + saltSize = hashSize; + else if (saltSize < 0) + saltSize = 0; + return saltSize; +} + +#if !USE_OPENSSL_FUNCTIONS_RSA // libtpms added +/* 10.2.17.4.9 PssEncode() */ +/* This function creates an encoded block of data that is the size of modulus. The function uses the + maximum salt size that will fit in the encoded block. */ +/* Returns TPM_RC_SUCCESS or goes into failure mode. */ +static TPM_RC +PssEncode( + TPM2B *out, // OUT: the encoded buffer + TPM_ALG_ID hashAlg, // IN: hash algorithm for the encoding + TPM2B *digest, // IN: the digest + RAND_STATE *rand // IN: random number source + ) +{ + UINT32 hLen = CryptHashGetDigestSize(hashAlg); + BYTE salt[MAX_RSA_KEY_BYTES - 1]; + UINT16 saltSize; + BYTE *ps = salt; + BYTE *pOut; + UINT16 mLen; + HASH_STATE hashState; + // These are fatal errors indicating bad TPM firmware + pAssert(out != NULL && hLen > 0 && digest != NULL); + // Get the size of the mask + mLen = (UINT16)(out->size - hLen - 1); + // Maximum possible salt size is mask length - 1 + saltSize = mLen - 1; + // Use the maximum salt size allowed by FIPS 186-4 + if(saltSize > hLen) + saltSize = (UINT16)hLen; + //using eOut for scratch space + // Set the first 8 bytes to zero + pOut = out->buffer; + memset(pOut, 0, 8); + // Get set the salt + DRBG_Generate(rand, salt, saltSize); + // Create the hash of the pad || input hash || salt + CryptHashStart(&hashState, hashAlg); + CryptDigestUpdate(&hashState, 8, pOut); + CryptDigestUpdate2B(&hashState, digest); + CryptDigestUpdate(&hashState, saltSize, salt); + CryptHashEnd(&hashState, hLen, &pOut[out->size - hLen - 1]); + // Create a mask + if(CryptMGF_KDF(mLen, pOut, hashAlg, hLen, &pOut[mLen], 0) != mLen) + FAIL(FATAL_ERROR_INTERNAL); + // Since this implementation uses key sizes that are all even multiples of + // 8, just need to make sure that the most significant bit is CLEAR + *pOut &= 0x7f; + // Before we mess up the pOut value, set the last byte to 0xbc + pOut[out->size - 1] = 0xbc; + // XOR a byte of 0x01 at the position just before where the salt will be XOR'ed + pOut = &pOut[mLen - saltSize - 1]; + *pOut++ ^= 0x01; + // XOR the salt data into the buffer + for(; saltSize > 0; saltSize--) + *pOut++ ^= *ps++; + // and we are done + return TPM_RC_SUCCESS; +} +/* 10.2.17.4.10 PssDecode() */ +/* This function checks that the PSS encoded block was built from the provided digest. If the check + is successful, TPM_RC_SUCCESS is returned. Any other value indicates an error. */ +/* This implementation of PSS decoding is intended for the reference TPM implementation and is not + at all generalized. It is used to check signatures over hashes and assumptions are made about + the sizes of values. Those assumptions are enforce by this implementation. This implementation + does allow for a variable size salt value to have been used by the creator of the signature. */ +/* Error Returns Meaning */ +/* TPM_RC_SCHEME hashAlg is not a supported hash algorithm */ +/* TPM_RC_VALUE decode operation failed */ +static TPM_RC +PssDecode( + TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding + TPM2B *dIn, // In: the digest to compare + TPM2B *eIn // IN: the encoded data + ) +{ + UINT32 hLen = CryptHashGetDigestSize(hashAlg); + BYTE mask[MAX_RSA_KEY_BYTES]; + BYTE *pm = mask; + BYTE *pe; + BYTE pad[8] = {0}; + UINT32 i; + UINT32 mLen; + BYTE fail; + TPM_RC retVal = TPM_RC_SUCCESS; + HASH_STATE hashState; + // These errors are indicative of failures due to programmer error + pAssert(dIn != NULL && eIn != NULL); + pe = eIn->buffer; + // check the hash scheme + if(hLen == 0) + ERROR_RETURN(TPM_RC_SCHEME); + // most significant bit must be zero + fail = pe[0] & 0x80; + // last byte must be 0xbc + fail |= pe[eIn->size - 1] ^ 0xbc; + // Use the hLen bytes at the end of the buffer to generate a mask + // Doesn't start at the end which is a flag byte + mLen = eIn->size - hLen - 1; + CryptMGF_KDF(mLen, mask, hashAlg, hLen, &pe[mLen], 0); + // Clear the MSO of the mask to make it consistent with the encoding. + mask[0] &= 0x7F; + pAssert(mLen <= sizeof(mask)); + // XOR the data into the mask to recover the salt. This sequence + // advances eIn so that it will end up pointing to the seed data + // which is the hash of the signature data + for(i = mLen; i > 0; i--) + *pm++ ^= *pe++; + // Find the first byte of 0x01 after a string of all 0x00 + for(pm = mask, i = mLen; i > 0; i--) + { + if(*pm == 0x01) + break; + else + fail |= *pm++; + } + // i should not be zero + fail |= (i == 0); + // if we have failed, will continue using the entire mask as the salt value so + // that the timing attacks will not disclose anything (I don't think that this + // is a problem for TPM applications but, usually, we don't fail so this + // doesn't cost anything). + if(fail) + { + i = mLen; + pm = mask; + } + else + { + pm++; + i--; + } + // i contains the salt size and pm points to the salt. Going to use the input + // hash and the seed to recreate the hash in the lower portion of eIn. + CryptHashStart(&hashState, hashAlg); + // add the pad of 8 zeros + CryptDigestUpdate(&hashState, 8, pad); + // add the provided digest value + CryptDigestUpdate(&hashState, dIn->size, dIn->buffer); + // and the salt + CryptDigestUpdate(&hashState, i, pm); + // get the result + fail |= (CryptHashEnd(&hashState, hLen, mask) != hLen); + // Compare all bytes + for(pm = mask; hLen > 0; hLen--) + // don't use fail = because that could skip the increment and compare + // operations after the first failure and that gives away timing + // information. + fail |= *pm++ ^ *pe++; + retVal = (fail != 0) ? TPM_RC_VALUE : TPM_RC_SUCCESS; + Exit: + return retVal; +} +/* 10.2.17.4.16 MakeDerTag() */ +/* Construct the DER value that is used in RSASSA */ +/* Return Value Meaning */ +/* > 0 size of value */ +/* <= 0 no hash exists */ +INT16 +MakeDerTag( + TPM_ALG_ID hashAlg, + INT16 sizeOfBuffer, + BYTE *buffer + ) +{ + // 0x30, 0x31, // SEQUENCE (2 elements) 1st + // 0x30, 0x0D, // SEQUENCE (2 elements) + // 0x06, 0x09, // HASH OID + // 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, + // 0x05, 0x00, // NULL + // 0x04, 0x20 // OCTET STRING + HASH_DEF *info = CryptGetHashDef(hashAlg); + INT16 oidSize; + // If no OID, can't do encode + VERIFY(info != NULL); + oidSize = 2 + (info->OID)[1]; + // make sure this fits in the buffer + VERIFY(sizeOfBuffer >= (oidSize + 8)); + *buffer++ = 0x30; // 1st SEQUENCE + // Size of the 1st SEQUENCE is 6 bytes + size of the hash OID + size of the + // digest size + *buffer++ = (BYTE)(6 + oidSize + info->digestSize); // + *buffer++ = 0x30; // 2nd SEQUENCE + // size is 4 bytes of overhead plus the side of the OID + *buffer++ = (BYTE)(2 + oidSize); + MemoryCopy(buffer, info->OID, oidSize); + buffer += oidSize; + *buffer++ = 0x05; // Add a NULL + *buffer++ = 0x00; + + *buffer++ = 0x04; + *buffer++ = (BYTE)(info->digestSize); + return oidSize + 8; + Error: + return 0; + +} + +/* 10.2.17.4.17 RSASSA_Encode() */ +/* Encode a message using PKCS1v1.5 method. */ +/* Error Returns Meaning */ +/* TPM_RC_SCHEME hashAlg is not a supported hash algorithm */ +/* TPM_RC_SIZE eOutSize is not large enough */ +/* TPM_RC_VALUE hInSize does not match the digest size of hashAlg */ +static TPM_RC +RSASSA_Encode( + TPM2B *pOut, // IN:OUT on in, the size of the public key + // on out, the encoded area + TPM_ALG_ID hashAlg, // IN: hash algorithm for PKCS1v1_5 + TPM2B *hIn // IN: digest value to encode + ) +{ + BYTE DER[20]; + BYTE *der = DER; + INT32 derSize = MakeDerTag(hashAlg, sizeof(DER), DER); + BYTE *eOut; + INT32 fillSize; + TPM_RC retVal = TPM_RC_SUCCESS; + + // Can't use this scheme if the algorithm doesn't have a DER string defined. + if(derSize == 0) + ERROR_RETURN(TPM_RC_SCHEME); + + // If the digest size of 'hashAl' doesn't match the input digest size, then + // the DER will misidentify the digest so return an error + if(CryptHashGetDigestSize(hashAlg) != hIn->size) + ERROR_RETURN(TPM_RC_VALUE); + fillSize = pOut->size - derSize - hIn->size - 3; + eOut = pOut->buffer; + + // Make sure that this combination will fit in the provided space + if(fillSize < 8) + ERROR_RETURN(TPM_RC_SIZE); + + // Start filling + *eOut++ = 0; // initial byte of zero + *eOut++ = 1; // byte of 0x01 + for(; fillSize > 0; fillSize--) + *eOut++ = 0xff; // bunch of 0xff + *eOut++ = 0; // another 0 + for(; derSize > 0; derSize--) + *eOut++ = *der++; // copy the DER + der = hIn->buffer; + for(fillSize = hIn->size; fillSize > 0; fillSize--) + *eOut++ = *der++; // copy the hash + Exit: + return retVal; +} + +/* 10.2.17.4.18 RSASSA_Decode() */ +/* This function performs the RSASSA decoding of a signature. */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE decode unsuccessful */ +/* TPM_RC_SCHEME haslAlg is not supported */ +static TPM_RC +RSASSA_Decode( + TPM_ALG_ID hashAlg, // IN: hash algorithm to use for the encoding + TPM2B *hIn, // In: the digest to compare + TPM2B *eIn // IN: the encoded data + ) +{ + BYTE fail; + BYTE DER[20]; + BYTE *der = DER; + INT32 derSize = MakeDerTag(hashAlg, sizeof(DER), DER); + BYTE *pe; + INT32 hashSize = CryptHashGetDigestSize(hashAlg); + INT32 fillSize; + TPM_RC retVal; + BYTE *digest; + UINT16 digestSize; + + pAssert(hIn != NULL && eIn != NULL); + pe = eIn->buffer; + + // Can't use this scheme if the algorithm doesn't have a DER string + // defined or if the provided hash isn't the right size + if(derSize == 0 || (unsigned)hashSize != hIn->size) + ERROR_RETURN(TPM_RC_SCHEME); + + // Make sure that this combination will fit in the provided space + // Since no data movement takes place, can just walk though this + // and accept nearly random values. This can only be called from + // CryptValidateSignature() so eInSize is known to be in range. + fillSize = eIn->size - derSize - hashSize - 3; + + // Start checking (fail will become non-zero if any of the bytes do not have + // the expected value. + fail = *pe++; // initial byte of zero + fail |= *pe++ ^ 1; // byte of 0x01 + for(; fillSize > 0; fillSize--) + fail |= *pe++ ^ 0xff; // bunch of 0xff + fail |= *pe++; // another 0 + for(; derSize > 0; derSize--) + fail |= *pe++ ^ *der++; // match the DER + digestSize = hIn->size; + digest = hIn->buffer; + for(; digestSize > 0; digestSize--) + fail |= *pe++ ^ *digest++; // match the hash + retVal = (fail != 0) ? TPM_RC_VALUE : TPM_RC_SUCCESS; + Exit: + return retVal; +} +#endif // libtpms added + +/* 10.2.17.4.13 CryptRsaSelectScheme() */ +/* This function is used by TPM2_RSA_Decrypt() and TPM2_RSA_Encrypt(). It sets up the rules to + select a scheme between input and object default. This function assume the RSA object is + loaded. If a default scheme is defined in object, the default scheme should be chosen, otherwise, + the input scheme should be chosen. In the case that both the object and scheme are not + TPM_ALG_NULL, then if the schemes are the same, the input scheme will be chosen. if the scheme + are not compatible, a NULL pointer will be returned. */ +/* The return pointer may point to a TPM_ALG_NULL scheme. */ +TPMT_RSA_DECRYPT* +CryptRsaSelectScheme( + TPMI_DH_OBJECT rsaHandle, // IN: handle of an RSA key + TPMT_RSA_DECRYPT *scheme // IN: a sign or decrypt scheme + ) +{ + OBJECT *rsaObject; + TPMT_ASYM_SCHEME *keyScheme; + TPMT_RSA_DECRYPT *retVal = NULL; + // Get sign object pointer + rsaObject = HandleToObject(rsaHandle); + keyScheme = &rsaObject->publicArea.parameters.asymDetail.scheme; + // if the default scheme of the object is TPM_ALG_NULL, then select the + // input scheme + if(keyScheme->scheme == TPM_ALG_NULL) + { + retVal = scheme; + } + // if the object scheme is not TPM_ALG_NULL and the input scheme is + // TPM_ALG_NULL, then select the default scheme of the object. + else if(scheme->scheme == TPM_ALG_NULL) + { + // if input scheme is NULL + retVal = (TPMT_RSA_DECRYPT *)keyScheme; + } + // get here if both the object scheme and the input scheme are + // not TPM_ALG_NULL. Need to insure that they are the same. + // IMPLEMENTATION NOTE: This could cause problems if future versions have + // schemes that have more values than just a hash algorithm. A new function + // (IsSchemeSame()) might be needed then. + else if(keyScheme->scheme == scheme->scheme + && keyScheme->details.anySig.hashAlg == scheme->details.anySig.hashAlg) + { + retVal = scheme; + } + // two different, incompatible schemes specified will return NULL + return retVal; +} +/* 10.2.17.4.14 CryptRsaLoadPrivateExponent() */ +/* Error Returns Meaning */ +/* TPM_RC_BINDING public and private parts of rsaKey are not matched */ +TPM_RC +CryptRsaLoadPrivateExponent( + OBJECT *rsaKey // IN: the RSA key object + ) +{ + BN_RSA_INITIALIZED(bnN, &rsaKey->publicArea.unique.rsa); + BN_PRIME_INITIALIZED(bnP, &rsaKey->sensitive.sensitive.rsa); + BN_RSA(bnQ); + BN_PRIME(bnQr); + BN_WORD_INITIALIZED(bnE, (rsaKey->publicArea.parameters.rsaDetail.exponent == 0) + ? RSA_DEFAULT_PUBLIC_EXPONENT + : rsaKey->publicArea.parameters.rsaDetail.exponent); + TPM_RC retVal = TPM_RC_SUCCESS; + if(!rsaKey->attributes.privateExp) + { + TEST(TPM_ALG_NULL); + // Make sure that the bigNum used for the exponent is properly initialized + RsaInitializeExponent(&rsaKey->privateExponent); + // Find the second prime by division + BnDiv(bnQ, bnQr, bnN, bnP); + if(!BnEqualZero(bnQr)) + ERROR_RETURN(TPM_RC_BINDING); + // Compute the private exponent and return it if found + if(!ComputePrivateExponent(bnP, bnQ, bnE, bnN, + &rsaKey->privateExponent)) + ERROR_RETURN(TPM_RC_BINDING); + } + Exit: + rsaKey->attributes.privateExp = (retVal == TPM_RC_SUCCESS); + return retVal; +} +#if !USE_OPENSSL_FUNCTIONS_RSA // libtpms added +/* 10.2.17.4.15 CryptRsaEncrypt() */ +/* This is the entry point for encryption using RSA. Encryption is use of the public exponent. The + padding parameter determines what padding will be used. */ +/* The cOutSize parameter must be at least as large as the size of the key. */ +/* If the padding is RSA_PAD_NONE, dIn is treated as a number. It must be lower in value than the + key modulus. */ +/* NOTE: If dIn has fewer bytes than cOut, then we don't add low-order zeros to dIn to make it the + size of the RSA key for the call to RSAEP. This is because the high order bytes of dIn might have + a numeric value that is greater than the value of the key modulus. If this had low-order zeros + added, it would have a numeric value larger than the modulus even though it started out with a + lower numeric value. */ +/* Error Returns Meaning */ +/* TPM_RC_VALUE cOutSize is too small (must be the size of the modulus) */ +/* TPM_RC_SCHEME padType is not a supported scheme */ +LIB_EXPORT TPM_RC +CryptRsaEncrypt( + TPM2B_PUBLIC_KEY_RSA *cOut, // OUT: the encrypted data + TPM2B *dIn, // IN: the data to encrypt + OBJECT *key, // IN: the key used for encryption + TPMT_RSA_DECRYPT *scheme, // IN: the type of padding and hash + // if needed + const TPM2B *label, // IN: in case it is needed + RAND_STATE *rand // IN: random number generator + // state (mostly for testing) + ) +{ + TPM_RC retVal = TPM_RC_SUCCESS; + TPM2B_PUBLIC_KEY_RSA dataIn; + // + // if the input and output buffers are the same, copy the input to a scratch + // buffer so that things don't get messed up. + if(dIn == &cOut->b) + { + MemoryCopy2B(&dataIn.b, dIn, sizeof(dataIn.t.buffer)); + dIn = &dataIn.b; + } + // All encryption schemes return the same size of data + cOut->t.size = key->publicArea.unique.rsa.t.size; + TEST(scheme->scheme); + switch(scheme->scheme) + { + case TPM_ALG_NULL: // 'raw' encryption + { + INT32 i; + INT32 dSize = dIn->size; + // dIn can have more bytes than cOut as long as the extra bytes + // are zero. Note: the more significant bytes of a number in a byte + // buffer are the bytes at the start of the array. + for(i = 0; (i < dSize) && (dIn->buffer[i] == 0); i++); + dSize -= i; + if(dSize > cOut->t.size) + ERROR_RETURN(TPM_RC_VALUE); + // Pad cOut with zeros if dIn is smaller + memset(cOut->t.buffer, 0, cOut->t.size - dSize); + // And copy the rest of the value + memcpy(&cOut->t.buffer[cOut->t.size - dSize], &dIn->buffer[i], dSize); + // If the size of dIn is the same as cOut dIn could be larger than + // the modulus. If it is, then RSAEP() will catch it. + } + break; + case TPM_ALG_RSAES: + retVal = RSAES_PKCS1v1_5Encode(&cOut->b, dIn, rand); + break; + case TPM_ALG_OAEP: + retVal = OaepEncode(&cOut->b, scheme->details.oaep.hashAlg, label, dIn, + rand); + break; + default: + ERROR_RETURN(TPM_RC_SCHEME); + break; + } + // All the schemes that do padding will come here for the encryption step + // Check that the Encoding worked + if(retVal == TPM_RC_SUCCESS) + // Padding OK so do the encryption + retVal = RSAEP(&cOut->b, key); + Exit: + return retVal; +} +/* 10.2.17.4.16 CryptRsaDecrypt() */ +/* This is the entry point for decryption using RSA. Decryption is use of the private exponent. The + padType parameter determines what padding was used. */ +/* Error Returns Meaning */ +/* TPM_RC_SIZE cInSize is not the same as the size of the public modulus of key; or numeric value of + the encrypted data is greater than the modulus */ +/* TPM_RC_VALUE dOutSize is not large enough for the result */ +/* TPM_RC_SCHEME padType is not supported */ +LIB_EXPORT TPM_RC +CryptRsaDecrypt( + TPM2B *dOut, // OUT: the decrypted data + TPM2B *cIn, // IN: the data to decrypt + OBJECT *key, // IN: the key to use for decryption + TPMT_RSA_DECRYPT *scheme, // IN: the padding scheme + const TPM2B *label // IN: in case it is needed for the scheme + ) +{ + TPM_RC retVal; + // Make sure that the necessary parameters are provided + pAssert(cIn != NULL && dOut != NULL && key != NULL); + // Size is checked to make sure that the encrypted value is the right size + if(cIn->size != key->publicArea.unique.rsa.t.size) + ERROR_RETURN(TPM_RC_SIZE); + TEST(scheme->scheme); + // For others that do padding, do the decryption in place and then + // go handle the decoding. + retVal = RSADP(cIn, key); + if(retVal == TPM_RC_SUCCESS) + { + // Remove padding + switch(scheme->scheme) + { + case TPM_ALG_NULL: + if(dOut->size < cIn->size) + return TPM_RC_VALUE; + MemoryCopy2B(dOut, cIn, dOut->size); + break; + case TPM_ALG_RSAES: + retVal = RSAES_Decode(dOut, cIn); + break; + case TPM_ALG_OAEP: + retVal = OaepDecode(dOut, scheme->details.oaep.hashAlg, label, cIn); + break; + default: + retVal = TPM_RC_SCHEME; + break; + } + } + Exit: + return retVal; +} +/* 10.2.17.4.17 CryptRsaSign() */ +/* This function is used to generate an RSA signature of the type indicated in scheme. */ +/* Error Returns Meaning */ +/* TPM_RC_SCHEME scheme or hashAlg are not supported */ +/* TPM_RC_VALUE hInSize does not match hashAlg (for RSASSA) */ +LIB_EXPORT TPM_RC +CryptRsaSign( + TPMT_SIGNATURE *sigOut, + OBJECT *key, // IN: key to use + TPM2B_DIGEST *hIn, // IN: the digest to sign + RAND_STATE *rand // IN: the random number generator + // to use (mostly for testing) + ) +{ + TPM_RC retVal = TPM_RC_SUCCESS; + UINT16 modSize; + // parameter checks + pAssert(sigOut != NULL && key != NULL && hIn != NULL); + modSize = key->publicArea.unique.rsa.t.size; + // for all non-null signatures, the size is the size of the key modulus + sigOut->signature.rsapss.sig.t.size = modSize; + TEST(sigOut->sigAlg); + switch(sigOut->sigAlg) + { + case TPM_ALG_NULL: + sigOut->signature.rsapss.sig.t.size = 0; + return TPM_RC_SUCCESS; + case TPM_ALG_RSAPSS: + retVal = PssEncode(&sigOut->signature.rsapss.sig.b, + sigOut->signature.rsapss.hash, &hIn->b, rand); + break; + case TPM_ALG_RSASSA: + retVal = RSASSA_Encode(&sigOut->signature.rsassa.sig.b, + sigOut->signature.rsassa.hash, &hIn->b); + break; + default: + retVal = TPM_RC_SCHEME; + } + if(retVal == TPM_RC_SUCCESS) + { + // Do the encryption using the private key + retVal = RSADP(&sigOut->signature.rsapss.sig.b, key); + } + return retVal; +} +/* 10.2.17.4.18 CryptRsaValidateSignature() */ +/* This function is used to validate an RSA signature. If the signature is valid TPM_RC_SUCCESS is + returned. If the signature is not valid, TPM_RC_SIGNATURE is returned. Other return codes + indicate either parameter problems or fatal errors. */ +/* Error Returns Meaning */ +/* TPM_RC_SIGNATURE the signature does not check */ +/* TPM_RC_SCHEME unsupported scheme or hash algorithm */ +LIB_EXPORT TPM_RC +CryptRsaValidateSignature( + TPMT_SIGNATURE *sig, // IN: signature + OBJECT *key, // IN: public modulus + TPM2B_DIGEST *digest // IN: The digest being validated + ) +{ + TPM_RC retVal; + // + // Fatal programming errors + pAssert(key != NULL && sig != NULL && digest != NULL); + switch(sig->sigAlg) + { + case TPM_ALG_RSAPSS: + case TPM_ALG_RSASSA: + break; + default: + return TPM_RC_SCHEME; + } + // Errors that might be caused by calling parameters + if(sig->signature.rsassa.sig.t.size != key->publicArea.unique.rsa.t.size) + ERROR_RETURN(TPM_RC_SIGNATURE); + TEST(sig->sigAlg); + // Decrypt the block + retVal = RSAEP(&sig->signature.rsassa.sig.b, key); + if(retVal == TPM_RC_SUCCESS) + { + switch(sig->sigAlg) + { + case TPM_ALG_RSAPSS: + retVal = PssDecode(sig->signature.any.hashAlg, &digest->b, + &sig->signature.rsassa.sig.b); + break; + case TPM_ALG_RSASSA: + retVal = RSASSA_Decode(sig->signature.any.hashAlg, &digest->b, + &sig->signature.rsassa.sig.b); + break; + default: + return TPM_RC_SCHEME; + } + } + Exit: + return (retVal != TPM_RC_SUCCESS) ? TPM_RC_SIGNATURE : TPM_RC_SUCCESS; +} +#endif // libtpms added +#if SIMULATION && USE_RSA_KEY_CACHE +extern int s_rsaKeyCacheEnabled; +int GetCachedRsaKey(OBJECT *key, RAND_STATE *rand); +#define GET_CACHED_KEY(key, rand) \ + (s_rsaKeyCacheEnabled && GetCachedRsaKey(key, rand)) +#else +#define GET_CACHED_KEY(key, rand) +#endif +/* 10.2.17.4.19 CryptRsaGenerateKey() */ +/* Generate an RSA key from a provided seed */ +/* Error Returns Meaning */ +/* TPM_RC_CANCELED operation was canceled */ +/* TPM_RC_RANGE public exponent is not supported */ +/* TPM_RC_VALUE could not find a prime using the provided parameters */ +LIB_EXPORT TPM_RC +CryptRsaGenerateKey( + OBJECT *rsaKey, // IN/OUT: The object structure in which + // the key is created. + RAND_STATE *rand // IN: if not NULL, the deterministic + // RNG state + ) +{ + UINT32 i; + BN_PRIME(bnP); // These four declarations initialize the number to 0 + BN_PRIME(bnQ); + BN_RSA(bnD); + BN_RSA(bnN); + BN_WORD(bnE); + UINT32 e; + int keySizeInBits; + TPMT_PUBLIC *publicArea = &rsaKey->publicArea; + TPMT_SENSITIVE *sensitive = &rsaKey->sensitive; + TPM_RC retVal = TPM_RC_NO_RESULT; + // + // Need to make sure that the caller did not specify an exponent that is + // not supported + e = publicArea->parameters.rsaDetail.exponent; + if(e == 0) + e = RSA_DEFAULT_PUBLIC_EXPONENT; + if(e < 65537) + ERROR_RETURN(TPM_RC_RANGE); + if(e != RSA_DEFAULT_PUBLIC_EXPONENT && !IsPrimeInt(e)) + ERROR_RETURN(TPM_RC_RANGE); + BnSetWord(bnE, e); + // Check that e is prime + // check for supported key size. + keySizeInBits = publicArea->parameters.rsaDetail.keyBits; + if(((keySizeInBits % 1024) != 0) + || (keySizeInBits > MAX_RSA_KEY_BITS) // this might be redundant, but... + || (keySizeInBits == 0)) + ERROR_RETURN(TPM_RC_VALUE); + // Set the prime size for instrumentation purposes + INSTRUMENT_SET(PrimeIndex, PRIME_INDEX(keySizeInBits / 2)); +#if SIMULATION && USE_RSA_KEY_CACHE + if(GET_CACHED_KEY(rsaKey, rand)) + return TPM_RC_SUCCESS; +#endif + // Make sure that key generation has been tested + TEST(TPM_ALG_NULL); +#if USE_OPENSSL_FUNCTIONS_RSA // libtpms added begin + if (rand == NULL) + return OpenSSLCryptRsaGenerateKey(rsaKey, e, keySizeInBits); +#endif // libtpms added end + // Need to initialize the privateExponent structure + RsaInitializeExponent(&rsaKey->privateExponent); + // The prime is computed in P. When a new prime is found, Q is checked to + // see if it is zero. If so, P is copied to Q and a new P is found. + // When both P and Q are non-zero, the modulus and + // private exponent are computed and a trial encryption/decryption is + // performed. If the encrypt/decrypt fails, assume that at least one of the + // primes is composite. Since we don't know which one, set Q to zero and start + // over and find a new pair of primes. + for(i = 1; (retVal != TPM_RC_SUCCESS) && (i != 100); i++) + { + if(_plat__IsCanceled()) + ERROR_RETURN(TPM_RC_CANCELED); + BnGeneratePrimeForRSA(bnP, keySizeInBits / 2, e, rand); + INSTRUMENT_INC(PrimeCounts[PrimeIndex]); + // If this is the second prime, make sure that it differs from the + // first prime by at least 2^100 + if(BnEqualZero(bnQ)) + { + // copy p to q and compute another prime in p + BnCopy(bnQ, bnP); + continue; + } + // Make sure that the difference is at least 100 bits. Need to do it this + // way because the big numbers are only positive values + if(BnUnsignedCmp(bnP, bnQ) < 0) + BnSub(bnD, bnQ, bnP); + else + BnSub(bnD, bnP, bnQ); + if(BnMsb(bnD) < 100) + continue; + //Form the public modulus and set the unique value + BnMult(bnN, bnP, bnQ); + BnTo2B(bnN, &publicArea->unique.rsa.b, + (NUMBYTES)BITS_TO_BYTES(keySizeInBits)); + // And the prime to the sensitive area + BnTo2B(bnP, &sensitive->sensitive.rsa.b, + (NUMBYTES)BITS_TO_BYTES(keySizeInBits) / 2); + // Make sure everything came out right. The MSb of the values must be + // one + if(((publicArea->unique.rsa.t.buffer[0] & 0x80) == 0) + || ((sensitive->sensitive.rsa.t.buffer[0] & 0x80) == 0)) + FAIL(FATAL_ERROR_INTERNAL); + // Make sure that we can form the private exponent values + if(ComputePrivateExponent(bnP, bnQ, bnE, bnN, &rsaKey->privateExponent) + != TRUE) + { + // If ComputePrivateExponent could not find an inverse for + // Q, then copy P and recompute P. This might + // cause both to be recomputed if P is also zero + if(BnEqualZero(bnQ)) + BnCopy(bnQ, bnP); + continue; + } + retVal = TPM_RC_SUCCESS; + // Do a trial encryption decryption if this is a signing key + if(IS_ATTRIBUTE(publicArea->objectAttributes, TPMA_OBJECT, sign)) + { + BN_RSA(temp1); + BN_RSA(temp2); + BnGenerateRandomInRange(temp1, bnN, rand); + // Encrypt with public exponent... + BnModExp(temp2, temp1, bnE, bnN); + // ... then decrypt with private exponent + RsaPrivateKeyOp(temp2, bnN, bnP, &rsaKey->privateExponent); + // If the starting and ending values are not the same, + // start over )-; + if(BnUnsignedCmp(temp2, temp1) != 0) + { + BnSetWord(bnQ, 0); + retVal = TPM_RC_NO_RESULT; + } + } + } + Exit: + if(retVal == TPM_RC_SUCCESS) + rsaKey->attributes.privateExp = SET; + return retVal; +} + +#if USE_OPENSSL_FUNCTIONS_RSA // libtpms added begin +LIB_EXPORT TPM_RC +CryptRsaEncrypt( + TPM2B_PUBLIC_KEY_RSA *cOut, // OUT: the encrypted data + TPM2B *dIn, // IN: the data to encrypt + OBJECT *key, // IN: the key used for encryption + TPMT_RSA_DECRYPT *scheme, // IN: the type of padding and hash + // if needed + const TPM2B *label, // IN: in case it is needed + RAND_STATE *rand // IN: random number generator + // state (mostly for testing) + ) +{ + TPM_RC retVal; + TPM2B_PUBLIC_KEY_RSA dataIn; + TPM2B_PUBLIC_KEY_RSA scratch; + size_t outlen; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md; + const char *digestname; + unsigned char *tmp = NULL; + // + // if the input and output buffers are the same, copy the input to a scratch + // buffer so that things don't get messed up. + if(dIn == &cOut->b) + { + MemoryCopy2B(&dataIn.b, dIn, sizeof(dataIn.t.buffer)); + dIn = &dataIn.b; + } + // All encryption schemes return the same size of data + pAssert(sizeof(cOut->t.buffer) >= key->publicArea.unique.rsa.t.size); + cOut->t.size = key->publicArea.unique.rsa.t.size; + TEST(scheme->scheme); + + retVal = InitOpenSSLRSAPublicKey(key, &pkey); + if (retVal != TPM_RC_SUCCESS) + return retVal; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == NULL || + EVP_PKEY_encrypt_init(ctx) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + switch(scheme->scheme) + { + case TPM_ALG_NULL: // 'raw' encryption + { + INT32 i; + INT32 dSize = dIn->size; + // dIn can have more bytes than cOut as long as the extra bytes + // are zero. Note: the more significant bytes of a number in a byte + // buffer are the bytes at the start of the array. + for(i = 0; (i < dSize) && (dIn->buffer[i] == 0); i++); + dSize -= i; + scratch.t.size = cOut->t.size; + pAssert(scratch.t.size <= sizeof(scratch.t.buffer)); + if(dSize > scratch.t.size) + ERROR_RETURN(TPM_RC_VALUE); + // Pad cOut with zeros if dIn is smaller + memset(scratch.t.buffer, 0, scratch.t.size - dSize); + // And copy the rest of the value; value is then right-aligned + memcpy(&scratch.t.buffer[scratch.t.size - dSize], &dIn->buffer[i], dSize); + + dIn = &scratch.b; + } + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + break; + case TPM_ALG_RSAES: + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + break; + case TPM_ALG_OAEP: + digestname = GetDigestNameByHashAlg(scheme->details.oaep.hashAlg); + if (digestname == NULL) + ERROR_RETURN(TPM_RC_VALUE); + + md = EVP_get_digestbyname(digestname); + if (md == NULL || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + if (label->size > 0) { + tmp = malloc(label->size); + if (tmp == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + memcpy(tmp, label->buffer, label->size); + } + // label->size == 0 is supported + if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, tmp, label->size) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + tmp = NULL; + break; + default: + ERROR_RETURN(TPM_RC_SCHEME); + break; + } + + outlen = cOut->t.size; + + if (EVP_PKEY_encrypt(ctx, cOut->t.buffer, &outlen, + dIn->buffer, dIn->size) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + cOut->t.size = outlen; + + Exit: + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + free(tmp); + + return retVal; +} + +LIB_EXPORT TPM_RC +CryptRsaDecrypt( + TPM2B *dOut, // OUT: the decrypted data + TPM2B *cIn, // IN: the data to decrypt + OBJECT *key, // IN: the key to use for decryption + TPMT_RSA_DECRYPT *scheme, // IN: the padding scheme + const TPM2B *label // IN: in case it is needed for the scheme + ) +{ + TPM_RC retVal; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md = NULL; + const char *digestname; + size_t outlen; + unsigned char *tmp = NULL; + unsigned char buffer[MAX_RSA_KEY_BYTES]; + + // Make sure that the necessary parameters are provided + pAssert(cIn != NULL && dOut != NULL && key != NULL); + // Size is checked to make sure that the encrypted value is the right size + if(cIn->size != key->publicArea.unique.rsa.t.size) + ERROR_RETURN(TPM_RC_SIZE); + TEST(scheme->scheme); + + retVal = InitOpenSSLRSAPrivateKey(key, &pkey); + if (retVal != TPM_RC_SUCCESS) + return retVal; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == NULL || + EVP_PKEY_decrypt_init(ctx) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + switch(scheme->scheme) + { + case TPM_ALG_NULL: // 'raw' encryption + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + break; + case TPM_ALG_RSAES: + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + break; + case TPM_ALG_OAEP: + digestname = GetDigestNameByHashAlg(scheme->details.oaep.hashAlg); + if (digestname == NULL) + ERROR_RETURN(TPM_RC_VALUE); + + md = EVP_get_digestbyname(digestname); + if (md == NULL || + EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0 || + EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + if (label->size > 0) { + tmp = malloc(label->size); + if (tmp == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + memcpy(tmp, label->buffer, label->size); + + if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, tmp, label->size) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + tmp = NULL; + } + break; + default: + ERROR_RETURN(TPM_RC_SCHEME); + break; + } + + /* cannot use cOut->buffer */ + outlen = sizeof(buffer); + if (EVP_PKEY_decrypt(ctx, buffer, &outlen, + cIn->buffer, cIn->size) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + if (outlen > dOut->size) + ERROR_RETURN(TPM_RC_FAILURE); + + memcpy(dOut->buffer, buffer, outlen); + dOut->size = outlen; + + retVal = TPM_RC_SUCCESS; + + Exit: + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + free(tmp); + + return retVal; +} + +LIB_EXPORT TPM_RC +CryptRsaSign( + TPMT_SIGNATURE *sigOut, + OBJECT *key, // IN: key to use + TPM2B_DIGEST *hIn, // IN: the digest to sign + RAND_STATE *rand // IN: the random number generator + // to use (mostly for testing) + ) +{ + TPM_RC retVal = TPM_RC_SUCCESS; + UINT16 modSize; + size_t outlen; + int padding; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md; + const char *digestname; + TPMI_ALG_HASH hashAlg; + + // parameter checks + pAssert(sigOut != NULL && key != NULL && hIn != NULL); + modSize = key->publicArea.unique.rsa.t.size; + // for all non-null signatures, the size is the size of the key modulus + sigOut->signature.rsapss.sig.t.size = modSize; + TEST(sigOut->sigAlg); + + switch(sigOut->sigAlg) + { + case TPM_ALG_NULL: + sigOut->signature.rsapss.sig.t.size = 0; + return TPM_RC_SUCCESS; + case TPM_ALG_RSAPSS: + padding = RSA_PKCS1_PSS_PADDING; + hashAlg = sigOut->signature.rsapss.hash; + break; + case TPM_ALG_RSASSA: + padding = RSA_PKCS1_PADDING; + hashAlg = sigOut->signature.rsassa.hash; + break; + default: + ERROR_RETURN(TPM_RC_SCHEME); + } + + digestname = GetDigestNameByHashAlg(hashAlg); + if (digestname == NULL) + ERROR_RETURN(TPM_RC_VALUE); + + md = EVP_get_digestbyname(digestname); + if (md == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + retVal = InitOpenSSLRSAPrivateKey(key, &pkey); + if (retVal != TPM_RC_SUCCESS) + return retVal; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (ctx == NULL || + EVP_PKEY_sign_init(ctx) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 || + EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + /* careful with PSS padding: Use salt length = hash length (-1) if + * length(digest) + length(hash-to-sign) + 2 <= modSize + * otherwise use the max. possible salt length, which is the default (-2) + * test case: 1024 bit key PSS signing sha512 hash + */ + if (padding == RSA_PKCS1_PSS_PADDING && + EVP_MD_size(md) + hIn->b.size + 2 <= modSize && /* OSSL: RSA_padding_add_PKCS1_PSS_mgf1 */ + EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + outlen = sigOut->signature.rsapss.sig.t.size; + if (EVP_PKEY_sign(ctx, + sigOut->signature.rsapss.sig.t.buffer, &outlen, + hIn->b.buffer, hIn->b.size) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + sigOut->signature.rsapss.sig.t.size = outlen; + + Exit: + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + + return retVal; +} + +LIB_EXPORT TPM_RC +CryptRsaValidateSignature( + TPMT_SIGNATURE *sig, // IN: signature + OBJECT *key, // IN: public modulus + TPM2B_DIGEST *digest // IN: The digest being validated + ) +{ + TPM_RC retVal; + int padding; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const EVP_MD *md; + const char *digestname; + + // + // Fatal programming errors + pAssert(key != NULL && sig != NULL && digest != NULL); + switch(sig->sigAlg) + { + case TPM_ALG_RSAPSS: + padding = RSA_PKCS1_PSS_PADDING; + break; + case TPM_ALG_RSASSA: + padding = RSA_PKCS1_PADDING; + break; + default: + return TPM_RC_SCHEME; + } + // Errors that might be caused by calling parameters + if(sig->signature.rsassa.sig.t.size != key->publicArea.unique.rsa.t.size) + ERROR_RETURN(TPM_RC_SIGNATURE); + TEST(sig->sigAlg); + + retVal = InitOpenSSLRSAPublicKey(key, &pkey); + if (retVal != TPM_RC_SUCCESS) + return retVal; + + digestname = GetDigestNameByHashAlg(sig->signature.any.hashAlg); + if (digestname == NULL) + ERROR_RETURN(TPM_RC_VALUE); + + md = EVP_get_digestbyname(digestname); + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (md == NULL || ctx == NULL || + EVP_PKEY_verify_init(ctx) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0 || + EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) + ERROR_RETURN(TPM_RC_FAILURE); + + if (EVP_PKEY_verify(ctx, + sig->signature.rsassa.sig.t.buffer, sig->signature.rsassa.sig.t.size, + digest->t.buffer, digest->t.size) <= 0) + ERROR_RETURN(TPM_RC_SIGNATURE); + + retVal = TPM_RC_SUCCESS; + + Exit: + EVP_PKEY_free(pkey); + EVP_PKEY_CTX_free(ctx); + + return (retVal != TPM_RC_SUCCESS) ? TPM_RC_SIGNATURE : TPM_RC_SUCCESS; +} +#endif // USE_OPENSSL_FUNCTIONS_RSA libtpms added end + +#endif // TPM_ALG_RSA diff --git a/src/tpm2/crypto/openssl/CryptSmac.c b/src/tpm2/crypto/openssl/CryptSmac.c new file mode 100644 index 0000000..c4b3515 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptSmac.c @@ -0,0 +1,156 @@ +/********************************************************************************/ +/* */ +/* Message Authentication Codes Based on a Symmetric Block Cipher */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptSmac.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2018 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.20 CryptSmac.c */ +/* 10.2.20.1 Introduction */ +/* This file contains the implementation of the message authentication codes based on a symmetric + block cipher. These functions only use the single block encryption functions of the selected + symmetric cryptographic library. */ +/* 10.2.20.2 Includes, Defines, and Typedefs */ +#define _CRYPT_HASH_C_ +#include "Tpm.h" +#if SMAC_IMPLEMENTED + /* 10.2.20.2.1 CryptSmacStart() */ + /* Function to start an SMAC. */ +UINT16 +CryptSmacStart( + HASH_STATE *state, + TPMU_PUBLIC_PARMS *keyParameters, + TPM_ALG_ID macAlg, // IN: the type of MAC + TPM2B *key + ) +{ + UINT16 retVal = 0; + // + // Make sure that the key size is correct. This should have been checked + // at key load, but... + if(BITS_TO_BYTES(keyParameters->symDetail.sym.keyBits.sym) == key->size) + { + switch(macAlg) + { +#if ALG_CMAC + case TPM_ALG_CMAC: + retVal = CryptCmacStart(&state->state.smac, keyParameters, + macAlg, key); + break; +#endif + default: + break; + } + } + state->type = (retVal != 0) ? HASH_STATE_SMAC : HASH_STATE_EMPTY; + return retVal; +} +/* 10.2.20.2.2 CryptMacStart() */ +/* Function to start either an HMAC or an SMAC. Cannot reuse the CryptHmacStart() function because + of the difference in number of parameters. */ +UINT16 +CryptMacStart( + HMAC_STATE *state, + TPMU_PUBLIC_PARMS *keyParameters, + TPM_ALG_ID macAlg, // IN: the type of MAC + TPM2B *key + ) +{ + MemorySet(state, 0, sizeof(HMAC_STATE)); + if(CryptHashIsValidAlg(macAlg, FALSE)) + { + return CryptHmacStart(state, macAlg, key->size, key->buffer); + } + else if(CryptSmacIsValidAlg(macAlg, FALSE)) + { + return CryptSmacStart(&state->hashState, keyParameters, macAlg, key); + } + else + return 0; +} +/* 10.2.20.2.3 CryptMacEnd() */ +/* Dispatch to the MAC end function using a size and buffer pointer. */ +UINT16 +CryptMacEnd( + HMAC_STATE *state, + UINT32 size, + BYTE *buffer + ) +{ + UINT16 retVal = 0; + if(state->hashState.type == HASH_STATE_SMAC) + retVal = (state->hashState.state.smac.smacMethods.end)( + &state->hashState.state.smac.state, size, buffer); + else if(state->hashState.type == HASH_STATE_HMAC) + retVal = CryptHmacEnd(state, size, buffer); + state->hashState.type = HASH_STATE_EMPTY; + return retVal; +} +#if 0 /* libtpms added */ +/* 10.2.20.2.4 CryptMacEnd2B() */ +/* Dispatch to the MAC end function using a 2B. */ +UINT16 +CryptMacEnd2B ( + HMAC_STATE *state, + TPM2B *data + ) +{ + return CryptMacEnd(state, data->size, data->buffer); +} +#endif /* libtpms added */ +#endif // SMAC_IMPLEMENTED + diff --git a/src/tpm2/crypto/openssl/CryptSym.c b/src/tpm2/crypto/openssl/CryptSym.c new file mode 100644 index 0000000..c8a0497 --- /dev/null +++ b/src/tpm2/crypto/openssl/CryptSym.c @@ -0,0 +1,771 @@ +/********************************************************************************/ +/* */ +/* Symmetric block cipher modes */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: CryptSym.c 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* 10.2.19 CryptSym.c */ +/* 10.2.19.1 Introduction */ +/* This file contains the implementation of the symmetric block cipher modes allowed for a + TPM. These functions only use the single block encryption functions of the selected symmetric + crypto library. */ + +/* 10.2.19.2 Includes, Defines, and Typedefs */ +#include "Tpm.h" +#include "CryptSym.h" +#include "Helpers_fp.h" // libtpms changed + + +#define KEY_BLOCK_SIZES(ALG, alg) \ + static const INT16 alg##KeyBlockSizes[] = { \ + ALG##_KEY_SIZES_BITS, -1, ALG##_BLOCK_SIZES }; + +FOR_EACH_SYM(KEY_BLOCK_SIZES) + +/* 10.2.19.3 Initialization and Data Access Functions */ +/* 10.2.19.3.1 CryptSymInit() */ +/* This function is called to do _TPM_Init() processing */ +BOOL +CryptSymInit( + void + ) +{ + return TRUE; +} +/* 10.2.19.3.2 CryptSymStartup() */ +/* This function is called to do TPM2_Startup() processing */ +BOOL +CryptSymStartup( + void + ) +{ + return TRUE; +} +/* 10.2.20.4 Data Access Functions */ +/* 10.2.20.4.1 CryptGetSymmetricBlockSize() */ +/* This function returns the block size of the algorithm. The table of bit sizes has an entry for + each allowed key size. The entry for a key size is 0 if the TPM does not implement that key + size. The key size table is delimited with a negative number (-1). After the delimiter is a list + of block sizes with each entry corresponding to the key bit size. For most symmetric algorithms, + the block size is the same regardless of the key size but this arrangement allows them to be + different. */ +/* Return Values Meaning */ +/* <= 0 cipher not supported */ +/* > 0 the cipher block size in bytes */ + +LIB_EXPORT INT16 +CryptGetSymmetricBlockSize( + TPM_ALG_ID symmetricAlg, // IN: the symmetric algorithm + UINT16 keySizeInBits // IN: the key size + ) +{ + const INT16 *sizes; + INT16 i; +#if 0 // libtpms added +#define ALG_CASE(SYM, sym) case TPM_ALG_##SYM: sizes = sym##KeyBlockSizes; break +#endif // libtpms added + switch(symmetricAlg) + { +#define GET_KEY_BLOCK_POINTER(SYM, sym) \ + case TPM_ALG_##SYM: \ + sizes = sym##KeyBlockSizes; \ + break; + // Get the pointer to the block size array + FOR_EACH_SYM(GET_KEY_BLOCK_POINTER); + + default: + return 0; + } + // Find the index of the indicated keySizeInBits + for(i = 0; *sizes >= 0; i++, sizes++) + { + if(*sizes == keySizeInBits) + break; + } + // If sizes is pointing at the end of the list of key sizes, then the desired + // key size was not found so set the block size to zero. + if(*sizes++ < 0) + return 0; + // Advance until the end of the list is found + while(*sizes++ >= 0); + // sizes is pointing to the first entry in the list of block sizes. Use the + // ith index to find the block size for the corresponding key size. + return sizes[i]; +} + +#if !USE_OPENSSL_FUNCTIONS_SYMMETRIC // libtpms added +/* 10.2.20.5 Symmetric Encryption */ +/* This function performs symmetric encryption based on the mode. */ +/* Error Returns Meaning */ +/* TPM_RC_SIZE dSize is not a multiple of the block size for an algorithm that requires it */ +/* TPM_RC_FAILURE Fatal error */ +LIB_EXPORT TPM_RC +CryptSymmetricEncrypt( + BYTE *dOut, // OUT: + TPM_ALG_ID algorithm, // IN: the symmetric algorithm + UINT16 keySizeInBits, // IN: key size in bits + const BYTE *key, // IN: key buffer. The size of this buffer + // in bytes is (keySizeInBits + 7) / 8 + TPM2B_IV *ivInOut, // IN/OUT: IV for decryption. + TPM_ALG_ID mode, // IN: Mode to use + INT32 dSize, // IN: data size (may need to be a + // multiple of the blockSize) + const BYTE *dIn // IN: data buffer + ) +{ + BYTE *pIv; + int i; + BYTE tmp[MAX_SYM_BLOCK_SIZE]; + BYTE *pT; + tpmCryptKeySchedule_t keySchedule; + INT16 blockSize; + TpmCryptSetSymKeyCall_t encrypt; + BYTE *iv; + BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0}; + // + memset(&keySchedule, 0, sizeof(keySchedule)); // libtpms added; coverity + pAssert(dOut != NULL && key != NULL && dIn != NULL); + if(dSize == 0) + return TPM_RC_SUCCESS; + TEST(algorithm); + blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits); + if(blockSize == 0) + return TPM_RC_FAILURE; + // If the iv is provided, then it is expected to be block sized. In some cases, + // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE] + // with no knowledge of the actual block size. This function will set it. + if((ivInOut != NULL) && (mode != TPM_ALG_ECB)) + { + ivInOut->t.size = blockSize; + iv = ivInOut->t.buffer; + } + else + iv = defaultIv; + pIv = iv; + // Create encrypt key schedule and set the encryption function pointer. + switch (algorithm) + { + FOR_EACH_SYM(ENCRYPT_CASE) + + default: + return TPM_RC_SYMMETRIC; + } + switch(mode) + { +#if ALG_CTR + case TPM_ALG_CTR: + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the current value of the IV(counter) + ENCRYPT(&keySchedule, iv, tmp); + //increment the counter (counter is big-endian so start at end) + for(i = blockSize - 1; i >= 0; i--) + if((iv[i] += 1) != 0) + break; + // XOR the encrypted counter value with input and put into output + pT = tmp; + for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--) + *dOut++ = *dIn++ ^ *pT++; + } + break; +#endif +#if ALG_OFB + case TPM_ALG_OFB: + // This is written so that dIn and dOut may be the same + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the current value of the "IV" + ENCRYPT(&keySchedule, iv, iv); + // XOR the encrypted IV into dIn to create the cipher text (dOut) + pIv = iv; + for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--) + *dOut++ = (*pIv++ ^ *dIn++); + } + break; +#endif +#if ALG_CBC + case TPM_ALG_CBC: + // For CBC the data size must be an even multiple of the + // cipher block size + if((dSize % blockSize) != 0) + return TPM_RC_SIZE; + // XOR the data block into the IV, encrypt the IV into the IV + // and then copy the IV to the output + for(; dSize > 0; dSize -= blockSize) + { + pIv = iv; + for(i = blockSize; i > 0; i--) + *pIv++ ^= *dIn++; + ENCRYPT(&keySchedule, iv, iv); + pIv = iv; + for(i = blockSize; i > 0; i--) + *dOut++ = *pIv++; + } + break; +#endif + // CFB is not optional + case TPM_ALG_CFB: + // Encrypt the IV into the IV, XOR in the data, and copy to output + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the current value of the IV + ENCRYPT(&keySchedule, iv, iv); + pIv = iv; + for(i = (int)(dSize < blockSize) ? dSize : blockSize; i > 0; i--) + // XOR the data into the IV to create the cipher text + // and put into the output + *dOut++ = *pIv++ ^= *dIn++; + } + // If the inner loop (i loop) was smaller than blockSize, then dSize + // would have been smaller than blockSize and it is now negative. If + // it is negative, then it indicates how many bytes are needed to pad + // out the IV for the next round. + for(; dSize < 0; dSize++) + *pIv++ = 0; + break; +#if ALG_ECB + case TPM_ALG_ECB: + // For ECB the data size must be an even multiple of the + // cipher block size + if((dSize % blockSize) != 0) + return TPM_RC_SIZE; + // Encrypt the input block to the output block + for(; dSize > 0; dSize -= blockSize) + { + ENCRYPT(&keySchedule, dIn, dOut); + dIn = &dIn[blockSize]; + dOut = &dOut[blockSize]; + } + break; +#endif + default: + return TPM_RC_FAILURE; + } + return TPM_RC_SUCCESS; +} +/* 10.2.20.5.1 CryptSymmetricDecrypt() */ +/* This function performs symmetric decryption based on the mode. */ +/* Error Returns Meaning */ +/* TPM_RC_FAILURE A fatal error */ +/* TPM_RCS_SIZE dSize is not a multiple of the block size for an algorithm that requires it */ +LIB_EXPORT TPM_RC +CryptSymmetricDecrypt( + BYTE *dOut, // OUT: decrypted data + TPM_ALG_ID algorithm, // IN: the symmetric algorithm + UINT16 keySizeInBits, // IN: key size in bits + const BYTE *key, // IN: key buffer. The size of this buffer + // in bytes is (keySizeInBits + 7) / 8 + TPM2B_IV *ivInOut, // IN/OUT: IV for decryption. + TPM_ALG_ID mode, // IN: Mode to use + INT32 dSize, // IN: data size (may need to be a + // multiple of the blockSize) + const BYTE *dIn // IN: data buffer + ) +{ + BYTE *pIv; + int i; + BYTE tmp[MAX_SYM_BLOCK_SIZE]; + BYTE *pT; + tpmCryptKeySchedule_t keySchedule; + INT16 blockSize; + BYTE *iv; + TpmCryptSetSymKeyCall_t encrypt; + TpmCryptSetSymKeyCall_t decrypt; + BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0}; + + memset(&keySchedule, 0, sizeof(keySchedule)); // libtpms added; coverity + // These are used but the compiler can't tell because they are initialized + // in case statements and it can't tell if they are always initialized + // when needed, so... Comment these out if the compiler can tell or doesn't + // care that these are initialized before use. + encrypt = NULL; + decrypt = NULL; + pAssert(dOut != NULL && key != NULL && dIn != NULL); + if(dSize == 0) + return TPM_RC_SUCCESS; + TEST(algorithm); + blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits); + if(blockSize == 0) + return TPM_RC_FAILURE; + // If the iv is provided, then it is expected to be block sized. In some cases, + // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE] + // with no knowledge of the actual block size. This function will set it. + if((ivInOut != NULL) && (mode != TPM_ALG_ECB)) + { + ivInOut->t.size = blockSize; + iv = ivInOut->t.buffer; + } + else + iv = defaultIv; + pIv = iv; + // Use the mode to select the key schedule to create. Encrypt always uses the + // encryption schedule. Depending on the mode, decryption might use either + // the decryption or encryption schedule. + switch(mode) + { +#if ALG_CBC || ALG_ECB + case TPM_ALG_CBC: // decrypt = decrypt + case TPM_ALG_ECB: + // For ECB and CBC, the data size must be an even multiple of the + // cipher block size + if((dSize % blockSize) != 0) + return TPM_RC_SIZE; + switch (algorithm) + { + FOR_EACH_SYM(DECRYPT_CASE) + default: + return TPM_RC_SYMMETRIC; + } + break; +#endif + default: + // For the remaining stream ciphers, use encryption to decrypt + switch (algorithm) + { + FOR_EACH_SYM(ENCRYPT_CASE) + default: + return TPM_RC_SYMMETRIC; + } + } + // Now do the mode-dependent decryption + switch(mode) + { +#if ALG_CBC + case TPM_ALG_CBC: + // Copy the input data to a temp buffer, decrypt the buffer into the + // output, XOR in the IV, and copy the temp buffer to the IV and repeat. + for(; dSize > 0; dSize -= blockSize) + { + pT = tmp; + for(i = blockSize; i > 0; i--) + *pT++ = *dIn++; + DECRYPT(&keySchedule, tmp, dOut); + pIv = iv; + pT = tmp; + for(i = blockSize; i > 0; i--) + { + *dOut++ ^= *pIv; + *pIv++ = *pT++; + } + } + break; +#endif + case TPM_ALG_CFB: + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the IV into the temp buffer + ENCRYPT(&keySchedule, iv, tmp); + pT = tmp; + pIv = iv; + for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--) + // Copy the current cipher text to IV, XOR + // with the temp buffer and put into the output + *dOut++ = *pT++ ^ (*pIv++ = *dIn++); + } + // If the inner loop (i loop) was smaller than blockSize, then dSize + // would have been smaller than blockSize and it is now negative + // If it is negative, then it indicates how may fill bytes + // are needed to pad out the IV for the next round. + for(; dSize < 0; dSize++) + *pIv++ = 0; + break; +#if ALG_CTR + case TPM_ALG_CTR: + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the current value of the IV(counter) + ENCRYPT(&keySchedule, iv, tmp); + //increment the counter (counter is big-endian so start at end) + for(i = blockSize - 1; i >= 0; i--) + if((iv[i] += 1) != 0) + break; + // XOR the encrypted counter value with input and put into output + pT = tmp; + for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--) + *dOut++ = *dIn++ ^ *pT++; + } + break; +#endif +#if ALG_ECB + case TPM_ALG_ECB: + for(; dSize > 0; dSize -= blockSize) + { + DECRYPT(&keySchedule, dIn, dOut); + dIn = &dIn[blockSize]; + dOut = &dOut[blockSize]; + } + break; +#endif +#if ALG_OFB + case TPM_ALG_OFB: + // This is written so that dIn and dOut may be the same + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the current value of the "IV" + ENCRYPT(&keySchedule, iv, iv); + // XOR the encrypted IV into dIn to create the cipher text (dOut) + pIv = iv; + for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--) + *dOut++ = (*pIv++ ^ *dIn++); + } + break; +#endif + default: + return TPM_RC_FAILURE; + } + return TPM_RC_SUCCESS; +} + +#else // libtpms added begin + +#if ALG_TDES && ALG_CTR +// Emulated TDES Counter mode since OpenSSL does not implement it +static void TDES_CTR(const BYTE *key, // IN + INT32 keySizeInBits, // IN + INT32 dSize, // IN + const BYTE *dIn, // IN + BYTE *iv, // IN + BYTE *dOut, // OUT + INT16 blockSize // IN + ) +{ + tpmCryptKeySchedule_t keySchedule; + int i; + BYTE tmp[MAX_SYM_BLOCK_SIZE]; + BYTE *pT; + + TDES_set_encrypt_key(key, keySizeInBits, + (tpmKeyScheduleTDES *)&keySchedule.tdes); + + for(; dSize > 0; dSize -= blockSize) + { + // Encrypt the current value of the IV(counter) + TDES_encrypt(iv, tmp, (tpmKeyScheduleTDES *)&keySchedule.tdes); + //increment the counter (counter is big-endian so start at end) + for(i = blockSize - 1; i >= 0; i--) + if((iv[i] += 1) != 0) + break; + // XOR the encrypted counter value with input and put into output + pT = tmp; + for(i = (dSize < blockSize) ? dSize : blockSize; i > 0; i--) + *dOut++ = *dIn++ ^ *pT++; + } +} +#endif + +/* 10.2.20.5 Symmetric Encryption */ +/* This function performs symmetric encryption based on the mode. */ +/* Error Returns Meaning */ +/* TPM_RC_SIZE dSize is not a multiple of the block size for an algorithm that requires it */ +/* TPM_RC_FAILURE Fatal error */ +LIB_EXPORT TPM_RC +CryptSymmetricEncrypt( + BYTE *dOut, // OUT: + TPM_ALG_ID algorithm, // IN: the symmetric algorithm + UINT16 keySizeInBits, // IN: key size in bits + const BYTE *key, // IN: key buffer. The size of this buffer + // in bytes is (keySizeInBits + 7) / 8 + TPM2B_IV *ivInOut, // IN/OUT: IV for decryption. + TPM_ALG_ID mode, // IN: Mode to use + INT32 dSize, // IN: data size (may need to be a + // multiple of the blockSize) + const BYTE *dIn // IN: data buffer + ) +{ + INT16 blockSize; + BYTE *iv; + BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0}; + evpfunc evpfn; + EVP_CIPHER_CTX *ctx = NULL; + int outlen1 = 0; + int outlen2 = 0; + BYTE *pOut = dOut; + BYTE *buffer = NULL; // for in-place encryption + UINT32 buffersize = 0; + BYTE keyToUse[MAX_SYM_KEY_BYTES]; + UINT16 keyToUseLen = (UINT16)sizeof(keyToUse); + TPM_RC retVal = TPM_RC_SUCCESS; + int ivLen; + + pAssert(dOut != NULL && key != NULL && dIn != NULL); + if(dSize == 0) + return TPM_RC_SUCCESS; + TEST(algorithm); + blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits); + if(blockSize == 0) + return TPM_RC_FAILURE; + // If the iv is provided, then it is expected to be block sized. In some cases, + // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE] + // with no knowledge of the actual block size. This function will set it. + if((ivInOut != NULL) && (mode != TPM_ALG_ECB)) + { + ivInOut->t.size = blockSize; + iv = ivInOut->t.buffer; + } + else + iv = defaultIv; + + switch (mode) + { + case TPM_ALG_ECB: + case TPM_ALG_CBC: + // For ECB & CBC the data size must be an even multiple of the + // cipher block size + if((dSize % blockSize) != 0) + return TPM_RC_SIZE; + } + + evpfn = GetEVPCipher(algorithm, keySizeInBits, mode, key, + keyToUse, &keyToUseLen); + if (evpfn == NULL) + return TPM_RC_FAILURE; + + if (dIn == dOut) { + // in-place encryption; we use a temp buffer + buffersize = TPM2_ROUNDUP(dSize, blockSize); + buffer = malloc(buffersize); + if (buffer == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + pOut = buffer; + } + +#if ALG_TDES && ALG_CTR + if (algorithm == TPM_ALG_TDES && mode == TPM_ALG_CTR) { + TDES_CTR(keyToUse, keyToUseLen * 8, dSize, dIn, iv, pOut, blockSize); + outlen1 = dSize; + ERROR_RETURN(TPM_RC_SUCCESS); + } +#endif + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx || + EVP_EncryptInit_ex(ctx, evpfn(), NULL, keyToUse, iv) != 1 || + EVP_CIPHER_CTX_set_padding(ctx, 0) != 1 || + EVP_EncryptUpdate(ctx, pOut, &outlen1, dIn, dSize) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + pAssert(outlen1 <= dSize || dSize >= outlen1 + blockSize); + + if (EVP_EncryptFinal_ex(ctx, pOut + outlen1, &outlen2) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + if (ivInOut) { + ivLen = EVP_CIPHER_CTX_iv_length(ctx); + if (ivLen < 0 || (size_t)ivLen > sizeof(ivInOut->t.buffer)) + ERROR_RETURN(TPM_RC_FAILURE); + + ivInOut->t.size = ivLen; + memcpy(ivInOut->t.buffer, EVP_CIPHER_CTX_iv(ctx), ivInOut->t.size); + } + Exit: + if (retVal == TPM_RC_SUCCESS && pOut != dOut) + memcpy(dOut, pOut, outlen1 + outlen2); + + clear_and_free(buffer, buffersize); + EVP_CIPHER_CTX_free(ctx); + + return retVal; +} + +/* 10.2.20.5.1 CryptSymmetricDecrypt() */ +/* This function performs symmetric decryption based on the mode. */ +/* Error Returns Meaning */ +/* TPM_RC_FAILURE A fatal error */ +/* TPM_RCS_SIZE dSize is not a multiple of the block size for an algorithm that requires it */ +LIB_EXPORT TPM_RC +CryptSymmetricDecrypt( + BYTE *dOut, // OUT: decrypted data + TPM_ALG_ID algorithm, // IN: the symmetric algorithm + UINT16 keySizeInBits, // IN: key size in bits + const BYTE *key, // IN: key buffer. The size of this buffer + // in bytes is (keySizeInBits + 7) / 8 + TPM2B_IV *ivInOut, // IN/OUT: IV for decryption. + TPM_ALG_ID mode, // IN: Mode to use + INT32 dSize, // IN: data size (may need to be a + // multiple of the blockSize) + const BYTE *dIn // IN: data buffer + ) +{ + INT16 blockSize; + BYTE *iv; + BYTE defaultIv[MAX_SYM_BLOCK_SIZE] = {0}; + evpfunc evpfn; + EVP_CIPHER_CTX *ctx = NULL; + int outlen1 = 0; + int outlen2 = 0; + BYTE *buffer; + UINT32 buffersize = 0; + BYTE keyToUse[MAX_SYM_KEY_BYTES]; + UINT16 keyToUseLen = (UINT16)sizeof(keyToUse); + TPM_RC retVal = TPM_RC_SUCCESS; + int ivLen; + + // These are used but the compiler can't tell because they are initialized + // in case statements and it can't tell if they are always initialized + // when needed, so... Comment these out if the compiler can tell or doesn't + // care that these are initialized before use. + pAssert(dOut != NULL && key != NULL && dIn != NULL); + if(dSize == 0) + return TPM_RC_SUCCESS; + TEST(algorithm); + blockSize = CryptGetSymmetricBlockSize(algorithm, keySizeInBits); + if(blockSize == 0) + return TPM_RC_FAILURE; + // If the iv is provided, then it is expected to be block sized. In some cases, + // the caller is providing an array of 0's that is equal to [MAX_SYM_BLOCK_SIZE] + // with no knowledge of the actual block size. This function will set it. + if((ivInOut != NULL) && (mode != TPM_ALG_ECB)) + { + ivInOut->t.size = blockSize; + iv = ivInOut->t.buffer; + } + else + iv = defaultIv; + + switch(mode) + { +#if ALG_CBC || ALG_ECB + case TPM_ALG_CBC: + case TPM_ALG_ECB: + // For ECB and CBC, the data size must be an even multiple of the + // cipher block size + if((dSize % blockSize) != 0) + return TPM_RC_SIZE; + break; +#endif + default: + break; + } + + evpfn = GetEVPCipher(algorithm, keySizeInBits, mode, key, + keyToUse, &keyToUseLen); + if (evpfn == NULL) + return TPM_RC_FAILURE; + + /* a buffer with a 'safety margin' for EVP_DecryptUpdate */ + buffersize = TPM2_ROUNDUP(dSize + blockSize, blockSize); + buffer = malloc(buffersize); + if (buffer == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + +#if ALG_TDES && ALG_CTR + if (algorithm == TPM_ALG_TDES && mode == TPM_ALG_CTR) { + TDES_CTR(keyToUse, keyToUseLen * 8, dSize, dIn, iv, buffer, blockSize); + outlen1 = dSize; + ERROR_RETURN(TPM_RC_SUCCESS); + } +#endif + + ctx = EVP_CIPHER_CTX_new(); + if (!ctx || + EVP_DecryptInit_ex(ctx, evpfn(), NULL, keyToUse, iv) != 1 || + EVP_CIPHER_CTX_set_padding(ctx, 0) != 1 || + EVP_DecryptUpdate(ctx, buffer, &outlen1, dIn, dSize) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + pAssert((int)buffersize >= outlen1); + + if ((int)buffersize <= outlen1 /* coverity */ || + EVP_DecryptFinal(ctx, &buffer[outlen1], &outlen2) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + pAssert((int)buffersize >= outlen1 + outlen2); + + if (ivInOut) { + ivLen = EVP_CIPHER_CTX_iv_length(ctx); + if (ivLen < 0 || (size_t)ivLen > sizeof(ivInOut->t.buffer)) + ERROR_RETURN(TPM_RC_FAILURE); + + ivInOut->t.size = ivLen; + memcpy(ivInOut->t.buffer, EVP_CIPHER_CTX_iv(ctx), ivInOut->t.size); + } + + Exit: + if (retVal == TPM_RC_SUCCESS) { + pAssert(dSize >= outlen1 + outlen2); + memcpy(dOut, buffer, outlen1 + outlen2); + } + + clear_and_free(buffer, buffersize); + EVP_CIPHER_CTX_free(ctx); + + return retVal; +} + +#endif // libtpms added end + +/* 10.2.20.5.2 CryptSymKeyValidate() */ +/* Validate that a provided symmetric key meets the requirements of the TPM */ +/* Error Returns Meaning */ +/* TPM_RC_KEY_SIZE Key size specifiers do not match */ +/* TPM_RC_KEY Key is not allowed */ +TPM_RC +CryptSymKeyValidate( + TPMT_SYM_DEF_OBJECT *symDef, + TPM2B_SYM_KEY *key + ) +{ + if(key->t.size != BITS_TO_BYTES(symDef->keyBits.sym)) + return TPM_RCS_KEY_SIZE; +#if ALG_TDES + if(symDef->algorithm == TPM_ALG_TDES && !CryptDesValidateKey(key)) + return TPM_RCS_KEY; +#endif // TPM_ALG_TDES + return TPM_RC_SUCCESS; +} diff --git a/src/tpm2/crypto/openssl/ExpDCache.c b/src/tpm2/crypto/openssl/ExpDCache.c new file mode 100644 index 0000000..5aeaf14 --- /dev/null +++ b/src/tpm2/crypto/openssl/ExpDCache.c @@ -0,0 +1,200 @@ +/********************************************************************************/ +/* */ +/* Private Exponent D cache functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp., 2021 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "ExpDCache_fp.h" + +/* Implement a cache for the private exponent D so it doesn't need to be + * recalculated every time from P, Q, E and N (modulus). The cache has a + * number of entries that cache D and use P, Q, and E for lookup. + * A least-recently-used cache eviction strategy is implemented that evicts + * the oldest cache entry in case space is needed. An entry is young once + * it is added or made young when it was found via lookup. All other entries + * age by '1' when an entry is added or accessed. + */ + +struct ExpDCacheEntry { + /* The age of the entry; the higher the number the more likely it + * will be evicted soon + */ + unsigned int age; + BIGNUM *P; /* input */ + BIGNUM *N; /* input */ + BIGNUM *E; /* input */ + BIGNUM *Q; /* cached */ + BIGNUM *D; /* cached */ +}; + +#define DCACHE_NUM_ENTRIES 64 + +static struct ExpDCacheEntry ExpDCache[DCACHE_NUM_ENTRIES]; + +/* Increment the age of all cache entries that have a current age <= maxage */ +static void ExpDCacheIncrementAge(unsigned maxage) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(ExpDCache); i++) { + if (ExpDCache[i].age <= maxage && ExpDCache[i].D != NULL) + ExpDCache[i].age++; + } +} + +/* Free the data associated with a ExpDCacheEntry and initialize it */ +static void ExpDCacheEntryFree(struct ExpDCacheEntry *dce) +{ + BN_clear_free(dce->P); + BN_free(dce->N); + BN_free(dce->E); + BN_clear_free(dce->Q); + BN_clear_free(dce->D); + memset(dce, 0, sizeof(*dce)); +} + +void ExpDCacheFree(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(ExpDCache); i++) + ExpDCacheEntryFree(&ExpDCache[i]); +} + +/* Get a ExpDCacheEntry by finding either an unused entry or evicting the oldest + * entry. The returned entry will have all NULL pointers and age 0. + */ +static struct ExpDCacheEntry *ExpDCacheEntryGet(void) +{ + size_t i, use_i = 0; + unsigned oldest_age = 0; + struct ExpDCacheEntry *dce; + + for (i = 0; i < ARRAY_SIZE(ExpDCache); i++) { + if (ExpDCache[i].D == NULL) { + /* use this free entry */ + use_i = i; + break; + } + if (ExpDCache[i].age > oldest_age) { + /* this one is currently the oldest */ + use_i = i; + oldest_age = ExpDCache[i].age; + } + } + dce = &ExpDCache[use_i]; + + ExpDCacheEntryFree(dce); + + return dce; +} + +/* Add 'D' to the ExpDCache. This function does not check for duplicates */ +void ExpDCacheAdd(const BIGNUM *P, const BIGNUM *N, const BIGNUM *E, + const BIGNUM *Q, const BIGNUM *D) +{ + struct ExpDCacheEntry *dce = ExpDCacheEntryGet(); + + /* age of 'dce' is '0' */ + dce->P = BN_dup(P); + dce->N = BN_dup(N); + dce->E = BN_dup(E); + dce->Q = BN_dup(Q); + dce->D = BN_dup(D); + + if (!dce->P || !dce->N || !dce->E || !dce->Q || !dce->D) + ExpDCacheEntryFree(dce); + else + ExpDCacheIncrementAge(~0); +} + +BIGNUM *ExpDCacheFind(const BIGNUM *P, const BIGNUM *N, const BIGNUM *E, BIGNUM **Q) +{ + size_t i; + unsigned myage; + BIGNUM *D; + + for (i = 0; i < ARRAY_SIZE(ExpDCache); i++) { + if (BN_cmp(ExpDCache[i].P, P) == 0 && BN_cmp(ExpDCache[i].N, N) == 0 && + BN_cmp(ExpDCache[i].E, E) == 0) { + /* entry found */ + myage = ExpDCache[i].age; + /* mark this entry as most recently used */ + ExpDCache[i].age = 0; + /* Increment everyone who is <= 'myage'. + * The age of this entry will be '1' after that. + */ + ExpDCacheIncrementAge(myage); + + *Q = BN_dup(ExpDCache[i].Q); + if (*Q == NULL) + return NULL; + D = BN_dup(ExpDCache[i].D); + if (D == NULL) { + BN_clear_free(*Q); + *Q = NULL; + return NULL; + } + BN_set_flags(*Q, BN_FLG_CONSTTIME); + BN_set_flags(D, BN_FLG_CONSTTIME); + return D; + } + } + + return NULL; +} diff --git a/src/tpm2/crypto/openssl/ExpDCache_fp.h b/src/tpm2/crypto/openssl/ExpDCache_fp.h new file mode 100644 index 0000000..b8ee9d7 --- /dev/null +++ b/src/tpm2/crypto/openssl/ExpDCache_fp.h @@ -0,0 +1,75 @@ +/********************************************************************************/ +/* */ +/* Private Exponent D cache functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp., 2021 */ +/* */ +/********************************************************************************/ + +#ifndef DCACHE_FP_H +#define DCACHE_FP_H + +#include <openssl/bn.h> + +BIGNUM *ExpDCacheFind(const BIGNUM *P, const BIGNUM *N, const BIGNUM *E, + BIGNUM **Q); + +void ExpDCacheAdd(const BIGNUM *P, const BIGNUM *N, const BIGNUM *E, + const BIGNUM *Q, const BIGNUM *D); + +void ExpDCacheFree(void); + +#endif /* DCACHE_FP_H */ + diff --git a/src/tpm2/crypto/openssl/Helpers.c b/src/tpm2/crypto/openssl/Helpers.c new file mode 100644 index 0000000..f47cdbf --- /dev/null +++ b/src/tpm2/crypto/openssl/Helpers.c @@ -0,0 +1,625 @@ +/********************************************************************************/ +/* */ +/* OpenSSL helper functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2019 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "ExpDCache_fp.h" +#include "Helpers_fp.h" +#include "TpmToOsslMath_fp.h" + +#include "config.h" + +#include <openssl/evp.h> +#include <openssl/rsa.h> + +/* to enable RSA_check_key() on private keys set to != 0 */ +#ifndef DO_RSA_CHECK_KEY +#define DO_RSA_CHECK_KEY 0 +#endif + +#if USE_OPENSSL_FUNCTIONS_SYMMETRIC + +TPM_RC +OpenSSLCryptGenerateKeyDes( + TPMT_SENSITIVE *sensitive // OUT: sensitive area + ) +{ + DES_cblock *key; + size_t offset; + size_t limit; + + limit = MIN(sizeof(sensitive->sensitive.sym.t.buffer), + sensitive->sensitive.sym.t.size); + limit = TPM2_ROUNDUP(limit, sizeof(*key)); + pAssert(limit < sizeof(sensitive->sensitive.sym.t.buffer)); + + for (offset = 0; offset < limit; offset += sizeof(*key)) { + key = (DES_cblock *)&sensitive->sensitive.sym.t.buffer[offset]; + if (DES_random_key(key) != 1) + return TPM_RC_NO_RESULT; + } + return TPM_RC_SUCCESS; +} + +evpfunc GetEVPCipher(TPM_ALG_ID algorithm, // IN + UINT16 keySizeInBits, // IN + TPM_ALG_ID mode, // IN + const BYTE *key, // IN + BYTE *keyToUse, // OUT same as key or stretched key + UINT16 *keyToUseLen // IN/OUT + ) +{ + int i; + UINT16 keySizeInBytes = keySizeInBits / 8; + evpfunc evpfn = NULL; + + // key size to array index: 128 -> 0, 192 -> 1, 256 -> 2 + i = (keySizeInBits >> 6) - 2; + if (i < 0 || i > 2) + return NULL; + + pAssert(*keyToUseLen >= keySizeInBytes) + memcpy(keyToUse, key, keySizeInBytes); + + switch (algorithm) { +#if ALG_AES + case TPM_ALG_AES: + *keyToUseLen = keySizeInBytes; + switch (mode) { +#if ALG_CTR + case TPM_ALG_CTR: + evpfn = (evpfunc []){EVP_aes_128_ctr, EVP_aes_192_ctr, + EVP_aes_256_ctr}[i]; + break; +#endif +#if ALG_OFB + case TPM_ALG_OFB: + evpfn = (evpfunc[]){EVP_aes_128_ofb, EVP_aes_192_ofb, + EVP_aes_256_ofb}[i]; + break; +#endif +#if ALG_CBC + case TPM_ALG_CBC: + evpfn = (evpfunc[]){EVP_aes_128_cbc, EVP_aes_192_cbc, + EVP_aes_256_cbc}[i]; + break; +#endif +#if ALG_CFB + case TPM_ALG_CFB: + evpfn = (evpfunc[]){EVP_aes_128_cfb, EVP_aes_192_cfb, + EVP_aes_256_cfb}[i]; + break; +#endif +#if ALG_ECB + case TPM_ALG_ECB: + evpfn = (evpfunc[]){EVP_aes_128_ecb, EVP_aes_192_ecb, + EVP_aes_256_ecb}[i]; + break; +#endif + } + break; +#endif +#if ALG_TDES + case TPM_ALG_TDES: + if (keySizeInBits == 128) { + pAssert(*keyToUseLen >= BITS_TO_BYTES(192)) + // stretch the key + memcpy(&keyToUse[16], &keyToUse[0], 8); + *keyToUseLen = BITS_TO_BYTES(192); + } + + switch (mode) { +#if ALG_CTR + case TPM_ALG_CTR: + evpfn = (evpfunc[]){EVP_des_ede3, EVP_des_ede3, NULL}[i]; + break; +#endif +#if ALG_OFB + case TPM_ALG_OFB: + evpfn = (evpfunc[]){EVP_des_ede3_ofb, EVP_des_ede3_ofb, NULL}[i]; + break; +#endif +#if ALG_CBC + case TPM_ALG_CBC: + evpfn = (evpfunc[]){EVP_des_ede3_cbc, EVP_des_ede3_cbc, NULL}[i]; + break; +#endif +#if ALG_CFB + case TPM_ALG_CFB: + evpfn = (evpfunc[]){EVP_des_ede3_cfb64, EVP_des_ede3_cfb64, NULL}[i]; + break; +#endif +#if ALG_ECB + case TPM_ALG_ECB: + evpfn = (evpfunc[]){EVP_des_ede3_ecb, EVP_des_ede3_ecb, NULL}[i]; + break; +#endif + } + break; +#endif + +#if ALG_SM4 + case TPM_ALG_SM4: + *keyToUseLen = keySizeInBytes; + switch (mode) { +#if ALG_CTR + case TPM_ALG_CTR: + evpfn = (evpfunc[]){EVP_sm4_ctr, NULL, NULL}[i]; + break; +#endif +#if ALG_OFB + case TPM_ALG_OFB: + evpfn = (evpfunc[]){EVP_sm4_ofb, NULL, NULL}[i]; + break; +#endif +#if ALG_CBC + case TPM_ALG_CBC: + evpfn = (evpfunc[]){EVP_sm4_cbc, NULL, NULL}[i]; + break; +#endif +#if ALG_CFB + case TPM_ALG_CFB: + evpfn = (evpfunc[]){EVP_sm4_cfb, NULL, NULL}[i]; + break; +#endif +#if ALG_ECB + case TPM_ALG_ECB: + evpfn = (evpfunc[]){EVP_sm4_ecb, NULL, NULL}[i]; + break; +#endif + } + break; +#endif + +#if ALG_CAMELLIA + case TPM_ALG_CAMELLIA: + *keyToUseLen = keySizeInBytes; + switch (mode) { +#if ALG_CTR + case TPM_ALG_CTR: + evpfn = (evpfunc []){EVP_camellia_128_ctr, EVP_camellia_192_ctr, + EVP_camellia_256_ctr}[i]; + break; +#endif +#if ALG_OFB + case TPM_ALG_OFB: + evpfn = (evpfunc[]){EVP_camellia_128_ofb, EVP_camellia_192_ofb, + EVP_camellia_256_ofb}[i]; + break; +#endif +#if ALG_CBC + case TPM_ALG_CBC: + evpfn = (evpfunc[]){EVP_camellia_128_cbc, EVP_camellia_192_cbc, + EVP_camellia_256_cbc}[i]; + break; +#endif +#if ALG_CFB + case TPM_ALG_CFB: + evpfn = (evpfunc[]){EVP_camellia_128_cfb, EVP_camellia_192_cfb, + EVP_camellia_256_cfb}[i]; + break; +#endif +#if ALG_ECB + case TPM_ALG_ECB: + evpfn = (evpfunc[]){EVP_camellia_128_ecb, EVP_camellia_192_ecb, + EVP_camellia_256_ecb}[i]; + break; +#endif + } + break; +#endif + } + + if (evpfn == NULL) + MemorySet(keyToUse, 0, *keyToUseLen); + + return evpfn; +} + +#endif // USE_OPENSSL_FUNCTIONS_SYMMETRIC + +#if USE_OPENSSL_FUNCTIONS_EC +BOOL +OpenSSLEccGetPrivate( + bigNum dOut, // OUT: the qualified random value + const EC_GROUP *G, // IN: the EC_GROUP to use + const UINT32 requestedBits // IN: if not 0, then dOut must have that many bits + ) +{ + BOOL OK = FALSE; + const BIGNUM *D; + EC_KEY *eckey = EC_KEY_new(); + UINT32 requestedBytes = BITS_TO_BYTES(requestedBits); + int repeats = 0; + int maxRepeats; + int numBytes; + + pAssert(G != NULL); + + if (!eckey) + return FALSE; + + if (EC_KEY_set_group(eckey, G) != 1) + goto Exit; + + maxRepeats = 8; + // non-byte boundary order'ed curves, like NIST P521, need more loops to + // have a result with topmost byte != 0 + if (requestedBits & 7) + maxRepeats += (9 - (requestedBits & 7)); + + while (true) { + if (EC_KEY_generate_key(eckey) == 1) { + D = EC_KEY_get0_private_key(eckey); + // if we need a certain amount of bytes and we are below a threshold + // of loops, check the number of bytes we have, otherwise take the + // result + if ((requestedBytes != 0) && (repeats < maxRepeats)) { + numBytes = BN_num_bytes(D); + if ((int)requestedBytes != numBytes) { + // result does not have enough bytes + repeats++; + continue; + } + // result is sufficient + } + OK = TRUE; + OsslToTpmBn(dOut, D); + } + break; + } + + Exit: + EC_KEY_free(eckey); + + return OK; +} +#endif // USE_OPENSSL_FUNCTIONS_EC + +#if USE_OPENSSL_FUNCTIONS_RSA + +static const struct hnames { + const char *name; + TPM_ALG_ID hashAlg; +} hnames[HASH_COUNT + 1] = { + { +#if ALG_SHA1 + .name = "sha1", + .hashAlg = ALG_SHA1_VALUE, + }, { +#endif +#if ALG_SHA256 + .name = "sha256", + .hashAlg = ALG_SHA256_VALUE, + }, { +#endif +#if ALG_SHA384 + .name = "sha384", + .hashAlg = ALG_SHA384_VALUE, + }, { +#endif +#if ALG_SHA512 + .name = "sha512", + .hashAlg = ALG_SHA512_VALUE, + }, { +#endif + .name = NULL, + } +}; +#if HASH_COUNT != ALG_SHA1 + ALG_SHA256 + ALG_SHA384 + ALG_SHA512 +# error Missing entry in hnames array! +#endif + +LIB_EXPORT const char * +GetDigestNameByHashAlg(const TPM_ALG_ID hashAlg) +{ + unsigned i; + + for (i = 0; i < HASH_COUNT; i++) { + if (hashAlg == hnames[i].hashAlg) + return hnames[i].name; + } + return NULL; +} + +static BOOL +ComputePrivateExponentD( + const BIGNUM *P, // IN: first prime (size is 1/2 of bnN) + const BIGNUM *Q, // IN: second prime (size is 1/2 of bnN) + const BIGNUM *E, // IN: the public exponent + const BIGNUM *N, // IN: the public modulus + BIGNUM **D // OUT: + ) +{ + BOOL pOK = FALSE; + BIGNUM *phi; + BN_CTX *ctx; + // + // compute Phi = (p - 1)(q - 1) = pq - p - q + 1 = n - p - q + 1 + phi = BN_dup(N); + ctx = BN_CTX_new(); + if (phi && ctx) { + pOK = BN_sub(phi, phi, P); + pOK = pOK && BN_sub(phi, phi, Q); + pOK = pOK && BN_add_word(phi, 1); + // Compute the multiplicative inverse d = 1/e mod Phi + BN_set_flags(phi, BN_FLG_CONSTTIME); // phi is secret + pOK = pOK && (*D = BN_mod_inverse(NULL, E, phi, ctx)) != NULL; + } + BN_CTX_free(ctx); + BN_clear_free(phi); + + return pOK; +} + +LIB_EXPORT TPM_RC +InitOpenSSLRSAPublicKey(OBJECT *key, // IN + EVP_PKEY **pkey // OUT + ) +{ + TPM_RC retVal; + RSA *rsakey = RSA_new(); + BIGNUM *N = NULL; + BIGNUM *E = BN_new(); + BN_ULONG eval; + + *pkey = EVP_PKEY_new(); + + if (rsakey == NULL || *pkey == NULL || E == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + if(key->publicArea.parameters.rsaDetail.exponent != 0) + eval = key->publicArea.parameters.rsaDetail.exponent; + else + eval = RSA_DEFAULT_PUBLIC_EXPONENT; + + if (BN_set_word(E, eval) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + N = BN_bin2bn(key->publicArea.unique.rsa.b.buffer, + key->publicArea.unique.rsa.b.size, NULL); + if (N == NULL || + RSA_set0_key(rsakey, N, E, NULL) != 1 || + EVP_PKEY_assign_RSA(*pkey, rsakey) == 0) + ERROR_RETURN(TPM_RC_FAILURE) + + RSA_set_flags(rsakey, RSA_FLAG_NO_BLINDING); + + retVal = TPM_RC_SUCCESS; + + Exit: + if (retVal != TPM_RC_SUCCESS) { + RSA_free(rsakey); + EVP_PKEY_free(*pkey); + *pkey = NULL; + } + + return retVal; +} + +static void DoRSACheckKey(const BIGNUM *P, const BIGNUM *Q, const BIGNUM *N, + const BIGNUM *E, const BIGNUM *D) +{ + RSA *mykey; + static int disp; + + if (!DO_RSA_CHECK_KEY) + return; + if (!disp) { + fprintf(stderr, "RSA key checking is enabled\n"); + disp = 1; + } + + mykey = RSA_new(); + RSA_set0_factors(mykey, BN_dup(P), BN_dup(Q)); + RSA_set0_key(mykey, BN_dup(N), BN_dup(E), BN_dup(D)); + if (RSA_check_key(mykey) != 1) { + fprintf(stderr, "Detected bad RSA key. STOP.\n"); + while (1); + } + RSA_free(mykey); +} + +LIB_EXPORT TPM_RC +InitOpenSSLRSAPrivateKey(OBJECT *rsaKey, // IN + EVP_PKEY **pkey // OUT + ) +{ + const BIGNUM *N = NULL; + const BIGNUM *E = NULL; + BIGNUM *P = NULL; + BIGNUM *Q = NULL; + BIGNUM *Qr = NULL; + BIGNUM *D = NULL; +#if CRT_FORMAT_RSA == YES + BIGNUM *dP = BN_new(); + BIGNUM *dQ = BN_new(); + BIGNUM *qInv = BN_new(); +#endif + RSA *key = NULL; + BN_CTX *ctx = NULL; + TPM_RC retVal = InitOpenSSLRSAPublicKey(rsaKey, pkey); + + if (retVal != TPM_RC_SUCCESS) + return retVal; + + if(!rsaKey->attributes.privateExp) + CryptRsaLoadPrivateExponent(rsaKey); + + P = BN_bin2bn(rsaKey->sensitive.sensitive.rsa.t.buffer, + rsaKey->sensitive.sensitive.rsa.t.size, NULL); + if (P == NULL) + ERROR_RETURN(TPM_RC_FAILURE) + + key = EVP_PKEY_get1_RSA(*pkey); + if (key == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + RSA_get0_key(key, &N, &E, NULL); + + D = ExpDCacheFind(P, N, E, &Q); + if (D == NULL) { + ctx = BN_CTX_new(); + Q = BN_new(); + Qr = BN_new(); + if (ctx == NULL || Q == NULL || Qr == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + /* Q = N/P; no remainder */ + BN_set_flags(P, BN_FLG_CONSTTIME); // P is secret + BN_div(Q, Qr, N, P, ctx); + if(!BN_is_zero(Qr)) + ERROR_RETURN(TPM_RC_BINDING); + BN_set_flags(Q, BN_FLG_CONSTTIME); // Q is secret + + if (ComputePrivateExponentD(P, Q, E, N, &D) == FALSE) + ERROR_RETURN(TPM_RC_FAILURE); + ExpDCacheAdd(P, N, E, Q, D); + } + if (RSA_set0_key(key, NULL, NULL, D) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + DoRSACheckKey(P, Q, N, E, D); + + D = NULL; + +#if CRT_FORMAT_RSA == YES + /* CRT parameters are not absolutely needed but may speed up ops */ + dP = BigInitialized(dP, (bigConst)&rsaKey->privateExponent.dP); + dQ = BigInitialized(dQ, (bigConst)&rsaKey->privateExponent.dQ); + qInv = BigInitialized(qInv, (bigConst)&rsaKey->privateExponent.qInv); + if (dP == NULL || dQ == NULL || qInv == NULL || + RSA_set0_crt_params(key, dP, dQ, qInv) != 1) + ERROR_RETURN(TPM_RC_FAILURE); +#endif + + retVal = TPM_RC_SUCCESS; + + Exit: + BN_CTX_free(ctx); + BN_clear_free(P); + BN_clear_free(Q); + BN_free(Qr); + RSA_free(key); // undo reference from EVP_PKEY_get1_RSA() + + if (retVal != TPM_RC_SUCCESS) { + BN_clear_free(D); +#if CRT_FORMAT_RSA == YES + BN_clear_free(dP); + BN_clear_free(dQ); + BN_clear_free(qInv); +#endif + EVP_PKEY_free(*pkey); + *pkey = NULL; + } + + return retVal; +} + +LIB_EXPORT TPM_RC +OpenSSLCryptRsaGenerateKey( + OBJECT *rsaKey, // IN/OUT: The object structure in which + // the key is created. + UINT32 e, + int keySizeInBits + ) +{ + TPMT_PUBLIC *publicArea = &rsaKey->publicArea; + TPMT_SENSITIVE *sensitive = &rsaKey->sensitive; + TPM_RC retVal = TPM_RC_SUCCESS; + int rc; + RSA *rsa = NULL; + const BIGNUM *bnP = NULL; + const BIGNUM *bnN = NULL; + BIGNUM *bnE = BN_new(); + BN_RSA(tmp); + + if (bnE == NULL || BN_set_word(bnE, e) != 1) + ERROR_RETURN(TPM_RC_FAILURE); + + // Need to initialize the privateExponent structure + RsaInitializeExponent(&rsaKey->privateExponent); + + rsa = RSA_new(); + if (rsa == NULL) + ERROR_RETURN(TPM_RC_FAILURE); + + rc = RSA_generate_key_ex(rsa, keySizeInBits, bnE, NULL); + if (rc == 0) + ERROR_RETURN(TPM_RC_NO_RESULT); + + RSA_get0_key(rsa, &bnN, NULL, NULL); + RSA_get0_factors(rsa, &bnP, NULL); + + OsslToTpmBn(tmp, bnN); + BnTo2B((bigNum)tmp, &publicArea->unique.rsa.b, 0); + + OsslToTpmBn(tmp, bnP); + BnTo2B((bigNum)tmp, &sensitive->sensitive.rsa.b, 0); + + // CryptRsaGenerateKey calls ComputePrivateExponent; we have to call + // it via CryptRsaLoadPrivateExponent + retVal = CryptRsaLoadPrivateExponent(rsaKey); + + Exit: + BN_free(bnE); + RSA_free(rsa); + + return retVal; +} + +#endif // USE_OPENSSL_FUNCTIONS_RSA diff --git a/src/tpm2/crypto/openssl/Helpers_fp.h b/src/tpm2/crypto/openssl/Helpers_fp.h new file mode 100644 index 0000000..5b9ca14 --- /dev/null +++ b/src/tpm2/crypto/openssl/Helpers_fp.h @@ -0,0 +1,117 @@ +/********************************************************************************/ +/* */ +/* OpenSSL helper functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2019 */ +/* */ +/********************************************************************************/ + +#ifndef HELPERS_FP_H +#define HELPERS_FP_H + +#include "TpmTypes.h" + +#include <openssl/evp.h> + +#if USE_OPENSSL_FUNCTIONS_SYMMETRIC +TPM_RC +OpenSSLCryptGenerateKeyDes( + TPMT_SENSITIVE *sensitive // OUT: sensitive area + ); + +typedef const EVP_CIPHER *(*evpfunc)(void); + +evpfunc GetEVPCipher(TPM_ALG_ID algorithm, // IN + UINT16 keySizeInBits, // IN + TPM_ALG_ID mode, // IN + const BYTE *key, // IN + BYTE *keyToUse, // OUT same as key or stretched key + UINT16 *keyToUseLen // IN/OUT + ); +#endif + +#if USE_OPENSSL_FUNCTIONS_EC +BOOL OpenSSLEccGetPrivate( + bigNum dOut, // OUT: the qualified random value + const EC_GROUP *G, // IN: the EC_GROUP to use + const UINT32 requestedBits // IN: if not 0, then dOut must have that many bits + ); +#endif + +#if USE_OPENSSL_FUNCTIONS_RSA + +const char *GetDigestNameByHashAlg(const TPM_ALG_ID hashAlg); + +LIB_EXPORT TPM_RC +OpenSSLCryptRsaGenerateKey( + OBJECT *rsaKey, // IN/OUT: The object structure in which + // the key is created. + UINT32 e, + int keySizeInBits + ); + +LIB_EXPORT TPM_RC +InitOpenSSLRSAPublicKey(OBJECT *key, // IN + EVP_PKEY **pkey //OUT + ); + +LIB_EXPORT TPM_RC +InitOpenSSLRSAPrivateKey(OBJECT *rsaKey, // IN + EVP_PKEY **pkey // OUT + ); + +#endif // USE_OPENSSL_FUNCTIONS_RSA + +#endif /* HELPERS_FP_H */ diff --git a/src/tpm2/crypto/openssl/LibSupport.h b/src/tpm2/crypto/openssl/LibSupport.h new file mode 100644 index 0000000..d571b84 --- /dev/null +++ b/src/tpm2/crypto/openssl/LibSupport.h @@ -0,0 +1,98 @@ +/********************************************************************************/ +/* */ +/* select the library code that gets included in the TPM build */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: LibSupport.h 1656 2021-01-15 21:45:18Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +// 5.12 LibSupport.h +// This header file is used to select the library code that gets included in the TPM build +#ifndef _LIB_SUPPORT_H_ +#define _LIB_SUPPORT_H_ + +#if 0 // libtpms added +/* kgold added power and s390 */ +#ifndef RADIX_BITS +# if defined(__x86_64__) || defined(__x86_64) \ + || defined(__amd64__) || defined(__amd64) \ + || defined(_WIN64) || defined(_M_X64) \ + || defined(_M_ARM64) || defined(__aarch64__) \ + || defined(__powerpc64__) || defined(__PPC64__) || defined(__ppc64__) \ + || defined(__s390x__) +# define RADIX_BITS 64 +# elif defined(__i386__) || defined(__i386) || defined(i386) \ + || defined(_WIN32) || defined(_M_IX86) \ + || defined(_M_ARM) || defined(__arm__) || defined(__thumb__) \ + || defined(__powerpc__) || defined(__PPC__) +# define RADIX_BITS 32 +# else +# error Unable to determine RADIX_BITS from compiler environment +# endif +#endif // RADIX_BITS +#endif // libtpms added + +// These macros use the selected libraries to the proper include files. +#define LIB_QUOTE(_STRING_) #_STRING_ +#define LIB_INCLUDE2(_LIB_, _TYPE_) LIB_QUOTE(TpmTo##_LIB_##_TYPE_.h) +#define LIB_INCLUDE(_LIB_, _TYPE_) LIB_INCLUDE2(_LIB_, _TYPE_) +// Include the options for hashing and symmetric. Defer the load of the math package until the +// bignum parameters are defined. +#include LIB_INCLUDE(SYM_LIB, Sym) +#include LIB_INCLUDE(HASH_LIB, Hash) +#undef MIN +#undef MAX +#endif // _LIB_SUPPORT_H_ diff --git a/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c b/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c new file mode 100644 index 0000000..d27aad2 --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslDesSupport.c @@ -0,0 +1,119 @@ +/********************************************************************************/ +/* */ +/* TPM DES Support */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslDesSupport.c 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +/* B.2.3.1. TpmToOsslDesSupport.c */ +/* B.2.3.1.1. Introduction */ +/* The functions in this file are used for initialization of the interface to the OpenSSL + library. */ +/* B.2.3.1.2. Defines and Includes */ +#include "Tpm.h" +#if (defined SYM_LIB_OSSL) && ALG_TDES +/* B.2.3.1.3. Functions */ +/* B.2.3.1.3.1. TDES_set_encyrpt_key() */ +/* This function makes creation of a TDES key look like the creation of a key for any of the other + OpenSSL block ciphers. It will create three key schedules, one for each of the DES keys. If + there are only two keys, then the third schedule is a copy of the first. */ +void +TDES_set_encrypt_key( + const BYTE *key, + UINT16 keySizeInBits, + tpmKeyScheduleTDES *keySchedule + ) +{ + DES_set_key_unchecked((const_DES_cblock *)key, &keySchedule[0]); + DES_set_key_unchecked((const_DES_cblock *)&key[8], &keySchedule[1]); + // If is two-key, copy the schedule for K1 into K3, otherwise, compute the + // the schedule for K3 + if(keySizeInBits == 128) + keySchedule[2] = keySchedule[0]; + else + DES_set_key_unchecked((const_DES_cblock *)&key[16], + &keySchedule[2]); +} +/* B.2.3.1.3.2. TDES_encyrpt() */ +/* The TPM code uses one key schedule. For TDES, the schedule contains three schedules. OpenSSL + wants the schedules referenced separately. This function does that. */ +void TDES_encrypt( + const BYTE *in, + BYTE *out, + tpmKeyScheduleTDES *ks + ) +{ + DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock *)out, + &ks[0], &ks[1], &ks[2], + DES_ENCRYPT); +} +#if !USE_OPENSSL_FUNCTIONS_SYMMETRIC +/* B.2.3.1.3.3. TDES_decrypt() */ +/* As with TDES_encypt() this function bridges between the TPM single schedule model and the + OpenSSL three schedule model. */ +void TDES_decrypt( + const BYTE *in, + BYTE *out, + tpmKeyScheduleTDES *ks + ) +{ + DES_ecb3_encrypt((const_DES_cblock *)in, (DES_cblock *)out, + &ks[0], &ks[1], &ks[2], + DES_DECRYPT); +} +#endif // !USE_OPENSSL_FUNCTIONS_SYMMETRIC +#endif // SYM_LIB_OSSL diff --git a/src/tpm2/crypto/openssl/TpmToOsslDesSupport_fp.h b/src/tpm2/crypto/openssl/TpmToOsslDesSupport_fp.h new file mode 100644 index 0000000..4338fe6 --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslDesSupport_fp.h @@ -0,0 +1,83 @@ +/********************************************************************************/ +/* */ +/* */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslDesSupport_fp.h 809 2016-11-16 18:31:54Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 */ +/* */ +/********************************************************************************/ + +#ifndef TPMTOOSSLDESSUPPORT_FP_H +#define TPMTOOSSLDESSUPPORT_FP_H + +void +TDES_set_encrypt_key( + const BYTE *key, + UINT16 keySizeInBits, + tpmKeyScheduleTDES *keySchedule + ); +void TDES_encrypt( + const BYTE *in, + BYTE *out, + tpmKeyScheduleTDES *ks + ); +void TDES_decrypt( + const BYTE *in, + BYTE *out, + tpmKeyScheduleTDES *ks + ); + + +#endif diff --git a/src/tpm2/crypto/openssl/TpmToOsslHash.h b/src/tpm2/crypto/openssl/TpmToOsslHash.h new file mode 100644 index 0000000..9fa6479 --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslHash.h @@ -0,0 +1,219 @@ +/********************************************************************************/ +/* */ +/* Used to splice the OpenSSL() hash code into the TPM code */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslHash.h 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* B.2.2.1. TpmToOsslHash.h */ +/* B.2.2.1.1. Introduction */ +/* This header file is used to splice the OpenSSL hash code into the TPM code. */ +#ifndef HASH_LIB_DEFINED +#define HASH_LIB_DEFINED +#define HASH_LIB_OSSL +#include <openssl/evp.h> +#include <openssl/sha.h> + +#if ALG_SM3_256 +# if defined(OPENSSL_NO_SM3) || OPENSSL_VERSION_NUMBER < 0x10101010L +# if ALG_SM3_256 // libtpms added begin +# error This version of OpenSSL does not support SM3 +# endif // libtpms added end +# undef ALG_SM3_256 +# define ALG_SM3_256 ALG_NO +# elif OPENSSL_VERSION_NUMBER >= 0x10200000L +# include <openssl/sm3.h> +# else +// OpenSSL 1.1.1 keeps smX.h headers in the include/crypto directory, +// and they do not get installed as part of the libssl package +# define SM3_LBLOCK (64/4) + +# error Check support for this version of SM3 in OpenSSL (libtpms) +typedef struct SM3state_st { + unsigned int A, B, C, D, E, F, G, H; + unsigned int Nl, Nh; + unsigned int data[SM3_LBLOCK]; + unsigned int num; +} SM3_CTX; + +int sm3_init(SM3_CTX *c); +int sm3_update(SM3_CTX *c, const void *data, size_t len); +int sm3_final(unsigned char *md, SM3_CTX *c); +# endif // OpenSSL < 1.2 +#endif // ALG_SM3_256 + +#include <openssl/ossl_typ.h> + +#define HASH_ALIGNMENT RADIX_BYTES /* libtpms: keep; not sure whether needed */ + +/* B.2.2.1.2. 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 +#if ALG_SM3_256 +# error "The version of OpenSSL used by this code does not support SM3" +#endif +/* 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 BYTE *PBYTE; +typedef const BYTE *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. */ + +#define HASH_ALIGNMENT RADIX_BYTES + +/* Initialize the hash context */ +#define HASH_START_METHOD_DEF void (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 \ + void (HASH_DATA_METHOD)(PANY_HASH_STATE state, \ + PCBYTE buffer, \ + size_t 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 \ + void (HASH_END_METHOD)(BYTE *buffer, PANY_HASH_STATE state) +#define HASH_END(hashState, buffer) \ + ((hashState)->def->method.end)(buffer, &(hashState)->state) +/* 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 format (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 SHA1_Init // external name of the initialization method +#define tpmHashData_SHA1 SHA1_Update +#define tpmHashEnd_SHA1 SHA1_Final +#define tpmHashStateCopy_SHA1 memcpy +#define tpmHashStateExport_SHA1 memcpy +#define tpmHashStateImport_SHA1 memcpy +#define tpmHashStart_SHA256 SHA256_Init +#define tpmHashData_SHA256 SHA256_Update +#define tpmHashEnd_SHA256 SHA256_Final +#define tpmHashStateCopy_SHA256 memcpy +#define tpmHashStateExport_SHA256 memcpy +#define tpmHashStateImport_SHA256 memcpy +#define tpmHashStart_SHA384 SHA384_Init +#define tpmHashData_SHA384 SHA384_Update +#define tpmHashEnd_SHA384 SHA384_Final +#define tpmHashStateCopy_SHA384 memcpy +#define tpmHashStateExport_SHA384 memcpy +#define tpmHashStateImport_SHA384 memcpy +#define tpmHashStart_SHA512 SHA512_Init +#define tpmHashData_SHA512 SHA512_Update +#define tpmHashEnd_SHA512 SHA512_Final +#define tpmHashStateCopy_SHA512 memcpy +#define tpmHashStateExport_SHA512 memcpy +#define tpmHashStateImport_SHA512 memcpy +#define tpmHashStart_SM3_256 sm3_init +#define tpmHashData_SM3_256 sm3_update +#define tpmHashEnd_SM3_256 sm3_final +#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() +#endif // // HASH_LIB_DEFINED + + diff --git a/src/tpm2/crypto/openssl/TpmToOsslMath.c b/src/tpm2/crypto/openssl/TpmToOsslMath.c new file mode 100644 index 0000000..18e6c23 --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslMath.c @@ -0,0 +1,736 @@ +/********************************************************************************/ +/* */ +/* TPM to OpenSSL BigNum Shim Layer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslMath.c 1598 2020-03-27 21:59:49Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +/* B.2.3.2. TpmToOsslMath.c */ +/* B.2.3.2.1. Introduction */ + +/* The functions in this file provide the low-level interface between the TPM code and the big + number and elliptic curve math routines in OpenSSL. */ +/* Most math on big numbers require a context. The context contains the memory in which OpenSSL + creates and manages the big number values. When a OpenSSL math function will be called that + modifies a BIGNUM value, that value must be created in an OpenSSL context. The first line of code + in such a function must be: OSSL_ENTER(); and the last operation before returning must be + OSSL_LEAVE(). OpenSSL variables can then be created with BnNewVariable(). Constant values to be + used by OpenSSL are created from the bigNum values passed to the functions in this file. Space + for the BIGNUM control block is allocated in the stack of the function and then it is initialized + by calling BigInitialized(). That function sets up the values in the BIGNUM structure and sets + the data pointer to point to the data in the bignum_t. This is only used when the value is known + to be a constant in the called function. */ +/* Because the allocations of constants is on the local stack and the OSSL_ENTER()/OSSL_LEAVE() pair + flushes everything created in OpenSSL memory, there should be no chance of a memory leak. */ + + +#include "Tpm.h" +#ifdef MATH_LIB_OSSL +#include "TpmToOsslMath_fp.h" + +/* B.2.3.2.3.1. 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 Value Meaning */ +/* TRUE(1) success */ +/* FALSE(0) failure because value will not fit or OpenSSL variable doesn't exist */ +BOOL +OsslToTpmBn( + bigNum bn, + const BIGNUM *osslBn // libtpms: added 'const' + ) +{ + VERIFY(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. + unsigned char buffer[LARGEST_NUMBER + 1]; // libtpms added + int buffer_len; // libtpms added + + if(bn != NULL) + { +#if 1 //libtpms added begin + int num_bytes; + + num_bytes = BN_num_bytes(osslBn); + VERIFY(num_bytes >= 0 && sizeof(buffer) >= (size_t)num_bytes); + buffer_len = BN_bn2bin(osslBn, buffer); /* ossl to bin */ + BnFromBytes(bn, buffer, buffer_len); /* bin to TPM */ +#else // libtpms added end + int i; + // + VERIFY((unsigned)osslBn->top <= BnGetAllocated(bn)); + for(i = 0; i < osslBn->top; i++) + bn->d[i] = osslBn->d[i]; + BnSetTop(bn, osslBn->top); +#endif // libtpms added + } + return TRUE; + Error: + return FALSE; +} + +/* B.2.3.2.3.2. 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 1 // libtpms added begin + BIGNUM *_toInit; + unsigned char buffer[LARGEST_NUMBER + 1]; + NUMBYTES buffer_len = (NUMBYTES )sizeof(buffer); +#endif // libtpms added end + + if(initializer == NULL) + FAIL(FATAL_ERROR_PARAMETER); + if(toInit == NULL || initializer == NULL) + return NULL; + +#if 1 // libtpms added begin + BnToBytes(initializer, buffer, &buffer_len); /* TPM to bin */ + _toInit = BN_bin2bn(buffer, buffer_len, NULL); /* bin to ossl */ + BN_set_flags(_toInit, BN_FLG_CONSTTIME); + BN_copy(toInit, _toInit); + BN_clear_free(_toInit); +#else // libtpms added end + toInit->d = (BN_ULONG *)&initializer->d[0]; + toInit->dmax = (int)initializer->allocated; + toInit->top = (int)initializer->size; + toInit->neg = 0; + toInit->flags = 0; +#endif + return toInit; +} + +#ifndef OSSL_DEBUG +# define BIGNUM_PRINT(label, bn, eol) +# define DEBUG_PRINT(x) +#else +# define DEBUG_PRINT(x) printf("%s", x) +# define BIGNUM_PRINT(label, bn, eol) BIGNUM_print((label), (bn), (eol)) + +static +void BIGNUM_print( + const char *label, + const BIGNUM *a, + BOOL eol + ) +{ + BN_ULONG *d; + int i; + int notZero = FALSE; + if(label != NULL) + printf("%s", label); + if(a == NULL) + { + printf("NULL"); + goto done; + } + if (a->neg) + printf("-"); + 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) + printf("%02x", b); + } + if(!notZero) + printf("0"); + } + done: + if(eol) + printf("\n"); + return; +} +#endif + +/* B.2.3.2.3.4. 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 = BN_CTX_get(CTX)) == NULL)) + FAIL(FATAL_ERROR_ALLOCATION); + return new; +} + +#if LIBRARY_COMPATIBILITY_CHECK + +BOOL +MathLibraryCompatibilityCheck( + void + ) +{ + OSSL_ENTER(); + BIGNUM *osslTemp = BnNewVariable(CTX); +#if 0 + crypt_uword_t i; +#endif + 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 + BN_bin2bn(test, sizeof(test), osslTemp); + // Make sure the values are consistent +#if 0 + VERIFY(osslTemp->top == (int)tpmTemp->size); + for(i = 0; i < tpmTemp->size; i++) + VERIFY(osslTemp->d[i] == tpmTemp->d[i]); +#endif + OSSL_LEAVE(); + return 1; +#if 0 + Error: + return 0; +#endif +} + +#endif + +/* B.2.3.2.3.3. BnModMult() */ +/* Does multiply and divide returning the remainder of the divide. */ +/* Return Value Meaning */ +/* TRUE(1) success */ +/* FALSE(0) failure in operation */ + +LIB_EXPORT BOOL +BnModMult( + bigNum result, + bigConst op1, + bigConst op2, + bigConst modulus + ) +{ + OSSL_ENTER(); + BOOL OK = TRUE; + BIGNUM *bnResult = BN_NEW(); + BIGNUM *bnTemp = BN_NEW(); + BIG_INITIALIZED(bnOp1, op1); + BIG_INITIALIZED(bnOp2, op2); + BIG_INITIALIZED(bnMod, modulus); + // + VERIFY(BN_mul(bnTemp, bnOp1, bnOp2, CTX)); + VERIFY(BN_div(NULL, bnResult, bnTemp, bnMod, CTX)); + VERIFY(OsslToTpmBn(result, bnResult)); + goto Exit; + Error: + OK = FALSE; + Exit: + BN_clear_free(bnMod); // libtpms added + BN_clear_free(bnOp2); // libtpms added + BN_clear_free(bnOp1); // libtpms added + OSSL_LEAVE(); + return OK; +} + +/* B.2.3.2.3.4. BnMult() */ +/* Multiplies two numbers */ +/* Return Value Meaning */ +/* TRUE(1) success */ +/* FALSE(0) failure in operation */ + +LIB_EXPORT BOOL +BnMult( + bigNum result, + bigConst multiplicand, + bigConst multiplier + ) +{ + OSSL_ENTER(); + BIGNUM *bnTemp = BN_NEW(); + BOOL OK = TRUE; + BIG_INITIALIZED(bnA, multiplicand); + BIG_INITIALIZED(bnB, multiplier); + // + VERIFY(BN_mul(bnTemp, bnA, bnB, CTX)); + VERIFY(OsslToTpmBn(result, bnTemp)); + goto Exit; + Error: + OK = FALSE; + Exit: + BN_clear_free(bnB); // libtpms added + BN_clear_free(bnA); // libtpms added + OSSL_LEAVE(); + return OK; +} + +/* B.2.3.2.3.5. BnDiv() */ +/* This function divides two bigNum values. The function returns FALSE if there is an error in the + operation. */ +/* Return Value Meaning */ +/* 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 = TRUE; + BIG_INITIALIZED(bnDend, dividend); + BIG_INITIALIZED(bnSor, divisor); + // + if(BnEqualZero(divisor)) + FAIL(FATAL_ERROR_DIVIDE_ZERO); + VERIFY(BN_div(bnQ, bnR, bnDend, bnSor, CTX)); + VERIFY(OsslToTpmBn(quotient, bnQ)); + VERIFY(OsslToTpmBn(remainder, bnR)); + 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); + goto Exit; + Error: + OK = FALSE; + Exit: + BN_clear_free(bnSor); // libtpms added + BN_clear_free(bnDend); // libtpms added + OSSL_LEAVE(); + return OK; +} + +#if ALG_RSA +#if !RSA_KEY_SIEVE // libtpms added +/* B.2.3.2.3.6. BnGcd() */ +/* Get the greatest common divisor of two numbers */ +/* Return Value Meaning */ +/* 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 = TRUE; + BIG_INITIALIZED(bn1, number1); + BIG_INITIALIZED(bn2, number2); + // + BN_set_flags(bn1, BN_FLG_CONSTTIME); // number1 is secret prime number + VERIFY(BN_gcd(bnGcd, bn1, bn2, CTX)); + VERIFY(OsslToTpmBn(gcd, bnGcd)); + goto Exit; + Error: + OK = FALSE; + Exit: + BN_clear_free(bn2); // libtpms added + BN_clear_free(bn1); // libtpms added + OSSL_LEAVE(); + return OK; +} +#endif // libtpms added + +/* B.2.3.2.3.7. 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 Value Meaning */ +/* 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 = TRUE; + BIG_INITIALIZED(bnN, number); + BIG_INITIALIZED(bnE, exponent); + BIG_INITIALIZED(bnM, modulus); + // + BN_set_flags(bnE, BN_FLG_CONSTTIME); // exponent may be private + VERIFY(BN_mod_exp(bnResult, bnN, bnE, bnM, CTX)); + VERIFY(OsslToTpmBn(result, bnResult)); + goto Exit; + Error: + OK = FALSE; + Exit: + BN_clear_free(bnM); // libtpms added + BN_clear_free(bnE); // libtpms added + BN_clear_free(bnN); // libtpms added + OSSL_LEAVE(); + return OK; +} + +/* B.2.3.2.3.8. BnModInverse() */ +/* Modular multiplicative inverse */ +/* Return Value Meaning */ +/* 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 = TRUE; + BIG_INITIALIZED(bnN, number); + BIG_INITIALIZED(bnM, modulus); + // + BN_set_flags(bnN, BN_FLG_CONSTTIME); // number may be private + VERIFY(BN_mod_inverse(bnResult, bnN, bnM, CTX) != NULL); + VERIFY(OsslToTpmBn(result, bnResult)); + goto Exit; + Error: + OK = FALSE; + Exit: + BN_clear_free(bnM); // libtpms added + BN_clear_free(bnN); // libtpms added + OSSL_LEAVE(); + return OK; +} + +#endif // TPM_ALG_RSA + +#if ALG_ECC + +/* B.2.3.2.3.9. PointFromOssl() */ +/* Function to copy the point result from an OSSL function to a bigNum */ +/* Return Value Meaning */ +/* TRUE(1) success */ +/* FALSE(0) failure in operation */ +static BOOL +PointFromOssl( + bigPoint pOut, // OUT: resulting point + EC_POINT *pIn, // IN: the point to return + bigCurve E // IN: the curve + ) +{ + BIGNUM *x = NULL; + BIGNUM *y = NULL; + BOOL OK; + BN_CTX_start(E->CTX); + // + x = BN_CTX_get(E->CTX); + y = BN_CTX_get(E->CTX); + if(y == NULL) + FAIL(FATAL_ERROR_ALLOCATION); + // If this returns false, then the point is at infinity +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER) // libtpms added begin + OK = EC_POINT_get_affine_coordinates(E->G, pIn, x, y, E->CTX); +#else // libtpms added begin + OK = EC_POINT_get_affine_coordinates_GFp(E->G, pIn, x, y, E->CTX); +#endif // libtpms added end + if(OK) + { + OsslToTpmBn(pOut->x, x); + OsslToTpmBn(pOut->y, y); + BnSetWord(pOut->z, 1); + } + else + BnSetWord(pOut->z, 0); + BN_CTX_end(E->CTX); + return OK; +} +/* B.2.3.2.3.10. EcPointInitialized() */ +/* Allocate and initialize a point. */ + +LIB_EXPORT EC_POINT * // libtpms: exported function +EcPointInitialized( + pointConst initializer, + bigCurve 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 = EC_POINT_new(E->G); +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER) // libtpms added begin + if(!EC_POINT_set_affine_coordinates(E->G, P, bnX, bnY, E->CTX)) +#else // libtpms added end + if(!EC_POINT_set_affine_coordinates_GFp(E->G, P, bnX, bnY, E->CTX)) +#endif // libtpms added + P = NULL; + BN_clear_free(bnX); // libtpms added + BN_clear_free(bnY); // libtpms added + } + return P; +} + +/* B.2.3.2.3.11. BnCurveInitialize() */ +/* This function initializes the OpenSSL group definition */ +/* It is a fatal error if groupContext is not provided. */ +/* Return Values Meaning */ +/* NULL the TPM_ECC_CURVE is not valid */ +/* non-NULL points to a structure in groupContext */ + +LIB_EXPORT bigCurve +BnCurveInitialize( + bigCurve E, // IN: curve structure to initialize + TPM_ECC_CURVE curveId // IN: curve identifier + ) +{ + const ECC_CURVE_DATA *C = GetCurveData(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 = EC_GROUP_new_curve_GFp(bnP, bnA, bnB, CTX); + VERIFY(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 = EC_POINT_new(E->G); + VERIFY(P != NULL); + + // Need to use this in case Montgomery method is being used +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER) // libtpms added begin + VERIFY(EC_POINT_set_affine_coordinates(E->G, P, bnX, bnY, CTX)); +#else // libtpms added end + VERIFY(EC_POINT_set_affine_coordinates_GFp(E->G, P, bnX, bnY, CTX)); +#endif // libtpms added + // Now set the generator + VERIFY(EC_GROUP_set_generator(E->G, P, bnN, bnH)); + + EC_POINT_free(P); + goto Exit_free; // libtpms changed + Error: + EC_POINT_free(P); + BnCurveFree(E); + E = NULL; + + Exit_free: // libtpms added begin + BN_clear_free(bnH); + BN_clear_free(bnN); + BN_clear_free(bnY); + BN_clear_free(bnX); + BN_clear_free(bnB); + BN_clear_free(bnA); + BN_clear_free(bnP); // libtpms added end + } +// Exit: + return E; +} + +/* B.2.3.2.3.15. 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( + bigCurve E + ) +{ + if(E) + { + EC_GROUP_free(E->G); + OsslContextLeave(E->CTX); + } +} + +/* B.2.3.2.3.11. BnEccModMult() */ +/* This functi2n does a point multiply of the form R = [d]S */ +/* Return Values Meaning */ +/* FALSE 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 + bigCurve E + ) +{ + EC_POINT *pR = EC_POINT_new(E->G); + EC_POINT *pS = EcPointInitialized(S, E); + BIG_INITIALIZED(bnD, d); + + if(S == NULL) + EC_POINT_mul(E->G, pR, bnD, NULL, NULL, E->CTX); + else + EC_POINT_mul(E->G, pR, NULL, pS, bnD, E->CTX); + PointFromOssl(R, pR, E); + EC_POINT_clear_free(pR); // libtpms changed + EC_POINT_clear_free(pS); // libtpms changed + BN_clear_free(bnD); // libtpms added + return !BnEqualZero(R->z); +} + +/* B.2.3.2.3.13. BnEccModMult2() */ +/* This function does a point multiply of the form R = [d]G + [u]Q */ +/* FALSE 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 + bigCurve E // IN: curve + ) +{ + EC_POINT *pR = EC_POINT_new(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)&(AccessCurveData(E)->base)) + EC_POINT_mul(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; + EC_POINTs_mul(E->G, pR, NULL, 2, points, scalars, E->CTX); + } + PointFromOssl(R, pR, E); + EC_POINT_clear_free(pR); // libtpms changed + EC_POINT_clear_free(pS); // libtpms changed + EC_POINT_clear_free(pQ); // libtpms changed + BN_clear_free(bnD); // libtpms added + BN_clear_free(bnU); // libtpms added + + return !BnEqualZero(R->z); +} + +/* B.2.3.2.4. BnEccAdd() */ +/* This function does addition of two points. */ +/* Return Values Meaning */ +/* FALSE failure in operation; treat as result being point at infinity */ +LIB_EXPORT BOOL +BnEccAdd( + bigPoint R, // OUT: computed point + pointConst S, // IN: point to multiply by 'd' + pointConst Q, // IN: second point + bigCurve E // IN: curve + ) +{ + EC_POINT *pR = EC_POINT_new(E->G); + EC_POINT *pS = EcPointInitialized(S, E); + EC_POINT *pQ = EcPointInitialized(Q, E); + // + EC_POINT_add(E->G, pR, pS, pQ, E->CTX); + PointFromOssl(R, pR, E); + EC_POINT_clear_free(pR); // libtpms changed + EC_POINT_clear_free(pS); // libtpms changed + EC_POINT_clear_free(pQ); // libtpms changed + return !BnEqualZero(R->z); +} + +#endif // ALG_ECC +#endif // MATH_LIB_OSSL diff --git a/src/tpm2/crypto/openssl/TpmToOsslMath.h b/src/tpm2/crypto/openssl/TpmToOsslMath.h new file mode 100644 index 0000000..47333c7 --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslMath.h @@ -0,0 +1,164 @@ +/********************************************************************************/ +/* */ +/* TPM to OpenSSL BigNum Shim Layer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslMath.h 1658 2021-01-22 23:14:01Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2021 */ +/* */ +/********************************************************************************/ + +/* B.2.2.1. TpmToOsslMath.h */ +/* B.2.2.1.1. Introduction */ +/* This file contains the structure definitions used for ECC in the OpenSSL version of the + code. These definitions would change, based on the library. The ECC-related structures that cross + the TPM interface are defined in TpmTypes.h */ + +#ifndef MATH_LIB_DEFINED +#define MATH_LIB_DEFINED +#define MATH_LIB_OSSL +#include <openssl/evp.h> +#include <openssl/ec.h> + +#define SYMMETRIC_ALIGNMENT RADIX_BYTES + +#if 0 // libtpms added +#if OPENSSL_VERSION_NUMBER >= 0x10200000L +// Check the bignum_st definition in crypto/bn/bn_lcl.h and either update the +// version check or provide the new definition for this version. +# error Untested OpenSSL version +#elif OPENSSL_VERSION_NUMBER >= 0x10100000L +// from crypto/bn/bn_lcl.h +struct bignum_st { + BN_ULONG *d; + int top; + + int dmax; + int neg; + int flags; +}; +#if 0 // libtpms added +# define EC_POINT_get_affine_coordinates EC_POINT_get_affine_coordinates_GFp +# define EC_POINT_set_affine_coordinates EC_POINT_set_affine_coordinates_GFp +#endif // libtpms added +#endif // OPENSSL_VERSION_NUMBER +#endif // libtpms added + +#include <openssl/bn.h> +#if USE_OPENSSL_FUNCTIONS_ECDSA // libtpms added begin +#include <openssl/ecdsa.h> +#endif // libtpms added end + +/* B.2.2.2.2. 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 = BN_new(); /* libtpms */ \ + BIGNUM *name = BigInitialized(_##name, /* libtpms */ \ + 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 = BN_new(); /* libtpms */ \ + BIGNUM *name = BigInitialized(_##name, initializer) /* libtpms */ + +typedef struct +{ + const ECC_CURVE_DATA *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; +typedef OSSL_CURVE_DATA *bigCurve; +#define AccessCurveData(E) ((E)->C) + +#include "TpmToOsslSupport_fp.h" + +#define OSSL_ENTER() BN_CTX *CTX = OsslContextEnter() +#define OSSL_LEAVE() OsslContextLeave(CTX) + +/* Start and end a context that spans multiple ECC functions. This is used so that the group for the + curve can persist across multiple frames. */ + +#define CURVE_INITIALIZED(name, initializer) \ + OSSL_CURVE_DATA _##name; \ + bigCurve name = BnCurveInitialize(&_##name, initializer) + +#define CURVE_FREE(name) BnCurveFree(name) + +/* Start and end a local stack frame within the context of the curve frame */ +#if 0 /* kgold not used */ +#define ECC_ENTER() BN_CTX *CTX = OsslPushContext(E->CTX) +#define ECC_LEAVE() OsslPopContext(CTX) +#endif +#define BN_NEW() BnNewVariable(CTX) + + +/* This definition would change if there were something to report */ +#define MathLibSimulationEnd() +#endif // MATH_LIB_DEFINED + + diff --git a/src/tpm2/crypto/openssl/TpmToOsslMath_fp.h b/src/tpm2/crypto/openssl/TpmToOsslMath_fp.h new file mode 100644 index 0000000..7c42e71 --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslMath_fp.h @@ -0,0 +1,152 @@ +/********************************************************************************/ +/* */ +/* TPM to OpenSSL BigNum Shim Layer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslMath_fp.h 1519 2019-11-15 20:43:51Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef TPMTOOSSLMATH_FP_H +#define TPMTOOSSLMATH_FP_H + +#include <openssl/bn.h> + +BOOL +OsslToTpmBn( + bigNum bn, + const BIGNUM *osslBn // libtpms added 'const' + ); +BIGNUM * +BigInitialized( + BIGNUM *toInit, + bigConst initializer + ); +// libtpms added begin +EC_POINT * +EcPointInitialized( + pointConst initializer, + bigCurve E + ); +// libtpms added end +LIB_EXPORT BOOL +BnModMult( + bigNum result, + bigConst op1, + bigConst op2, + bigConst modulus + ); +LIB_EXPORT BOOL +BnMult( + bigNum result, + bigConst multiplicand, + bigConst multiplier + ); +LIB_EXPORT BOOL +BnDiv( + bigNum quotient, + bigNum remainder, + bigConst dividend, + bigConst divisor + ); +LIB_EXPORT BOOL +BnGcd( + bigNum gcd, // OUT: the common divisor + bigConst number1, // IN: + bigConst number2 // IN: + ); +LIB_EXPORT BOOL +BnModExp( + bigNum result, // OUT: the result + bigConst number, // IN: number to exponentiate + bigConst exponent, // IN: + bigConst modulus // IN: + ); +LIB_EXPORT BOOL +BnModInverse( + bigNum result, + bigConst number, + bigConst modulus + ); +bigCurve +BnCurveInitialize( + bigCurve E, // IN: curve structure to initialize + TPM_ECC_CURVE curveId // IN: curve identifier + ); +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 + bigCurve E + ); +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 + bigCurve E // IN: curve + ); +LIB_EXPORT BOOL +BnEccAdd( + bigPoint R, // OUT: computed point + pointConst S, // IN: point to multiply by 'd' + pointConst Q, // IN: second point + bigCurve E // IN: curve + ); + +#endif diff --git a/src/tpm2/crypto/openssl/TpmToOsslSupport.c b/src/tpm2/crypto/openssl/TpmToOsslSupport.c new file mode 100644 index 0000000..921b02f --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslSupport.c @@ -0,0 +1,129 @@ +/********************************************************************************/ +/* */ +/* Initialization of the Interface to the OpenSSL Library. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslSupport.c 1519 2019-11-15 20:43:51Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +/* B.2.3.3. TpmToOsslSupport.c */ +/* B.2.3.3.1. Introduction */ +/* The functions in this file are used for initialization of the interface to the OpenSSL + library. */ +/* B.2.3.3.2. Defines and Includes */ +#include "Tpm.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]; +/* B.2.3.3.2.1. SupportLibInit() */ +/* This does any initialization required by the support library. */ +LIB_EXPORT int +SupportLibInit( + void + ) +{ + return TRUE; +} +/* B.2.3.3.2.2. 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 = BN_CTX_new(); + return OsslPushContext(CTX); +} +/* B.2.3.3.2.3. OsslContextLeave() */ +/* This is the companion function to OsslContextEnter(). */ +void +OsslContextLeave( + BN_CTX *CTX + ) +{ + OsslPopContext(CTX); + BN_CTX_free(CTX); +} + +/* B.2.3.3.2.4. 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); + BN_CTX_start(CTX); + return CTX; +} + +/* B.2.3.3.2.5. 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) + BN_CTX_end(CTX); +} + +#endif // HASH_LIB_OSSL || MATH_LIB_OSSL || SYM_LIB_OSSL diff --git a/src/tpm2/crypto/openssl/TpmToOsslSupport_fp.h b/src/tpm2/crypto/openssl/TpmToOsslSupport_fp.h new file mode 100644 index 0000000..c8d7b5a --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslSupport_fp.h @@ -0,0 +1,83 @@ +/********************************************************************************/ +/* */ +/* Initialization of the Interface to the OpenSSL Library */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslSupport_fp.h 1476 2019-06-10 19:32:03Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#ifndef TPMTOOSSLSUPPORT_FP_H +#define TPMTOOSSLSUPPORT_FP_H + +BN_CTX * +OsslContextEnter( + void + ); +void +OsslContextLeave( + BN_CTX *context + ); +BN_CTX * +OsslPushContext( + BN_CTX *CTX + ); +void +OsslPopContext( + BN_CTX *CTX + ); + + +#endif diff --git a/src/tpm2/crypto/openssl/TpmToOsslSym.h b/src/tpm2/crypto/openssl/TpmToOsslSym.h new file mode 100644 index 0000000..521204f --- /dev/null +++ b/src/tpm2/crypto/openssl/TpmToOsslSym.h @@ -0,0 +1,197 @@ +/********************************************************************************/ +/* */ +/* Splice the OpenSSL() library into the TPM code. */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: TpmToOsslSym.h 1619 2020-05-19 16:51:47Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2020 */ +/* */ +/********************************************************************************/ + +/* B.2.3.2. TpmToOsslSym.h */ +/* B.2.3.2.1. Introduction */ +/* This header file is used to splice the OpenSSL() library into the TPM code. */ +/* The support required of a library are a hash module, a block cipher module and portions of a big + number library. All of the library-dependent headers should have the same guard to that only the + first one gets defined. */ + +#ifndef SYM_LIB_DEFINED +#define SYM_LIB_DEFINED +#define SYM_LIB_OSSL +#include <openssl/aes.h> +#if ALG_TDES +#include <openssl/des.h> +#endif + +#if ALG_SM4 +# if defined(OPENSSL_NO_SM4) || OPENSSL_VERSION_NUMBER < 0x10101010L +# undef ALG_SM4 +# define ALG_SM4 ALG_NO +# elif OPENSSL_VERSION_NUMBER >= 0x10200000L +# include <openssl/sm4.h> +# else +// OpenSSL 1.1.1 keeps smX.h headers in the include/crypto directory, +// and they do not get installed as part of the libssl package + +# define SM4_KEY_SCHEDULE 32 + +typedef struct SM4_KEY_st { + uint32_t rk[SM4_KEY_SCHEDULE]; +} SM4_KEY; + +int SM4_set_key(const uint8_t *key, SM4_KEY *ks); +void SM4_encrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks); +void SM4_decrypt(const uint8_t *in, uint8_t *out, const SM4_KEY *ks); +# endif // OpenSSL < 1.2 +#endif // ALG_SM4 + +#if ALG_CAMELLIA +#include <openssl/camellia.h> +#endif +#include <openssl/bn.h> +#include <openssl/ossl_typ.h> + +/* B.2.2.3.2. Links to the OpenSSL symmetric algorithms */ +// The Crypt functions that call the block encryption function use the parameters in the order: +// a) keySchedule +// b) in buffer +// c) 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) \ + (const BYTE *)(in), (BYTE *)(out), (void *)(keySchedule) + +// Define the order of parameters to the library functions that do block encryption and decryption. + +typedef void(*TpmCryptSetSymKeyCall_t)( + const BYTE *in, + BYTE *out, + void *keySchedule + ); + +#define SYM_ALIGNMENT 4 /* libtpms: keep old value */ + +/* B.2.2.3.3. Links to the OpenSSL AES code */ +/* Macros to set up the encryption/decryption key schedules */ + +#define TpmCryptSetEncryptKeyAES(key, keySizeInBits, schedule) \ + AES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleAES *)(schedule)) +#define TpmCryptSetDecryptKeyAES(key, keySizeInBits, schedule) \ + AES_set_decrypt_key((key), (keySizeInBits), (tpmKeyScheduleAES *)(schedule)) + +/* 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 AES_encrypt +#define TpmCryptDecryptAES AES_decrypt +#define tpmKeyScheduleAES AES_KEY + +/* B.2.2.3.4. Links to the OpenSSL DES code */ + +#if ALG_TDES && 0 // libtpms changed +#include "TpmToOsslDesSupport_fp.h" +#endif + +#define TpmCryptSetEncryptKeyTDES(key, keySizeInBits, schedule) \ + TDES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleTDES *)(schedule)) +#define TpmCryptSetDecryptKeyTDES(key, keySizeInBits, schedule) \ + TDES_set_encrypt_key((key), (keySizeInBits), (tpmKeyScheduleTDES *)(schedule)) + +/* Macros to alias encryption calls to specific algorithms. This should be used + sparingly. Currently, only used by CryptRand.c */ + +#define TpmCryptEncryptTDES TDES_encrypt +#define TpmCryptDecryptTDES TDES_decrypt +#define tpmKeyScheduleTDES DES_key_schedule + +#if ALG_TDES // libtpms added begin +#include "TpmToOsslDesSupport_fp.h" +#endif // libtpms added end + +/* B.2.2.3.5. Links to the OpenSSL SM4 code */ +/* Macros to set up the encryption/decryption key schedules */ + +#define TpmCryptSetEncryptKeySM4(key, keySizeInBits, schedule) \ + SM4_set_key((key), (tpmKeyScheduleSM4 *)(schedule)) +#define TpmCryptSetDecryptKeySM4(key, keySizeInBits, schedule) \ + SM4_set_key((key), (tpmKeyScheduleSM4 *)(schedule)) +/* Macros to alias encryption calls to specific algorithms. This should be used sparingly. */ + +#define TpmCryptEncryptSM4 SM4_encrypt +#define TpmCryptDecryptSM4 SM4_decrypt +#define tpmKeyScheduleSM4 SM4_KEY + +/* B.2.2.3.6. Links to the OpenSSL CAMELLIA code */ +/* Macros to set up the encryption/decryption key schedules */ + +#define TpmCryptSetEncryptKeyCAMELLIA(key, keySizeInBits, schedule) \ + Camellia_set_key((key), (keySizeInBits), (tpmKeyScheduleCAMELLIA *)(schedule)) +#define TpmCryptSetDecryptKeyCAMELLIA(key, keySizeInBits, schedule) \ + Camellia_set_key((key), (keySizeInBits), (tpmKeyScheduleCAMELLIA *)(schedule)) + +/* Macros to alias encryption calls to specific algorithms. This should be used sparingly. */ + +#define TpmCryptEncryptCAMELLIA Camellia_encrypt +#define TpmCryptDecryptCAMELLIA Camellia_decrypt +#define tpmKeyScheduleCAMELLIA CAMELLIA_KEY + +/* Forward reference */ + +// kgold typedef union tpmCryptKeySchedule_t tpmCryptKeySchedule_t; + +/* This definition would change if there were something to report */ +#define SymLibSimulationEnd() +#endif // SYM_LIB_DEFINED diff --git a/src/tpm2/crypto/openssl/consttime.txt b/src/tpm2/crypto/openssl/consttime.txt new file mode 100644 index 0000000..6dd8328 --- /dev/null +++ b/src/tpm2/crypto/openssl/consttime.txt @@ -0,0 +1,76 @@ +The following (top level) OpenSSL public BIGNUM functions check for +the BN_FLG_CONSTTIME: + +bn_blind.c: + BN_BLINDING_new() + +bn_exp.c: + BN_exp : must not be set for input bignums +! BN_mod_exp : SHOULD be set for any one of input bignums (only) if m is odd + BN_mod_exp_recp: must NOT be set for input bignums + BN_mod_exp_mont: SHOULD be set for any one of input bignums + BN_mod_exp_mont_word: must NOT be set for input bignums + BN_mod_exp_simple: must NOT bet set for input bignums + +bn_gcd.c: +! BN_mod_inverse: SHOULD be set for any one of input bignums + +bn_lib: + BN_num_bits +! BN_copy + +bn_mont.c: + BN_MONT_CTX_set + +bn.h: +! BN_num_bytes: Calls BN_num_bits + + +Relevant files and functions in the files: +Helpers.c + ComputePrivateExponentD: + - BN_dup: -> BN_copy: YES, BN_FLG_CONSTTIME set by caller on P and Q + - BN_sub: no + - BN_add_word: no + - BN_mod_inverse: YES, DONE + InitOpenSSLRSAPublicKey: + - BN_set_word: no + - BN_bin2bn: no + InitOpenSSLRSAPrivateKey: + - BN_bin2bn: no + - BN_div: -> BN_copy: YES, DONE + - BN_is_zero: no + +TpmToOsslMath: + OsslToTpmBn: + - BN_num_bytes: need not + - BN_bn2bin: -> BN_num_bytes: need not + BigInitialized: + - BN_bin2bn: no + - BN_copy: YES, DONE + BnModMult: + - BN_mul: no + - BN_div: -> BN_copy: ? + BnMult: + - BN_mul: no + BnDiv: + - BN_div: -> BN_copy: ? + BnGcd: /* FUNCTION IS NOT USED */ + - BN_gcd: -> BN_copy, BN_num_bits: YES, DONE + BnModExp: + - BN_mod_exp: YES, DONE + BnModInverse: + - BN_mod_inverse: YES, DONE + + +Elliptic curve signing : + +CryptEccMain.c: + BnEccGenerateKeyPair: + - BnEccModMult: YES, DONE (we have control over random number bnD) + called by BnSignEcSchnorr + called by BnSignEcdsa (if OpenSSL function not used) + +CryptEccSignature.c: + BnEccSignSM2: + - BnEccModMult: YES, DONE (we have control over random number bnK) diff --git a/src/tpm2/crypto/openssl/consttime.txt' b/src/tpm2/crypto/openssl/consttime.txt' new file mode 100644 index 0000000..b667086 --- /dev/null +++ b/src/tpm2/crypto/openssl/consttime.txt' @@ -0,0 +1,58 @@ +The following OpenSSL public BIGNUM functions check for the BN_FLG_CONSTTIME: + +bn_blind.c: + BN_BLINDING_new() + +bn_exp.c: + BN_exp : must not be set for input bignums +! BN_mod_exp : SHOULD be set for any one of input bignums (only) if m is odd + BN_mod_exp_recp: must NOT be set for input bignums + BN_mod_exp_mont: SHOULD be set for any one of input bignums + BN_mod_exp_mont_word: must NOT be set for input bignums + BN_mod_exp_simple: must NOT bet set for input bignums + +bn_gcd.c: +! BN_mod_inverse: SHOULD be set for any one of input bignums + +bn_lib: + BN_num_bits +! BN_copy + +bn_mont.c: + BN_MONT_CTX_set + +bn.h: +! BN_num_bytes: Calls BN_num_bits + + +Relevant files and functions in the files: +Helpers.c + - BN_dup: + - BN_sub: + - BN_add_word: + - BN_mod_inverse: yes + - BN_set_word: + - BN_bin2bn: + - BN_div: + - BN_is_zero: + +TpmToOsslMath: + OsslToTpmBn: + - BN_num_bytes: + - BN_bn2bin: + BigInitialized: + - BN_bin2bn: + - BN_copy: + BnModMult: + - BN_mul: + - BN_div: + BnMult: + - BN_mul: + BnDiv: + - BN_div: + BnGcd: + - BN_gcd: + BnModExp: + - BN_mod_exp: YES + BnModInverse: + - BN_mod_inverse: YES |