From cb95aed41b6f4b6be3af568d1034e30833fce8ea Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Fri, 18 Feb 2022 16:55:11 -0500 Subject: [PATCH 01/12] Parsing of custom extensions in X.509 certificates. --- wolfcrypt/src/asn.c | 46 ++++++++++++++++++++++++++++++++++++++--- wolfssl/wolfcrypt/asn.h | 17 ++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index b6c8ee3cd..1e45814bf 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -16565,11 +16565,14 @@ exit: * @return Other -ve value on error. */ static int DecodeExtensionType(const byte* input, int length, word32 oid, - byte critical, DecodedCert* cert) + byte critical, DecodedCert* cert, int *unknown) { int ret = 0; word32 idx = 0; + if (unknown != NULL) + *unknown = 0; + switch (oid) { /* Basic Constraints. */ case BASIC_CA_OID: @@ -16753,6 +16756,8 @@ static int DecodeExtensionType(const byte* input, int length, word32 oid, return ASN_PARSE_E; break; default: + if (unknown != NULL) + *unknown = 1; #ifndef WOLFSSL_NO_ASN_STRICT /* While it is a failure to not support critical extensions, * still parse the certificate ignoring the unsupported @@ -16806,6 +16811,16 @@ enum { #define certExtASN_Length (sizeof(certExtASN) / sizeof(ASNItem)) #endif +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ + && defined(HAVE_OID_DECODING) +WOLFSSL_ASN_API void SetUnknownExtCallback(DecodedCert* cert, + wc_UnknownExtCallback cb) { + if (cert != NULL) { + cert->unknownExtCallback = cb; + } +} +#endif + /* * Processing the Certificate Extensions. This does not modify the current * index. It is works starting with the recorded extensions pointer. @@ -16893,7 +16908,8 @@ static int DecodeCertExtensions(DecodedCert* cert) return ret; } - ret = DecodeExtensionType(input + idx, length, oid, critical, cert); + ret = DecodeExtensionType(input + idx, length, oid, critical, cert, + NULL); if (ret == ASN_CRIT_EXT_E) { ret = 0; criticalFail = 1; @@ -16938,6 +16954,7 @@ end: /* Parse each extension. */ while ((ret == 0) && (idx < (word32)sz)) { byte critical = 0; + int unknown = 0; /* Clear dynamic data. */ XMEMSET(dataASN, 0, sizeof(*dataASN) * certExtASN_Length); @@ -16953,7 +16970,30 @@ end: int length = dataASN[CERTEXTASN_IDX_VAL].length; /* Decode the extension by type. */ - ret = DecodeExtensionType(input + idx, length, oid, critical, cert); + ret = DecodeExtensionType(input + idx, length, oid, critical, cert, + &unknown); +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ + && defined(HAVE_OID_DECODING) + if (unknown && (cert->unknownExtCallback != NULL)) { + word16 decOid[16]; + word32 decOidSz = sizeof(decOid); + ret = DecodeObjectId( + dataASN[CERTEXTASN_IDX_OID].data.oid.data, + dataASN[CERTEXTASN_IDX_OID].data.oid.length, + decOid, &decOidSz); + if (ret != 0) { + /* Should never get here as the extension was successfully + * decoded earlier. */ + printf("DecodeObjectId failed: %d\n", ret); + } + + ret = cert->unknownExtCallback(decOid, decOidSz, critical, + dataASN[CERTEXTASN_IDX_VAL].data.buffer.data, + dataASN[CERTEXTASN_IDX_VAL].length); + } +#endif + (void)unknown; + /* Move index on to next extension. */ idx += length; } diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index a2b207a1f..d82d0b3d2 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -513,7 +513,7 @@ WOLFSSL_LOCAL void SetASN_OID(ASNSetData *dataASN, int oid, int oidType); */ #define SetASN_Buffer(dataASN, d, l) \ do { \ - (dataASN)->data.buffer.data = d; \ + (dataASN)->data.buffer.data = (const byte *) d; \ (dataASN)->data.buffer.length = l; \ } while (0) @@ -1459,6 +1459,11 @@ typedef struct TrustedPeerCert TrustedPeerCert; typedef struct SignatureCtx SignatureCtx; typedef struct CertSignCtx CertSignCtx; +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ + && defined(HAVE_OID_DECODING) +typedef int (*wc_UnknownExtCallback)(const word16* oid, word32 oidSz, int crit, + const unsigned char* der, word32 derSz); +#endif struct DecodedCert { const byte* publicKey; @@ -1689,6 +1694,10 @@ struct DecodedCert { #ifdef WOLFSSL_CERT_REQ byte isCSR : 1; /* Do we intend on parsing a CSR? */ #endif +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ + && defined(HAVE_OID_DECODING) + wc_UnknownExtCallback unknownExtCallback; +#endif }; #ifdef NO_SHA @@ -1816,6 +1825,12 @@ WOLFSSL_ASN_API void FreeDecodedCert(DecodedCert* cert); WOLFSSL_ASN_API int ParseCert(DecodedCert* cert, int type, int verify, void* cm); +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ + && defined(HAVE_OID_DECODING) +WOLFSSL_ASN_API void SetUnknownExtCallback(DecodedCert* cert, + wc_UnknownExtCallback cb); +#endif + WOLFSSL_LOCAL int DecodePolicyOID(char *out, word32 outSz, const byte *in, word32 inSz); WOLFSSL_LOCAL int EncodePolicyOID(byte *out, word32 *outSz, From 0053bd3af18630841209cf5974d2efc234b0e14b Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 2 Mar 2022 15:16:39 -0500 Subject: [PATCH 02/12] Now we can inject as wellgit checkout custom_ext_parse --- wolfcrypt/src/asn.c | 128 ++++++++++++++++++++++++++++++--- wolfssl/wolfcrypt/asn.h | 2 +- wolfssl/wolfcrypt/asn_public.h | 26 ++++++- 3 files changed, 144 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 1e45814bf..cc409823e 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -21250,7 +21250,7 @@ static int SetEccPublicKey(byte* output, ecc_key* key, int outLen, oidKeyType); /* Set the curve OID. */ SetASN_Buffer(&dataASN[ECCPUBLICKEYASN_IDX_ALGOID_CURVEID], - key->dp->oid, key->dp->oidSz); + (const byte *)key->dp->oid, key->dp->oidSz); /* Don't try to write out explicit parameters. */ dataASN[ECCPUBLICKEYASN_IDX_ALGOID_PARAMS].noOut = 1; /* Set size of public point to ensure space is made for it. */ @@ -23240,7 +23240,7 @@ static int EncodePublicKey(int keyType, byte* output, int outLen, * X.509: RFC 5280, 4.1 - Basic Certificate Fields. * All extensions supported for encoding are described. */ -static const ASNItem certExtsASN[] = { +static const ASNItem static_certExtsASN[] = { /* Basic Constraints Extension - 4.2.1.9 */ /* BC_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* BC_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, @@ -23337,10 +23337,14 @@ enum { CERTEXTSASN_IDX_CUSTOM_SEQ, CERTEXTSASN_IDX_CUSTOM_OID, CERTEXTSASN_IDX_CUSTOM_STR, + CERTEXTSASN_IDX_START_CUSTOM, }; -/* Number of items in ASN.1 template for certificate extensions. */ -#define certExtsASN_Length (sizeof(certExtsASN) / sizeof(ASNItem)) +/* Number of items in ASN.1 template for certificate extensions. We multiply + * by 4 because there are 4 things (seq, OID, crit flag, octet string). */ +#define certExtsASN_Length ((sizeof(static_certExtsASN) / sizeof(ASNItem)) \ + + (NUM_CUSTOM_EXT * 4)) + static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, int forRequest) @@ -23348,6 +23352,7 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, DECL_ASNSETDATA(dataASN, certExtsASN_Length); int sz; int ret = 0; + int i = 0; static const byte bcOID[] = { 0x55, 0x1d, 0x13 }; #ifdef WOLFSSL_ALT_NAMES static const byte sanOID[] = { 0x55, 0x1d, 0x11 }; @@ -23363,6 +23368,43 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, static const byte crlInfoOID[] = { 0x55, 0x1D, 0x1F }; #endif +#ifdef WOLFSSL_SMALL_STACK + byte *encodedOids; + ASNItem *certExtsASN = (ASNItem *)XMALLOC(certExtsASN_Length * + sizeof(ASNItem), cert->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (certExtsASN == NULL) { + return MEMORY_E; + } + + encodedOids = (byte *)XMALLOC(NUM_CUSTOM_EXT * MAX_OID_SZ, cert->heap, + DYNAMIC_TYPE_TMP_BUFFER); + if (encodedOids == NULL) { + XFREE(certExtsASN, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } + +#else + ASNItem certExtsASN[certExtsASN_Length]; + byte encodedOids[NUM_CUSTOM_EXT * MAX_OID_SZ]; +#endif + + /* Clone static_certExtsASN into a certExtsASN and then fill the rest of it + * with (NUM_CUSTOM_EXT*4) more ASNItems specifying extensions. See comment + * above definition of certExtsASN_Length. */ + XMEMCPY(certExtsASN, static_certExtsASN, sizeof(*static_certExtsASN)); + for (i = sizeof(static_certExtsASN) / sizeof(ASNItem); + i < (int)(sizeof(certExtsASN) / sizeof(ASNItem)); i += 4) { + /* CUSTOM_SEQ */ + certExtsASN[i+0] = (ASNItem) { 0, ASN_SEQUENCE, 1, 1, 0 }; + /* CUSTOM_OID */ + certExtsASN[i+1] = (ASNItem) { 1, ASN_OBJECT_ID, 0, 0, 0 }; + /* CUSTOM_CRIT */ + certExtsASN[i+2] = (ASNItem) { 1, ASN_BOOLEAN, 0, 0, 0 }; + /* CUSTOM_STR */ + certExtsASN[i+3] = (ASNItem) { 1, ASN_OCTET_STRING, 0, 0, 0 }; + } + (void)forRequest; CALLOC_ASNSETDATA(dataASN, certExtsASN_Length, ret, cert->heap); @@ -23512,7 +23554,6 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_CRLINFO_SEQ, CERTEXTSASN_IDX_CRLINFO_STR); } - #endif /* WOLFSSL_CERT_EXT */ #ifdef WOLFSSL_CUSTOM_OID /* encode a custom oid and value */ @@ -23522,13 +23563,40 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, cert->extCustom.oid, cert->extCustom.oidSz); SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_CUSTOM_STR], cert->extCustom.val, cert->extCustom.valSz); - } - else { + } else + #endif + { /* Don't write out custom OID. */ SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_CUSTOM_SEQ, CERTEXTSASN_IDX_CUSTOM_STR); } + + #ifdef WOLFSSL_CUSTOM_OID + for (i = 0; i < cert->customCertExtCount; i++) { + int idx = CERTEXTSASN_IDX_START_CUSTOM + (i * 4); + word32 encodedOidSz = MAX_OID_SZ; + idx ++; /* Skip one for for SEQ. */ + /* EncodePolicyOID() will never return error since we parsed this + * OID when it was set. */ + EncodePolicyOID(&encodedOids[i * MAX_OID_SZ], &encodedOidSz, + cert->customCertExt[i].oid, NULL); + SetASN_Buffer(&dataASN[idx], &encodedOids[i * MAX_OID_SZ], + encodedOidSz); + idx++; + SetASN_Boolean(&dataASN[idx], cert->customCertExt[i].crit); + idx++; + SetASN_Buffer(&dataASN[idx], cert->customCertExt[i].val, + cert->customCertExt[i].valSz); + } #endif + + /* Note: i initialized to 0 at top. */ + while (i < NUM_CUSTOM_EXT) { + SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_START_CUSTOM + (i * 4), + CERTEXTSASN_IDX_START_CUSTOM + (i * 4) + 3); + i++; + } + #endif /* WOLFSSL_CERT_EXT */ } if (ret == 0) { @@ -23577,6 +23645,11 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, } FREE_ASNSETDATA(dataASN, cert->heap); +#ifdef WOLFSSL_SMALL_STACK + XFREE(encodedOids, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(certExtsASN, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return ret; } #endif /* WOLFSSL_ASN_TEMPLATE */ @@ -26180,6 +26253,43 @@ int wc_SetExtKeyUsageOID(Cert *cert, const char *in, word32 sz, byte idx, return 0; } #endif /* WOLFSSL_EKU_OID */ + +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CERT_GEN) && \ + defined(WOLFSSL_CUSTOM_OID) && defined(HAVE_OID_ENCODING) && \ + defined(WOLFSSL_CERT_EXT) +int wc_SetCustomExtension(Cert *cert, int critical, const char *oid, + const byte *der, word32 derSz) { + CertExtension *ext; + byte encodedOid[MAX_OID_SZ]; + word32 encodedOidSz = MAX_OID_SZ; + int ret; + + if (cert == NULL || oid == NULL || der == NULL || derSz == 0) { + return BAD_FUNC_ARG; + } + + if (cert->customCertExtCount >= NUM_CUSTOM_EXT) { + return MEMORY_E; + } + + /* Make sure we can properly parse the OID. */ + ret = EncodePolicyOID(encodedOid, &encodedOidSz, oid, NULL); + if (ret != 0) { + return ret; + } + + ext = &cert->customCertExt[cert->customCertExtCount]; + + ext->oid = oid; + ext->crit = (critical == 0) ? 0 : 1; + ext->val = der; + ext->valSz = derSz; + + cert->customCertExtCount++; + return 0; +} +#endif + #endif /* WOLFSSL_CERT_EXT */ @@ -28249,8 +28359,8 @@ static int wc_BuildEccKeyDer(ecc_key* key, byte* output, word32 *inLen, SetASN_Buffer(&dataASN[ECCKEYASN_IDX_PKEY], NULL, privSz); if (curveIn) { /* Curve OID */ - SetASN_Buffer(&dataASN[ECCKEYASN_IDX_CURVEID], key->dp->oid, - key->dp->oidSz); + SetASN_Buffer(&dataASN[ECCKEYASN_IDX_CURVEID], + (const byte *)key->dp->oid, key->dp->oidSz); /* TODO: add support for SpecifiedECDomain curve. */ dataASN[ECCKEYASN_IDX_CURVEPARAMS].noOut = 1; } diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index d82d0b3d2..ebfb2f498 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -513,7 +513,7 @@ WOLFSSL_LOCAL void SetASN_OID(ASNSetData *dataASN, int oid, int oidType); */ #define SetASN_Buffer(dataASN, d, l) \ do { \ - (dataASN)->data.buffer.data = (const byte *) d; \ + (dataASN)->data.buffer.data = d; \ (dataASN)->data.buffer.length = l; \ } while (0) diff --git a/wolfssl/wolfcrypt/asn_public.h b/wolfssl/wolfcrypt/asn_public.h index f333cf97d..c80e7317a 100644 --- a/wolfssl/wolfcrypt/asn_public.h +++ b/wolfssl/wolfcrypt/asn_public.h @@ -322,6 +322,13 @@ typedef struct CertOidField { int valSz; char enc; } CertOidField; + +typedef struct CertExtension { + const char* oid; + byte crit; + const byte* val; + int valSz; +} CertExtension; #endif #endif /* WOLFSSL_CERT_GEN */ @@ -369,6 +376,10 @@ typedef struct CertName { #ifdef WOLFSSL_CERT_GEN +#ifndef NUM_CUSTOM_EXT +#define NUM_CUSTOM_EXT 16 +#endif + /* for user to fill for certificate generation */ typedef struct Cert { int version; /* x509 version */ @@ -432,9 +443,13 @@ typedef struct Cert { int challengePwPrintableString; /* encode as PrintableString */ #endif #ifdef WOLFSSL_CUSTOM_OID - CertOidField extCustom; /* user oid and value to go in req extensions */ -#endif + /* user oid and value to go in req extensions */ + CertOidField extCustom; + /* Extensions to go into X.509 certificates */ + CertExtension customCertExt[NUM_CUSTOM_EXT]; + int customCertExtCount; +#endif void* decodedCert; /* internal DecodedCert allocated from heap */ byte* der; /* Pointer to buffer of current DecodedCert cache */ void* heap; /* heap hint */ @@ -530,6 +545,13 @@ WOLFSSL_API int wc_SetExtKeyUsage(Cert *cert, const char *value); WOLFSSL_API int wc_SetExtKeyUsageOID(Cert *cert, const char *oid, word32 sz, byte idx, void* heap); #endif /* WOLFSSL_EKU_OID */ + +#if defined(WOLFSSL_ASN_TEMPLATE) && defined(WOLFSSL_CUSTOM_OID) && \ + defined(HAVE_OID_ENCODING) +WOLFSSL_API int wc_SetCustomExtension(Cert *cert, int critical, const char *oid, + const byte *der, word32 derSz); +#endif + #endif /* WOLFSSL_CERT_EXT */ #endif /* WOLFSSL_CERT_GEN */ From a54045113a6c0dc84fe982c1e083fcb7feb42a59 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 2 Mar 2022 17:39:15 -0500 Subject: [PATCH 03/12] fixes from review by dgarske --- wolfcrypt/src/asn.c | 55 +++++++++++++++++++++++------------------ wolfssl/wolfcrypt/asn.h | 6 ++--- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index cc409823e..02b7e4400 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -5119,14 +5119,16 @@ static int DumpOID(const byte* oidData, word32 oidSz, word32 oid, #ifdef HAVE_OID_DECODING { - word16 decOid[16]; - word32 decOidSz = sizeof(decOid); + byte decOid[MAX_OID_SZ]; + word16 *out = decOid; + word32 decOidSz = sizeof(decOid) / 2; /* Decode the OID into dotted form. */ - ret = DecodeObjectId(oidData, oidSz, decOid, &decOidSz); + ret = DecodeObjectId(oidData, oidSz, (word16*)decOid, &decOidSz); if (ret == 0) { printf(" Decoded (Sz %d): ", decOidSz); - for (i=0; iunknownExtCallback = cb; +int wc_SetUnknownExtCallback(DecodedCert* cert, + wc_UnknownExtCallback cb) { + if (cert == NULL) { + return BAD_FUNC_ARG; } + + cert->unknownExtCallback = cb; + return 0; } #endif @@ -16954,7 +16960,7 @@ end: /* Parse each extension. */ while ((ret == 0) && (idx < (word32)sz)) { byte critical = 0; - int unknown = 0; + int isUnknownExt = 0; /* Clear dynamic data. */ XMEMSET(dataASN, 0, sizeof(*dataASN) * certExtASN_Length); @@ -16971,28 +16977,29 @@ end: /* Decode the extension by type. */ ret = DecodeExtensionType(input + idx, length, oid, critical, cert, - &unknown); + &isUnknownExt); #if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ && defined(HAVE_OID_DECODING) - if (unknown && (cert->unknownExtCallback != NULL)) { - word16 decOid[16]; - word32 decOidSz = sizeof(decOid); + if (isUnknownExt && (cert->unknownExtCallback != NULL)) { + byte decOid[MAX_OID_SZ]; + word32 decOidSz = sizeof(decOid) / 2; ret = DecodeObjectId( dataASN[CERTEXTASN_IDX_OID].data.oid.data, dataASN[CERTEXTASN_IDX_OID].data.oid.length, - decOid, &decOidSz); + (word16*)decOid, &decOidSz); if (ret != 0) { /* Should never get here as the extension was successfully - * decoded earlier. */ - printf("DecodeObjectId failed: %d\n", ret); + * decoded earlier. Something might be corrupted. */ + WOLFSSL_MSG("DecodeObjectId() failed. Corruption?"); + WOLFSSL_ERROR(ret); } - ret = cert->unknownExtCallback(decOid, decOidSz, critical, + ret = cert->unknownExtCallback(decOid, decOidSz * 2, critical, dataASN[CERTEXTASN_IDX_VAL].data.buffer.data, dataASN[CERTEXTASN_IDX_VAL].length); } #endif - (void)unknown; + (void)isUnknownExt; /* Move index on to next extension. */ idx += length; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index ebfb2f498..640d2debc 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1461,7 +1461,7 @@ typedef struct CertSignCtx CertSignCtx; #if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ && defined(HAVE_OID_DECODING) -typedef int (*wc_UnknownExtCallback)(const word16* oid, word32 oidSz, int crit, +typedef int (*wc_UnknownExtCallback)(const byte* oid, word32 oidSz, int crit, const unsigned char* der, word32 derSz); #endif @@ -1827,8 +1827,8 @@ WOLFSSL_ASN_API int ParseCert(DecodedCert* cert, int type, int verify, #if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ && defined(HAVE_OID_DECODING) -WOLFSSL_ASN_API void SetUnknownExtCallback(DecodedCert* cert, - wc_UnknownExtCallback cb); +WOLFSSL_ASN_API int wc_SetUnknownExtCallback(DecodedCert* cert, + wc_UnknownExtCallback cb); #endif WOLFSSL_LOCAL int DecodePolicyOID(char *out, word32 outSz, const byte *in, From 949f8b5be1c3a34ec19cfc3a1fbc19e980450cf0 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Thu, 3 Mar 2022 10:41:05 -0500 Subject: [PATCH 04/12] Revert back to word16 API. --- wolfcrypt/src/asn.c | 20 +++++++++----------- wolfssl/wolfcrypt/asn.h | 2 +- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 02b7e4400..bb505b8ae 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -5119,16 +5119,14 @@ static int DumpOID(const byte* oidData, word32 oidSz, word32 oid, #ifdef HAVE_OID_DECODING { - byte decOid[MAX_OID_SZ]; - word16 *out = decOid; - word32 decOidSz = sizeof(decOid) / 2; + word16 decOid[16]; + word32 decOidSz = sizeof(decOid); /* Decode the OID into dotted form. */ - ret = DecodeObjectId(oidData, oidSz, (word16*)decOid, &decOidSz); + ret = DecodeObjectId(oidData, oidSz, decOid, &decOidSz); if (ret == 0) { printf(" Decoded (Sz %d): ", decOidSz); - for (i=0; iunknownExtCallback != NULL)) { - byte decOid[MAX_OID_SZ]; - word32 decOidSz = sizeof(decOid) / 2; + word16 decOid[16]; + word32 decOidSz = sizeof(decOid); ret = DecodeObjectId( dataASN[CERTEXTASN_IDX_OID].data.oid.data, dataASN[CERTEXTASN_IDX_OID].data.oid.length, - (word16*)decOid, &decOidSz); + decOid, &decOidSz); if (ret != 0) { /* Should never get here as the extension was successfully * decoded earlier. Something might be corrupted. */ @@ -16994,7 +16992,7 @@ end: WOLFSSL_ERROR(ret); } - ret = cert->unknownExtCallback(decOid, decOidSz * 2, critical, + ret = cert->unknownExtCallback(decOid, decOidSz, critical, dataASN[CERTEXTASN_IDX_VAL].data.buffer.data, dataASN[CERTEXTASN_IDX_VAL].length); } diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 640d2debc..c97463315 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -1461,7 +1461,7 @@ typedef struct CertSignCtx CertSignCtx; #if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ && defined(HAVE_OID_DECODING) -typedef int (*wc_UnknownExtCallback)(const byte* oid, word32 oidSz, int crit, +typedef int (*wc_UnknownExtCallback)(const word16* oid, word32 oidSz, int crit, const unsigned char* der, word32 derSz); #endif From 7ec61dfe0536f54fa5b2e398fbaee10552ffa2f7 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Thu, 3 Mar 2022 15:44:00 -0500 Subject: [PATCH 05/12] Make jenkins happy --- wolfcrypt/src/asn.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index bb505b8ae..fcb1e1e77 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -23374,7 +23374,9 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, #endif #ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_CERT_EXT) byte *encodedOids; +#endif ASNItem *certExtsASN = (ASNItem *)XMALLOC(certExtsASN_Length * sizeof(ASNItem), cert->heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -23382,16 +23384,19 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, return MEMORY_E; } +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_CERT_EXT) encodedOids = (byte *)XMALLOC(NUM_CUSTOM_EXT * MAX_OID_SZ, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); if (encodedOids == NULL) { XFREE(certExtsASN, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } - +#endif #else ASNItem certExtsASN[certExtsASN_Length]; +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_CERT_EXT) byte encodedOids[NUM_CUSTOM_EXT * MAX_OID_SZ]; +#endif #endif /* Clone static_certExtsASN into a certExtsASN and then fill the rest of it @@ -23651,7 +23656,9 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, FREE_ASNSETDATA(dataASN, cert->heap); #ifdef WOLFSSL_SMALL_STACK +#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_CERT_EXT) XFREE(encodedOids, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); +#endif XFREE(certExtsASN, cert->heap, DYNAMIC_TYPE_TMP_BUFFER); #endif From 3ad94c63f514e0fdafcc1df6cadbf3e8e4e74f99 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Thu, 3 Mar 2022 17:02:26 -0500 Subject: [PATCH 06/12] Pass the tests! --- wolfcrypt/src/asn.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index fcb1e1e77..174068a07 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -23259,7 +23259,6 @@ static const ASNItem static_certExtsASN[] = { /* SAN_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* SAN_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, /* SAN_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 }, -#ifdef WOLFSSL_CERT_EXT /* Subject Key Identifier - 4.2.1.2 */ /* SKID_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* SKID_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, @@ -23294,12 +23293,9 @@ static const ASNItem static_certExtsASN[] = { /* CRLINFO_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* CRLINFO_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, /* CRLINFO_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 }, -#endif /* WOLFSSL_CERT_EXT */ -#ifdef WOLFSSL_CUSTOM_OID /* CUSTOM_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* CUSTOM_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, /* CUSTOM_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 }, -#endif }; enum { CERTEXTSASN_IDX_BC_SEQ = 0, @@ -23343,6 +23339,7 @@ enum { CERTEXTSASN_IDX_CUSTOM_OID, CERTEXTSASN_IDX_CUSTOM_STR, CERTEXTSASN_IDX_START_CUSTOM, + }; /* Number of items in ASN.1 template for certificate extensions. We multiply @@ -23402,7 +23399,7 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, /* Clone static_certExtsASN into a certExtsASN and then fill the rest of it * with (NUM_CUSTOM_EXT*4) more ASNItems specifying extensions. See comment * above definition of certExtsASN_Length. */ - XMEMCPY(certExtsASN, static_certExtsASN, sizeof(*static_certExtsASN)); + XMEMCPY(certExtsASN, static_certExtsASN, sizeof(static_certExtsASN)); for (i = sizeof(static_certExtsASN) / sizeof(ASNItem); i < (int)(sizeof(certExtsASN) / sizeof(ASNItem)); i += 4) { /* CUSTOM_SEQ */ @@ -23581,8 +23578,9 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, CERTEXTSASN_IDX_CUSTOM_STR); } + i = 0; #ifdef WOLFSSL_CUSTOM_OID - for (i = 0; i < cert->customCertExtCount; i++) { + for (; i < cert->customCertExtCount; i++) { int idx = CERTEXTSASN_IDX_START_CUSTOM + (i * 4); word32 encodedOidSz = MAX_OID_SZ; idx ++; /* Skip one for for SEQ. */ @@ -23600,7 +23598,6 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, } #endif - /* Note: i initialized to 0 at top. */ while (i < NUM_CUSTOM_EXT) { SetASNItem_NoOut(dataASN, CERTEXTSASN_IDX_START_CUSTOM + (i * 4), CERTEXTSASN_IDX_START_CUSTOM + (i * 4) + 3); From 806cd4fbbaa7ddd2d273658b683d50cb482ede7d Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Fri, 4 Mar 2022 15:32:11 -0500 Subject: [PATCH 07/12] doxygen for myUnknownExtCallback() --- doc/dox_comments/header_files/asn_public.h | 52 ++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/doc/dox_comments/header_files/asn_public.h b/doc/dox_comments/header_files/asn_public.h index 97ca254f4..2c15c1cba 100644 --- a/doc/dox_comments/header_files/asn_public.h +++ b/doc/dox_comments/header_files/asn_public.h @@ -1937,3 +1937,55 @@ WOLFSSL_API int wc_SetTimeCb(wc_time_cb f); \sa wc_SetTimeCb */ WOLFSSL_API time_t wc_Time(time_t* t); + +/*! + \ingroup ASN + + \brief This function registers a callback that will be used anytime + wolfSSL encounters an unknown X.509 extension in a certificate while parsing + a certificate. The prototype of the callback should be: + + \return 0 Returned on success. + + \param cert the DecodedCert struct that is to be associated with this + callback. + \param cb function to register as the time callback. + + _Example_ + \code + int ret = 0; + // Unkown extension callback prototype + int myUnknownExtCallback(const word16* oid, word32 oidSz, int crit, + const unsigned char* der, word32 derSz); + + // Register it + ret = wc_SetUnknownExtCallback(cert, myUnknownExtCallback); + if (ret != 0) { + // failed to set the callback + } + + // oid: Array of integers that are the dot separated values in an oid. + // oidSz: Number of values in oid. + // crit: Whether the extension was mark critical. + // der: The der encoding of the content of the extension. + // derSz: The size in bytes of the der encoding. + int myCustomExtCallback(const word16* oid, word32 oidSz, int crit, + const unsigned char* der, word32 derSz) { + + // Logic to parse extension goes here. + + // NOTE: by returning zero, we are accepting this extension and + // informing wolfSSL that it is acceptable. If you find an extension + // that you do not find acceptable, you should return an error. The + // standard behavior upon encountering an unknown extension with the + // critical flag set is to return ASN_CRIT_EXT_E. For the sake of + // brevity, this example is always accepting every extension; you + // should use different logic. + return 0; + } + \endcode + + \sa ParseCert +*/ +WOLFSSL_ASN_API int wc_SetUnknownExtCallback(DecodedCert* cert, + wc_UnknownExtCallback cb); From 0a1c052c40537c1b5c823b857f37dfdbfde6cb87 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Fri, 4 Mar 2022 16:24:27 -0500 Subject: [PATCH 08/12] doxygen for wc_SetCustomExtension() --- doc/dox_comments/header_files/asn_public.h | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/dox_comments/header_files/asn_public.h b/doc/dox_comments/header_files/asn_public.h index 2c15c1cba..3407e9c24 100644 --- a/doc/dox_comments/header_files/asn_public.h +++ b/doc/dox_comments/header_files/asn_public.h @@ -1938,6 +1938,52 @@ WOLFSSL_API int wc_SetTimeCb(wc_time_cb f); */ WOLFSSL_API time_t wc_Time(time_t* t); +/*! + \ingroup ASN + + \brief This function injects a custom extension in to an X.509 certificate. + + \return 0 Returned on success. + \return Other negative values on failure. + + \param cert Pointer to an initialized DecodedCert object. + \param critical If 0, the extension will not be marked critical, otherwise + it will be marked critical. + \param oid Dot separted oid as a string. For example "1.2.840.10045.3.1.7" + \param der The der encoding of the content of the extension. + \param derSz The size in bytes of the der encoding. + + + _Example_ + \code + int ret = 0; + Cert newCert; + wc_InitCert(&newCert); + + // Code to setup subject, public key, issuer, and other things goes here. + + ret = wc_SetCustomExtension(&newCert, 1, "1.2.3.4.5", + (const byte *)"This is a critical extension", 28); + if (ret < 0) { + // Failed to set the extension. + } + + ret = wc_SetCustomExtension(&newCert, 0, "1.2.3.4.6", + (const byte *)"This is NOT a critical extension", 32) + if (ret < 0) { + // Failed to set the extension. + } + + // Code to sign the certificate and then write it out goes here. + + \endcode + + \sa wc_InitCert + \sa wc_SetUnknownExtCallback +*/ +WOLFSSL_API int wc_SetCustomExtension(Cert *cert, int critical, const char *oid, + const byte *der, word32 derSz); + /*! \ingroup ASN @@ -1946,6 +1992,7 @@ WOLFSSL_API time_t wc_Time(time_t* t); a certificate. The prototype of the callback should be: \return 0 Returned on success. + \return Other negative values on failure. \param cert the DecodedCert struct that is to be associated with this callback. @@ -1986,6 +2033,7 @@ WOLFSSL_API time_t wc_Time(time_t* t); \endcode \sa ParseCert + \sa wc_SetCustomExtension */ WOLFSSL_ASN_API int wc_SetUnknownExtCallback(DecodedCert* cert, wc_UnknownExtCallback cb); From d77d9b93dc651a1034e1e3b339f9e2c355bf3e2d Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Mon, 7 Mar 2022 15:47:47 -0500 Subject: [PATCH 09/12] This fixes a make check error. The flags activated code that didn't account for the new oid encoding. This code fixes that. --- wolfcrypt/src/ecc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 643d440a4..12470349b 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4047,17 +4047,37 @@ int wc_ecc_get_curve_id_from_dp_params(const ecc_set_type* dp) int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len) { int curve_idx; +#ifdef HAVE_OID_DECODING + int ret; + word16 decOid[16]; + word32 decOidSz = sizeof(decOid); +#endif if (oid == NULL) return BAD_FUNC_ARG; +#ifdef HAVE_OID_DECODING + ret = DecodeObjectId(oid, len, decOid, &decOidSz); + if (ret != 0) { + return ret; + } +#endif + for (curve_idx = 0; ecc_sets[curve_idx].size != 0; curve_idx++) { if ( #ifndef WOLFSSL_ECC_CURVE_STATIC ecc_sets[curve_idx].oid && #endif + #ifdef HAVE_OID_DECODING + /* We double because decOidSz is a count of word16 elements. */ + ecc_sets[curve_idx].oidSz == decOidSz && + XMEMCMP(ecc_sets[curve_idx].oid, decOid, + decOidSz * 2) == 0 + #else ecc_sets[curve_idx].oidSz == len && - XMEMCMP(ecc_sets[curve_idx].oid, oid, len) == 0) { + XMEMCMP(ecc_sets[curve_idx].oid, oid, len) == 0 + #endif + ) { break; } } From 2cbe28fcf9bfcd6d106958a1a76d161ad50b9e22 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Mon, 7 Mar 2022 18:50:38 -0500 Subject: [PATCH 10/12] Sequences are constructed --- wolfcrypt/src/asn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 174068a07..e5902e16d 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -23284,7 +23284,7 @@ static const ASNItem static_certExtsASN[] = { /* POLICIES_SEQ, */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* POLICIES_OID, */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, /* POLICIES_STR, */ { 1, ASN_OCTET_STRING, 0, 1, 0 }, -/* POLICIES_INFO */ { 2, ASN_SEQUENCE, 0, 0, 0 }, +/* POLICIES_INFO */ { 2, ASN_SEQUENCE, 1, 0, 0 }, /* Netscape Certificate Type */ /* NSTYPE_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, /* NSTYPE_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, From b043225dbd07389746dfbcb1bb0ec55d2ee614b6 Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 9 Mar 2022 13:39:53 -0500 Subject: [PATCH 11/12] Fixes inspired by review by SparkiDev. --- wolfcrypt/src/asn.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index e5902e16d..0d2f25f0c 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -16976,8 +16976,7 @@ end: /* Decode the extension by type. */ ret = DecodeExtensionType(input + idx, length, oid, critical, cert, &isUnknownExt); -#if defined(WOLFSSL_CUSTOM_OID) && defined(WOLFSSL_ASN_TEMPLATE) \ - && defined(HAVE_OID_DECODING) +#if defined(WOLFSSL_CUSTOM_OID) && defined(HAVE_OID_DECODING) if (isUnknownExt && (cert->unknownExtCallback != NULL)) { word16 decOid[16]; word32 decOidSz = sizeof(decOid); @@ -23347,6 +23346,12 @@ enum { #define certExtsASN_Length ((sizeof(static_certExtsASN) / sizeof(ASNItem)) \ + (NUM_CUSTOM_EXT * 4)) +static const ASNItem customExtASN[] = { +/* CUSTOM_SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 }, +/* CUSTOM_OID */ { 1, ASN_OBJECT_ID, 0, 0, 0 }, +/* CUSTOM_CRIT */ { 1, ASN_BOOLEAN, 0, 0, 0 }, +/* CUSTOM_STR */ { 1, ASN_OCTET_STRING, 0, 0, 0 }, +}; static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, int forRequest) @@ -23402,14 +23407,7 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, XMEMCPY(certExtsASN, static_certExtsASN, sizeof(static_certExtsASN)); for (i = sizeof(static_certExtsASN) / sizeof(ASNItem); i < (int)(sizeof(certExtsASN) / sizeof(ASNItem)); i += 4) { - /* CUSTOM_SEQ */ - certExtsASN[i+0] = (ASNItem) { 0, ASN_SEQUENCE, 1, 1, 0 }; - /* CUSTOM_OID */ - certExtsASN[i+1] = (ASNItem) { 1, ASN_OBJECT_ID, 0, 0, 0 }; - /* CUSTOM_CRIT */ - certExtsASN[i+2] = (ASNItem) { 1, ASN_BOOLEAN, 0, 0, 0 }; - /* CUSTOM_STR */ - certExtsASN[i+3] = (ASNItem) { 1, ASN_OCTET_STRING, 0, 0, 0 }; + XMEMCPY(&certExtsASN[i], customExtASN, sizeof(customExtASN)); } (void)forRequest; @@ -23570,7 +23568,8 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, cert->extCustom.oid, cert->extCustom.oidSz); SetASN_Buffer(&dataASN[CERTEXTSASN_IDX_CUSTOM_STR], cert->extCustom.val, cert->extCustom.valSz); - } else + } + else #endif { /* Don't write out custom OID. */ @@ -23583,7 +23582,7 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, for (; i < cert->customCertExtCount; i++) { int idx = CERTEXTSASN_IDX_START_CUSTOM + (i * 4); word32 encodedOidSz = MAX_OID_SZ; - idx ++; /* Skip one for for SEQ. */ + idx++; /* Skip one for for SEQ. */ /* EncodePolicyOID() will never return error since we parsed this * OID when it was set. */ EncodePolicyOID(&encodedOids[i * MAX_OID_SZ], &encodedOidSz, @@ -23591,7 +23590,11 @@ static int EncodeExtensions(Cert* cert, byte* output, word32 maxSz, SetASN_Buffer(&dataASN[idx], &encodedOids[i * MAX_OID_SZ], encodedOidSz); idx++; - SetASN_Boolean(&dataASN[idx], cert->customCertExt[i].crit); + if (cert->customCertExt[i].crit) { + SetASN_Boolean(&dataASN[idx], 1); + } else { + dataASN[idx].noOut = 1; + } idx++; SetASN_Buffer(&dataASN[idx], cert->customCertExt[i].val, cert->customCertExt[i].valSz); From 98f733767bec7c68b2efc8637564b84c6650820c Mon Sep 17 00:00:00 2001 From: Anthony Hu Date: Wed, 9 Mar 2022 17:20:50 -0500 Subject: [PATCH 12/12] Use MAX_OID_SZ --- wolfcrypt/src/asn.c | 4 ++-- wolfcrypt/src/ecc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 0d2f25f0c..082dcfe52 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -5119,7 +5119,7 @@ static int DumpOID(const byte* oidData, word32 oidSz, word32 oid, #ifdef HAVE_OID_DECODING { - word16 decOid[16]; + word16 decOid[MAX_OID_SZ]; word32 decOidSz = sizeof(decOid); /* Decode the OID into dotted form. */ ret = DecodeObjectId(oidData, oidSz, decOid, &decOidSz); @@ -16978,7 +16978,7 @@ end: &isUnknownExt); #if defined(WOLFSSL_CUSTOM_OID) && defined(HAVE_OID_DECODING) if (isUnknownExt && (cert->unknownExtCallback != NULL)) { - word16 decOid[16]; + word16 decOid[MAX_OID_SZ]; word32 decOidSz = sizeof(decOid); ret = DecodeObjectId( dataASN[CERTEXTASN_IDX_OID].data.oid.data, diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 12470349b..864f40ac6 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -4049,7 +4049,7 @@ int wc_ecc_get_curve_id_from_oid(const byte* oid, word32 len) int curve_idx; #ifdef HAVE_OID_DECODING int ret; - word16 decOid[16]; + word16 decOid[MAX_OID_SZ]; word32 decOidSz = sizeof(decOid); #endif