From c42fff4f7fc3fb73b1690e0941e0f12278ca623c Mon Sep 17 00:00:00 2001 From: David Garske Date: Thu, 23 Jan 2025 16:02:28 -0800 Subject: [PATCH] EK Cert Verification with TPM only (no wolfCrypt). Example assumes ST33KTPM2X. `./configure --disable-wolfcrypt && make && ./examples/endorsement/verify_ek_cert` --- .gitignore | 1 + examples/endorsement/README.md | 236 +++++++++ examples/endorsement/endorsement.h | 1 + examples/endorsement/get_ek_certs.c | 12 +- examples/endorsement/include.am | 15 +- examples/endorsement/trusted_certs.h | 42 ++ examples/endorsement/trusted_certs_der.h | 137 +++++ examples/endorsement/verify_ek_cert.c | 646 +++++++++++++++++++++++ 8 files changed, 1085 insertions(+), 5 deletions(-) create mode 100644 examples/endorsement/trusted_certs_der.h create mode 100644 examples/endorsement/verify_ek_cert.c diff --git a/.gitignore b/.gitignore index a65ce02..3f87523 100644 --- a/.gitignore +++ b/.gitignore @@ -84,6 +84,7 @@ examples/boot/secret_unseal examples/firmware/ifx_fw_extract examples/firmware/ifx_fw_update examples/endorsement/get_ek_certs +examples/endorsement/verify_ek_cert # Generated Cert Files certs/ca-*.pem diff --git a/examples/endorsement/README.md b/examples/endorsement/README.md index 5e0856c..d346747 100644 --- a/examples/endorsement/README.md +++ b/examples/endorsement/README.md @@ -44,3 +44,239 @@ Example: - STSAFE-TPM RSA intermediate CA 10 (http://sw-center.st.com/STSAFE/stsafetpmrsaint10.crt) - STSAFE ECC root CA 02 (http://sw-center.st.com/STSAFE/STSAFEEccRootCA02.crt) - STSAFE-TPM ECC intermediate CA 10 (http://sw-center.st.com/STSAFE/stsafetpmeccint10.crt) + +Sample Output: + +``` +$ ./examples/endorsement/verify_ek_cert +Endorsement Certificate Verify +TPM2: Caps 0x30000415, Did 0x0004, Vid 0x104a, Rid 0x 1 +TPM2_Startup pass +TPM2_NV_ReadPublic: Sz 14, Idx 0x1c00002, nameAlg 11, Attr 0x62076801, authPol 0, dataSz 1300, name 34 +TPM2_NV_ReadPublic: Sz 14, Idx 0x1c00002, nameAlg 11, Attr 0x62076801, authPol 0, dataSz 1300, name 34 +TPM2_NV_Read: Auth 0x1c00002, Idx 0x1c00002, Offset 0, Size 768 +TPM2_NV_Read: Auth 0x1c00002, Idx 0x1c00002, Offset 768, Size 532 +EK Data: 1300 + 30 82 05 10 30 82 02 f8 a0 03 02 01 02 02 14 58 | 0...0..........X + 63 86 17 74 73 22 ca 34 60 4a f6 cf d9 b4 44 9e | c..ts".4`J....D. + 4b ba 03 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0c | K..0...*.H...... + 05 00 30 59 31 0b 30 09 06 03 55 04 06 13 02 43 | ..0Y1.0...U....C + 48 31 1e 30 1c 06 03 55 04 0a 13 15 53 54 4d 69 | H1.0...U....STMi + 63 72 6f 65 6c 65 63 74 72 6f 6e 69 63 73 20 4e | croelectronics N + 56 31 2a 30 28 06 03 55 04 03 13 21 53 54 53 41 | V1*0(..U...!STSA + 46 45 20 54 50 4d 20 52 53 41 20 49 6e 74 65 72 | FE TPM RSA Inter + 6d 65 64 69 61 74 65 20 43 41 20 32 30 30 20 17 | mediate CA 200 . + 0d 32 33 30 36 30 31 30 39 34 39 33 35 5a 18 0f | .230601094935Z.. + 39 39 39 39 31 32 33 31 32 33 35 39 35 39 5a 30 | 99991231235959Z0 + 00 30 82 01 22 30 0d 06 09 2a 86 48 86 f7 0d 01 | .0.."0...*.H.... + 01 01 05 00 03 82 01 0f 00 30 82 01 0a 02 82 01 | .........0...... + 01 00 b3 20 db 1a 10 d2 16 8c 5d 92 c0 47 87 b1 | ... ......]..G.. + dc ae af 5b f2 44 15 dd 84 9a 17 3f c6 76 61 29 | ...[.D.....?.va) + c6 c3 4c e5 50 27 a2 26 8b fd e0 9d 34 09 93 0f | ..L.P'.&....4... + 64 6a b0 46 f5 5b 19 1c 14 45 b7 24 d3 a9 a5 7d | dj.F.[...E.$...} + 4c a7 0a ba cc d4 72 a2 18 2e 1a 20 a5 33 6f 5f | L.....r.... .3o_ + f5 21 10 bf db af 74 7f 97 93 46 64 40 16 c2 e9 | .!....t...Fd@... + 8f cc e0 f2 4a 94 29 4e 73 87 6f a4 bb c8 f3 e1 | ....J.)Ns.o..... + 02 35 12 c9 c7 e8 4c f2 59 94 5f d2 5a ca 35 48 | .5....L.Y._.Z.5H + e3 0d 59 90 41 33 10 cd 4b f5 ff a7 0c 4e 94 ce | ..Y.A3..K....N.. + 86 45 fb 89 aa b4 76 10 8e ed 90 1e bf b9 6b 88 | .E....v.......k. + df 5a 1a b7 b5 cb a8 80 ff cf 4d a8 c1 05 b6 15 | .Z........M..... + 49 8d 22 74 29 56 95 56 e5 1d 4f 31 44 da 77 3c | I."t)V.V..O1D.w< + a7 46 a3 e2 d5 ee 18 51 0c 9c 51 52 49 ff d1 ba | .F.....Q..QRI... + 4f cd 33 42 0d 8e e9 c8 da a0 ff 10 02 0d dd e4 | O.3B............ + fa 49 21 98 e9 28 c7 c5 25 ac 7b 90 91 99 fb 99 | .I!..(..%.{..... + 36 63 dc 50 98 fa fd 32 37 c2 08 9c 43 fc 59 d6 | 6c.P...27...C.Y. + 27 5f 02 03 01 00 01 a3 82 01 25 30 82 01 21 30 | '_........%0..!0 + 1f 06 03 55 1d 23 04 18 30 16 80 14 8f e0 78 f8 | ...U.#..0.....x. + ca 88 59 fe fe 3f 7a 98 37 2c fc 02 c6 08 44 49 | ..Y..?z.7,....DI + 30 58 06 03 55 1d 11 01 01 ff 04 4e 30 4c a4 4a | 0X..U......N0L.J + 30 48 31 16 30 14 06 05 67 81 05 02 01 0c 0b 69 | 0H1.0...g......i + 64 3a 35 33 35 34 34 44 32 30 31 16 30 14 06 05 | d:53544D201.0... + 67 81 05 02 02 0c 0b 53 54 33 33 4b 54 50 4d 32 | g......ST33KTPM2 + 41 49 31 16 30 14 06 05 67 81 05 02 03 0c 0b 69 | AI1.0...g......i + 64 3a 30 30 30 41 30 31 30 31 30 22 06 03 55 1d | d:000A01010"..U. + 09 04 1b 30 19 30 17 06 05 67 81 05 02 10 31 0e | ...0.0...g....1. + 30 0c 0c 03 32 2e 30 02 01 00 02 02 00 9f 30 0c | 0...2.0.......0. + 06 03 55 1d 13 01 01 ff 04 02 30 00 30 10 06 03 | ..U.......0.0... + 55 1d 25 04 09 30 07 06 05 67 81 05 08 01 30 0e | U.%..0...g....0. + 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 20 30 50 | ..U.......... 0P + 06 08 2b 06 01 05 05 07 01 01 04 44 30 42 30 40 | ..+........D0B0@ + 06 08 2b 06 01 05 05 07 30 02 86 34 68 74 74 70 | ..+.....0..4http + 3a 2f 2f 73 77 2d 63 65 6e 74 65 72 2e 73 74 2e | ://sw-center.st. + 63 6f 6d 2f 53 54 53 41 46 45 2f 73 74 73 61 66 | com/STSAFE/stsaf + 65 74 70 6d 72 73 61 69 6e 74 32 30 2e 63 72 74 | etpmrsaint20.crt + 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0c 05 00 03 | 0...*.H......... + 82 02 01 00 b5 7a 68 4d aa d5 3a bf a2 6a 6f 1d | .....zhM..:..jo. + 1a 5e 35 74 47 f4 b7 ee a0 63 8e 08 42 8c a3 80 | .^5tG....c..B... + 3a 91 8e 92 1a 22 73 c8 a6 07 61 42 63 5f 4e c7 | :...."s...aBc_N. + 17 dc 5e c2 51 73 13 51 0f 57 17 01 63 9e da b5 | ..^.Qs.Q.W..c... + 4a fd 92 6d 0a 33 8b e4 dc 5f 63 96 7b 89 d3 3a | J..m.3..._c.{..: + 99 29 ac f0 7c 0a 99 ea 9c 40 33 86 4b 55 30 03 | .)..|....@3.KU0. + 24 41 05 f6 48 43 5f b9 39 b4 74 17 2c 71 bf 26 | $A..HC_.9.t.,q.& + f4 a3 7a 9f ae 80 0c 8b 92 c8 22 35 0f f8 64 da | ..z......."5..d. + 50 b1 2f 5f e2 a4 19 32 a6 7e 74 bb 31 74 93 10 | P./_...2.~t.1t.. + 85 a2 5f 10 9f 1d 0c 57 90 d2 56 e4 70 7f 54 99 | .._....W..V.p.T. + 87 c0 bd d7 8f c4 31 eb 9d bc cd ca 35 b2 64 d0 | ......1.....5.d. + ee 6b c8 e1 1b 34 bc 09 3f cd d1 f1 53 c2 18 dd | .k...4..?...S... + 82 85 2e 6c 44 9b 21 df eb 7b 5b 8f 07 f5 61 34 | ...lD.!..{[...a4 + 25 e5 97 ee bd 01 2e 1c 35 53 00 b0 be 92 96 80 | %.......5S...... + 50 9b 6e e0 f3 e3 1d 0c 0a 99 96 cd 42 64 e4 43 | P.n.........Bd.C + 6a 4a de c2 03 19 a2 a7 b6 fa 7d 25 37 04 53 30 | jJ........}%7.S0 + 3a 69 b2 38 6c c9 e9 e3 59 a4 8b 1e ae 62 5d eb | :i.8l...Y....b]. + 3c 85 e3 2f f1 cb 7b 3c 0d 2d bf 6e f0 9c 7c c9 | <../..{<.-.n..|. + c8 84 35 26 21 82 2a 83 f7 54 80 51 73 34 c2 7b | ..5&!.*..T.Qs4.{ + 2b 5d 32 b7 26 a6 8c b2 46 d6 c2 63 5c 38 0c 0b | +]2.&...F..c\8.. + 5e ba 81 ee 0b 55 c6 e7 ab 48 8d 6a e4 c7 ec 45 | ^....U...H.j...E + 0d 46 b9 2e 8e a9 be e1 26 b4 79 b5 56 4c 2a dd | .F......&.y.VL*. + 93 22 01 d5 2c ca bd c0 6a 30 ff 53 8c 08 98 22 | ."..,...j0.S..." + 33 3c 78 a1 59 25 43 cc db e1 26 cc 55 7f bb 4b | 3 +#endif + +#include + +#include + +#ifndef WOLFTPM2_NO_WRAPPER + +#include +#include + +#include "trusted_certs_der.h" + +#ifndef WOLFTPM2_NO_WOLFCRYPT +#include +#include +#endif + +#ifndef MAX_CERT_SZ +#define MAX_CERT_SZ 2048 +#endif + + +#ifdef WOLFTPM2_NO_WOLFCRYPT +#define ASN_SEQUENCE 0x10 +#define ASN_CONSTRUCTED 0x20 +#define ASN_CONTEXT_SPECIFIC 0x80 + +#define ASN_LONG_LENGTH 0x80 /* indicates additional length fields */ + +#define ASN_INTEGER 0x02 +#define ASN_BIT_STRING 0x03 +#define ASN_OCTET_STRING 0x04 +#define ASN_TAG_NULL 0x05 +#define ASN_OBJECT_ID 0x06 +#endif + +#if defined(WOLFTPM2_NO_WOLFCRYPT) || defined(NO_RSA) +#define RSA_BLOCK_TYPE_1 1 +#define RSA_BLOCK_TYPE_2 2 +#endif + +typedef struct DecodedX509 { + word32 certBegin; + byte* cert; /* pointer to start of cert */ + word32 certSz; + byte* publicKey; /* pointer to public key */ + word32 pubKeySz; + byte* signature; /* pointer to signature */ + word32 sigSz; /* length of signature */ +} DecodedX509; + + +static void usage(void) +{ + printf("Expected usage:\n"); + printf("./examples/endorsement/verify_ek_cert\n"); +} + +static void dump_hex_bytes(const byte* buf, word32 sz) +{ + word32 i; + /* Print as : separated hex bytes - max 15 bytes per line */ + printf("\t"); + for (i=0; i0 && ((i+1)%16)==0) printf("\n\t"); + } + } + printf("\n"); +} + +/* Display EK public information */ +static void show_tpm_public(const char* desc, const TPM2B_PUBLIC* pub) +{ + printf("%s %s, Hash: %s, objAttr: 0x%X\n", + desc, + TPM2_GetAlgName(pub->publicArea.type), + TPM2_GetAlgName(pub->publicArea.nameAlg), + (unsigned int)pub->publicArea.objectAttributes); + + /* parameters and unique field depend on algType */ + if (pub->publicArea.type == TPM_ALG_RSA) { + printf("\tKeyBits: %d, exponent: 0x%X, unique size %d\n", + pub->publicArea.parameters.rsaDetail.keyBits, + (unsigned int)pub->publicArea.parameters.rsaDetail.exponent, + pub->publicArea.unique.rsa.size); + dump_hex_bytes(pub->publicArea.unique.rsa.buffer, + pub->publicArea.unique.rsa.size); + } + else if (pub->publicArea.type == TPM_ALG_ECC) { + const char* curveName = "NULL"; + #if !defined(WOLFTPM2_NO_WOLFCRYPT) && defined(HAVE_ECC) + curveName = wc_ecc_get_name( + TPM2_GetWolfCurve(pub->publicArea.parameters.eccDetail.curveID)); + #endif + printf("\tCurveID %s (0x%x), size %d, unique X/Y size %d/%d\n", + curveName, pub->publicArea.parameters.eccDetail.curveID, + TPM2_GetCurveSize(pub->publicArea.parameters.eccDetail.curveID), + pub->publicArea.unique.ecc.x.size, + pub->publicArea.unique.ecc.y.size); + dump_hex_bytes(pub->publicArea.unique.ecc.x.buffer, + pub->publicArea.unique.ecc.x.size); + dump_hex_bytes(pub->publicArea.unique.ecc.y.buffer, + pub->publicArea.unique.ecc.y.size); + } +} + +static int DecodeAsn1Tag(const uint8_t* input, int inputSz, int* inOutIdx, + int* tag_len, uint8_t tag) +{ + int rc = -1; /* default to fail case */ + int tag_len_bytes = 1; + + *tag_len = 0; /* reset tag length */ + if (input[*inOutIdx] == tag) { /* check tag is expected */ + (*inOutIdx)++; /* skip asn.1 tag */ + if (input[*inOutIdx] & ASN_LONG_LENGTH) { + tag_len_bytes = (int)(input[*inOutIdx] & 0x7F); + if (tag_len_bytes > 4) { + return -1; /* too long */ + } + (*inOutIdx)++; /* skip long length field */ + } + while (tag_len_bytes--) { + *tag_len = (*tag_len << 8) | input[*inOutIdx]; + (*inOutIdx)++; /* skip length */ + } + if (*tag_len + *inOutIdx <= inputSz) { /* check length */ + rc = 0; + } + } + return rc; +} + +static int RsaDecodeSignature(uint8_t** pInput, int inputSz) +{ + int rc; + uint8_t* input = *pInput; + int idx = 0; + int tot_len, algo_len, digest_len = 0; + + /* sequence - total size */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &tot_len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + if (rc == 0) { + /* sequence - algoid */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &algo_len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + idx += algo_len; /* skip algoid */ + + /* digest */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &digest_len, ASN_OCTET_STRING); + } + if (rc == 0) { + /* return digest buffer pointer */ + *pInput = &input[idx]; + + rc = digest_len; + } + return rc; +} + +static int DecodeX509Cert(uint8_t* input, int inputSz, DecodedX509* x509) +{ + int rc; + int idx = 0; + int tot_len, cert_len = 0, len, pubkey_len = 0, sig_len = 0; + + /* sequence - total size */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &tot_len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + if (rc == 0) { + x509->certBegin = idx; + x509->cert = &input[idx]; + + /* sequence - cert */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &cert_len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + x509->certSz = cert_len + (idx - x509->certBegin); + /* cert - version */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED)); + } + if (rc == 0) { + /* check version == 1 */ + if (input[idx] != ASN_INTEGER && input[idx] != 1) { + rc = -1; + } + } + if (rc == 0) { + idx += len; /* skip version */ + + /* cert - serial */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, ASN_INTEGER); + } + if (rc == 0) { + idx += len; /* skip serial */ + + /* cert - signature oid */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + idx += len; /* skip signature oid */ + + /* cert - issuer */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + idx += len; /* skip issuer */ + + /* cert - validity */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + idx += len; /* skip validity */ + + /* cert - subject */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + idx += len; /* skip subject */ + + /* cert - subject public key info */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + /* cert - subject public key alg oid */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + idx += len; /* skip alg oid */ + + /* cert - subject public key alg params */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &pubkey_len, + ASN_BIT_STRING); + } + + if (rc == 0) { + /* skip leading zero for bit string */ + if (input[idx] == 0x00) { + idx++; + pubkey_len--; + } + /* return pointer to public key */ + x509->publicKey = &input[idx]; + x509->pubKeySz = pubkey_len; + } + if (rc == 0) { + /* skip to start of signature */ + idx = x509->certBegin + x509->certSz; + + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + } + if (rc == 0) { + /* signature oid */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, ASN_OBJECT_ID); + } + if (rc == 0) { + idx += len; /* skip oid */ + /* sig algo params */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &len, ASN_TAG_NULL); + } + if (rc == 0) { + idx += len; /* skip tag */ + + /* signature bit string */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &sig_len, + ASN_BIT_STRING); + } + if (rc == 0) { + /* skip leading zero for bit string */ + if (input[idx] == 0x00) { + idx++; + sig_len--; + } + + /* signature */ + x509->sigSz = sig_len; + x509->signature = &input[idx]; + } + + return rc; +} + +static int DecodeRsaPubKey(uint8_t* input, int inputSz, TPM2B_PUBLIC* pub) +{ + int rc; + int idx = 0; + int tot_len, mod_len = 0, exp_len = 0; + + /* sequence - total size */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &tot_len, + (ASN_SEQUENCE | ASN_CONSTRUCTED)); + if (rc == 0) { + /* modulus */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &mod_len, ASN_INTEGER); + } + if (rc == 0) { + /* skip leading zero if exists */ + if (input[idx] == 0x00) { + idx++; + mod_len--; + } + if (mod_len > (int)sizeof(pub->publicArea.unique.rsa.buffer)) { + rc = -1; + } + } + if (rc == 0) { + /* Populate Modulus */ + pub->publicArea.parameters.rsaDetail.keyBits = mod_len * 8; + pub->publicArea.unique.rsa.size = mod_len; + XMEMCPY(pub->publicArea.unique.rsa.buffer, &input[idx], mod_len); + } + if (rc == 0) { + idx += mod_len; /* skip modulus */ + + /* exponent */ + rc = DecodeAsn1Tag(input, inputSz, &idx, &exp_len, ASN_INTEGER); + /* skip leading zero if exists */ + if (input[idx] == 0x00) { + idx++; + exp_len--; + } + if (exp_len > + (int)sizeof(pub->publicArea.parameters.rsaDetail.exponent)) { + rc = -1; + } + } + if (rc == 0) { + XMEMCPY(&pub->publicArea.parameters.rsaDetail.exponent, &input[idx], + exp_len); + } + return rc; +} + +static int RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz) +{ + int rc = -1; /* default to error */ + uint8_t* sig = *pSig; + int idx = 0; + + /* RSA PKCSv1.5 unpad */ + if (sig[idx++] == 0x00 && sig[idx++] == RSA_BLOCK_TYPE_1) { + + /* skip padding 0xFF's */ + while (idx < *sigSz) { + if (sig[idx] != 0xFF) + break; + idx++; + } + + /* verify 0x00 after pad */ + if (sig[idx++] == 0x00) { + /* success unpadding */ + rc = 0; + *pSig = &sig[idx]; + *sigSz -= idx; + } + } + return rc; +} + +int TPM2_EndorsementCertVerify_Example(void* userCtx, int argc, char *argv[]) +{ + int rc = -1; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY endorse; + TPMS_NV_PUBLIC nvPublic; + WOLFTPM2_KEY issuer; + WOLFTPM2_NV nv; + WOLFTPM2_HASH hash; + TPMT_PUBLIC publicTemplate; + TPM2B_PUBLIC ekPub; + DecodedX509 issuerX509, ekX509; + + uint32_t nvIndex = TPM2_NV_RSA_EK_CERT; /* RSA 2048-bit EK Cert Index */ + uint8_t cert[MAX_CERT_SZ]; /* buffer to hold device cert from NV */ + uint32_t certSz; + TPM_ALG_ID hashAlg = TPM_ALG_SHA384; /* Signer uses SHA2-384 */ + uint8_t hashBuf[TPM_MAX_DIGEST_SIZE]; /* hash of device cert, for verify */ + uint32_t hashSz = 0; + uint8_t sig[512]; /* 4096-bit max, hold decrypted signature */ + int sigSz = (int)sizeof(sig); + uint8_t* sigDigest; /* offset to digest in signature */ + int sigDigestSz = 0; + + XMEMSET(&endorse, 0, sizeof(endorse)); + XMEMSET(&nvPublic, 0, sizeof(nvPublic)); + XMEMSET(&issuer, 0, sizeof(issuer)); + XMEMSET(&nv, 0, sizeof(nv)); + XMEMSET(&hash, 0, sizeof(hash)); + XMEMSET(&issuerX509, 0, sizeof(issuerX509)); + XMEMSET(&ekX509, 0, sizeof(ekX509)); + XMEMSET(&ekPub, 0, sizeof(ekPub)); + + if (argc >= 2) { + if (XSTRCMP(argv[1], "-?") == 0 || + XSTRCMP(argv[1], "-h") == 0 || + XSTRCMP(argv[1], "--help") == 0) { + usage(); + return 0; + } + } + + printf("Endorsement Certificate Verify\n"); + + rc = wolfTPM2_Init(&dev, TPM2_IoCb, userCtx); + if (rc != TPM_RC_SUCCESS) { + printf("wolfTPM2_Init failed 0x%x: %s\n", rc, TPM2_GetRCString(rc)); + goto exit; + } + + /* Get Endorsement Public Key template using NV index */ + rc = wolfTPM2_GetKeyTemplate_EKIndex(nvIndex, &publicTemplate); + if (rc != 0) { + printf("EK Index 0x%08x not valid\n", nvIndex); + goto exit; + } + + /* Read Public portion of NV to get actual size */ + if (rc == 0) + rc = wolfTPM2_NVReadPublic(&dev, nvIndex, &nvPublic); + if (rc != 0) { + printf("Failed to read public for NV Index 0x%08x\n", nvIndex); + } + if (rc == 0) { /* Read data */ + certSz = (uint32_t)sizeof(cert); + if (certSz > nvPublic.dataSize) { + certSz = nvPublic.dataSize; + } + rc = wolfTPM2_NVReadAuth(&dev, &nv, nvIndex, cert, &certSz, 0); + if (rc == 0) { + #ifdef DEBUG_WOLFTPM + printf("EK Data: %d\n", certSz); + TPM2_PrintBin(cert, certSz); + #endif + } + } + + /* Create Endorsement Key */ + if (rc == 0) { + /* Create Endorsement Key using EK auth policy */ + printf("Creating Endorsement Key\n"); + rc = wolfTPM2_CreatePrimaryKey(&dev, &endorse, TPM_RH_ENDORSEMENT, + &publicTemplate, NULL, 0); + if (rc != 0) goto exit; + printf("Endorsement key loaded at handle 0x%08x\n", + endorse.handle.hndl); + + /* Display EK public information */ + show_tpm_public("EK", &endorse.pub); + } + + if (rc == 0) { + /* Parse device certificate and extract public key */ + rc = DecodeX509Cert(cert, certSz, &ekX509); + if (rc == 0) { + /* Parse RSA Public Key Raw Modulus */ + rc = DecodeRsaPubKey((uint8_t*)ekX509.publicKey, ekX509.pubKeySz, + &ekPub); + } + } + + if (rc == 0) { + /* Compare certificate public key with generated EK public key */ + if (ekPub.publicArea.unique.rsa.size != + endorse.pub.publicArea.unique.rsa.size || + XMEMCMP(ekPub.publicArea.unique.rsa.buffer, + endorse.pub.publicArea.unique.rsa.buffer, + endorse.pub.publicArea.unique.rsa.size) != 0) + { + printf("Error: Generated EK public key does not match NV cert " + "public key!\n"); + rc = -1; + } + } + + if (rc == 0) { + /* Hash certificate (excluding signature) */ + rc = wolfTPM2_HashStart(&dev, &hash, hashAlg, NULL, 0); + if (rc == 0) { + rc = wolfTPM2_HashUpdate(&dev, &hash, ekX509.cert, ekX509.certSz); + if (rc == 0) { + hashSz = sizeof(hashBuf); + rc = wolfTPM2_HashFinish(&dev, &hash, hashBuf, &hashSz); + } + + printf("Cert Hash: %d\n", hashSz); + dump_hex_bytes(hashBuf, hashSz); + } + } + + if (rc == 0) { + /* Parse and extract the issuer's public key modulus from certificate */ + rc = DecodeX509Cert((uint8_t*)kSTSAFEIntCa20, + (int)sizeof(kSTSAFEIntCa20), &issuerX509); + if (rc == 0) { + /* Parse RSA Public Key Raw Modulus */ + rc = DecodeRsaPubKey((uint8_t*)issuerX509.publicKey, + issuerX509.pubKeySz, &issuer.pub); + } + } + if (rc == 0) { + printf("Issuer Public Exponent 0x%x, Modulus %d\n", + issuer.pub.publicArea.parameters.rsaDetail.exponent, + issuer.pub.publicArea.unique.rsa.size); + dump_hex_bytes(issuer.pub.publicArea.unique.rsa.buffer, + issuer.pub.publicArea.unique.rsa.size); + + /* Import issuer certificate public key */ + issuer.pub.publicArea.type = TPM_ALG_RSA; + issuer.pub.publicArea.nameAlg = hashAlg; + issuer.pub.publicArea.objectAttributes = (TPMA_OBJECT_decrypt); + issuer.pub.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL; + issuer.pub.publicArea.parameters.rsaDetail.scheme.details.anySig.hashAlg = hashAlg; + issuer.pub.publicArea.parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL; + rc = wolfTPM2_LoadPublicKey(&dev, &issuer, &issuer.pub); + } + + if (rc == 0) { + /* Display Cert public information */ + show_tpm_public("Issuer", &issuer.pub); + + printf("EK Certificate Signature: %d\n", ekX509.sigSz); + dump_hex_bytes(ekX509.signature, ekX509.sigSz); + + /* RSA Public Decrypt EK certificate signature */ + rc = wolfTPM2_RsaEncrypt(&dev, &issuer, + TPM_ALG_NULL, /* no padding */ + ekX509.signature, ekX509.sigSz, + sig, &sigSz); + if (rc != 0) { + printf("RSA Public Failed!\n"); + goto exit; + } + printf("Decrypted Sig: %d\n", sigSz); + dump_hex_bytes(sig, sigSz); + } + + if (rc == 0) { + sigDigest = sig; + rc = RsaUnpadPkcsv15(&sigDigest, &sigSz); + } + if (rc == 0) { + rc = RsaDecodeSignature(&sigDigest, sigSz); + if (rc > 0) { + sigDigestSz = rc; + rc = 0; + } + } + if (rc == 0) { + printf("Expected Hash: %d\n", hashSz); + dump_hex_bytes(hashBuf, hashSz); + + printf("Sig Hash: %d\n", sigDigestSz); + dump_hex_bytes(sigDigest, sigDigestSz); + + /* Compare certificate hash with signature hash */ + if (sigDigestSz == (int)hashSz && + memcmp(sigDigest, hashBuf, hashSz) == 0) { + printf("Certificate signature is valid\n"); + } + else { + printf("Error: Certificate signature is invalid!\n"); + rc = -1; + } + } + +exit: + + if (rc != 0) { + printf("Error verifying EK certificate! %s (%d)\n", + TPM2_GetRCString(rc), rc); + } + + wolfTPM2_UnloadHandle(&dev, &issuer.handle); + wolfTPM2_UnloadHandle(&dev, &endorse.handle); + wolfTPM2_Cleanup(&dev); + + return rc; +} + +/******************************************************************************/ +/* --- END TPM2.0 Endorsement certificate tool -- */ +/******************************************************************************/ +#endif /* !WOLFTPM2_NO_WRAPPER */ + +#ifndef NO_MAIN_DRIVER +int main(int argc, char *argv[]) +{ + int rc = -1; + +#ifndef WOLFTPM2_NO_WRAPPER + rc = TPM2_EndorsementCertVerify_Example(NULL, argc, argv); +#else + printf("Wrapper code not compiled in\n"); + (void)argc; + (void)argv; +#endif /* !WOLFTPM2_NO_WRAPPER */ + + return rc; +} +#endif