diff --git a/IDE/VisualStudio/wolftpm.vcxproj b/IDE/VisualStudio/wolftpm.vcxproj index 7428a92..0b996fe 100644 --- a/IDE/VisualStudio/wolftpm.vcxproj +++ b/IDE/VisualStudio/wolftpm.vcxproj @@ -36,6 +36,7 @@ + diff --git a/src/tpm2_asn.c b/src/tpm2_asn.c index cbed56f..bc586e5 100644 --- a/src/tpm2_asn.c +++ b/src/tpm2_asn.c @@ -27,6 +27,21 @@ #ifndef WOLFTPM2_NO_ASN +#if defined(HAVE_ECC) && (defined(WOLFTPM_CRYPTOCB) || \ + (defined(HAVE_PK_CALLBACKS) && !defined(WOLFCRYPT_ONLY))) +/* Helper to trim leading zeros when not required */ +byte* TPM2_ASN_TrimZeros(byte* in, word32* len) +{ + word32 idx = 0; + while (idx+1 < *len && in[idx] == 0 && (in[idx+1] & 0x80) == 0) { + idx++; + in++; + } + *len -= idx; + return in; +} +#endif + int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len, word32 maxIdx, int check) { diff --git a/src/tpm2_cryptocb.c b/src/tpm2_cryptocb.c index 0f386e8..8753100 100644 --- a/src/tpm2_cryptocb.c +++ b/src/tpm2_cryptocb.c @@ -24,24 +24,10 @@ #endif #include +#include #if !defined(WOLFTPM2_NO_WRAPPER) -#if defined(HAVE_ECC) && (defined(WOLFTPM_CRYPTOCB) || \ - (defined(HAVE_PK_CALLBACKS) && !defined(WOLFCRYPT_ONLY))) -/* Helper to trim leading zeros when not required */ -static byte* wolfTPM2_ASNTrimZeros(byte* in, word32* len) -{ - word32 idx = 0; - while (idx+1 < *len && in[idx] == 0 && (in[idx+1] & 0x80) == 0) { - idx++; - in++; - } - *len -= idx; - return in; -} -#endif - #ifdef WOLFTPM_CRYPTOCB /* Internal structure for tracking hash state */ @@ -272,8 +258,8 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) rLen = sLen = rsLen / 2; r = &sigRS[0]; s = &sigRS[rLen]; - r = wolfTPM2_ASNTrimZeros(r, &rLen); - s = wolfTPM2_ASNTrimZeros(s, &sLen); + r = TPM2_ASN_TrimZeros(r, &rLen); + s = TPM2_ASN_TrimZeros(s, &sLen); /* Encode ECDSA Header */ rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, @@ -1134,8 +1120,8 @@ int wolfTPM2_PK_EccSign(WOLFSSL* ssl, rLen = sLen = rsLen / 2; r = &sigRS[0]; s = &sigRS[rLen]; - r = wolfTPM2_ASNTrimZeros(r, &rLen); - s = wolfTPM2_ASNTrimZeros(s, &sLen); + r = TPM2_ASN_TrimZeros(r, &rLen); + s = TPM2_ASN_TrimZeros(s, &sLen); /* Encode ECDSA Header */ ret = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, out, outSz); diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index 4f8d329..b3e9513 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -3756,7 +3756,7 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, int sigOutSz = 0; if (dev == NULL || key == NULL || digest == NULL || sig == NULL || - sigSz == NULL) { + sigSz == NULL) { return BAD_FUNC_ARG; } @@ -3772,18 +3772,18 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, /* set session auth for key */ wolfTPM2_SetAuthHandle(dev, 0, &key->handle); + /* verify input cannot exceed buffer */ + if (digestSz > (int)sizeof(signIn.digest.buffer)) + digestSz = (int)sizeof(signIn.digest.buffer); + XMEMSET(&signIn, 0, sizeof(signIn)); signIn.keyHandle = key->handle.hndl; signIn.digest.size = TPM2_GetHashDigestSize(hashAlg); if (signIn.digest.size <= 0) { return BAD_FUNC_ARG; } - /* truncate if too large */ - if (signIn.digest.size > curveSize) { - signIn.digest.size = curveSize; - } /* if digest provided is smaller than key size then zero pad leading */ - if (signIn.digest.size > digestSz) { + if (digestSz < signIn.digest.size) { XMEMCPY(&signIn.digest.buffer[signIn.digest.size - digestSz], digest, digestSz); } @@ -3932,8 +3932,20 @@ int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, XMEMSET(&verifySigIn, 0, sizeof(verifySigIn)); verifySigIn.keyHandle = key->handle.hndl; - verifySigIn.digest.size = digestSz; - XMEMCPY(verifySigIn.digest.buffer, digest, digestSz); + + + verifySigIn.digest.size = TPM2_GetHashDigestSize(hashAlg); + if (verifySigIn.digest.size <= 0) { + return BAD_FUNC_ARG; + } + /* if digest provided is smaller than key size then zero pad leading */ + if (digestSz < verifySigIn.digest.size) { + XMEMCPY(&verifySigIn.digest.buffer[verifySigIn.digest.size - digestSz], + digest, digestSz); + } + else { + XMEMCPY(verifySigIn.digest.buffer, digest, digestSz); + } verifySigIn.signature.sigAlg = sigAlg; verifySigIn.signature.signature.any.hashAlg = hashAlg; if (key->pub.publicArea.type == TPM_ALG_ECC) { diff --git a/tests/unit_tests.c b/tests/unit_tests.c index 6bf5acd..f064837 100644 --- a/tests/unit_tests.c +++ b/tests/unit_tests.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -396,6 +397,153 @@ static void test_wolfTPM2_CSR(void) #endif } +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) +static void test_wolfTPM2_EccSignVerifyDig(const byte* digest, int digestSz, + TPM_ECC_CURVE curve, TPMI_ALG_HASH hashAlg) +{ + int rc; + int verifyRes = 0; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY storageKey; + WOLFTPM2_KEY eccKey; + TPMT_PUBLIC publicTemplate; + byte sigRs[MAX_ECC_BYTES*2]; + word32 sigRsSz = (word32)sizeof(sigRs); + byte sig[ECC_MAX_SIG_SIZE]; + word32 sigSz; + byte *r, *s; + word32 rLen, sLen; + ecc_key wolfKey; + int curveSize = TPM2_GetCurveSize(curve); + + /* Initialize TPM */ + rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL); + AssertIntEQ(rc, 0); + + /* -- Use TPM key to sign and verify with wolfCrypt -- */ + /* Create storage key */ + rc = wolfTPM2_CreateSRK(&dev, &storageKey, TPM_ALG_ECC, + (byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1); + AssertIntEQ(rc, 0); + + /* Create ECC key for signing */ + rc = wolfTPM2_GetKeyTemplate_ECC_ex(&publicTemplate, hashAlg, + (TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | + TPMA_OBJECT_sign | TPMA_OBJECT_noDA), + curve, TPM_ALG_ECDSA, hashAlg); + AssertIntEQ(rc, 0); + rc = wolfTPM2_CreateAndLoadKey(&dev, &eccKey, &storageKey.handle, + &publicTemplate, (byte*)gKeyAuth, sizeof(gKeyAuth)-1); + AssertIntEQ(rc, 0); + + /* Sign with TPM */ + rc = wolfTPM2_SignHashScheme(&dev, &eccKey, digest, digestSz, + sigRs, (int*)&sigRsSz, TPM_ALG_ECDSA, hashAlg); + AssertIntEQ(rc, 0); + + /* Make sure leading zero's not required are trimmed */ + rLen = sLen = sigRsSz / 2; + r = &sigRs[0]; + s = &sigRs[rLen]; + r = TPM2_ASN_TrimZeros(r, &rLen); + s = TPM2_ASN_TrimZeros(s, &sLen); + + /* Encode ECDSA Header */ + sigSz = (word32)sizeof(sig); + rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, sig, &sigSz); + AssertIntEQ(rc, 0); + + /* Initialize wolfCrypt ECC key */ + rc = wc_ecc_init(&wolfKey); + AssertIntEQ(rc, 0); + + /* Convert TPM key to wolfCrypt key for verification */ + rc = wolfTPM2_EccKey_TpmToWolf(&dev, &eccKey, &wolfKey); + AssertIntEQ(rc, 0); + + /* Verify TPM signature with wolfCrypt */ + rc = wc_ecc_verify_hash(sig, sigSz, digest, digestSz, &verifyRes, &wolfKey); + AssertIntEQ(rc, 0); + AssertIntEQ(verifyRes, 1); /* 1 indicates successful verification */ + + /* Cleanup first wolfCrypt key */ + wc_ecc_free(&wolfKey); + wolfTPM2_UnloadHandle(&dev, &eccKey.handle); + + + /* -- Use wolfCrypt key to sign and verify with TPM -- */ + /* Initialize new wolfCrypt ECC key */ + rc = wc_ecc_init(&wolfKey); + AssertIntEQ(rc, 0); + + /* Generate new ECC key with wolfCrypt */ + rc = wc_ecc_make_key(wolfTPM2_GetRng(&dev), curveSize, &wolfKey); + AssertIntEQ(rc, 0); + + /* Sign with wolfCrypt */ + sigSz = (word32)sizeof(sig); + rc = wc_ecc_sign_hash(digest, digestSz, sig, &sigSz, + wolfTPM2_GetRng(&dev), &wolfKey); + AssertIntEQ(rc, 0); + + /* Decode ECDSA Header */ + r = sigRs; + s = &sigRs[MAX_ECC_BYTES]; + rLen = sLen = MAX_ECC_BYTES; + rc = wc_ecc_sig_to_rs(sig, + sigSz, r, &rLen, s, &sLen); + AssertIntEQ(rc, 0); + + /* Convert wolfCrypt key to TPM key for verification */ + rc = wolfTPM2_EccKey_WolfToTpm(&dev, &wolfKey, &eccKey); + AssertIntEQ(rc, 0); + + /* combine R and S at key size (zero pad leading) */ + XMEMCPY(&sigRs[curveSize-rLen], r, rLen); + XMEMSET(&sigRs[0], 0, curveSize-rLen); + XMEMCPY(&sigRs[curveSize + (curveSize-sLen)], s, sLen); + XMEMSET(&sigRs[curveSize], 0, curveSize-sLen); + + /* Verify wolfCrypt signature with TPM */ + rc = wolfTPM2_VerifyHashScheme(&dev, &eccKey, sigRs, curveSize*2, + digest, digestSz, TPM_ALG_ECDSA, hashAlg); + AssertIntEQ(rc, 0); + + /* Cleanup */ + wc_ecc_free(&wolfKey); + wolfTPM2_UnloadHandle(&dev, &eccKey.handle); + wolfTPM2_UnloadHandle(&dev, &storageKey.handle); + wolfTPM2_Cleanup(&dev); + + printf("Test TPM Wrapper:\tSign/Verify Interop (digestSz=%d, curve=%d, hashAlg=%d):\t%s\n", + digestSz, curve, hashAlg, rc == 0 ? "Passed" : "Failed"); +} + +/* Test with smaller, same and larger digest sizes using different ECC curves. + * Interop sign and verify with wolfCrypt and TPM */ +static void test_wolfTPM2_EccSignVerify(void) +{ + int i; + byte digest[TPM_MAX_DIGEST_SIZE]; + + for (i = 0; i < 64; i++) { + digest[i] = (byte)(0x11 + i); + } + + test_wolfTPM2_EccSignVerifyDig(digest, 20, TPM_ECC_NIST_P256, TPM_ALG_SHA256); + test_wolfTPM2_EccSignVerifyDig(digest, 32, TPM_ECC_NIST_P256, TPM_ALG_SHA256); + test_wolfTPM2_EccSignVerifyDig(digest, 48, TPM_ECC_NIST_P256, TPM_ALG_SHA256); + test_wolfTPM2_EccSignVerifyDig(digest, 64, TPM_ECC_NIST_P256, TPM_ALG_SHA256); + +#if defined(HAVE_ECC384) && ECC_MIN_KEY_SZ <= 384 + test_wolfTPM2_EccSignVerifyDig(digest, 20, TPM_ECC_NIST_P384, TPM_ALG_SHA384); + test_wolfTPM2_EccSignVerifyDig(digest, 32, TPM_ECC_NIST_P384, TPM_ALG_SHA384); + test_wolfTPM2_EccSignVerifyDig(digest, 48, TPM_ECC_NIST_P384, TPM_ALG_SHA384); + test_wolfTPM2_EccSignVerifyDig(digest, 64, TPM_ECC_NIST_P384, TPM_ALG_SHA384); +#endif +} +#endif + #if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFTPM2_PEM_DECODE) && \ !defined(NO_RSA) static WOLFTPM2_KEY authKey; /* also used for test_wolfTPM2_PCRPolicy */ @@ -681,6 +829,9 @@ int unit_tests(int argc, char *argv[]) test_wolfTPM2_KeyBlob(TPM_ALG_ECC); test_wolfTPM2_Cleanup(); test_wolfTPM2_thread_local_storage(); + #if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) + test_wolfTPM2_EccSignVerify(); + #endif #endif /* !WOLFTPM2_NO_WRAPPER */ return 0; diff --git a/wolftpm/tpm2_asn.h b/wolftpm/tpm2_asn.h index 4159264..a557597 100644 --- a/wolftpm/tpm2_asn.h +++ b/wolftpm/tpm2_asn.h @@ -139,6 +139,10 @@ WOLFTPM_API int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz, TPM2B_PUBL */ WOLFTPM_API int TPM2_ASN_RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz); + +WOLFTPM_LOCAL byte* TPM2_ASN_TrimZeros(byte* in, word32* len); + + #ifdef __cplusplus } /* extern "C" */ #endif