mirror of https://github.com/wolfSSL/wolfTPM.git
commit
a6e54ccf93
|
@ -35,6 +35,7 @@ set(TPM_SOURCES
|
|||
src/tpm2_tis.c
|
||||
src/tpm2_winapi.c
|
||||
src/tpm2_wrap.c
|
||||
src/tpm2_asn.c
|
||||
src/tpm2_cryptocb.c
|
||||
hal/tpm_io.c
|
||||
)
|
||||
|
|
|
@ -30,9 +30,10 @@
|
|||
#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>
|
||||
|
@ -45,41 +46,6 @@
|
|||
#include <wolfssl/wolfcrypt/rsa.h>
|
||||
#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");
|
||||
|
@ -137,272 +103,6 @@ static void show_tpm_public(const char* desc, const TPM2B_PUBLIC* pub)
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -496,10 +196,10 @@ int TPM2_EndorsementCertVerify_Example(void* userCtx, int argc, char *argv[])
|
|||
|
||||
if (rc == 0) {
|
||||
/* Parse device certificate and extract public key */
|
||||
rc = DecodeX509Cert(cert, certSz, &ekX509);
|
||||
rc = TPM2_ASN_DecodeX509Cert(cert, certSz, &ekX509);
|
||||
if (rc == 0) {
|
||||
/* Parse RSA Public Key Raw Modulus */
|
||||
rc = DecodeRsaPubKey((uint8_t*)ekX509.publicKey, ekX509.pubKeySz,
|
||||
rc = TPM2_ASN_DecodeRsaPubKey((uint8_t*)ekX509.publicKey, ekX509.pubKeySz,
|
||||
&ekPub);
|
||||
}
|
||||
}
|
||||
|
@ -535,11 +235,11 @@ int TPM2_EndorsementCertVerify_Example(void* userCtx, int argc, char *argv[])
|
|||
|
||||
if (rc == 0) {
|
||||
/* Parse and extract the issuer's public key modulus from certificate */
|
||||
rc = DecodeX509Cert((uint8_t*)kSTSAFEIntCa20,
|
||||
rc = TPM2_ASN_DecodeX509Cert((uint8_t*)kSTSAFEIntCa20,
|
||||
(int)sizeof(kSTSAFEIntCa20), &issuerX509);
|
||||
if (rc == 0) {
|
||||
/* Parse RSA Public Key Raw Modulus */
|
||||
rc = DecodeRsaPubKey((uint8_t*)issuerX509.publicKey,
|
||||
rc = TPM2_ASN_DecodeRsaPubKey((uint8_t*)issuerX509.publicKey,
|
||||
issuerX509.pubKeySz, &issuer.pub);
|
||||
}
|
||||
}
|
||||
|
@ -582,10 +282,10 @@ int TPM2_EndorsementCertVerify_Example(void* userCtx, int argc, char *argv[])
|
|||
|
||||
if (rc == 0) {
|
||||
sigDigest = sig;
|
||||
rc = RsaUnpadPkcsv15(&sigDigest, &sigSz);
|
||||
rc = TPM2_ASN_RsaUnpadPkcsv15(&sigDigest, &sigSz);
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = RsaDecodeSignature(&sigDigest, sigSz);
|
||||
rc = TPM2_ASN_RsaDecodeSignature(&sigDigest, sigSz);
|
||||
if (rc > 0) {
|
||||
sigDigestSz = rc;
|
||||
rc = 0;
|
||||
|
@ -627,19 +327,20 @@ exit:
|
|||
/* --- 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;
|
||||
|
||||
#ifndef WOLFTPM2_NO_WRAPPER
|
||||
#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 */
|
||||
#endif /* !WOLFTPM2_NO_WRAPPER && !WOLFTPM2_NO_ASN */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ src_libwolftpm_la_SOURCES = \
|
|||
src/tpm2_packet.c \
|
||||
src/tpm2_tis.c \
|
||||
src/tpm2_wrap.c \
|
||||
src/tpm2_asn.c \
|
||||
src/tpm2_param_enc.c \
|
||||
src/tpm2_cryptocb.c
|
||||
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
/* tpm2_asn.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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <wolftpm/tpm2_asn.h>
|
||||
|
||||
#ifndef WOLFTPM2_NO_ASN
|
||||
|
||||
int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
|
||||
word32 maxIdx, int check)
|
||||
{
|
||||
int length = 0;
|
||||
word32 idx = *inOutIdx;
|
||||
byte b;
|
||||
|
||||
*len = 0; /* default length */
|
||||
|
||||
if ((idx + 1) > maxIdx) {
|
||||
return TPM_RC_INSUFFICIENT;
|
||||
}
|
||||
|
||||
b = input[idx++];
|
||||
if (b >= TPM2_ASN_LONG_LENGTH) {
|
||||
word32 bytes = b & 0x7F;
|
||||
if ((idx + bytes) > maxIdx) {
|
||||
return TPM_RC_INSUFFICIENT;
|
||||
}
|
||||
while (bytes--) {
|
||||
b = input[idx++];
|
||||
length = (length << 8) | b;
|
||||
}
|
||||
}
|
||||
else
|
||||
length = b;
|
||||
|
||||
if (check && (idx + length) > maxIdx) {
|
||||
return TPM_RC_INSUFFICIENT;
|
||||
}
|
||||
|
||||
*inOutIdx = idx;
|
||||
if (length > 0)
|
||||
*len = length;
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx, int* len,
|
||||
word32 maxIdx)
|
||||
{
|
||||
return TPM2_ASN_GetLength_ex(input, inOutIdx, len, maxIdx, 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Decodes ASN.1 tag and length
|
||||
\param input Buffer containing ASN.1 data
|
||||
\param tag Expected ASN.1 tag value
|
||||
\param inOutIdx Current position in buffer, updated to new position
|
||||
\param len Decoded length value
|
||||
\param maxIdx Maximum allowed index in buffer
|
||||
\return Length on success, TPM_RC_VALUE on tag mismatch, TPM_RC_INSUFFICIENT on buffer error
|
||||
*/
|
||||
static int TPM2_ASN_GetHeader(const uint8_t* input, byte tag, word32* inOutIdx, int* len,
|
||||
word32 maxIdx)
|
||||
{
|
||||
word32 idx = *inOutIdx;
|
||||
byte b;
|
||||
int length;
|
||||
|
||||
if ((idx + 1) > maxIdx)
|
||||
return TPM_RC_INSUFFICIENT;
|
||||
|
||||
b = input[idx++];
|
||||
if (b != tag)
|
||||
return TPM_RC_VALUE;
|
||||
|
||||
if (TPM2_ASN_GetLength(input, &idx, &length, maxIdx) < 0)
|
||||
return TPM_RC_VALUE;
|
||||
|
||||
*len = length;
|
||||
*inOutIdx = idx;
|
||||
return length;
|
||||
}
|
||||
|
||||
int TPM2_ASN_DecodeTag(const uint8_t* input, int inputSz,
|
||||
int* inOutIdx, int* tag_len, uint8_t tag)
|
||||
{
|
||||
word32 idx = *inOutIdx;
|
||||
int rc = TPM2_ASN_GetHeader(input, tag, &idx, tag_len, inputSz);
|
||||
if (rc >= 0) {
|
||||
*inOutIdx = idx;
|
||||
rc = 0;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TPM2_ASN_RsaDecodeSignature(uint8_t** pInput, int inputSz)
|
||||
{
|
||||
int rc;
|
||||
uint8_t* input = *pInput;
|
||||
int idx = 0;
|
||||
int tot_len, algo_len, digest_len = 0;
|
||||
|
||||
rc = TPM2_ASN_DecodeTag(input, inputSz, &idx, &tot_len,
|
||||
(TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED));
|
||||
if (rc == 0) {
|
||||
rc = TPM2_ASN_DecodeTag(input, inputSz, &idx, &algo_len,
|
||||
(TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED));
|
||||
}
|
||||
if (rc == 0) {
|
||||
idx += algo_len;
|
||||
rc = TPM2_ASN_DecodeTag(input, inputSz, &idx, &digest_len, TPM2_ASN_OCTET_STRING);
|
||||
}
|
||||
if (rc == 0) {
|
||||
*pInput = &input[idx];
|
||||
rc = digest_len;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
|
||||
DecodedX509* x509)
|
||||
{
|
||||
int rc = 0;
|
||||
word32 idx = 0;
|
||||
int tot_len, cert_len = 0, len, pubkey_len = 0, sig_len = 0;
|
||||
|
||||
if (input == NULL || x509 == NULL) {
|
||||
rc = TPM_RC_VALUE;
|
||||
}
|
||||
|
||||
/* Decode outer SEQUENCE */
|
||||
if (rc == 0) {
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &tot_len, inputSz);
|
||||
}
|
||||
|
||||
/* Store certificate location */
|
||||
if (rc == 0) {
|
||||
x509->certBegin = idx;
|
||||
x509->cert = &input[idx];
|
||||
|
||||
/* Decode certificate SEQUENCE */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &cert_len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
x509->certSz = cert_len + (idx - x509->certBegin);
|
||||
|
||||
/* Decode version */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_CONTEXT_SPECIFIC | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/* check version == 1 */
|
||||
if (input[idx] != TPM2_ASN_INTEGER || input[idx] != 1) {
|
||||
rc = TPM_RC_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip version */
|
||||
|
||||
/* Skip serial number */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_INTEGER, &idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip serial */
|
||||
|
||||
/* Skip algorithm identifier */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip signature oid */
|
||||
|
||||
/* Skip issuer */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip issuer */
|
||||
|
||||
/* Skip validity */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip validity */
|
||||
|
||||
/* Skip subject */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip subject */
|
||||
|
||||
/* Skip subject public key info */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip subject public key info */
|
||||
|
||||
/* Get public key */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_BIT_STRING, &idx, &pubkey_len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
/* skip leading zero for bit string */
|
||||
if (input[idx] == 0x00) {
|
||||
idx++;
|
||||
pubkey_len--;
|
||||
}
|
||||
x509->publicKey = &input[idx];
|
||||
x509->pubKeySz = pubkey_len;
|
||||
|
||||
/* Get signature algorithm */
|
||||
idx = x509->certBegin + x509->certSz;
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
|
||||
&idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_OBJECT_ID, &idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip oid */
|
||||
|
||||
/* Skip signature algorithm parameters */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_TAG_NULL, &idx, &len, inputSz);
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
idx += len; /* skip tag */
|
||||
|
||||
/* Get signature */
|
||||
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_BIT_STRING, &idx, &sig_len, inputSz);
|
||||
}
|
||||
|
||||
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];
|
||||
rc = TPM_RC_SUCCESS;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz,
|
||||
TPM2B_PUBLIC* pub)
|
||||
{
|
||||
int rc;
|
||||
int idx = 0;
|
||||
int tot_len, mod_len = 0, exp_len = 0;
|
||||
|
||||
rc = TPM2_ASN_DecodeTag(input, inputSz, &idx, &tot_len,
|
||||
(TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED));
|
||||
if (rc == 0) {
|
||||
rc = TPM2_ASN_DecodeTag(input, inputSz, &idx, &mod_len, TPM2_ASN_INTEGER);
|
||||
}
|
||||
if (rc == 0) {
|
||||
if (input[idx] == 0x00) {
|
||||
idx++;
|
||||
mod_len--;
|
||||
}
|
||||
if (mod_len > (int)sizeof(pub->publicArea.unique.rsa.buffer)) {
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
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;
|
||||
rc = TPM2_ASN_DecodeTag(input, inputSz, &idx, &exp_len, TPM2_ASN_INTEGER);
|
||||
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;
|
||||
}
|
||||
|
||||
int TPM2_ASN_RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz)
|
||||
{
|
||||
int rc = -1;
|
||||
uint8_t* sig = *pSig;
|
||||
int idx = 0;
|
||||
|
||||
if (sig[idx++] == 0x00 && sig[idx++] == 0x01) {
|
||||
while (idx < *sigSz) {
|
||||
if (sig[idx] != 0xFF)
|
||||
break;
|
||||
idx++;
|
||||
}
|
||||
if (sig[idx++] == 0x00) {
|
||||
rc = 0;
|
||||
*pSig = &sig[idx];
|
||||
*sigSz -= idx;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* !WOLFTPM2_NO_ASN */
|
|
@ -0,0 +1,147 @@
|
|||
/* tpm2_asn.h
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef WOLFTPM_TPM2_ASN_H
|
||||
#define WOLFTPM_TPM2_ASN_H
|
||||
|
||||
#include <wolftpm/tpm2.h>
|
||||
#include <wolftpm/tpm2_types.h>
|
||||
|
||||
#ifndef WOLFTPM2_NO_ASN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef MAX_CERT_SZ
|
||||
#define MAX_CERT_SZ 2048
|
||||
#endif
|
||||
|
||||
/* ASN Error Codes */
|
||||
#define TPM_RC_ASN_PARSE (-201) /* ASN parsing error */
|
||||
#define TPM_RC_INSUFFICIENT (-202) /* ASN insufficient data */
|
||||
#define TPM_RC_VALUE (-203) /* ASN value error (invalid tag) */
|
||||
#define TPM_RC_BUFFER (-204) /* ASN buffer error */
|
||||
|
||||
/* ASN.1 Constants */
|
||||
enum {
|
||||
TPM2_ASN_SEQUENCE = 0x10,
|
||||
TPM2_ASN_CONSTRUCTED = 0x20,
|
||||
TPM2_ASN_CONTEXT_SPECIFIC = 0x80,
|
||||
TPM2_ASN_LONG_LENGTH = 0x80,
|
||||
TPM2_ASN_INTEGER = 0x02,
|
||||
TPM2_ASN_BIT_STRING = 0x03,
|
||||
TPM2_ASN_OCTET_STRING = 0x04,
|
||||
TPM2_ASN_TAG_NULL = 0x05,
|
||||
TPM2_ASN_OBJECT_ID = 0x06
|
||||
};
|
||||
|
||||
#if defined(WOLFTPM2_NO_WOLFCRYPT) || defined(NO_RSA)
|
||||
#define RSA_BLOCK_TYPE_1 1
|
||||
#define RSA_BLOCK_TYPE_2 2
|
||||
#endif
|
||||
|
||||
/* ASN.1 Decoder Types */
|
||||
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;
|
||||
|
||||
/* ASN.1 Decoder Functions */
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Decodes ASN.1 length with length checking enabled
|
||||
\param input Buffer containing ASN.1 data
|
||||
\param inOutIdx Current position in buffer, updated to new position
|
||||
\param len Decoded length value
|
||||
\param maxIdx Maximum allowed index in buffer
|
||||
\return Length on success, TPM_RC_INSUFFICIENT on buffer error
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_GetLength(const uint8_t* input, word32* inOutIdx, int* len,
|
||||
word32 maxIdx);
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Decodes ASN.1 length with optional length checking
|
||||
\param input Buffer containing ASN.1 data
|
||||
\param inOutIdx Current position in buffer, updated to new position
|
||||
\param len Decoded length value
|
||||
\param maxIdx Maximum allowed index in buffer
|
||||
\param check Flag to enable length validation
|
||||
\return Length on success, TPM_RC_INSUFFICIENT on buffer error
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_GetLength_ex(const uint8_t* input, word32* inOutIdx, int* len,
|
||||
word32 maxIdx, int check);
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Decodes ASN.1 tag and validates length
|
||||
\param input Buffer containing ASN.1 data
|
||||
\param inputSz Size of input buffer
|
||||
\param inOutIdx Current position in buffer, updated to new position
|
||||
\param tag_len Decoded length value
|
||||
\param tag Expected ASN.1 tag value
|
||||
\return 0 on success, TPM_RC_INSUFFICIENT on buffer error, TPM_RC_VALUE on tag mismatch
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_DecodeTag(const uint8_t* input, int inputSz, int* inOutIdx, int* tag_len, uint8_t tag);
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Decodes RSA signature from ASN.1 format
|
||||
\param pInput Pointer to buffer containing ASN.1 encoded RSA signature
|
||||
\param inputSz Size of input buffer
|
||||
\return Size of decoded signature on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_RsaDecodeSignature(uint8_t** pInput, int inputSz);
|
||||
/*!
|
||||
\brief Decodes an X.509 certificate
|
||||
\param input Buffer containing ASN.1 encoded X.509 certificate
|
||||
\param inputSz Size of input buffer
|
||||
\param x509 Structure to store decoded certificate data
|
||||
\return 0 on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz, DecodedX509* x509);
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Decodes RSA public key from ASN.1 format into TPM2B_PUBLIC structure
|
||||
\param input Buffer containing ASN.1 encoded RSA public key
|
||||
\param inputSz Size of input buffer
|
||||
\param pub TPM2B_PUBLIC structure to store decoded key
|
||||
\return 0 on success, TPM_RC_VALUE on invalid input, TPM_RC_INSUFFICIENT on buffer error
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz, TPM2B_PUBLIC* pub);
|
||||
/*!
|
||||
\ingroup ASN
|
||||
\brief Removes PKCS#1 v1.5 padding from RSA signature
|
||||
\param pSig Pointer to buffer containing padded signature, updated to point to unpadded data
|
||||
\param sigSz Size of signature buffer, updated with unpadded size
|
||||
\return 0 on success, TPM_RC_VALUE on invalid padding
|
||||
*/
|
||||
WOLFTPM_API int TPM2_ASN_RsaUnpadPkcsv15(uint8_t** pSig, int* sigSz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* !WOLFTPM2_NO_ASN */
|
||||
#endif /* WOLFTPM_TPM2_ASN_H */
|
Loading…
Reference in New Issue