Merge pull request #404 from tmael/asn

Refactor ASN.1 parsing for RSA cert
pull/407/head
David Garske 2025-03-06 10:30:49 -08:00 committed by GitHub
commit a6e54ccf93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 510 additions and 310 deletions

View File

@ -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
)

View File

@ -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;
}

View File

@ -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

350
src/tpm2_asn.c 100644
View File

@ -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 */

147
wolftpm/tpm2_asn.h 100644
View File

@ -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 */