Skip to content
Open
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
56 changes: 56 additions & 0 deletions doc/dox_comments/header_files/asn_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -3889,6 +3889,62 @@ int wc_SetCustomExtension(Cert *cert, int critical, const char *oid,
*/
int wc_SetUnknownExtCallback(DecodedCert* cert,
wc_UnknownExtCallback cb);

/*!
\ingroup ASN

\brief This function registers a callback that will be used anytime
wolfSSL encounters an unknown OID within the Extended Key Usage (EKU)
extension in a certificate while parsing. The prototype of the callback
should be:

\code
int myUnknownEKUCallback(const word16* oid, word32 oidSz);
\endcode

\return 0 Returned on success.
\return BAD_FUNC_ARG Returned when cert is NULL.

\param cert the DecodedCert struct that is to be associated with this
callback.
\param cb function to register as the unknown EKU OID callback.

_Example_
\code
int ret = 0;
DecodedCert cert;

// Unknown EKU callback prototype
int myUnknownEKUCallback(const word16* oid, word32 oidSz);

// Initialize cert, then register callback
ret = wc_SetUnknownExtKeyUsageCallback(&cert, myUnknownEKUCallback);
if (ret != 0) {
// failed to set the callback
}

// oid: Array of integers that are the dot separated values in an OID.
// For example, OID 1.2.3.4.5 would be {1, 2, 3, 4, 5}.
// oidSz: Number of values in oid array.
int myUnknownEKUCallback(const word16* oid, word32 oidSz) {

// Logic to handle unknown EKU OID goes here.
// For example, check if the OID is acceptable for your application.

// NOTE: by returning zero, we are accepting this OID and
// informing wolfSSL that it is acceptable. If you find an OID
// that you do not find acceptable, you should return an error
// which will cause certificate parsing to fail.
return 0;
}
\endcode

\sa ParseCert
\sa wc_SetUnknownExtCallback
*/
int wc_SetUnknownExtKeyUsageCallback(DecodedCert* cert,
wc_UnknownExtKeyUsageCallback cb);

/*!
\ingroup ASN

Expand Down
2 changes: 1 addition & 1 deletion src/x509.c
Original file line number Diff line number Diff line change
Expand Up @@ -3602,7 +3602,7 @@ static int wolfSSL_ASN1_STRING_into_old_ext_fmt(WOLFSSL_ASN1_STRING *asn1str,

ret = DecodeExtKeyUsage((const byte*)asn1str->data, asn1str->length,
&extExtKeyUsageSrc, &extExtKeyUsageSz, &extExtKeyUsageCount,
&extExtKeyUsage, &extExtKeyUsageSsh);
&extExtKeyUsage, &extExtKeyUsageSsh, NULL);
if (ret != 0)
return ret;

Expand Down
106 changes: 103 additions & 3 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -22031,6 +22031,7 @@ enum {
* @param [out] extExtKeyUsageCount Number of usages read.
* @param [out] extExtKeyUsage Usages read.
* @param [out] extExtKeyUsageSsh SSH usages read.
* @param [in] unknownCb Callback for unknown EKU OIDs.
* @return 0 on success.
* @return ASN_BITSTR_E when the expected BIT_STRING tag is not found.
* @return ASN_PARSE_E when BER encoded data does not match ASN.1 items or
Expand All @@ -22040,18 +22041,30 @@ enum {
int DecodeExtKeyUsage(const byte* input, word32 sz,
const byte **extExtKeyUsageSrc, word32 *extExtKeyUsageSz,
word32 *extExtKeyUsageCount, byte *extExtKeyUsage,
byte *extExtKeyUsageSsh)
byte *extExtKeyUsageSsh,
#ifdef WC_ASN_UNKNOWN_EXT_CB
wc_UnknownExtKeyUsageCallback unknownCb
#else
void *unknownCb
#endif
)
{
#ifndef WOLFSSL_ASN_TEMPLATE
word32 idx = 0, oid;
int length, ret;
#ifdef WC_ASN_UNKNOWN_EXT_CB
word32 oidStartIdx;
#endif

WOLFSSL_ENTER("DecodeExtKeyUsage");

(void) extExtKeyUsageSrc;
(void) extExtKeyUsageSz;
(void) extExtKeyUsageCount;
(void) extExtKeyUsageSsh;
#ifndef WC_ASN_UNKNOWN_EXT_CB
(void) unknownCb;
#endif

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
*extExtKeyUsageSrc = NULL;
Expand All @@ -22074,9 +22087,34 @@ int DecodeExtKeyUsage(const byte* input, word32 sz,
#endif

while (idx < (word32)sz) {
#ifdef WC_ASN_UNKNOWN_EXT_CB
oidStartIdx = idx;
#endif
ret = GetObjectId(input, &idx, &oid, oidCertKeyUseType, sz);
if (ret == WC_NO_ERR_TRACE(ASN_UNKNOWN_OID_E))
if (ret == WC_NO_ERR_TRACE(ASN_UNKNOWN_OID_E)) {
#ifdef WC_ASN_UNKNOWN_EXT_CB
if (unknownCb != NULL) {
word16 decOid[MAX_OID_SZ];
word32 decOidSz = sizeof(decOid);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buffer size passed as bytes instead of elements

Medium Severity

decOidSz is initialized to sizeof(decOid) which yields the byte size (MAX_OID_SZ * sizeof(word16) = 64), but DecodeObjectId interprets *outSz as the number of elements in the array (documented as "On in, number of elements in array"). The decOid array only holds MAX_OID_SZ (32) elements. The bounds check inside DecodeObjectId (y >= (int)*outSz) would allow writing up to index 63, causing a stack buffer overflow for OIDs with more than ~31 dotted components. The correct value is MAX_OID_SZ or sizeof(decOid)/sizeof(decOid[0]). This follows a pre-existing pattern elsewhere in the file, but each new call site is a new exploitable path reachable via a crafted certificate.

Additional Locations (2)

Fix in Cursor Fix in Web

/* Skip past the tag and length to get raw OID bytes */
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@aisle-analyzer , does this comment make sense?

word32 oidIdx = oidStartIdx;
int oidLen;
byte tag;
if (GetASNTag(input, &oidIdx, &tag, sz) == 0 &&
tag == ASN_OBJECT_ID &&
GetLength(input, &oidIdx, &oidLen, sz) >= 0) {
ret = DecodeObjectId(input + oidIdx, (word32)oidLen,
decOid, &decOidSz);
if (ret == 0) {
ret = unknownCb(decOid, decOidSz);
}
if (ret != 0)
return ret;
}
}
#endif
continue;
}
else if (ret < 0)
return ret;

Expand Down Expand Up @@ -22127,13 +22165,19 @@ int DecodeExtKeyUsage(const byte* input, word32 sz,
word32 idx = 0;
int length;
int ret = 0;
#ifdef WC_ASN_UNKNOWN_EXT_CB
int isKnownOid;
#endif

WOLFSSL_ENTER("DecodeExtKeyUsage");

(void) extExtKeyUsageSrc;
(void) extExtKeyUsageSz;
(void) extExtKeyUsageCount;
(void) extExtKeyUsageSsh;
#ifndef WC_ASN_UNKNOWN_EXT_CB
(void) unknownCb;
#endif

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
*extExtKeyUsageSrc = NULL;
Expand Down Expand Up @@ -22171,9 +22215,29 @@ int DecodeExtKeyUsage(const byte* input, word32 sz,
input, &idx, sz);
/* Skip unknown OIDs. */
if (ret == WC_NO_ERR_TRACE(ASN_UNKNOWN_OID_E)) {
#ifdef WC_ASN_UNKNOWN_EXT_CB
if (unknownCb != NULL) {
word16 decOid[MAX_OID_SZ];
word32 decOidSz = sizeof(decOid);
ret = DecodeObjectId(
dataASN[KEYPURPOSEIDASN_IDX_OID].data.oid.data,
dataASN[KEYPURPOSEIDASN_IDX_OID].data.oid.length,
decOid, &decOidSz);
if (ret == 0) {
ret = unknownCb(decOid, decOidSz);
}
}
else {
ret = 0;
}
#else
ret = 0;
#endif
}
else if (ret == 0) {
#ifdef WC_ASN_UNKNOWN_EXT_CB
isKnownOid = 1;
#endif
/* Store the bit for the OID. */
switch (dataASN[KEYPURPOSEIDASN_IDX_OID].data.oid.sum) {
case EKU_ANY_OID:
Expand All @@ -22197,7 +22261,28 @@ int DecodeExtKeyUsage(const byte* input, word32 sz,
case EKU_OCSP_SIGN_OID:
*extExtKeyUsage |= EXTKEYUSE_OCSP_SIGN;
break;
#ifdef WC_ASN_UNKNOWN_EXT_CB
default:
isKnownOid = 0;
break;
#endif
}

#ifdef WC_ASN_UNKNOWN_EXT_CB
/* Handle unknown OIDs that parsed successfully but aren't
* recognized */
if (!isKnownOid && unknownCb != NULL) {
word16 decOid[MAX_OID_SZ];
word32 decOidSz = sizeof(decOid);
ret = DecodeObjectId(
dataASN[KEYPURPOSEIDASN_IDX_OID].data.oid.data,
dataASN[KEYPURPOSEIDASN_IDX_OID].data.oid.length,
decOid, &decOidSz);
if (ret == 0) {
ret = unknownCb(decOid, decOidSz);
}
}
#endif

#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)
/* Keep count for WOLFSSL_X509. */
Expand Down Expand Up @@ -22238,7 +22323,12 @@ static int DecodeExtKeyUsageInternal(const byte* input, word32 sz,
#endif
&cert->extExtKeyUsage,
#ifdef WOLFSSL_WOLFSSH
&cert->extExtKeyUsageSsh
&cert->extExtKeyUsageSsh,
#else
NULL,
#endif
#ifdef WC_ASN_UNKNOWN_EXT_CB
cert->unknownExtKeyUsageCallback
#else
NULL
#endif
Expand Down Expand Up @@ -23663,6 +23753,16 @@ int wc_SetUnknownExtCallbackEx(DecodedCert* cert,
cert->unknownExtCallbackExCtx = ctx;
return 0;
}

int wc_SetUnknownExtKeyUsageCallback(DecodedCert* cert,
wc_UnknownExtKeyUsageCallback cb) {
if (cert == NULL) {
return BAD_FUNC_ARG;
}

cert->unknownExtKeyUsageCallback = cb;
return 0;
}
#endif /* WC_ASN_UNKNOWN_EXT_CB */

/*
Expand Down
12 changes: 11 additions & 1 deletion wolfssl/wolfcrypt/asn.h
Original file line number Diff line number Diff line change
Expand Up @@ -1721,6 +1721,7 @@ typedef int (*wc_UnknownExtCallback)(const word16* oid, word32 oidSz, int crit,
typedef int (*wc_UnknownExtCallbackEx)(const word16* oid, word32 oidSz,
int crit, const unsigned char* der,
word32 derSz, void *ctx);
typedef int (*wc_UnknownExtKeyUsageCallback)(const word16* oid, word32 oidSz);
#endif

struct DecodedCert {
Expand Down Expand Up @@ -2052,6 +2053,7 @@ struct DecodedCert {
wc_UnknownExtCallback unknownExtCallback;
wc_UnknownExtCallbackEx unknownExtCallbackEx;
void *unknownExtCallbackExCtx;
wc_UnknownExtKeyUsageCallback unknownExtKeyUsageCallback;
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* Subject Alternative Public Key Info */
Expand Down Expand Up @@ -2277,6 +2279,8 @@ WOLFSSL_API int wc_SetUnknownExtCallback(DecodedCert* cert,
WOLFSSL_API int wc_SetUnknownExtCallbackEx(DecodedCert* cert,
wc_UnknownExtCallbackEx cb,
void *ctx);
WOLFSSL_API int wc_SetUnknownExtKeyUsageCallback(DecodedCert* cert,
wc_UnknownExtKeyUsageCallback cb);
#endif

WOLFSSL_LOCAL int DecodePolicyOID(char *out, word32 outSz, const byte *in,
Expand Down Expand Up @@ -2341,7 +2345,13 @@ WOLFSSL_LOCAL int DecodeKeyUsage(const byte* input, word32 sz,
WOLFSSL_LOCAL int DecodeExtKeyUsage(const byte* input, word32 sz,
const byte **extExtKeyUsageSrc, word32 *extExtKeyUsageSz,
word32 *extExtKeyUsageCount, byte *extExtKeyUsage,
byte *extExtKeyUsageSsh);
byte *extExtKeyUsageSsh,
#ifdef WC_ASN_UNKNOWN_EXT_CB
wc_UnknownExtKeyUsageCallback unknownCb
#else
void *unknownCb
#endif
);

WOLFSSL_LOCAL int TryDecodeRPKToKey(DecodedCert* cert);
WOLFSSL_LOCAL int wc_GetPubX509(DecodedCert* cert, int verify, int* badDate);
Expand Down