Skip to content

Commit bd68255

Browse files
authored
Merge pull request #418 from dgarske/tpmsign
Fix logic for signing with input digest smaller than key size
2 parents 761cb4a + a45f922 commit bd68255

File tree

6 files changed

+258
-38
lines changed

6 files changed

+258
-38
lines changed

IDE/VisualStudio/wolftpm.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
</ItemGroup>
3737
<ItemGroup>
3838
<ClCompile Include="..\..\src\tpm2.c" />
39+
<ClCompile Include="..\..\src\tpm2_asn.c" />
3940
<ClCompile Include="..\..\src\tpm2_cryptocb.c" />
4041
<ClCompile Include="..\..\src\tpm2_packet.c" />
4142
<ClCompile Include="..\..\src\tpm2_param_enc.c" />

src/tpm2_asn.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,18 @@
2727

2828
#ifndef WOLFTPM2_NO_ASN
2929

30+
/* Helper to trim leading zeros when not required */
31+
byte* TPM2_ASN_TrimZeros(byte* in, word32* len)
32+
{
33+
word32 idx = 0;
34+
while (idx+1 < *len && in[idx] == 0 && (in[idx+1] & 0x80) == 0) {
35+
idx++;
36+
in++;
37+
}
38+
*len -= idx;
39+
return in;
40+
}
41+
3042
int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
3143
word32 maxIdx, int check)
3244
{

src/tpm2_cryptocb.c

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,10 @@
2424
#endif
2525

2626
#include <wolftpm/tpm2_wrap.h>
27+
#include <wolftpm/tpm2_asn.h>
2728

2829
#if !defined(WOLFTPM2_NO_WRAPPER)
2930

30-
#if defined(HAVE_ECC) && (defined(WOLFTPM_CRYPTOCB) || \
31-
(defined(HAVE_PK_CALLBACKS) && !defined(WOLFCRYPT_ONLY)))
32-
/* Helper to trim leading zeros when not required */
33-
static byte* wolfTPM2_ASNTrimZeros(byte* in, word32* len)
34-
{
35-
word32 idx = 0;
36-
while (idx+1 < *len && in[idx] == 0 && (in[idx+1] & 0x80) == 0) {
37-
idx++;
38-
in++;
39-
}
40-
*len -= idx;
41-
return in;
42-
}
43-
#endif
44-
4531
#ifdef WOLFTPM_CRYPTOCB
4632

4733
/* Internal structure for tracking hash state */
@@ -272,8 +258,8 @@ int wolfTPM2_CryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx)
272258
rLen = sLen = rsLen / 2;
273259
r = &sigRS[0];
274260
s = &sigRS[rLen];
275-
r = wolfTPM2_ASNTrimZeros(r, &rLen);
276-
s = wolfTPM2_ASNTrimZeros(s, &sLen);
261+
r = TPM2_ASN_TrimZeros(r, &rLen);
262+
s = TPM2_ASN_TrimZeros(s, &sLen);
277263

278264
/* Encode ECDSA Header */
279265
rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen,
@@ -1134,8 +1120,8 @@ int wolfTPM2_PK_EccSign(WOLFSSL* ssl,
11341120
rLen = sLen = rsLen / 2;
11351121
r = &sigRS[0];
11361122
s = &sigRS[rLen];
1137-
r = wolfTPM2_ASNTrimZeros(r, &rLen);
1138-
s = wolfTPM2_ASNTrimZeros(s, &sLen);
1123+
r = TPM2_ASN_TrimZeros(r, &rLen);
1124+
s = TPM2_ASN_TrimZeros(s, &sLen);
11391125

11401126
/* Encode ECDSA Header */
11411127
ret = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, out, outSz);

src/tpm2_wrap.c

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3756,7 +3756,7 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
37563756
int sigOutSz = 0;
37573757

37583758
if (dev == NULL || key == NULL || digest == NULL || sig == NULL ||
3759-
sigSz == NULL) {
3759+
sigSz == NULL) {
37603760
return BAD_FUNC_ARG;
37613761
}
37623762

@@ -3772,10 +3772,24 @@ int wolfTPM2_SignHashScheme(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
37723772
/* set session auth for key */
37733773
wolfTPM2_SetAuthHandle(dev, 0, &key->handle);
37743774

3775+
/* verify input cannot exceed buffer */
3776+
if (digestSz > (int)sizeof(signIn.digest.buffer))
3777+
digestSz = (int)sizeof(signIn.digest.buffer);
3778+
37753779
XMEMSET(&signIn, 0, sizeof(signIn));
37763780
signIn.keyHandle = key->handle.hndl;
3777-
signIn.digest.size = digestSz;
3778-
XMEMCPY(signIn.digest.buffer, digest, signIn.digest.size);
3781+
signIn.digest.size = TPM2_GetHashDigestSize(hashAlg);
3782+
if (signIn.digest.size <= 0) {
3783+
return BAD_FUNC_ARG;
3784+
}
3785+
/* if digest provided is smaller than key size then zero pad leading */
3786+
if (digestSz < signIn.digest.size) {
3787+
XMEMCPY(&signIn.digest.buffer[signIn.digest.size - digestSz], digest,
3788+
digestSz);
3789+
}
3790+
else {
3791+
XMEMCPY(signIn.digest.buffer, digest, digestSz);
3792+
}
37793793
signIn.inScheme.scheme = sigAlg;
37803794
signIn.inScheme.details.any.hashAlg = hashAlg;
37813795
signIn.validation.tag = TPM_ST_HASHCHECK;
@@ -3918,8 +3932,18 @@ int wolfTPM2_VerifyHashTicket(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key,
39183932

39193933
XMEMSET(&verifySigIn, 0, sizeof(verifySigIn));
39203934
verifySigIn.keyHandle = key->handle.hndl;
3921-
verifySigIn.digest.size = digestSz;
3922-
XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
3935+
verifySigIn.digest.size = TPM2_GetHashDigestSize(hashAlg);
3936+
if (verifySigIn.digest.size <= 0) {
3937+
return BAD_FUNC_ARG;
3938+
}
3939+
/* if digest provided is smaller than key size then zero pad leading */
3940+
if (digestSz < verifySigIn.digest.size) {
3941+
XMEMCPY(&verifySigIn.digest.buffer[verifySigIn.digest.size - digestSz],
3942+
digest, digestSz);
3943+
}
3944+
else {
3945+
XMEMCPY(verifySigIn.digest.buffer, digest, digestSz);
3946+
}
39233947
verifySigIn.signature.sigAlg = sigAlg;
39243948
verifySigIn.signature.signature.any.hashAlg = hashAlg;
39253949
if (key->pub.publicArea.type == TPM_ALG_ECC) {

tests/unit_tests.c

Lines changed: 180 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <wolftpm/tpm2.h>
2929
#include <wolftpm/tpm2_wrap.h>
3030
#include <wolftpm/tpm2_param_enc.h>
31+
#include <wolftpm/tpm2_asn.h>
3132

3233
#include <hal/tpm_io.h>
3334
#include <examples/tpm_test.h>
@@ -100,7 +101,8 @@ static void test_wolfTPM2_Init(void)
100101
AssertIntNE(rc, 0);
101102
/* Test second argument, TPM2 IO Callbacks */
102103
rc = wolfTPM2_Init(&dev, NULL, NULL);
103-
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || defined(WOLFTPM_WINAPI)
104+
#if defined(WOLFTPM_LINUX_DEV) || defined(WOLFTPM_SWTPM) || \
105+
defined(WOLFTPM_WINAPI)
104106
/* Custom IO Callbacks are not needed for Linux TIS driver */
105107
AssertIntEQ(rc, 0);
106108
#else
@@ -275,11 +277,12 @@ static void test_TPM2_PCRSel(void)
275277

276278
/* Test bad case - invalid PCR */
277279
XMEMSET(&pcr, 0, sizeof(pcr));
278-
pcrArray[0] = PCR_SELECT_MAX+1;
280+
pcrArray[0] = PCR_LAST+1;
279281
TPM2_SetupPCRSelArray(&pcr, TPM_ALG_SHA256, pcrArray, 1);
280282
if (pcr.count != 0) {
281283
rc = BAD_FUNC_ARG;
282284
}
285+
AssertIntEQ(rc, 0);
283286

284287
/* Test bad case - too many hash algorithms */
285288
XMEMSET(&pcr, 0, sizeof(pcr));
@@ -294,6 +297,7 @@ static void test_TPM2_PCRSel(void)
294297
if (pcr.count != HASH_COUNT) {
295298
rc = BAD_FUNC_ARG;
296299
}
300+
AssertIntEQ(rc, 0);
297301

298302
printf("Test TPM Wrapper:\tPCR Select Array:\t%s\n",
299303
rc == 0 ? "Passed" : "Failed");
@@ -345,7 +349,8 @@ static void test_TPM2_KDFa(void)
345349
0xd7, 0x04, 0xb6, 0x9a, 0x90, 0x2e, 0x9a, 0xde, 0x84, 0xc4};
346350
#endif
347351

348-
rc = TPM2_KDFa(TPM_ALG_SHA256, &keyIn, label, &contextU, &contextV, key, keyIn.size);
352+
rc = TPM2_KDFa(TPM_ALG_SHA256, &keyIn, label, &contextU, &contextV, key,
353+
keyIn.size);
349354
#ifdef WOLFTPM2_NO_WOLFCRYPT
350355
AssertIntEQ(NOT_COMPILED_IN, rc);
351356
#else
@@ -396,6 +401,172 @@ static void test_wolfTPM2_CSR(void)
396401
#endif
397402
}
398403

404+
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
405+
!defined(WOLFTPM2_NO_ASN)
406+
static void test_wolfTPM2_EccSignVerifyDig(WOLFTPM2_DEV* dev,
407+
WOLFTPM2_KEY* storageKey, const byte* digest, int digestSz,
408+
TPM_ECC_CURVE curve, TPMI_ALG_HASH hashAlg)
409+
{
410+
int rc;
411+
int verifyRes = 0;
412+
WOLFTPM2_KEY eccKey;
413+
TPMT_PUBLIC publicTemplate;
414+
byte sigRs[MAX_ECC_BYTES*2];
415+
word32 sigRsSz = (word32)sizeof(sigRs);
416+
byte sig[ECC_MAX_SIG_SIZE];
417+
word32 sigSz;
418+
byte *r, *s;
419+
word32 rLen, sLen;
420+
ecc_key wolfKey;
421+
int curveSize = TPM2_GetCurveSize(curve);
422+
423+
/* -- Use TPM key to sign and verify with wolfCrypt -- */
424+
/* Create ECC key for signing */
425+
rc = wolfTPM2_GetKeyTemplate_ECC_ex(&publicTemplate, hashAlg,
426+
(TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth |
427+
TPMA_OBJECT_sign | TPMA_OBJECT_noDA),
428+
curve, TPM_ALG_ECDSA, hashAlg);
429+
AssertIntEQ(rc, 0);
430+
rc = wolfTPM2_CreateAndLoadKey(dev, &eccKey, &storageKey->handle,
431+
&publicTemplate, (byte*)gKeyAuth, sizeof(gKeyAuth)-1);
432+
if ((rc & TPM_RC_HASH) == TPM_RC_HASH) {
433+
printf("Hash type not supported... Skipping\n");
434+
return;
435+
}
436+
AssertIntEQ(rc, 0);
437+
438+
/* Sign with TPM */
439+
rc = wolfTPM2_SignHashScheme(dev, &eccKey, digest, digestSz,
440+
sigRs, (int*)&sigRsSz, TPM_ALG_ECDSA, hashAlg);
441+
AssertIntEQ(rc, 0);
442+
443+
/* Make sure leading zero's not required are trimmed */
444+
rLen = sLen = sigRsSz / 2;
445+
r = &sigRs[0];
446+
s = &sigRs[rLen];
447+
r = TPM2_ASN_TrimZeros(r, &rLen);
448+
s = TPM2_ASN_TrimZeros(s, &sLen);
449+
450+
/* Encode ECDSA Header */
451+
sigSz = (word32)sizeof(sig);
452+
rc = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, sig, &sigSz);
453+
AssertIntEQ(rc, 0);
454+
455+
/* Initialize wolfCrypt ECC key */
456+
rc = wc_ecc_init(&wolfKey);
457+
AssertIntEQ(rc, 0);
458+
459+
/* Convert TPM key to wolfCrypt key for verification */
460+
rc = wolfTPM2_EccKey_TpmToWolf(dev, &eccKey, &wolfKey);
461+
AssertIntEQ(rc, 0);
462+
463+
/* Verify TPM signature with wolfCrypt */
464+
rc = wc_ecc_verify_hash(sig, sigSz, digest, digestSz, &verifyRes, &wolfKey);
465+
AssertIntEQ(rc, 0);
466+
AssertIntEQ(verifyRes, 1); /* 1 indicates successful verification */
467+
468+
/* Cleanup first wolfCrypt key */
469+
wc_ecc_free(&wolfKey);
470+
wolfTPM2_UnloadHandle(dev, &eccKey.handle);
471+
472+
473+
/* -- Use wolfCrypt key to sign and verify with TPM -- */
474+
/* Initialize new wolfCrypt ECC key */
475+
rc = wc_ecc_init(&wolfKey);
476+
AssertIntEQ(rc, 0);
477+
478+
/* Generate new ECC key with wolfCrypt */
479+
rc = wc_ecc_make_key(wolfTPM2_GetRng(dev), curveSize, &wolfKey);
480+
AssertIntEQ(rc, 0);
481+
482+
/* Sign with wolfCrypt */
483+
sigSz = (word32)sizeof(sig);
484+
rc = wc_ecc_sign_hash(digest, digestSz, sig, &sigSz, wolfTPM2_GetRng(dev),
485+
&wolfKey);
486+
AssertIntEQ(rc, 0);
487+
488+
/* Decode ECDSA Header */
489+
r = sigRs;
490+
s = &sigRs[MAX_ECC_BYTES];
491+
rLen = sLen = MAX_ECC_BYTES;
492+
rc = wc_ecc_sig_to_rs(sig,
493+
sigSz, r, &rLen, s, &sLen);
494+
AssertIntEQ(rc, 0);
495+
496+
/* Convert wolfCrypt key to TPM key for verification */
497+
rc = wolfTPM2_EccKey_WolfToTpm(dev, &wolfKey, &eccKey);
498+
AssertIntEQ(rc, 0);
499+
500+
/* combine R and S at key size (zero pad leading) */
501+
XMEMCPY(&sigRs[curveSize-rLen], r, rLen);
502+
XMEMSET(&sigRs[0], 0, curveSize-rLen);
503+
XMEMCPY(&sigRs[curveSize + (curveSize-sLen)], s, sLen);
504+
XMEMSET(&sigRs[curveSize], 0, curveSize-sLen);
505+
506+
/* Verify wolfCrypt signature with TPM */
507+
rc = wolfTPM2_VerifyHashScheme(dev, &eccKey, sigRs, curveSize*2,
508+
digest, digestSz, TPM_ALG_ECDSA, hashAlg);
509+
AssertIntEQ(rc, 0);
510+
511+
/* Cleanup */
512+
wc_ecc_free(&wolfKey);
513+
wolfTPM2_UnloadHandle(dev, &eccKey.handle);
514+
515+
printf("Test TPM Wrapper:\t"
516+
"Sign/Verify (DigSz=%d, CurveSz=%d, Hash=%s):"
517+
"\t%s\n",
518+
digestSz, TPM2_GetCurveSize(curve), TPM2_GetAlgName(hashAlg),
519+
rc == 0 ? "Passed" : "Failed");
520+
}
521+
522+
/* Test with smaller, same and larger digest sizes using different ECC curves.
523+
* Interop sign and verify with wolfCrypt and TPM */
524+
static void test_wolfTPM2_EccSignVerify(void)
525+
{
526+
int rc, i;
527+
byte digest[TPM_MAX_DIGEST_SIZE];
528+
WOLFTPM2_DEV dev;
529+
WOLFTPM2_KEY storageKey;
530+
531+
/* Initialize TPM */
532+
rc = wolfTPM2_Init(&dev, TPM2_IoCb, NULL);
533+
AssertIntEQ(rc, 0);
534+
535+
/* Create storage key */
536+
rc = wolfTPM2_CreateSRK(&dev, &storageKey, TPM_ALG_ECC,
537+
(byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1);
538+
AssertIntEQ(rc, 0);
539+
540+
541+
for (i = 0; i < (int)sizeof(digest); i++) {
542+
digest[i] = (byte)i;
543+
}
544+
545+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 20,
546+
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
547+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 32,
548+
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
549+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 48,
550+
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
551+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 64,
552+
TPM_ECC_NIST_P256, TPM_ALG_SHA256);
553+
554+
#if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
555+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 20,
556+
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
557+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 32,
558+
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
559+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 48,
560+
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
561+
test_wolfTPM2_EccSignVerifyDig(&dev, &storageKey, digest, 64,
562+
TPM_ECC_NIST_P384, TPM_ALG_SHA384);
563+
#endif
564+
565+
wolfTPM2_UnloadHandle(&dev, &storageKey.handle);
566+
wolfTPM2_Cleanup(&dev);
567+
}
568+
#endif
569+
399570
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(WOLFTPM2_PEM_DECODE) && \
400571
!defined(NO_RSA)
401572
static WOLFTPM2_KEY authKey; /* also used for test_wolfTPM2_PCRPolicy */
@@ -479,7 +650,8 @@ static void test_wolfTPM2_PCRPolicy(void)
479650
digest, &digestSz, NULL, 0);
480651
AssertIntEQ(rc, 0);
481652

482-
AssertIntEQ(XMEMCMP(digest, expectedPolicyAuth, sizeof(expectedPolicyAuth)), 0);
653+
AssertIntEQ(XMEMCMP(digest, expectedPolicyAuth, sizeof(expectedPolicyAuth)),
654+
0);
483655

484656
rc = wolfTPM2_ResetPCR(&dev, pcrIndex);
485657
AssertIntEQ(rc, 0);
@@ -679,6 +851,10 @@ int unit_tests(int argc, char *argv[])
679851
#endif
680852
test_wolfTPM2_KeyBlob(TPM_ALG_RSA);
681853
test_wolfTPM2_KeyBlob(TPM_ALG_ECC);
854+
#if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) && \
855+
!defined(WOLFTPM2_NO_ASN)
856+
test_wolfTPM2_EccSignVerify();
857+
#endif
682858
test_wolfTPM2_Cleanup();
683859
test_wolfTPM2_thread_local_storage();
684860
#endif /* !WOLFTPM2_NO_WRAPPER */

0 commit comments

Comments
 (0)