diff --git a/src/tpm2.c b/src/tpm2.c index 09fa2841..358eba13 100644 --- a/src/tpm2.c +++ b/src/tpm2.c @@ -7034,6 +7034,20 @@ int TPM2_GetCurveSize(TPM_ECC_CURVE curveID) return 0; } +TPM_ALG_ID TPM2_GetCurveHashAlg(TPM_ECC_CURVE curveID) +{ + int curveSz = TPM2_GetCurveSize(curveID); + + /* Pair the message digest strength to the curve size, matching the TCG + * recommended curve/hash combinations (P256/SHA256, P384/SHA384, + * P521/SHA512). */ + if (curveSz >= 64) /* P521 (66), BP512 (64) */ + return TPM_ALG_SHA512; + if (curveSz == 48) /* P384, BP384 */ + return TPM_ALG_SHA384; + return TPM_ALG_SHA256; /* P256 and smaller */ +} + int TPM2_GetTpmCurve(int curve_id) { int ret = -1; diff --git a/src/tpm2_cryptocb.c b/src/tpm2_cryptocb.c index 43733e3a..63cd00a2 100644 --- a/src/tpm2_cryptocb.c +++ b/src/tpm2_cryptocb.c @@ -234,15 +234,13 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) TPMT_PUBLIC publicTemplate; TPMI_ALG_HASH hashAlg; - if (curve_id == TPM_ECC_NIST_P521) - hashAlg = TPM_ALG_SHA512; - else if (curve_id == TPM_ECC_NIST_P384) - hashAlg = TPM_ALG_SHA384; - else - hashAlg = TPM_ALG_SHA256; + hashAlg = TPM2_GetCurveHashAlg(curve_id); XMEMSET(&publicTemplate, 0, sizeof(publicTemplate)); - rc = wolfTPM2_GetKeyTemplate_ECC_ex(&publicTemplate, hashAlg, + /* Use the internal helper (not the public _ex wrapper) so + * the curve wolfCrypt negotiated is honored exactly and is + * not remapped by WOLFTPM2_ECC_DEFAULT_CURVE. */ + rc = GetKeyTemplateECC(&publicTemplate, hashAlg, TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | TPMA_OBJECT_sign | TPMA_OBJECT_noDA, curve_id, TPM_ALG_ECDSA, hashAlg); diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index f95851d1..7f0f5d0e 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -8224,20 +8224,32 @@ int GetKeyTemplateECC(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve, TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash) { - int curveSz = TPM2_GetCurveSize(curve); + int curveSz; - if (publicTemplate == NULL || curveSz == 0) + if (publicTemplate == NULL) return BAD_FUNC_ARG; -#if defined(NO_ECC256) && defined(HAVE_ECC384) && ECC_MIN_KEY_SZ <= 384 - /* make sure we use a curve that is enabled */ +#ifdef NO_ECC256 + /* P256 is compiled out of wolfCrypt; substitute the configured (enabled) + * default curve so callers requesting P256 still get a usable curve. This + * is availability-driven and applies to every caller (including the named + * EK/SRK/AIK templates) because the build simply cannot honor P256. The + * configurable default-curve preference lives in the public ECC template + * wrappers, not here, so explicit curves through this helper are honored. */ if (curve == TPM_ECC_NIST_P256) { - curve = TPM_ECC_NIST_P384; - nameAlg = TPM_ALG_SHA384; - sigHash = TPM_ALG_SHA384; + curve = WOLFTPM2_ECC_DEFAULT_CURVE; + nameAlg = TPM2_GetCurveHashAlg(curve); + if (sigHash != TPM_ALG_NULL) + sigHash = nameAlg; } #endif + /* Compute curve size after any substitution so coordinate sizes and the + * AES wrap strength below match the curve actually used. */ + curveSz = TPM2_GetCurveSize(curve); + if (curveSz == 0) + return BAD_FUNC_ARG; + XMEMSET(publicTemplate, 0, sizeof(TPMT_PUBLIC)); publicTemplate->type = TPM_ALG_ECC; publicTemplate->nameAlg = nameAlg; @@ -8280,10 +8292,35 @@ int wolfTPM2_GetKeyTemplate_RSA(TPMT_PUBLIC* publicTemplate, TPM_ALG_NULL, WOLFTPM2_WRAP_DIGEST); } +/* Resolve a P256 "use the library default" request to the build-configured + * WOLFTPM2_ECC_DEFAULT_CURVE, pairing the name/sig hash via + * TPM2_GetCurveHashAlg. No-op when the default is P256 (the shipped default), + * so existing builds are unchanged. This lets a build make P384 (or another + * curve) the wrapper default - e.g. wolfTPM2_CreateSRK(TPM_ALG_ECC) - without + * editing call sites. The EK index templates (TCG-fixed curve and auth policy), + * the explicit-curve IAK/IDevID helpers, and the crypto callback (curve + * negotiated by wolfCrypt) intentionally do NOT use this and keep their exact + * curve. */ +static void wolfTPM2_ResolveDefaultEccCurve(TPM_ECC_CURVE* curve, + TPM_ALG_ID* nameAlg, TPM_ALG_ID* sigHash) +{ + if (*curve == TPM_ECC_NIST_P256 && + WOLFTPM2_ECC_DEFAULT_CURVE != TPM_ECC_NIST_P256) { + *curve = WOLFTPM2_ECC_DEFAULT_CURVE; + if (nameAlg != NULL) + *nameAlg = TPM2_GetCurveHashAlg(*curve); + if (sigHash != NULL && *sigHash != TPM_ALG_NULL) + *sigHash = TPM2_GetCurveHashAlg(*curve); + } +} + int wolfTPM2_GetKeyTemplate_ECC_ex(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID nameAlg, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve, TPM_ALG_ID sigScheme, TPM_ALG_ID sigHash) { + /* General-purpose ECC template API: a P256 request follows the configured + * default curve. */ + wolfTPM2_ResolveDefaultEccCurve(&curve, &nameAlg, &sigHash); return GetKeyTemplateECC(publicTemplate, nameAlg, objectAttributes, curve, sigScheme, sigHash); } @@ -8291,7 +8328,9 @@ int wolfTPM2_GetKeyTemplate_ECC_ex(TPMT_PUBLIC* publicTemplate, int wolfTPM2_GetKeyTemplate_ECC(TPMT_PUBLIC* publicTemplate, TPMA_OBJECT objectAttributes, TPM_ECC_CURVE curve, TPM_ALG_ID sigScheme) { - return GetKeyTemplateECC(publicTemplate, WOLFTPM2_WRAP_DIGEST, + /* Route through the _ex wrapper so the configurable default curve applies + * to this general-purpose API as well. */ + return wolfTPM2_GetKeyTemplate_ECC_ex(publicTemplate, WOLFTPM2_WRAP_DIGEST, objectAttributes, curve, sigScheme, WOLFTPM2_WRAP_DIGEST); } @@ -8541,13 +8580,17 @@ int wolfTPM2_GetKeyTemplate_RSA_SRK(TPMT_PUBLIC* publicTemplate) int wolfTPM2_GetKeyTemplate_ECC_SRK(TPMT_PUBLIC* publicTemplate) { + TPM_ECC_CURVE curve = TPM_ECC_NIST_P256; + TPM_ALG_ID nameAlg = TPM_ALG_SHA256; TPMA_OBJECT objectAttributes = ( TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent | TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | TPMA_OBJECT_restricted | TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA); - return GetKeyTemplateECC(publicTemplate, TPM_ALG_SHA256, - objectAttributes, TPM_ECC_NIST_P256, TPM_ALG_NULL, TPM_ALG_NULL); + /* Storage primary defaults to P256 but follows WOLFTPM2_ECC_DEFAULT_CURVE. */ + wolfTPM2_ResolveDefaultEccCurve(&curve, &nameAlg, NULL); + return GetKeyTemplateECC(publicTemplate, nameAlg, + objectAttributes, curve, TPM_ALG_NULL, TPM_ALG_NULL); } int wolfTPM2_GetKeyTemplate_RSA_AIK(TPMT_PUBLIC* publicTemplate) @@ -8569,13 +8612,19 @@ int wolfTPM2_GetKeyTemplate_RSA_AIK(TPMT_PUBLIC* publicTemplate) int wolfTPM2_GetKeyTemplate_ECC_AIK(TPMT_PUBLIC* publicTemplate) { int ret; + TPM_ECC_CURVE curve = TPM_ECC_NIST_P256; + TPM_ALG_ID nameAlg = TPM_ALG_SHA256; + TPM_ALG_ID sigHash = TPM_ALG_SHA256; TPMA_OBJECT objectAttributes = ( TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent | TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | TPMA_OBJECT_restricted | TPMA_OBJECT_sign | TPMA_OBJECT_noDA); - ret = GetKeyTemplateECC(publicTemplate, TPM_ALG_SHA256, - objectAttributes, TPM_ECC_NIST_P256, TPM_ALG_ECDSA, TPM_ALG_SHA256); + /* Attestation signing key defaults to P256 but follows the configured + * default curve. */ + wolfTPM2_ResolveDefaultEccCurve(&curve, &nameAlg, &sigHash); + ret = GetKeyTemplateECC(publicTemplate, nameAlg, + objectAttributes, curve, TPM_ALG_ECDSA, sigHash); if (ret == 0) { publicTemplate->parameters.eccDetail.symmetric.algorithm = TPM_ALG_NULL; } diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 07a7f26c..c2448504 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -2538,10 +2538,67 @@ static void test_TPM2_BrainpoolCurveMapping(void) AssertIntEQ(TPM2_GetCurveSize(TPM_ECC_BP_P384_R1), 48); AssertIntEQ(TPM2_GetCurveSize(TPM_ECC_BP_P512_R1), 64); + /* TPM2_GetCurveHashAlg pairs the digest strength to the curve size, + * per TCG recommended combinations. */ + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_NIST_P256), TPM_ALG_SHA256); + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_NIST_P384), TPM_ALG_SHA384); + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_NIST_P521), TPM_ALG_SHA512); + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_BP_P256_R1), TPM_ALG_SHA256); + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_BP_P384_R1), TPM_ALG_SHA384); + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_BP_P512_R1), TPM_ALG_SHA512); /* 64 -> SHA512 */ + AssertIntEQ(TPM2_GetCurveHashAlg(TPM_ECC_BN_P638), TPM_ALG_SHA512); + printf("Test TPM Wrapper:\tBrainpool curve mapping:\tPassed\n"); #endif } +/* The P256-defaulting wrapper templates (general ECC, SRK, AIK) follow the + * build's WOLFTPM2_ECC_DEFAULT_CURVE: a no-op in the shipped P256 build, an + * upgrade when overridden to e.g. P384. The EK templates are TCG-fixed and keep + * their exact curve and policy (except under NO_ECC256, where P256 is + * unavailable to every caller - the EK checks are guarded for that case). */ +static void test_TPM2_EccDefaultCurveTemplate(void) +{ +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) + TPMT_PUBLIC t; + + /* P256 through the general API follows the configured default + paired + * hash. In an overridden build this proves the upgrade; in the default + * P256 build it is a no-op. */ + AssertIntEQ(wolfTPM2_GetKeyTemplate_ECC(&t, TPMA_OBJECT_sign, + TPM_ECC_NIST_P256, TPM_ALG_ECDSA), 0); + AssertIntEQ(t.parameters.eccDetail.curveID, WOLFTPM2_ECC_DEFAULT_CURVE); + AssertIntEQ(t.nameAlg, TPM2_GetCurveHashAlg(WOLFTPM2_ECC_DEFAULT_CURVE)); + + /* The storage primary (wolfTPM2_CreateSRK ECC path) follows the default. */ + AssertIntEQ(wolfTPM2_GetKeyTemplate_ECC_SRK(&t), 0); + AssertIntEQ(t.parameters.eccDetail.curveID, WOLFTPM2_ECC_DEFAULT_CURVE); + AssertIntEQ(t.nameAlg, TPM2_GetCurveHashAlg(WOLFTPM2_ECC_DEFAULT_CURVE)); + + /* The attestation signing key (AIK) follows the default. This block + * exercises the sigHash arg of the resolver, so lock in name and sig + * hash too. */ + AssertIntEQ(wolfTPM2_GetKeyTemplate_ECC_AIK(&t), 0); + AssertIntEQ(t.parameters.eccDetail.curveID, WOLFTPM2_ECC_DEFAULT_CURVE); + AssertIntEQ(t.nameAlg, TPM2_GetCurveHashAlg(WOLFTPM2_ECC_DEFAULT_CURVE)); + AssertIntEQ(t.parameters.eccDetail.scheme.details.ecdsa.hashAlg, + TPM2_GetCurveHashAlg(WOLFTPM2_ECC_DEFAULT_CURVE)); + +#ifndef NO_ECC256 + /* EK P256 NV index is TCG-fixed and must NOT follow the default curve. + * Skipped under NO_ECC256: there GetKeyTemplateECC substitutes P256 for an + * enabled curve for every caller, including the EK, because the build + * cannot honor P256 at all. */ + AssertIntEQ(wolfTPM2_GetKeyTemplate_EKIndex(TPM2_NV_EK_ECC_P256, &t), 0); + AssertIntEQ(t.parameters.eccDetail.curveID, TPM_ECC_NIST_P256); + AssertIntEQ(t.nameAlg, TPM_ALG_SHA256); + AssertIntEQ(t.authPolicy.size, sizeof(TPM_20_EK_AUTH_POLICY)); +#endif + + printf("Test TPM Wrapper:\tECC default-curve template:\tPassed\n"); +#endif +} + static void test_TPM2_KeyedHashScheme_XorSerialize(void) { TPM2_Packet packet; @@ -4965,6 +5022,7 @@ int unit_tests(int argc, char *argv[]) test_TPM2_ParsePoint_OuterResync(); test_TPM2_ParseSignature_NullAlg(); test_TPM2_BrainpoolCurveMapping(); + test_TPM2_EccDefaultCurveTemplate(); test_wolfTPM2_RsaEncryptDecrypt_OversizedBufferE(); test_wolfTPM2_SignHashScheme_DigestSize(); test_wolfTPM2_VerifyHashTicket_DigestSize(); diff --git a/wolftpm/tpm2.h b/wolftpm/tpm2.h index 30569ab3..36f386a2 100644 --- a/wolftpm/tpm2.h +++ b/wolftpm/tpm2.h @@ -4122,6 +4122,19 @@ WOLFTPM_API const char* TPM2_GetHierarchyDesc(TPMI_RH_HIERARCHY_AUTH authHandle) */ WOLFTPM_API int TPM2_GetCurveSize(TPM_ECC_CURVE curveID); +/*! + \ingroup TPM2_Proprietary + \brief Determine the recommended message digest for a TPM ECC Curve + + \return TPM_ALG_ID of the hash paired to the curve size (P256->SHA256, + P384->SHA384, P521->SHA512). Defaults to TPM_ALG_SHA256. + + \param curveID value of type TPM_ECC_CURVE + + \sa TPM2_GetCurveSize +*/ +WOLFTPM_API TPM_ALG_ID TPM2_GetCurveHashAlg(TPM_ECC_CURVE curveID); + /*! \ingroup TPM2_Proprietary \brief Translate a wolfcrypt curve type to its corresponding TPM curve type diff --git a/wolftpm/tpm2_types.h b/wolftpm/tpm2_types.h index b9a8c975..d8b75fa3 100644 --- a/wolftpm/tpm2_types.h +++ b/wolftpm/tpm2_types.h @@ -890,6 +890,31 @@ typedef int64_t INT64; #define WOLFTPM2_WRAP_ECC_KEY_BITS (MAX_ECC_KEY_BITS*8) #endif +/* Defines the library-default ECC curve used by the wrapper key templates that + * default to P256: wolfTPM2_GetKeyTemplate_ECC[_ex] and the storage/attestation + * primaries (wolfTPM2_GetKeyTemplate_ECC_SRK / _AIK, used by + * wolfTPM2_CreateSRK(TPM_ALG_ECC)). A P256 request through these follows this + * default, so a build can opt in to a stronger default (e.g. P384) without + * editing call sites. Override at build time, e.g. + * -DWOLFTPM2_ECC_DEFAULT_CURVE=TPM_ECC_NIST_P384. The matching name/sig hash is + * derived from the curve via TPM2_GetCurveHashAlg, so only the curve needs to + * be set. When left at the default of P256 the behavior is unchanged. The EK + * templates (TCG-fixed curve and auth policy), the explicit-curve IAK/IDevID + * helpers, and crypto-callback keys (curve negotiated by wolfCrypt) keep their + * exact curve. If P256 is compiled out (NO_ECC256) the default falls back to an + * enabled curve. */ +#ifndef WOLFTPM2_ECC_DEFAULT_CURVE + #if !defined(NO_ECC256) + #define WOLFTPM2_ECC_DEFAULT_CURVE TPM_ECC_NIST_P256 + #elif defined(HAVE_ECC384) && ECC_MIN_KEY_SZ <= 384 + #define WOLFTPM2_ECC_DEFAULT_CURVE TPM_ECC_NIST_P384 + #elif defined(HAVE_ECC521) && ECC_MIN_KEY_SZ <= 521 + #define WOLFTPM2_ECC_DEFAULT_CURVE TPM_ECC_NIST_P521 + #else + #define WOLFTPM2_ECC_DEFAULT_CURVE TPM_ECC_NIST_P256 + #endif +#endif + #if !defined(WOLFTPM2_NO_WOLFCRYPT) && \ (defined(WOLF_CRYPTO_DEV) || defined(WOLF_CRYPTO_CB)) /* Enable the crypto callback support */ diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index 56113382..ee644c1f 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -3490,7 +3490,7 @@ WOLFTPM_API int wolfTPM2_GetKeyTemplate_RSA_ex(TPMT_PUBLIC* publicTemplate, \param publicTemplate pointer to an empty structure of TPMT_PUBLIC type, to store the new ECC key template \param objectAttributes integer value of TPMA_OBJECT type, can contain one or more attributes, e.g. TPMA_OBJECT_fixedTPM - \param curve integer value of TPM_ECC_CURVE type, specifying a TPM supported ECC curve ID + \param curve integer value of TPM_ECC_CURVE type, specifying a TPM supported ECC curve ID; a TPM_ECC_NIST_P256 request follows the build-configured WOLFTPM2_ECC_DEFAULT_CURVE (with its matching hash), other curves are used as given \param sigScheme integer value of TPM_ALG_ID type, specifying a TPM supported signature scheme \sa wolfTPM2_GetKeyTemplate_ECC_ex @@ -3512,7 +3512,7 @@ WOLFTPM_API int wolfTPM2_GetKeyTemplate_ECC(TPMT_PUBLIC* publicTemplate, \param publicTemplate pointer to an empty structure of TPMT_PUBLIC type, to store the new ECC key template \param nameAlg integer value of TPM_ALG_ID type, specifying a TPM supported hashing algorithm, typically TPM_ALG_SHA256 for SHA 256 \param objectAttributes integer value of TPMA_OBJECT type, can contain one or more attributes, e.g. TPMA_OBJECT_fixedTPM - \param curve integer value of TPM_ECC_CURVE type, specifying a TPM supported ECC curve ID + \param curve integer value of TPM_ECC_CURVE type, specifying a TPM supported ECC curve ID; a TPM_ECC_NIST_P256 request follows the build-configured WOLFTPM2_ECC_DEFAULT_CURVE (with its matching hash), other curves are used as given \param sigScheme integer value of TPM_ALG_ID type, specifying a TPM supported signature scheme \param sigHash integer value of TPM_ALG_ID type, specifying a TPM supported signature hash scheme