Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 86 additions & 5 deletions src/tpm2_asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ static int TPM2_ASN_GetHeader(const uint8_t* input, byte tag, word32* inOutIdx,
word32 idx = *inOutIdx;
byte b;
int length;
int rc;

if ((idx + 1) > maxIdx)
return TPM_RC_ASN_INSUFFICIENT;
Expand All @@ -108,8 +109,9 @@ static int TPM2_ASN_GetHeader(const uint8_t* input, byte tag, word32* inOutIdx,
if (b != tag)
return TPM_RC_ASN_VALUE;

if (TPM2_ASN_GetLength(input, &idx, &length, maxIdx) < 0)
return TPM_RC_ASN_VALUE;
rc = TPM2_ASN_GetLength(input, &idx, &length, maxIdx);
if (rc < 0)
return rc;

*len = length;
*inOutIdx = idx;
Expand Down Expand Up @@ -177,7 +179,7 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
DecodedX509* x509)
{
int rc = 0;
word32 idx = 0, sigAlgEnd = 0;
word32 idx = 0, sigAlgEnd = 0, nameBegin = 0;
word32 tbsSigAlgBegin = 0, tbsSigAlgSz = 0;
word32 outerSigAlgBegin = 0, outerSigAlgSz = 0;
int tot_len, cert_len = 0, len, pubkey_len = 0, sig_len = 0;
Expand Down Expand Up @@ -244,13 +246,16 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
tbsSigAlgSz = idx - tbsSigAlgBegin + (word32)len;
idx += len; /* skip signature oid */

/* Skip issuer */
/* Issuer */
Comment thread
dgarske marked this conversation as resolved.
x509->issuer = &input[idx];
nameBegin = idx;
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
&idx, &len, inputSz);
}

if (rc >= 0) {
idx += len; /* skip issuer */
x509->issuerSz = idx - nameBegin;

/* Skip validity */
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
Expand All @@ -260,13 +265,16 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
if (rc >= 0) {
idx += len; /* skip validity */

/* Skip subject */
/* Subject */
x509->subject = &input[idx];
nameBegin = idx;
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
&idx, &len, inputSz);
}

if (rc >= 0) {
idx += len; /* skip subject */
x509->subjectSz = idx - nameBegin;
/* subject public key info */
rc = TPM2_ASN_GetHeader(input, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
&idx, &len, inputSz);
Expand Down Expand Up @@ -357,6 +365,79 @@ int TPM2_ASN_DecodeX509Cert(uint8_t* input, int inputSz,
return rc;
}

int TPM2_ASN_GetNameAttr(const uint8_t* name, word32 nameSz,
const uint8_t* oid, word32 oidSz, const uint8_t** value, word32* valueSz)
{
int rc;
int len, setLen, attrLen, oidLen;
int match;
word32 idx = 0, nameEnd, setEnd, attrEnd;

if (name == NULL || oid == NULL || oidSz == 0 || value == NULL ||
valueSz == NULL) {
return TPM_RC_ASN_VALUE;
}

/* Name ::= SEQUENCE OF RelativeDistinguishedName */
rc = TPM2_ASN_GetHeader(name, TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED,
&idx, &len, nameSz);
if (rc < 0) {
return rc;
}
nameEnd = idx + (word32)len;

while (idx < nameEnd) {
/* RelativeDistinguishedName ::= SET OF AttributeTypeAndValue */
rc = TPM2_ASN_GetHeader(name, TPM2_ASN_SET | TPM2_ASN_CONSTRUCTED,
&idx, &setLen, nameEnd);
if (rc < 0) {
return rc;
}
setEnd = idx + (word32)setLen;

while (idx < setEnd) {
/* AttributeTypeAndValue ::= SEQUENCE { type OID, value ANY } */
rc = TPM2_ASN_GetHeader(name,
TPM2_ASN_SEQUENCE | TPM2_ASN_CONSTRUCTED, &idx, &attrLen,
setEnd);
if (rc < 0) {
return rc;
}
attrEnd = idx + (word32)attrLen;

rc = TPM2_ASN_GetHeader(name, TPM2_ASN_OBJECT_ID, &idx, &oidLen,
attrEnd);
if (rc < 0) {
return rc;
}
Comment thread
dgarske marked this conversation as resolved.
match = ((word32)oidLen == oidSz &&
XMEMCMP(&name[idx], oid, oidSz) == 0);
idx += (word32)oidLen;

/* value must be exactly one TLV filling the rest of the SEQUENCE */
if (idx >= attrEnd) {
return TPM_RC_ASN_VALUE;
}
idx++; /* any string tag */
rc = TPM2_ASN_GetLength(name, &idx, &len, attrEnd);
if (rc < 0) {
return rc;
}
if (idx + (word32)len != attrEnd) {
return TPM_RC_ASN_VALUE;
}
if (match) {
*value = &name[idx];
*valueSz = (word32)len;
return 0;
}
idx = attrEnd;
}
}

return TPM_RC_ASN_VALUE;
}

int TPM2_ASN_DecodeRsaPubKey(uint8_t* input, int inputSz,
TPM2B_PUBLIC* pub)
{
Expand Down
215 changes: 215 additions & 0 deletions tests/unit_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -8894,6 +8894,220 @@ static void test_TPM2_ASN_DecodeX509Cert_Valid(void)
#endif
}

static void test_TPM2_ASN_GetNameAttr(void)
{
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
/* from wolfSSL ./certs/server-ecc.der */
static const byte cert[] = {
0x30, 0x82, 0x02, 0xa4, 0x30, 0x82, 0x02, 0x4a, 0xa0, 0x03, 0x02, 0x01,
0x02, 0x02, 0x01, 0x03, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, 0x98, 0x31, 0x0b, 0x30, 0x09, 0x06,
0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11,
0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69,
0x6e, 0x67, 0x74, 0x6f, 0x6e, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
0x04, 0x07, 0x0c, 0x07, 0x53, 0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31,
0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x07, 0x77, 0x6f,
0x6c, 0x66, 0x53, 0x53, 0x4c, 0x31, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55,
0x04, 0x0b, 0x0c, 0x0b, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d,
0x65, 0x6e, 0x74, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73,
0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x66, 0x61,
0x63, 0x74, 0x73, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e,
0x63, 0x6f, 0x6d, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x36, 0x31,
0x31, 0x32, 0x31, 0x34, 0x34, 0x32, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x39,
0x30, 0x33, 0x30, 0x37, 0x32, 0x31, 0x34, 0x34, 0x32, 0x39, 0x5a, 0x30,
0x81, 0x91, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08,
0x0c, 0x0a, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x74, 0x6f, 0x6e,
0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x07, 0x53,
0x65, 0x61, 0x74, 0x74, 0x6c, 0x65, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
0x55, 0x04, 0x0a, 0x0c, 0x08, 0x45, 0x6c, 0x6c, 0x69, 0x70, 0x74, 0x69,
0x63, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03,
0x45, 0x43, 0x43, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x0f, 0x77, 0x77, 0x77, 0x2e, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73,
0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x31, 0x20, 0x30, 0x1e, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x11, 0x66, 0x61,
0x63, 0x74, 0x73, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e,
0x63, 0x6f, 0x6d, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48,
0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xbb, 0x33, 0xac, 0x4c, 0x27, 0x50,
0x4a, 0xc6, 0x4a, 0xa5, 0x04, 0xc3, 0x3c, 0xde, 0x9f, 0x36, 0xdb, 0x72,
0x2d, 0xce, 0x94, 0xea, 0x2b, 0xfa, 0xcb, 0x20, 0x09, 0x39, 0x2c, 0x16,
0xe8, 0x61, 0x02, 0xe9, 0xaf, 0x4d, 0xd3, 0x02, 0x93, 0x9a, 0x31, 0x5b,
0x97, 0x92, 0x21, 0x7f, 0xf0, 0xcf, 0x18, 0xda, 0x91, 0x11, 0x02, 0x34,
0x86, 0xe8, 0x20, 0x58, 0x33, 0x0b, 0x80, 0x34, 0x89, 0xd8, 0xa3, 0x81,
0x89, 0x30, 0x81, 0x86, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
0x16, 0x04, 0x14, 0x5d, 0x5d, 0x26, 0xef, 0xac, 0x7e, 0x36, 0xf9, 0x9b,
0x76, 0x15, 0x2b, 0x4a, 0x25, 0x02, 0x23, 0xef, 0xb2, 0x89, 0x30, 0x30,
0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14,
0x56, 0x8e, 0x9a, 0xc3, 0xf0, 0x42, 0xde, 0x18, 0xb9, 0x45, 0x55, 0x6e,
0xf9, 0x93, 0xcf, 0xea, 0xc3, 0xf3, 0xa5, 0x21, 0x30, 0x0c, 0x06, 0x03,
0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00, 0x30, 0x0e,
0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02,
0x03, 0xa8, 0x30, 0x13, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30,
0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x30,
0x11, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01,
0x04, 0x04, 0x03, 0x02, 0x06, 0x40, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x48, 0x00, 0x30, 0x45, 0x02,
0x20, 0x45, 0x9c, 0xf5, 0x02, 0x68, 0xb0, 0x25, 0xcf, 0x84, 0x5b, 0xba,
0x4c, 0xab, 0x95, 0x3b, 0xf3, 0x19, 0xe0, 0x7d, 0x05, 0x2b, 0x1d, 0xae,
0x31, 0x6e, 0xb2, 0x08, 0x14, 0x52, 0xe1, 0xed, 0x3d, 0x02, 0x21, 0x00,
0x98, 0x47, 0x72, 0x4f, 0xae, 0xeb, 0xc4, 0xe8, 0x02, 0x46, 0x51, 0x47,
0x3c, 0x03, 0x2f, 0x4e, 0x67, 0x3d, 0x00, 0x07, 0x18, 0xa9, 0x66, 0x80,
0x5f, 0xfe, 0x82, 0xe9, 0x68, 0x92, 0xf5, 0x97
};
static const byte oidCN[] = { 0x55, 0x04, 0x03 };
static const byte oidSerial[] = { 0x55, 0x04, 0x05 };
static const byte oidOU[] = { 0x55, 0x04, 0x0B };
static const byte oidO[] = { 0x55, 0x04, 0x0A };
static const byte multiRdn[] = {
0x30, 0x1f, 0x31, 0x1d,
0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x01, 'x',
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x05, 0x13, 0x0a,
'P', 'I', 'D', ':', 'A', ' ', 'S', 'N', ':', 'B'
};
/* malformed Names, all looking up commonName */
static const byte badLen[] = { 0x30, 0x81 };
static const byte badTag[] = { 0x31, 0x00 };
static const byte badSet[] = { 0x30, 0x02, 0x31, 0x05 };
static const byte badAttr[] = { 0x30, 0x04, 0x31, 0x02, 0x30, 0x05 };
static const byte badOid[] = {
0x30, 0x06, 0x31, 0x04, 0x30, 0x02, 0x06, 0x05
};
static const byte noValue[] = {
0x30, 0x09, 0x31, 0x07, 0x30, 0x05, 0x06, 0x03, 0x55, 0x04, 0x03
};
static const byte noValueOther[] = {
0x30, 0x15,
0x31, 0x07, 0x30, 0x05, 0x06, 0x03, 0x55, 0x04, 0x0a,
0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x01, 'a'
};
static const byte extraField[] = {
0x30, 0x0e, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x01, 'a', 0x05, 0x00
};
static const byte valueTagOnly[] = {
0x30, 0x0a, 0x31, 0x08, 0x30, 0x06, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c
};
static const byte valueLen[] = {
0x30, 0x0c, 0x31, 0x0a, 0x30, 0x08, 0x06, 0x03, 0x55, 0x04, 0x03,
0x0c, 0x05, 'a'
};
static const struct {
const byte* name;
word32 nameSz;
int rc;
} bad[] = {
{ badLen, sizeof(badLen), TPM_RC_ASN_INSUFFICIENT },
{ badTag, sizeof(badTag), TPM_RC_ASN_VALUE },
{ badSet, sizeof(badSet), TPM_RC_ASN_INSUFFICIENT },
{ badAttr, sizeof(badAttr), TPM_RC_ASN_INSUFFICIENT },
{ badOid, sizeof(badOid), TPM_RC_ASN_INSUFFICIENT },
{ noValue, sizeof(noValue), TPM_RC_ASN_VALUE },
{ noValueOther, sizeof(noValueOther), TPM_RC_ASN_VALUE },
{ extraField, sizeof(extraField), TPM_RC_ASN_VALUE },
{ valueTagOnly, sizeof(valueTagOnly), TPM_RC_ASN_INSUFFICIENT },
{ valueLen, sizeof(valueLen), TPM_RC_ASN_INSUFFICIENT },
{ noValue, 0, TPM_RC_ASN_INSUFFICIENT }
};
byte certBuf[sizeof(cert)];
DecodedX509 x509;
const byte* val = NULL;
word32 valSz = 0;
word32 i;
int rc;

XMEMCPY(certBuf, cert, sizeof(cert));
XMEMSET(&x509, 0, sizeof(x509));
rc = TPM2_ASN_DecodeX509Cert(certBuf, (int)sizeof(certBuf), &x509);
AssertIntEQ(rc, 0);
AssertNotNull(x509.subject);
AssertNotNull(x509.issuer);
AssertIntGT(x509.subjectSz, 0);
AssertIntGT(x509.issuerSz, 0);

rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidCN,
sizeof(oidCN), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 15);
AssertIntEQ(XMEMCMP(val, "www.wolfssl.com", 15), 0);

rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidO,
sizeof(oidO), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 8);
AssertIntEQ(XMEMCMP(val, "Elliptic", 8), 0);

rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidOU,
sizeof(oidOU), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 3);
AssertIntEQ(XMEMCMP(val, "ECC", 3), 0);

rc = TPM2_ASN_GetNameAttr(x509.issuer, x509.issuerSz, oidO,
sizeof(oidO), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 7);
AssertIntEQ(XMEMCMP(val, "wolfSSL", 7), 0);

rc = TPM2_ASN_GetNameAttr(x509.issuer, x509.issuerSz, oidOU,
sizeof(oidOU), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 11);
AssertIntEQ(XMEMCMP(val, "Development", 11), 0);

/* absent attribute */
rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidSerial,
sizeof(oidSerial), &val, &valSz);
AssertIntEQ(rc, TPM_RC_ASN_VALUE);

/* truncated Name must not read past the buffer */
Comment thread
dgarske marked this conversation as resolved.
rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz - 1, oidCN,
sizeof(oidCN), &val, &valSz);
AssertIntEQ(rc, TPM_RC_ASN_INSUFFICIENT);

rc = TPM2_ASN_GetNameAttr(NULL, 0, oidCN, sizeof(oidCN), &val, &valSz);
AssertIntEQ(rc, TPM_RC_ASN_VALUE);
rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, NULL,
sizeof(oidCN), &val, &valSz);
AssertIntEQ(rc, TPM_RC_ASN_VALUE);
rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidCN, 0,
&val, &valSz);
AssertIntEQ(rc, TPM_RC_ASN_VALUE);
rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidCN,
sizeof(oidCN), NULL, &valSz);
AssertIntEQ(rc, TPM_RC_ASN_VALUE);
rc = TPM2_ASN_GetNameAttr(x509.subject, x509.subjectSz, oidCN,
sizeof(oidCN), &val, NULL);
AssertIntEQ(rc, TPM_RC_ASN_VALUE);

for (i = 0; i < (word32)(sizeof(bad) / sizeof(bad[0])); i++) {
rc = TPM2_ASN_GetNameAttr(bad[i].name, bad[i].nameSz, oidCN,
sizeof(oidCN), &val, &valSz);
if (rc != bad[i].rc) {
printf("GetNameAttr bad case %u\n", (unsigned)i);
}
AssertIntEQ(rc, bad[i].rc);
}

/* multi-valued RDN: SET { O=x, serialNumber=PID:A SN:B } */
rc = TPM2_ASN_GetNameAttr(multiRdn, sizeof(multiRdn), oidSerial,
sizeof(oidSerial), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 10);
AssertIntEQ(XMEMCMP(val, "PID:A SN:B", 10), 0);
rc = TPM2_ASN_GetNameAttr(multiRdn, sizeof(multiRdn), oidO,
sizeof(oidO), &val, &valSz);
AssertIntEQ(rc, 0);
AssertIntEQ(valSz, 1);
AssertIntEQ(val[0], 'x');

printf("Test TPM Wrapper: %-40s Passed\n", "ASN GetNameAttr:");
#endif
}

static void test_TPM2_ASN_DecodeTag_Errors(void)
{
#if !defined(WOLFTPM2_NO_WRAPPER) && !defined(WOLFTPM2_NO_ASN)
Expand Down Expand Up @@ -11534,6 +11748,7 @@ int unit_tests(int argc, char *argv[])
test_wolfTPM2_CryptoDevCb_KeyIdRefused();
test_wolfTPM2_CryptoDevCb_MlDsaKeyId();
test_TPM2_ASN_DecodeX509Cert_Errors();
test_TPM2_ASN_GetNameAttr();
test_TPM2_ASN_RsaUnpadPkcsv15();
test_TPM2_ASN_TrimZeros();
test_TPM2_ASN_DecodeX509Cert_Valid();
Expand Down
Loading
Loading