mirror of https://github.com/wolfSSL/wolfTPM.git
348 lines
11 KiB
C
348 lines
11 KiB
C
/* verify_ek_cert.c
|
|
*
|
|
* Copyright (C) 2006-2025 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfTPM.
|
|
*
|
|
* wolfTPM is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfTPM is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
/* This example shows how to generate and validate an EK based on a
|
|
* trusted public key. This example is supported in stand-alone (no wolfCrypt)
|
|
* This example assumes ST33KTPM2X with signer
|
|
* "STSAFE TPM RSA Intermediate CA 20" : RSA 4096-bit key with SHA2-384
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <wolftpm/tpm2_wrap.h>
|
|
#include <wolftpm/tpm2_asn.h>
|
|
|
|
#include <stdio.h>
|
|
#ifndef WOLFTPM2_NO_ASN
|
|
#ifndef WOLFTPM2_NO_WRAPPER
|
|
|
|
#include <examples/endorsement/endorsement.h>
|
|
#include <hal/tpm_io.h>
|
|
|
|
#include "trusted_certs_der.h"
|
|
|
|
#ifndef WOLFTPM2_NO_WOLFCRYPT
|
|
#include <wolfssl/wolfcrypt/asn.h>
|
|
#include <wolfssl/wolfcrypt/rsa.h>
|
|
#endif
|
|
|
|
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; i<sz; i++) {
|
|
printf("%02x", buf[i]);
|
|
if (i+1 < sz) {
|
|
printf(":");
|
|
if (i>0 && ((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);
|
|
}
|
|
}
|
|
|
|
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 = TPM2_ASN_DecodeX509Cert(cert, certSz, &ekX509);
|
|
if (rc == 0) {
|
|
/* Parse RSA Public Key Raw Modulus */
|
|
rc = TPM2_ASN_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 = TPM2_ASN_DecodeX509Cert((uint8_t*)kSTSAFEIntCa20,
|
|
(int)sizeof(kSTSAFEIntCa20), &issuerX509);
|
|
if (rc == 0) {
|
|
/* Parse RSA Public Key Raw Modulus */
|
|
rc = TPM2_ASN_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 = TPM2_ASN_RsaUnpadPkcsv15(&sigDigest, &sigSz);
|
|
}
|
|
if (rc == 0) {
|
|
rc = TPM2_ASN_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 */
|
|
#endif /* !WOLFTPM2_NO_ASN */
|
|
|
|
#ifndef NO_MAIN_DRIVER
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int rc = -1;
|
|
|
|
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
|
|
rc = TPM2_EndorsementCertVerify_Example(NULL, argc, argv);
|
|
#else
|
|
printf("Wrapper code not compiled in\n");
|
|
(void)argc;
|
|
(void)argv;
|
|
#endif /* !WOLFTPM2_NO_WRAPPER && !WOLFTPM2_NO_ASN */
|
|
|
|
return rc;
|
|
}
|
|
#endif
|