Skip to content

Fixed encode policy oid - #11019

Open
stenslae wants to merge 1 commit into
wolfSSL:masterfrom
stenslae:fix-encodepolicyoid-multibyte-arc
Open

Fixed encode policy oid#11019
stenslae wants to merge 1 commit into
wolfSSL:masterfrom
stenslae:fix-encodepolicyoid-multibyte-arc

Conversation

@stenslae

Copy link
Copy Markdown
Member

Description

Fixed a bug in EncodePolicyOID where combined first identifiers (the first two OID arcs) were improperly cast to a single byte when exceeding 127, rather than using the required ITU-T X.690 base-128 continuation encoding. Also added improved bounds checking.

Testing

Added new test coverage to exercise these changes.

Checklist

  • added tests
  • updated/added doxygen
  • updated appropriate READMEs
  • Updated manual and documentation

@stenslae stenslae self-assigned this Jul 30, 2026

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

No new issues found in the changed files. ✅

@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 49ac912 to 6755e0b Compare July 30, 2026 16:32
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

gcc-arm-cortex-m4

  • FLASH: .rodata.CSWTCH.1 +4 B, .rodata.str1.1 +43 B (+0.0%, 201,886 B / 262,144 B, total: 77% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .rodata.CSWTCH.1 +4 B, .rodata.str1.1 +43 B (+0.0%, 176,025 B / 262,144 B, total: 67% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .rodata +64 B, .text +384 B (+0.1%, 775,932 B / 1,048,576 B, total: 74% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .rodata.CSWTCH.1 +4 B, .rodata.str1.1 +43 B, .text -32 B (+0.0%, 214,850 B / 262,144 B, total: 82% used)

gcc-arm-cortex-m4-pq

  • FLASH: .rodata +52 B, .text -144 B (-0.0%, 297,536 B / 1,048,576 B, total: 28% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .rodata +48 B, .text -64 B (-0.0%, 328,096 B / 1,048,576 B, total: 31% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .rodata.CSWTCH.1 +4 B, .rodata.str1.1 +43 B (+0.0%, 238,416 B / 262,144 B, total: 91% used)

gcc-arm-cortex-m7

  • FLASH: .rodata.CSWTCH.1 +4 B, .rodata.str1.1 +43 B (+0.0%, 201,886 B / 262,144 B, total: 77% used)

gcc-arm-cortex-m7-pq

  • FLASH: .rodata +52 B, .text -80 B (-0.0%, 298,496 B / 1,048,576 B, total: 28% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .rodata.CSWTCH.1 +4 B, .rodata.str1.1 +43 B (+0.0%, 238,480 B / 262,144 B, total: 91% used)

linuxkm-pie

  • Data: __patchable_function_entries +32 B (+0.1%, 26,592 B)

linuxkm-standard

  • Data: __patchable_function_entries +24 B (+0.0%, 49,400 B)

stm32-sim-stm32h753

@stenslae
stenslae requested review from wolfSSL-Fenrir-bot and removed request for wolfSSL-Fenrir-bot July 30, 2026 16:47

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

No new issues found in the changed files. ✅

@stenslae stenslae removed their assignment Jul 30, 2026
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 6755e0b to 47a52ac Compare July 30, 2026 19:21

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

No new issues found in the changed files. ✅

@stenslae

Copy link
Copy Markdown
Member Author

jenkins retest this please

Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread wolfcrypt/src/asn.c Outdated
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 47a52ac to 9aee0e8 Compare August 5, 2026 21:50

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

Findings: 2
2 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread tests/api/test_asn.c
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread tests/api/test_asn.c
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 9aee0e8 to c07964a Compare August 5, 2026 22:28

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

No new issues found in the changed files. ✅

@dgarske
dgarske self-requested a review August 6, 2026 00:37
Comment thread wolfcrypt/src/asn.c

while (*idx < inSz) {
if (in[*idx] & 0x80) {
if (cnt == 0 && in[*idx] == 0x80)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The new DecodeOidArc() applies its non-minimal-encoding check (cnt == 0 && in[*idx] == 0x80) and its word32-overflow check (v > (0xFFFFFFFFU >> 7)) unconditionally, i.e. to every arc, not just the first identifier. The strict flag only changes what happens when the input ends mid-continuation. The old loop tolerated both of these for arcs after the first identifier: a leading 0x80 simply contributed 0, and an overflowing shift silently wrapped. Because DecodeCertPolicy() (asn.c:21443) treats any <= 0 return as fatal and returns ASN_PARSE_E, a certificate carrying such a policy OID now fails to parse entirely where it previously parsed. I confirmed this against the built library: {0x2a, 0x80, 0x03} used to decode to "1.2.3" and now returns -144 (ASN_OBJECT_ID_E); {0x2a, 0x90, 0x80, 0x80, 0x80, 0x00} (arc == 2^32) used to render as ".0" and now returns -144. Rejecting is the more correct DER posture and is probably intended, but the PR body only describes an encoder fix plus "improved bounds checking", and the new doxygen note on wc_DecodePolicyOID only mentions the first-identifier strictness and the 2.40-2.47 rendering change.

Recommendation: Confirm the parse-side strictness is intended, then (a) extend the wc_DecodePolicyOID note to cover later arcs

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Confirmed the parse-side strictness is intended and added fixes on the decode route.

Comment thread tests/api/test_asn.c Outdated
* whatever partial value had accumulated so far. */
{
const byte truncated[] = { 0x81, 0x81 };
ExpectIntLT(DecodePolicyOID(decoded, sizeof(decoded),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

DecodeOidArc()'s strict parameter changes behavior in exactly one place: end-of-input mid-continuation returns ASN_OBJECT_ID_E when strict and ASN_OID_ARC_TRUNCATED (silently dropping the partial arc) when not. Test 16 covers only the strict side ({0x81, 0x81} as a first identifier). Nothing in the new suite exercises a truncated trailing arc, so the if (ret == ASN_OID_ARC_TRUNCATED) break; path in wc_DecodePolicyOID and the return strict ? ... : ASN_OID_ARC_TRUNCATED line are both untested. I verified the intended behavior against the built library: {0x2a, 0x81} returns 3 with "1.2". Similarly, the newly-strict later-arc paths described in the previous finding (non-minimal {0x2a, 0x80, 0x03} and overflow {0x2a, 0x90, 0x80, 0x80, 0x80, 0x00}, both -144) have no assertions, so a future relaxation of that behavior would pass CI silently. The heap != NULL path through wc_EncodePolicyOID (which is what every in-tree caller except the OpenSSL-compat layer uses) is also never exercised.

Recommendation: Add the truncated-trailing-arc, non-minimal-later-arc, overflow-later-arc, and max-word32-arc cases above, plus at least one wc_EncodePolicyOID call with a non-NULL heap so the XMALLOC/XFREE pairing on the heap-hint path is exercised.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Added suggested test coverage

Comment thread wolfcrypt/src/asn.c Outdated
len = (word32)XSTRLEN(in);
if (len == 0 || in[0] == '.' || in[len - 1] == '.')
return ASN_OBJECT_ID_E;
if (XSTRSTR(in, "..") != NULL)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The new empty-arc rejection calls XSTRSTR(in, ".."). Grepping the tree, this is the only XSTRSTR use in wolfcrypt/src/*.c, and wolfssl/wolfcrypt/types.h:1021-1023 carries an explicit note directly above the definition: "strstr, strncmp, strcmp, and strncat only used by wolfSSL proper, not required for wolfCrypt only". Ports that build with STRING_USER and supply only the wolfCrypt-required X-macros will now fail to compile wolfcrypt/src/asn.c under --enable-certgen --enable-certext, a wolfCrypt-only configuration. The check is also redundant work: the function already walks the whole string in ParseOidArc per token, and the three pre-scans (XSTRLEN, in[0], in[len-1], XSTRSTR) can collapse into one pass.

Recommendation: Replace XSTRSTR with an inline scan so wolfcrypt/src/asn.c does not gain a dependency on a string routine that types.h documents as wolfSSL-proper-only.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Used inline scan instead

Comment thread wolfssl/wolfcrypt/asn.h Outdated
WOLFSSL_TEST_VIS int wc_EncodePolicyOID(byte *out, word32 *outSz,
const char *in, void* heap);
/* Deprecated public API names kept for backwards build compatibility */
#define DecodePolicyOID(out, outSz, in, inSz) \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We actually do not need the old macros because they were WOLFSSL_LOCAL. If anywhere else in our code base is using them we should rename those. If customers are using this in a static build (for example) they will need to update their code.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The old macros have been removed and any remaining internal usages were renamed to use the wc_ prefix.

Comment thread wolfcrypt/src/asn_orig.c
@@ -5547,7 +5547,7 @@ static int SetCertificatePolicies(byte *output,
oidSz = sizeof(oid);
XMEMSET(oid, 0, oidSz);

ret = EncodePolicyOID(oid, &oidSz, input[i], heap);
ret = wc_EncodePolicyOID(oid, &oidSz, input[i], heap);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The PR renamed EncodePolicyOID -> wc_EncodePolicyOID at asn_orig.c:5550 but left DecodePolicyOID at asn_orig.c:4227 on the old spelling, relying on the new header macro. Same file, same PR, two conventions. asn_orig.c is #included into asn.c (asn.c:39546) so it compiles either way, but the inconsistency is the reason the compat macros cannot be deleted.

Recommendation: Rename this call site to wc_DecodePolicyOID to match the other in-tree call sites updated by this PR.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Changed to wc_

Comment thread wolfcrypt/src/asn.c Outdated
@@ -21229,58 +21229,114 @@ static int DecodeNameConstraints(const byte* input, word32 sz,
#if defined(WOLFSSL_CERT_EXT) || \
defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL)

/* returned by DecodeOidArc() (in place of 0/ASN_OBJECT_ID_E) when the
* input ends mid-continuation with no terminating byte and strict==0 */
#define ASN_OID_ARC_TRUNCATED 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Recommendation: Either rename out of the ASN_* namespace and #undef at the end of the guarded block, or replace the sentinel with an int* truncated out-parameter so the function keeps asn.c's usual 0/negative return contract.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Replaced the sentinel with an int* truncated out-parameter to maintain the standard 0/negative return contract.

Comment thread src/ssl_asn1.c
}

if ((bufSz = DecodePolicyOID(buf, (word32)bufSz, a->obj + idx,
if ((bufSz = wc_DecodePolicyOID(buf, (word32)bufSz, a->obj + idx,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The doc comment states "String is of the form ... and is always NUL terminated. Truncated when the buffer is too small." The PR tightens wc_DecodePolicyOID's length checks from w > outSz - outIdx to w >= outSz - outIdx and adds a bound check on the first XSNPRINTF that had none, so the exact-fit case that previously produced a silently truncated (and therefore wrong) OID string now returns BUFFER_E, which this function maps to WOLFSSL_FAILURE. The stricter behavior is the right call - a silently shortened OID string is worse than an error, and the missing first-XSNPRINTF check was an out-of-bounds out[outIdx] = 0 write when the first identifier alone overflowed the caller's buffer - but the comment now describes behavior the code no longer has, and it diverges from OpenSSL's OBJ_obj2txt, which truncates and returns the length that would have been needed.

Code:

         * String is of the form "1.2.840.113549.1.9.1" and is always NUL
         * terminated. Truncated when the buffer is too small.
         ...
         * @return  0 when decoding the object fails.

Recommendation: Update the comment to say the call fails rather than truncates on a short buffer, and note the OpenSSL-compat divergence if it matters for callers of wolfSSL_OBJ_obj2txt(buf, small, obj, 1).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I've updated the doc comment to explicitly state that the function will fail and return BUFFER_E when the buffer is too small. I also added a note regarding the divergence from OpenSSL's OBJ_obj2txt behavior.

@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from c07964a to c5b3eed Compare August 6, 2026 17:53
Comment thread tests/api/test_asn.c Outdated
Comment thread tests/api/test_ossl_asn1.c
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from e530c44 to 4071edc Compare August 7, 2026 21:49
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 4071edc to 381b1a8 Compare August 7, 2026 21:53

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src

Findings: 7
7 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c Outdated
Comment thread tests/api/test_ossl_obj.c
Comment thread tests/api/test_asn.c
Comment thread src/x509.c
Comment thread tests/api/test_ossl_obj.c
Comment thread src/x509.c
Comment thread tests/api/test_ossl_obj.c
Comment thread tests/api/test_asn.c
Comment thread src/x509.c
Comment thread src/x509.c
Comment thread tests/api/test_ossl_obj.c
Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c Outdated
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 381b1a8 to 0fbefc3 Compare August 12, 2026 16:13

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfssl-bugs
Failed targets: wolfcrypt-src, wolfssl-src

Findings: 5
5 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c
Comment thread tests/api/test_asn.c Outdated
Comment thread tests/unit-mcdc/test_asn_ext_whitebox.c Outdated
Comment thread wolfssl/wolfcrypt/asn_public.h Outdated
Comment thread wolfssl/wolfcrypt/asn_public.h Outdated
Comment thread tests/unit-mcdc/test_asn_ext_whitebox.c Outdated
Comment thread tests/api/test_asn.c Outdated
Comment thread wolfcrypt/src/asn.c
Comment thread wolfcrypt/src/asn.c
@stenslae
stenslae force-pushed the fix-encodepolicyoid-multibyte-arc branch from 0fbefc3 to 0f22bbb Compare August 12, 2026 21:09
@stenslae
stenslae requested review from dgarske and wolfSSL-Fenrir-bot and removed request for wolfSSL-Fenrir-bot August 12, 2026 21:10

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11019

Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfssl-bugs
Failed targets: wolfcrypt-src, wolfssl-src

Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread wolfcrypt/src/asn.c
(decodeRet == WC_NO_ERR_TRACE(BUFFER_E))) {
WOLFSSL_MSG("\tSkipping policy OID that doesn't fit");
skipPolicy = 1;
cert->extCertPoliciesTruncated = 1;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟠 [Medium] extCertPoliciesTruncated not set when the MAX_CERTPOL_NB cap drops policies · API contract violations

extCertPoliciesTruncated is set only for the ASN_OID_ARC_TOO_BIG_E/BUFFER_E skip path. When the while-loop guard extCertPoliciesNb < MAX_CERTPOL_NB (asn.c:21448, asn_orig.c:4281) ends parsing early, entries are dropped with the flag left 0, so wc_CertGetPoliciesTruncated() reports 0 for any cert carrying more than MAX_CERTPOL_NB (2) policies.

Fix: Set cert->extCertPoliciesTruncated = 1 after the loop when it exited on the MAX_CERTPOL_NB cap with input remaining, in both asn.c and asn_orig.c.

Comment thread tests/api/test_asn.c
{
EXPECT_DECLS;

#if (defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT)) \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 [Low] test_wc_EncodePolicyOID guard is looser than the implementation's NO_CERTS guard · API contract violations

wc_EncodePolicyOID and wc_DecodePolicyOID are compiled inside #ifndef NO_CERTS in wolfcrypt/src/asn.c (blocks opened at line 16894 and 27321). The new test's guard omits !defined(NO_CERTS), so an OPENSSL_EXTRA + NO_CERTS build references symbols that do not exist. The sibling test test_wc_EncodePolicyOID_certgen (line 2451) and the mcdc test (test_asn_keys_whitebox.c:1384) both include that condition.

Fix: Add !defined(NO_CERTS) && !defined(NO_ASN) to the #if guard of test_wc_EncodePolicyOID.

Comment thread tests/api/test_asn.c
wc_InitDecodedCert(&decoded, der, (word32)certSz, HEAP_HINT);
ExpectIntEQ(wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL),
0);
ExpectIntEQ(decoded.extCertPoliciesNb, 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚪ [Info] New BUFFER_E skip branch in DecodeCertPolicy is not exercised · Missing edge-case coverage on a function the PR also changed

DecodeCertPolicy now skips a policy (rather than failing the cert) on two decode results: ASN_OID_ARC_TOO_BIG_E and BUFFER_E (wolfcrypt/src/asn.c:21504). Only the ASN_OID_ARC_TOO_BIG_E arm is covered; the BUFFER_E arm — a policy whose dotted string exceeds MAX_CERTPOL_SZ — is reachable (up to 127 OID content bytes) but untested.

Fix: Add a cert case whose policy OID decodes to more than MAX_CERTPOL_SZ characters and assert the policy is skipped with the truncated flag set.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants