All of lore.kernel.org
 help / color / mirror / Atom feed
* [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689
@ 2026-09-07 10:22 ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 2/33] libnfs: patch CVE-2026-57918 ankur.tyagi85
                   ` (31 more replies)
  0 siblings, 32 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-53689

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../libnfs/libnfs/CVE-2026-53689.patch        | 34 +++++++++++++++++++
 .../libnfs/libnfs_6.0.2.bb                    |  1 +
 2 files changed, 35 insertions(+)
 create mode 100644 meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-53689.patch

diff --git a/meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-53689.patch b/meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-53689.patch
new file mode 100644
index 0000000000..0c624c7219
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-53689.patch
@@ -0,0 +1,34 @@
+From d45a7d6cdc899ac2a62abc21280d674ae91ae0ae Mon Sep 17 00:00:00 2001
+From: Ronnie Sahlberg <ronniesahlberg@gmail.com>
+Date: Wed, 10 Jun 2026 11:43:28 +1000
+Subject: [PATCH] ZDR: check the string size for sanity
+
+It could otherwise cause an overflow in the bounds check later.
+
+Reported-by: Nick Hummel <nickhummel@google.com>
+Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
+(cherry picked from commit 55c18ea33a83d667f79f0ef209c96895795c729f)
+
+CVE: CVE-2026-53689
+Upstream-Status: Backport [https://github.com/sahlberg/libnfs/commit/55c18ea33a83d667f79f0ef209c96895795c729f]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ lib/libnfs-zdr.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/lib/libnfs-zdr.c b/lib/libnfs-zdr.c
+index bc507eb..cbdb650 100644
+--- a/lib/libnfs-zdr.c
++++ b/lib/libnfs-zdr.c
+@@ -305,7 +305,9 @@ bool_t libnfs_zdr_string(ZDR *zdrs, char **strp, uint32_t maxsize)
+ 	if (!libnfs_zdr_u_int(zdrs, &size)) {
+ 		return FALSE;
+ 	}
+-
++	if (size > zdrs->size) {
++		return FALSE;
++	}
+ 	if (zdrs->pos + (int)size > zdrs->size) {
+ 		return FALSE;
+ 	}
diff --git a/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb b/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb
index 83f32d3a07..403bae9465 100644
--- a/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb
+++ b/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb
@@ -5,6 +5,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=825301ba17efc9d188ee0abd4b924ada"
 
 SRC_URI = "git://github.com/sahlberg/libnfs.git;protocol=https;branch=master \
            file://0001-CMakeLists.txt-respect-CMAKE_INSTALL_LIBDIR-for-mult.patch \
+           file://CVE-2026-53689.patch \
            "
 SRCREV = "18c5c73ee88bb7dc8da0d55dc95164bb77e49dc6"
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 2/33] libnfs: patch CVE-2026-57918
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 3/33] libssh: ignore CVE-2025-14821 ankur.tyagi85
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-57918

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../libnfs/libnfs/CVE-2026-57918.patch        | 34 +++++++++++++++++++
 .../libnfs/libnfs_6.0.2.bb                    |  1 +
 2 files changed, 35 insertions(+)
 create mode 100644 meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-57918.patch

diff --git a/meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-57918.patch b/meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-57918.patch
new file mode 100644
index 0000000000..27c99b5704
--- /dev/null
+++ b/meta-oe/recipes-connectivity/libnfs/libnfs/CVE-2026-57918.patch
@@ -0,0 +1,34 @@
+From 589568b88a06d92b298ecce563ae57b5fad91238 Mon Sep 17 00:00:00 2001
+From: Ronnie Sahlberg <ronniesahlberg@gmail.com>
+Date: Wed, 10 Jun 2026 12:21:58 +1000
+Subject: [PATCH] socket: prevent an underflow in xid
+
+if the expected pdu-size is larger than the absolute pdu size
+from the xid/record-marker.
+
+Reported-by: Nick Hummel <nickhummel@google.com>
+Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
+(cherry picked from commit 935b8db712b3c6649bc57ddc276526c4a31680de)
+
+CVE: CVE-2026-57918
+Upstream-Status: Backport [https://github.com/sahlberg/libnfs/commit/935b8db712b3c6649bc57ddc276526c4a31680de]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ lib/socket.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/lib/socket.c b/lib/socket.c
+index f51ca4d..8e38eb8 100644
+--- a/lib/socket.c
++++ b/lib/socket.c
+@@ -929,6 +929,9 @@ rpc_read_from_socket(struct rpc_context *rpc)
+                                 break;
+                         case READ_IOVEC:
+                                 rpc->pdu->read_count -= rpc->pdu_size;
++                                if (rpc->rm_xid[0] < rpc->pdu_size) {
++                                        return -1;
++                                }
+                                 rpc->rm_xid[0] -= rpc->pdu_size;
+                                 if (!rpc->rm_xid[0]) {
+                                         rpc_finished_pdu(rpc);
diff --git a/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb b/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb
index 403bae9465..36676708cb 100644
--- a/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb
+++ b/meta-oe/recipes-connectivity/libnfs/libnfs_6.0.2.bb
@@ -6,6 +6,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=825301ba17efc9d188ee0abd4b924ada"
 SRC_URI = "git://github.com/sahlberg/libnfs.git;protocol=https;branch=master \
            file://0001-CMakeLists.txt-respect-CMAKE_INSTALL_LIBDIR-for-mult.patch \
            file://CVE-2026-53689.patch \
+           file://CVE-2026-57918.patch \
            "
 SRCREV = "18c5c73ee88bb7dc8da0d55dc95164bb77e49dc6"
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 3/33] libssh: ignore CVE-2025-14821
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 2/33] libnfs: patch CVE-2026-57918 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 4/33] libssh: mark CVEs patched ankur.tyagi85
                   ` (29 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2025-14821

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-oe/recipes-support/libssh/libssh_0.11.5.bb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.5.bb b/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
index c28a417244..612cfdbb19 100644
--- a/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
+++ b/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
@@ -47,3 +47,5 @@ do_install_ptest () {
 }
 
 BBCLASSEXTEND = "native nativesdk"
+
+CVE_STATUS[CVE-2025-14821] = "not-applicable-platform: issue only applies on Windows"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 4/33] libssh: mark CVEs patched
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 2/33] libnfs: patch CVE-2026-57918 ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 3/33] libssh: ignore CVE-2025-14821 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 5/33] libssh: ignore CVE-2025-59842 ankur.tyagi85
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Changelog[1] also confirms the fix.

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-15370
https://nvd.nist.gov/vuln/detail/cve-2026-59843
https://nvd.nist.gov/vuln/detail/cve-2026-59844
https://nvd.nist.gov/vuln/detail/cve-2026-59845
https://nvd.nist.gov/vuln/detail/cve-2026-59846
https://nvd.nist.gov/vuln/detail/cve-2026-59847
https://nvd.nist.gov/vuln/detail/cve-2026-59848
https://nvd.nist.gov/vuln/detail/cve-2026-59849
https://nvd.nist.gov/vuln/detail/cve-2026-59850

[1]https://gitlab.com/libssh/libssh-mirror/-/blob/libssh-0.11.5/CHANGELOG?ref_type=tags

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-oe/recipes-support/libssh/libssh_0.11.5.bb | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.5.bb b/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
index 612cfdbb19..752bded528 100644
--- a/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
+++ b/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
@@ -49,3 +49,12 @@ do_install_ptest () {
 BBCLASSEXTEND = "native nativesdk"
 
 CVE_STATUS[CVE-2025-14821] = "not-applicable-platform: issue only applies on Windows"
+CVE_STATUS[CVE-2026-15370] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59843] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59844] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59845] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59846] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59847] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59848] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59849] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2026-59850] = "fixed-version: fixed in v0.11.5"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 5/33] libssh: ignore CVE-2025-59842
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (2 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 4/33] libssh: mark CVEs patched ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 6/33] miniupnpd: patch CVE-2026-5720 ankur.tyagi85
                   ` (27 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

The vulnerability exists in GSSAPI key exchange introduced in v0.12.0[1]
Also confirmed by libssh security advisory[2]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-59842

[1]https://gitlab.com/libssh/libssh-mirror/-/commit/88c2ea6752fab7b3da9cc4c51eaf632361a44080
[2]https://www.libssh.org/security/advisories/CVE-2026-59842.txt

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-oe/recipes-support/libssh/libssh_0.11.5.bb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/meta-oe/recipes-support/libssh/libssh_0.11.5.bb b/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
index 752bded528..5cc270477e 100644
--- a/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
+++ b/meta-oe/recipes-support/libssh/libssh_0.11.5.bb
@@ -58,3 +58,4 @@ CVE_STATUS[CVE-2026-59847] = "fixed-version: fixed in v0.11.5"
 CVE_STATUS[CVE-2026-59848] = "fixed-version: fixed in v0.11.5"
 CVE_STATUS[CVE-2026-59849] = "fixed-version: fixed in v0.11.5"
 CVE_STATUS[CVE-2026-59850] = "fixed-version: fixed in v0.11.5"
+CVE_STATUS[CVE-2025-59842] = "cpe-incorrect: the current version (0.11.5) is not affected"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 6/33] miniupnpd: patch CVE-2026-5720
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (3 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 5/33] libssh: ignore CVE-2025-59842 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 7/33] python3-zeroconf: patch CVE-2026-47180 ankur.tyagi85
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-5720

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../miniupnpd/files/CVE-2026-5720.patch       | 35 +++++++++++++++++++
 .../miniupnpd/miniupnpd_2.1.20191006.bb       |  1 +
 2 files changed, 36 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/miniupnpd/files/CVE-2026-5720.patch

diff --git a/meta-networking/recipes-connectivity/miniupnpd/files/CVE-2026-5720.patch b/meta-networking/recipes-connectivity/miniupnpd/files/CVE-2026-5720.patch
new file mode 100644
index 0000000000..902e8321a5
--- /dev/null
+++ b/meta-networking/recipes-connectivity/miniupnpd/files/CVE-2026-5720.patch
@@ -0,0 +1,35 @@
+From d1c82ab65fd685ceed28a1a0de29510df7c3c959 Mon Sep 17 00:00:00 2001
+From: Thomas Bernard <miniupnp@free.fr>
+Date: Mon, 23 Mar 2026 02:37:02 +0100
+Subject: [PATCH] upnphttp.c: fix removal of quotes in ParseHttpHeaders()
+
+the length of the string including the quotes must be at
+least 2 for the string to contain the 2 enclosing quotes !
+
+(cherry picked from commit f56bd09b2f2650126b832c5f30a65a09e28167fa)
+
+CVE: CVE-2026-5720
+Upstream-Status: Backport [https://github.com/miniupnp/miniupnp/commit/f56bd09b2f2650126b832c5f30a65a09e28167fa]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ upnphttp.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/upnphttp.c b/upnphttp.c
+index fc8ccb6..2d9a2a6 100644
+--- a/upnphttp.c
++++ b/upnphttp.c
+@@ -269,9 +269,10 @@ ParseHttpHeaders(struct upnphttp * h)
+ 					p++;
+ 				while(p[n]>=' ')
+ 					n++;
+-				if((p[0] == '"' && p[n-1] == '"')
+-				  || (p[0] == '\'' && p[n-1] == '\''))
++				if((n >= 2) && ((p[0] == '"' && p[n-1] == '"')
++				             || (p[0] == '\'' && p[n-1] == '\'')))
+ 				{
++					/* remove the quotes */
+ 					p++; n -= 2;
+ 				}
+ 				h->req_soapActionOff = p - h->req_buf;
diff --git a/meta-networking/recipes-connectivity/miniupnpd/miniupnpd_2.1.20191006.bb b/meta-networking/recipes-connectivity/miniupnpd/miniupnpd_2.1.20191006.bb
index b7ba37f290..0aadfe9cf6 100644
--- a/meta-networking/recipes-connectivity/miniupnpd/miniupnpd_2.1.20191006.bb
+++ b/meta-networking/recipes-connectivity/miniupnpd/miniupnpd_2.1.20191006.bb
@@ -14,6 +14,7 @@ DEPENDS += "iptables net-tools util-linux libmnl libnetfilter-conntrack openssl"
 SRC_URI = "http://miniupnp.tuxfamily.org/files/download.php?file=${BP}.tar.gz;downloadfilename=${BP}.tar.gz \
            file://miniupnpd.service \
            file://0001-Add-OpenEmbedded-cross-compile-case.patch \
+           file://CVE-2026-5720.patch \
            "
 SRC_URI[sha256sum] = "218fad7af31f3c22fb4c9db28a55a2a8b5067d41f5b38f52008a057a00d2206d"
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-python][wrynose][PATCH 7/33] python3-zeroconf: patch CVE-2026-47180
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (4 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 6/33] miniupnpd: patch CVE-2026-5720 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 8/33] python3-zeroconf: patch CVE-2026-47183 ankur.tyagi85
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-47180

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../python3-zeroconf/CVE-2026-47180.patch     | 110 ++++++++++++++++++
 .../python/python3-zeroconf_0.148.0.bb        |   2 +
 2 files changed, 112 insertions(+)
 create mode 100644 meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47180.patch

diff --git a/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47180.patch b/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47180.patch
new file mode 100644
index 0000000000..7d27066d6f
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47180.patch
@@ -0,0 +1,110 @@
+From 7ffd3a90230cb99bcae4350fcb8498c48044f6a6 Mon Sep 17 00:00:00 2001
+From: "J. Nick Koston" <nick@koston.org>
+Date: Sun, 17 May 2026 19:48:44 -0700
+Subject: [PATCH] fix: bound DNS compression-pointer chain depth in DNSIncoming
+ (#1719)
+
+(cherry picked from commit f9e23592137f30fdf7ef710dba065da31c79b1cf)
+
+CVE: CVE-2026-47180
+Upstream-Status: Backport [https://github.com/python-zeroconf/python-zeroconf/commit/f9e23592137f30fdf7ef710dba065da31c79b1cf]
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/zeroconf/_protocol/incoming.pxd |  2 +-
+ src/zeroconf/_protocol/incoming.py  | 14 ++++++++++----
+ tests/test_protocol.py              | 22 ++++++++++++++++++++++
+ 3 files changed, 33 insertions(+), 5 deletions(-)
+
+diff --git a/src/zeroconf/_protocol/incoming.pxd b/src/zeroconf/_protocol/incoming.pxd
+index feaa2a0..eface8d 100644
+--- a/src/zeroconf/_protocol/incoming.pxd
++++ b/src/zeroconf/_protocol/incoming.pxd
+@@ -83,7 +83,7 @@ cdef class DNSIncoming:
+         link_py_int=object,
+         linked_labels=cython.list
+     )
+-    cdef unsigned int _decode_labels_at_offset(self, unsigned int off, cython.list labels, cython.set seen_pointers)
++    cdef unsigned int _decode_labels_at_offset(self, unsigned int off, cython.list labels, cython.set seen_pointers, unsigned int depth)
+ 
+     @cython.locals(offset="unsigned int")
+     cdef void _read_header(self)
+diff --git a/src/zeroconf/_protocol/incoming.py b/src/zeroconf/_protocol/incoming.py
+index 2d977b6..d772f47 100644
+--- a/src/zeroconf/_protocol/incoming.py
++++ b/src/zeroconf/_protocol/incoming.py
+@@ -60,7 +60,7 @@ DNS_COMPRESSION_POINTER_LEN = 2
+ MAX_DNS_LABELS = 128
+ MAX_NAME_LENGTH = 253
+ 
+-DECODE_EXCEPTIONS = (IndexError, struct.error, IncomingDecodeError)
++DECODE_EXCEPTIONS = (IndexError, struct.error, IncomingDecodeError, RecursionError)
+ 
+ 
+ _seen_logs: dict[str, int | tuple] = {}
+@@ -409,7 +409,7 @@ class DNSIncoming:
+         labels: list[str] = []
+         seen_pointers: set[int] = set()
+         original_offset = self.offset
+-        self.offset = self._decode_labels_at_offset(original_offset, labels, seen_pointers)
++        self.offset = self._decode_labels_at_offset(original_offset, labels, seen_pointers, 0)
+         self._name_cache[original_offset] = labels
+         name = ".".join(labels) + "."
+         if len(name) > MAX_NAME_LENGTH:
+@@ -418,8 +418,14 @@ class DNSIncoming:
+             )
+         return name
+ 
+-    def _decode_labels_at_offset(self, off: _int, labels: list[str], seen_pointers: set[int]) -> int:
++    def _decode_labels_at_offset(
++        self, off: _int, labels: list[str], seen_pointers: set[int], depth: _int
++    ) -> int:
+         # This is a tight loop that is called frequently, small optimizations can make a difference.
++        if depth > MAX_DNS_LABELS:
++            raise IncomingDecodeError(
++                f"DNS compression pointer chain exceeds {MAX_DNS_LABELS} at {off} from {self.source}"
++            )
+         view = self.view
+         while off < self._data_len:
+             length = view[off]
+@@ -457,7 +463,7 @@ class DNSIncoming:
+             if not linked_labels:
+                 linked_labels = []
+                 seen_pointers.add(link_py_int)
+-                self._decode_labels_at_offset(link, linked_labels, seen_pointers)
++                self._decode_labels_at_offset(link, linked_labels, seen_pointers, depth + 1)
+                 self._name_cache[link_py_int] = linked_labels
+             labels.extend(linked_labels)
+             if len(labels) > MAX_DNS_LABELS:
+diff --git a/tests/test_protocol.py b/tests/test_protocol.py
+index edd87c2..bac2b44 100644
+--- a/tests/test_protocol.py
++++ b/tests/test_protocol.py
+@@ -1011,6 +1011,28 @@ def test_label_compression_attack():
+     assert len(parsed.answers()) == 1
+ 
+ 
++def test_dns_compression_pointer_chain_depth_attack() -> None:
++    """Test our wire parser rejects deeply chained compression pointers without recursing."""
++    # Build a packet with one question whose name is a 1500-deep chain of forward
++    # compression pointers, ending in a root label. Each pointer is 2 bytes,
++    # so chain length easily exceeds CPython's default recursion limit.
++    header = b"\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00"
++    # Question at offset 12: pointer to offset 18 (past the question's type/class).
++    question_name = bytes([0xC0, 18])
++    question_type_class = b"\x00\x01\x00\x01"
++    chain_depth = 1500
++    chain = bytearray()
++    for i in range(chain_depth):
++        target = 18 + 2 * (i + 1)
++        chain.append(0xC0 | (target >> 8))
++        chain.append(target & 0xFF)
++    chain.append(0x00)
++    packet = header + question_name + question_type_class + bytes(chain)
++    parsed = r.DNSIncoming(packet, ("1.2.3.4", 5353))
++    assert parsed.valid is False
++    assert parsed.questions == []
++
++
+ def test_dns_compression_loop_attack():
+     """Test our wire parser does not loop forever when dns compression is in a loop."""
+     packet = (
diff --git a/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb b/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
index fd083d6ee8..c405e83b8c 100644
--- a/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
+++ b/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
@@ -5,6 +5,8 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=9fe712b1bc27c5c4e9ecd7f31d208900"
 
 SRC_URI[sha256sum] = "03fcca123df3652e23d945112d683d2f605f313637611b7d4adf31056f681702"
 
+SRC_URI += "file://CVE-2026-47180.patch"
+
 inherit pypi python_poetry_core cython
 
 RDEPENDS:${PN} += " \


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-python][wrynose][PATCH 8/33] python3-zeroconf: patch CVE-2026-47183
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (5 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 7/33] python3-zeroconf: patch CVE-2026-47180 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 9/33] python3-zeroconf: patch CVE-2026-47184 ankur.tyagi85
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-47183

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../python3-zeroconf/CVE-2026-47183.patch     | 401 ++++++++++++++++++
 .../python/python3-zeroconf_0.148.0.bb        |   4 +-
 2 files changed, 404 insertions(+), 1 deletion(-)
 create mode 100644 meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47183.patch

diff --git a/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47183.patch b/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47183.patch
new file mode 100644
index 0000000000..a1ab4cbfe6
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47183.patch
@@ -0,0 +1,401 @@
+From 831dda6b9d17d6abd6e9501b45ad8b3573a8fab5 Mon Sep 17 00:00:00 2001
+From: "J. Nick Koston" <nick@koston.org>
+Date: Sun, 17 May 2026 20:58:18 -0700
+Subject: [PATCH] fix: bound _seen_logs and stop retaining exc_info (#1717)
+
+(cherry picked from commit 95561e28b24922358f1991e38e3a86d70d72dcec)
+
+CVE: CVE-2026-47183
+Upstream-Status: Backport [https://github.com/python-zeroconf/python-zeroconf/commit/95561e28b24922358f1991e38e3a86d70d72dcec]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/zeroconf/_logger.py            | 89 +++++++++++++++++++-----------
+ src/zeroconf/_protocol/incoming.py | 12 +---
+ tests/benchmarks/test_mark_seen.py | 39 +++++++++++++
+ tests/test_logger.py               | 87 +++++++++++++++++++++++++++--
+ tests/test_protocol.py             | 34 ++++++++++++
+ 5 files changed, 214 insertions(+), 47 deletions(-)
+ create mode 100644 tests/benchmarks/test_mark_seen.py
+
+diff --git a/src/zeroconf/_logger.py b/src/zeroconf/_logger.py
+index 0d734df..99990cf 100644
+--- a/src/zeroconf/_logger.py
++++ b/src/zeroconf/_logger.py
+@@ -25,7 +25,7 @@ from __future__ import annotations
+ 
+ import logging
+ import sys
+-from typing import Any, ClassVar, cast
++from typing import Any
+ 
+ log = logging.getLogger(__name__.split(".", maxsplit=1)[0])
+ log.addHandler(logging.NullHandler())
+@@ -39,50 +39,73 @@ def set_logger_level_if_unset() -> None:
+ set_logger_level_if_unset()
+ 
+ 
+-class QuietLogger:
+-    _seen_logs: ClassVar[dict[str, int | tuple]] = {}
++_MAX_SEEN_LOGS = 512
++_seen_logs: dict[str, None] = {}
++
++
++def _evict_oldest(seen: dict[str, None]) -> bool:
++    """Pop the oldest entry from ``seen``; return False if it raced.
++
++    Individual dict ops (``pop`` with a default, ``next``) are atomic
++    on the free-threaded build, but the compound ``iter`` → ``next``
++    used to pick the FIFO victim can raise ``RuntimeError`` if
++    another thread mutates the dict between the two ops. The caller
++    breaks its drain loop on False so concurrent mutation can't make
++    it spin.
++    """
++    try:
++        seen.pop(next(iter(seen)), None)
++    except (RuntimeError, StopIteration):
++        return False
++    return True
++
++
++def _mark_seen(seen: dict[str, None], key: str) -> bool:
++    """Record ``key`` in ``seen`` and return True if it was newly added.
++
++    Bounds the dict so callers passing attacker-influenced keys (peer
++    addresses, packet offsets) cannot grow it without bound. Evicts
++    the oldest entries on overflow (dict preserves insertion order on
++    Python 3.7+), so ``_MAX_SEEN_LOGS`` is a recency window.
++
++    The dict is shared across all ``Zeroconf`` instances in the
++    process; on the free-threaded build (3.14t) and under multi-
++    instance sync use, callers can race the ``len < cap`` check and
++    both insert, leaving the dict transiently above the cap. The
++    drain loop runs on every call (steady-state-at-cap hits are a
++    single ``len`` + compare past the membership check because the
++    helper short-circuits) so a contention burst is corrected by the
++    next caller regardless of whether it's a hit or a miss.
++    """
++    inserting = key not in seen
++    # Hit (``inserting`` is False): drain only if drifted above cap.
++    # Miss (``inserting`` is True): drain to ``cap - 1`` to make room
++    # for the new key. Bool subtracts as 0/1 to pick the right limit.
++    while len(seen) > _MAX_SEEN_LOGS - inserting and _evict_oldest(seen):
++        pass
++    if inserting:
++        seen[key] = None
++    return inserting
++
+ 
++class QuietLogger:
+     @classmethod
+     def log_exception_warning(cls, *logger_data: Any) -> None:
+-        exc_info = sys.exc_info()
+-        exc_str = str(exc_info[1])
+-        if exc_str not in cls._seen_logs:
+-            # log at warning level the first time this is seen
+-            cls._seen_logs[exc_str] = exc_info
+-            logger = log.warning
+-        else:
+-            logger = log.debug
++        first_time = _mark_seen(_seen_logs, str(sys.exc_info()[1]))
++        logger = log.warning if first_time else log.debug
+         logger(*(logger_data or ["Exception occurred"]), exc_info=True)
+ 
+     @classmethod
+     def log_exception_debug(cls, *logger_data: Any) -> None:
+-        log_exc_info = False
+-        exc_info = sys.exc_info()
+-        exc_str = str(exc_info[1])
+-        if exc_str not in cls._seen_logs:
+-            # log the trace only on the first time
+-            cls._seen_logs[exc_str] = exc_info
+-            log_exc_info = True
+-        log.debug(*(logger_data or ["Exception occurred"]), exc_info=log_exc_info)
++        first_time = _mark_seen(_seen_logs, str(sys.exc_info()[1]))
++        log.debug(*(logger_data or ["Exception occurred"]), exc_info=first_time)
+ 
+     @classmethod
+     def log_warning_once(cls, *args: Any) -> None:
+-        msg_str = args[0]
+-        if msg_str not in cls._seen_logs:
+-            cls._seen_logs[msg_str] = 0
+-            logger = log.warning
+-        else:
+-            logger = log.debug
+-        cls._seen_logs[msg_str] = cast(int, cls._seen_logs[msg_str]) + 1
++        logger = log.warning if _mark_seen(_seen_logs, args[0]) else log.debug
+         logger(*args)
+ 
+     @classmethod
+     def log_exception_once(cls, exc: Exception, *args: Any) -> None:
+-        msg_str = args[0]
+-        if msg_str not in cls._seen_logs:
+-            cls._seen_logs[msg_str] = 0
+-            logger = log.warning
+-        else:
+-            logger = log.debug
+-        cls._seen_logs[msg_str] = cast(int, cls._seen_logs[msg_str]) + 1
++        logger = log.warning if _mark_seen(_seen_logs, args[0]) else log.debug
+         logger(*args, exc_info=exc)
+diff --git a/src/zeroconf/_protocol/incoming.py b/src/zeroconf/_protocol/incoming.py
+index d772f47..ffbbb59 100644
+--- a/src/zeroconf/_protocol/incoming.py
++++ b/src/zeroconf/_protocol/incoming.py
+@@ -37,7 +37,7 @@ from .._dns import (
+     DNSText,
+ )
+ from .._exceptions import IncomingDecodeError
+-from .._logger import log
++from .._logger import _mark_seen, log
+ from .._utils.time import current_time_millis
+ from ..const import (
+     _FLAGS_QR_MASK,
+@@ -63,7 +63,7 @@ MAX_NAME_LENGTH = 253
+ DECODE_EXCEPTIONS = (IndexError, struct.error, IncomingDecodeError, RecursionError)
+ 
+ 
+-_seen_logs: dict[str, int | tuple] = {}
++_seen_logs: dict[str, None] = {}
+ _str = str
+ _int = int
+ 
+@@ -182,13 +182,7 @@ class DNSIncoming:
+ 
+     @classmethod
+     def _log_exception_debug(cls, *logger_data: Any) -> None:
+-        log_exc_info = False
+-        exc_info = sys.exc_info()
+-        exc_str = str(exc_info[1])
+-        if exc_str not in _seen_logs:
+-            # log the trace only on the first time
+-            _seen_logs[exc_str] = exc_info
+-            log_exc_info = True
++        log_exc_info = _mark_seen(_seen_logs, str(sys.exc_info()[1]))
+         log.debug(*(logger_data or ["Exception occurred"]), exc_info=log_exc_info)
+ 
+     def answers(self) -> list[DNSRecord]:
+diff --git a/tests/benchmarks/test_mark_seen.py b/tests/benchmarks/test_mark_seen.py
+new file mode 100644
+index 0000000..4f82da8
+--- /dev/null
++++ b/tests/benchmarks/test_mark_seen.py
+@@ -0,0 +1,39 @@
++"""Benchmark for _logger._mark_seen."""
++
++from __future__ import annotations
++
++from pytest_codspeed import BenchmarkFixture
++
++from zeroconf._logger import _MAX_SEEN_LOGS, _mark_seen
++
++
++def test_mark_seen_hit(benchmark: BenchmarkFixture) -> None:
++    """Benchmark the cache-hit path (same key repeated)."""
++    seen: dict[str, None] = {"warm": None}
++
++    @benchmark
++    def _hit() -> None:
++        for _ in range(1000):
++            _mark_seen(seen, "warm")
++
++
++def test_mark_seen_fill(benchmark: BenchmarkFixture) -> None:
++    """Benchmark filling from empty up to the cap (no evictions)."""
++    keys = [f"key-{i}" for i in range(_MAX_SEEN_LOGS)]
++
++    @benchmark
++    def _fill() -> None:
++        seen: dict[str, None] = {}
++        for k in keys:
++            _mark_seen(seen, k)
++
++
++def test_mark_seen_churn(benchmark: BenchmarkFixture) -> None:
++    """Benchmark sustained eviction (every call past the cap drops oldest)."""
++    keys = [f"churn-{i}" for i in range(_MAX_SEEN_LOGS * 4)]
++
++    @benchmark
++    def _churn() -> None:
++        seen: dict[str, None] = {}
++        for k in keys:
++            _mark_seen(seen, k)
+diff --git a/tests/test_logger.py b/tests/test_logger.py
+index 4e09aa3..8042e49 100644
+--- a/tests/test_logger.py
++++ b/tests/test_logger.py
+@@ -5,7 +5,8 @@ from __future__ import annotations
+ import logging
+ from unittest.mock import call, patch
+ 
+-from zeroconf._logger import QuietLogger, set_logger_level_if_unset
++from zeroconf import _logger
++from zeroconf._logger import _MAX_SEEN_LOGS, QuietLogger, _mark_seen, set_logger_level_if_unset
+ 
+ 
+ def test_loading_logger():
+@@ -25,7 +26,7 @@ def test_loading_logger():
+ 
+ def test_log_warning_once():
+     """Test we only log with warning level once."""
+-    QuietLogger._seen_logs = {}
++    _logger._seen_logs.clear()
+     quiet_logger = QuietLogger()
+     with (
+         patch("zeroconf._logger.log.warning") as mock_log_warning,
+@@ -48,7 +49,7 @@ def test_log_warning_once():
+ 
+ def test_log_exception_warning():
+     """Test we only log with warning level once."""
+-    QuietLogger._seen_logs = {}
++    _logger._seen_logs.clear()
+     quiet_logger = QuietLogger()
+     with (
+         patch("zeroconf._logger.log.warning") as mock_log_warning,
+@@ -71,7 +72,7 @@ def test_log_exception_warning():
+ 
+ def test_llog_exception_debug():
+     """Test we only log with a trace once."""
+-    QuietLogger._seen_logs = {}
++    _logger._seen_logs.clear()
+     quiet_logger = QuietLogger()
+     with patch("zeroconf._logger.log.debug") as mock_log_debug:
+         quiet_logger.log_exception_debug("the exception")
+@@ -84,9 +85,85 @@ def test_llog_exception_debug():
+     assert mock_log_debug.mock_calls == [call("the exception", exc_info=False)]
+ 
+ 
++def test_mark_seen_absorbs_runtime_error_during_eviction() -> None:
++    """Concurrent mutation can make ``iter(seen)`` raise ``RuntimeError``.
++
++    Free-threaded (3.14t) and multi-instance sync callers share
++    ``_seen_logs``; if another thread mutates it between ``iter()``
++    and ``next()`` the iterator raises ``RuntimeError``.
++    ``_mark_seen`` must absorb that and still insert the new key.
++    """
++
++    class RacyDict(dict[str, None]):
++        def __iter__(self):  # type: ignore[override]
++            raise RuntimeError("dictionary changed size during iteration")
++
++    seen: dict[str, None] = RacyDict()
++    for i in range(_MAX_SEEN_LOGS):
++        seen[f"k-{i}"] = None
++    assert _mark_seen(seen, "new-key") is True
++    assert "new-key" in seen
++
++
++def test_mark_seen_drains_drift_above_cap() -> None:
++    """``_mark_seen`` drains a drifted-over-cap dict back to the cap.
++
++    Concurrent inserts on the free-threaded build can leave the dict
++    transiently above ``_MAX_SEEN_LOGS`` (e.g. two threads both passed
++    the ``len < cap`` check and both inserted). The next non-racing
++    call must drain the accumulated overshoot, not just evict one
++    entry — otherwise the cap silently inflates with thread count.
++    """
++    seen: dict[str, None] = {}
++    drift = 10
++    for i in range(_MAX_SEEN_LOGS + drift):
++        seen[f"k-{i}"] = None
++    assert len(seen) == _MAX_SEEN_LOGS + drift
++    assert _mark_seen(seen, "new-key") is True
++    assert len(seen) == _MAX_SEEN_LOGS
++    assert "new-key" in seen
++    for i in range(drift + 1):
++        assert f"k-{i}" not in seen
++
++
++def test_mark_seen_drains_drift_on_hit_path() -> None:
++    """``_mark_seen`` drains drift even when ``key`` is already cached.
++
++    A hit-heavy workload after a contention burst (e.g. the same
++    exception text deduplicated repeatedly) must still correct the
++    overshoot — otherwise the dict can sit permanently above the cap
++    until a miss happens to come along.
++    """
++    seen: dict[str, None] = {}
++    drift = 10
++    for i in range(_MAX_SEEN_LOGS + drift):
++        seen[f"k-{i}"] = None
++    # Hit on a non-oldest key — survives the drift drain.
++    hit_key = f"k-{_MAX_SEEN_LOGS}"
++    assert _mark_seen(seen, hit_key) is False
++    assert len(seen) == _MAX_SEEN_LOGS
++    assert hit_key in seen
++    for i in range(drift):
++        assert f"k-{i}" not in seen
++
++
++def test_seen_logs_is_bounded() -> None:
++    """``_seen_logs`` stays at the cap and evicts oldest-first (FIFO)."""
++    _logger._seen_logs.clear()
++    overflow = 5
++    with patch("zeroconf._logger.log.warning"), patch("zeroconf._logger.log.debug"):
++        for i in range(_MAX_SEEN_LOGS + overflow):
++            QuietLogger.log_warning_once(f"warning-{i}")
++    assert len(_logger._seen_logs) == _MAX_SEEN_LOGS
++    for i in range(overflow):
++        assert f"warning-{i}" not in _logger._seen_logs
++    for i in range(_MAX_SEEN_LOGS, _MAX_SEEN_LOGS + overflow):
++        assert f"warning-{i}" in _logger._seen_logs
++
++
+ def test_log_exception_once():
+     """Test we only log with warning level once."""
+-    QuietLogger._seen_logs = {}
++    _logger._seen_logs.clear()
+     quiet_logger = QuietLogger()
+     exc = Exception()
+     with (
+diff --git a/tests/test_protocol.py b/tests/test_protocol.py
+index bac2b44..782b77a 100644
+--- a/tests/test_protocol.py
++++ b/tests/test_protocol.py
+@@ -14,6 +14,8 @@ import pytest
+ 
+ import zeroconf as r
+ from zeroconf import DNSHinfo, DNSIncoming, DNSText, const, current_time_millis
++from zeroconf._logger import _MAX_SEEN_LOGS
++from zeroconf._protocol import incoming as _incoming_module
+ 
+ from . import has_working_ipv6
+ 
+@@ -962,6 +964,38 @@ def test_dns_compression_generic_failure(caplog):
+     assert "Received invalid packet from ('1.2.3.4', 5353)" in caplog.text
+ 
+ 
++def test_seen_logs_is_bounded():
++    """Corrupt packets from varying peers fill ``_seen_logs`` exactly to the cap."""
++    packet = (
++        b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x06domain\x05local\x00\x00\x01"
++        b"\x80\x01\x00\x00\x00\x01\x00\x04\xc0\xa8\xd0\x05-\x0c\x00\x01\x80\x01\x00\x00"
++        b"\x00\x01\x00\x04\xc0\xa8\xd0\x06"
++    )
++    overflow = 5
++    _incoming_module._seen_logs.clear()
++    # Snapshot the actual key the parser inserted per port. This is whatever
++    # ``str(exc_info()[1])`` produces today — the test stays agnostic to the
++    # exception text format so a future normalization of the message (see
++    # the discussion on #1714) doesn't break the assertions, while still
++    # pinning that the parser exception path actually entered the dict.
++    keys_per_port: list[str] = []
++    for port in range(_MAX_SEEN_LOGS + overflow):
++        r.DNSIncoming(packet, ("1.2.3.4", port))
++        keys_per_port.append(next(reversed(_incoming_module._seen_logs)))
++    # Bound is hit exactly.
++    assert len(_incoming_module._seen_logs) == _MAX_SEEN_LOGS
++    # Each port produced a distinct dedup key — a regression that dropped
++    # the per-packet-varying component (e.g. self.source) from the exception
++    # text would collapse all 517 calls to one key and fail this.
++    assert len(set(keys_per_port)) == _MAX_SEEN_LOGS + overflow
++    # FIFO eviction by key identity (no substring matching on the message
++    # format): the earliest ports' keys are gone, the latest ports' remain.
++    for port in range(overflow):
++        assert keys_per_port[port] not in _incoming_module._seen_logs
++    for port in range(_MAX_SEEN_LOGS, _MAX_SEEN_LOGS + overflow):
++        assert keys_per_port[port] in _incoming_module._seen_logs
++
++
+ def test_label_length_attack():
+     """Test our wire parser does not loop forever when the name exceeds 253 chars."""
+     packet = (
diff --git a/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb b/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
index c405e83b8c..aa1bb11065 100644
--- a/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
+++ b/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
@@ -5,7 +5,9 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=9fe712b1bc27c5c4e9ecd7f31d208900"
 
 SRC_URI[sha256sum] = "03fcca123df3652e23d945112d683d2f605f313637611b7d4adf31056f681702"
 
-SRC_URI += "file://CVE-2026-47180.patch"
+SRC_URI += "file://CVE-2026-47180.patch \
+            file://CVE-2026-47183.patch \
+"
 
 inherit pypi python_poetry_core cython
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-python][wrynose][PATCH 9/33] python3-zeroconf: patch CVE-2026-47184
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (6 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 8/33] python3-zeroconf: patch CVE-2026-47183 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 10/33] valkey: mark CVE-2026-56684 and CVE-2026-63639 patched ankur.tyagi85
                   ` (23 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-47184

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../python3-zeroconf/CVE-2026-47184.patch     | 558 ++++++++++++++++++
 .../python/python3-zeroconf_0.148.0.bb        |   1 +
 2 files changed, 559 insertions(+)
 create mode 100644 meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47184.patch

diff --git a/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47184.patch b/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47184.patch
new file mode 100644
index 0000000000..73d4c2bd9c
--- /dev/null
+++ b/meta-python/recipes-devtools/python/python3-zeroconf/CVE-2026-47184.patch
@@ -0,0 +1,558 @@
+From 61d9e147da48ffb5f660e639f6d457e5cda008d4 Mon Sep 17 00:00:00 2001
+From: "J. Nick Koston" <nick@koston.org>
+Date: Sun, 17 May 2026 21:48:40 -0700
+Subject: [PATCH] fix: bound DNSCache record count to prevent unbounded
+ LAN-driven growth (#1718)
+
+(cherry picked from commit 0ad3f37b5b852b8f614d322283d148efb2cef6e4)
+
+CVE: CVE-2026-47184
+Upstream-Status: Backport [https://github.com/python-zeroconf/python-zeroconf/commit/0ad3f37b5b852b8f614d322283d148efb2cef6e4]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/zeroconf/_cache.pxd              |  11 +-
+ src/zeroconf/_cache.py               |  79 +++++----
+ src/zeroconf/const.py                |   6 +
+ tests/benchmarks/test_cache_bound.py |  68 ++++++++
+ tests/test_cache.py                  | 241 ++++++++++++++++++++++++++-
+ 5 files changed, 374 insertions(+), 31 deletions(-)
+ create mode 100644 tests/benchmarks/test_cache_bound.py
+
+diff --git a/src/zeroconf/_cache.pxd b/src/zeroconf/_cache.pxd
+index 05a40c0..023304b 100644
+--- a/src/zeroconf/_cache.pxd
++++ b/src/zeroconf/_cache.pxd
+@@ -19,6 +19,7 @@ cdef object _UNIQUE_RECORD_TYPES
+ cdef unsigned int _TYPE_PTR
+ cdef cython.uint _ONE_SECOND
+ cdef unsigned int _MIN_SCHEDULED_RECORD_EXPIRATION
++cdef unsigned int _MAX_CACHE_RECORDS
+ 
+ 
+ @cython.locals(record_cache=dict)
+@@ -31,6 +32,7 @@ cdef class DNSCache:
+     cdef public cython.dict service_cache
+     cdef public list _expire_heap
+     cdef public dict _expirations
++    cdef public unsigned int _total_records
+ 
+     cpdef bint async_add_records(self, object entries)
+ 
+@@ -60,10 +62,17 @@ cdef class DNSCache:
+         service_store=cython.dict,
+         service_record=DNSService,
+         when=object,
+-        new=bint
++        new=bint,
++        is_new=bint
+     )
+     cdef bint _async_add(self, DNSRecord record)
+ 
++    @cython.locals(record=DNSRecord, when_record=tuple)
++    cdef void _async_evict_oldest(self)
++
++    @cython.locals(expire_heap_len="unsigned int")
++    cdef void _maybe_rebuild_heap(self)
++
+     @cython.locals(service_record=DNSService)
+     cdef void _async_remove(self, DNSRecord record)
+ 
+diff --git a/src/zeroconf/_cache.py b/src/zeroconf/_cache.py
+index c7ca847..d323a6a 100644
+--- a/src/zeroconf/_cache.py
++++ b/src/zeroconf/_cache.py
+@@ -37,7 +37,7 @@ from ._dns import (
+     DNSText,
+ )
+ from ._utils.time import current_time_millis
+-from .const import _ONE_SECOND, _TYPE_PTR
++from .const import _MAX_CACHE_RECORDS, _ONE_SECOND, _TYPE_PTR
+ 
+ _UNIQUE_RECORD_TYPES = (DNSAddress, DNSHinfo, DNSPointer, DNSText, DNSService)
+ _UniqueRecordsType = Union[DNSAddress, DNSHinfo, DNSPointer, DNSText, DNSService]
+@@ -72,6 +72,7 @@ class DNSCache:
+         self._expire_heap: list[tuple[float, DNSRecord]] = []
+         self._expirations: dict[DNSRecord, float] = {}
+         self.service_cache: _DNSRecordCacheType = {}
++        self._total_records: int = 0
+ 
+     # Functions prefixed with async_ are NOT threadsafe and must
+     # be run in the event loop.
+@@ -89,15 +90,34 @@ class DNSCache:
+         # replaces any existing records that are __eq__ to each other which
+         # removes the risk that accessing the cache from the wrong
+         # direction would return the old incorrect entry.
+-        if (store := self.cache.get(record.key)) is None:
++        store = self.cache.get(record.key)
++        is_new = store is None or record not in store
++        # Bound total cache size; evict closest-to-expiration entry to
++        # make room before inserting a new record. Prevents a LAN-local
++        # flood of unique-name records from growing the cache without
++        # bound (RFC 6762 §10 advisory caching, defense-in-depth).
++        if is_new and self._total_records >= _MAX_CACHE_RECORDS:
++            self._async_evict_oldest()
++            # The victim may have been the last record under
++            # ``record.key``, in which case ``_remove_key`` deleted
++            # the bucket. Re-fetch before creating below.
++            store = self.cache.get(record.key)
++        if store is None:
+             store = self.cache[record.key] = {}
+-        new = record not in store and not isinstance(record, DNSNsec)
++        new = is_new and not isinstance(record, DNSNsec)
++        if is_new:
++            self._total_records += 1
+         store[record] = record
+         when = record.created + (record.ttl * 1000)
+         if self._expirations.get(record) != when:
+-            # Avoid adding duplicates to the heap
+             heappush(self._expire_heap, (when, record))
+             self._expirations[record] = when
++            # Re-adds of an existing record with a new TTL push a fresh
++            # entry but leave the prior tuple behind as stale, so a peer
++            # that just replays cached records can grow ``_expire_heap``
++            # without ever tripping the cap. Rebuild when stale entries
++            # dominate.
++            self._maybe_rebuild_heap()
+ 
+         if isinstance(record, DNSService):
+             service_record = record
+@@ -106,6 +126,28 @@ class DNSCache:
+             service_store[service_record] = service_record
+         return new
+ 
++    def _async_evict_oldest(self) -> None:
++        """Drop the closest-to-expiration record to make room for a new one."""
++        while self._expire_heap:
++            when_record = heappop(self._expire_heap)
++            record = when_record[1]
++            if self._expirations.get(record) != when_record[0]:
++                continue
++            self._async_remove(record)
++            return
++
++    def _maybe_rebuild_heap(self) -> None:
++        """Rebuild ``_expire_heap`` when stale entries dominate live ones."""
++        expire_heap_len = len(self._expire_heap)
++        if (
++            expire_heap_len > _MIN_SCHEDULED_RECORD_EXPIRATION
++            and expire_heap_len > len(self._expirations) * 2
++        ):
++            self._expire_heap = [
++                entry for entry in self._expire_heap if self._expirations.get(entry[1]) == entry[0]
++            ]
++            heapify(self._expire_heap)
++
+     def async_add_records(self, entries: Iterable[DNSRecord]) -> bool:
+         """Add multiple records.
+ 
+@@ -129,6 +171,7 @@ class DNSCache:
+             _remove_key(self.service_cache, service_record.server_key, service_record)
+         _remove_key(self.cache, record.key, record)
+         self._expirations.pop(record, None)
++        self._total_records -= 1
+ 
+     def async_remove_records(self, entries: Iterable[DNSRecord]) -> None:
+         """Remove multiple records.
+@@ -145,43 +188,23 @@ class DNSCache:
+ 
+         :param now: The current time in milliseconds.
+         """
+-        if not (expire_heap_len := len(self._expire_heap)):
++        if not self._expire_heap:
+             return []
+ 
+         expired: list[DNSRecord] = []
+-        # Find any expired records and add them to the to-delete list
+         while self._expire_heap:
+             when_record = self._expire_heap[0]
+             when = when_record[0]
+             if when > now:
+                 break
+             heappop(self._expire_heap)
+-            # Check if the record hasn't been re-added to the heap
+-            # with a different expiration time as it will be removed
+-            # later when it reaches the top of the heap and its
+-            # expiration time is met.
++            # Skip entries left behind by a TTL re-add; the live tuple is
++            # later in the heap and will be removed when it reaches the top.
+             record = when_record[1]
+             if self._expirations.get(record) == when:
+                 expired.append(record)
+ 
+-        # If the expiration heap grows larger than the number expirations
+-        # times two, we clean it up to avoid keeping expired entries in
+-        # the heap and consuming memory. We guard this with a minimum
+-        # threshold to avoid cleaning up the heap too often when there are
+-        # only a few scheduled expirations.
+-        if (
+-            expire_heap_len > _MIN_SCHEDULED_RECORD_EXPIRATION
+-            and expire_heap_len > len(self._expirations) * 2
+-        ):
+-            # Remove any expired entries from the expiration heap
+-            # that do not match the expiration time in the expirations
+-            # as it means the record has been re-added to the heap
+-            # with a different expiration time.
+-            self._expire_heap = [
+-                entry for entry in self._expire_heap if self._expirations.get(entry[1]) == entry[0]
+-            ]
+-            heapify(self._expire_heap)
+-
++        self._maybe_rebuild_heap()
+         self.async_remove_records(expired)
+         return expired
+ 
+diff --git a/src/zeroconf/const.py b/src/zeroconf/const.py
+index 1db39a4..a17e468 100644
+--- a/src/zeroconf/const.py
++++ b/src/zeroconf/const.py
+@@ -59,6 +59,12 @@ _DNS_OTHER_TTL = 4500  # 75 minutes for non-host records (PTR, TXT etc) as-per R
+ # level of rate limit and safe guards so we use 1/4 of the recommended value
+ _DNS_PTR_MIN_TTL = 1125
+ 
++# Upper bound on the number of records the DNSCache will hold before it
++# starts evicting the closest-to-expiration entry to make room for new
++# arrivals. Bounds the memory a malicious LAN peer can force the cache
++# to retain by multicasting many unique-name records.
++_MAX_CACHE_RECORDS = 10000
++
+ _DNS_PACKET_HEADER_LEN = 12
+ 
+ _MAX_MSG_TYPICAL = 1460  # unused
+diff --git a/tests/benchmarks/test_cache_bound.py b/tests/benchmarks/test_cache_bound.py
+new file mode 100644
+index 0000000..774129e
+--- /dev/null
++++ b/tests/benchmarks/test_cache_bound.py
+@@ -0,0 +1,68 @@
++"""Benchmark for the DNSCache record-count bound + overflow eviction."""
++
++from __future__ import annotations
++
++from collections.abc import Iterator
++from itertools import count
++
++from pytest_codspeed import BenchmarkFixture
++
++from zeroconf import DNSAddress, DNSCache, current_time_millis
++from zeroconf.const import _CLASS_IN, _MAX_CACHE_RECORDS, _TYPE_A
++
++
++def _make_records(count_: int, now: float, prefix: str = "bench") -> list[DNSAddress]:
++    return [
++        DNSAddress(
++            f"{prefix}-{i}.local.",
++            _TYPE_A,
++            _CLASS_IN,
++            120,
++            bytes(((i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF)),
++            created=now + i,
++        )
++        for i in range(count_)
++    ]
++
++
++def _unbounded_records(now: float, prefix: str = "evict") -> Iterator[DNSAddress]:
++    """Unbounded generator of unique-name DNSAddress records."""
++    for i in count():
++        yield DNSAddress(
++            f"{prefix}-{i}.local.",
++            _TYPE_A,
++            _CLASS_IN,
++            120,
++            bytes(((i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF)),
++            created=now + i,
++        )
++
++
++def test_cache_add_below_cap(benchmark: BenchmarkFixture) -> None:
++    """Adding records while the cache is well below the cap (no eviction)."""
++    now = current_time_millis()
++    records = _make_records(1000, now)
++
++    @benchmark
++    def _add() -> None:
++        cache = DNSCache()
++        cache.async_add_records(records)
++
++
++def test_cache_add_at_cap_evicts(benchmark: BenchmarkFixture) -> None:
++    """Steady-state add at the cap: every measured insert forces one eviction.
++
++    Pre-fills the cache to ``_MAX_CACHE_RECORDS`` outside the timed body so
++    only the eviction-path adds are measured. Each benchmark iteration
++    pulls one fresh unique record from an unbounded generator, keeping the
++    cache permanently at the cap. The generator avoids the iteration-count
++    cap that a pre-built pool would impose for very fast operations.
++    """
++    now = current_time_millis()
++    cache = DNSCache()
++    cache.async_add_records(_make_records(_MAX_CACHE_RECORDS, now, prefix="fill"))
++    pool = _unbounded_records(now + _MAX_CACHE_RECORDS)
++
++    @benchmark
++    def _evict_one() -> None:
++        cache.async_add_records([next(pool)])
+diff --git a/tests/test_cache.py b/tests/test_cache.py
+index 9d55435..aeb3a2a 100644
+--- a/tests/test_cache.py
++++ b/tests/test_cache.py
+@@ -439,7 +439,9 @@ async def test_cache_heap_multi_name_cleanup() -> None:
+         )
+         cache.async_add_records([record])
+ 
+-    assert len(cache._expire_heap) == min_records_to_cleanup + 5
++    # ``_async_add`` rebuilds ``_expire_heap`` proactively when stale entries
++    # dominate (heap > 2x expirations), so the heap is already capped at
++    # ~one entry per unique record long before ``async_expire`` is called.
+     assert len(cache.async_entries_with_name(name)) == 1
+     assert len(cache.async_entries_with_name(name2)) == 5
+ 
+@@ -473,7 +475,8 @@ async def test_cache_heap_pops_order() -> None:
+         )
+         cache.async_add_records([record])
+ 
+-    assert len(cache._expire_heap) == min_records_to_cleanup + 5
++    # ``_async_add`` proactively rebuilds the heap when stale entries dominate,
++    # so the heap holds only one entry per unique record by this point.
+     assert len(cache.async_entries_with_name(name)) == 1
+     assert len(cache.async_entries_with_name(name2)) == 5
+ 
+@@ -482,3 +485,237 @@ async def test_cache_heap_pops_order() -> None:
+         ts, _ = heappop(cache._expire_heap)
+         assert ts >= start_ts
+         start_ts = ts
++
++
++def _addr(name: str, idx: int, *, ttl: int = 120, created: float | None = None) -> r.DNSAddress:
++    """Build a DNSAddress with idx-derived payload for the bound/eviction tests."""
++    return r.DNSAddress(
++        name,
++        const._TYPE_A,
++        const._CLASS_IN,
++        ttl,
++        bytes((idx & 0xFF, (idx >> 8) & 0xFF, 0, 1)),
++        created=r.current_time_millis() if created is None else created,
++    )
++
++
++def test_cache_size_is_bounded() -> None:
++    """A flood of unique-name records is capped at ``_MAX_CACHE_RECORDS``."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++    overflow = 1000
++    flood_size = const._MAX_CACHE_RECORDS + overflow
++
++    cache.async_add_records(_addr(f"flood-{i}.local.", i, created=now + i) for i in range(flood_size))
++
++    total = sum(len(store) for store in cache.cache.values())
++    assert total == const._MAX_CACHE_RECORDS
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++    # FIFO-ish: the earliest-created records (closest to expiration) get
++    # evicted first, so the names that remain are from the tail.
++    for i in range(overflow):
++        assert f"flood-{i}.local." not in cache.cache
++    for i in range(flood_size - overflow, flood_size):
++        assert f"flood-{i}.local." in cache.cache
++
++
++def test_cache_eviction_empty_heap_returns_without_evicting() -> None:
++    """Eviction tolerates an empty ``_expire_heap`` (invariant-violation safety net)."""
++    cache = r.DNSCache()
++    # By the cache invariant every record in ``_total_records`` has a heap
++    # entry, so eviction should never see an empty heap. Force the broken
++    # state directly to pin the defensive behaviour: ``_async_evict_oldest``
++    # returns without raising and the subsequent insert still lands. Since
++    # eviction can't free space, the counter is allowed to drift past the
++    # cap by exactly one — pinned so a future change to the recovery
++    # semantics (e.g., refusing the add or clamping) fails this test.
++    cache._total_records = const._MAX_CACHE_RECORDS
++    cache._expire_heap = []
++    cache.async_add_records([_addr("post-empty.local.", 0)])
++    assert "post-empty.local." in cache.cache
++    assert cache._total_records == const._MAX_CACHE_RECORDS + 1
++
++
++def test_cache_eviction_skips_stale_heap_entries() -> None:
++    """Eviction skips stale heap entries left by TTL re-adds."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++    cache.async_add_records(
++        _addr(f"stale-{i}.local.", i, created=now + i) for i in range(const._MAX_CACHE_RECORDS)
++    )
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++
++    # Re-add the closest-to-expiration record with a longer TTL; the prior
++    # ``(when, record)`` tuple stays as stale, eviction must skip it.
++    victim_name = "stale-0.local."
++    cache.async_add_records([_addr(victim_name, 0, ttl=7200, created=now)])
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++
++    cache.async_add_records([_addr("trigger.local.", 0xFFFF, created=now + const._MAX_CACHE_RECORDS)])
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++    assert victim_name in cache.cache
++    assert "stale-1.local." not in cache.cache
++
++
++def test_cache_eviction_victim_shares_key_with_new_record() -> None:
++    """Inserting a record whose key collides with the eviction victim keeps it reachable."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++    cache.async_add_records(
++        _addr(f"filler-{i}.local.", i, created=now + 1000 + i) for i in range(const._MAX_CACHE_RECORDS - 1)
++    )
++
++    # Insert at "shared.local." with the earliest expiration so eviction
++    # picks it. ``_remove_key`` then deletes ``cache["shared.local."]``.
++    shared_key = "shared.local."
++    cache.async_add_records([_addr(shared_key, 0x0102, created=now)])
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++
++    # Adding a new record under the SAME key: a pre-eviction-captured
++    # ``store`` would write into an orphaned dict; the fix re-resolves.
++    new_shared = _addr(shared_key, 0x0506, created=now + 999)
++    cache.async_add_records([new_shared])
++
++    assert shared_key in cache.cache, "new record orphaned: cache bucket missing"
++    assert new_shared in cache.cache[shared_key]
++    assert cache.async_get_unique(new_shared) == new_shared
++    total = sum(len(store) for store in cache.cache.values())
++    assert total == cache._total_records
++
++
++def test_cache_dnsnsec_at_cap_evicts_prior_record() -> None:
++    """A single DNSNsec arriving at the cap evicts one prior record and stays reachable."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++    cache.async_add_records(
++        _addr(f"fill-{i}.local.", i, created=now + i) for i in range(const._MAX_CACHE_RECORDS)
++    )
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++
++    nsec = r.DNSNsec(
++        "nsec-arrival.local.",
++        const._TYPE_NSEC,
++        const._CLASS_IN,
++        120,
++        "nsec-arrival.local.",
++        [const._TYPE_A],
++    )
++    cache.async_add_records([nsec])
++
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++    assert nsec in cache.cache[nsec.key]
++    # The earliest-created fill record is gone (FIFO-ish eviction).
++    assert "fill-0.local." not in cache.cache
++
++
++def test_cache_dnsnsec_flood_is_bounded() -> None:
++    """DNSNsec records honour ``_MAX_CACHE_RECORDS`` (no bypass via the ``new`` flag)."""
++    cache = r.DNSCache()
++    overflow = 100
++    cache.async_add_records(
++        r.DNSNsec(
++            f"nsec-{i}.local.",
++            const._TYPE_NSEC,
++            const._CLASS_IN,
++            120,
++            f"nsec-{i}.local.",
++            [const._TYPE_A],
++        )
++        for i in range(const._MAX_CACHE_RECORDS + overflow)
++    )
++    assert cache._total_records == const._MAX_CACHE_RECORDS
++    total = sum(len(store) for store in cache.cache.values())
++    assert total == const._MAX_CACHE_RECORDS
++
++
++def test_cache_re_add_flood_does_not_grow_heap_unbounded() -> None:
++    """Replaying cached records with shifting TTLs cannot grow ``_expire_heap`` unbounded."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++    # Stay below the cache cap so eviction never fires; the attack here is
++    # heap growth via re-add, not cap saturation. Clear the
++    # ``_MIN_SCHEDULED_RECORD_EXPIRATION`` floor so the rebuild engages.
++    record_count = 200
++    cache.async_add_records(_addr(f"flood-{i}.local.", i, created=now) for i in range(record_count))
++    assert cache._total_records == record_count
++
++    # 10 cycles x ``record_count`` stale pushes each. Without
++    # ``_maybe_rebuild_heap`` firing inside ``_async_add``, the heap would
++    # grow to ~11 x record_count.
++    for cycle in range(10):
++        cache.async_add_records(
++            _addr(f"flood-{i}.local.", i, ttl=7200 + cycle, created=now) for i in range(record_count)
++        )
++
++    # Heap is bounded near the rebuild threshold; ``+ record_count`` of slack
++    # to stay resilient to where in a re-add cycle the rebuild last fired.
++    assert len(cache._expire_heap) <= 2 * len(cache._expirations) + record_count
++    assert cache._total_records == record_count
++
++
++def test_cache_eviction_decrements_total_records() -> None:
++    """Natural removal (goodbyes, expirations) keeps ``_total_records`` in sync."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++    records = [_addr(f"sync-{i}.local.", i, created=now) for i in range(50)]
++    cache.async_add_records(records)
++    assert cache._total_records == 50
++
++    cache.async_remove_records(records[:20])
++    assert cache._total_records == 30
++
++    cache.async_expire(now + (200 * 1000))
++    assert cache._total_records == 0
++    assert not cache.cache
++
++
++def test_cache_total_records_invariant_under_mixed_ops() -> None:
++    """``_total_records`` stays equal to the sum of bucket sizes across all touched paths."""
++    cache = r.DNSCache()
++    now = r.current_time_millis()
++
++    def actual() -> int:
++        return sum(len(store) for store in cache.cache.values())
++
++    addrs = [_addr(f"mix-{i}.local.", i, created=now + i) for i in range(20)]
++    cache.async_add_records(addrs)
++    assert cache._total_records == actual() == 20
++
++    # Re-add of an identical record: no increment.
++    cache.async_add_records([addrs[0]])
++    assert cache._total_records == actual() == 20
++
++    # DNSService writes service_cache too — counter still matches cache size.
++    svc = r.DNSService("svc.local.", const._TYPE_SRV, const._CLASS_IN, 120, 0, 0, 80, "host.local.")
++    cache.async_add_records([svc])
++    assert cache._total_records == actual() == 21
++    cache.async_remove_records([svc])
++    assert cache._total_records == actual() == 20
++
++    # DNSNsec is stored but excluded from the "new" return; counter tracks it anyway.
++    nsec = r.DNSNsec("nsec.local.", const._TYPE_NSEC, const._CLASS_IN, 120, "nsec.local.", [const._TYPE_A])
++    cache.async_add_records([nsec])
++    assert cache._total_records == actual() == 21
++    cache.async_remove_records([nsec])
++    assert cache._total_records == actual() == 20
++
++    # Shared-key insert/remove: emptying the bucket drops the cache key but
++    # counter decrements only by the records that left.
++    shared_a = _addr("shared.local.", 0x0101, created=now)
++    shared_b = _addr("shared.local.", 0x0202, created=now)
++    cache.async_add_records([shared_a, shared_b])
++    assert cache._total_records == actual() == 22
++    cache.async_remove_records([shared_a, shared_b])
++    assert cache._total_records == actual() == 20
++    assert "shared.local." not in cache.cache
++
++    cache.async_expire(now + (200 * 1000))
++    assert cache._total_records == actual() == 0
++    assert not cache.cache
++
++    # Full-cap eviction loop: counter never grows past the cap, never drifts.
++    cap_records = [_addr(f"cap-{i}.local.", i, created=now + i) for i in range(const._MAX_CACHE_RECORDS + 50)]
++    for rec in cap_records:
++        cache.async_add_records([rec])
++        assert cache._total_records == actual()
++    assert cache._total_records == const._MAX_CACHE_RECORDS
diff --git a/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb b/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
index aa1bb11065..cc68ffbf96 100644
--- a/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
+++ b/meta-python/recipes-devtools/python/python3-zeroconf_0.148.0.bb
@@ -7,6 +7,7 @@ SRC_URI[sha256sum] = "03fcca123df3652e23d945112d683d2f605f313637611b7d4adf31056f
 
 SRC_URI += "file://CVE-2026-47180.patch \
             file://CVE-2026-47183.patch \
+            file://CVE-2026-47184.patch \
 "
 
 inherit pypi python_poetry_core cython


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 10/33] valkey: mark CVE-2026-56684 and CVE-2026-63639 patched
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (7 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 9/33] python3-zeroconf: patch CVE-2026-47184 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 11/33] libyang: patch CVE-2026-41401 ankur.tyagi85
                   ` (22 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Also mentioned in the release notes[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-56684
https://nvd.nist.gov/vuln/detail/cve-2026-63639

[1]https://github.com/valkey-io/valkey/releases/tag/9.0.5

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-oe/recipes-extended/valkey/valkey_9.0.5.bb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/meta-oe/recipes-extended/valkey/valkey_9.0.5.bb b/meta-oe/recipes-extended/valkey/valkey_9.0.5.bb
index d57aa6e1b4..d7ce19ce72 100644
--- a/meta-oe/recipes-extended/valkey/valkey_9.0.5.bb
+++ b/meta-oe/recipes-extended/valkey/valkey_9.0.5.bb
@@ -74,3 +74,5 @@ INITSCRIPT_PARAMS = "defaults 87"
 SYSTEMD_SERVICE:${PN} = "valkey.service"
 
 CVE_STATUS[CVE-2022-3734] = "not-applicable-platform: CVE only applies for Windows."
+CVE_STATUS[CVE-2026-56684] = "fixed-version: fixed in v9.0.5"
+CVE_STATUS[CVE-2026-63639] = "fixed-version: fixed in v9.0.5"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 11/33] libyang: patch CVE-2026-41401
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (8 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 10/33] valkey: mark CVE-2026-56684 and CVE-2026-63639 patched ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 12/33] tinyproxy: patch CVE-2026-31842 ankur.tyagi85
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Backport patch identified by Debian[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-41401

[1]https://security-tracker.debian.org/tracker/CVE-2026-41401

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../libyang/libyang/CVE-2026-41401.patch      | 43 +++++++++++++++++++
 .../libyang/libyang_3.13.6.bb                 |  1 +
 2 files changed, 44 insertions(+)
 create mode 100644 meta-oe/recipes-extended/libyang/libyang/CVE-2026-41401.patch

diff --git a/meta-oe/recipes-extended/libyang/libyang/CVE-2026-41401.patch b/meta-oe/recipes-extended/libyang/libyang/CVE-2026-41401.patch
new file mode 100644
index 0000000000..06537acbb8
--- /dev/null
+++ b/meta-oe/recipes-extended/libyang/libyang/CVE-2026-41401.patch
@@ -0,0 +1,43 @@
+From 34b2a26ee86716e2b593c44e51e38ee15d4e8434 Mon Sep 17 00:00:00 2001
+From: Michal Vasko <mvasko@cesnet.cz>
+Date: Thu, 26 Mar 2026 08:33:44 +0100
+Subject: [PATCH] parser common BUGFIX invalid metadata removal
+
+(cherry picked from commit 54c3276d871023da266d4ed3ceaee7e8d71d0b04)
+
+CVE: CVE-2026-41401
+Upstream-Status: Backport [https://github.com/CESNET/libyang/commit/54c3276d871023da266d4ed3ceaee7e8d71d0b04]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/parser_common.c                                    | 4 ++--
+ tests/fuzz/corpus/lyd_parse_mem_xml/advisory2026_03_26 | 5 +++++
+ 2 files changed, 7 insertions(+), 2 deletions(-)
+ create mode 100644 tests/fuzz/corpus/lyd_parse_mem_xml/advisory2026_03_26
+
+diff --git a/src/parser_common.c b/src/parser_common.c
+index 0b221af72..fefe723eb 100644
+--- a/src/parser_common.c
++++ b/src/parser_common.c
+@@ -413,8 +413,8 @@ lyd_parser_set_data_flags(struct lyd_node *node, struct lyd_meta **meta, struct
+             next_meta = meta2->next;
+ 
+             /* delete the metadata */
+-            if (meta != &node->meta) {
+-                *meta = (*meta)->next;
++            if ((meta != &node->meta) && (meta2 == *meta)) {
++                *meta = next_meta;
+             }
+             lyd_free_meta_single(meta2);
+             if (prev_meta) {
+diff --git a/tests/fuzz/corpus/lyd_parse_mem_xml/advisory2026_03_26 b/tests/fuzz/corpus/lyd_parse_mem_xml/advisory2026_03_26
+new file mode 100644
+index 000000000..7e3b6c39e
+--- /dev/null
++++ b/tests/fuzz/corpus/lyd_parse_mem_xml/advisory2026_03_26
+@@ -0,0 +1,5 @@
++<int32 xmlns="urn:tests:types"
++       xmlns:yang="urn:ietf:params:xml:ns:yang:1"
++       xmlns:dflt="urn:ietf:params:xml:ns:netconf:default:1.0"
++       yang:operation="create"
++       dflt:default="true">5</int32>
diff --git a/meta-oe/recipes-extended/libyang/libyang_3.13.6.bb b/meta-oe/recipes-extended/libyang/libyang_3.13.6.bb
index 822c30ba24..7724b4c218 100644
--- a/meta-oe/recipes-extended/libyang/libyang_3.13.6.bb
+++ b/meta-oe/recipes-extended/libyang/libyang_3.13.6.bb
@@ -11,6 +11,7 @@ SRCREV = "c2ddd01b9b810a30d6a7d6749a3bc9adeb7b01fb"
 SRC_URI = "git://github.com/CESNET/libyang.git;branch=master;protocol=https;tag=v${PV} \
            file://0001-test_context-skip-test-case-test_searchdirs.patch \
            file://run-ptest \
+           file://CVE-2026-41401.patch \
            "
 
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 12/33] tinyproxy: patch CVE-2026-31842
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (9 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 11/33] libyang: patch CVE-2026-41401 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 13/33] tinyproxy: patch CVE-2026-54387 ankur.tyagi85
                   ` (20 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Backport commit identified by Debian[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-31842

[1]https://security-tracker.debian.org/tracker/CVE-2026-31842

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../tinyproxy/tinyproxy/CVE-2026-31842.patch  | 33 +++++++++++++++++++
 .../tinyproxy/tinyproxy_1.11.3.bb             |  1 +
 2 files changed, 34 insertions(+)
 create mode 100644 meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-31842.patch

diff --git a/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-31842.patch b/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-31842.patch
new file mode 100644
index 0000000000..6b8c02d629
--- /dev/null
+++ b/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-31842.patch
@@ -0,0 +1,33 @@
+From ed5252d213a68546feaff68e2b40e401d2c2afd4 Mon Sep 17 00:00:00 2001
+From: rofl0r <rofl0r@users.noreply.github.com>
+Date: Fri, 3 Apr 2026 11:21:23 +0200
+Subject: [PATCH] reqs: fix case-sensitive matching of "chunked" (#605)
+
+the chunked transfer encoding needs to be matched in a case-
+insensitive manner.
+
+closes #604
+
+(cherry picked from commit 879bf844abffa0bf5fae6aff0c73179024dd9f98)
+
+CVE: CVE-2026-31842
+Upstream-Status: Backport [https://github.com/tinyproxy/tinyproxy/commit/879bf844abffa0bf5fae6aff0c73179024dd9f98]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/reqs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/reqs.c b/src/reqs.c
+index 7aacfd3..8b68538 100644
+--- a/src/reqs.c
++++ b/src/reqs.c
+@@ -850,7 +850,7 @@ static int is_chunked_transfer (pseudomap *hashofheaders)
+ {
+         char *data;
+         data = pseudomap_find (hashofheaders, "transfer-encoding");
+-        return data ? !strcmp (data, "chunked") : 0;
++        return data ? !strcasecmp (data, "chunked") : 0;
+ }
+ 
+ /*
diff --git a/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb b/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
index 56e3296066..4ce766b40b 100644
--- a/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
+++ b/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
@@ -9,6 +9,7 @@ SRC_URI = "https://github.com/${BPN}/${BPN}/releases/download/${PV}/${BP}.tar.gz
            file://run-ptest \
            file://CVE-2026-3945-1.patch \
            file://CVE-2026-3945-2.patch \
+           file://CVE-2026-31842.patch \
            "
 
 SRC_URI[sha256sum] = "9bcf46db1a2375ff3e3d27a41982f1efec4706cce8899ff9f33323a8218f7592"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 13/33] tinyproxy: patch CVE-2026-54387
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (10 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 12/33] tinyproxy: patch CVE-2026-31842 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 14/33] tinyproxy: patch CVE-2026-55202 ankur.tyagi85
                   ` (19 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Backport commit identified by Debian[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-54387

[1]https://security-tracker.debian.org/tracker/CVE-2026-54387

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../tinyproxy/tinyproxy/CVE-2026-54387.patch  | 37 +++++++++++++++++++
 .../tinyproxy/tinyproxy_1.11.3.bb             |  1 +
 2 files changed, 38 insertions(+)
 create mode 100644 meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-54387.patch

diff --git a/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-54387.patch b/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-54387.patch
new file mode 100644
index 0000000000..b12572f0ad
--- /dev/null
+++ b/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-54387.patch
@@ -0,0 +1,37 @@
+From a9602e492cedd5d5d18dd3675d9be90e9b0d9e66 Mon Sep 17 00:00:00 2001
+From: rofl0r <rofl0r@users.noreply.github.com>
+Date: Thu, 7 May 2026 16:33:11 +0000
+Subject: [PATCH] reqs: prevent request smuggling via both content-length and
+ chunked
+
+addressing point 1 of #609
+
+(cherry picked from commit 623bfc093df009296f0b85d40bc677ef9d5c09bb)
+
+CVE: CVE-2026-54387
+Upstream-Statys: Backport [https://github.com/tinyproxy/tinyproxy/commit/623bfc093df009296f0b85d40bc677ef9d5c09bb]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/reqs.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/reqs.c b/src/reqs.c
+index 8b68538..e3cfe76 100644
+--- a/src/reqs.c
++++ b/src/reqs.c
+@@ -942,8 +942,13 @@ process_client_headers (struct conn_s *connptr, pseudomap *hashofheaders)
+         connptr->content_length.client = get_content_length (hashofheaders);
+ 
+         /* Check whether client sends chunked data. */
+-        if (connptr->content_length.client == -1 && is_chunked_transfer (hashofheaders))
++        if (is_chunked_transfer (hashofheaders)) {
++                if (connptr->content_length.client != -1)
++                        /* request smuggling, see GH issue #609 */
++                        pseudomap_remove (hashofheaders, "content-length");
++
+                 connptr->content_length.client = -2;
++        }
+ 
+         /*
+          * See if there is a "Connection" header.  If so, we need to do a bit
diff --git a/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb b/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
index 4ce766b40b..b8a508d8d4 100644
--- a/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
+++ b/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
@@ -10,6 +10,7 @@ SRC_URI = "https://github.com/${BPN}/${BPN}/releases/download/${PV}/${BP}.tar.gz
            file://CVE-2026-3945-1.patch \
            file://CVE-2026-3945-2.patch \
            file://CVE-2026-31842.patch \
+           file://CVE-2026-54387.patch \
            "
 
 SRC_URI[sha256sum] = "9bcf46db1a2375ff3e3d27a41982f1efec4706cce8899ff9f33323a8218f7592"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 14/33] tinyproxy: patch CVE-2026-55202
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (11 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 13/33] tinyproxy: patch CVE-2026-54387 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:22 ` [oe][meta-webserver][wrynose][PATCH 15/33] nginx: mark CVE-2026-1642 patched ankur.tyagi85
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Backport commit identified by Debian[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-55202

[1]https://security-tracker.debian.org/tracker/CVE-2026-55202

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../tinyproxy/tinyproxy/CVE-2026-55202.patch  | 107 ++++++++++++++++++
 .../tinyproxy/tinyproxy_1.11.3.bb             |   1 +
 2 files changed, 108 insertions(+)
 create mode 100644 meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-55202.patch

diff --git a/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-55202.patch b/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-55202.patch
new file mode 100644
index 0000000000..4e446542e2
--- /dev/null
+++ b/meta-networking/recipes-support/tinyproxy/tinyproxy/CVE-2026-55202.patch
@@ -0,0 +1,107 @@
+From 04b34f814076d790db26925d7df7c30798910c99 Mon Sep 17 00:00:00 2001
+From: rofl0r <rofl0r@users.noreply.github.com>
+Date: Sat, 18 Apr 2026 00:03:15 +0200
+Subject: [PATCH] reqs: improve stathost detection (#606)
+
+until now, only the basicauth code checked the host header, regular connections didn't.
+
+- add a new helper function to compare a hostname with optional
+  trailingcolon/port against the stathost.
+- add stathost check via host header before transparent proxy check,
+  else stathost might be misdetected as a trans host request.
+- refactor existing stathost checks to use the new helper
+
+this should make it easier to access the stathost, for example by
+injecting a host header into a curl command line with -H:
+
+    $ curl -H "Host: tinyproxy.stats" 127.0.0.1:8080
+
+the stathost can also be specified as an ip address, e.g.
+Stathost "127.0.0.10" + a separate Listen statement for that ip.
+in such a case e.g.
+
+    $ curl http://127.0.0.10:8080
+
+would work too, even if curl didn't add a Host header (but it does anyway).
+
+(cherry picked from commit 09312a185ae25cc486b4ff5987638a7917a48bce)
+
+CVE: CVE-2026-55202
+Upstream-Status: Backport [https://github.com/tinyproxy/tinyproxy/commit/09312a185ae25cc486b4ff5987638a7917a48bce]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/reqs.c | 37 +++++++++++++++++++++++++------------
+ 1 file changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/src/reqs.c b/src/reqs.c
+index e3cfe76..d5037cf 100644
+--- a/src/reqs.c
++++ b/src/reqs.c
+@@ -316,6 +316,17 @@ static int send_connect_method_response (struct conn_s *connptr)
+                                       connptr->protocol.minor);
+ }
+ 
++/* determine whether a hostname with optional trailing colon/port is the
++   stathost */
++static int is_stathost (const char* host)
++{
++        const char *p = config->stathost;
++        const char *q = host;
++        if (!p || !q) return 0;
++        while (*p && *(p++) == *(q++));
++        return *p == 0 && (*q == 0 || *q == ':');
++}
++
+ /*
+  * Break the request line apart and figure out where to connect and
+  * build a new request line. Finally connect to the remote server.
+@@ -384,6 +395,16 @@ BAD_REQUEST_ERROR:
+                 goto fail;
+         }
+ 
++        /*
++         * Check to see if they're requesting the stat host
++         */
++        if (is_stathost (pseudomap_find (hashofheaders, "host"))) {
++got_stathost:
++                log_message (LOG_NOTICE, "Request for the stathost.");
++                connptr->show_stats = TRUE;
++                goto fail;
++        }
++
+ #ifdef REVERSE_SUPPORT
+         if (config->reversepath_list != NULL) {
+                 /*
+@@ -497,19 +518,11 @@ BAD_REQUEST_ERROR:
+                 }
+         }
+ #endif
+-
+-
+-        /*
+-         * Check to see if they're requesting the stat host
+-         */
+-        if (config->stathost && strcmp (config->stathost, request->host) == 0) {
+-                log_message (LOG_NOTICE, "Request for the stathost.");
+-                connptr->show_stats = TRUE;
+-                goto fail;
+-        }
++        /* check whether hostname from url is the stathost */
++        if (is_stathost (request->host))
++                goto got_stathost;
+ 
+         safefree (url);
+-
+         return request;
+ 
+ fail:
+@@ -1688,7 +1701,7 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
+ 
+                 if (!authstring && config->stathost) {
+                         authstring = pseudomap_find (hashofheaders, "host");
+-                        if (authstring && !strncmp(authstring, config->stathost, strlen(config->stathost))) {
++                        if (authstring && is_stathost(authstring)) {
+                                 authstring = pseudomap_find (hashofheaders, "authorization");
+                                 stathost_connect = 1;
+                         } else authstring = 0;
diff --git a/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb b/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
index b8a508d8d4..f9d425b45a 100644
--- a/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
+++ b/meta-networking/recipes-support/tinyproxy/tinyproxy_1.11.3.bb
@@ -11,6 +11,7 @@ SRC_URI = "https://github.com/${BPN}/${BPN}/releases/download/${PV}/${BP}.tar.gz
            file://CVE-2026-3945-2.patch \
            file://CVE-2026-31842.patch \
            file://CVE-2026-54387.patch \
+           file://CVE-2026-55202.patch \
            "
 
 SRC_URI[sha256sum] = "9bcf46db1a2375ff3e3d27a41982f1efec4706cce8899ff9f33323a8218f7592"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-webserver][wrynose][PATCH 15/33] nginx: mark CVE-2026-1642 patched
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (12 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 14/33] tinyproxy: patch CVE-2026-55202 ankur.tyagi85
@ 2026-09-07 10:22 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 16/33] open62541: patch CVE-2026-11946 ankur.tyagi85
                   ` (17 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:22 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Debian[1] also identified the commit[2]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-1642

[1]https://security-tracker.debian.org/tracker/CVE-2026-1642
[2]https://github.com/nginx/nginx/commit/784fa05025cb8cd0c770f99bc79d2794b9f85b6e

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-webserver/recipes-httpd/nginx/nginx_1.28.3.bb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/meta-webserver/recipes-httpd/nginx/nginx_1.28.3.bb b/meta-webserver/recipes-httpd/nginx/nginx_1.28.3.bb
index 9872a6de3b..f797f4a289 100644
--- a/meta-webserver/recipes-httpd/nginx/nginx_1.28.3.bb
+++ b/meta-webserver/recipes-httpd/nginx/nginx_1.28.3.bb
@@ -5,3 +5,4 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=3dc49537b08b14c8b66ad247bb4c4593"
 SRC_URI[sha256sum] = "2c96a946bfb0882a21744ed429770a2123ae1828c7c48665092993ddee91a918"
 
 CVE_STATUS[CVE-2025-53859] = "cpe-stable-backport: Fix is included in 1.28.1"
+CVE_STATUS[CVE-2026-1642] = "fixed-version: fixed since v1.28.2"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 16/33] open62541: patch CVE-2026-11946
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (13 preceding siblings ...)
  2026-09-07 10:22 ` [oe][meta-webserver][wrynose][PATCH 15/33] nginx: mark CVE-2026-1642 patched ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 17/33] smarty: mark CVEs patched ankur.tyagi85
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Backport commit identified by Debian[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-11946

[1]https://security-tracker.debian.org/tracker/CVE-2026-11946

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../opcua/open62541/CVE-2026-11946.patch      | 48 +++++++++++++++++++
 .../opcua/open62541_1.4.16.bb                 |  1 +
 2 files changed, 49 insertions(+)
 create mode 100644 meta-networking/recipes-protocols/opcua/open62541/CVE-2026-11946.patch

diff --git a/meta-networking/recipes-protocols/opcua/open62541/CVE-2026-11946.patch b/meta-networking/recipes-protocols/opcua/open62541/CVE-2026-11946.patch
new file mode 100644
index 0000000000..36c9c83af1
--- /dev/null
+++ b/meta-networking/recipes-protocols/opcua/open62541/CVE-2026-11946.patch
@@ -0,0 +1,48 @@
+From 47df558c02eef86bec125a54284b78563d1928b8 Mon Sep 17 00:00:00 2001
+From: Niels Beier <niels.beier@o6-automation.com>
+Date: Thu, 7 May 2026 15:25:30 +0200
+Subject: [PATCH] fix(server): Enforce default message and chunk size limits to
+ prevent DoS
+
+When tcpMaxMsgSize or tcpMaxChunks are configured as 0, the server treats the
+limit as truly unbounded. A remote attacker can exploit this by sending
+arbitrarily large messages or an unbounded number of chunks, exhausting server
+memory and causing a denial of service.
+
+Set safe defaults (512 MB per message, 16384 chunks) whenever the configured
+value is zero, mirroring the existing behaviour for recv/sendBufferSize.
+
+This commit mitigates a vulnerability reported by Lorenzo Cannella.
+
+Internal Vulnerability Advisory: open62541-SA-2026-0002
+
+(cherry picked from commit c9563e8ea4a8db2f64059c8ff7efe0b49a35bea3)
+
+CVE: CVE-2026-11946
+Upstream-Status: Backport [https://github.com/open62541/open62541/commit/c9563e8ea4a8db2f64059c8ff7efe0b49a35bea3]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/server/ua_server_binary.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/src/server/ua_server_binary.c b/src/server/ua_server_binary.c
+index b2de3b271..13859ce56 100644
+--- a/src/server/ua_server_binary.c
++++ b/src/server/ua_server_binary.c
+@@ -1114,6 +1114,15 @@ createServerSecureChannel(UA_BinaryProtocolManager *bpm, UA_ConnectionManager *c
+     if(connConfig.sendBufferSize == 0)
+         connConfig.sendBufferSize = 1 << 16; /* 64kB */
+ 
++    if(connConfig.localMaxMessageSize == 0)
++        connConfig.localMaxMessageSize = 1 << 29; /* 512 MB */
++    if(connConfig.remoteMaxMessageSize == 0)
++        connConfig.remoteMaxMessageSize = 1 << 29; /* 512 MB */
++    if(connConfig.localMaxChunkCount == 0)
++        connConfig.localMaxChunkCount = 1 << 14; /* 16384 */
++    if(connConfig.remoteMaxChunkCount == 0)
++        connConfig.remoteMaxChunkCount = 1 << 14; /* 16384 */
++
+     /* Set up the new SecureChannel */
+     UA_SecureChannel_init(&entry->channel);
+     entry->channel.config = connConfig;
diff --git a/meta-networking/recipes-protocols/opcua/open62541_1.4.16.bb b/meta-networking/recipes-protocols/opcua/open62541_1.4.16.bb
index 32f7148f4b..b9edc5fe30 100644
--- a/meta-networking/recipes-protocols/opcua/open62541_1.4.16.bb
+++ b/meta-networking/recipes-protocols/opcua/open62541_1.4.16.bb
@@ -18,6 +18,7 @@ SRC_URI = " \
     git://github.com/Pro/mdnsd.git;name=mdnsd;protocol=https;branch=master;destsuffix=${BB_GIT_DEFAULT_DESTSUFFIX}/deps/mdnsd \
     git://github.com/OPCFoundation/UA-Nodeset;name=ua-nodeset;protocol=https;branch=latest;destsuffix=${BB_GIT_DEFAULT_DESTSUFFIX}/deps/ua-nodeset \
     git://github.com/LiamBindle/MQTT-C.git;name=mqtt-c;protocol=https;branch=master;destsuffix=${BB_GIT_DEFAULT_DESTSUFFIX}/deps/mqtt-c \
+    file://CVE-2026-11946.patch \
 "
 
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 17/33] smarty: mark CVEs patched
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (14 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 16/33] open62541: patch CVE-2026-11946 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 18/33] tesseract: patch CVE-2026-73066 ankur.tyagi85
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

CVE-2024-35226[1], CVE-2026-62992[2], CVE-2026-62996[3] are patched in
current version.

Details:
https://nvd.nist.gov/vuln/detail/cve-2024-35226
https://nvd.nist.gov/vuln/detail/cve-2026-62992
https://nvd.nist.gov/vuln/detail/cve-2026-62996

[1]https://github.com/smarty-php/smarty/commit/0be92bc8a6fb83e6e0d883946f7e7c09ba4e857a
[2]https://github.com/smarty-php/smarty/commit/99c048ce7a590c519b79fbd38ad0143a08183a1f
[3]https://github.com/smarty-php/smarty/commit/3c9f77a2e06ce319ae0092496af32cc8f3adc52e

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-oe/recipes-support/smarty/smarty_5.8.4.bb | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/meta-oe/recipes-support/smarty/smarty_5.8.4.bb b/meta-oe/recipes-support/smarty/smarty_5.8.4.bb
index dcb7c85a80..cf6c42345c 100644
--- a/meta-oe/recipes-support/smarty/smarty_5.8.4.bb
+++ b/meta-oe/recipes-support/smarty/smarty_5.8.4.bb
@@ -35,3 +35,7 @@ FILES:${PN} += "${datadir}/php/smarty3/"
 RDEPENDS:${PN} = "php"
 
 CVE_PRODUCT = "smarty:smarty smarty-php:smarty"
+
+CVE_STATUS[CVE-2024-35226] = "fixed-version: fixed since v5.2.0"
+CVE_STATUS[CVE-2026-62992] = "fixed-version: fixed since v5.8.2"
+CVE_STATUS[CVE-2024-62996] = "fixed-version: fixed in v5.8.4"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 18/33] tesseract: patch CVE-2026-73066
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (15 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 17/33] smarty: mark CVEs patched ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 19/33] tesseract: patch CVE-2026-73067 ankur.tyagi85
                   ` (14 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-73066

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../tesseract/tesseract/CVE-2026-73066.patch  | 152 ++++++++++++++++++
 .../tesseract/tesseract_5.5.2.bb              |   4 +-
 2 files changed, 155 insertions(+), 1 deletion(-)
 create mode 100644 meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73066.patch

diff --git a/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73066.patch b/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73066.patch
new file mode 100644
index 0000000000..fc762ba8ca
--- /dev/null
+++ b/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73066.patch
@@ -0,0 +1,152 @@
+From f66bfcc45d1acd3e3c98f81e1edc8ddf49786555 Mon Sep 17 00:00:00 2001
+From: Stefan Weil <sw@weilnetz.de>
+Date: Thu, 23 Jul 2026 18:05:39 +0200
+Subject: [PATCH] Fix integer overflow in LSTM Convolve and Reconfig
+ deserialization (#4588)
+
+Add range and overflow validation in Convolve::DeSerialize and
+Reconfig::DeSerialize to prevent a crafted .traineddata file from
+triggering a heap out-of-bounds write via unchecked signed integer
+multiplication when computing the output-channel count.
+
+Validate ni/no/num_weights in Network::CreateFromFile.
+
+Add defense-in-depth bounds assertions in NetworkIO::Randomize and
+NetworkIO::CopyTimeStepGeneral.
+
+Reported-by: Eunho Kim <eunhok98@gmail.com>
+Signed-off-by: Stefan Weil <sw@weilnetz.de>
+Assisted-by: OpenCode / big-pickle (opencode)
+Tested-by: Eunho Kim <eunhok98@gmail.com>
+(cherry picked from commit 2f4d2f4bf45c363785d7bf1da29b6628f8939a72)
+
+CVE: CVE-2026-73066
+Upstream-Status: Backport [https://github.com/tesseract-ocr/tesseract/commit/2f4d2f4bf45c363785d7bf1da29b6628f8939a72]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/lstm/convolve.cpp  | 24 +++++++++++++++++++++++-
+ src/lstm/network.cpp   |  6 ++++++
+ src/lstm/networkio.cpp |  2 ++
+ src/lstm/reconfig.cpp  | 20 +++++++++++++++++++-
+ 4 files changed, 50 insertions(+), 2 deletions(-)
+
+diff --git a/src/lstm/convolve.cpp b/src/lstm/convolve.cpp
+index 6cfaa06e..d20a991c 100644
+--- a/src/lstm/convolve.cpp
++++ b/src/lstm/convolve.cpp
+@@ -23,8 +23,11 @@
+ 
+ #include "convolve.h"
+ 
++#include <cstdint>
++
+ #include "networkscratch.h"
+ #include "serialis.h"
++#include "tprintf.h"
+ 
+ namespace tesseract {
+ 
+@@ -46,7 +49,26 @@ bool Convolve::DeSerialize(TFile *fp) {
+   if (!fp->DeSerialize(&half_y_)) {
+     return false;
+   }
+-  no_ = ni_ * (2 * half_x_ + 1) * (2 * half_y_ + 1);
++  if (half_x_ < 0 || half_y_ < 0 || ni_ <= 0) {
++    tprintf("Error: invalid Convolve parameters: ni=%d half_x=%d half_y=%d\n", ni_, half_x_,
++            half_y_);
++    return false;
++  }
++  int64_t kx = 2LL * half_x_ + 1;
++  int64_t ky = 2LL * half_y_ + 1;
++  // Stepwise overflow check: ni_ * kx * ky must fit in int.
++  if (kx > INT_MAX / ky) {
++    tprintf("Error: Convolve output-channel count overflows: ni=%d half_x=%d half_y=%d\n", ni_,
++            half_x_, half_y_);
++    return false;
++  }
++  int64_t kxky = kx * ky;
++  if (static_cast<int64_t>(ni_) > INT_MAX / kxky) {
++    tprintf("Error: Convolve output-channel count overflows: ni=%d half_x=%d half_y=%d\n", ni_,
++            half_x_, half_y_);
++    return false;
++  }
++  no_ = static_cast<int>(static_cast<int64_t>(ni_) * kxky);
+   return true;
+ }
+ 
+diff --git a/src/lstm/network.cpp b/src/lstm/network.cpp
+index cfddbfd4..8230992a 100644
+--- a/src/lstm/network.cpp
++++ b/src/lstm/network.cpp
+@@ -247,6 +247,12 @@ Network *Network::CreateFromFile(TFile *fp) {
+     return nullptr;
+   }
+ 
++  if (ni < 0 || no < 0 || num_weights < 0) {
++    tprintf("Error: invalid network layer parameters: type=%d ni=%d no=%d num_weights=%d\n", type,
++            ni, no, num_weights);
++    return nullptr;
++  }
++
+   switch (type) {
+     case NT_CONVOLVE:
+       network = new Convolve(name, ni, 0, 0);
+diff --git a/src/lstm/networkio.cpp b/src/lstm/networkio.cpp
+index 3cb068c6..8636075b 100644
+--- a/src/lstm/networkio.cpp
++++ b/src/lstm/networkio.cpp
+@@ -405,6 +405,7 @@ void NetworkIO::CopyTimeStepFrom(int dest_t, const NetworkIO &src, int src_t) {
+ void NetworkIO::CopyTimeStepGeneral(int dest_t, int dest_offset, int num_features,
+                                     const NetworkIO &src, int src_t, int src_offset) {
+   ASSERT_HOST(int_mode_ == src.int_mode_);
++  ASSERT_HOST(dest_offset + num_features <= NumFeatures());
+   if (int_mode_) {
+     memcpy(i_[dest_t] + dest_offset, src.i_[src_t] + src_offset, num_features * sizeof(i_[0][0]));
+   } else {
+@@ -414,6 +415,7 @@ void NetworkIO::CopyTimeStepGeneral(int dest_t, int dest_offset, int num_feature
+ 
+ // Sets the given range to random values.
+ void NetworkIO::Randomize(int t, int offset, int num_features, TRand *randomizer) {
++  ASSERT_HOST(offset + num_features <= NumFeatures());
+   if (int_mode_) {
+     int8_t *line = i_[t] + offset;
+     for (int i = 0; i < num_features; ++i) {
+diff --git a/src/lstm/reconfig.cpp b/src/lstm/reconfig.cpp
+index 2f49d63e..a4e99497 100644
+--- a/src/lstm/reconfig.cpp
++++ b/src/lstm/reconfig.cpp
+@@ -18,6 +18,10 @@
+ 
+ #include "reconfig.h"
+ 
++#include <cstdint>
++
++#include "tprintf.h"
++
+ namespace tesseract {
+ 
+ Reconfig::Reconfig(const std::string &name, int ni, int x_scale, int y_scale)
+@@ -60,7 +64,21 @@ bool Reconfig::DeSerialize(TFile *fp) {
+   if (!fp->DeSerialize(&y_scale_)) {
+     return false;
+   }
+-  no_ = ni_ * x_scale_ * y_scale_;
++  if (x_scale_ <= 0 || y_scale_ <= 0 || ni_ <= 0) {
++    tprintf("Error: invalid Reconfig parameters: ni=%d x_scale=%d y_scale=%d\n", ni_, x_scale_,
++            y_scale_);
++    return false;
++  }
++  int64_t xs = x_scale_;
++  int64_t ys = y_scale_;
++  // Stepwise overflow check: ni_ * x_scale_ * y_scale_ must fit in int.
++  int64_t xsys = xs * ys;
++  if (static_cast<int64_t>(ni_) > INT_MAX / xsys) {
++    tprintf("Error: Reconfig output-channel count overflows: ni=%d x_scale=%d y_scale=%d\n", ni_,
++            x_scale_, y_scale_);
++    return false;
++  }
++  no_ = static_cast<int>(static_cast<int64_t>(ni_) * xsys);
+   return true;
+ }
+ 
diff --git a/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb b/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb
index 46b789cbc4..1b5a5fe2df 100644
--- a/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb
+++ b/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb
@@ -6,7 +6,9 @@ LICENSE = "Apache-2.0"
 LIC_FILES_CHKSUM = "file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57"
 
 SRCREV = "6e1d56a847e697de07b38619356550e5cf4e8633"
-SRC_URI = "git://github.com/${BPN}-ocr/${BPN}.git;branch=main;protocol=https;tag=${PV}"
+SRC_URI = "git://github.com/${BPN}-ocr/${BPN}.git;branch=main;protocol=https;tag=${PV} \
+           file://CVE-2026-73066.patch \
+"
 
 
 DEPENDS = "leptonica"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-oe][wrynose][PATCH 19/33] tesseract: patch CVE-2026-73067
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (16 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 18/33] tesseract: patch CVE-2026-73066 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 20/33] wolfssl: mark CVEs patched ankur.tyagi85
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-73067

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../tesseract/CVE-2026-73067-1.patch          | 423 ++++++++++++++++++
 .../tesseract/CVE-2026-73067-2.patch          |  96 ++++
 .../tesseract/tesseract_5.5.2.bb              |   2 +
 3 files changed, 521 insertions(+)
 create mode 100644 meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-1.patch
 create mode 100644 meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-2.patch

diff --git a/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-1.patch b/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-1.patch
new file mode 100644
index 0000000000..95fd102ebf
--- /dev/null
+++ b/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-1.patch
@@ -0,0 +1,423 @@
+From 9d83107c2511e7e2a7dc649c7bb1633da746669f Mon Sep 17 00:00:00 2001
+From: Stefan Weil <sw@weilnetz.de>
+Date: Sun, 12 Jul 2026 13:49:46 +0200
+Subject: [PATCH] Fix memory-safety issues in .traineddata deserialization
+
+Add bounds checking on count/length fields read from untrusted
+.traineddata files before they are used to size allocations or index
+arrays. Use unsigned types where negative values make no sense.
+
+Key changes:
+- serialis.cpp: overflow check in DeSerializeSkip, size limits for
+  DeSerialize(string) and DeSerialize(vector<char>)
+- unicharcompress.h: validate RecodedCharID length before reading
+  into fixed-size code array (buffer overflow fix), change length_
+  to uint32_t, use unsigned types for Set() index and length()
+- dawg.cpp/h: use uint32_t for num_edges_, add bounds checks on all
+  edge traversal loops, replace no-op ASSERT_HOST with proper errors
+- fontinfo.cpp: bounds check font name size to prevent integer
+  overflow in size+1, use uint32_t for spacing vector size
+- tessdatamanager.cpp: validate offsets are within file bounds
+- bitvector.cpp, weightmatrix.cpp, plumbing.cpp: add size limits
+
+Assisted-by: OpenCode / big-pickle (opencode)
+Signed-off-by: Stefan Weil <stweil@tessus.org>
+(cherry picked from commit 82727cc11c34eaf1249af002d69f6bbae70993b9)
+
+CVE: CVE-2026-73067
+Upstream-Status: Backport [https://github.com/tesseract-ocr/tesseract/commit/82727cc11c34eaf1249af002d69f6bbae70993b9]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/ccstruct/fontinfo.cpp      | 10 ++++++---
+ src/ccstruct/fontinfo.h        |  2 +-
+ src/ccutil/bitvector.cpp       |  4 ++++
+ src/ccutil/serialis.cpp        | 10 +++++++++
+ src/ccutil/tessdatamanager.cpp |  9 ++++++++
+ src/ccutil/unicharcompress.h   | 19 ++++++++++------
+ src/dict/dawg.cpp              | 40 ++++++++++++++++++++++++++--------
+ src/dict/dawg.h                | 16 +++++++++-----
+ src/lstm/plumbing.cpp          |  4 ++++
+ src/lstm/weightmatrix.cpp      |  4 ++++
+ 10 files changed, 92 insertions(+), 26 deletions(-)
+
+diff --git a/src/ccstruct/fontinfo.cpp b/src/ccstruct/fontinfo.cpp
+index 65d4d032..9984469f 100644
+--- a/src/ccstruct/fontinfo.cpp
++++ b/src/ccstruct/fontinfo.cpp
+@@ -145,6 +145,10 @@ bool read_info(TFile *f, FontInfo *fi) {
+   if (!f->DeSerialize(&size)) {
+     return false;
+   }
++  // Reject unreasonably large font names to prevent overflow in size + 1.
++  if (size > 100000) {
++    return false;
++  }
+   char *font_name = new char[size + 1];
+   fi->name = font_name;
+   if (!f->DeSerialize(font_name, size)) {
+@@ -161,16 +165,16 @@ bool write_info(FILE *f, const FontInfo &fi) {
+ }
+ 
+ bool read_spacing_info(TFile *f, FontInfo *fi) {
+-  int32_t vec_size, kern_size;
++  uint32_t vec_size;
++  int32_t kern_size;
+   if (!f->DeSerialize(&vec_size)) {
+     return false;
+   }
+-  ASSERT_HOST(vec_size >= 0);
+   if (vec_size == 0) {
+     return true;
+   }
+   fi->init_spacing(vec_size);
+-  for (int i = 0; i < vec_size; ++i) {
++  for (uint32_t i = 0; i < vec_size; ++i) {
+     auto *fs = new FontSpacingInfo();
+     if (!f->DeSerialize(&fs->x_gap_before) || !f->DeSerialize(&fs->x_gap_after) ||
+         !f->DeSerialize(&kern_size)) {
+diff --git a/src/ccstruct/fontinfo.h b/src/ccstruct/fontinfo.h
+index 1a84a567..cfb19e06 100644
+--- a/src/ccstruct/fontinfo.h
++++ b/src/ccstruct/fontinfo.h
+@@ -76,7 +76,7 @@ struct FontInfo {
+   bool DeSerialize(TFile *fp);
+ 
+   // Reserves unicharset_size spots in spacing_vec.
+-  void init_spacing(int unicharset_size) {
++  void init_spacing(uint32_t unicharset_size) {
+     spacing_vec = new std::vector<FontSpacingInfo *>(unicharset_size);
+   }
+   // Adds the given pointer to FontSpacingInfo to spacing_vec member
+diff --git a/src/ccutil/bitvector.cpp b/src/ccutil/bitvector.cpp
+index a02781a8..2b8b7f00 100644
+--- a/src/ccutil/bitvector.cpp
++++ b/src/ccutil/bitvector.cpp
+@@ -102,6 +102,10 @@ bool BitVector::DeSerialize(bool swap, FILE *fp) {
+   if (swap) {
+     ReverseN(&new_bit_size, sizeof(new_bit_size));
+   }
++  // Reject unreasonably large bit vectors.
++  if (new_bit_size > 500000000) {
++    return false;
++  }
+   Alloc(new_bit_size);
+   int wordlen = WordLength();
+   if (!tesseract::DeSerialize(fp, &array_[0], wordlen)) {
+diff --git a/src/ccutil/serialis.cpp b/src/ccutil/serialis.cpp
+index d9c9a8d4..cb663094 100644
+--- a/src/ccutil/serialis.cpp
++++ b/src/ccutil/serialis.cpp
+@@ -88,6 +88,10 @@ bool TFile::DeSerializeSkip(size_t size) {
+   if (!DeSerialize(&len)) {
+     return false;
+   }
++  // Check for overflow: len * size must not overflow size_t.
++  if (size != 0 && len > SIZE_MAX / size) {
++    return false;
++  }
+   return Skip(len * size);
+ }
+ 
+@@ -95,6 +99,9 @@ bool TFile::DeSerialize(std::string &data) {
+   uint32_t size;
+   if (!DeSerialize(&size)) {
+     return false;
++  } else if (size > 50000000) {
++    // Arbitrarily limit the size to protect against bad data.
++    return false;
+   } else if (size > 0) {
+     // TODO: optimize.
+     data.resize(size);
+@@ -113,6 +120,9 @@ bool TFile::DeSerialize(std::vector<char> &data) {
+   uint32_t size;
+   if (!DeSerialize(&size)) {
+     return false;
++  } else if (size > 50000000) {
++    // Arbitrarily limit the size to protect against bad data.
++    return false;
+   } else if (size > 0) {
+     // TODO: optimize.
+     data.resize(size);
+diff --git a/src/ccutil/tessdatamanager.cpp b/src/ccutil/tessdatamanager.cpp
+index 8ab26506..67e86dc0 100644
+--- a/src/ccutil/tessdatamanager.cpp
++++ b/src/ccutil/tessdatamanager.cpp
+@@ -132,14 +132,23 @@ bool TessdataManager::LoadMemBuffer(const char *name, const char *data, int size
+   }
+   for (unsigned i = 0; i < num_entries && i < TESSDATA_NUM_ENTRIES; ++i) {
+     if (offset_table[i] >= 0) {
++      if (offset_table[i] > size) {
++        return false;
++      }
+       int64_t entry_size = size - offset_table[i];
+       unsigned j = i + 1;
+       while (j < num_entries && offset_table[j] == -1) {
+         ++j;
+       }
+       if (j < num_entries) {
++        if (offset_table[j] < 0 || offset_table[j] > size) {
++          return false;
++        }
+         entry_size = offset_table[j] - offset_table[i];
+       }
++      if (entry_size < 0) {
++        return false;
++      }
+       entries_[i].resize(entry_size);
+       if (!fp.DeSerialize(&entries_[i][0], entry_size)) {
+         return false;
+diff --git a/src/ccutil/unicharcompress.h b/src/ccutil/unicharcompress.h
+index 2e81bbde..67a441e8 100644
+--- a/src/ccutil/unicharcompress.h
++++ b/src/ccutil/unicharcompress.h
+@@ -41,7 +41,7 @@ public:
+     length_ = length;
+   }
+   // Sets the code value at the given index in the code.
+-  void Set(int index, int value) {
++  void Set(uint32_t index, int value) {
+     code_[index] = value;
+     if (length_ <= index) {
+       length_ = index + 1;
+@@ -59,7 +59,7 @@ public:
+     return length_ == 0;
+   }
+   // Accessors
+-  int length() const {
++  uint32_t length() const {
+     return length_;
+   }
+   int operator()(int index) const {
+@@ -73,14 +73,19 @@ public:
+   }
+   // Reads from the given file. Returns false in case of error.
+   bool DeSerialize(TFile *fp) {
+-    return fp->DeSerialize(&self_normalized_) && fp->DeSerialize(&length_) &&
+-           fp->DeSerialize(&code_[0], length_);
++    if (!fp->DeSerialize(&self_normalized_) || !fp->DeSerialize(&length_)) {
++      return false;
++    }
++    if (length_ > kMaxCodeLen) {
++      return false;
++    }
++    return fp->DeSerialize(&code_[0], length_);
+   }
+   bool operator==(const RecodedCharID &other) const {
+     if (length_ != other.length_) {
+       return false;
+     }
+-    for (int i = 0; i < length_; ++i) {
++    for (uint32_t i = 0; i < length_; ++i) {
+       if (code_[i] != other.code_[i]) {
+         return false;
+       }
+@@ -91,7 +96,7 @@ public:
+   struct RecodedCharIDHash {
+     uint64_t operator()(const RecodedCharID &code) const {
+       uint64_t result = 0;
+-      for (int i = 0; i < code.length_; ++i) {
++      for (uint32_t i = 0; i < code.length_; ++i) {
+         result ^= static_cast<uint64_t>(code(i)) << (7 * i);
+       }
+       return result;
+@@ -103,7 +108,7 @@ private:
+   // that map to the same code. Has boolean value, but int8_t for serialization.
+   int8_t self_normalized_;
+   // The number of elements in use in code_;
+-  int32_t length_;
++  uint32_t length_;
+   // The re-encoded form of the unichar-id to which this RecodedCharID relates.
+   int32_t code_[kMaxCodeLen];
+ };
+diff --git a/src/dict/dawg.cpp b/src/dict/dawg.cpp
+index af45176f..dab4dfc2 100644
+--- a/src/dict/dawg.cpp
++++ b/src/dict/dawg.cpp
+@@ -221,7 +221,11 @@ EDGE_REF SquishedDawg::edge_char_of(NODE_REF node, UNICHAR_ID unichar_id,
+             (!word_end || end_of_word_from_edge_rec(edges_[edge]))) {
+           return (edge);
+         }
+-      } while (!last_edge(edge++));
++        if (last_edge(edge)) {
++          break;
++        }
++        ++edge;
++      } while (edge < num_edges_);
+     }
+   }
+   return (NO_EDGE); // not found
+@@ -234,7 +238,11 @@ int32_t SquishedDawg::num_forward_edges(NODE_REF node) const {
+   if (forward_edge(edge)) {
+     do {
+       num++;
+-    } while (!last_edge(edge++));
++      if (last_edge(edge)) {
++        break;
++      }
++      ++edge;
++    } while (edge < num_edges_);
+   }
+ 
+   return (num);
+@@ -274,7 +282,11 @@ void SquishedDawg::print_node(NODE_REF node, int max_num_edges) const {
+       if (edge - node > max_num_edges) {
+         return;
+       }
+-    } while (!last_edge(edge++));
++      if (last_edge(edge)) {
++        break;
++      }
++      ++edge;
++    } while (edge < num_edges_);
+ 
+     if (edge < num_edges_ && edge_occupied(edge) && backward_edge(edge)) {
+       do {
+@@ -290,7 +302,11 @@ void SquishedDawg::print_node(NODE_REF node, int max_num_edges) const {
+         if (edge - node > MAX_NODE_EDGES_DISPLAY) {
+           return;
+         }
+-      } while (!last_edge(edge++));
++        if (last_edge(edge)) {
++          break;
++        }
++        ++edge;
++      } while (edge < num_edges_);
+     }
+   } else {
+     tprintf(REFFORMAT " : no edges in this node\n", node);
+@@ -326,14 +342,17 @@ bool SquishedDawg::read_squished_dawg(TFile *file) {
+     return false;
+   }
+ 
+-  int32_t unicharset_size;
++  uint32_t unicharset_size;
+   if (!file->DeSerialize(&unicharset_size)) {
+     return false;
+   }
+   if (!file->DeSerialize(&num_edges_)) {
+     return false;
+   }
+-  ASSERT_HOST(num_edges_ > 0); // DAWG should not be empty
++  if (num_edges_ == 0) {
++    tprintf("Empty dawg: num_edges is 0\n");
++    return false;
++  }
+   Dawg::init(unicharset_size);
+ 
+   edges_ = new EDGE_RECORD[num_edges_];
+@@ -341,7 +360,7 @@ bool SquishedDawg::read_squished_dawg(TFile *file) {
+     return false;
+   }
+   if (debug_level_ > 2) {
+-    tprintf("type: %d lang: %s perm: %d unicharset_size: %d num_edges: %d\n",
++    tprintf("type: %d lang: %s perm: %d unicharset_size: %d num_edges: %" PRIu32 "\n",
+             type_, lang_.c_str(), perm_, unicharset_size_, num_edges_);
+     for (EDGE_REF edge = 0; edge < num_edges_; ++edge) {
+       print_edge(edge);
+@@ -378,8 +397,11 @@ std::unique_ptr<EDGE_REF[]> SquishedDawg::build_node_map(
+         break;
+       }
+       if (backward_edge(edge)) {
+-        while (!last_edge(edge++)) {
+-          ;
++        while (edge < num_edges_ && !last_edge(edge)) {
++          ++edge;
++        }
++        if (edge < num_edges_) {
++          ++edge; // Skip past the last backward edge.
+         }
+       }
+       edge--;
+diff --git a/src/dict/dawg.h b/src/dict/dawg.h
+index b87b3880..d0f412c3 100644
+--- a/src/dict/dawg.h
++++ b/src/dict/dawg.h
+@@ -418,7 +418,7 @@ public:
+     ASSERT_HOST(read_squished_dawg(&file));
+     num_forward_edges_in_node0 = num_forward_edges(0);
+   }
+-  SquishedDawg(EDGE_ARRAY edges, int num_edges, DawgType type,
++  SquishedDawg(EDGE_ARRAY edges, uint32_t num_edges, DawgType type,
+                const std::string &lang, PermuterType perm, int unicharset_size,
+                int debug_level)
+       : Dawg(type, lang, perm, debug_level),
+@@ -441,7 +441,7 @@ public:
+     return true;
+   }
+ 
+-  int NumEdges() {
++  uint32_t NumEdges() const {
+     return num_edges_;
+   }
+ 
+@@ -462,7 +462,11 @@ public:
+       if (!word_end || end_of_word_from_edge_rec(edges_[edge])) {
+         vec->push_back(NodeChild(unichar_id_from_edge_rec(edges_[edge]), edge));
+       }
+-    } while (!last_edge(edge++));
++      if (last_edge(edge)) {
++        break;
++      }
++      ++edge;
++    } while (edge < num_edges_);
+   }
+ 
+   /// Returns the next node visited by following the edge
+@@ -516,7 +520,7 @@ private:
+   }
+   /// Goes through all the edges and clears each one out.
+   inline void clear_all_edges() {
+-    for (int edge = 0; edge < num_edges_; edge++) {
++    for (uint32_t edge = 0; edge < num_edges_; edge++) {
+       set_empty_edge(edge);
+     }
+   }
+@@ -555,7 +559,7 @@ private:
+   /// Prints the contents of the SquishedDawg.
+   void print_all(const char *msg) {
+     tprintf("\n__________________________\n%s\n", msg);
+-    for (int i = 0; i < num_edges_; ++i) {
++    for (uint32_t i = 0; i < num_edges_; ++i) {
+       print_edge(i);
+     }
+     tprintf("__________________________\n");
+@@ -565,7 +569,7 @@ private:
+ 
+   // Member variables.
+   EDGE_ARRAY edges_ = nullptr;
+-  int32_t num_edges_ = 0;
++  uint32_t num_edges_ = 0;
+   int num_forward_edges_in_node0 = 0;
+ };
+ 
+diff --git a/src/lstm/plumbing.cpp b/src/lstm/plumbing.cpp
+index ebb6612e..f0133148 100644
+--- a/src/lstm/plumbing.cpp
++++ b/src/lstm/plumbing.cpp
+@@ -222,6 +222,10 @@ bool Plumbing::DeSerialize(TFile *fp) {
+   if (!fp->DeSerialize(&size)) {
+     return false;
+   }
++  // Reject unreasonably large network stacks.
++  if (size > 10000) {
++    return false;
++  }
+   for (uint32_t i = 0; i < size; ++i) {
+     Network *network = CreateFromFile(fp);
+     if (network == nullptr) {
+diff --git a/src/lstm/weightmatrix.cpp b/src/lstm/weightmatrix.cpp
+index 86255266..d40e9373 100644
+--- a/src/lstm/weightmatrix.cpp
++++ b/src/lstm/weightmatrix.cpp
+@@ -295,6 +295,10 @@ bool WeightMatrix::DeSerialize(bool training, TFile *fp) {
+     if (!fp->DeSerialize(&size)) {
+       return false;
+     }
++    // Reject unreasonably large scale vectors.
++    if (size > 100000000) {
++      return false;
++    }
+ #ifdef FAST_FLOAT
+     scales_.reserve(size);
+     for (auto n = size; n > 0; n--) {
diff --git a/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-2.patch b/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-2.patch
new file mode 100644
index 0000000000..04d1db2dc5
--- /dev/null
+++ b/meta-oe/recipes-graphics/tesseract/tesseract/CVE-2026-73067-2.patch
@@ -0,0 +1,96 @@
+From 364a1a76ed19fd2f975f267405f8e36f521e7175 Mon Sep 17 00:00:00 2001
+From: Stefan Weil <sw@weilnetz.de>
+Date: Sun, 12 Jul 2026 18:04:46 +0200
+Subject: [PATCH] Fix unbounded allocation and validate DAWG edge structure
+
+Bound num_edges_ against remaining component bytes before allocating
+the edges_ array in read_squished_dawg. This prevents a crafted
+num_edges_ = 0x7FFFFFFF from requesting ~17 GB and aborting via
+uncaught std::bad_alloc.
+
+After loading, validate the edge structure:
+- Reject edges whose next_node value exceeds num_edges_ (wild-index
+  read during dictionary lookup).
+- Reject unterminated forward edge runs (the original heap OOB read).
+
+Also add TFile::RemainingBytes() to query how many bytes are left to
+read from the current position.
+
+Assisted-by: OpenCode / big-pickle (opencode)
+Reported-by: GitHub Copilot
+Signed-off-by: Stefan Weil <stweil@tessus.org>
+(cherry picked from commit 55287a94b8044c05ce3fd10f5aca6ebbd238e518)
+
+CVE: CVE-2026-73067
+Upstream-Status: Backport [https://github.com/tesseract-ocr/tesseract/commit/55287a94b8044c05ce3fd10f5aca6ebbd238e518]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/ccutil/serialis.h |  4 ++++
+ src/dict/dawg.cpp     | 32 ++++++++++++++++++++++++++++++++
+ 2 files changed, 36 insertions(+)
+
+diff --git a/src/ccutil/serialis.h b/src/ccutil/serialis.h
+index d6e4a996..59a4e1f1 100644
+--- a/src/ccutil/serialis.h
++++ b/src/ccutil/serialis.h
+@@ -75,6 +75,10 @@ public:
+   void set_swap(bool value) {
+     swap_ = value;
+   }
++  // Returns the number of bytes remaining to be read.
++  size_t RemainingBytes() const {
++    return data_ != nullptr && offset_ < data_->size() ? data_->size() - offset_ : 0;
++  }
+ 
+   // Deserialize data.
+   bool DeSerializeSize(int32_t *data);
+diff --git a/src/dict/dawg.cpp b/src/dict/dawg.cpp
+index dab4dfc2..75cb9a1f 100644
+--- a/src/dict/dawg.cpp
++++ b/src/dict/dawg.cpp
+@@ -353,12 +353,44 @@ bool SquishedDawg::read_squished_dawg(TFile *file) {
+     tprintf("Empty dawg: num_edges is 0\n");
+     return false;
+   }
++  // Reject if the declared edge count exceeds the remaining component bytes.
++  if (num_edges_ > file->RemainingBytes() / sizeof(EDGE_RECORD)) {
++    tprintf("Dawg num_edges %u exceeds remaining data\n", num_edges_);
++    return false;
++  }
+   Dawg::init(unicharset_size);
+ 
+   edges_ = new EDGE_RECORD[num_edges_];
+   if (!file->DeSerialize(&edges_[0], num_edges_)) {
+     return false;
+   }
++  // Validate the loaded edge structure: check that next_node values are in
++  // bounds and that forward edge runs are properly terminated.
++  for (uint32_t i = 0; i < num_edges_; ++i) {
++    if (edges_[i] == next_node_mask_) {
++      continue; // Empty slot.
++    }
++    NODE_REF next = next_node_from_edge_rec(edges_[i]);
++    if (next != 0 && static_cast<uint32_t>(next) >= num_edges_) {
++      tprintf("Dawg edge %u has out-of-bounds next_node\n", i);
++      return false;
++    }
++    if (forward_edge(i)) {
++      uint32_t j = i;
++      bool terminated = false;
++      do {
++        if (last_edge(j)) {
++          terminated = true;
++          break;
++        }
++        ++j;
++      } while (j < num_edges_);
++      if (!terminated) {
++        tprintf("Dawg forward edge run starting at %u is not terminated\n", i);
++        return false;
++      }
++    }
++  }
+   if (debug_level_ > 2) {
+     tprintf("type: %d lang: %s perm: %d unicharset_size: %d num_edges: %" PRIu32 "\n",
+             type_, lang_.c_str(), perm_, unicharset_size_, num_edges_);
diff --git a/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb b/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb
index 1b5a5fe2df..f26d2f36a1 100644
--- a/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb
+++ b/meta-oe/recipes-graphics/tesseract/tesseract_5.5.2.bb
@@ -8,6 +8,8 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57"
 SRCREV = "6e1d56a847e697de07b38619356550e5cf4e8633"
 SRC_URI = "git://github.com/${BPN}-ocr/${BPN}.git;branch=main;protocol=https;tag=${PV} \
            file://CVE-2026-73066.patch \
+           file://CVE-2026-73067-1.patch \
+           file://CVE-2026-73067-2.patch \
 "
 
 


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 20/33] wolfssl: mark CVEs patched
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (17 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 19/33] tesseract: patch CVE-2026-73067 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 21/33] wolfssl: patch CVE-2026-10098 ankur.tyagi85
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

CVE-2023-6937[1] and CVE-2024-5814[2] are patched in current version.

Details:
https://nvd.nist.gov/vuln/detail/cve-2023-6937
https://nvd.nist.gov/vuln/detail/cve-2024-5814

[1]https://github.com/wolfSSL/wolfssl/blob/v5.6.6-stable/ChangeLog.md#vulnerabilities
[2]https://github.com/wolfSSL/wolfssl/blob/v5.7.2-stable/ChangeLog.md#vulnerabilities

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 2978ff1cc1..295029246c 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -69,3 +69,5 @@ CVE_STATUS[CVE-2026-5504] = "fixed-version: fixed in 5.9.1"
 CVE_STATUS[CVE-2026-5507] = "fixed-version: fixed in 5.9.1"
 CVE_STATUS[CVE-2026-5772] = "fixed-version: fixed in 5.9.1"
 CVE_STATUS[CVE-2026-5778] = "fixed-version: fixed in 5.9.1"
+CVE_STATUS[CVE-2023-6937] = "fixed-version: fixed since v5.6.6"
+CVE_STATUS[CVE-2024-5814] = "fixed-version: fixed since v5.7.2"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 21/33] wolfssl: patch CVE-2026-10098
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (18 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 20/33] wolfssl: mark CVEs patched ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 22/33] wolfssl: patch CVE-2026-10512 ankur.tyagi85
                   ` (11 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

CVE-2026-10098-1.patch is needed to cherry-pick the commit mentioned in the
PR[1]

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-10098

[1]https://github.com/wolfSSL/wolfssl/pull/10554/commits

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-10098-1.patch      | 368 ++++++++++++++++++
 .../wolfssl/files/CVE-2026-10098-2.patch      | 126 ++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   2 +
 3 files changed, 496 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-1.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-2.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-1.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-1.patch
new file mode 100644
index 0000000000..86f1c8a9a0
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-1.patch
@@ -0,0 +1,368 @@
+From d2dca1bdcb6dc5f6fb02c44a042130cd11d27cd0 Mon Sep 17 00:00:00 2001
+From: Colton Willey <colton@wolfssl.com>
+Date: Mon, 13 Apr 2026 20:29:50 -0700
+Subject: [PATCH] Fix NULL derefs, buffer overflow, and i2d contract in
+ EVP/OCSP/X509
+
+Harden OpenSSL compatibility layer against NULL pointers, negative lengths,
+and buffer overflows across EVP, OCSP, and X509 APIs. Fix DSA SignFinal
+write-before-check overflow, add missing i2d_OCSP_RESPONSE allocation path,
+and fix unaligned keyUsage access.
+
+(cherry picked from commit 58a27848a800aadca91f606dc4fe5234b9971011)
+
+CVE: CVE-2026-10098
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/58a27848a800aadca91f606dc4fe5234b9971011]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/ocsp.c               | 39 +++++++++++++++++++++++++------
+ src/ssl.c                |  8 ++++++-
+ src/x509.c               | 12 ++++++++--
+ tests/api.c              |  2 +-
+ wolfcrypt/src/evp.c      | 50 ++++++++++++++++++++++++++++++++--------
+ wolfcrypt/src/pwdbased.c |  3 +++
+ 6 files changed, 94 insertions(+), 20 deletions(-)
+
+diff --git a/src/ocsp.c b/src/ocsp.c
+index 2fff7ced5..9de23cb9e 100644
+--- a/src/ocsp.c
++++ b/src/ocsp.c
+@@ -749,7 +749,9 @@ int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
+ 
+     single = bs->single;
+     while (single != NULL) {
+-        if ((XMEMCMP(single->status->serial, id->status->serial, (size_t)single->status->serialSz) == 0)
++        if (single->status != NULL && id->status != NULL &&
++            (XMEMCMP(single->status->serial, id->status->serial,
++                     (size_t)single->status->serialSz) == 0)
+          && (XMEMCMP(single->issuerHash, id->issuerHash, OCSP_DIGEST_SIZE) == 0)
+          && (XMEMCMP(single->issuerKeyHash, id->issuerKeyHash, OCSP_DIGEST_SIZE) == 0)) {
+             break;
+@@ -757,7 +759,7 @@ int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
+         single = single->next;
+     }
+ 
+-    if (single == NULL)
++    if (single == NULL || single->status == NULL)
+         return WOLFSSL_FAILURE;
+ 
+     if (status != NULL)
+@@ -1108,6 +1110,9 @@ int wolfSSL_OCSP_basic_verify(WOLFSSL_OCSP_BASICRESP* bs,
+     int embedded;
+     DecodedCert *cert = NULL;
+ 
++    if (bs == NULL)
++        return WOLFSSL_FAILURE;
++
+     ret = OcspFindSigner(bs, certs, &cert, &embedded, flags);
+     if (ret != 0) {
+         WOLFSSL_MSG("OCSP no signer found");
+@@ -1300,15 +1305,31 @@ int wolfSSL_i2d_OCSP_RESPONSE(OcspResponse* response,
+     if (response == NULL)
+         return BAD_FUNC_ARG;
+ 
++    if (response->source == NULL)
++        return BAD_FUNC_ARG;
++
+     if (data == NULL)
+         return (int)response->maxIdx;
+ 
+-    XMEMCPY(*data, response->source, response->maxIdx);
++    if (*data == NULL) {
++        *data = (unsigned char*)XMALLOC(response->maxIdx, NULL,
++                                        DYNAMIC_TYPE_OPENSSL);
++        if (*data == NULL)
++            return -1;
++        XMEMCPY(*data, response->source, response->maxIdx);
++    }
++    else {
++        XMEMCPY(*data, response->source, response->maxIdx);
++        *data += response->maxIdx;
++    }
++
+     return (int)response->maxIdx;
+ }
+ 
+ int wolfSSL_OCSP_response_status(OcspResponse *response)
+ {
++    if (response == NULL)
++        return -1;
+     return response->responseStatus;
+ }
+ 
+@@ -1335,8 +1356,12 @@ const char *wolfSSL_OCSP_response_status_str(long s)
+ WOLFSSL_OCSP_BASICRESP* wolfSSL_OCSP_response_get1_basic(OcspResponse* response)
+ {
+     WOLFSSL_OCSP_BASICRESP* bs;
+-    const unsigned char *ptr = response->source;
++    const unsigned char *ptr;
+ 
++    if (response == NULL || response->source == NULL)
++        return NULL;
++
++    ptr = response->source;
+     bs = wolfSSL_d2i_OCSP_RESPONSE(NULL, &ptr, response->maxIdx);
+     return bs;
+ }
+@@ -1637,8 +1662,8 @@ int wolfSSL_OCSP_single_get0_status(WOLFSSL_OCSP_SINGLERESP *single,
+                                     WOLFSSL_ASN1_TIME **thisupd,
+                                     WOLFSSL_ASN1_TIME **nextupd)
+ {
+-    if (single == NULL)
+-        return WOLFSSL_FAILURE;
++    if (single == NULL || single->status == NULL)
++        return -1;
+ 
+ #ifdef WOLFSSL_OCSP_PARSE_STATUS
+     if (thisupd != NULL)
+@@ -1784,7 +1809,7 @@ int wolfSSL_OCSP_REQ_CTX_add1_header(WOLFSSL_OCSP_REQ_CTX *ctx,
+ {
+     WOLFSSL_ENTER("wolfSSL_OCSP_REQ_CTX_add1_header");
+ 
+-    if (name == NULL) {
++    if (ctx == NULL || name == NULL) {
+         WOLFSSL_MSG("Bad parameter");
+         return WOLFSSL_FAILURE;
+     }
+diff --git a/src/ssl.c b/src/ssl.c
+index 58cd6701c..7d6ca462b 100644
+--- a/src/ssl.c
++++ b/src/ssl.c
+@@ -11699,13 +11699,19 @@ char* wolfSSL_CIPHER_description(const WOLFSSL_CIPHER* cipher, char* in,
+ int wolfSSL_OCSP_parse_url(const char* url, char** host, char** port,
+         char** path, int* ssl)
+ {
+-    const char* u = url;
++    const char* u;
+     const char* upath; /* path in u */
+     const char* uport; /* port in u */
+     const char* hostEnd;
+ 
+     WOLFSSL_ENTER("OCSP_parse_url");
+ 
++    if (url == NULL || host == NULL || port == NULL || path == NULL ||
++            ssl == NULL) {
++        return WOLFSSL_FAILURE;
++    }
++
++    u = url;
+     *host = NULL;
+     *port = NULL;
+     *path = NULL;
+diff --git a/src/x509.c b/src/x509.c
+index 46dfd38ed..b92f7d735 100644
+--- a/src/x509.c
++++ b/src/x509.c
+@@ -1317,7 +1317,9 @@ int wolfSSL_X509_add_ext(WOLFSSL_X509 *x509, WOLFSSL_X509_EXTENSION *ext,
+         if (ext && ext->value.data) {
+             if (ext->value.length == sizeof(word16)) {
+                 /* if ext->value is already word16, set directly */
+-                x509->keyUsage = *(word16*)ext->value.data;
++                word16 ku;
++                XMEMCPY(&ku, ext->value.data, sizeof(word16));
++                x509->keyUsage = ku;
+ #ifdef BIG_ENDIAN_ORDER
+                 x509->keyUsage = rotlFixed16(x509->keyUsage, 8U);
+ #endif
+@@ -10998,6 +11000,11 @@ WOLFSSL_ASN1_INTEGER* wolfSSL_X509_get_serialNumber(WOLFSSL_X509* x509)
+     if (x509->serialNumber != NULL)
+        return x509->serialNumber;
+ 
++    if (x509->serialSz < 0) {
++        WOLFSSL_MSG("Invalid serial number size");
++        return NULL;
++    }
++
+     a = wolfSSL_ASN1_INTEGER_new();
+     if (a == NULL)
+         return NULL;
+@@ -16120,7 +16127,8 @@ int wolfSSL_X509_set1_notBefore(WOLFSSL_X509* x509, const WOLFSSL_ASN1_TIME *t)
+ int wolfSSL_X509_set_serialNumber(WOLFSSL_X509* x509, WOLFSSL_ASN1_INTEGER* s)
+ {
+     WOLFSSL_ENTER("wolfSSL_X509_set_serialNumber");
+-    if (x509 == NULL || s == NULL || s->length >= EXTERNAL_SERIAL_SIZE)
++    if (x509 == NULL || s == NULL || s->data == NULL ||
++            s->length >= EXTERNAL_SERIAL_SIZE)
+         return WOLFSSL_FAILURE;
+ 
+     /* WOLFSSL_ASN1_INTEGER has type | size | data
+diff --git a/tests/api.c b/tests/api.c
+index 5eca4071a..919b951b3 100644
+--- a/tests/api.c
++++ b/tests/api.c
+@@ -20274,7 +20274,7 @@ static int test_wolfSSL_OCSP_single_get0_status(void)
+     ExpectPtrEq(nextDate, &certStatus.nextDateParsed);
+ 
+     ExpectIntEQ(wolfSSL_OCSP_single_get0_status(NULL, NULL, NULL, NULL, NULL),
+-        CERT_GOOD);
++        -1);
+     ExpectIntEQ(wolfSSL_OCSP_single_get0_status(&single, NULL, NULL, NULL,
+         NULL), CERT_GOOD);
+ #endif
+diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c
+index 05e406883..996f31f86 100644
+--- a/wolfcrypt/src/evp.c
++++ b/wolfcrypt/src/evp.c
+@@ -1314,7 +1314,11 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out,
+ #ifndef WOLFSSL_AESGCM_STREAM
+             if ((ctx->authBuffer && ctx->authBufferLen > 0)
+              || (ctx->authBufferLen == 0)) {
+-                if (ctx->enc)
++                if (ctx->authBufferLen > 0 && out == NULL) {
++                    ret = WOLFSSL_FAILURE;
++                    *outl = 0;
++                }
++                else if (ctx->enc)
+                     ret = wc_AesGcmEncrypt(&ctx->cipher.aes, out,
+                             ctx->authBuffer, ctx->authBufferLen,
+                             ctx->iv, ctx->ivSz, ctx->authTag, ctx->authTagSz,
+@@ -1397,7 +1401,11 @@ int wolfSSL_EVP_CipherFinal(WOLFSSL_EVP_CIPHER_CTX *ctx, unsigned char *out,
+         case WC_AES_256_CCM_TYPE:
+             if ((ctx->authBuffer && ctx->authBufferLen > 0)
+              || (ctx->authBufferLen == 0)) {
+-                if (ctx->enc) {
++                if (ctx->authBufferLen > 0 && out == NULL) {
++                    ret = WOLFSSL_FAILURE;
++                    *outl = 0;
++                }
++                else if (ctx->enc) {
+                     ret = wc_AesCcmEncrypt(&ctx->cipher.aes, out,
+                         ctx->authBuffer, (word32)ctx->authBufferLen,
+                         ctx->iv, (word32)ctx->ivSz, ctx->authTag,
+@@ -4309,16 +4317,19 @@ int wolfSSL_EVP_SignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sigret,
+ #ifndef NO_DSA
+     case WC_EVP_PKEY_DSA: {
+         int bytes;
+-        ret = wolfSSL_DSA_do_sign(md, sigret, pkey->dsa);
++        unsigned char tmpSig[DSA_MAX_SIG_SIZE];
++        ret = wolfSSL_DSA_do_sign(md, tmpSig, pkey->dsa);
+         /* wolfSSL_DSA_do_sign() can return WOLFSSL_FATAL_ERROR */
+         if (ret != WOLFSSL_SUCCESS)
+             return ret;
+         bytes = wolfSSL_BN_num_bytes(pkey->dsa->q);
+         if (bytes == WC_NO_ERR_TRACE(WOLFSSL_FAILURE) ||
+-            (int)*siglen < bytes * 2)
++            bytes > DSA_MAX_HALF_SIZE ||
++            bytes * 2 > (int)*siglen)
+         {
+             return WOLFSSL_FAILURE;
+         }
++        XMEMCPY(sigret, tmpSig, bytes * 2);
+         *siglen = (unsigned int)(bytes * 2);
+         return WOLFSSL_SUCCESS;
+     }
+@@ -4398,7 +4409,8 @@ int wolfSSL_EVP_VerifyFinal(WOLFSSL_EVP_MD_CTX *ctx,
+     unsigned char md[WC_MAX_DIGEST_SIZE];
+     unsigned int mdsize;
+ 
+-    if (ctx == NULL) return WOLFSSL_FAILURE;
++    if (ctx == NULL || pkey == NULL || sig == NULL)
++        return WOLFSSL_FAILURE;
+     WOLFSSL_ENTER("EVP_VerifyFinal");
+     ret = wolfSSL_EVP_DigestFinal(ctx, md, &mdsize);
+     if (ret <= 0)
+@@ -4459,6 +4471,9 @@ WOLFSSL_EVP_PKEY* wolfSSL_EVP_PKEY_new_mac_key(int type, WOLFSSL_ENGINE* e,
+     if (type != WC_EVP_PKEY_HMAC || (key == NULL && keylen != 0))
+         return NULL;
+ 
++    if (keylen < 0)
++        return NULL;
++
+     pkey = wolfSSL_EVP_PKEY_new();
+     if (pkey != NULL) {
+         pkey->pkey.ptr = (char*)XMALLOC((size_t)keylen, NULL,
+@@ -4870,6 +4885,9 @@ int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig,
+             return WOLFSSL_SUCCESS;
+         }
+     }
++    else if (ctx->pctx == NULL || ctx->pctx->pkey == NULL) {
++        return WOLFSSL_FAILURE;
++    }
+ #ifndef NO_RSA
+     else if (ctx->pctx->pkey->type == WC_EVP_PKEY_RSA) {
+         if (sig == NULL) {
+@@ -5007,6 +5025,8 @@ int wolfSSL_EVP_DigestVerifyFinal(WOLFSSL_EVP_MD_CTX *ctx,
+         return WOLFSSL_FAILURE;
+     }
+     else {
++        if (ctx->pctx == NULL || ctx->pctx->pkey == NULL)
++            return WOLFSSL_FAILURE;
+         /* Verify the signature with the digest. */
+         switch (ctx->pctx->pkey->type) {
+     #if !defined(NO_RSA)
+@@ -10232,6 +10252,9 @@ int wolfSSL_EVP_Digest(const unsigned char* in, int inSz, unsigned char* out,
+         return WOLFSSL_FAILURE;
+     }
+ 
++    if (inSz < 0)
++        return WOLFSSL_FAILURE;
++
+     err = wolfSSL_EVP_get_hashinfo(evp, &hashType, &hashSz);
+     if (err != WOLFSSL_SUCCESS)
+         return err;
+@@ -11279,6 +11302,7 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
+         enum wc_HashType macType;
+ 
+         WOLFSSL_ENTER("wolfSSL_EVP_DigestFinal");
++
+         macType = EvpMd2MacType(wolfSSL_EVP_MD_CTX_md(ctx));
+         switch (macType) {
+             case WC_HASH_TYPE_MD4:
+@@ -11304,16 +11328,18 @@ int wolfSSL_EVP_MD_type(const WOLFSSL_EVP_MD* type)
+ 
+             case WC_HASH_TYPE_SHAKE128:
+         #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE128)
+-                *s = 16; /* if mixing up XOF with plain digest 128 bit is
+-                          * default for SHAKE128 */
++                if (s != NULL)
++                    *s = 16; /* if mixing up XOF with plain digest 128 bit is
++                              * default for SHAKE128 */
+         #else
+                 return WOLFSSL_FAILURE;
+         #endif
+                 break;
+             case WC_HASH_TYPE_SHAKE256:
+         #if defined(WOLFSSL_SHA3) && defined(WOLFSSL_SHAKE256)
+-                *s = 32; /* if mixing up XOF with plain digest 256 bit is
+-                          * default for SHAKE256 */
++                if (s != NULL)
++                    *s = 32; /* if mixing up XOF with plain digest 256 bit is
++                              * default for SHAKE256 */
+         #else
+                 return WOLFSSL_FAILURE;
+         #endif
+@@ -12881,6 +12907,9 @@ int wolfSSL_EVP_EncodeBlock(unsigned char *out, const unsigned char *in,
+     if (out == NULL || in == NULL)
+         return WOLFSSL_FATAL_ERROR;
+ 
++    if (inLen < 0)
++        return WOLFSSL_FATAL_ERROR;
++
+     if (Base64_Encode_NoNl(in, (word32)inLen, out, &ret) == 0)
+         return (int)ret;
+     else
+@@ -12897,6 +12926,9 @@ int wolfSSL_EVP_DecodeBlock(unsigned char *out, const unsigned char *in,
+     if (out == NULL || in == NULL)
+         return WOLFSSL_FATAL_ERROR;
+ 
++    if (inLen < 0)
++        return WOLFSSL_FATAL_ERROR;
++
+     if (Base64_Decode(in, (word32)inLen, out, &ret) == 0)
+         return (int)ret;
+     else
+diff --git a/wolfcrypt/src/pwdbased.c b/wolfcrypt/src/pwdbased.c
+index c2ed5c042..4b9502a8c 100644
+--- a/wolfcrypt/src/pwdbased.c
++++ b/wolfcrypt/src/pwdbased.c
+@@ -76,6 +76,9 @@ int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
+         return BAD_FUNC_ARG;
+     }
+ 
++    if (keyLen > INT_MAX - ivLen)
++        return BAD_FUNC_ARG;
++
+     if (iterations <= 0)
+         iterations = 1;
+ 
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-2.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-2.patch
new file mode 100644
index 0000000000..0c28dbbba0
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10098-2.patch
@@ -0,0 +1,126 @@
+From 1260ee5fe45c6e4c0aeb62c26a04db5faec6ff08 Mon Sep 17 00:00:00 2001
+From: Reda Chouk <reda@wolfssl.com>
+Date: Fri, 29 May 2026 05:10:21 -0700
+Subject: [PATCH] Require equal serial lengths before comparing serial bytes so
+ a response serial that is only a prefix of the requested serial is not
+ treated as a match
+
+(cherry picked from commit 53e1db478b62f40ad6ce9b1a1d65d593a9d3d9fb)
+
+CVE: CVE-2026-10098
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/53e1db478b62f40ad6ce9b1a1d65d593a9d3d9fb]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/ocsp.c            |  3 ++-
+ tests/api.c           |  1 +
+ tests/api/test_ocsp.c | 57 +++++++++++++++++++++++++++++++++++++++++++
+ tests/api/test_ocsp.h |  1 +
+ 4 files changed, 61 insertions(+), 1 deletion(-)
+
+diff --git a/src/ocsp.c b/src/ocsp.c
+index 9de23cb9e..b8352ee72 100644
+--- a/src/ocsp.c
++++ b/src/ocsp.c
+@@ -750,7 +750,8 @@ int wolfSSL_OCSP_resp_find_status(WOLFSSL_OCSP_BASICRESP *bs,
+     single = bs->single;
+     while (single != NULL) {
+         if (single->status != NULL && id->status != NULL &&
+-            (XMEMCMP(single->status->serial, id->status->serial,
++            (single->status->serialSz == id->status->serialSz)
++         && (XMEMCMP(single->status->serial, id->status->serial,
+                      (size_t)single->status->serialSz) == 0)
+          && (XMEMCMP(single->issuerHash, id->issuerHash, OCSP_DIGEST_SIZE) == 0)
+          && (XMEMCMP(single->issuerKeyHash, id->issuerKeyHash, OCSP_DIGEST_SIZE) == 0)) {
+diff --git a/tests/api.c b/tests/api.c
+index 919b951b3..ad5f84573 100644
+--- a/tests/api.c
++++ b/tests/api.c
+@@ -35924,6 +35924,7 @@ TEST_CASE testCases[] = {
+     TEST_DECL(test_ocsp_response_parsing),
+     TEST_DECL(test_ocsp_certid_enc_dec),
+     TEST_DECL(test_ocsp_certid_dup),
++    TEST_DECL(test_ocsp_resp_find_status_serial_prefix),
+     TEST_DECL(test_ocsp_tls_cert_cb),
+     TEST_DECL(test_ocsp_cert_unknown_crl_fallback),
+     TEST_DECL(test_ocsp_cert_unknown_crl_fallback_nonleaf),
+diff --git a/tests/api/test_ocsp.c b/tests/api/test_ocsp.c
+index 02938adfd..1f1055fc6 100644
+--- a/tests/api/test_ocsp.c
++++ b/tests/api/test_ocsp.c
+@@ -723,6 +723,63 @@ int test_ocsp_certid_dup(void)
+ }
+ #endif
+ 
++int test_ocsp_resp_find_status_serial_prefix(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_OCSP) && defined(OPENSSL_EXTRA) && !defined(NO_SHA)
++    OcspResponse response;
++    OcspEntry    single;
++    CertStatus   responseStatus;
++    OcspEntry    requestedId;
++    CertStatus   requestedStatus;
++    int          status;
++
++    XMEMSET(&response, 0, sizeof(response));
++    XMEMSET(&single, 0, sizeof(single));
++    XMEMSET(&responseStatus, 0, sizeof(responseStatus));
++    XMEMSET(&requestedId, 0, sizeof(requestedId));
++    XMEMSET(&requestedStatus, 0, sizeof(requestedStatus));
++
++    single.status   = &responseStatus;
++    requestedId.status = &requestedStatus;
++    response.single  = &single;
++
++    /* Matching issuer name and key hashes on both sides. */
++    XMEMSET(single.issuerHash, 0x41, OCSP_DIGEST_SIZE);
++    XMEMSET(single.issuerKeyHash, 0x42, OCSP_DIGEST_SIZE);
++    XMEMCPY(requestedId.issuerHash, single.issuerHash, OCSP_DIGEST_SIZE);
++    XMEMCPY(requestedId.issuerKeyHash, single.issuerKeyHash, OCSP_DIGEST_SIZE);
++
++    /* Response carries a CERT_GOOD status for serial 01:02 (2 bytes). */
++    responseStatus.serial[0] = 0x01;
++    responseStatus.serial[1] = 0x02;
++    responseStatus.serialSz  = 2;
++    responseStatus.status    = CERT_GOOD;
++
++    /* Sanity check: an exact serial match must be found and report CERT_GOOD. */
++    requestedStatus.serial[0] = 0x01;
++    requestedStatus.serial[1] = 0x02;
++    requestedStatus.serialSz  = 2;
++    status = -1;
++    ExpectIntEQ(wolfSSL_OCSP_resp_find_status(&response, &requestedId, &status,
++                    NULL, NULL, NULL, NULL), WOLFSSL_SUCCESS);
++    ExpectIntEQ(status, CERT_GOOD);
++
++    /* Request serial 01:02:03 (3 bytes) shares the 01:02 prefix of the
++     * response serial.
++     * The lookup must not bind the good response to this longer and
++     * differing serial. */
++    requestedStatus.serial[0] = 0x01;
++    requestedStatus.serial[1] = 0x02;
++    requestedStatus.serial[2] = 0x03;
++    requestedStatus.serialSz  = 3;
++    status = -1;
++    ExpectIntEQ(wolfSSL_OCSP_resp_find_status(&response, &requestedId, &status,
++                    NULL, NULL, NULL, NULL), WOLFSSL_FAILURE);
++#endif
++    return EXPECT_RESULT();
++}
++
+ #if defined(HAVE_OCSP) && defined(WOLFSSL_CERT_SETUP_CB) && \
+     defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && !defined(NO_RSA) && \
+     (defined(HAVE_CERTIFICATE_STATUS_REQUEST) || \
+diff --git a/tests/api/test_ocsp.h b/tests/api/test_ocsp.h
+index 6df114b87..2ad56ce55 100644
+--- a/tests/api/test_ocsp.h
++++ b/tests/api/test_ocsp.h
+@@ -24,6 +24,7 @@
+ 
+ int test_ocsp_certid_enc_dec(void);
+ int test_ocsp_certid_dup(void);
++int test_ocsp_resp_find_status_serial_prefix(void);
+ int test_ocsp_status_callback(void);
+ int test_ocsp_basic_verify(void);
+ int test_ocsp_response_parsing(void);
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 295029246c..094bf8d78b 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -15,6 +15,8 @@ RPROVIDES:${PN} = "cyassl"
 SRC_URI = " \
     git://github.com/wolfSSL/wolfssl.git;protocol=https;branch=master;tag=v${PV}-stable \
     file://run-ptest \
+    file://CVE-2026-10098-1.patch \
+    file://CVE-2026-10098-2.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 22/33] wolfssl: patch CVE-2026-10512
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (19 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 21/33] wolfssl: patch CVE-2026-10098 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 23/33] wolfssl: ignore CVE-2026-12340 ankur.tyagi85
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-10512

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-10512.patch        | 182 ++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   1 +
 2 files changed, 183 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10512.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10512.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10512.patch
new file mode 100644
index 0000000000..74288c28f9
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-10512.patch
@@ -0,0 +1,182 @@
+From 8c3f7b9c7f7efb9e8539c2d98fe52e116f3402eb Mon Sep 17 00:00:00 2001
+From: Sean Parkinson <sean@wolfssl.com>
+Date: Wed, 27 May 2026 12:16:06 +1000
+Subject: [PATCH] X25519 x64 ASM: fix full reduction
+
+The last add was overflowing into the top bit.
+Must mask the last word to clear top bit.
+
+Add test vectors from Wycheproof.
+
+(cherry picked from commit 14b55a0bc42c4f2d2fa0a06af53a603ed619c9b0)
+
+CVE: CVE-2026-10512
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/14b55a0bc42c4f2d2fa0a06af53a603ed619c9b0]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ tests/api/test_curve25519.c   | 93 +++++++++++++++++++++++++++++++++++
+ tests/api/test_curve25519.h   |  2 +
+ wolfcrypt/src/fe_x25519_asm.S |  4 ++
+ 3 files changed, 99 insertions(+)
+
+diff --git a/tests/api/test_curve25519.c b/tests/api/test_curve25519.c
+index 36cf643f2..36c8e58af 100644
+--- a/tests/api/test_curve25519.c
++++ b/tests/api/test_curve25519.c
+@@ -353,6 +353,99 @@ int test_wc_curve25519_shared_secret_ex(void)
+     return EXPECT_RESULT();
+ } /* END test_wc_curve25519_shared_secret_ex */
+ 
++/*
++ * Known-answer tests for wc_curve25519_shared_secret_ex.
++ *
++ * Both vectors share one private scalar and produce a shared secret that is a
++ * small canonical value (9 and 16, little-endian). Because the result is close
++ * to a multiple of the field prime, these exercise the final modular reduction
++ * of the X25519 computation: a result that was only reduced mod 2^256 (or left
++ * in [p, 2^255)) instead of fully reduced mod 2^255-19 would not match.
++ * All values are 32-byte little-endian encodings per RFC 7748.
++ */
++int test_wc_curve25519_shared_secret_ex_kat(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT)
++    /* Private scalar shared by both vectors. */
++    static const byte kPriv[CURVE25519_KEYSIZE] = {
++        0x60, 0xa3, 0xa4, 0xf1, 0x30, 0xb9, 0x8a, 0x5b,
++        0xe4, 0xb1, 0xce, 0xdb, 0x7c, 0xb8, 0x55, 0x84,
++        0xa3, 0x52, 0x0e, 0x14, 0x2d, 0x47, 0x4d, 0xc9,
++        0xcc, 0xb9, 0x09, 0xa0, 0x73, 0xa9, 0x76, 0x7f
++    };
++    /* Vector 1 public value, expected shared secret == 9. */
++    static const byte kPub1[CURVE25519_KEYSIZE] = {
++        0x3b, 0x18, 0xdf, 0x1e, 0x50, 0xb8, 0x99, 0xeb,
++        0xd5, 0x88, 0xc3, 0x16, 0x1c, 0xbd, 0x3b, 0xf9,
++        0x8e, 0xbc, 0xc2, 0xc1, 0xf7, 0xdf, 0x53, 0xb8,
++        0x11, 0xbd, 0x0e, 0x91, 0xb4, 0xd5, 0x15, 0x3d
++    };
++    static const byte kExpected1[CURVE25519_KEYSIZE] = {
++        0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++    };
++    /* Vector 2 public value, expected shared secret == 16. */
++    static const byte kPub2[CURVE25519_KEYSIZE] = {
++        0xca, 0xb6, 0xf9, 0xe7, 0xd8, 0xce, 0x00, 0xdf,
++        0xce, 0xa9, 0xbb, 0xd8, 0xf0, 0x69, 0xef, 0x7f,
++        0xb2, 0xac, 0x50, 0x4a, 0xbf, 0x83, 0xb8, 0x7d,
++        0xb6, 0x01, 0xb5, 0xae, 0x0a, 0x7f, 0x76, 0x15
++    };
++    static const byte kExpected2[CURVE25519_KEYSIZE] = {
++        0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
++    };
++    /* Table-driven so both vectors run through the identical code path. */
++    struct {
++        const byte* pub;
++        const byte* expected;
++    } vec[2];
++    curve25519_key private_key;
++    curve25519_key public_key;
++    WC_RNG         rng;
++    byte           out[CURVE25519_KEYSIZE];
++    word32         outLen;
++    int i;
++
++    vec[0].pub = kPub1; vec[0].expected = kExpected1;
++    vec[1].pub = kPub2; vec[1].expected = kExpected2;
++
++    XMEMSET(&rng, 0, sizeof(WC_RNG));
++    ExpectIntEQ(wc_InitRng(&rng), 0);
++
++    for (i = 0; i < 2; i++) {
++        XMEMSET(&private_key, 0, sizeof(private_key));
++        XMEMSET(&public_key, 0, sizeof(public_key));
++        ExpectIntEQ(wc_curve25519_init(&private_key), 0);
++        ExpectIntEQ(wc_curve25519_init(&public_key), 0);
++    #ifdef WOLFSSL_CURVE25519_BLINDING
++        ExpectIntEQ(wc_curve25519_set_rng(&private_key, &rng), 0);
++    #endif
++        ExpectIntEQ(wc_curve25519_import_private_ex(kPriv, sizeof(kPriv),
++            &private_key, EC25519_LITTLE_ENDIAN), 0);
++        ExpectIntEQ(wc_curve25519_import_public_ex(vec[i].pub,
++            CURVE25519_KEYSIZE, &public_key, EC25519_LITTLE_ENDIAN), 0);
++
++        outLen = sizeof(out);
++        ExpectIntEQ(wc_curve25519_shared_secret_ex(&private_key, &public_key,
++            out, &outLen, EC25519_LITTLE_ENDIAN), 0);
++        ExpectIntEQ(outLen, CURVE25519_KEYSIZE);
++        ExpectIntEQ(XMEMCMP(out, vec[i].expected, CURVE25519_KEYSIZE), 0);
++
++        wc_curve25519_free(&private_key);
++        wc_curve25519_free(&public_key);
++    }
++
++    DoExpectIntEQ(wc_FreeRng(&rng), 0);
++#endif
++    return EXPECT_RESULT();
++} /* END test_wc_curve25519_shared_secret_ex_kat */
++
+ /*
+  * Testing wc_curve25519_make_pub
+  */
+diff --git a/tests/api/test_curve25519.h b/tests/api/test_curve25519.h
+index 0e0e65287..770b509af 100644
+--- a/tests/api/test_curve25519.h
++++ b/tests/api/test_curve25519.h
+@@ -30,6 +30,7 @@ int test_wc_curve25519_export_key_raw(void);
+ int test_wc_curve25519_export_key_raw_ex(void);
+ int test_wc_curve25519_make_key(void);
+ int test_wc_curve25519_shared_secret_ex(void);
++int test_wc_curve25519_shared_secret_ex_kat(void);
+ int test_wc_curve25519_make_pub(void);
+ int test_wc_curve25519_export_public_ex(void);
+ int test_wc_curve25519_export_private_raw_ex(void);
+@@ -43,6 +44,7 @@ int test_wc_curve25519_import_private(void);
+     TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_key_raw_ex),       \
+     TEST_DECL_GROUP("curve25519", test_wc_curve25519_make_key),                \
+     TEST_DECL_GROUP("curve25519", test_wc_curve25519_shared_secret_ex),        \
++    TEST_DECL_GROUP("curve25519", test_wc_curve25519_shared_secret_ex_kat),    \
+     TEST_DECL_GROUP("curve25519", test_wc_curve25519_make_pub),                \
+     TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_public_ex),        \
+     TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_private_raw_ex),   \
+diff --git a/wolfcrypt/src/fe_x25519_asm.S b/wolfcrypt/src/fe_x25519_asm.S
+index f4cdf343c..5abe4cd5e 100644
+--- a/wolfcrypt/src/fe_x25519_asm.S
++++ b/wolfcrypt/src/fe_x25519_asm.S
+@@ -4639,6 +4639,7 @@ L_curve25519_base_x64_3:
+         adcq	$0x00, %r8
+         adcq	$0x00, %r9
+         adcq	$0x00, %r10
++        andq	%rax, %r10
+         # Store
+         movq	%rcx, (%rdi)
+         movq	%r8, 8(%rdi)
+@@ -7054,6 +7055,7 @@ L_curve25519_x64_3:
+         adcq	$0x00, %r9
+         adcq	$0x00, %r10
+         adcq	$0x00, %r11
++        andq	%rax, %r11
+         # Store
+         movq	%rcx, (%rdi)
+         movq	%r9, 8(%rdi)
+@@ -15107,6 +15109,7 @@ L_curve25519_base_avx2_last_3:
+         adcq	$0x00, %r9
+         adcq	$0x00, %r10
+         adcq	$0x00, %r11
++        andq	%rcx, %r11
+         # Store
+         movq	%r8, (%rdi)
+         movq	%r9, 8(%rdi)
+@@ -17116,6 +17119,7 @@ L_curve25519_avx2_last_3:
+         adcq	$0x00, %r10
+         adcq	$0x00, %r11
+         adcq	$0x00, %r12
++        andq	%rcx, %r12
+         # Store
+         movq	%r9, (%rdi)
+         movq	%r10, 8(%rdi)
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 094bf8d78b..4f6ae56567 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -17,6 +17,7 @@ SRC_URI = " \
     file://run-ptest \
     file://CVE-2026-10098-1.patch \
     file://CVE-2026-10098-2.patch \
+    file://CVE-2026-10512.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 23/33] wolfssl: ignore CVE-2026-12340
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (20 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 22/33] wolfssl: patch CVE-2026-10512 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 24/33] wolfssl: patch CVE-2026-55958 ankur.tyagi85
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-12340

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb | 1 +
 1 file changed, 1 insertion(+)

diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 4f6ae56567..f69497a80c 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -74,3 +74,4 @@ CVE_STATUS[CVE-2026-5772] = "fixed-version: fixed in 5.9.1"
 CVE_STATUS[CVE-2026-5778] = "fixed-version: fixed in 5.9.1"
 CVE_STATUS[CVE-2023-6937] = "fixed-version: fixed since v5.6.6"
 CVE_STATUS[CVE-2024-5814] = "fixed-version: fixed since v5.7.2"
+CVE_STATUS[CVE-2026-12340] = "not-applicable-config: this only affects builds with SM2 support"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 24/33] wolfssl: patch CVE-2026-55958
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (21 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 23/33] wolfssl: ignore CVE-2026-12340 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 25/33] wolfssl: patch CVE-2026-6091 ankur.tyagi85
                   ` (8 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-55958

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-55958.patch        | 36 +++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |  1 +
 2 files changed, 37 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-55958.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-55958.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-55958.patch
new file mode 100644
index 0000000000..a1f77eb40f
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-55958.patch
@@ -0,0 +1,36 @@
+From ea7c289d463c506fe3eb856c5d128b7d0e1799b7 Mon Sep 17 00:00:00 2001
+From: Chris Conlon <chris@wolfssl.com>
+Date: Tue, 16 Jun 2026 13:58:52 -0600
+Subject: [PATCH] Renesas TSIP: skip XMEMCPY on MEMORY_E from
+ tsip_StoreMessage()
+
+(cherry picked from commit 6ebc379f313769ac49a84be0221c626162ffcfab)
+
+CVE: CVE-2026-55958
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/6ebc379f313769ac49a84be0221c626162ffcfab]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/port/Renesas/renesas_tsip_sha.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/wolfcrypt/src/port/Renesas/renesas_tsip_sha.c b/wolfcrypt/src/port/Renesas/renesas_tsip_sha.c
+index 0d5957744..d04072397 100644
+--- a/wolfcrypt/src/port/Renesas/renesas_tsip_sha.c
++++ b/wolfcrypt/src/port/Renesas/renesas_tsip_sha.c
+@@ -203,10 +203,11 @@ WOLFSSL_LOCAL int tsip_StoreMessage(struct WOLFSSL* ssl, const byte* data,
+             WOLFSSL_MSG("Capacity over error in tsip_StoreMessage");
+             ret = MEMORY_E;
+         }
+-
+-        XMEMCPY(bag->buff + bag->buffIdx, data, sz);
+-        bag->msgTypes[bag->msgIdx++] = *data;   /* store message type */
+-        bag->buffIdx += sz;
++        else {
++            XMEMCPY(bag->buff + bag->buffIdx, data, sz);
++            bag->msgTypes[bag->msgIdx++] = *data;   /* store message type */
++            bag->buffIdx += sz;
++        }
+     }
+ 
+     WOLFSSL_LEAVE("tsip_StoreMessage", ret);
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index f69497a80c..e2bb53a646 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -18,6 +18,7 @@ SRC_URI = " \
     file://CVE-2026-10098-1.patch \
     file://CVE-2026-10098-2.patch \
     file://CVE-2026-10512.patch \
+    file://CVE-2026-55958.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 25/33] wolfssl: patch CVE-2026-6091
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (22 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 24/33] wolfssl: patch CVE-2026-55958 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 26/33] wolfssl: patch CVE-2026-6092 ankur.tyagi85
                   ` (7 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6091

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6091-1.patch       | 295 ++++++++++++++++++
 .../wolfssl/files/CVE-2026-6091-2.patch       |  30 ++
 .../wolfssl/files/CVE-2026-6091-3.patch       |  36 +++
 .../wolfssl/wolfssl_5.9.1.bb                  |   3 +
 4 files changed, 364 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-1.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-2.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-3.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-1.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-1.patch
new file mode 100644
index 0000000000..644797266e
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-1.patch
@@ -0,0 +1,295 @@
+From 54bce5dd1dce8839ea64e0bddebe4c6f8fd2cc6c Mon Sep 17 00:00:00 2001
+From: Eric Blankenhorn <eric@wolfssl.com>
+Date: Wed, 8 Apr 2026 16:27:07 -0500
+Subject: [PATCH] Fix partial chain verification
+
+(cherry picked from commit a6fd25b94e0c03c1be265a4454390d7225e81129)
+
+CVE: CVE-2026-6091
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/a6fd25b94e0c03c1be265a4454390d7225e81129]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/x509_str.c                 |  90 ++++++++++++++++++++++-
+ tests/api/test_ossl_x509_str.c | 127 +++++++++++++++++++++++++++++++++
+ 2 files changed, 216 insertions(+), 1 deletion(-)
+
+diff --git a/src/x509_str.c b/src/x509_str.c
+index 90113caed..01e975198 100644
+--- a/src/x509_str.c
++++ b/src/x509_str.c
+@@ -552,6 +552,53 @@ static int X509VerifyCertSetupRetry(WOLFSSL_X509_STORE_CTX* ctx,
+     return ret;
+ }
+ 
++/* Returns 1 if cur and x509 have identical DER encodings, 0 otherwise. */
++static int X509DerEquals(WOLFSSL_X509* cur, WOLFSSL_X509* x509)
++{
++    if (cur == NULL || cur->derCert == NULL ||
++        x509 == NULL || x509->derCert == NULL) {
++        return 0;
++    }
++    if (cur->derCert->length != x509->derCert->length)
++        return 0;
++    return XMEMCMP(cur->derCert->buffer, x509->derCert->buffer,
++                   x509->derCert->length) == 0;
++}
++
++/* Returns 1 if x509's DER matches an entry in either origTrustedSk (an
++ * immutable snapshot of the caller's trusted set captured before any
++ * intermediates were injected for this verification call) or in
++ * store->trusted.  Returns 0 otherwise.  Used by the
++ * X509_V_FLAG_PARTIAL_CHAIN fallback to confirm that a chain actually
++ * terminates at a caller-trusted certificate. */
++static int X509StoreCertIsTrusted(WOLFSSL_X509_STORE* store,
++        WOLFSSL_X509* x509, WOLF_STACK_OF(WOLFSSL_X509)* origTrustedSk)
++{
++    int i;
++    int n;
++
++    if (x509 == NULL || x509->derCert == NULL)
++        return 0;
++
++    if (origTrustedSk != NULL) {
++        n = wolfSSL_sk_X509_num(origTrustedSk);
++        for (i = 0; i < n; i++) {
++            if (X509DerEquals(wolfSSL_sk_X509_value(origTrustedSk, i), x509))
++                return 1;
++        }
++    }
++
++    if (store != NULL && store->trusted != NULL) {
++        n = wolfSSL_sk_X509_num(store->trusted);
++        for (i = 0; i < n; i++) {
++            if (X509DerEquals(wolfSSL_sk_X509_value(store->trusted, i), x509))
++                return 1;
++        }
++    }
++
++    return 0;
++}
++
+ /* Verifies certificate chain using WOLFSSL_X509_STORE_CTX
+  * returns 1 on success or <= 0 on failure.
+  */
+@@ -570,6 +617,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
+     WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL;
+     WOLF_STACK_OF(WOLFSSL_X509)* certsToUse = NULL;
+     WOLF_STACK_OF(WOLFSSL_X509)* failedCerts = NULL;
++    WOLF_STACK_OF(WOLFSSL_X509)* origTrustedSk = NULL;
+     WOLFSSL_ENTER("wolfSSL_X509_verify_cert");
+ 
+     if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL
+@@ -586,9 +634,37 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
+     if (certs == NULL &&
+         wolfSSL_sk_X509_num(ctx->ctxIntermediates) > 0) {
+         certsToUse = wolfSSL_sk_X509_new_null();
++        if (certsToUse == NULL) {
++            ret = WOLFSSL_FAILURE;
++            goto exit;
++        }
+         ret = addAllButSelfSigned(certsToUse, ctx->ctxIntermediates, NULL);
++        /* certsToUse holds only injected intermediates, none are trusted, so
++         * leave origTrustedSk NULL (empty snapshot). */
++        certs = certsToUse;
+     }
+     else {
++        /* Snapshot the caller-trusted entries before injecting the
++         * caller-supplied untrusted intermediates.  Only the entries already
++         * present count as trusted for the partial-chain check below, and
++         * we need a stable reference because X509VerifyCertSetupRetry may
++         * remove nodes from `certs` during chain building. */
++        if (certs != NULL && wolfSSL_sk_X509_num(certs) > 0) {
++            int j;
++            int n = wolfSSL_sk_X509_num(certs);
++            origTrustedSk = wolfSSL_sk_X509_new_null();
++            if (origTrustedSk == NULL) {
++                ret = WOLFSSL_FAILURE;
++                goto exit;
++            }
++            for (j = 0; j < n; j++) {
++                if (wolfSSL_sk_X509_push(origTrustedSk,
++                        wolfSSL_sk_X509_value(certs, j)) <= 0) {
++                    ret = WOLFSSL_FAILURE;
++                    goto exit;
++                }
++            }
++        }
+         /* Add the intermediates provided on init to the list of untrusted
+          * intermediates to be used */
+         ret = addAllButSelfSigned(certs, ctx->ctxIntermediates, &numInterAdd);
+@@ -677,9 +753,17 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
+              * a trusted CA in the CM */
+             ret = X509StoreVerifyCert(ctx);
+             if (ret != WOLFSSL_SUCCESS) {
++                /* WOLFSSL_PARTIAL_CHAIN may only terminate the chain at a
++                 * certificate the caller actually trusts.  The previous
++                 * "added == 1" guard merely confirmed that some untrusted
++                 * intermediate had been temporarily loaded into the
++                 * CertManager during chain building, which would accept
++                 * chains that never reach a trust anchor.  Verify that
++                 * ctx->current_cert is itself in the original trust set. */
+                 if (((ctx->flags & WOLFSSL_PARTIAL_CHAIN) ||
+                      (ctx->store->param->flags & WOLFSSL_PARTIAL_CHAIN)) &&
+-                    (added == 1)) {
++                    X509StoreCertIsTrusted(ctx->store, ctx->current_cert,
++                        origTrustedSk)) {
+                     wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
+                     ret = WOLFSSL_SUCCESS;
+                 } else {
+@@ -749,6 +833,10 @@ exit:
+     if (certsToUse != NULL) {
+         wolfSSL_sk_X509_free(certsToUse);
+     }
++    if (origTrustedSk != NULL) {
++        /* Shallow free: only the snapshot's stack nodes, not the X509s. */
++        wolfSSL_sk_X509_free(origTrustedSk);
++    }
+ 
+     /* Enforce hostname / IP verification from X509_VERIFY_PARAM if set.
+      * Always check against the leaf (end-entity) certificate, captured in
+diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c
+index 99b82877c..01ed9edfb 100644
+--- a/tests/api/test_ossl_x509_str.c
++++ b/tests/api/test_ossl_x509_str.c
+@@ -785,6 +785,127 @@ static int test_wolfSSL_X509_STORE_CTX_ex11(X509_STORE_test_data *testData)
+     return EXPECT_RESULT();
+ }
+ 
++static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_neg(
++    X509_STORE_test_data *testData)
++{
++    EXPECT_DECLS;
++    X509_STORE* store = NULL;
++    X509_STORE_CTX* ctx = NULL;
++    STACK_OF(X509)* untrusted = NULL;
++
++    /* Negative partial-chain test: with X509_V_FLAG_PARTIAL_CHAIN set, the
++     * intermediates are supplied ONLY as untrusted (passed through the
++     * X509_STORE_CTX_init "chain" argument and never added to the store).
++     * No certificate in the chain is in the store, so verification must
++     * fail.  Pre-fix, wolfSSL_X509_verify_cert would incorrectly accept
++     * this chain because its partial-chain fallback only checked that some
++     * intermediate had been temporarily loaded into the CertManager, not
++     * that any chain certificate was actually trusted. */
++    ExpectNotNull(store = X509_STORE_new());
++    /* Intentionally do NOT add x509CaInt, x509CaInt2, or x509Ca. */
++    ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
++
++    ExpectNotNull(untrusted = sk_X509_new_null());
++    ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt2), 0);
++    ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt), 0);
++
++    ExpectNotNull(ctx = X509_STORE_CTX_new());
++    ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, untrusted),
++        1);
++    /* Must NOT verify: partial-chain does not relax the trust requirement. */
++    ExpectIntNE(X509_verify_cert(ctx), 1);
++    /* Verify the failure is specifically due to missing trust anchor, not
++     * some unrelated error. */
++    ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
++        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
++
++    X509_STORE_CTX_free(ctx);
++    X509_STORE_free(store);
++    sk_X509_free(untrusted);
++    return EXPECT_RESULT();
++}
++
++static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_mixed(
++    X509_STORE_test_data *testData)
++{
++    EXPECT_DECLS;
++    X509_STORE* store = NULL;
++    X509_STORE_CTX* ctx = NULL;
++    STACK_OF(X509)* untrusted = NULL;
++
++    /* Mixed trusted-store + untrusted-chain partial-chain test: the store
++     * trusts an intermediate (x509CaInt2, the leaf's direct issuer), while
++     * an additional intermediate (x509CaInt) is supplied only as untrusted
++     * via the chain argument.  With X509_V_FLAG_PARTIAL_CHAIN, verification
++     * must succeed by terminating at the trusted intermediate.  This test
++     * exercises the snapshot-based trust check in X509StoreCertIsTrusted:
++     * the untrusted intermediate injected during verification must not be
++     * treated as a trust anchor, but the intermediate already in the store
++     * must be. */
++    ExpectNotNull(store = X509_STORE_new());
++    ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1);
++    ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
++
++    ExpectNotNull(untrusted = sk_X509_new_null());
++    ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt), 0);
++
++    ExpectNotNull(ctx = X509_STORE_CTX_new());
++    ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, untrusted),
++        1);
++    /* Must verify: chain terminates at trusted intermediate in the store. */
++    ExpectIntEQ(X509_verify_cert(ctx), 1);
++
++    X509_STORE_CTX_free(ctx);
++    X509_STORE_free(store);
++    sk_X509_free(untrusted);
++    return EXPECT_RESULT();
++}
++
++static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_untrusted_terminal(
++    X509_STORE_test_data *testData)
++{
++    EXPECT_DECLS;
++    X509_STORE* store = NULL;
++    X509_STORE_CTX* ctx = NULL;
++    STACK_OF(X509)* untrusted = NULL;
++
++    /* Partial-chain boundary test: the store trusts a CA (x509Ca) that is
++     * NOT reachable from the leaf given the supplied untrusted intermediates,
++     * and an untrusted intermediate (x509CaInt2) IS the terminal of the
++     * (truncated) chain.  With X509_V_FLAG_PARTIAL_CHAIN set, verification
++     * must FAIL because the chain terminates at an untrusted certificate.
++     *
++     * This test specifically targets the snapshot-based trust check in
++     * X509StoreCertIsTrusted.  Before addAllButSelfSigned injects
++     * x509CaInt2, origTrustedSk is snapshotted from the caller-trusted set
++     * and contains only x509Ca.  When the chain terminates at x509CaInt2,
++     * the trust check consults origTrustedSk (not the mutated working
++     * stack) and correctly finds no match.  A regression that consulted
++     * the post-injection working stack instead of the snapshot would
++     * incorrectly mark x509CaInt2 as trusted and cause verification to
++     * succeed. */
++    ExpectNotNull(store = X509_STORE_new());
++    ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1);
++    ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1);
++
++    /* Only x509CaInt2 supplied as untrusted; x509CaInt is intentionally
++     * withheld so the chain cannot actually reach the trusted x509Ca. */
++    ExpectNotNull(untrusted = sk_X509_new_null());
++    ExpectIntGT(sk_X509_push(untrusted, testData->x509CaInt2), 0);
++
++    ExpectNotNull(ctx = X509_STORE_CTX_new());
++    ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, untrusted),
++        1);
++    /* Must NOT verify: the chain terminal (x509CaInt2) is not in the
++     * original trust set, even though the store is non-empty. */
++    ExpectIntNE(X509_verify_cert(ctx), 1);
++
++    X509_STORE_CTX_free(ctx);
++    X509_STORE_free(store);
++    sk_X509_free(untrusted);
++    return EXPECT_RESULT();
++}
++
+ #ifdef HAVE_ECC
+ static int test_wolfSSL_X509_STORE_CTX_ex12(void)
+ {
+@@ -870,6 +991,12 @@ int test_wolfSSL_X509_STORE_CTX_ex(void)
+     ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex9(&testData), 1);
+     ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex10(&testData), 1);
+     ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex11(&testData), 1);
++    ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex_partial_chain_neg(&testData), 1);
++    ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex_partial_chain_mixed(&testData),
++        1);
++    ExpectIntEQ(
++        test_wolfSSL_X509_STORE_CTX_ex_partial_chain_untrusted_terminal(
++            &testData), 1);
+ #ifdef HAVE_ECC
+     ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex12(), 1);
+ #endif
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-2.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-2.patch
new file mode 100644
index 0000000000..373f942496
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-2.patch
@@ -0,0 +1,30 @@
+From 62e57461f512849af4f466f77594085c90ffad73 Mon Sep 17 00:00:00 2001
+From: Eric Blankenhorn <eric@wolfssl.com>
+Date: Tue, 14 Apr 2026 07:58:43 -0500
+Subject: [PATCH] Fix from review
+
+(cherry picked from commit c873f3f77da8273e160612468f08892b2ba0ed99)
+
+CVE: CVE-2026-6091
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/c873f3f77da8273e160612468f08892b2ba0ed99]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/x509_str.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/x509_str.c b/src/x509_str.c
+index 01e975198..67e3fcae6 100644
+--- a/src/x509_str.c
++++ b/src/x509_str.c
+@@ -765,6 +765,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
+                     X509StoreCertIsTrusted(ctx->store, ctx->current_cert,
+                         origTrustedSk)) {
+                     wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
++                    /* Clear error set by the failed X509StoreVerifyCert
++                     * attempt; the partial-chain fallback accepted the
++                     * chain at a caller-trusted certificate. */
++                    ctx->error = 0;
+                     ret = WOLFSSL_SUCCESS;
+                 } else {
+                     X509VerifyCertSetupRetry(ctx, certs, failedCerts,
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-3.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-3.patch
new file mode 100644
index 0000000000..418e45fc13
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6091-3.patch
@@ -0,0 +1,36 @@
+From 13c4a12c9904a2e50d1729d8a6899f111f3bcd2a Mon Sep 17 00:00:00 2001
+From: Eric Blankenhorn <eric@wolfssl.com>
+Date: Tue, 14 Apr 2026 07:41:30 -0500
+Subject: [PATCH] Fix from review
+
+(cherry picked from commit 2b503dae543d09c63a08b1e24238e0e9ce1ac6c5)
+
+CVE: CVE-2026-6091
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/2b503dae543d09c63a08b1e24238e0e9ce1ac6c5]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ tests/api/test_ossl_x509_str.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c
+index 01ed9edfb..14f3538a4 100644
+--- a/tests/api/test_ossl_x509_str.c
++++ b/tests/api/test_ossl_x509_str.c
+@@ -854,6 +854,7 @@ static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_mixed(
+         1);
+     /* Must verify: chain terminates at trusted intermediate in the store. */
+     ExpectIntEQ(X509_verify_cert(ctx), 1);
++    ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_OK);
+ 
+     X509_STORE_CTX_free(ctx);
+     X509_STORE_free(store);
+@@ -899,6 +900,8 @@ static int test_wolfSSL_X509_STORE_CTX_ex_partial_chain_untrusted_terminal(
+     /* Must NOT verify: the chain terminal (x509CaInt2) is not in the
+      * original trust set, even though the store is non-empty. */
+     ExpectIntNE(X509_verify_cert(ctx), 1);
++    ExpectIntEQ(X509_STORE_CTX_get_error(ctx),
++        X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY);
+ 
+     X509_STORE_CTX_free(ctx);
+     X509_STORE_free(store);
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index e2bb53a646..139d73c572 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -19,6 +19,9 @@ SRC_URI = " \
     file://CVE-2026-10098-2.patch \
     file://CVE-2026-10512.patch \
     file://CVE-2026-55958.patch \
+    file://CVE-2026-6091-1.patch \
+    file://CVE-2026-6091-2.patch \
+    file://CVE-2026-6091-3.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 26/33] wolfssl: patch CVE-2026-6092
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (23 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 25/33] wolfssl: patch CVE-2026-6091 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 27/33] wolfssl: patch CVE-2026-6094 ankur.tyagi85
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6092

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6092.patch         | 163 ++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   1 +
 2 files changed, 164 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6092.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6092.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6092.patch
new file mode 100644
index 0000000000..80868d255e
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6092.patch
@@ -0,0 +1,163 @@
+From 5e2fa43aed59a2524c33a443c93445882519677b Mon Sep 17 00:00:00 2001
+From: Eric Blankenhorn <eric@wolfssl.com>
+Date: Wed, 8 Apr 2026 15:06:11 -0500
+Subject: [PATCH] Fix ETM on resumption
+
+(cherry picked from commit af5369636a938faf4a79d1f550d3b206c51fafec)
+
+CVE: CVE-2026-6092
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/af5369636a938faf4a79d1f550d3b206c51fafec]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/internal.c       | 20 +++++++----
+ tests/api/test_tls.c | 83 ++++++++++++++++++++++++++++++++++++++++++++
+ tests/api/test_tls.h |  2 ++
+ 3 files changed, 99 insertions(+), 6 deletions(-)
+
+diff --git a/src/internal.c b/src/internal.c
+index ad1587e0f..267c75a5d 100644
+--- a/src/internal.c
++++ b/src/internal.c
+@@ -38436,13 +38436,21 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
+ 
+ #if defined(HAVE_TLS_EXTENSIONS) && defined(HAVE_ENCRYPT_THEN_MAC) && \
+     !defined(WOLFSSL_AEAD_ONLY)
+-            if (ssl->options.encThenMac && ssl->specs.cipher_type == block) {
+-                ret = TLSX_EncryptThenMac_Respond(ssl);
+-                if (ret != 0)
+-                    goto out;
++            /* Only respond to ETM here when resumption actually succeeded;
++             * HandleTlsResumption populates ssl->specs via SetCipherSpecs only
++             * on the success path. If resumption failed, resuming has been
++             * cleared and ssl->specs.cipher_type is still zero-initialized,
++             * so we must defer the ETM decision until after MatchSuite. */
++            if (ssl->options.resuming) {
++                if (ssl->options.encThenMac &&
++                                          ssl->specs.cipher_type == block) {
++                    ret = TLSX_EncryptThenMac_Respond(ssl);
++                    if (ret != 0)
++                        goto out;
++                }
++                else
++                    ssl->options.encThenMac = 0;
+             }
+-            else
+-                ssl->options.encThenMac = 0;
+ #endif
+             if (ssl->options.clientState == CLIENT_KEYEXCHANGE_COMPLETE) {
+                 WOLFSSL_LEAVE("DoClientHello", ret);
+diff --git a/tests/api/test_tls.c b/tests/api/test_tls.c
+index 565006171..f6cbb6d38 100644
+--- a/tests/api/test_tls.c
++++ b/tests/api/test_tls.c
+@@ -730,6 +730,89 @@ int test_tls12_no_null_compression(void)
+  * uppercase names like "SECP384R1" do not match the lowercase "secp384r1"
+  * entry; they fall through to the wolfCrypt ECC look-up which uses
+  * XSTRCASECMP. */
++/* Regression test for the encrypt-then-MAC silent-disable bug.
++ *
++ * Before the fix, when a client sent a 32-byte session ID in its ClientHello
++ * (so the server set ssl->options.resuming = 1) but the server's session
++ * cache did not contain that session, DoClientHello would run an
++ * encrypt_then_mac decision *before* MatchSuite/SetCipherSpecs had populated
++ * ssl->specs.cipher_type.  Because cipher_type was zero-initialized
++ * (== stream, not block), the ETM block cleared encThenMac to 0, and the
++ * post-MatchSuite block could not re-enable it.  The connection then
++ * silently negotiated MAC-then-encrypt instead of encrypt-then-MAC.
++ *
++ * This test forces a stale-resumption ClientHello against a server with an
++ * empty session cache, using a CBC-mode cipher suite, and asserts that the
++ * server still negotiates encrypt-then-MAC. */
++int test_tls12_etm_failed_resumption(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
++    !defined(WOLFSSL_NO_TLS12) && defined(HAVE_ENCRYPT_THEN_MAC) && \
++    !defined(WOLFSSL_AEAD_ONLY) && !defined(NO_RSA) && !defined(NO_AES) && \
++    defined(HAVE_AES_CBC) && !defined(NO_SHA256) && \
++    defined(HAVE_SESSION_TICKET) && defined(HAVE_ECC)
++    /* TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 — a CBC suite, where ETM applies. */
++    const char* cbcSuite = "ECDHE-RSA-AES128-SHA256";
++    WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
++    WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
++    WOLFSSL_SESSION *sess = NULL;
++    struct test_memio_ctx test_ctx;
++
++    /* First handshake: establish a session-ID-based session on the client.
++     * Disable TLS 1.2 session tickets on both sides so resumption uses the
++     * session ID path (not tickets), which is the path the bug lives on. */
++    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
++    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
++                    wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
++    ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cbcSuite), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cbcSuite), WOLFSSL_SUCCESS);
++    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
++    /* Sanity: the first handshake itself must use ETM. */
++    ExpectIntEQ(ssl_s->options.encThenMac, 1);
++    ExpectNotNull(sess = wolfSSL_get1_session(ssl_c));
++
++    wolfSSL_free(ssl_c); ssl_c = NULL;
++    wolfSSL_free(ssl_s); ssl_s = NULL;
++    wolfSSL_CTX_free(ctx_c); ctx_c = NULL;
++    wolfSSL_CTX_free(ctx_s); ctx_s = NULL;
++
++    /* Second handshake against a *fresh* server context (empty cache).  The
++     * client offers the saved session, so the server's ClientHello parser
++     * sets options.resuming = 1, but HandleTlsResumption then fails to find
++     * the session and clears resuming.  Pre-fix, ETM was silently dropped
++     * here. */
++    XMEMSET(&test_ctx, 0, sizeof(test_ctx));
++    ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
++                    wolfTLSv1_2_client_method, wolfTLSv1_2_server_method), 0);
++    /* The internal session cache is process-global, so the saved session is
++     * still findable via the cache.  Disable lookups on this server SSL
++     * directly so that HandleTlsResumption hits its "session lookup failed"
++     * path — exactly the scenario the bug fix targets. */
++    ssl_s->options.sessionCacheOff = 1;
++    ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_c), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_NoTicketTLSv12(ssl_s), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_c, cbcSuite), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_set_cipher_list(ssl_s, cbcSuite), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_set_session(ssl_c, sess), WOLFSSL_SUCCESS);
++    ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
++    /* The server should NOT have actually resumed (fresh ctx, empty cache). */
++    ExpectIntEQ(ssl_s->options.resuming, 0);
++    /* And — the regression check — encrypt-then-MAC must still be active. */
++    ExpectIntEQ(ssl_s->options.encThenMac, 1);
++    ExpectIntEQ(ssl_c->options.encThenMac, 1);
++
++    wolfSSL_SESSION_free(sess);
++    wolfSSL_free(ssl_c);
++    wolfSSL_free(ssl_s);
++    wolfSSL_CTX_free(ctx_c);
++    wolfSSL_CTX_free(ctx_s);
++#endif
++    return EXPECT_RESULT();
++}
++
+ int test_tls_set_curves_list_ecc_fallback(void)
+ {
+     EXPECT_DECLS;
+diff --git a/tests/api/test_tls.h b/tests/api/test_tls.h
+index 46d540434..9d28a599a 100644
+--- a/tests/api/test_tls.h
++++ b/tests/api/test_tls.h
+@@ -30,6 +30,7 @@ int test_tls13_curve_intersection(void);
+ int test_tls_certreq_order(void);
+ int test_tls12_bad_cv_sig_alg(void);
+ int test_tls12_no_null_compression(void);
++int test_tls12_etm_failed_resumption(void);
+ int test_tls_set_curves_list_ecc_fallback(void);
+ 
+ #define TEST_TLS_DECLS                                                         \
+@@ -41,6 +42,7 @@ int test_tls_set_curves_list_ecc_fallback(void);
+         TEST_DECL_GROUP("tls", test_tls_certreq_order),                        \
+         TEST_DECL_GROUP("tls", test_tls12_bad_cv_sig_alg),                     \
+         TEST_DECL_GROUP("tls", test_tls12_no_null_compression),                \
++        TEST_DECL_GROUP("tls", test_tls12_etm_failed_resumption),              \
+         TEST_DECL_GROUP("tls", test_tls_set_curves_list_ecc_fallback)
+ 
+ #endif /* TESTS_API_TEST_TLS_H */
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 139d73c572..ce3839e9a2 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -22,6 +22,7 @@ SRC_URI = " \
     file://CVE-2026-6091-1.patch \
     file://CVE-2026-6091-2.patch \
     file://CVE-2026-6091-3.patch \
+    file://CVE-2026-6092.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 27/33] wolfssl: patch CVE-2026-6094
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (24 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 26/33] wolfssl: patch CVE-2026-6092 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 28/33] wolfssl: patch CVE-2026-6291 ankur.tyagi85
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details
https://nvd.nist.gov/vuln/detail/cve-2026-6094

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6094-1.patch       | 32 ++++++++
 .../wolfssl/files/CVE-2026-6094-2.patch       | 35 +++++++++
 .../wolfssl/files/CVE-2026-6094-3.patch       | 39 ++++++++++
 .../wolfssl/files/CVE-2026-6094-4.patch       | 36 +++++++++
 .../wolfssl/files/CVE-2026-6094-5.patch       | 73 +++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |  5 ++
 6 files changed, 220 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-1.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-2.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-3.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-4.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-5.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-1.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-1.patch
new file mode 100644
index 0000000000..c9a7c1867e
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-1.patch
@@ -0,0 +1,32 @@
+From f162b7679bafacd5b9866d72400b1115f8fbc7b7 Mon Sep 17 00:00:00 2001
+From: Kareem <kareem@wolfssl.com>
+Date: Fri, 3 Apr 2026 16:05:44 -0700
+Subject: [PATCH] Ensure esd->signedAttribsCount contains the correct count in
+ case some are skipped by using the current idx rather than the total array
+ size.
+
+Thanks to Zou Dikai for the report.
+
+(cherry picked from commit 7f218574c4d30a8aa8c520c7023c3d017fc13b86)
+
+CVE: CVE-2026-6094
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/7f218574c4d30a8aa8c520c7023c3d017fc13b86]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/pkcs7.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c
+index 3f6649d0a..67803f84d 100644
+--- a/wolfcrypt/src/pkcs7.c
++++ b/wolfcrypt/src/pkcs7.c
+@@ -2253,7 +2253,7 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd,
+             idx++;
+         }
+ 
+-        esd->signedAttribsCount += cannedAttribsCount;
++        esd->signedAttribsCount += idx;
+         esd->signedAttribsSz += (word32)EncodeAttributes(
+             &esd->signedAttribs[atrIdx], (int)idx, cannedAttribs,
+             (int)cannedAttribsCount);
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-2.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-2.patch
new file mode 100644
index 0000000000..8df72e6f5b
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-2.patch
@@ -0,0 +1,35 @@
+From 6d7fe2926a18982278c53b4ec413fe7b2349a019 Mon Sep 17 00:00:00 2001
+From: Kareem <kareem@wolfssl.com>
+Date: Fri, 3 Apr 2026 16:06:35 -0700
+Subject: [PATCH] In wc_PKCS7_DecodeEnvelopedData, confirm
+ encryptedContentTotalSz does not exceed the total message size before using
+ it in the non-streaming case.
+
+Thanks to Zou Dikai for the report.
+
+(cherry picked from commit 1397268aa12e2cf3f80c3acfa9b6036b809c08ef)
+
+CVE: CVE-2026-6094
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/1397268aa12e2cf3f80c3acfa9b6036b809c08ef]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/pkcs7.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c
+index 67803f84d..43bcf3ee4 100644
+--- a/wolfcrypt/src/pkcs7.c
++++ b/wolfcrypt/src/pkcs7.c
+@@ -13231,6 +13231,11 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                 }
+                 wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap);
+             } else {
++                if ((idx + (word32)encryptedContentTotalSz) > pkiMsgSz) {
++                    ret = BUFFER_E;
++                    break;
++                }
++
+                 pkcs7->cachedEncryptedContentSz =
+                     (word32)encryptedContentTotalSz;
+                 pkcs7->totalEncryptedContentSz =
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-3.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-3.patch
new file mode 100644
index 0000000000..6e0d902c85
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-3.patch
@@ -0,0 +1,39 @@
+From c7f7a8ef00e6a7a33a623543507f8fa089f6037b Mon Sep 17 00:00:00 2001
+From: Kareem <kareem@wolfssl.com>
+Date: Fri, 3 Apr 2026 16:56:04 -0700
+Subject: [PATCH] Code review feedback
+
+(cherry picked from commit ebdcc03b718cd7175355097b1a3831a0eb4875b2)
+
+CVE: CVE-2026-6094
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/ebdcc03b718cd7175355097b1a3831a0eb4875b2]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/pkcs7.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c
+index 43bcf3ee4..50d33bdb8 100644
+--- a/wolfcrypt/src/pkcs7.c
++++ b/wolfcrypt/src/pkcs7.c
+@@ -2256,7 +2256,7 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd,
+         esd->signedAttribsCount += idx;
+         esd->signedAttribsSz += (word32)EncodeAttributes(
+             &esd->signedAttribs[atrIdx], (int)idx, cannedAttribs,
+-            (int)cannedAttribsCount);
++            (int)idx);
+         atrIdx += idx;
+     } else {
+         esd->signedAttribsCount = 0;
+@@ -13231,7 +13231,9 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                 }
+                 wc_PKCS7_DecryptContentFree(pkcs7, encOID, pkcs7->heap);
+             } else {
+-                if ((idx + (word32)encryptedContentTotalSz) > pkiMsgSz) {
++                word32 tmpSum;
++                if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentTotalSz, tmpSum) ||
++                    tmpSum > pkiMsgSz) {
+                     ret = BUFFER_E;
+                     break;
+                 }
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-4.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-4.patch
new file mode 100644
index 0000000000..3c49028ec4
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-4.patch
@@ -0,0 +1,36 @@
+From a9015491db03d415f766f47c139841249adce843 Mon Sep 17 00:00:00 2001
+From: Kareem <kareem@wolfssl.com>
+Date: Mon, 6 Apr 2026 11:58:12 -0700
+Subject: [PATCH] Fix unused variable error
+
+(cherry picked from commit 3e04475875a4942652fdf6794a01fdfd65801fdc)
+
+CVE: CVE-2026-6094
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/3e04475875a4942652fdf6794a01fdfd65801fdc]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/pkcs7.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c
+index 50d33bdb8..2cde73846 100644
+--- a/wolfcrypt/src/pkcs7.c
++++ b/wolfcrypt/src/pkcs7.c
+@@ -2197,7 +2197,6 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd,
+ #endif
+     word32 idx    = 0;
+     word32 atrIdx = 0;
+-    word32 cannedAttribsCount;
+ 
+     if (pkcs7 == NULL || esd == NULL || contentType == NULL ||
+         contentTypeOid == NULL || messageDigestOid == NULL ||
+@@ -2220,8 +2219,6 @@ static int wc_PKCS7_BuildSignedAttributes(wc_PKCS7* pkcs7, ESD* esd,
+             return timeSz;
+     #endif
+ 
+-        cannedAttribsCount = sizeof(cannedAttribs)/sizeof(PKCS7Attrib);
+-
+         XMEMSET(&cannedAttribs[idx], 0, sizeof(cannedAttribs[idx]));
+ 
+         if ((pkcs7->defaultSignedAttribs & WOLFSSL_CONTENT_TYPE_ATTRIBUTE) ||
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-5.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-5.patch
new file mode 100644
index 0000000000..a0dcd8ce72
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6094-5.patch
@@ -0,0 +1,73 @@
+From c27fbdecfd2f4a31acdc73229a5bc631184265f1 Mon Sep 17 00:00:00 2001
+From: Kareem <kareem@wolfssl.com>
+Date: Mon, 6 Apr 2026 16:41:32 -0700
+Subject: [PATCH] Add additional checks for encryptedContentSz exceeding
+ pkiMsgSz.
+
+(cherry picked from commit b3c2877a146e0c75715368ca5dfe2387bfc2cadf)
+
+CVE: CVE-2026-6094
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/b3c2877a146e0c75715368ca5dfe2387bfc2cadf]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/pkcs7.c | 38 ++++++++++++++++++++++++++------------
+ 1 file changed, 26 insertions(+), 12 deletions(-)
+
+diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c
+index 2cde73846..8df3a2430 100644
+--- a/wolfcrypt/src/pkcs7.c
++++ b/wolfcrypt/src/pkcs7.c
+@@ -14380,9 +14380,17 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+             }
+ 
+             if (ret == 0) {
+-                XMEMCPY(encryptedContent, &pkiMsg[idx],
++                word32 tmpSum;
++                if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentSz,
++                                        tmpSum) ||
++                    tmpSum > pkiMsgSz) {
++                    ret = BUFFER_E;
++                    break;
++                } else {
++                    XMEMCPY(encryptedContent, &pkiMsg[idx],
+                                                     (word32)encryptedContentSz);
+-                idx += (word32)encryptedContentSz;
++                    idx += (word32)encryptedContentSz;
++                }
+             }
+         #ifndef NO_PKCS7_STREAM
+             pkcs7->stream->bufferPt = encryptedContent;
+@@ -15316,16 +15324,22 @@ int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             }
+ 
+             if (ret == 0) {
+-                XMEMCPY(encryptedContent, &pkiMsg[idx],
+-                    (unsigned int)encryptedContentSz);
+-                idx += (word32)encryptedContentSz;
+-
+-                /* decrypt encryptedContent */
+-                ret = wc_PKCS7_DecryptContent(pkcs7, encOID,
+-                              pkcs7->encryptionKey, pkcs7->encryptionKeySz,
+-                              tmpIv, expBlockSz, NULL, 0, NULL, 0,
+-                              encryptedContent, encryptedContentSz,
+-                              encryptedContent, pkcs7->devId, pkcs7->heap);
++                word32 tmpSum;
++                if (!WC_SAFE_SUM_WORD32(idx, (word32)encryptedContentSz, tmpSum) ||
++                    tmpSum > pkiMsgSz) {
++                    ret = BUFFER_E;
++                } else {
++                    XMEMCPY(encryptedContent, &pkiMsg[idx],
++                        (unsigned int)encryptedContentSz);
++                    idx += (word32)encryptedContentSz;
++
++                    /* decrypt encryptedContent */
++                    ret = wc_PKCS7_DecryptContent(pkcs7, encOID,
++                                pkcs7->encryptionKey, pkcs7->encryptionKeySz,
++                                tmpIv, expBlockSz, NULL, 0, NULL, 0,
++                                encryptedContent, encryptedContentSz,
++                                encryptedContent, pkcs7->devId, pkcs7->heap);
++                }
+                 if (ret != 0) {
+                     XFREE(encryptedContent, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+                 }
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index ce3839e9a2..8802202114 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -23,6 +23,11 @@ SRC_URI = " \
     file://CVE-2026-6091-2.patch \
     file://CVE-2026-6091-3.patch \
     file://CVE-2026-6092.patch \
+    file://CVE-2026-6094-1.patch \
+    file://CVE-2026-6094-2.patch \
+    file://CVE-2026-6094-3.patch \
+    file://CVE-2026-6094-4.patch \
+    file://CVE-2026-6094-5.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 28/33] wolfssl: patch CVE-2026-6291
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (25 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 27/33] wolfssl: patch CVE-2026-6094 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 29/33] wolfssl: patch CVE-2026-6325 ankur.tyagi85
                   ` (4 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6291

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6291.patch         | 2948 +++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |    1 +
 2 files changed, 2949 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6291.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6291.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6291.patch
new file mode 100644
index 0000000000..dd41f9f15d
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6291.patch
@@ -0,0 +1,2948 @@
+From 3aab2df7436240515c608971ca9b899c37f93f47 Mon Sep 17 00:00:00 2001
+From: Sean Parkinson <sean@wolfssl.com>
+Date: Fri, 24 Apr 2026 10:13:43 +1000
+Subject: [PATCH] Merge pull request #10203 from Frauschi/pkcs7_fixes
+
+PKCS#7 fixes
+
+(cherry picked from commit 936f8e54230b11dee50e82bcc5a2247ea9d9c91c)
+
+CVE: CVE-2026-6291
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/936f8e54230b11dee50e82bcc5a2247ea9d9c91c]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ .wolfssl_known_macro_extras    |   1 +
+ src/ssl_p7p12.c                |  28 +-
+ tests/api.c                    | 707 +++++++++++++++++++++++++++++++++
+ tests/api/test_ossl_p7p12.c    | 454 +++++++++++++++++++++
+ tests/api/test_ossl_p7p12.h    |   4 +
+ tests/api/test_pkcs7.c         | 356 +++++++++++++++--
+ tests/api/test_pkcs7.h         |  25 +-
+ wolfcrypt/src/pkcs7.c          | 633 +++++++++++++++++++++++++++--
+ wolfssl/wolfcrypt/wc_encrypt.h |   3 +
+ 9 files changed, 2154 insertions(+), 57 deletions(-)
+
+diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras
+index ba5e47ef6..3e411ca86 100644
+--- a/.wolfssl_known_macro_extras
++++ b/.wolfssl_known_macro_extras
+@@ -825,6 +825,7 @@ WOLFSSL_NO_KCAPI_HMAC_SHA256
+ WOLFSSL_NO_KCAPI_HMAC_SHA384
+ WOLFSSL_NO_KCAPI_HMAC_SHA512
+ WOLFSSL_NO_KCAPI_SHA224
++WOLFSSL_NO_KTRI_ORACLE_WARNING
+ WOLFSSL_NO_OCSP_DATE_CHECK
+ WOLFSSL_NO_OCSP_ISSUER_CHAIN_CHECK
+ WOLFSSL_NO_OCSP_OPTIONAL_CERTS
+diff --git a/src/ssl_p7p12.c b/src/ssl_p7p12.c
+index ee48d700a..a07f018b2 100644
+--- a/src/ssl_p7p12.c
++++ b/src/ssl_p7p12.c
+@@ -269,24 +269,42 @@ WOLFSSL_STACK* wolfSSL_PKCS7_get0_signers(PKCS7* pkcs7, WOLFSSL_STACK* certs,
+     WOLFSSL_X509* x509 = NULL;
+     WOLFSSL_STACK* signers = NULL;
+     WOLFSSL_PKCS7* p7 = (WOLFSSL_PKCS7*)pkcs7;
++    byte* signerCert;
++    word32 signerCertSz;
+ 
+     if (p7 == NULL)
+         return NULL;
+ 
+-    /* Only PKCS#7 messages with a single cert that is the verifying certificate
+-     * is supported.
+-     */
+     if (flags & PKCS7_NOINTERN) {
+         WOLFSSL_MSG("PKCS7_NOINTERN flag not supported");
+         return NULL;
+     }
+ 
++    /* Prefer the certificate that actually verified the signature. Falling
++     * back to singleCert (cert[0]) would let an attacker that bundles a
++     * trusted cert ahead of their own attacker cert have the trusted cert
++     * reported as the signer even though it did not produce the signature.
++     *
++     * Copy the chosen pointer into a local before passing its address to
++     * wolfSSL_d2i_X509; d2i_X509 advances *in by the DER length, and if
++     * we handed it the address of the struct field directly it would
++     * permanently corrupt the field, producing a heap-OOB read on the
++     * next use (pointer advanced, singleCertSz unchanged). */
++    if (p7->pkcs7.verifyCert != NULL && p7->pkcs7.verifyCertSz > 0) {
++        signerCert   = p7->pkcs7.verifyCert;
++        signerCertSz = p7->pkcs7.verifyCertSz;
++    }
++    else {
++        signerCert   = p7->pkcs7.singleCert;
++        signerCertSz = p7->pkcs7.singleCertSz;
++    }
++
+     signers = wolfSSL_sk_X509_new_null();
+     if (signers == NULL)
+         return NULL;
+ 
+-    if (wolfSSL_d2i_X509(&x509, (const byte**)&p7->pkcs7.singleCert,
+-                         p7->pkcs7.singleCertSz) == NULL) {
++    if (wolfSSL_d2i_X509(&x509, (const byte**)&signerCert,
++                         signerCertSz) == NULL) {
+         wolfSSL_sk_X509_pop_free(signers, NULL);
+         return NULL;
+     }
+diff --git a/tests/api.c b/tests/api.c
+index ad5f84573..78fcf13ce 100644
+--- a/tests/api.c
++++ b/tests/api.c
+@@ -34990,6 +34990,706 @@ static int test_pkcs7_ori_oversized_oid(void)
+     return EXPECT_RESULT();
+ }
+ 
++/* ORI callback that flags if oriValueSz looks like an underflow (>= 0x80000000) */
++#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
++static int test_ori_underflow_cb(wc_PKCS7* pkcs7, byte* oriType,
++                                 word32 oriTypeSz, byte* oriValue,
++                                 word32 oriValueSz, byte* decryptedKey,
++                                 word32* decryptedKeySz, void* ctx)
++{
++    int* called = (int*)ctx;
++    (void)pkcs7; (void)oriType; (void)oriTypeSz;
++    (void)oriValue; (void)decryptedKey; (void)decryptedKeySz;
++    if (called != NULL)
++        *called = (int)oriValueSz;  /* record what we received */
++    return -1;
++}
++#endif
++
++/* Test: PKCS#7 ORI must reject when OID consumption exceeds the [4] implicit
++ * SEQUENCE length (integer underflow in oriValueSz computation).
++ *
++ * With implicit tagging, [4] CONSTRUCTED replaces the SEQUENCE tag, so
++ * wc_PKCS7_DecryptOri reads seqSz directly from the [4] length field.
++ * We set [4] length = 5 while the OID inside consumes 22 bytes
++ * (tag + length + 20 content), triggering oriValueSz = 5 - 22 = underflow.
++ *
++ * The buffer includes a dummy EncryptedContentInfo after the RecipientInfos
++ * so the total message is large enough for the PKCS7 streaming code (which
++ * requests the full remaining message before parsing the ORI). */
++static int test_pkcs7_ori_seqsz_underflow(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
++    wc_PKCS7* p7 = NULL;
++    byte out[256];
++    int cbCalled = 0;
++
++    /*
++     * Byte layout (all outer lengths match actual byte counts on wire):
++     *
++     * OID inside [4]: 06 14 <20 bytes>                  = 22 bytes
++     * [4] (declared len 5, actual content 22):
++     *   a4 05 <22 bytes>                                = 24 bytes on wire
++     * SET: 31 18 <24 bytes>                             = 26 bytes on wire
++     * version: 02 01 00                                 = 3 bytes
++     * EncryptedContentInfo (filler, never parsed):
++     *   30 0b { 06 09 <9 bytes OID> }                   = 13 bytes on wire
++     * EnvelopedData: 30 2a <3+26+13=42 bytes>           = 44 bytes on wire
++     * [0] EXPLICIT: a0 2c <44 bytes>                    = 46 bytes on wire
++     * OID(envelopedData): 06 09 <9 bytes>               = 11 bytes on wire
++     * ContentInfo: 30 39 <11+46=57 bytes>               = 59 bytes total
++     */
++    static const byte poc[] = {
++        /* ContentInfo SEQUENCE (length 57) */
++        0x30, 0x39,
++          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
++          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
++          /* [0] EXPLICIT (length 44) */
++          0xa0, 0x2c,
++            /* EnvelopedData SEQUENCE (length 42) */
++            0x30, 0x2a,
++              /* version = 0 */
++              0x02, 0x01, 0x00,
++              /* RecipientInfos SET (length 24) */
++              0x31, 0x18,
++                /* [4] CONSTRUCTED = ORI implicit SEQUENCE, declared len 5 */
++                /* Actual OID is 22 bytes -> exceeds declared 5 */
++                0xa4, 0x05,
++                  /* OID: tag=06, len=0x14(20), content=20 bytes = 22 total */
++                  0x06, 0x14,
++                  0x2a, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
++                  0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
++                  0x12, 0x13, 0x14, 0x15,
++              /* EncryptedContentInfo SEQUENCE (length 11) - filler so
++               * streaming has enough data; never actually parsed because
++               * DecryptOri fails before we get here */
++              0x30, 0x0b,
++                /* contentType = data 1.2.840.113549.1.7.1 */
++                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
++                0x01
++    };
++
++    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
++    ExpectNotNull(p7);
++    if (p7 != NULL) {
++        wc_PKCS7_SetOriDecryptCb(p7, test_ori_underflow_cb);
++        wc_PKCS7_SetOriDecryptCtx(p7, &cbCalled);
++
++        /* Must return an error before the callback sees an underflowed size */
++        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
++                                                  out, sizeof(out)), 0);
++
++        /* The callback must NOT have been invoked with a wrapped oriValueSz.
++         * cbCalled == 0 means the callback was never reached (ideal).
++         * cbCalled < 0 would indicate the underflow was passed through. */
++        ExpectIntGE(cbCalled, 0);
++
++        wc_PKCS7_Free(p7);
++    }
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Test: PKCS#7 ORI must reject when seqSz extends oriValue past input buffer.
++ *
++ * The first ORI bounds check (OID exceeds SEQUENCE boundary) is covered by
++ * test_pkcs7_ori_seqsz_underflow. This test covers the *second* check:
++ * oriValue region extends past the end of the input buffer. We craft a
++ * message where the [4] SEQUENCE length is valid relative to the OID
++ * (OID fits inside it), but the remaining oriValue portion extends past
++ * the end of the actual input buffer.
++ *
++ * To bypass GetLength's own bounds validation, we set the outer lengths
++ * (EnvelopedData SEQUENCE, RecipientInfos SET) to match the [4] claim,
++ * but truncate the actual buffer we pass to DecodeEnvelopedData. */
++static int test_pkcs7_ori_orivalue_overflow(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC)
++    wc_PKCS7* p7 = NULL;
++    byte out[256];
++
++    /* EnvelopedData with [4] ORI whose seqSz (40) is valid for the OID
++     * (6 bytes consumed) but oriValueSz (34) extends past the truncated
++     * input buffer.
++     *
++     * Layout:
++     * ContentInfo SEQUENCE
++     *   OID envelopedData
++     *   [0] EXPLICIT
++     *     EnvelopedData SEQUENCE
++     *       version = 0
++     *       RecipientInfos SET
++     *         [4] CONSTRUCTED (seqSz = 40)
++     *           OID (tag 06, len 04, 4 content bytes = 6 total)
++     *           oriValue should be 34 bytes but input is truncated
++     *       EncryptedContentInfo (filler for streaming)
++     *
++     * We pass the full array to DecodeEnvelopedData, but the actual
++     * input ends before [4]'s declared 40 bytes are consumed.
++     */
++    static const byte poc[] = {
++        /* ContentInfo SEQUENCE */
++        0x30, 0x43,
++          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
++          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
++          /* [0] EXPLICIT */
++          0xa0, 0x36,
++            /* EnvelopedData SEQUENCE */
++            0x30, 0x34,
++              /* version = 0 */
++              0x02, 0x01, 0x00,
++              /* RecipientInfos SET (len = 44 covers [4] tag+len+40) */
++              0x31, 0x2c,
++                /* [4] CONSTRUCTED = ORI implicit SEQUENCE, seqSz = 40 */
++                0xa4, 0x28,
++                  /* OID: tag=06, len=04, 4 content bytes = 6 total */
++                  0x06, 0x04, 0x2a, 0x03, 0x04, 0x05,
++                  /* Only 4 bytes of oriValue here, but seqSz claims 34 more */
++                  0x00, 0x00, 0x00, 0x00,
++              /* EncryptedContentInfo SEQUENCE (filler) */
++              0x30, 0x0b,
++                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
++                0x01
++    };
++
++    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
++    ExpectNotNull(p7);
++    if (p7 != NULL) {
++        wc_PKCS7_SetOriDecryptCb(p7, test_dummy_ori_cb);
++
++        /* Must return error - oriValue extends past input buffer */
++        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
++                                                  out, sizeof(out)), 0);
++
++        wc_PKCS7_Free(p7);
++    }
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Test: PKCS#7 KTRI must not match recipient when SKID length differs
++ * from expected keyIdSize.
++ *
++ * The fix adds a `length == keyIdSize` check before comparing the SKID
++ * bytes. Without this check, XMEMCMP could compare against data beyond
++ * the SKID content. This test crafts a KTRI RecipientInfo where the
++ * [0] SubjectKeyIdentifier has length 5 instead of KEYID_SIZE (20).
++ * The decode must return an error (no matching recipient). */
++static int test_pkcs7_ktri_skid_length_mismatch(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(WOLFSSL_NO_MALLOC)
++    wc_PKCS7* p7 = NULL;
++    byte out[256];
++
++    /* Minimal EnvelopedData with KTRI using version=2 (SKID path).
++     * The SKID [0] has length 5 instead of 20.
++     *
++     * ContentInfo SEQUENCE
++     *   OID envelopedData
++     *   [0] EXPLICIT
++     *     EnvelopedData SEQUENCE
++     *       version = 2
++     *       RecipientInfos SET
++     *         KTRI SEQUENCE
++     *           version = 2
++     *           [0] SKID (5 bytes, should be 20)
++     *           AlgorithmIdentifier (RSA OID)
++     *           OCTET STRING (fake encrypted key)
++     *       EncryptedContentInfo (filler)
++     */
++    static const byte poc[] = {
++        /* ContentInfo SEQUENCE */
++        0x30, 0x46,
++          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
++          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
++          /* [0] EXPLICIT */
++          0xa0, 0x39,
++            /* EnvelopedData SEQUENCE */
++            0x30, 0x37,
++              /* version = 2 (triggers SKID-based recipient identification) */
++              0x02, 0x01, 0x02,
++              /* RecipientInfos SET */
++              0x31, 0x21,
++                /* KTRI SEQUENCE */
++                0x30, 0x1f,
++                  /* version = 2 (SKID) */
++                  0x02, 0x01, 0x02,
++                  /* [0] IMPLICIT SubjectKeyIdentifier, length = 5 (wrong!) */
++                  0x80, 0x05, 0x01, 0x02, 0x03, 0x04, 0x05,
++                  /* AlgorithmIdentifier: RSA 1.2.840.113549.1.1.1 */
++                  0x30, 0x0d,
++                    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
++                    0x01, 0x01, 0x01,
++                    0x05, 0x00, /* NULL params */
++                  /* encryptedKey OCTET STRING (2 bytes fake) */
++                  0x04, 0x02, 0xAA, 0xBB,
++              /* EncryptedContentInfo SEQUENCE (filler) */
++              0x30, 0x0b,
++                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
++                0x01
++    };
++
++    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
++    ExpectNotNull(p7);
++    if (p7 != NULL) {
++        /* Decode without a cert - SKID will never match, and the
++         * mismatched SKID length must not cause out-of-bounds reads */
++        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
++                                                  out, sizeof(out)), 0);
++
++        wc_PKCS7_Free(p7);
++    }
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Test: PKCS#7 KARI must reject BIT STRING with length < 2 in
++ * OriginatorPublicKey.
++ *
++ * The fix adds `if (length < 2) return ASN_PARSE_E` after parsing
++ * the BIT STRING tag and length. A BIT STRING must have at least
++ * the unused-bits byte plus one byte of content. This test crafts
++ * a KARI [1] RecipientInfo where the OriginatorPublicKey's BIT STRING
++ * has length 1 (degenerate). The PKCS7 object is initialized with a
++ * real ECC cert so that KariParseRecipCert succeeds and parsing reaches
++ * the BIT STRING validation. */
++static int test_pkcs7_kari_degenerate_bitstring(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && defined(HAVE_ECC) && defined(HAVE_X963_KDF) && \
++    !defined(WOLFSSL_NO_MALLOC)
++    wc_PKCS7* p7 = NULL;
++    byte out[256];
++    byte* eccCert = NULL;
++    byte* eccPrivKey = NULL;
++    word32 eccCertSz = 0;
++    word32 eccPrivKeySz = 0;
++#if !defined(USE_CERT_BUFFERS_256) && !defined(NO_FILESYSTEM)
++    XFILE f = XBADFILE;
++#endif
++
++    /* Minimal EnvelopedData with KARI [1] containing a degenerate
++     * BIT STRING (length 1) in OriginatorPublicKey.
++     *
++     * ContentInfo SEQUENCE
++     *   OID envelopedData
++     *   [0] EXPLICIT
++     *     EnvelopedData SEQUENCE
++     *       version = 2
++     *       RecipientInfos SET
++     *         [1] CONSTRUCTED (KARI)
++     *           version = 3
++     *           [0] CONSTRUCTED (OriginatorIdentifierOrKey)
++     *             [1] CONSTRUCTED (OriginatorPublicKey)
++     *               AlgorithmIdentifier (ECDSAk)
++     *               BIT STRING length=1 (degenerate!)
++     *       EncryptedContentInfo (filler)
++     */
++    static const byte poc[] = {
++        /* ContentInfo SEQUENCE */
++        0x30, 0x44,
++          /* contentType = envelopedData 1.2.840.113549.1.7.3 */
++          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
++          /* [0] EXPLICIT */
++          0xa0, 0x37,
++            /* EnvelopedData SEQUENCE */
++            0x30, 0x35,
++              /* version = 2 */
++              0x02, 0x01, 0x02,
++              /* RecipientInfos SET */
++              0x31, 0x1f,
++                /* [1] CONSTRUCTED (KARI implicit) */
++                0xa1, 0x1d,
++                  /* version = 3 */
++                  0x02, 0x01, 0x03,
++                  /* [0] CONSTRUCTED (OriginatorIdentifierOrKey) */
++                  0xa0, 0x18,
++                    /* [1] CONSTRUCTED (OriginatorPublicKey) */
++                    0xa1, 0x16,
++                      /* AlgorithmIdentifier SEQUENCE */
++                      0x30, 0x13,
++                        /* OID: id-ecPublicKey 1.2.840.10045.2.1 */
++                        0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01,
++                        /* OID: prime256v1 1.2.840.10045.3.1.7 */
++                        0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
++                        0x01, 0x07,
++                      /* BIT STRING with length 1 - degenerate! */
++                      0x03, 0x01, 0x00,
++              /* EncryptedContentInfo SEQUENCE (filler) */
++              0x30, 0x0b,
++                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
++                0x01
++    };
++
++    /* Load ECC cert and key so KariParseRecipCert succeeds and
++     * parsing reaches the BIT STRING check */
++#ifdef USE_CERT_BUFFERS_256
++    eccCertSz = (word32)sizeof_cliecc_cert_der_256;
++    ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (eccCert != NULL)
++        XMEMCPY(eccCert, cliecc_cert_der_256, eccCertSz);
++    eccPrivKeySz = (word32)sizeof_ecc_clikey_der_256;
++    ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (eccPrivKey != NULL)
++        XMEMCPY(eccPrivKey, ecc_clikey_der_256, eccPrivKeySz);
++#elif !defined(NO_FILESYSTEM)
++    eccCertSz = FOURK_BUF;
++    ExpectNotNull(eccCert = (byte*)XMALLOC(eccCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    ExpectTrue((f = XFOPEN("./certs/client-ecc-cert.der", "rb")) != XBADFILE);
++    ExpectTrue((eccCertSz = (word32)XFREAD(eccCert, 1, eccCertSz, f)) > 0);
++    if (f != XBADFILE) {
++        XFCLOSE(f);
++        f = XBADFILE;
++    }
++    eccPrivKeySz = FOURK_BUF;
++    ExpectNotNull(eccPrivKey = (byte*)XMALLOC(eccPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    ExpectTrue((f = XFOPEN("./certs/ecc-client-key.der", "rb")) != XBADFILE);
++    ExpectTrue((eccPrivKeySz = (word32)XFREAD(eccPrivKey, 1, eccPrivKeySz,
++        f)) > 0);
++    if (f != XBADFILE)
++        XFCLOSE(f);
++#else
++    eccCert = NULL;
++    eccCertSz = 0;
++    eccPrivKey = NULL;
++    eccPrivKeySz = 0;
++#endif
++
++    p7 = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID);
++    ExpectNotNull(p7);
++    if (p7 != NULL && eccCert != NULL) {
++        ExpectIntEQ(wc_PKCS7_InitWithCert(p7, eccCert, eccCertSz), 0);
++        if (p7 != NULL) {
++            p7->privateKey = eccPrivKey;
++            p7->privateKeySz = eccPrivKeySz;
++        }
++
++        /* Must return error - BIT STRING length < 2 is invalid */
++        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
++                                                  out, sizeof(out)), 0);
++
++        if (p7 != NULL) {
++            p7->privateKey = NULL;
++            p7->privateKeySz = 0;
++        }
++        wc_PKCS7_Free(p7);
++    }
++    else if (p7 != NULL) {
++        wc_PKCS7_Free(p7);
++    }
++
++    XFREE(eccCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++    XFREE(eccPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Test: PKCS#7 EncryptedData must reject when encryptedContentSz exceeds
++ * the remaining input buffer.
++ *
++ * The fix adds `encryptedContentSz > (int)(pkiMsgSz - idx)` to the
++ * existing `encryptedContentSz <= 0` check in stage 6. This test crafts
++ * a minimal EncryptedData where the [0] IMPLICIT content length claims
++ * 0x200 (512) bytes but only 32 bytes of ciphertext are present. */
++static int test_pkcs7_encrypted_content_size_overflow(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(NO_AES) && defined(HAVE_AES_CBC) && \
++    defined(WOLFSSL_AES_256) && !defined(NO_PKCS7_ENCRYPTED_DATA) && \
++    !defined(WOLFSSL_NO_MALLOC)
++    wc_PKCS7* p7 = NULL;
++    byte key[32];
++    byte out[256];
++
++    /* EncryptedData with [0] content claiming 512 bytes but only 32 present.
++     *
++     * ContentInfo SEQUENCE
++     *   OID encryptedData (1.2.840.113549.1.7.6)
++     *   [0] EXPLICIT
++     *     EncryptedData SEQUENCE
++     *       version = 0
++     *       EncryptedContentInfo SEQUENCE
++     *         OID data (1.2.840.113549.1.7.1)
++     *         AlgorithmIdentifier
++     *           OID AES-256-CBC (2.16.840.1.101.3.4.1.42)
++     *           OCTET STRING IV (16 zero bytes)
++     *         [0] IMPLICIT content (claimed len=0x200, actual=32 bytes)
++     */
++    static const byte poc[] = {
++        /* ContentInfo SEQUENCE (len covers entire message) */
++        0x30, 0x50,
++          /* OID encryptedData 1.2.840.113549.1.7.6 */
++          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x06,
++          /* [0] EXPLICIT */
++          0xa0, 0x43,
++            /* EncryptedData SEQUENCE */
++            0x30, 0x41,
++              /* version = 0 */
++              0x02, 0x01, 0x00,
++              /* EncryptedContentInfo SEQUENCE */
++              0x30, 0x3c,
++                /* OID data 1.2.840.113549.1.7.1 */
++                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
++                0x01,
++                /* AlgorithmIdentifier SEQUENCE */
++                0x30, 0x1d,
++                  /* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */
++                  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
++                  0x2a,
++                  /* IV: OCTET STRING (16 zero bytes) */
++                  0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                /* [0] IMPLICIT encryptedContent - claims 512 bytes!
++                 * Only 16 bytes of fake ciphertext follow. */
++                0x80, 0x82, 0x02, 0x00,
++                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
++                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
++    };
++
++    XMEMSET(key, 0, sizeof(key));
++
++    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
++    ExpectNotNull(p7);
++    if (p7 != NULL) {
++        p7->encryptionKey = key;
++        p7->encryptionKeySz = sizeof(key);
++
++        /* Must return error - content extends past input buffer */
++        ExpectIntLT(wc_PKCS7_DecodeEncryptedData(p7, (byte*)poc, sizeof(poc),
++                                                  out, sizeof(out)), 0);
++
++        wc_PKCS7_Free(p7);
++    }
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Test: PKCS#7 SignedData must reject when the signature field is not
++ * an OCTET STRING.
++ *
++ * The fix adds `else if (ret == 0) { ret = ASN_PARSE_E; }` so that
++ * when the tag at the signature position is not ASN_OCTET_STRING,
++ * parsing returns an error instead of silently continuing with no
++ * signature. This test encodes a valid SignedData, then corrupts
++ * the signature OCTET STRING tag and verifies that decode fails. */
++static int test_pkcs7_signed_bad_sig_tag(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
++    !defined(WOLFSSL_NO_MALLOC)
++    PKCS7* pkcs7 = NULL;
++    WC_RNG rng;
++    byte  encoded[FOURK_BUF];
++    int   encodedSz = 0;
++    int   i;
++    byte* rsaCert = NULL;
++    byte* rsaPrivKey = NULL;
++    word32 rsaCertSz = 0;
++    word32 rsaPrivKeySz = 0;
++#if !defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024) && \
++    !defined(NO_FILESYSTEM)
++    XFILE f = XBADFILE;
++#endif
++
++    const byte data[] = "Test signed data";
++
++    XMEMSET(&rng, 0, sizeof(WC_RNG));
++
++    /* Load RSA cert and key */
++#if defined(USE_CERT_BUFFERS_2048)
++    rsaCertSz = (word32)sizeof_client_cert_der_2048;
++    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaCert != NULL)
++        XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz);
++    rsaPrivKeySz = (word32)sizeof_client_key_der_2048;
++    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaPrivKey != NULL)
++        XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz);
++#elif defined(USE_CERT_BUFFERS_1024)
++    rsaCertSz = (word32)sizeof_client_cert_der_1024;
++    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaCert != NULL)
++        XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz);
++    rsaPrivKeySz = (word32)sizeof_client_key_der_1024;
++    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaPrivKey != NULL)
++        XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz);
++#elif !defined(NO_FILESYSTEM)
++    rsaCertSz = FOURK_BUF;
++    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE);
++    ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0);
++    if (f != XBADFILE) { XFCLOSE(f); f = XBADFILE; }
++    rsaPrivKeySz = FOURK_BUF;
++    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE);
++    ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1,
++        rsaPrivKeySz, f)) > 0);
++    if (f != XBADFILE) XFCLOSE(f);
++#else
++    rsaCert = NULL; rsaCertSz = 0;
++    rsaPrivKey = NULL; rsaPrivKeySz = 0;
++#endif
++
++    if (rsaCert == NULL || rsaPrivKey == NULL) {
++        XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++        XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++        return TEST_SKIPPED;
++    }
++
++    ExpectIntEQ(wc_InitRng(&rng), 0);
++
++    /* Encode a valid SignedData */
++    ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
++    ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
++    if (pkcs7 != NULL) {
++        pkcs7->content    = (byte*)data;
++        pkcs7->contentSz  = (word32)sizeof(data);
++        pkcs7->contentOID = DATA;
++        pkcs7->hashOID    = SHA256h;
++        pkcs7->encryptOID = RSAk;
++        pkcs7->privateKey = rsaPrivKey;
++        pkcs7->privateKeySz = rsaPrivKeySz;
++        pkcs7->rng = &rng;
++    }
++
++    ExpectIntGT(encodedSz = wc_PKCS7_EncodeSignedData(pkcs7, encoded,
++        sizeof(encoded)), 0);
++    wc_PKCS7_Free(pkcs7);
++    pkcs7 = NULL;
++
++    /* Find the signature OCTET STRING tag (0x04) near the end of the
++     * encoded message and corrupt it. The signature is the last large
++     * OCTET STRING in the SignerInfo. Search backwards for 0x04 followed
++     * by a length that looks like an RSA signature (>= 64 bytes).
++     * This heuristic depends on the signature being the last large
++     * OCTET STRING; the found==1 assertion below guards against
++     * silent false passes if encoding changes. */
++    if (EXPECT_SUCCESS()) {
++        int found = 0;
++        for (i = encodedSz - 10; i > 10; i--) {
++            if (encoded[i] == 0x04) {
++                int len = 0, lbytes = 0;
++                if (encoded[i+1] < 0x80) {
++                    len = encoded[i+1]; lbytes = 1;
++                }
++                else if (encoded[i+1] == 0x81) {
++                    len = encoded[i+2]; lbytes = 2;
++                }
++                else if (encoded[i+1] == 0x82) {
++                    len = (encoded[i+2] << 8) | encoded[i+3]; lbytes = 3;
++                }
++                /* RSA signature is typically >= 128 bytes */
++                if (len >= 64 && i + 1 + lbytes + len <= encodedSz) {
++                    /* Corrupt the OCTET STRING tag to INTEGER */
++                    encoded[i] = 0x02; /* ASN_INTEGER instead of OCTET STRING */
++                    found = 1;
++                    break;
++                }
++            }
++        }
++        ExpectIntEQ(found, 1);
++    }
++
++    /* Verify the corrupted SignedData - must fail */
++    if (EXPECT_SUCCESS()) {
++        ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
++        ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, NULL, 0), 0);
++        ExpectIntLT(wc_PKCS7_VerifySignedData(pkcs7, encoded,
++            (word32)encodedSz), 0);
++        wc_PKCS7_Free(pkcs7);
++        pkcs7 = NULL;
++    }
++
++    DoExpectIntEQ(wc_FreeRng(&rng), 0);
++    XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++    XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Test: PKCS#7 EnvelopedData must reject when encryptedContentTotalSz
++ * exceeds the remaining input buffer.
++ *
++ * The fix adds a bounds check under NO_PKCS7_STREAM, but the same
++ * crafted message should also be properly handled in streaming mode.
++ * This test crafts an EnvelopedData where the [0] content length
++ * claims 512 bytes but only minimal data follows. */
++static int test_pkcs7_enveloped_content_size_overflow(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(WOLFSSL_NO_MALLOC) && !defined(NO_RSA)
++    wc_PKCS7* p7 = NULL;
++    byte out[256];
++
++    /* EnvelopedData with KTRI where the EncryptedContentInfo [0] claims
++     * 512 bytes but only 16 are present.
++     *
++     * The outer structure is valid enough to reach the content parsing:
++     *   ContentInfo -> EnvelopedData -> version=0 ->
++     *   RecipientInfos (empty SET) -> EncryptedContentInfo ->
++     *   contentType + AlgorithmIdentifier + [0] oversized content */
++    static const byte poc[] = {
++        /* ContentInfo SEQUENCE */
++        0x30, 0x50,
++          /* OID envelopedData 1.2.840.113549.1.7.3 */
++          0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x03,
++          /* [0] EXPLICIT */
++          0xa0, 0x43,
++            /* EnvelopedData SEQUENCE */
++            0x30, 0x41,
++              /* version = 0 */
++              0x02, 0x01, 0x00,
++              /* RecipientInfos SET (empty - no recipients) */
++              0x31, 0x00,
++              /* EncryptedContentInfo SEQUENCE */
++              0x30, 0x3c,
++                /* OID data 1.2.840.113549.1.7.1 */
++                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
++                0x01,
++                /* AlgorithmIdentifier SEQUENCE */
++                0x30, 0x1d,
++                  /* OID AES-256-CBC 2.16.840.1.101.3.4.1.42 */
++                  0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01,
++                  0x2a,
++                  /* IV: OCTET STRING (16 zero bytes) */
++                  0x04, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
++                /* [0] IMPLICIT encryptedContent - claims 512 bytes! */
++                0x80, 0x82, 0x02, 0x00,
++                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
++                0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA
++    };
++
++    p7 = wc_PKCS7_New(NULL, INVALID_DEVID);
++    ExpectNotNull(p7);
++    if (p7 != NULL) {
++        /* With an empty RecipientInfos SET, the function may fail at
++         * the recipient matching stage before reaching the content-size
++         * bounds check.  The ExpectIntLT assertion ensures the
++         * oversized content does not cause a buffer over-read. */
++        ExpectIntLT(wc_PKCS7_DecodeEnvelopedData(p7, (byte*)poc, sizeof(poc),
++                                                  out, sizeof(out)), 0);
++
++        wc_PKCS7_Free(p7);
++    }
++#endif
++    return EXPECT_RESULT();
++}
++
+ /* Dilithium verify_ctx_msg must reject absurdly large msgLen */
+ static int test_dilithium_hash(void)
+ {
+@@ -35936,6 +36636,13 @@ TEST_CASE testCases[] = {
+     TEST_DECL(test_ed448_rejects_identity_key),
+     TEST_DECL(test_pkcs7_decode_encrypted_outputsz),
+     TEST_DECL(test_pkcs7_ori_oversized_oid),
++    TEST_DECL(test_pkcs7_ori_seqsz_underflow),
++    TEST_DECL(test_pkcs7_ori_orivalue_overflow),
++    TEST_DECL(test_pkcs7_ktri_skid_length_mismatch),
++    TEST_DECL(test_pkcs7_kari_degenerate_bitstring),
++    TEST_DECL(test_pkcs7_encrypted_content_size_overflow),
++    TEST_DECL(test_pkcs7_signed_bad_sig_tag),
++    TEST_DECL(test_pkcs7_enveloped_content_size_overflow),
+     TEST_DECL(test_pkcs7_padding),
+ 
+ #if defined(WOLFSSL_SNIFFER) && defined(WOLFSSL_SNIFFER_CHAIN_INPUT)
+diff --git a/tests/api/test_ossl_p7p12.c b/tests/api/test_ossl_p7p12.c
+index c92b80ee5..03590a3ad 100644
+--- a/tests/api/test_ossl_p7p12.c
++++ b/tests/api/test_ossl_p7p12.c
+@@ -446,6 +446,460 @@ int test_wolfSSL_PKCS7_sign(void)
+     return EXPECT_RESULT();
+ }
+ 
++/* Regression test for CMS SignedData signer-identity forgery.
++ *
++ * The embedded DER is a CMS SignedData message crafted so that the
++ * certificates SET contains two certificates:
++ *   cert[0] = certs/ca-cert.pem (trusted wolfSSL CA; attacker does NOT hold
++ *             its private key)
++ *   cert[1] = a self-signed "attacker" P-256 certificate (attacker holds
++ *             the private key)
++ * The signerInfo sid names the attacker certificate, and the signature
++ * was produced with the attacker's key over "Hello World".
++ *
++ * The bug that was present: wolfSSL_PKCS7_verify() iterated all bundled
++ * certificates trying each public key against the signature. When the
++ * attacker's key verified, it still reported cert[0] (the trusted CA cert,
++ * via singleCert) as the signer, and chain validation therefore succeeded
++ * on an unrelated trusted cert - a full signer-identity forgery.
++ *
++ * The expected, correct behavior: the CMS message is rejected because the
++ * signer certificate named by the sid (the attacker cert) does not chain
++ * to any certificate in the trust store. */
++int test_wolfSSL_PKCS7_verify_signer_forgery(void)
++{
++    EXPECT_DECLS;
++#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \
++    !defined(NO_FILESYSTEM) && !defined(NO_RSA) && defined(HAVE_ECC)
++    static const byte forgedSignedData[] = {
++        0x30, 0x82, 0x07, 0x9c, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
++        0x01, 0x07, 0x02, 0xa0, 0x82, 0x07, 0x8d, 0x30, 0x82, 0x07, 0x89, 0x02,
++        0x01, 0x01, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
++        0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48,
++        0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01, 0xa0, 0x0e, 0x04, 0x0c, 0x48, 0x65,
++        0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0a, 0xa0, 0x82,
++        0x06, 0xab, 0x30, 0x82, 0x04, 0xff, 0x30, 0x82, 0x03, 0xe7, 0xa0, 0x03,
++        0x02, 0x01, 0x02, 0x02, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7,
++        0x8e, 0xf9, 0x18, 0x0d, 0xca, 0x70, 0x4d, 0x5b, 0x15, 0x2a, 0x43, 0xd6,
++        0x24, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
++        0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09, 0x06,
++        0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e,
++        0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, 0x6e, 0x74, 0x61,
++        0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c,
++        0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, 0x11, 0x30, 0x0f,
++        0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, 0x77, 0x74, 0x6f,
++        0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0b,
++        0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e, 0x67,
++        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, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
++        0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f, 0x40,
++        0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x30,
++        0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x31, 0x31, 0x33, 0x32, 0x30, 0x34,
++        0x31, 0x31, 0x31, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, 0x38, 0x30, 0x39,
++        0x32, 0x30, 0x34, 0x31, 0x31, 0x31, 0x5a, 0x30, 0x81, 0x94, 0x31, 0x0b,
++        0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31,
++        0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f,
++        0x6e, 0x74, 0x61, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
++        0x04, 0x07, 0x0c, 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31,
++        0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61,
++        0x77, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
++        0x55, 0x04, 0x0b, 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74,
++        0x69, 0x6e, 0x67, 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, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a,
++        0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e,
++        0x66, 0x6f, 0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63,
++        0x6f, 0x6d, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
++        0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
++        0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xbf,
++        0x0c, 0xca, 0x2d, 0x14, 0xb2, 0x1e, 0x84, 0x42, 0x5b, 0xcd, 0x38, 0x1f,
++        0x4a, 0xf2, 0x4d, 0x75, 0x10, 0xf1, 0xb6, 0x35, 0x9f, 0xdf, 0xca, 0x7d,
++        0x03, 0x98, 0xd3, 0xac, 0xde, 0x03, 0x66, 0xee, 0x2a, 0xf1, 0xd8, 0xb0,
++        0x7d, 0x6e, 0x07, 0x54, 0x0b, 0x10, 0x98, 0x21, 0x4d, 0x80, 0xcb, 0x12,
++        0x20, 0xe7, 0xcc, 0x4f, 0xde, 0x45, 0x7d, 0xc9, 0x72, 0x77, 0x32, 0xea,
++        0xca, 0x90, 0xbb, 0x69, 0x52, 0x10, 0x03, 0x2f, 0xa8, 0xf3, 0x95, 0xc5,
++        0xf1, 0x8b, 0x62, 0x56, 0x1b, 0xef, 0x67, 0x6f, 0xa4, 0x10, 0x41, 0x95,
++        0xad, 0x0a, 0x9b, 0xe3, 0xa5, 0xc0, 0xb0, 0xd2, 0x70, 0x76, 0x50, 0x30,
++        0x5b, 0xa8, 0xe8, 0x08, 0x2c, 0x7c, 0xed, 0xa7, 0xa2, 0x7a, 0x8d, 0x38,
++        0x29, 0x1c, 0xac, 0xc7, 0xed, 0xf2, 0x7c, 0x95, 0xb0, 0x95, 0x82, 0x7d,
++        0x49, 0x5c, 0x38, 0xcd, 0x77, 0x25, 0xef, 0xbd, 0x80, 0x75, 0x53, 0x94,
++        0x3c, 0x3d, 0xca, 0x63, 0x5b, 0x9f, 0x15, 0xb5, 0xd3, 0x1d, 0x13, 0x2f,
++        0x19, 0xd1, 0x3c, 0xdb, 0x76, 0x3a, 0xcc, 0xb8, 0x7d, 0xc9, 0xe5, 0xc2,
++        0xd7, 0xda, 0x40, 0x6f, 0xd8, 0x21, 0xdc, 0x73, 0x1b, 0x42, 0x2d, 0x53,
++        0x9c, 0xfe, 0x1a, 0xfc, 0x7d, 0xab, 0x7a, 0x36, 0x3f, 0x98, 0xde, 0x84,
++        0x7c, 0x05, 0x67, 0xce, 0x6a, 0x14, 0x38, 0x87, 0xa9, 0xf1, 0x8c, 0xb5,
++        0x68, 0xcb, 0x68, 0x7f, 0x71, 0x20, 0x2b, 0xf5, 0xa0, 0x63, 0xf5, 0x56,
++        0x2f, 0xa3, 0x26, 0xd2, 0xb7, 0x6f, 0xb1, 0x5a, 0x17, 0xd7, 0x38, 0x99,
++        0x08, 0xfe, 0x93, 0x58, 0x6f, 0xfe, 0xc3, 0x13, 0x49, 0x08, 0x16, 0x0b,
++        0xa7, 0x4d, 0x67, 0x00, 0x52, 0x31, 0x67, 0x23, 0x4e, 0x98, 0xed, 0x51,
++        0x45, 0x1d, 0xb9, 0x04, 0xd9, 0x0b, 0xec, 0xd8, 0x28, 0xb3, 0x4b, 0xbd,
++        0xed, 0x36, 0x79, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0x45,
++        0x30, 0x82, 0x01, 0x41, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04,
++        0x16, 0x04, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f,
++        0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0x30,
++        0x81, 0xd4, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x81, 0xcc, 0x30, 0x81,
++        0xc9, 0x80, 0x14, 0x27, 0x8e, 0x67, 0x11, 0x74, 0xc3, 0x26, 0x1d, 0x3f,
++        0xed, 0x33, 0x63, 0xb3, 0xa4, 0xd8, 0x1d, 0x30, 0xe5, 0xe8, 0xd5, 0xa1,
++        0x81, 0x9a, 0xa4, 0x81, 0x97, 0x30, 0x81, 0x94, 0x31, 0x0b, 0x30, 0x09,
++        0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30,
++        0x0e, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x07, 0x4d, 0x6f, 0x6e, 0x74,
++        0x61, 0x6e, 0x61, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x07,
++        0x0c, 0x07, 0x42, 0x6f, 0x7a, 0x65, 0x6d, 0x61, 0x6e, 0x31, 0x11, 0x30,
++        0x0f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x08, 0x53, 0x61, 0x77, 0x74,
++        0x6f, 0x6f, 0x74, 0x68, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04,
++        0x0b, 0x0c, 0x0a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x74, 0x69, 0x6e,
++        0x67, 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, 0x1f, 0x30, 0x1d, 0x06, 0x09, 0x2a, 0x86, 0x48,
++        0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01, 0x16, 0x10, 0x69, 0x6e, 0x66, 0x6f,
++        0x40, 0x77, 0x6f, 0x6c, 0x66, 0x73, 0x73, 0x6c, 0x2e, 0x63, 0x6f, 0x6d,
++        0x82, 0x14, 0x3f, 0x29, 0x11, 0x20, 0x57, 0x71, 0xe7, 0x8e, 0xf9, 0x18,
++        0x0d, 0xca, 0x70, 0x4d, 0x5b, 0x15, 0x2a, 0x43, 0xd6, 0x24, 0x30, 0x0c,
++        0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff,
++        0x30, 0x1c, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04, 0x15, 0x30, 0x13, 0x82,
++        0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
++        0x87, 0x04, 0x7f, 0x00, 0x00, 0x01, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d,
++        0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
++        0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
++        0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
++        0x01, 0x0b, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x0f, 0xae, 0x89,
++        0xd5, 0x68, 0xe4, 0x41, 0xf8, 0x9b, 0xe0, 0xc5, 0x61, 0x06, 0x57, 0xff,
++        0xa0, 0x92, 0x0f, 0xb2, 0xed, 0xd3, 0x99, 0x5b, 0x99, 0x5e, 0x32, 0x7e,
++        0x97, 0xc7, 0xaf, 0x6c, 0xfe, 0x8c, 0xa6, 0xae, 0x32, 0xa1, 0x0d, 0xca,
++        0xcd, 0xfc, 0x18, 0xe5, 0xd1, 0xf8, 0x20, 0x5b, 0x5a, 0x38, 0x81, 0x46,
++        0x5b, 0x48, 0x87, 0xa5, 0x3f, 0x3b, 0x7b, 0xc7, 0xea, 0xf5, 0x35, 0x29,
++        0x31, 0x15, 0x39, 0x38, 0x5d, 0x48, 0xe6, 0x01, 0x81, 0x5c, 0x5e, 0x7c,
++        0x10, 0xf5, 0x16, 0xe3, 0x59, 0xaf, 0x44, 0xc8, 0xb5, 0x8d, 0xc1, 0x32,
++        0x23, 0xb3, 0xb8, 0x12, 0x6e, 0x5c, 0x8d, 0xe6, 0xc2, 0xd2, 0x41, 0x03,
++        0xeb, 0x17, 0x42, 0xe2, 0x7f, 0xbc, 0x00, 0x5d, 0xa5, 0x31, 0xef, 0xc6,
++        0x48, 0xee, 0xdb, 0xcc, 0xe0, 0xf1, 0x56, 0xf5, 0xd4, 0xca, 0x45, 0xa1,
++        0x59, 0xb5, 0xe4, 0xd7, 0x60, 0x9c, 0x57, 0xe0, 0xa7, 0x5a, 0xf2, 0x35,
++        0x1e, 0xa0, 0x22, 0xdb, 0x5e, 0x1c, 0x0c, 0x61, 0xbd, 0xa1, 0xc5, 0x7b,
++        0x9f, 0x69, 0xf2, 0xd5, 0x95, 0xe2, 0xbc, 0x52, 0xb9, 0x1d, 0x9c, 0x2c,
++        0xda, 0xb6, 0x73, 0x75, 0x4a, 0x84, 0xe5, 0x94, 0xb8, 0x19, 0x4d, 0xdd,
++        0x70, 0xbd, 0x7f, 0x4c, 0xb9, 0x17, 0x6a, 0x58, 0x16, 0x89, 0x22, 0x44,
++        0x37, 0x57, 0x55, 0x26, 0x42, 0xe3, 0xb7, 0xe5, 0xc7, 0x2b, 0x40, 0x0c,
++        0xe9, 0xe4, 0x7f, 0x52, 0x75, 0xdf, 0x06, 0xc9, 0xfb, 0x01, 0x44, 0x34,
++        0xac, 0x20, 0x3c, 0xb4, 0xbe, 0x2b, 0x3e, 0xef, 0x85, 0x38, 0x96, 0x5b,
++        0x9b, 0x1e, 0x25, 0x86, 0x18, 0x4c, 0xa4, 0x06, 0x70, 0x06, 0x6a, 0xc8,
++        0x4b, 0x6f, 0x5f, 0xc4, 0x05, 0x1f, 0x03, 0x62, 0x30, 0x11, 0x61, 0xbc,
++        0xc1, 0x40, 0x31, 0x66, 0xdc, 0x64, 0xf0, 0x4f, 0x6b, 0xb9, 0xec, 0xc8,
++        0x29, 0x30, 0x82, 0x01, 0xa4, 0x30, 0x82, 0x01, 0x49, 0xa0, 0x03, 0x02,
++        0x01, 0x02, 0x02, 0x14, 0x62, 0x4d, 0x11, 0x9c, 0xcf, 0x5d, 0xe5, 0x71,
++        0xa2, 0x82, 0xd9, 0x8f, 0xe0, 0x04, 0xb8, 0x5f, 0x0e, 0x4d, 0x07, 0xad,
++        0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02,
++        0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
++        0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, 0x12, 0x30,
++        0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x75, 0x6e, 0x74, 0x72,
++        0x75, 0x73, 0x74, 0x65, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x36, 0x30,
++        0x34, 0x32, 0x31, 0x31, 0x31, 0x31, 0x36, 0x32, 0x38, 0x5a, 0x17, 0x0d,
++        0x33, 0x36, 0x30, 0x34, 0x31, 0x38, 0x31, 0x31, 0x31, 0x36, 0x32, 0x38,
++        0x5a, 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x03,
++        0x0c, 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65, 0x72, 0x31, 0x12,
++        0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09, 0x75, 0x6e, 0x74,
++        0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 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, 0xae, 0xdb, 0xf7,
++        0x3b, 0x7e, 0x82, 0x88, 0xfc, 0x1a, 0xfb, 0x86, 0x56, 0x83, 0x03, 0xdd,
++        0x05, 0x14, 0x79, 0x51, 0x0f, 0x3c, 0x86, 0x85, 0x2d, 0xeb, 0x18, 0x17,
++        0x20, 0x3b, 0x37, 0x6f, 0x7f, 0x78, 0x19, 0x3b, 0xf6, 0x71, 0xad, 0xc9,
++        0x65, 0x81, 0x7e, 0xe0, 0xa9, 0x29, 0xdd, 0xfd, 0xf0, 0xff, 0x04, 0x7d,
++        0x5a, 0x59, 0xd6, 0x6c, 0xe2, 0xde, 0xc5, 0xd5, 0xb6, 0x1f, 0x69, 0xd9,
++        0x33, 0xa3, 0x53, 0x30, 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
++        0x04, 0x16, 0x04, 0x14, 0xf7, 0xab, 0x3f, 0x49, 0xcf, 0x7d, 0x48, 0x9c,
++        0x04, 0x49, 0x1a, 0xac, 0x8f, 0x26, 0x16, 0x09, 0xa8, 0x2a, 0x74, 0xf5,
++        0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80,
++        0x14, 0xf7, 0xab, 0x3f, 0x49, 0xcf, 0x7d, 0x48, 0x9c, 0x04, 0x49, 0x1a,
++        0xac, 0x8f, 0x26, 0x16, 0x09, 0xa8, 0x2a, 0x74, 0xf5, 0x30, 0x0f, 0x06,
++        0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01,
++        0x01, 0xff, 0x30, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04,
++        0x03, 0x02, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x8d, 0xbf,
++        0x36, 0xe5, 0x51, 0x9a, 0xde, 0xf4, 0x7f, 0xbf, 0xbd, 0x7f, 0x71, 0x66,
++        0xc1, 0x67, 0xfa, 0x71, 0x0d, 0x79, 0xc6, 0x60, 0x3a, 0x6c, 0xeb, 0x43,
++        0xc3, 0xf2, 0x5e, 0xe8, 0x74, 0xb6, 0x02, 0x21, 0x00, 0xfa, 0xdb, 0x40,
++        0x47, 0x72, 0xf0, 0x15, 0x52, 0xc1, 0x78, 0x11, 0x6b, 0x76, 0xc5, 0x1f,
++        0xcf, 0xb6, 0x09, 0x6d, 0x8f, 0xcb, 0x92, 0x2f, 0x1b, 0x3c, 0xc3, 0x28,
++        0x48, 0x61, 0x0f, 0x60, 0x71, 0x31, 0x81, 0xa8, 0x30, 0x81, 0xa5, 0x02,
++        0x01, 0x01, 0x30, 0x3f, 0x30, 0x27, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03,
++        0x55, 0x04, 0x03, 0x0c, 0x08, 0x61, 0x74, 0x74, 0x61, 0x63, 0x6b, 0x65,
++        0x72, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x09,
++        0x75, 0x6e, 0x74, 0x72, 0x75, 0x73, 0x74, 0x65, 0x64, 0x02, 0x14, 0x62,
++        0x4d, 0x11, 0x9c, 0xcf, 0x5d, 0xe5, 0x71, 0xa2, 0x82, 0xd9, 0x8f, 0xe0,
++        0x04, 0xb8, 0x5f, 0x0e, 0x4d, 0x07, 0xad, 0x30, 0x0b, 0x06, 0x09, 0x60,
++        0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x30, 0x0a, 0x06, 0x08,
++        0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x04, 0x46, 0x30, 0x44,
++        0x02, 0x20, 0x22, 0x4a, 0x99, 0xb1, 0xbc, 0xa9, 0xee, 0x24, 0x60, 0x81,
++        0xb9, 0x64, 0xba, 0x86, 0x00, 0xae, 0xb5, 0xd7, 0xb8, 0x72, 0xb9, 0x8c,
++        0xb3, 0xe7, 0x78, 0x29, 0xdb, 0xa8, 0x27, 0xf7, 0x30, 0xf0, 0x02, 0x20,
++        0x19, 0x2d, 0xd3, 0x17, 0x9a, 0xc1, 0xf9, 0xd2, 0x63, 0x92, 0x8e, 0x78,
++        0xcc, 0xa4, 0x0b, 0x91, 0x12, 0xa5, 0xb2, 0xbc, 0x35, 0x87, 0x8e, 0x33,
++        0xa7, 0xe0, 0x5e, 0xab, 0x95, 0xb2, 0x2a, 0xf4
++    };
++    PKCS7* p7 = NULL;
++    X509_STORE* store = NULL;
++    X509* caCert = NULL;
++    WOLFSSL_BIO* caBio = NULL;
++    const byte* p = forgedSignedData;
++    const char* ca = "./certs/ca-cert.pem";
++
++    /* Load the same CA into the trust store that the attacker bundled at
++     * cert[0] in the forged message. */
++    ExpectNotNull(caBio = BIO_new_file(ca, "r"));
++    ExpectNotNull(caCert = PEM_read_bio_X509(caBio, NULL, 0, NULL));
++    ExpectNotNull(store = X509_STORE_new());
++    ExpectIntEQ(X509_STORE_add_cert(store, caCert), 1);
++
++    /* Parse the forged message. d2i_PKCS7 internally runs
++     * wc_PKCS7_VerifySignedData, which must NOT accept the attacker's
++     * signature under any bundled cert other than the one named by the
++     * signerInfo sid. Since the sid names the attacker cert (which does
++     * not chain to the trusted CA), the parse may succeed but verification
++     * against the trust store must fail. */
++    ExpectNotNull(p7 = d2i_PKCS7(NULL, &p, (int)sizeof(forgedSignedData)));
++
++    /* PKCS7_verify() MUST fail: the only certificate in the trust store
++     * is the wolfSSL CA - it is bundled at cert[0] but did NOT sign this
++     * message. The actual signer (the attacker's self-signed cert at
++     * cert[1]) cannot chain to any trust anchor. */
++    ExpectIntEQ(PKCS7_verify(p7, NULL, store, NULL, NULL, 0),
++                WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
++
++    PKCS7_free(p7);
++    X509_STORE_free(store);
++    X509_free(caCert);
++    BIO_free(caBio);
++#endif
++    return EXPECT_RESULT();
++}
++
++/* Exercise the SignerInfo-sid binding enforcement end-to-end.
++ *
++ * For both supported sid encodings (v1 = IssuerAndSerialNumber, v3 =
++ * SubjectKeyIdentifier), this builds a valid CMS SignedData message with
++ * two certificates in the bundle:
++ *   cert[0] = ca-cert (extra, non-signing)
++ *   cert[1] = server-cert (actual signer)
++ * and checks that:
++ *   - parsing + signature verification succeeds,
++ *   - chain validation against a trust store containing ca-cert succeeds,
++ *   - PKCS7_get0_signers() returns the *signer* (server-cert), not the
++ *     extra cert at cert[0] - which would be the pre-fix behavior and the
++ *     core of the signer-identity forgery bug. */
++int test_wolfSSL_PKCS7_verify_sid_binding(void)
++{
++    EXPECT_DECLS;
++#if defined(OPENSSL_ALL) && defined(HAVE_PKCS7) && !defined(NO_BIO) && \
++    !defined(NO_FILESYSTEM) && !defined(NO_RSA)
++    const char* signerCertFile = "./certs/server-cert.pem";
++    const char* signerKeyFile  = "./certs/server-key.pem";
++    const char* caFile         = "./certs/ca-cert.pem";
++    const byte  content[] = "sid-binding test content";
++    /* Build both variants: default v1 (IssuerAndSerialNumber) and v3
++     * (SubjectKeyIdentifier). */
++    const int   sidTypes[2] = { CMS_ISSUER_AND_SERIAL_NUMBER, CMS_SKID };
++    int         variant;
++
++    BIO* signerCertBio = NULL;
++    BIO* caBio = NULL;
++    X509* signerCertX509 = NULL;
++    X509* caX509 = NULL;
++    byte* signerCertDer = NULL;
++    byte* caDer = NULL;
++    byte* signerKey = NULL;
++    int   signerCertDerSz = 0;
++    int   caDerSz = 0;
++    size_t signerKeySz = 0;
++    XFILE keyFile = XBADFILE;
++    WC_RNG rng;
++    int rngInited = 0;
++
++    /* ---- Load signer cert + key and the CA cert. ---- */
++    ExpectNotNull(signerCertBio = BIO_new_file(signerCertFile, "r"));
++    ExpectNotNull(signerCertX509 = PEM_read_bio_X509(signerCertBio, NULL, 0,
++                                                    NULL));
++    ExpectIntGT(signerCertDerSz = i2d_X509(signerCertX509, &signerCertDer), 0);
++
++    ExpectNotNull(caBio = BIO_new_file(caFile, "r"));
++    ExpectNotNull(caX509 = PEM_read_bio_X509(caBio, NULL, 0, NULL));
++    ExpectIntGT(caDerSz = i2d_X509(caX509, &caDer), 0);
++
++    /* Slurp the DER private key straight from a PEM->DER round-trip via
++     * wc_KeyPemToDer. The test only needs the bytes in a form
++     * wc_PKCS7_EncodeSignedData can consume. */
++    {
++        long   filePemLen = 0;
++        byte*  keyPem = NULL;
++        int    derLen = 0;
++
++        ExpectTrue((keyFile = XFOPEN(signerKeyFile, "rb")) != XBADFILE);
++        if (keyFile != XBADFILE) {
++            (void)XFSEEK(keyFile, 0, XSEEK_END);
++            filePemLen = XFTELL(keyFile);
++            (void)XFSEEK(keyFile, 0, XSEEK_SET);
++            ExpectIntGT(filePemLen, 0);
++            keyPem = (byte*)XMALLOC((size_t)filePemLen, NULL,
++                                    DYNAMIC_TYPE_TMP_BUFFER);
++            ExpectNotNull(keyPem);
++            if (keyPem != NULL) {
++                ExpectIntEQ(XFREAD(keyPem, 1, (size_t)filePemLen, keyFile),
++                            (size_t)filePemLen);
++                /* First call sizes the output buffer. */
++                derLen = wc_KeyPemToDer(keyPem, (word32)filePemLen, NULL, 0,
++                                        NULL);
++                ExpectIntGT(derLen, 0);
++                if (derLen > 0) {
++                    signerKey = (byte*)XMALLOC((size_t)derLen, NULL,
++                                               DYNAMIC_TYPE_TMP_BUFFER);
++                    ExpectNotNull(signerKey);
++                    if (signerKey != NULL) {
++                        derLen = wc_KeyPemToDer(keyPem, (word32)filePemLen,
++                                                signerKey, (word32)derLen,
++                                                NULL);
++                        ExpectIntGT(derLen, 0);
++                        signerKeySz = (size_t)derLen;
++                    }
++                }
++            }
++            XFREE(keyPem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
++            XFCLOSE(keyFile);
++            keyFile = XBADFILE;
++        }
++    }
++
++    ExpectIntEQ(wc_InitRng(&rng), 0);
++    if (EXPECT_SUCCESS())
++        rngInited = 1;
++
++    for (variant = 0; variant < 2; variant++) {
++        wc_PKCS7* p7Enc = NULL;
++        byte      encoded[4096];
++        int       encodedSz = 0;
++        PKCS7*    p7Ver = NULL;
++        X509_STORE* store = NULL;
++        const byte* encodedPtr = NULL;
++        STACK_OF(X509)* signers = NULL;
++        X509* reportedSigner = NULL;
++        byte* reportedSignerDer = NULL;
++        int   reportedSignerDerSz = 0;
++        X509* caForStore = NULL;
++        BIO*  caForStoreBio = NULL;
++
++        /* ---- Encode: signer=server-cert, extra bundle cert=ca. ---- */
++        ExpectNotNull(p7Enc = wc_PKCS7_New(HEAP_HINT, INVALID_DEVID));
++        ExpectIntEQ(wc_PKCS7_Init(p7Enc, HEAP_HINT, INVALID_DEVID), 0);
++        ExpectIntEQ(wc_PKCS7_InitWithCert(p7Enc, signerCertDer,
++                                          (word32)signerCertDerSz), 0);
++        /* wc_PKCS7_AddCertificate prepends to the cert list - the encoded
++         * SET therefore ends up [ca, signer], putting the actual signer
++         * at index 1 and exercising the sid-selection path (cert[0] is
++         * NOT the signer and must be skipped). */
++        ExpectIntEQ(wc_PKCS7_AddCertificate(p7Enc, caDer, (word32)caDerSz), 0);
++
++        if (p7Enc != NULL) {
++            p7Enc->content      = (byte*)content;
++            p7Enc->contentSz    = (word32)sizeof(content);
++            p7Enc->encryptOID   = RSAk;
++            p7Enc->hashOID      = SHA256h;
++            p7Enc->privateKey   = signerKey;
++            p7Enc->privateKeySz = (word32)signerKeySz;
++            p7Enc->rng          = &rng;
++        }
++
++        ExpectIntEQ(wc_PKCS7_SetSignerIdentifierType(p7Enc, sidTypes[variant]),
++                    0);
++
++        ExpectIntGT((encodedSz = wc_PKCS7_EncodeSignedData(p7Enc, encoded,
++                                                           sizeof(encoded))),
++                    0);
++        wc_PKCS7_Free(p7Enc);
++        p7Enc = NULL;
++
++        /* ---- Parse + verify through the OpenSSL compat layer. ---- */
++        encodedPtr = encoded;
++        ExpectNotNull(p7Ver = d2i_PKCS7(NULL, &encodedPtr, encodedSz));
++
++        /* Trust store holds only ca-cert. Reload it rather than reusing
++         * caX509, since X509_STORE_free takes ownership-like semantics. */
++        ExpectNotNull(caForStoreBio = BIO_new_file(caFile, "r"));
++        ExpectNotNull(caForStore = PEM_read_bio_X509(caForStoreBio, NULL, 0,
++                                                    NULL));
++        ExpectNotNull(store = X509_STORE_new());
++        ExpectIntEQ(X509_STORE_add_cert(store, caForStore), 1);
++
++        ExpectIntEQ(PKCS7_verify(p7Ver, NULL, store, NULL, NULL, 0), 1);
++
++        /* Snapshot the singleCert / verifyCert pointers and sizes after
++         * PKCS7_verify has finished re-parsing the message. A buggy
++         * implementation that passes &p7->pkcs7.singleCert (or verifyCert)
++         * directly to wolfSSL_d2i_X509 permanently advances the struct
++         * field, which corrupts it for any subsequent use - producing a
++         * heap-OOB read on the next call since the size isn't advanced.
++         * These pointers must stay exactly where they are across repeated
++         * get0_signers calls. */
++        if (p7Ver != NULL) {
++            wc_PKCS7* wcP7 = &((WOLFSSL_PKCS7*)p7Ver)->pkcs7;
++            byte*  singleBefore    = wcP7->singleCert;
++            word32 singleSzBefore  = wcP7->singleCertSz;
++            byte*  verifyBefore    = wcP7->verifyCert;
++            word32 verifySzBefore  = wcP7->verifyCertSz;
++            int    i;
++
++            /* Call get0_signers repeatedly. Each invocation must return
++             * the correct cert and must not mutate singleCert/verifyCert.
++             * Three iterations so the "second call reads past the end"
++             * pattern (the exact OOB the reporter hit) is exercised. */
++            for (i = 0; i < 3; i++) {
++                ExpectNotNull(signers = PKCS7_get0_signers(p7Ver, NULL, 0));
++                ExpectIntEQ(sk_X509_num(signers), 1);
++                ExpectNotNull(reportedSigner = sk_X509_value(signers, 0));
++                ExpectIntGT(reportedSignerDerSz = i2d_X509(reportedSigner,
++                                                      &reportedSignerDer), 0);
++                /* DER-compare: reportedSigner must equal server-cert and
++                 * must NOT equal ca-cert (the pre-fix signer-confusion
++                 * outcome). */
++                ExpectIntEQ(reportedSignerDerSz, signerCertDerSz);
++                if (reportedSignerDer != NULL && signerCertDer != NULL) {
++                    ExpectIntEQ(XMEMCMP(reportedSignerDer, signerCertDer,
++                                        (size_t)signerCertDerSz), 0);
++                    if (reportedSignerDerSz == caDerSz) {
++                        ExpectIntNE(XMEMCMP(reportedSignerDer, caDer,
++                                            (size_t)caDerSz), 0);
++                    }
++                }
++                XFREE(reportedSignerDer, NULL, DYNAMIC_TYPE_OPENSSL);
++                reportedSignerDer = NULL;
++                sk_X509_pop_free(signers, NULL);
++                signers = NULL;
++
++                /* Struct fields must survive every call unchanged. */
++                ExpectPtrEq(wcP7->singleCert,   singleBefore);
++                ExpectIntEQ(wcP7->singleCertSz, singleSzBefore);
++                ExpectPtrEq(wcP7->verifyCert,   verifyBefore);
++                ExpectIntEQ(wcP7->verifyCertSz, verifySzBefore);
++            }
++        }
++
++        PKCS7_free(p7Ver);
++        X509_STORE_free(store);
++        X509_free(caForStore);
++        BIO_free(caForStoreBio);
++    }
++
++    if (rngInited)
++        wc_FreeRng(&rng);
++
++    XFREE(signerKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
++    XFREE(signerCertDer, NULL, DYNAMIC_TYPE_OPENSSL);
++    XFREE(caDer, NULL, DYNAMIC_TYPE_OPENSSL);
++    X509_free(signerCertX509);
++    X509_free(caX509);
++    BIO_free(signerCertBio);
++    BIO_free(caBio);
++#endif
++    return EXPECT_RESULT();
++}
++
+ int test_wolfSSL_PKCS7_SIGNED_new(void)
+ {
+     EXPECT_DECLS;
+diff --git a/tests/api/test_ossl_p7p12.h b/tests/api/test_ossl_p7p12.h
+index 58aa9dd12..6704ab51e 100644
+--- a/tests/api/test_ossl_p7p12.h
++++ b/tests/api/test_ossl_p7p12.h
+@@ -27,6 +27,8 @@
+ int test_wolfssl_PKCS7(void);
+ int test_wolfSSL_PKCS7_certs(void);
+ int test_wolfSSL_PKCS7_sign(void);
++int test_wolfSSL_PKCS7_verify_signer_forgery(void);
++int test_wolfSSL_PKCS7_verify_sid_binding(void);
+ int test_wolfSSL_PKCS7_SIGNED_new(void);
+ int test_wolfSSL_PEM_write_bio_PKCS7(void);
+ int test_wolfSSL_PEM_write_bio_encryptedKey(void);
+@@ -38,6 +40,8 @@ int test_wolfSSL_PKCS12(void);
+     TEST_DECL_GROUP("ossl_p7", test_wolfssl_PKCS7),                         \
+     TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_certs),                   \
+     TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_sign),                    \
++    TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_verify_signer_forgery),   \
++    TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_verify_sid_binding),      \
+     TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PKCS7_SIGNED_new),              \
+     TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PEM_write_bio_PKCS7),           \
+     TEST_DECL_GROUP("ossl_p7", test_wolfSSL_PEM_write_bio_encryptedKey),    \
+diff --git a/tests/api/test_pkcs7.c b/tests/api/test_pkcs7.c
+index 3c8b59fb8..69b463160 100644
+--- a/tests/api/test_pkcs7.c
++++ b/tests/api/test_pkcs7.c
+@@ -1118,6 +1118,229 @@ int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void)
+ #endif
+ 
+ 
++/*
++ * Bleichenbacher padding-oracle regression: wc_PKCS7_DecryptKtri must not
++ * return a distinguishable error when RSA PKCS#1 v1.5 unwrap of the
++ * encrypted CEK fails vs. when it succeeds with a wrong key. The
++ * mitigation substitutes a deterministic pseudo-random CEK on RSA failure
++ * so content decryption fails indistinguishably. This test corrupts the
++ * encryptedKey in a valid EnvelopedData and asserts the error matches
++ * content corruption rather than surfacing an RSA/recipient-level code.
++ * Runs for AES-128 and AES-256 because the fake CEK is a fixed 32 bytes:
++ * AES-128 (key size 16) exercises the path where the fake size differs
++ * from the real CEK size.
++ */
++#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
++    !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
++    defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
++    !defined(WOLFSSL_NO_MALLOC) && \
++    (defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
++     !defined(NO_FILESYSTEM))
++static int pkcs7_ktri_bad_pad_case(int encryptOID, byte* rsaCert,
++                                   word32 rsaCertSz, byte* rsaPrivKey,
++                                   word32 rsaPrivKeySz, byte* encrypted,
++                                   word32 encryptedCap, byte* decoded,
++                                   word32 decodedCap)
++{
++    EXPECT_DECLS;
++    PKCS7* pkcs7 = NULL;
++    byte   data[] = "PKCS7 KTRI bad-RSA-padding regression payload.";
++    int    encryptedSz = 0;
++    int    badKeyRet = 0;
++    int    badContentRet = 0;
++    byte   savedKeyByte = 0;
++    byte   savedContentByte = 0;
++    word32 i;
++    word32 encryptedKeyOff = 0;
++    static const byte rsaEncOid[] = {
++        0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
++        0x01, 0x01, 0x01
++    };
++
++    ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
++    ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
++    if (pkcs7 != NULL) {
++        pkcs7->content    = data;
++        pkcs7->contentSz  = (word32)sizeof(data);
++        pkcs7->contentOID = DATA;
++        pkcs7->encryptOID = encryptOID;
++    }
++    ExpectIntGT(encryptedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7,
++                    encrypted, encryptedCap), 0);
++    wc_PKCS7_Free(pkcs7);
++    pkcs7 = NULL;
++
++    /* Locate the KTRI encryptedKey OCTET STRING. After the rsaEncryption
++     * OID there are NULL algorithm parameters (05 00), then a 256-byte
++     * OCTET STRING (tag 04, long-form length 82 01 00 for RSA-2048). */
++    for (i = 0; (int)(i + sizeof(rsaEncOid)) < encryptedSz; i++) {
++        if (XMEMCMP(&encrypted[i], rsaEncOid, sizeof(rsaEncOid)) == 0) {
++            word32 p = i + (word32)sizeof(rsaEncOid);
++            if (p + 2 < (word32)encryptedSz &&
++                encrypted[p] == 0x05 && encrypted[p + 1] == 0x00) {
++                p += 2;
++            }
++            if (p + 4 < (word32)encryptedSz && encrypted[p] == 0x04) {
++                if (encrypted[p + 1] == 0x82) {
++                    encryptedKeyOff = p + 4;
++                }
++                else if (encrypted[p + 1] == 0x81) {
++                    encryptedKeyOff = p + 3;
++                }
++                else {
++                    encryptedKeyOff = p + 2;
++                }
++            }
++            break;
++        }
++    }
++    ExpectIntGT(encryptedKeyOff, 0);
++    ExpectIntLT(encryptedKeyOff + 32, (word32)encryptedSz);
++
++    /* Case 1: corrupt a byte inside the RSA ciphertext, decode, restore. */
++    savedKeyByte = encrypted[encryptedKeyOff + 16];
++    encrypted[encryptedKeyOff + 16] ^= 0xA5;
++
++    ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
++    ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
++    if (pkcs7 != NULL) {
++        pkcs7->privateKey   = rsaPrivKey;
++        pkcs7->privateKeySz = rsaPrivKeySz;
++    }
++    badKeyRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted,
++                    (word32)encryptedSz, decoded, decodedCap);
++    wc_PKCS7_Free(pkcs7);
++    pkcs7 = NULL;
++    encrypted[encryptedKeyOff + 16] = savedKeyByte;
++
++    /* Case 2: corrupt a byte in the second-to-last AES ciphertext block.
++     * In CBC mode this deterministically XOR-flips the corresponding byte
++     * in the last plaintext block, invalidating the PKCS#7 padding
++     * (original pad byte 0x01 becomes 0x01^0xA5 = 0xA4 > blockSz).
++     * Corrupting the last ciphertext block directly would randomize the
++     * entire last plaintext block, giving ~1/256 chance of accidentally
++     * valid padding and intermittent test failures. */
++    savedContentByte = encrypted[encryptedSz - 17];
++    encrypted[encryptedSz - 17] ^= 0xA5;
++
++    ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
++    ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, rsaCert, rsaCertSz), 0);
++    if (pkcs7 != NULL) {
++        pkcs7->privateKey   = rsaPrivKey;
++        pkcs7->privateKeySz = rsaPrivKeySz;
++    }
++    badContentRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, encrypted,
++                    (word32)encryptedSz, decoded, decodedCap);
++    wc_PKCS7_Free(pkcs7);
++    pkcs7 = NULL;
++    encrypted[encryptedSz - 17] = savedContentByte;
++
++    /* Case 2 must always fail: the CBC-chain corruption deterministically
++     * invalidates the PKCS#7 padding. */
++    ExpectIntLT(badContentRet, 0);
++    /* Bad-key must NOT leak as an RSA- or recipient-level error. */
++    ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(PKCS7_RECIP_E));
++    ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_PAD_E));
++    ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(RSA_BUFFER_E));
++    ExpectIntNE(badKeyRet, WC_NO_ERR_TRACE(BAD_PADDING_E));
++    /* Case 1 (bad RSA key) decrypts content with a random fake CEK,
++     * producing fully random plaintext.  With ~1/256 probability the
++     * PKCS#7 padding accidentally looks valid, causing a positive
++     * garbage-length return instead of an error.  This does not leak
++     * RSA key information, so it is acceptable.  When both cases do
++     * fail, verify they fail at the same content-decryption layer. */
++    if (badKeyRet < 0) {
++        ExpectIntEQ(badKeyRet, badContentRet);
++    }
++
++    return EXPECT_RESULT();
++}
++
++int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void)
++{
++    EXPECT_DECLS;
++    byte   encrypted[FOURK_BUF];
++    byte   decoded[FOURK_BUF];
++    byte*  rsaCert = NULL;
++    byte*  rsaPrivKey = NULL;
++    word32 rsaCertSz = 0;
++    word32 rsaPrivKeySz = 0;
++#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048) && \
++    !defined(NO_FILESYSTEM)
++    XFILE f = XBADFILE;
++#endif
++
++    /* Load RSA cert and key */
++#if defined(USE_CERT_BUFFERS_1024)
++    rsaCertSz = (word32)sizeof_client_cert_der_1024;
++    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaCert != NULL)
++        XMEMCPY(rsaCert, client_cert_der_1024, rsaCertSz);
++    rsaPrivKeySz = (word32)sizeof_client_key_der_1024;
++    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaPrivKey != NULL)
++        XMEMCPY(rsaPrivKey, client_key_der_1024, rsaPrivKeySz);
++#elif defined(USE_CERT_BUFFERS_2048)
++    rsaCertSz = (word32)sizeof_client_cert_der_2048;
++    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaCert != NULL)
++        XMEMCPY(rsaCert, client_cert_der_2048, rsaCertSz);
++    rsaPrivKeySz = (word32)sizeof_client_key_der_2048;
++    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    if (rsaPrivKey != NULL)
++        XMEMCPY(rsaPrivKey, client_key_der_2048, rsaPrivKeySz);
++#elif !defined(NO_FILESYSTEM)
++    rsaCertSz = FOURK_BUF;
++    ExpectNotNull(rsaCert = (byte*)XMALLOC(rsaCertSz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    ExpectTrue((f = XFOPEN("./certs/client-cert.der", "rb")) != XBADFILE);
++    ExpectTrue((rsaCertSz = (word32)XFREAD(rsaCert, 1, rsaCertSz, f)) > 0);
++    if (f != XBADFILE) {
++        XFCLOSE(f);
++        f = XBADFILE;
++    }
++    rsaPrivKeySz = FOURK_BUF;
++    ExpectNotNull(rsaPrivKey = (byte*)XMALLOC(rsaPrivKeySz, HEAP_HINT,
++        DYNAMIC_TYPE_TMP_BUFFER));
++    ExpectTrue((f = XFOPEN("./certs/client-key.der", "rb")) != XBADFILE);
++    ExpectTrue((rsaPrivKeySz = (word32)XFREAD(rsaPrivKey, 1,
++        rsaPrivKeySz, f)) > 0);
++    if (f != XBADFILE)
++        XFCLOSE(f);
++#endif
++
++    if (rsaCert == NULL || rsaPrivKey == NULL) {
++        XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++        XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++        return TEST_SKIPPED;
++    }
++
++    /* AES-128: 32-byte fake CEK larger than real CEK size (16 bytes). */
++    ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES128CBCb, rsaCert, rsaCertSz,
++                rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
++                decoded, sizeof(decoded)), TEST_SUCCESS);
++#ifdef WOLFSSL_AES_192
++    /* AES-192: fake CEK (32) vs real CEK (24) - another size mismatch. */
++    ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES192CBCb, rsaCert, rsaCertSz,
++                rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
++                decoded, sizeof(decoded)), TEST_SUCCESS);
++#endif
++    /* AES-256: fake CEK size matches real CEK size (32 bytes). */
++    ExpectIntEQ(pkcs7_ktri_bad_pad_case(AES256CBCb, rsaCert, rsaCertSz,
++                rsaPrivKey, rsaPrivKeySz, encrypted, sizeof(encrypted),
++                decoded, sizeof(decoded)), TEST_SUCCESS);
++
++    XFREE(rsaCert, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++    XFREE(rsaPrivKey, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++    return EXPECT_RESULT();
++} /* END test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad */
++#endif
++
++
+ /*
+  * Testing wc_PKCS7_EncodeSignedData_ex() and wc_PKCS7_VerifySignedData_ex()
+  */
+@@ -2397,7 +2620,8 @@ static int myCEKwrapFunc(PKCS7* pkcs7, byte* cek, word32 cekSz, byte* keyId,
+           HAVE_AES_KEYWRAP */
+ 
+ 
+-#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA)
++#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) && \
++    !defined(NO_PKCS7_STREAM)
+ #define MAX_TEST_DECODE_SIZE 6000
+ static int test_wc_PKCS7_DecodeEnvelopedData_stream_decrypt_cb(wc_PKCS7* pkcs7,
+     const byte* output, word32 outputSz, void* ctx) {
+@@ -2430,7 +2654,8 @@ static int test_wc_PKCS7_DecodeEnvelopedData_stream_decrypt_cb(wc_PKCS7* pkcs7,
+ int test_wc_PKCS7_DecodeEnvelopedData_stream(void)
+ {
+     EXPECT_DECLS;
+-#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA)
++#if defined(HAVE_PKCS7) && defined(ASN_BER_TO_DER) && !defined(NO_RSA) && \
++    !defined(NO_PKCS7_STREAM)
+     PKCS7*      pkcs7 = NULL;
+     int ret = 0;
+     XFILE f = XBADFILE;
+@@ -2486,6 +2711,72 @@ int test_wc_PKCS7_DecodeEnvelopedData_stream(void)
+ } /* END test_wc_PKCS7_DecodeEnvelopedData_stream() */
+ 
+ 
++/*
++ * Regression test: a PKCS#7 EnvelopedData with a forged RecipientInfo SET
++ * length (parsed via GetSet_ex with NO_USER_CHECK) must not drive an
++ * uncapped heap allocation through wc_PKCS7_GrowStream(). The decoder
++ * must reject the oversized allocation rather than attempting it.
++ */
++int test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen(void)
++{
++    EXPECT_DECLS;
++#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_PKCS7_STREAM)
++    /* Crafted ContentInfo/EnvelopedData header. All lengths use the
++     * 4-byte long form for clarity. The RecipientInfo SET length is
++     * forged to 0x01000001 (16 MB + 1), which exceeds the default
++     * WOLFSSL_PKCS7_MAX_STREAM_ALLOC cap and should be rejected before
++     * any allocation succeeds. The body after the SET header is never
++     * consumed because the decoder fails at the GrowStream() cap. */
++    static const byte forged[] = {
++        /* ContentInfo SEQUENCE, body length 0x01000021 */
++        0x30, 0x84, 0x01, 0x00, 0x00, 0x21,
++        /* OID 1.2.840.113549.1.7.3 (id-envelopedData) */
++        0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
++        0x01, 0x07, 0x03,
++        /* [0] EXPLICIT content, body length 0x01000016 */
++        0xA0, 0x84, 0x01, 0x00, 0x00, 0x16,
++        /* EnvelopedData SEQUENCE, body length 0x01000010 */
++        0x30, 0x84, 0x01, 0x00, 0x00, 0x10,
++        /* version INTEGER 0 */
++        0x02, 0x01, 0x00,
++        /* Forged RecipientInfo SET header: length = 0x01000001 */
++        0x31, 0x84, 0x01, 0x00, 0x00, 0x01,
++        /* Padding so that header-parsing states can buffer their
++         * required lookahead without returning WC_PKCS7_WANT_READ_E.
++         * These bytes are never interpreted. */
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
++        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
++    };
++    PKCS7* pkcs7 = NULL;
++    byte   out[32];
++    int    ret;
++
++    ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
++    ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)client_cert_der_2048,
++        sizeof_client_cert_der_2048), 0);
++    ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)client_key_der_2048,
++        sizeof_client_key_der_2048), 0);
++
++    ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, (byte*)forged,
++        (word32)sizeof(forged), out, (word32)sizeof(out));
++    /* Must NOT return WC_PKCS7_WANT_READ_E (which would imply the
++     * oversized allocation succeeded and the decoder is waiting for
++     * the around 16 MB of SET body). Must NOT return 0 / positive length.
++     * Expected: BUFFER_E from the GrowStream cap. */
++    ExpectIntEQ(ret, WC_NO_ERR_TRACE(BUFFER_E));
++
++    wc_PKCS7_Free(pkcs7);
++#endif
++    return EXPECT_RESULT();
++} /* END test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen() */
++
++
+ /*
+  * Testing wc_PKCS7_DecodeEnvelopedData with streaming
+  */
+@@ -2501,6 +2792,8 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
+                                  bytes */
+     size_t testDerBufferSz = 0;
+     byte decodedData[8192];
++    byte serverDecodedData[8192];
++    int  serverRet = 0;
+ 
+     ExpectTrue((f = XFOPEN(testFile, "rb")) != XBADFILE);
+     if (f != XBADFILE) {
+@@ -2520,12 +2813,13 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
+         ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)server_key_der_2048,
+             sizeof_server_key_der_2048), 0);
+ 
+-        ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
+-            (word32)testDerBufferSz, decodedData, sizeof(decodedData));
++        serverRet = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
++            (word32)testDerBufferSz, serverDecodedData,
++            sizeof(serverDecodedData));
+     #if defined(NO_AES) || defined(NO_AES_256)
+-        ExpectIntEQ(ret, ALGO_ID_E);
++        ExpectIntEQ(serverRet, ALGO_ID_E);
+     #else
+-        ExpectIntGT(ret, 0);
++        ExpectIntGT(serverRet, 0);
+     #endif
+         wc_PKCS7_Free(pkcs7);
+         pkcs7 = NULL;
+@@ -2551,7 +2845,14 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
+         pkcs7 = NULL;
+     }
+ 
+-    /* test with ca cert recipient (which should fail) */
++    /* Test with ca cert recipient. The ca cert is not a listed recipient,
++     * so RSA unwrap fails. The Bleichenbacher mitigation substitutes a
++     * pseudo-random fake CEK on unwrap failure, so the call normally
++     * returns a negative error when content decryption rejects the
++     * resulting garbage padding - but around 1/256 of the time the random
++     * CEK yields plaintext with accidentally-valid PKCS#7 padding and the
++     * call returns a non-negative "decrypted" size. That case must not
++     * produce the real plaintext. */
+     ExpectNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, testDevId));
+     if (pkcs7) {
+         ExpectIntEQ(wc_PKCS7_InitWithCert(pkcs7, (byte*)ca_cert_der_2048,
+@@ -2560,9 +2861,15 @@ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void)
+         ExpectIntEQ(wc_PKCS7_SetKey(pkcs7, (byte*)ca_key_der_2048,
+             sizeof_ca_key_der_2048), 0);
+ 
++        XMEMSET(decodedData, 0, sizeof(decodedData));
+         ret = wc_PKCS7_DecodeEnvelopedData(pkcs7, testDerBuffer,
+             (word32)testDerBufferSz, decodedData, sizeof(decodedData));
+-        ExpectIntLT(ret, 0);
++    #if defined(NO_AES) || defined(NO_AES_256)
++        ExpectIntEQ(ret, ALGO_ID_E);
++    #else
++        ExpectTrue(ret < 0 || ret != serverRet ||
++                   XMEMCMP(decodedData, serverDecodedData, (size_t)ret) != 0);
++    #endif
+         wc_PKCS7_Free(pkcs7);
+         pkcs7 = NULL;
+     }
+@@ -2579,7 +2886,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
+     EXPECT_DECLS;
+ #if defined(HAVE_PKCS7)
+     PKCS7*      pkcs7 = NULL;
+-#ifdef ASN_BER_TO_DER
++#if defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM)
+     int encodedSz = 0;
+ #endif
+ #ifdef ECC_TIMING_RESISTANT
+@@ -2761,6 +3068,11 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
+                 AES128CBCb, AES128_WRAP, dhSinglePass_stdDH_sha1kdf_scheme,
+                 eccCert, eccCertSz, eccPrivKey, eccPrivKeySz},
+         #endif
++        #if defined(WOLFSSL_SHA224) && defined(WOLFSSL_AES_128)
++            {(byte*)input, (word32)(sizeof(input)/sizeof(char)), DATA,
++                AES128CBCb, AES128_WRAP, dhSinglePass_stdDH_sha224kdf_scheme,
++                eccCert, eccCertSz, eccPrivKey, eccPrivKeySz},
++        #endif
+         #if !defined(NO_SHA256) && defined(WOLFSSL_AES_256)
+             {(byte*)input, (word32)(sizeof(input)/sizeof(char)), DATA,
+                 AES256CBCb, AES256_WRAP, dhSinglePass_stdDH_sha256kdf_scheme,
+@@ -2784,7 +3096,7 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
+ 
+     testSz = (int)sizeof(testVectors)/(int)sizeof(pkcs7EnvelopedVector);
+     for (i = 0; i < testSz; i++) {
+-    #ifdef ASN_BER_TO_DER
++    #if defined(ASN_BER_TO_DER) && !defined(NO_PKCS7_STREAM)
+         encodeSignedDataStream strm;
+ 
+         /* test setting stream mode, the first one using IO callbacks */
+@@ -2950,17 +3262,11 @@ int test_wc_PKCS7_EncodeDecodeEnvelopedData(void)
+         pkcs7->singleCert = NULL;
+     }
+   #ifndef NO_RSA
+-    #if defined(NO_PKCS7_STREAM)
+-    /* when none streaming mode is used and PKCS7 is in bad state buffer error
+-     * is returned from kari parse which gets set to bad func arg */
+-    ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, output,
+-        (word32)sizeof(output), decoded, (word32)sizeof(decoded)),
+-        WC_NO_ERR_TRACE(BAD_FUNC_ARG));
+-    #else
++    /* With corrupted singleCert, decode should fail with a parse error.
++     * State is properly reset on error so re-decode starts from scratch. */
+     ExpectIntEQ(wc_PKCS7_DecodeEnvelopedData(pkcs7, output,
+         (word32)sizeof(output), decoded, (word32)sizeof(decoded)),
+         WC_NO_ERR_TRACE(ASN_PARSE_E));
+-    #endif
+   #endif /* !NO_RSA */
+     if (pkcs7 != NULL) {
+         pkcs7->singleCert = tmpBytePtr;
+@@ -3991,7 +4297,8 @@ int test_wc_PKCS7_Degenerate(void)
+ } /* END test_wc_PKCS7_Degenerate() */
+ 
+ #if defined(HAVE_PKCS7) && !defined(NO_FILESYSTEM) && \
+-    defined(ASN_BER_TO_DER) && !defined(NO_DES3) && !defined(NO_SHA)
++    defined(ASN_BER_TO_DER) && !defined(NO_DES3) && !defined(NO_SHA) && \
++    !defined(NO_PKCS7_STREAM)
+ static byte berContent[] = {
+     0x30, 0x80, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
+     0xF7, 0x0D, 0x01, 0x07, 0x03, 0xA0, 0x80, 0x30,
+@@ -4182,7 +4489,7 @@ static byte berContent[] = {
+     0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ #endif /* HAVE_PKCS7 && !NO_FILESYSTEM && ASN_BER_TO_DER &&
+-        * !NO_DES3 && !NO_SHA
++        * !NO_DES3 && !NO_SHA && !NO_PKCS7_STREAM
+         */
+ 
+ /*
+@@ -4197,7 +4504,7 @@ int test_wc_PKCS7_BER(void)
+     char   fName[] = "./certs/test-ber-exp02-05-2022.p7b";
+     XFILE  f = XBADFILE;
+     byte   der[4096];
+-#ifndef NO_DES3
++#if !defined(NO_DES3) && !defined(NO_PKCS7_STREAM)
+     byte   decoded[2048];
+ #endif
+     word32 derSz = 0;
+@@ -4242,8 +4549,9 @@ int test_wc_PKCS7_BER(void)
+     wc_PKCS7_Free(pkcs7);
+     pkcs7 = NULL;
+ 
+-#ifndef NO_DES3
+-    /* decode BER content */
++#if !defined(NO_DES3) && !defined(NO_PKCS7_STREAM)
++    /* decode BER content - requires PKCS7 streaming to handle indefinite
++     * length encoding in the EnvelopedData structure */
+     ExpectTrue((f = XFOPEN("./certs/1024/client-cert.der", "rb")) != XBADFILE);
+     ExpectTrue((derSz = (word32)XFREAD(der, 1, sizeof(der), f)) > 0);
+     if (f != XBADFILE) {
+@@ -4280,7 +4588,7 @@ int test_wc_PKCS7_BER(void)
+         sizeof(berContent), decoded, sizeof(decoded)), WC_NO_ERR_TRACE(NOT_COMPILED_IN));
+ #endif
+     wc_PKCS7_Free(pkcs7);
+-#endif /* !NO_DES3 */
++#endif /* !NO_DES3 && !NO_PKCS7_STREAM */
+ #endif
+     return EXPECT_RESULT();
+ } /* END test_wc_PKCS7_BER() */
+diff --git a/tests/api/test_pkcs7.h b/tests/api/test_pkcs7.h
+index 084744d43..f4aed161d 100644
+--- a/tests/api/test_pkcs7.h
++++ b/tests/api/test_pkcs7.h
+@@ -38,6 +38,14 @@ int test_wc_PKCS7_EncodeSignedData_RSA_PSS(void);
+     !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_256)
+ int test_wc_PKCS7_EnvelopedData_KTRI_RSA_PSS(void);
+ #endif
++#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
++    !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
++    defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
++    !defined(WOLFSSL_NO_MALLOC) && \
++    (defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
++     !defined(NO_FILESYSTEM))
++int test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad(void);
++#endif
+ int test_wc_PKCS7_EncodeSignedData_ex(void);
+ int test_wc_PKCS7_VerifySignedData_RSA(void);
+ int test_wc_PKCS7_VerifySignedData_ECC(void);
+@@ -57,6 +65,7 @@ int test_wc_PKCS7_SetOriEncryptCtx(void);
+ int test_wc_PKCS7_SetOriDecryptCtx(void);
+ int test_wc_PKCS7_DecodeCompressedData(void);
+ int test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients(void);
++int test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen(void);
+ int test_wc_PKCS7_VerifySignedData_PKCS7ContentSeq(void);
+ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
+ 
+@@ -82,6 +91,18 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
+ #define TEST_PKCS7_RSA_PSS_ED_DECL
+ #endif
+ 
++#if defined(HAVE_PKCS7) && !defined(NO_RSA) && !defined(NO_SHA256) && \
++    !defined(NO_AES) && defined(HAVE_AES_CBC) && defined(WOLFSSL_AES_128) && \
++    defined(WOLFSSL_AES_256) && !defined(NO_HMAC) && \
++    !defined(WOLFSSL_NO_MALLOC) && \
++    (defined(USE_CERT_BUFFERS_2048) || defined(USE_CERT_BUFFERS_1024) || \
++     !defined(NO_FILESYSTEM))
++#define TEST_PKCS7_KTRI_BADRSAPAD_DECL \
++    TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EnvelopedData_KTRI_BadRsaPad),
++#else
++#define TEST_PKCS7_KTRI_BADRSAPAD_DECL
++#endif
++
+ #define TEST_PKCS7_SIGNED_DATA_DECLS                                    \
+     TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_InitWithCert),            \
+     TEST_DECL_GROUP("pkcs7_sd", test_wc_PKCS7_EncodeData),              \
+@@ -100,6 +121,7 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_stream),  \
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeDecodeEnvelopedData),   \
+     TEST_PKCS7_RSA_PSS_ED_DECL                                              \
++    TEST_PKCS7_KTRI_BADRSAPAD_DECL                                          \
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetAESKeyWrapUnwrapCb),       \
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_GetEnvelopedDataKariRid),     \
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_EncodeEncryptedData),         \
+@@ -108,7 +130,8 @@ int test_wc_PKCS7_VerifySignedData_IndefLenOOB(void);
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeOneSymmetricKey),       \
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriEncryptCtx),            \
+     TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_SetOriDecryptCtx),            \
+-    TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients)
++    TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_multiple_recipients), \
++    TEST_DECL_GROUP("pkcs7_ed", test_wc_PKCS7_DecodeEnvelopedData_forgedRecipientSetLen)
+ 
+ #define TEST_PKCS7_SIGNED_ENCRYPTED_DATA_DECLS                              \
+     TEST_DECL_GROUP("pkcs7_sed", test_wc_PKCS7_signed_enveloped)
+diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c
+index 8df3a2430..f2c98efe5 100644
+--- a/wolfcrypt/src/pkcs7.c
++++ b/wolfcrypt/src/pkcs7.c
+@@ -44,6 +44,9 @@
+ 
+ #include <wolfssl/wolfcrypt/pkcs7.h>
+ #include <wolfssl/wolfcrypt/hash.h>
++#ifndef NO_HMAC
++    #include <wolfssl/wolfcrypt/hmac.h>
++#endif
+ #ifndef NO_RSA
+     #include <wolfssl/wolfcrypt/rsa.h>
+ #endif
+@@ -94,6 +97,7 @@ typedef enum {
+ /* holds information about the signers */
+ struct PKCS7SignerInfo {
+     int version;
++    int sidType;    /* CMS_ISSUER_AND_SERIAL_NUMBER or CMS_SKID */
+     byte  *sid;
+     word32 sidSz;
+ };
+@@ -109,6 +113,17 @@ struct PKCS7SignerInfo {
+ 
+ #ifndef NO_PKCS7_STREAM
+ 
++/* Hard upper bound on a single PKCS7 streaming buffer allocation. Guards
++ * wc_PKCS7_GrowStream against attacker-controlled ASN.1 lengths that were
++ * parsed with NO_USER_CHECK and would otherwise drive allocations up to
++ * around 2GB (e.g. via a forged RecipientInfo SET length). 16 MB is well above
++ * any legitimate RecipientInfo / encoded-attribute size but small enough
++ * that a forged length fails allocation on constrained targets and is
++ * rejected on larger ones. */
++#ifndef WOLFSSL_PKCS7_MAX_STREAM_ALLOC
++    #define WOLFSSL_PKCS7_MAX_STREAM_ALLOC (16 * 1024 * 1024)
++#endif
++
+ #define MAX_PKCS7_STREAM_BUFFER 256
+ struct PKCS7State {
+     byte* tmpCert;
+@@ -207,10 +222,15 @@ static void wc_PKCS7_ResetStream(wc_PKCS7* pkcs7)
+     #endif
+ 
+         /* free any buffers that may be allocated */
++        if (pkcs7->stream->aad != NULL && pkcs7->stream->aadSz > 0)
++            ForceZero(pkcs7->stream->aad, pkcs7->stream->aadSz);
+         XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(pkcs7->stream->tag, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(pkcs7->stream->nonce, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(pkcs7->stream->buffer, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++        /* stream->key is always allocated with MAX_ENCRYPTED_KEY_SZ */
++        if (pkcs7->stream->key != NULL)
++            ForceZero(pkcs7->stream->key, MAX_ENCRYPTED_KEY_SZ);
+         XFREE(pkcs7->stream->key, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         pkcs7->stream->aad    = NULL;
+         pkcs7->stream->tag    = NULL;
+@@ -265,6 +285,16 @@ static void wc_PKCS7_FreeStream(wc_PKCS7* pkcs7)
+ static int wc_PKCS7_GrowStream(wc_PKCS7* pkcs7, word32 newSz)
+ {
+     byte* pt;
++
++    /* Guard against attacker-controlled ASN.1 lengths reaching this
++     * allocation. Several callers parse lengths with NO_USER_CHECK and
++     * pass them here unvalidated (e.g. wc_PKCS7_ParseToRecipientInfoSet
++     * on a forged RecipientInfo SET header). */
++    if (newSz > WOLFSSL_PKCS7_MAX_STREAM_ALLOC) {
++        WOLFSSL_MSG("PKCS7 streaming allocation exceeds maximum");
++        return BUFFER_E;
++    }
++
+     pt = (byte*)XMALLOC(newSz, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+     if (pt == NULL) {
+         return MEMORY_E;
+@@ -4275,6 +4305,94 @@ int wc_PKCS7_SetEccSignRawDigestCb(wc_PKCS7* pkcs7, CallbackEccSignRawDigest cb)
+ #endif /* HAVE_ECC */
+ 
+ 
++#if !defined(NO_RSA) || defined(HAVE_ECC)
++/* Check whether the given decoded certificate matches the SignerIdentifier
++ * (sid) field of the currently parsed SignerInfo. Per RFC 5652 Section 5.3,
++ * the sid selects which certificate's public key must be used to verify the
++ * signature. Returns 1 on match, 0 on no match or when the sid is not
++ * available for comparison. */
++static int wc_PKCS7_CertMatchesSignerInfo(wc_PKCS7* pkcs7, DecodedCert* dCert)
++{
++    PKCS7SignerInfo* signerInfo;
++
++    if (pkcs7 == NULL || dCert == NULL)
++        return 0;
++
++    signerInfo = pkcs7->signerInfo;
++    if (signerInfo == NULL || signerInfo->sid == NULL ||
++            signerInfo->sidSz == 0) {
++        /* No SID parsed, cannot perform an identity binding check. */
++        return 0;
++    }
++
++    if (signerInfo->sidType == CMS_ISSUER_AND_SERIAL_NUMBER) {
++        /* IssuerAndSerialNumber: SID blob stores the content of the outer
++         * SEQUENCE (issuer Name followed by INTEGER serialNumber). */
++        word32 idx = 0;
++        byte sidIssuerHash[KEYID_SIZE];
++        WC_DECLARE_VAR(sidSerial, mp_int, 1, pkcs7->heap);
++        WC_DECLARE_VAR(certSerial, mp_int, 1, pkcs7->heap);
++        int cmp;
++        int match = 0;
++
++        if (GetNameHash_ex(signerInfo->sid, &idx, sidIssuerHash,
++                (int)signerInfo->sidSz, dCert->signatureOID) < 0) {
++            return 0;
++        }
++        if (XMEMCMP(sidIssuerHash, dCert->issuerHash, KEYID_SIZE) != 0)
++            return 0;
++
++        WC_ALLOC_VAR_EX(sidSerial, mp_int, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
++            { return 0; });
++        WC_ALLOC_VAR_EX(certSerial, mp_int, 1, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER,
++            { WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++              return 0; });
++
++        if (mp_init(sidSerial) != MP_OKAY) {
++            WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++            WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++            return 0;
++        }
++        if (mp_init(certSerial) != MP_OKAY) {
++            mp_clear(sidSerial);
++            WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++            WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++            return 0;
++        }
++
++        if (GetInt(sidSerial, signerInfo->sid, &idx, signerInfo->sidSz) == 0 &&
++                mp_read_unsigned_bin(certSerial, dCert->serial,
++                                     (word32)dCert->serialSz) == MP_OKAY) {
++            cmp = mp_cmp(sidSerial, certSerial);
++            if (cmp == MP_EQ)
++                match = 1;
++        }
++
++        mp_clear(sidSerial);
++        mp_clear(certSerial);
++        WC_FREE_VAR_EX(sidSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++        WC_FREE_VAR_EX(certSerial, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++        return match;
++    }
++    else if (signerInfo->sidType == CMS_SKID) {
++        /* SubjectKeyIdentifier: SID blob is the raw SKID octet string
++         * content. Normalize the same way the certificate side does so
++         * that comparisons between SHA-1 SKIDs and other lengths match. */
++        byte sidKid[KEYID_SIZE];
++
++        if (GetHashId(signerInfo->sid, (int)signerInfo->sidSz, sidKid,
++                      HashIdAlg(dCert->signatureOID)) != 0) {
++            return 0;
++        }
++        if (XMEMCMP(sidKid, dCert->extSubjKeyId, KEYID_SIZE) == 0)
++            return 1;
++        return 0;
++    }
++
++    return 0;
++}
++#endif /* !NO_RSA || HAVE_ECC */
++
+ #ifndef NO_RSA
+ 
+ /* returns size of signature put into out, negative on error */
+@@ -4354,6 +4472,31 @@ static int wc_PKCS7_RsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
+             continue;
+         }
+ 
++        /* If the SignerInfo sid was parsed, only try the certificate whose
++         * identity matches it. This binds the verifying public key to the
++         * signer identity advertised in the CMS message and prevents signer
++         * confusion when multiple certificates are embedded. */
++        if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL &&
++                !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) {
++            FreeDecodedCert(dCert);
++            wc_FreeRsaKey(key);
++            continue;
++        }
++
++        /* Defense in depth: the sid-matched cert must actually carry an
++         * RSA-family key before we feed its SPKI to the RSA key decoder.
++         * Rejecting here avoids depending on wc_RsaPublicKeyDecode to reject
++         * wrong-type SPKIs. */
++        if (dCert->keyOID != RSAk
++        #ifdef WC_RSA_PSS
++                && dCert->keyOID != RSAPSSk
++        #endif
++                ) {
++            FreeDecodedCert(dCert);
++            wc_FreeRsaKey(key);
++            continue;
++        }
++
+         if (wc_RsaPublicKeyDecode(dCert->publicKey, &scratch, key,
+                                   dCert->pubKeySize) < 0) {
+             WOLFSSL_MSG("ASN RSA key decode error");
+@@ -4464,6 +4607,24 @@ static int wc_PKCS7_RsaPssVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
+             continue;
+         }
+ 
++        /* Only try the certificate identified by the SignerInfo sid (see
++         * matching comment in wc_PKCS7_RsaVerify). */
++        if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL &&
++                !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) {
++            FreeDecodedCert(dCert);
++            wc_FreeRsaKey(key);
++            continue;
++        }
++
++        /* Defense in depth: reject non-RSA SPKIs before key decode. RSA
++         * rsaEncryption certs (keyOID=RSAk) are accepted for PSS signatures
++         * per RFC 8017 - a RSASSA-PSS cert is not required. */
++        if (dCert->keyOID != RSAk && dCert->keyOID != RSAPSSk) {
++            FreeDecodedCert(dCert);
++            wc_FreeRsaKey(key);
++            continue;
++        }
++
+         pkSz = dCert->pubKeySize;
+         if (pkSz > (MAX_RSA_INT_SZ + MAX_RSA_E_SZ))
+             pkSz = (MAX_RSA_INT_SZ + MAX_RSA_E_SZ);
+@@ -4629,6 +4790,22 @@ static int wc_PKCS7_EcdsaVerify(wc_PKCS7* pkcs7, byte* sig, int sigSz,
+             continue;
+         }
+ 
++        /* Only try the certificate identified by the SignerInfo sid (see
++         * matching comment in wc_PKCS7_RsaVerify). */
++        if (pkcs7->signerInfo != NULL && pkcs7->signerInfo->sid != NULL &&
++                !wc_PKCS7_CertMatchesSignerInfo(pkcs7, dCert)) {
++            FreeDecodedCert(dCert);
++            wc_ecc_free(key);
++            continue;
++        }
++
++        /* Defense in depth: reject non-ECDSA SPKIs before key decode. */
++        if (dCert->keyOID != ECDSAk) {
++            FreeDecodedCert(dCert);
++            wc_ecc_free(key);
++            continue;
++        }
++
+         if (wc_EccPublicKeyDecode(dCert->publicKey, &idx, key,
+                                   dCert->pubKeySize) < 0) {
+             WOLFSSL_MSG("ASN ECC key decode error");
+@@ -5337,11 +5514,16 @@ static int wc_PKCS7_ParseSignerInfo(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                 ret = ASN_PARSE_E;
+ 
+             if (ret == 0) {
++                pkcs7->signerInfo->sidType = CMS_ISSUER_AND_SERIAL_NUMBER;
+                 ret = wc_PKCS7_SignerInfoSetSID(pkcs7, in + idx, length);
+                 idx += (word32)length;
+             }
+ 
+         } else if (ret == 0 && version == 3) {
++            /* Default: SignerInfo version 3 carries SubjectKeyIdentifier.
++             * May be overridden below if the parser instead finds a
++             * SEQUENCE (IssuerAndSerialNumber fallback). */
++            pkcs7->signerInfo->sidType = CMS_SKID;
+             /* Get the sequence of SubjectKeyIdentifier */
+             if (idx + 1 > inSz)
+                 ret = BUFFER_E;
+@@ -5384,6 +5566,12 @@ static int wc_PKCS7_ParseSignerInfo(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+ 
+                     if (ret == 0 && GetSequence(in, &idx, &length, inSz) < 0)
+                         ret = ASN_PARSE_E;
++
++                    if (ret == 0) {
++                        /* v3 carrying IssuerAndSerialNumber fallback */
++                        pkcs7->signerInfo->sidType =
++                                CMS_ISSUER_AND_SERIAL_NUMBER;
++                    }
+                 }
+             }
+ 
+@@ -7029,6 +7217,9 @@ static int PKCS7_VerifySignedData(wc_PKCS7* pkcs7, const byte* hashBuf,
+ 
+                     idx += (word32)length;
+                 }
++                else if (ret == 0) {
++                    ret = ASN_PARSE_E;
++                }
+ 
+                 pkcs7->content = content;
+                 pkcs7->contentSz = (word32)contentSz;
+@@ -7721,6 +7912,9 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
+     secret = (byte*)XMALLOC(secretSz, kari->heap, DYNAMIC_TYPE_PKCS7);
+     if (secret == NULL)
+         return MEMORY_E;
++#ifdef WOLFSSL_CHECK_MEM_ZERO
++    wc_MemZero_Add("wc_PKCS7_KariGenerateKEK secret", secret, secretSz);
++#endif
+ 
+ #if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \
+     (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION != 2))) && \
+@@ -7756,6 +7950,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
+     }
+ 
+     if (ret != 0) {
++        ForceZero(secret, secretSz);
+         XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
+         return ret;
+     }
+@@ -7768,7 +7963,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
+             kdfType = WC_HASH_TYPE_SHA;
+             break;
+     #endif
+-    #ifndef WOLFSSL_SHA224
++    #ifdef WOLFSSL_SHA224
+         case dhSinglePass_stdDH_sha224kdf_scheme:
+             kdfType = WC_HASH_TYPE_SHA224;
+             break;
+@@ -7790,6 +7985,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
+     #endif
+         default:
+             WOLFSSL_MSG("Unsupported key agreement algorithm");
++            ForceZero(secret, secretSz);
+             XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
+             return BAD_FUNC_ARG;
+     };
+@@ -7802,6 +7998,7 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng,
+     ret = NOT_COMPILED_IN;
+ #endif
+ 
++    ForceZero(secret, secretSz);
+     XFREE(secret, kari->heap, DYNAMIC_TYPE_PKCS7);
+     return ret;
+ }
+@@ -9606,7 +9803,7 @@ static int wc_PKCS7_PwriKek_KeyUnWrap(wc_PKCS7* pkcs7, const byte* kek,
+     cekLen = outTmp[0];
+ 
+     /* verify length */
+-    fail |= ctMaskGT(cekLen, (int)inSz);
++    fail |= ctMaskGT(cekLen, (int)inSz - 4);
+     /* verify check bytes */
+     fail |= ctMaskNotEq((int)(outTmp[1] ^ outTmp[4]), 0xFF);
+     fail |= ctMaskNotEq((int)(outTmp[2] ^ outTmp[5]), 0xFF);
+@@ -9747,6 +9944,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
+                                     (word32)kekKeySz);
+     if (ret < 0) {
+         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++        ForceZero(kek, (word32)kekKeySz);
+         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         return ret;
+@@ -9758,6 +9956,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
+                                    tmpIv, (word32)kekBlockSz, encryptOID);
+     if (ret < 0) {
+         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++        ForceZero(kek, (word32)kekKeySz);
+         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         return ret;
+@@ -9782,6 +9981,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
+     ret = wc_SetContentType(PWRI_KEK_WRAP, keyEncAlgoId, sizeof(keyEncAlgoId));
+     if (ret <= 0) {
+         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++        ForceZero(kek, (word32)kekKeySz);
+         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         return ret;
+@@ -9813,6 +10013,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
+     ret = wc_SetContentType(kdfOID, kdfAlgoId, sizeof(kdfAlgoId));
+     if (ret <= 0) {
+         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++        ForceZero(kek, (word32)kekKeySz);
+         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         return ret;
+@@ -9838,6 +10039,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
+     if (totalSz > MAX_RECIP_SZ) {
+         WOLFSSL_MSG("CMS Recipient output buffer too small");
+         XFREE(recip, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++        ForceZero(kek, (word32)kekKeySz);
+         XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+         return BUFFER_E;
+@@ -9875,7 +10077,7 @@ int wc_PKCS7_AddRecipient_PWRI(wc_PKCS7* pkcs7, byte* passwd, word32 pLen,
+     XMEMCPY(recip->recip + idx, encryptedKey, encryptedKeySz);
+     idx += encryptedKeySz;
+ 
+-    ForceZero(kek, (word32)kekBlockSz);
++    ForceZero(kek, (word32)kekKeySz);
+     ForceZero(encryptedKey, encryptedKeySz);
+     XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+     XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+@@ -10580,6 +10782,81 @@ int wc_PKCS7_EncodeEnvelopedData(wc_PKCS7* pkcs7, byte* output, word32 outputSz)
+ }
+ 
+ #ifndef NO_RSA
++#if !defined(NO_HMAC) && !defined(NO_SHA256)
++/* Bleichenbacher padding-oracle mitigation for PKCS#7/CMS KTRI: produce a
++ * WC_SHA256_DIGEST_SIZE-byte pseudo-random CEK derived from a fresh
++ * random seed and the encrypted-key ciphertext. The output is random per
++ * call (driven by the RNG seed); deriving via HMAC of the ciphertext
++ * simply gives the same value within one call regardless of where it is
++ * referenced. Called unconditionally so the work is in the timing path
++ * regardless of RSA padding validity. */
++static int wc_PKCS7_KtriFakeCEK(wc_PKCS7* pkcs7, const byte* encryptedKey,
++                                word32 encryptedKeySz, byte* out)
++{
++    int ret;
++    byte seed[WC_SHA256_DIGEST_SIZE];
++    WC_RNG* rng = NULL;
++    int ownRng = 0;
++    WC_DECLARE_VAR(localRng, WC_RNG, 1, pkcs7->heap);
++    WC_DECLARE_VAR(hmac, Hmac, 1, pkcs7->heap);
++
++    if (pkcs7 == NULL || encryptedKey == NULL || out == NULL) {
++        return BAD_FUNC_ARG;
++    }
++
++    WC_ALLOC_VAR_EX(hmac, Hmac, 1, pkcs7->heap, DYNAMIC_TYPE_HMAC,
++                    return MEMORY_E);
++
++    /* Prefer a caller-provided RNG to avoid paying a DRBG init/reseed cost
++     * on every decrypt (and to keep the timing envelope flatter on FIPS /
++     * HW-RNG builds). Fall back to a one-shot RNG when pkcs7->rng is not
++     * set. */
++    if (pkcs7->rng != NULL) {
++        rng = pkcs7->rng;
++    }
++    else {
++        WC_ALLOC_VAR_EX(localRng, WC_RNG, 1, pkcs7->heap, DYNAMIC_TYPE_RNG,
++                        WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
++                        return MEMORY_E);
++        ret = wc_InitRng_ex(localRng, pkcs7->heap, pkcs7->devId);
++        if (ret != 0) {
++            WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG);
++            WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
++            return ret;
++        }
++        rng = localRng;
++        ownRng = 1;
++    }
++
++    ret = wc_RNG_GenerateBlock(rng, seed, (word32)sizeof(seed));
++
++    if (ownRng) {
++        wc_FreeRng(localRng);
++        WC_FREE_VAR_EX(localRng, pkcs7->heap, DYNAMIC_TYPE_RNG);
++    }
++
++    if (ret != 0) {
++        WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
++        return ret;
++    }
++
++    ret = wc_HmacInit(hmac, pkcs7->heap, pkcs7->devId);
++    if (ret == 0) {
++        ret = wc_HmacSetKey(hmac, WC_SHA256, seed, (word32)sizeof(seed));
++        if (ret == 0) {
++            ret = wc_HmacUpdate(hmac, encryptedKey, encryptedKeySz);
++        }
++        if (ret == 0) {
++            ret = wc_HmacFinal(hmac, out);
++        }
++        wc_HmacFree(hmac);
++    }
++    ForceZero(seed, sizeof(seed));
++    WC_FREE_VAR_EX(hmac, pkcs7->heap, DYNAMIC_TYPE_HMAC);
++    return ret;
++}
++#endif /* !NO_HMAC && !NO_SHA256 */
++
+ /* decode KeyTransRecipientInfo (ktri), return 0 on success, <0 on error */
+ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                                word32* idx, byte* decryptedKey,
+@@ -10596,7 +10873,9 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+     word32 pkiMsgSz = inSz;
+     byte   tag;
+ 
+-
++#ifndef WC_NO_RSA_OAEP
++    word32 outKeySz = 0;
++#endif
+ #ifndef NO_PKCS7_STREAM
+     word32 tmpIdx = *idx;
+ #endif
+@@ -10755,15 +11034,17 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                 if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
+                     return ASN_PARSE_E;
+ 
+-                if ((word32)keyIdSize > pkiMsgSz - (*idx))
++                /* Validate SKID container is within buffer */
++                if ((word32)length > pkiMsgSz - (*idx))
+                     return BUFFER_E;
+ 
+                 /* if we found correct recipient, SKID will match */
+-                if (XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId,
++                if (length == keyIdSize &&
++                        XMEMCMP(pkiMsg + (*idx), pkcs7->issuerSubjKeyId,
+                             (word32)keyIdSize) == 0) {
+                     *recipFound = 1;
+                 }
+-                (*idx) += (word32)keyIdSize;
++                (*idx) += (word32)length;
+             }
+ 
+             if (GetAlgoId(pkiMsg, idx, &encOID, oidKeyType, pkiMsgSz) < 0)
+@@ -10903,8 +11184,8 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             #ifndef WC_NO_RSA_OAEP
+                     }
+                     else {
+-                        word32 outLen = (word32)wc_RsaEncryptSize(privKey);
+-                        outKey = (byte*)XMALLOC(outLen, pkcs7->heap,
++                        outKeySz = (word32)wc_RsaEncryptSize(privKey);
++                        outKey = (byte*)XMALLOC(outKeySz, pkcs7->heap,
+                                                     DYNAMIC_TYPE_TMP_BUFFER);
+                         if (!outKey) {
+                             WOLFSSL_MSG("Failed to allocate out key buffer");
+@@ -10918,9 +11199,9 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                         }
+ 
+                         keySz = wc_RsaPrivateDecrypt_ex(encryptedKey,
+-                                (word32)encryptedKeySz, outKey, outLen, privKey,
+-                                WC_RSA_OAEP_PAD,
+-                                WC_HASH_TYPE_SHA, WC_MGF1SHA1, NULL, 0);
++                                    (word32)encryptedKeySz, outKey, outKeySz,
++                                    privKey, WC_RSA_OAEP_PAD, WC_HASH_TYPE_SHA,
++                                    WC_MGF1SHA1, NULL, 0);
+                     }
+             #endif
+                 }
+@@ -10935,30 +11216,153 @@ static int wc_PKCS7_DecryptKtri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             }
+             wc_FreeRsaKey(privKey);
+ 
++        #if !defined(NO_HMAC) && !defined(NO_SHA256)
++            {
++                /* Bleichenbacher padding-oracle mitigation: always compute
++                 * a pseudo-random fallback CEK so timing and error
++                 * behaviour do not depend on RSA padding validity. On
++                 * unwrap failure we substitute the fallback and let
++                 * content decryption fail indistinguishably from "unwrap
++                 * succeeded but CEK is wrong". */
++                byte fakeKey[WC_SHA256_DIGEST_SIZE];
++                int  fakeRet = wc_PKCS7_KtriFakeCEK(pkcs7, encryptedKey,
++                                                    (word32)encryptedKeySz,
++                                                    fakeKey);
++
++                if (fakeRet != 0) {
++                    /* Fallback generation failed (e.g. RNG/HMAC error).
++                     * Return the fallback-generation status, which does
++                     * not depend on RSA padding validity, rather than the
++                     * RSA status which would re-open the oracle. */
++                    ForceZero(fakeKey, sizeof(fakeKey));
++                    /* In the non-OAEP path RSA is decrypted in-place via
++                     * wc_RsaPrivateDecryptInline, so encryptedKey holds
++                     * the (possibly valid) plaintext CEK. Zero it before
++                     * free. */
++                    ForceZero(encryptedKey, (word32)encryptedKeySz);
++                    XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
++                    WC_FREE_VAR_EX(privKey, pkcs7->heap,
++                        DYNAMIC_TYPE_TMP_BUFFER);
++                #ifndef WC_NO_RSA_OAEP
++                    if (encOID == RSAESOAEPk) {
++                        if (outKey != NULL) {
++                            ForceZero(outKey, outKeySz);
++                            XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
++                        }
++                    }
++                #endif
++                    return fakeRet;
++                }
++
++                /* Constant-time select between fake and real CEK. On RSA
++                 * failure outKey may be NULL or keySz may be <= 0; in
++                 * both cases the mask selects fakeKey for every byte.
++                 *
++                 * To avoid data-dependent branches that leak realLen,
++                 * copy the real key into a fixed-size zero-padded buffer
++                 * first, then select byte-by-byte in constant time. */
++                {
++                    word32 i;
++                    byte   useFake;
++                    int    realLen = keySz;
++                    byte   realPad[WC_SHA256_DIGEST_SIZE];
++
++                    XMEMSET(realPad, 0, sizeof(realPad));
++                    /* Constant-time copy: avoid data-dependent branches
++                     * that could leak whether RSA padding was valid.
++                     * When outKey is NULL (inline RSA failure), use
++                     * encryptedKey as a safe readable source; the mask
++                     * will zero out all bytes anyway.  Both encryptedKey
++                     * and outKey (when non-NULL) are at least
++                     * sizeof(realPad) bytes for any RSA key size.
++                     *
++                     * Use constant-time pointer selection to avoid
++                     * branching on outKey nullity, which would leak
++                     * whether RSA PKCS#1 v1.5 padding was valid. */
++                    {
++                        byte haveSrc = ctMaskGTE(realLen, 1);
++                        const byte* srcTbl[2];
++                        const byte* src;
++                        word32 j = 0;
++                        word32 safeJ = 0;
++
++                        /* Select source without integer pointer synthesis.
++                         * Some safety-oriented compilers (e.g. Fil-C) treat
++                         * int-to-pointer reconstruction as a null-object
++                         * pointer on dereference. */
++                        srcTbl[0] = encryptedKey;
++                        srcTbl[1] = outKey;
++                        src = srcTbl[haveSrc & 1];
++
++                        /* safeJ is clamped to max(0, realLen-1): it
++                         * only advances while the next index would
++                         * still be inside realLen, so src[safeJ] is
++                         * always in bounds.  Bytes at j >= realLen are
++                         * masked to zero by inBounds anyway. */
++                        for (j = 0; j < (word32)sizeof(realPad); j++) {
++                            byte inBounds = ctMaskLT((int)j, realLen);
++                            byte advance = ctMaskLT((int)(safeJ + 1),
++                                                    realLen);
++                            realPad[j] = src[safeJ] & haveSrc & inBounds;
++                            safeJ += (word32)(advance & 1);
++                        }
++                    }
++                    useFake = ctMaskLT(realLen, 1); /* 0xFF if realLen<=0 */
++
++                    for (i = 0; i < (word32)sizeof(fakeKey); i++) {
++                        decryptedKey[i] = ctMaskSel(useFake, fakeKey[i],
++                                                    realPad[i]);
++                    }
++                    /* Report the real key size on success; on RSA
++                     * failure (realLen <= 0) report sizeof(fakeKey).
++                     * Constant-time select avoids branching on RSA
++                     * padding validity. */
++                    *decryptedKeySz = (word32)ctMaskSelInt(useFake,
++                                        (int)sizeof(fakeKey), realLen);
++                    ForceZero(realPad, sizeof(realPad));
++                }
++                ForceZero(fakeKey, sizeof(fakeKey));
++                /* In the non-OAEP path RSA is decrypted in-place via
++                 * wc_RsaPrivateDecryptInline, so encryptedKey holds the
++                 * plaintext CEK after the unwrap. Zero it before free. */
++                ForceZero(encryptedKey, (word32)encryptedKeySz);
++            }
++        #else /* NO_HMAC || NO_SHA256: mitigation unavailable */
++            #if !defined(WOLFSSL_NO_KTRI_ORACLE_WARNING)
++                #warning "PKCS7 KTRI Bleichenbacher mitigation requires HMAC " \
++                    "and SHA256; build without them leaves the RSA unwrap " \
++                    "error path observable to callers. " \
++                    "Define WOLFSSL_NO_KTRI_ORACLE_WARNING to silence."
++            #endif
++
+             if (keySz <= 0 || outKey == NULL) {
+                 ForceZero(encryptedKey, (word32)encryptedKeySz);
+                 XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
+                 WC_FREE_VAR_EX(privKey, pkcs7->heap,
+                     DYNAMIC_TYPE_TMP_BUFFER);
+-        #ifndef WC_NO_RSA_OAEP
++            #ifndef WC_NO_RSA_OAEP
+                 if (encOID == RSAESOAEPk) {
+                     if (outKey) {
++                        ForceZero(outKey, outKeySz);
+                         XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                     }
+                 }
+-        #endif
++            #endif
+                 return keySz;
+-            } else {
++            }
++            else {
+                 *decryptedKeySz = (word32)keySz;
+                 XMEMCPY(decryptedKey, outKey, (word32)keySz);
+                 ForceZero(encryptedKey, (word32)encryptedKeySz);
+             }
++        #endif /* !NO_HMAC && !NO_SHA256 */
+ 
+             XFREE(encryptedKey, pkcs7->heap, DYNAMIC_TYPE_WOLF_BIGINT);
+             WC_FREE_VAR_EX(privKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+         #ifndef WC_NO_RSA_OAEP
+             if (encOID == RSAESOAEPk) {
+                 if (outKey) {
++                    ForceZero(outKey, outKeySz);
+                     XFREE(outKey, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+                 }
+             }
+@@ -11040,6 +11444,14 @@ static int wc_PKCS7_KariGetOriginatorIdentifierOrKey(WC_PKCS7_KARI* kari,
+     if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
+         return ASN_PARSE_E;
+ 
++    /* BIT STRING must have at least unused-bits byte + 1 byte of content */
++    if (length < 2)
++        return ASN_PARSE_E;
++
++    /* Validate BIT STRING content is within input buffer */
++    if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx)
++        return ASN_PARSE_E;
++
+     if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
+         return ASN_EXPECT_0_E;
+ 
+@@ -11519,9 +11931,22 @@ static int wc_PKCS7_DecryptOri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             XMEMCPY(oriOID, pkiMsg + *idx, (word32)oriOIDSz);
+             *idx += (word32)oriOIDSz;
+ 
++            /* Validate OID did not consume more than the SEQUENCE declared */
++            if ((*idx - tmpIdx) > (word32)seqSz) {
++                WOLFSSL_MSG("ORI oriType OID exceeds SEQUENCE boundary");
++                return ASN_PARSE_E;
++            }
++
+             /* get oriValue, increment idx */
+             oriValue = pkiMsg + *idx;
+             oriValueSz = (word32)seqSz - (*idx - tmpIdx);
++
++            /* Validate oriValue region is within input buffer */
++            if (*idx > pkiMsgSz || oriValueSz > pkiMsgSz - *idx) {
++                WOLFSSL_MSG("ORI oriValue exceeds input buffer");
++                return ASN_PARSE_E;
++            }
++
+             *idx += oriValueSz;
+ 
+             /* pass oriOID and oriValue to user callback, expect back
+@@ -11699,6 +12124,12 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                 return ASN_PARSE_E;
+             }
+ 
++            /* Validate IV is within input buffer */
++            if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) {
++                XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                return ASN_PARSE_E;
++            }
++
+             XMEMCPY(tmpIv, pkiMsg + (*idx), (word32)length);
+             *idx += (word32)length;
+ 
+@@ -11718,6 +12149,12 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                 return ASN_PARSE_E;
+             }
+ 
++            /* Validate EncryptedKey is within input buffer */
++            if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx) {
++                XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                return ASN_PARSE_E;
++            }
++
+             /* allocate temporary space for decrypted key */
+             cekSz = (word32)length;
+             cek = (byte*)XMALLOC(cekSz, pkcs7->heap, DYNAMIC_TYPE_TMP_BUFFER);
+@@ -11740,6 +12177,7 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                                   iterations, kek, (word32)kekKeySz);
+             if (ret < 0) {
+                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                ForceZero(kek, (word32)kekKeySz);
+                 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+                 return ASN_PARSE_E;
+@@ -11752,7 +12190,9 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                                              pwriEncAlgoId);
+             if (ret < 0) {
+                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                ForceZero(kek, (word32)kekKeySz);
+                 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                ForceZero(cek, cekSz);
+                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+                 return ret;
+             }
+@@ -11761,7 +12201,9 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             if (*decryptedKeySz < cekSz) {
+                 WOLFSSL_MSG("Decrypted key buffer too small for CEK");
+                 XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                ForceZero(kek, (word32)kekKeySz);
+                 XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++                ForceZero(cek, cekSz);
+                 XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+                 return BUFFER_E;
+             }
+@@ -11770,7 +12212,9 @@ static int wc_PKCS7_DecryptPwri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             *decryptedKeySz = cekSz;
+ 
+             XFREE(salt, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++            ForceZero(kek, (word32)kekKeySz);
+             XFREE(kek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++            ForceZero(cek, cekSz);
+             XFREE(cek, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+ 
+             /* mark recipFound, since we only support one RecipientInfo for now */
+@@ -11804,7 +12248,7 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+     byte* keyId = NULL;
+     const byte* datePtr = NULL;
+     byte  dateFormat, tag;
+-    word32 keyIdSz, kekIdSz, keyWrapOID, localIdx;
++    word32 keyIdSz, kekIdSz, kekIdEnd, keyWrapOID, localIdx;
+ 
+     int ret = 0;
+     byte* pkiMsg    = in;
+@@ -11830,6 +12274,11 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                 return ASN_PARSE_E;
+ 
+             kekIdSz = (word32)length;
++            kekIdEnd = *idx + kekIdSz;
++
++            /* Validate KEKIdentifier boundary is within input buffer */
++            if (kekIdEnd < *idx || kekIdEnd > pkiMsgSz)
++                return ASN_PARSE_E;
+ 
+             if (GetASNTag(pkiMsg, idx, &tag, pkiMsgSz) < 0)
+                 return ASN_PARSE_E;
+@@ -11840,6 +12289,10 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
+                 return ASN_PARSE_E;
+ 
++            /* Validate keyIdentifier is within input buffer */
++            if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx)
++                return ASN_PARSE_E;
++
+             /* save keyIdentifier and length */
+             keyId = pkiMsg + *idx;
+             keyIdSz = (word32)length;
+@@ -11847,13 +12300,15 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+ 
+             /* may have OPTIONAL GeneralizedTime */
+             localIdx = *idx;
+-            if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag,
++            if ((*idx < kekIdEnd) && GetASNTag(pkiMsg, &localIdx, &tag,
+                         pkiMsgSz) == 0 && tag == ASN_GENERALIZED_TIME) {
+-                if (wc_GetDateInfo(pkiMsg + *idx, (int)pkiMsgSz, &datePtr,
+-                        &dateFormat, &dateLen) != 0) {
++                if (wc_GetDateInfo(pkiMsg + *idx, (int)(pkiMsgSz - *idx),
++                        &datePtr, &dateFormat, &dateLen) != 0) {
+                     return ASN_PARSE_E;
+                 }
+-                *idx += (word32)(dateLen + 1);
++                /* datePtr points to the start of the date value
++                 * within pkiMsg; advance past the full TLV. */
++                *idx = (word32)(datePtr - pkiMsg) + (word32)dateLen;
+             }
+ 
+             if (*idx > pkiMsgSz) {
+@@ -11862,7 +12317,7 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+ 
+             /* may have OPTIONAL OtherKeyAttribute */
+             localIdx = *idx;
+-            if ((*idx < kekIdSz) && GetASNTag(pkiMsg, &localIdx, &tag,
++            if ((*idx < kekIdEnd) && GetASNTag(pkiMsg, &localIdx, &tag,
+                             pkiMsgSz) == 0 && tag == (ASN_SEQUENCE |
+                             ASN_CONSTRUCTED)) {
+                 if (GetSequence(pkiMsg, idx, &length, pkiMsgSz) < 0)
+@@ -11891,6 +12346,10 @@ static int wc_PKCS7_DecryptKekri(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             if (GetLength(pkiMsg, idx, &length, pkiMsgSz) < 0)
+                 return ASN_PARSE_E;
+ 
++            /* Validate EncryptedKey is within input buffer */
++            if (*idx > pkiMsgSz || (word32)length > pkiMsgSz - *idx)
++                return ASN_PARSE_E;
++
+             #ifndef NO_AES
+                 direction = AES_DECRYPTION;
+             #else
+@@ -12644,6 +13103,22 @@ static int wc_PKCS7_ParseToRecipientInfoSet(wc_PKCS7* pkcs7, byte* in,
+                         NO_USER_CHECK) < 0)
+                 ret = ASN_PARSE_E;
+ 
++            /* GetSet_ex is called with NO_USER_CHECK, which skips the
++             * (idx + length > maxIdx) bounds check in GetLength_ex. In
++             * non-streaming mode, validate the SET length against the
++             * remaining input buffer; in streaming mode the length flows
++             * into pkcs7->stream->expected and then wc_PKCS7_GrowStream,
++             * where it is capped by WOLFSSL_PKCS7_MAX_STREAM_ALLOC. */
++            if (ret == 0 && length < 0)
++                ret = ASN_PARSE_E;
++        #ifdef NO_PKCS7_STREAM
++            if (ret == 0 &&
++                    (*idx > pkiMsgSz ||
++                     (word32)length > pkiMsgSz - *idx)) {
++                ret = ASN_PARSE_E;
++            }
++        #endif
++
+             if (ret < 0)
+                 break;
+ 
+@@ -12799,6 +13274,11 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                                                        DYNAMIC_TYPE_PKCS7);
+             if (decryptedKey == NULL)
+                 return MEMORY_E;
++            XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
++        #ifdef WOLFSSL_CHECK_MEM_ZERO
++            wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey,
++                            MAX_ENCRYPTED_KEY_SZ);
++        #endif
+             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_ENV_2);
+             tmpIdx = idx;
+             recipientSetSz = (word32)ret;
+@@ -13018,6 +13498,14 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                 ret = ASN_PARSE_E;
+             }
+ 
++        #ifdef NO_PKCS7_STREAM
++            if (ret == 0 && encryptedContentTotalSz > (int)(pkiMsgSz - idx)) {
++                /* In non-streaming mode, ensure the content fits in the buffer.
++                 * Streaming mode handles this via AddDataToStream. */
++                ret = BUFFER_E;
++            }
++        #endif
++
+             if (ret != 0)
+                 break;
+ 
+@@ -13033,10 +13521,18 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+             wc_PKCS7_StreamStoreVar(pkcs7, encOID, expBlockSz, explicitOctet);
+ 
+             if (explicitOctet) {
+-                /* initialize decryption state in preparation */
++                /* initialize decryption state in preparation. Use
++                 * contentSz (blockKeySz from the content algorithm) as
++                 * the AES key size rather than aadSz (the unwrapped CEK
++                 * length): the two are equal for well-formed messages,
++                 * but using blockKeySz avoids BAD_FUNC_ARG on crafted
++                 * messages where the CEK length does not match the
++                 * content cipher, which would otherwise be a
++                 * distinguishable error. */
+                 if (pkcs7->decryptionCb == NULL) {
+                     ret = wc_PKCS7_DecryptContentInit(pkcs7, encOID,
+-                        pkcs7->stream->aad, pkcs7->stream->aadSz,
++                        pkcs7->stream->aad,
++                        (word32)pkcs7->stream->contentSz,
+                         pkcs7->stream->tmpIv, expBlockSz,
+                         pkcs7->devId, pkcs7->heap);
+                     if (ret != 0)
+@@ -13319,8 +13815,13 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+ 
+             ret = (int)pkcs7->totalEncryptedContentSz - padLen;
+         #ifndef NO_PKCS7_STREAM
+-            pkcs7->stream->aad = NULL;
+-            pkcs7->stream->aadSz = 0;
++            /* decryptedKey (just freed) is the same buffer stream->aad
++             * aliases. Null the stream handle so ResetStream doesn't
++             * double-free it. */
++            if (pkcs7->stream != NULL) {
++                pkcs7->stream->aad = NULL;
++                pkcs7->stream->aadSz = 0;
++            }
+             wc_PKCS7_ResetStream(pkcs7);
+         #endif
+             wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
+@@ -13333,6 +13834,16 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+ 
+ #ifndef NO_PKCS7_STREAM
+     if (ret < 0 && ret != WC_NO_ERR_TRACE(WC_PKCS7_WANT_READ_E)) {
++        /* stream->aad aliases the MAX_ENCRYPTED_KEY_SZ decryptedKey
++         * buffer in this flow. ResetStream only zeros aadSz bytes, so
++         * explicitly zero and release the full buffer here to satisfy
++         * WOLFSSL_CHECK_MEM_ZERO and avoid leaking key material. */
++        if (pkcs7->stream != NULL && pkcs7->stream->aad != NULL) {
++            ForceZero(pkcs7->stream->aad, MAX_ENCRYPTED_KEY_SZ);
++            XFREE(pkcs7->stream->aad, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
++            pkcs7->stream->aad = NULL;
++            pkcs7->stream->aadSz = 0;
++        }
+         wc_PKCS7_ResetStream(pkcs7);
+         wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
+         if (pkcs7->cachedEncryptedContent != NULL) {
+@@ -13343,6 +13854,9 @@ int wc_PKCS7_DecodeEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+         }
+     }
+ #else
++    if (ret < 0) {
++        wc_PKCS7_ChangeState(pkcs7, WC_PKCS7_START);
++    }
+     if (decryptedKey != NULL && ret < 0) {
+         ForceZero(decryptedKey, MAX_ENCRYPTED_KEY_SZ);
+         XFREE(decryptedKey, pkcs7->heap, DYNAMIC_TYPE_PKCS7);
+@@ -14103,6 +14617,10 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+             }
+             else {
+                 XMEMSET(decryptedKey, 0, MAX_ENCRYPTED_KEY_SZ);
++            #ifdef WOLFSSL_CHECK_MEM_ZERO
++                wc_MemZero_Add("wc_PKCS7 decryptedKey", decryptedKey,
++                                MAX_ENCRYPTED_KEY_SZ);
++            #endif
+             }
+         #ifndef NO_PKCS7_STREAM
+             pkcs7->stream->key = decryptedKey;
+@@ -14238,6 +14756,11 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                 break;
+             }
+             pkiMsgSz = (pkcs7->stream->length > 0)? pkcs7->stream->length: inSz;
++
++            /* Restore encOID across WANT_READ re-entries so the nonce
++             * length validation below always sees the content-cipher
++             * algorithm parsed in AUTHENV_3. */
++            wc_PKCS7_StreamGetVar(pkcs7, &encOID, &blockKeySz, NULL);
+         #endif
+             /* get length of optional parameter sequence */
+             if (ret == 0 && GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) {
+@@ -14255,6 +14778,46 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                 ret = ASN_PARSE_E;
+             }
+ 
++            /* Enforce algorithm-specific nonce length bounds at the parser
++             * layer so malformed lengths (notably zero-length, which would
++             * catastrophically break AEAD uniqueness on HW backends that
++             * skip their own checks) cannot reach the cipher engine.
++             *   - AES-GCM in CMS: RFC 5084 Sec. 3.2 mandates a 12-octet IV.
++             *   - AES-CCM: RFC 3610 Sec. 2.3 requires 7..13 octets.
++             * Any other encOID here is a parser-state invariant violation. */
++            if (ret == 0) {
++                int nonceMin = 0, nonceMax = 0;
++                switch (encOID) {
++                #ifdef HAVE_AESGCM
++                    case AES128GCMb:
++                    case AES192GCMb:
++                    case AES256GCMb:
++                        nonceMin = GCM_NONCE_MID_SZ;
++                        nonceMax = GCM_NONCE_MID_SZ;
++                        break;
++                #endif
++                #ifdef HAVE_AESCCM
++                    case AES128CCMb:
++                    case AES192CCMb:
++                    case AES256CCMb:
++                        nonceMin = CCM_NONCE_MIN_SZ;
++                        nonceMax = CCM_NONCE_MAX_SZ;
++                        break;
++                #endif
++                    default:
++                        WOLFSSL_MSG(
++                            "AuthEnvelopedData unexpected content cipher");
++                        ret = ALGO_ID_E;
++                        break;
++                }
++                if (ret == 0 &&
++                        (nonceSz < nonceMin || nonceSz > nonceMax)) {
++                    WOLFSSL_MSG(
++                        "AuthEnvelopedData nonce length invalid for cipher");
++                    ret = ASN_PARSE_E;
++                }
++            }
++
+             if (ret == 0) {
+                 XMEMCPY(nonce, &pkiMsg[idx], (word32)nonceSz);
+                 idx += (word32)nonceSz;
+@@ -14406,7 +14969,16 @@ int wc_PKCS7_DecodeAuthEnvelopedData(wc_PKCS7* pkcs7, byte* in,
+                 if (GetLength_ex(pkiMsg, &idx, &length, pkiMsgSz, 0) <= 0) {
+                     ret = ASN_PARSE_E;
+                 }
+-            #ifndef NO_PKCS7_STREAM
++
++            #ifdef NO_PKCS7_STREAM
++                /* In non-streaming mode, validate authenticatedAttributes
++                 * length is within the input buffer. The streaming path
++                 * handles this via wc_PKCS7_AddDataToStream instead. */
++                if (ret == 0 &&
++                        (idx > pkiMsgSz || (word32)length > pkiMsgSz - idx)) {
++                    ret = ASN_PARSE_E;
++                }
++            #else
+                 pkcs7->stream->expected = (word32)length;
+             #endif
+                 encodedAttribSz = (word32)length + (idx - encodedAttribIdx);
+@@ -15274,6 +15846,12 @@ int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+                         pkiMsgSz, NO_USER_CHECK) <= 0)
+                 ret = ASN_PARSE_E;
+ 
++#ifdef NO_PKCS7_STREAM
++            if (ret == 0 && encryptedContentSz > (int)(pkiMsgSz - idx)) {
++                ret = BUFFER_E;
++            }
++#endif
++
+             if (ret < 0)
+                 break;
+ #ifndef NO_PKCS7_STREAM
+@@ -15311,7 +15889,8 @@ int wc_PKCS7_DecodeEncryptedData(wc_PKCS7* pkcs7, byte* in, word32 inSz,
+             version    = (int)pkcs7->stream->vers;
+             tmpIv      = pkcs7->stream->tmpIv;
+ #endif
+-            if (encryptedContentSz <= 0) {
++            if (encryptedContentSz <= 0 ||
++                    encryptedContentSz > (int)(pkiMsgSz - idx)) {
+                 ret = BUFFER_E;
+                 break;
+             }
+diff --git a/wolfssl/wolfcrypt/wc_encrypt.h b/wolfssl/wolfcrypt/wc_encrypt.h
+index da11b5392..7f1c48b63 100644
+--- a/wolfssl/wolfcrypt/wc_encrypt.h
++++ b/wolfssl/wolfcrypt/wc_encrypt.h
+@@ -73,6 +73,9 @@
+     #ifndef CCM_NONCE_MIN_SZ
+         #define CCM_NONCE_MIN_SZ 7
+     #endif
++    #ifndef CCM_NONCE_MAX_SZ
++        #define CCM_NONCE_MAX_SZ 13
++    #endif
+ #endif
+ 
+ 
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 8802202114..5569df4d56 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -28,6 +28,7 @@ SRC_URI = " \
     file://CVE-2026-6094-3.patch \
     file://CVE-2026-6094-4.patch \
     file://CVE-2026-6094-5.patch \
+    file://CVE-2026-6291.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 29/33] wolfssl: patch CVE-2026-6325
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (26 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 28/33] wolfssl: patch CVE-2026-6291 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 30/33] wolfssl: patch CVE-2026-6412 ankur.tyagi85
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6325

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6325.patch         | 123 ++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   1 +
 2 files changed, 124 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6325.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6325.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6325.patch
new file mode 100644
index 0000000000..5a67a30dc0
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6325.patch
@@ -0,0 +1,123 @@
+From b47170ed386de50deb3f1ce7c9f39cdb17630fc0 Mon Sep 17 00:00:00 2001
+From: Sean Parkinson <sean@wolfssl.com>
+Date: Wed, 15 Apr 2026 11:39:26 +1000
+Subject: [PATCH] Merge pull request #10204 from mattia-moffa/20260413-fixes
+
+SetSuitesHashSigAlgo fix
+
+(cherry picked from commit 6ac0f82b8589736e15683b7d94a822681b8949fc)
+
+CVE: CVE-2026-6325
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/6ac0f82b8589736e15683b7d94a822681b8949fc]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/internal.c | 11 ++++++++++
+ tests/api.c    | 58 +++++++++++++++++++++++++++-----------------------
+ 2 files changed, 42 insertions(+), 27 deletions(-)
+
+diff --git a/src/internal.c b/src/internal.c
+index 267c75a5d..769ba6764 100644
+--- a/src/internal.c
++++ b/src/internal.c
+@@ -29546,6 +29546,17 @@ int SetSuitesHashSigAlgo(Suites* suites, const char* list)
+                     break;
+                 }
+             }
++            {
++                word32 needed = 2;
++#if defined(WC_RSA_PSS) && defined(WOLFSSL_TLS13)
++                if (sig_alg == rsa_pss_sa_algo)
++                    needed = 4;
++#endif
++                if ((word32)idx + needed > WOLFSSL_MAX_SIGALGO) {
++                    ret = 0;
++                    break;
++                }
++            }
+             AddSuiteHashSigAlgo(suites->hashSigAlgo, mac_alg, sig_alg, 0, &idx);
+             sig_alg = 0;
+             mac_alg = no_mac;
+diff --git a/tests/api.c b/tests/api.c
+index 78fcf13ce..739cf0c68 100644
+--- a/tests/api.c
++++ b/tests/api.c
+@@ -15878,6 +15878,33 @@ static int test_wolfSSL_set1_sigalgs_list(void)
+                     WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
+         ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, "RSA+SHA256+RSA"),
+                     WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
++
++        {
++            const char entry[] = "RSA+SHA256";
++            const int entryLen = (int)sizeof(entry) - 1;
++            const int entries = WOLFSSL_MAX_SIGALGO + 1;
++            int listSz = entries * (entryLen + 1);
++            char* longList = (char*)XMALLOC(listSz, NULL,
++                DYNAMIC_TYPE_TMP_BUFFER);
++            int i;
++            int pos = 0;
++
++            ExpectNotNull(longList);
++            if (longList != NULL) {
++                for (i = 0; i < entries; i++) {
++                    if (i != 0)
++                        longList[pos++] = ':';
++                    XMEMCPY(longList + pos, entry, entryLen);
++                    pos += entryLen;
++                }
++                longList[pos] = '\0';
++                ExpectIntEQ(wolfSSL_CTX_set1_sigalgs_list(ctx, longList),
++                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
++                ExpectIntEQ(wolfSSL_set1_sigalgs_list(ssl, longList),
++                    WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
++                XFREE(longList, NULL, DYNAMIC_TYPE_TMP_BUFFER);
++            }
++        }
+     #endif
+ #endif
+ #ifdef HAVE_ECC
+@@ -35744,7 +35771,6 @@ static int test_pkcs7_padding(void)
+     int outSz;
+     int ctOff = -1;
+     int ctLen = 0;
+-    int i;
+ 
+     XMEMSET(key, 0xAA, sizeof(key));
+     XMEMSET(plaintext, 'X', sizeof(plaintext));
+@@ -35767,32 +35793,10 @@ static int test_pkcs7_padding(void)
+         (word32)encodedSz, output, sizeof(output)), (int)sizeof(plaintext));
+     wc_PKCS7_Free(&pkcs7);
+ 
+-    /* Find ciphertext block in encoded DER */
+-    if (EXPECT_SUCCESS()) {
+-        for (i = encodedSz - 10; i > 10; i--) {
+-            if (encoded[i] == 0x04 || encoded[i] == 0x80) {
+-                int len, lbytes;
+-
+-                if (encoded[i+1] < 0x80) {
+-                    len = encoded[i+1]; lbytes = 1;
+-                }
+-                else if (encoded[i+1] == 0x81) {
+-                    len = encoded[i+2]; lbytes = 2;
+-                }
+-                else {
+-                    continue;
+-                }
+-                if (len > 0 && len % 16 == 0 &&
+-                    i + 1 + lbytes + len <= encodedSz) {
+-                    ctOff = i + 1 + lbytes;
+-                    ctLen = len;
+-                    break;
+-                }
+-            }
+-        }
+-    }
+-    ExpectIntGT(ctOff, 0);
+-    ExpectIntGE(ctLen, 32);
++    /* encryptedContent is the last element in the DER, so it ends at encodedSz;
++     * 27-byte plaintext -> 32-byte AES-256-CBC ciphertext. */
++    ctLen = 32;
++    ctOff = encodedSz - ctLen;
+ 
+     /* Corrupt an interior padding byte via CBC bit-flip */
+     if (EXPECT_SUCCESS()) {
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 5569df4d56..843d5071b4 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -29,6 +29,7 @@ SRC_URI = " \
     file://CVE-2026-6094-4.patch \
     file://CVE-2026-6094-5.patch \
     file://CVE-2026-6291.patch \
+    file://CVE-2026-6325.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 30/33] wolfssl: patch CVE-2026-6412
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (27 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 29/33] wolfssl: patch CVE-2026-6325 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 31/33] wolfssl: patch CVE-2026-6450 ankur.tyagi85
                   ` (2 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6412

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6412-1.patch       | 159 ++++++++++++++++++
 .../wolfssl/files/CVE-2026-6412-2.patch       |  56 ++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   2 +
 3 files changed, 217 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-1.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-2.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-1.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-1.patch
new file mode 100644
index 0000000000..4d1d3b71cb
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-1.patch
@@ -0,0 +1,159 @@
+From eda0a3001ebe036da39f8911a347174a759ffce0 Mon Sep 17 00:00:00 2001
+From: Eric Blankenhorn <eric@wolfssl.com>
+Date: Tue, 14 Apr 2026 12:26:45 -0500
+Subject: [PATCH] Report cert verify failure with MD5
+
+(cherry picked from commit 4a13896b2ea6d6080d41cd32539193713e69935f)
+
+CVE: CVE-2026-6412
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/4a13896b2ea6d6080d41cd32539193713e69935f]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ .wolfssl_known_macro_extras |  1 +
+ tests/api/test_certman.c    | 81 +++++++++++++++++++++++++++++++++++++
+ tests/api/test_certman.h    |  4 +-
+ wolfcrypt/src/asn.c         |  7 ++++
+ 4 files changed, 92 insertions(+), 1 deletion(-)
+
+diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras
+index 3e411ca86..3233644ba 100644
+--- a/.wolfssl_known_macro_extras
++++ b/.wolfssl_known_macro_extras
+@@ -680,6 +680,7 @@ WOLFSSL_ALLOW_CRIT_AIA
+ WOLFSSL_ALLOW_CRIT_AKID
+ WOLFSSL_ALLOW_CRIT_SKID
+ WOLFSSL_ALLOW_MAX_FRAGMENT_ADJUST
++WOLFSSL_ALLOW_MD5_CERT_SIGS
+ WOLFSSL_ALLOW_NO_CN_IN_SAN
+ WOLFSSL_ALLOW_NO_SUITES
+ WOLFSSL_ALLOW_SERVER_SC_EXT
+diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c
+index dfce12334..9f87f4535 100644
+--- a/tests/api/test_certman.c
++++ b/tests/api/test_certman.c
+@@ -2540,3 +2540,84 @@ int test_various_pathlen_chains(void)
+ #endif
+     return EXPECT_RESULT();
+ }
++
++/* Verify that certificates signed with MD5 (md5WithRSAEncryption) are
++ * rejected during chain verification. MD5 must not be acceptable as a
++ * certificate signature hash, even when MD5 is compiled in (e.g. for TLS
++ * 1.0 PRF or HMAC uses). Trust anchors are exempt from this check because
++ * ParseCertRelative skips ConfirmSignature for CA_TYPE. */
++int test_wolfSSL_CertManagerRejectMD5Cert(void)
++{
++    EXPECT_DECLS;
++#if !defined(NO_CERTS) && !defined(NO_RSA) && !defined(NO_MD5) && \
++    !defined(WOLFSSL_ALLOW_MD5_CERT_SIGS) && defined(WOLFSSL_CERT_GEN) && \
++    !defined(NO_WOLFSSL_CM_VERIFY) && !defined(NO_ASN_CRYPT) && \
++    !defined(USE_CERT_BUFFERS_1024)
++    WOLFSSL_CERT_MANAGER* cm = NULL;
++    RsaKey  caKey;
++    WC_RNG  rng;
++    Cert    leaf;
++    byte*   der = NULL;
++    int     derSz = 0;
++    word32  idx = 0;
++    int     caKeyInit = 0;
++    int     rngInit = 0;
++
++    XMEMSET(&caKey, 0, sizeof(caKey));
++    XMEMSET(&rng,   0, sizeof(rng));
++
++    ExpectIntEQ(wc_InitRng(&rng), 0);
++    if (EXPECT_SUCCESS()) rngInit = 1;
++
++    ExpectIntEQ(wc_InitRsaKey_ex(&caKey, HEAP_HINT, testDevId), 0);
++    if (EXPECT_SUCCESS()) caKeyInit = 1;
++    ExpectIntEQ(wc_RsaPrivateKeyDecode(ca_key_der_2048, &idx, &caKey,
++                sizeof_ca_key_der_2048), 0);
++
++    ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT,
++                DYNAMIC_TYPE_TMP_BUFFER));
++
++    /* Build a leaf certificate whose issuer is the built-in 2048-bit
++     * wolfSSL test CA and sign it with MD5+RSA using the matching CA
++     * private key. */
++    ExpectIntEQ(wc_InitCert(&leaf), 0);
++    leaf.sigType = CTC_MD5wRSA;
++    leaf.isCA    = 0;
++    XSTRNCPY(leaf.subject.country,    "US",              CTC_NAME_SIZE);
++    XSTRNCPY(leaf.subject.state,      "MT",              CTC_NAME_SIZE);
++    XSTRNCPY(leaf.subject.locality,   "Bozeman",         CTC_NAME_SIZE);
++    XSTRNCPY(leaf.subject.org,        "wolfSSL",         CTC_NAME_SIZE);
++    XSTRNCPY(leaf.subject.unit,       "Test",            CTC_NAME_SIZE);
++    XSTRNCPY(leaf.subject.commonName, "md5-leaf",        CTC_NAME_SIZE);
++    XSTRNCPY(leaf.subject.email,      "info@wolfssl.com", CTC_NAME_SIZE);
++
++    ExpectIntEQ(wc_SetIssuerBuffer(&leaf, ca_cert_der_2048,
++                sizeof_ca_cert_der_2048), 0);
++
++    /* wc_MakeCert needs an RSA public key for the subject; reuse caKey
++     * for simplicity (we only care about signature-side verification). */
++    ExpectIntGT((derSz = wc_MakeCert(&leaf, der, FOURK_BUF, &caKey, NULL,
++                &rng)), 0);
++    ExpectIntGT((derSz = wc_SignCert(leaf.bodySz, leaf.sigType, der,
++                FOURK_BUF, &caKey, NULL, &rng)), 0);
++
++    /* Load the SHA-256 signed CA cert as a trust anchor and attempt
++     * to verify the MD5-signed leaf: it must be rejected because
++     * HashForSignature() now returns HASH_TYPE_E for MD5 in verify mode,
++     * which surfaces as ASN_SIG_CONFIRM_E from ConfirmSignature(). */
++    ExpectNotNull(cm = wolfSSL_CertManagerNew());
++    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, ca_cert_der_2048,
++                sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1),
++                WOLFSSL_SUCCESS);
++
++    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
++                WOLFSSL_FILETYPE_ASN1),
++                WC_NO_ERR_TRACE(HASH_TYPE_E));
++
++    wolfSSL_CertManagerFree(cm);
++    XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
++    if (caKeyInit) wc_FreeRsaKey(&caKey);
++    if (rngInit)   wc_FreeRng(&rng);
++#endif
++    return EXPECT_RESULT();
++}
+diff --git a/tests/api/test_certman.h b/tests/api/test_certman.h
+index 1588c81ec..a0b5d9548 100644
+--- a/tests/api/test_certman.h
++++ b/tests/api/test_certman.h
+@@ -41,6 +41,7 @@ int test_wolfSSL_CRL_static_revoked_list(void);
+ int test_wolfSSL_CRL_duplicate_extensions(void);
+ int test_wolfSSL_CertManagerCheckOCSPResponse(void);
+ int test_various_pathlen_chains(void);
++int test_wolfSSL_CertManagerRejectMD5Cert(void);
+ 
+ #define TEST_CERTMAN_DECLS                                                  \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerAPI),                \
+@@ -59,7 +60,8 @@ int test_various_pathlen_chains(void);
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_static_revoked_list),      \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_duplicate_extensions),      \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCheckOCSPResponse),  \
+-    TEST_DECL_GROUP("certman", test_various_pathlen_chains)
++    TEST_DECL_GROUP("certman", test_various_pathlen_chains),                \
++    TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerRejectMD5Cert)
+ 
+ #endif /* WOLFCRYPT_TEST_CERTMAN_H */
+ 
+diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c
+index fea449863..8d4f40a70 100644
+--- a/wolfcrypt/src/asn.c
++++ b/wolfcrypt/src/asn.c
+@@ -15880,6 +15880,13 @@ static int HashForSignature(const byte* buf, word32 bufSz, word32 sigOID,
+     #endif
+     #ifndef NO_MD5
+         case CTC_MD5wRSA:
++        #ifndef WOLFSSL_ALLOW_MD5_CERT_SIGS
++            if (verify) {
++                ret = HASH_TYPE_E;
++                WOLFSSL_MSG("MD5 not supported for certificate verification");
++                break;
++            }
++        #endif
+             if ((ret = wc_Md5Hash_ex(buf, bufSz, digest, heap, devId)) == 0) {
+                 *typeH    = MD5h;
+                 *digestSz = WC_MD5_DIGEST_SIZE;
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-2.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-2.patch
new file mode 100644
index 0000000000..0747e9dd99
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6412-2.patch
@@ -0,0 +1,56 @@
+From ab4cfd06ce09ca6aa33e06ca12bcfc1186c9f357 Mon Sep 17 00:00:00 2001
+From: Eric Blankenhorn <eric@wolfssl.com>
+Date: Tue, 14 Apr 2026 13:39:17 -0500
+Subject: [PATCH] Fix from review
+
+(cherry picked from commit a8ea8a898c45a4199ac196044ac14314dc82d981)
+
+CVE: CVE-2026-6412
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/a8ea8a898c45a4199ac196044ac14314dc82d981]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ tests/api/test_certman.c | 20 +++++++++++++-------
+ 1 file changed, 13 insertions(+), 7 deletions(-)
+
+diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c
+index 9f87f4535..6c5875dc5 100644
+--- a/tests/api/test_certman.c
++++ b/tests/api/test_certman.c
+@@ -2576,6 +2576,9 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void)
+ 
+     ExpectNotNull(der = (byte*)XMALLOC(FOURK_BUF, HEAP_HINT,
+                 DYNAMIC_TYPE_TMP_BUFFER));
++    if (der == NULL) {
++        goto cleanup;
++    }
+ 
+     /* Build a leaf certificate whose issuer is the built-in 2048-bit
+      * wolfSSL test CA and sign it with MD5+RSA using the matching CA
+@@ -2604,16 +2607,19 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void)
+     /* Load the SHA-256 signed CA cert as a trust anchor and attempt
+      * to verify the MD5-signed leaf: it must be rejected because
+      * HashForSignature() now returns HASH_TYPE_E for MD5 in verify mode,
+-     * which surfaces as ASN_SIG_CONFIRM_E from ConfirmSignature(). */
++     * and wolfSSL_CertManagerVerifyBuffer() returns that error. */
+     ExpectNotNull(cm = wolfSSL_CertManagerNew());
+-    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, ca_cert_der_2048,
+-                sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1),
+-                WOLFSSL_SUCCESS);
++    if (cm != NULL) {
++        ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, ca_cert_der_2048,
++                    sizeof_ca_cert_der_2048, WOLFSSL_FILETYPE_ASN1),
++                    WOLFSSL_SUCCESS);
+ 
+-    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
+-                WOLFSSL_FILETYPE_ASN1),
+-                WC_NO_ERR_TRACE(HASH_TYPE_E));
++        ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
++                    WOLFSSL_FILETYPE_ASN1),
++                    WC_NO_ERR_TRACE(HASH_TYPE_E));
++    }
+ 
++cleanup:
+     wolfSSL_CertManagerFree(cm);
+     XFREE(der, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER);
+     if (caKeyInit) wc_FreeRsaKey(&caKey);
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 843d5071b4..4ca330b029 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -30,6 +30,8 @@ SRC_URI = " \
     file://CVE-2026-6094-5.patch \
     file://CVE-2026-6291.patch \
     file://CVE-2026-6325.patch \
+    file://CVE-2026-6412-1.patch \
+    file://CVE-2026-6412-2.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 31/33] wolfssl: patch CVE-2026-6450
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (28 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 30/33] wolfssl: patch CVE-2026-6412 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 32/33] wolfssl: patch CVE-2026-6731 ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 33/33] wolfssl: patch CVE-2026-7531 ankur.tyagi85
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Also backport follow-up PR[1] to the initial PR mentioned in the NVD.

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6450

[1]https://github.com/wolfSSL/wolfssl/pull/10274

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6450-1.patch       | 456 ++++++++++++++++++
 .../wolfssl/files/CVE-2026-6450-2.patch       | 404 ++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   2 +
 3 files changed, 862 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-1.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-2.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-1.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-1.patch
new file mode 100644
index 0000000000..a754fc3e33
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-1.patch
@@ -0,0 +1,456 @@
+From b60e4b6fc0d757f5983a803ad02a1a57c0d0a463 Mon Sep 17 00:00:00 2001
+From: Reda Chouk <reda@wolfssl.com>
+Date: Thu, 16 Apr 2026 19:45:09 +0200
+Subject: [PATCH] reject crls with unrecognized critical extensions per rfc
+ 5280 section 5.2
+
+(cherry picked from commit 857141da35b67a14a580fb26ec57af1efa68a1d9)
+
+CVE: CVE-2026-6450
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/857141da35b67a14a580fb26ec57af1efa68a1d9]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ tests/api/test_certman.c | 342 +++++++++++++++++++++++++++++++++++++++
+ tests/api/test_certman.h |   4 +
+ wolfcrypt/src/asn.c      |   7 +-
+ wolfcrypt/src/asn_orig.c |   9 +-
+ 4 files changed, 359 insertions(+), 3 deletions(-)
+
+diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c
+index 6c5875dc5..7405f4bff 100644
+--- a/tests/api/test_certman.c
++++ b/tests/api/test_certman.c
+@@ -1964,6 +1964,348 @@ int test_wolfSSL_CRL_duplicate_extensions(void)
+     return EXPECT_RESULT();
+ }
+ 
++int test_wolfSSL_CRL_critical_idp(void)
++{
++    EXPECT_DECLS;
++#if !defined(NO_CERTS) && defined(HAVE_CRL) && !defined(NO_RSA)
++
++    /* CA cert (CN=claim-root), self-signed, 799 bytes DER */
++    static const unsigned char ca_cert_idp[] = {
++        0x30, 0x82, 0x03, 0x1b, 0x30, 0x82, 0x02, 0x03, 0xa0, 0x03, 0x02,
++        0x01, 0x02, 0x02, 0x14, 0x1e, 0x25, 0xc1, 0x5d, 0x6f, 0x02, 0x21,
++        0xa0, 0xf0, 0x14, 0x15, 0x9c, 0x3b, 0x4d, 0x1d, 0x73, 0x16, 0x00,
++        0xe4, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
++        0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30,
++        0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61,
++        0x69, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d,
++        0x32, 0x36, 0x30, 0x34, 0x31, 0x36, 0x31, 0x31, 0x33, 0x38, 0x35,
++        0x35, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x34, 0x31, 0x33, 0x31,
++        0x31, 0x33, 0x38, 0x35, 0x35, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
++        0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61,
++        0x69, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x22,
++        0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
++        0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
++        0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xba, 0x49, 0x8c, 0xb5,
++        0x17, 0xc1, 0x01, 0x24, 0x6f, 0x56, 0x1a, 0xa9, 0x3b, 0x03, 0xe2,
++        0x9f, 0x24, 0xb1, 0x25, 0x98, 0xfb, 0x38, 0x82, 0x78, 0x54, 0xa7,
++        0x1f, 0x69, 0x87, 0xe4, 0x96, 0x1b, 0x81, 0x18, 0x10, 0xb0, 0xc0,
++        0x5b, 0x4b, 0xbf, 0xb8, 0x1d, 0xf4, 0xee, 0x75, 0x0f, 0xb5, 0x45,
++        0x72, 0x70, 0xce, 0x65, 0x84, 0x44, 0x3e, 0x30, 0x78, 0xc4, 0xf3,
++        0xec, 0xba, 0x96, 0x78, 0xa4, 0x65, 0xfc, 0x62, 0x8d, 0xf5, 0x29,
++        0xf9, 0x7c, 0x3d, 0x78, 0x6c, 0x1d, 0x4a, 0x4c, 0xc9, 0x15, 0x2d,
++        0x22, 0x10, 0xea, 0x93, 0x26, 0xb8, 0xa6, 0x17, 0xd3, 0x0e, 0xbc,
++        0x0c, 0xab, 0x83, 0x63, 0xf6, 0x1c, 0xcc, 0x83, 0x73, 0x29, 0x7e,
++        0x7f, 0x83, 0x7f, 0xbd, 0x63, 0xaa, 0x8d, 0xfa, 0x78, 0x85, 0xd2,
++        0x3e, 0x60, 0x95, 0x5a, 0x8d, 0xfa, 0x8f, 0xcd, 0x94, 0x3f, 0x13,
++        0x28, 0xd9, 0xd0, 0x87, 0x28, 0x17, 0x78, 0xe2, 0x61, 0x8d, 0x79,
++        0x97, 0x01, 0xa9, 0x7c, 0x84, 0xc0, 0x1c, 0xbe, 0x5f, 0x5d, 0xca,
++        0x28, 0x6b, 0x5e, 0xdd, 0x83, 0xa5, 0x55, 0x34, 0x11, 0xba, 0xfa,
++        0x8b, 0x92, 0xa3, 0xde, 0xb6, 0xf3, 0xba, 0xab, 0x7f, 0x1a, 0x67,
++        0xfd, 0x6f, 0x20, 0x85, 0x4c, 0x77, 0xa7, 0x8e, 0xbe, 0xb8, 0xf8,
++        0x8f, 0x70, 0xe3, 0x5a, 0xd3, 0x77, 0xc9, 0x9e, 0x10, 0x60, 0xb4,
++        0xdb, 0x0c, 0xc5, 0x05, 0xe1, 0x1f, 0xbd, 0xe6, 0x79, 0xee, 0x82,
++        0x3f, 0x51, 0x76, 0xe2, 0x7f, 0x5c, 0x11, 0x6d, 0xd3, 0x21, 0x69,
++        0xec, 0x05, 0x11, 0x8b, 0xc8, 0x39, 0xb3, 0x2c, 0xa6, 0x83, 0xb4,
++        0x6f, 0xac, 0x19, 0xd6, 0x6a, 0x65, 0x0d, 0x08, 0x94, 0x58, 0xde,
++        0x3d, 0xc9, 0x0c, 0x54, 0x03, 0x73, 0x0c, 0x8d, 0x24, 0x09, 0xf3,
++        0xb1, 0x5d, 0xd2, 0xe3, 0xeb, 0x56, 0xd6, 0x28, 0x66, 0x5b, 0x02,
++        0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06,
++        0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
++        0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
++        0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06,
++        0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x52, 0x97, 0x58,
++        0x47, 0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e,
++        0xea, 0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x1f, 0x06, 0x03, 0x55,
++        0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x52, 0x97, 0x58,
++        0x47, 0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e,
++        0xea, 0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a,
++        0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
++        0x82, 0x01, 0x01, 0x00, 0x7d, 0x30, 0xd4, 0x6a, 0x01, 0x89, 0x3b,
++        0x62, 0xed, 0x16, 0x46, 0x59, 0x0f, 0xf2, 0x3b, 0xb5, 0xde, 0x89,
++        0x08, 0x17, 0x68, 0xcb, 0x46, 0xdc, 0x39, 0xa6, 0xcb, 0x56, 0xb0,
++        0x91, 0xeb, 0x03, 0xb2, 0x15, 0xc4, 0x3b, 0x4d, 0x63, 0x55, 0x22,
++        0x0a, 0x26, 0xe6, 0x64, 0x46, 0xe8, 0x0f, 0xa8, 0xf3, 0xde, 0xe1,
++        0x43, 0x54, 0xe6, 0xd7, 0x8a, 0xf4, 0x4f, 0xab, 0x56, 0x93, 0x12,
++        0x71, 0x4b, 0x25, 0x71, 0x0a, 0x31, 0x18, 0x79, 0xee, 0x45, 0xa4,
++        0xf5, 0x72, 0x67, 0xfa, 0x41, 0xd9, 0x87, 0x97, 0x09, 0xef, 0x55,
++        0xad, 0x6f, 0x47, 0x1d, 0x5a, 0xb2, 0xe9, 0xf7, 0x22, 0x05, 0x2d,
++        0x5a, 0x81, 0xa8, 0xe8, 0x53, 0xb0, 0x94, 0xf6, 0x63, 0xff, 0x3f,
++        0x51, 0x7a, 0x08, 0xac, 0x27, 0x9a, 0x57, 0x11, 0x22, 0xa4, 0x00,
++        0x84, 0x70, 0x86, 0x76, 0x39, 0x0f, 0x4f, 0x57, 0xcf, 0x8e, 0x94,
++        0xd2, 0x8e, 0x43, 0xc0, 0xd5, 0x34, 0x7d, 0xf5, 0xa1, 0x45, 0x1e,
++        0xb7, 0xc8, 0x7e, 0x7c, 0xfe, 0x5d, 0x4d, 0x53, 0x43, 0x25, 0x15,
++        0x9e, 0x08, 0x01, 0x56, 0xa4, 0xff, 0x79, 0x59, 0x25, 0xc9, 0x23,
++        0x98, 0xaf, 0x05, 0xaf, 0xc1, 0x0b, 0x29, 0xf1, 0xe2, 0xc4, 0x36,
++        0x31, 0x91, 0xfa, 0xf2, 0xbb, 0x12, 0xe8, 0x67, 0xf9, 0xc7, 0xa1,
++        0x5e, 0x8c, 0xed, 0x92, 0x12, 0xa3, 0x2b, 0xe1, 0xc2, 0xe1, 0xa0,
++        0xb0, 0x0e, 0x12, 0xa7, 0xd0, 0xa2, 0xae, 0xd6, 0xfa, 0x30, 0x21,
++        0x0f, 0x73, 0xfe, 0x24, 0x21, 0x5f, 0x03, 0x86, 0x69, 0xcd, 0xec,
++        0x76, 0x18, 0xe1, 0xfd, 0xb6, 0x64, 0x90, 0xa6, 0x06, 0x2e, 0x19,
++        0x40, 0x93, 0x50, 0x37, 0xe4, 0x90, 0xe3, 0x1f, 0x07, 0xae, 0xfb,
++        0x89, 0xc3, 0xf6, 0xc4, 0x90, 0xab, 0x40, 0x67, 0x4c, 0x43, 0x2c,
++        0xa2, 0xb0, 0x3e, 0x61, 0x16, 0x69, 0x8f
++    };
++
++    /* CRL with critical IDP onlyuser=TRUE, revokes serial 0x1000, 480 bytes */
++    static const unsigned char crl_user_idp[] = {
++        0x30, 0x82, 0x01, 0xdc, 0x30, 0x81, 0xc5, 0x02, 0x01, 0x01, 0x30,
++        0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++        0x0b, 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
++        0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2d,
++        0x72, 0x6f, 0x6f, 0x74, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x34, 0x31,
++        0x36, 0x31, 0x31, 0x33, 0x38, 0x35, 0x35, 0x5a, 0x17, 0x0d, 0x33,
++        0x36, 0x30, 0x34, 0x31, 0x33, 0x31, 0x31, 0x33, 0x38, 0x35, 0x35,
++        0x5a, 0x30, 0x15, 0x30, 0x13, 0x02, 0x02, 0x10, 0x00, 0x17, 0x0d,
++        0x32, 0x36, 0x30, 0x34, 0x31, 0x36, 0x31, 0x31, 0x33, 0x38, 0x35,
++        0x35, 0x5a, 0xa0, 0x65, 0x30, 0x63, 0x30, 0x1f, 0x06, 0x03, 0x55,
++        0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x52, 0x97, 0x58,
++        0x47, 0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e,
++        0xea, 0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x33, 0x06, 0x03, 0x55,
++        0x1d, 0x1c, 0x01, 0x01, 0xff, 0x04, 0x29, 0x30, 0x27, 0xa0, 0x22,
++        0xa0, 0x20, 0x86, 0x1e, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
++        0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2f,
++        0x63, 0x72, 0x6c, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x70, 0x65,
++        0x6d, 0x81, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x14,
++        0x04, 0x04, 0x02, 0x02, 0x20, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a,
++        0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
++        0x82, 0x01, 0x01, 0x00, 0x9b, 0x1a, 0x70, 0xba, 0xf8, 0x38, 0xff,
++        0xc6, 0x36, 0x59, 0x6e, 0xab, 0x87, 0x74, 0x04, 0xe3, 0x17, 0xb3,
++        0xdd, 0x62, 0x03, 0x25, 0x9e, 0xff, 0x53, 0xf7, 0xde, 0x48, 0xb0,
++        0x56, 0x0c, 0x19, 0xea, 0x86, 0x30, 0x21, 0x01, 0x63, 0xd6, 0xd2,
++        0xef, 0xd1, 0x0e, 0x1d, 0xde, 0xc1, 0x18, 0x33, 0xd2, 0x1b, 0x79,
++        0x2e, 0xa1, 0xd5, 0x51, 0xcc, 0x31, 0x35, 0x28, 0xa6, 0x6f, 0xc0,
++        0xcf, 0x78, 0xbf, 0x5d, 0xdd, 0x66, 0x81, 0x71, 0xa3, 0x52, 0xb5,
++        0x48, 0x81, 0x1a, 0x34, 0xf1, 0x03, 0x37, 0x3a, 0x97, 0x02, 0xd6,
++        0x56, 0x4a, 0x24, 0xeb, 0x93, 0x47, 0xb6, 0xc3, 0x69, 0xc6, 0x2b,
++        0xd8, 0xfc, 0xf9, 0x9f, 0x85, 0xab, 0xe2, 0x81, 0x66, 0x8f, 0xcf,
++        0x7a, 0x81, 0xd7, 0x46, 0xb4, 0x8d, 0x44, 0x05, 0x40, 0xd2, 0x3b,
++        0x1c, 0xb8, 0x4a, 0x88, 0xb8, 0x65, 0x69, 0x5e, 0x7f, 0x6c, 0x43,
++        0x1c, 0x4f, 0xbf, 0x48, 0x55, 0x6b, 0xb0, 0xb3, 0x70, 0x49, 0x1a,
++        0xfa, 0xd1, 0x55, 0xe7, 0xb9, 0x5d, 0x4f, 0x2d, 0x7e, 0xc1, 0xa5,
++        0x5f, 0x5e, 0x38, 0xef, 0x74, 0xe8, 0x72, 0x89, 0x9c, 0x86, 0x24,
++        0x65, 0x2d, 0x38, 0x88, 0x53, 0x81, 0x48, 0x8a, 0x7d, 0xc3, 0x0d,
++        0x87, 0xaf, 0xd3, 0xf7, 0x39, 0xeb, 0xac, 0x36, 0xc2, 0xc9, 0x1f,
++        0x78, 0xa9, 0x53, 0x1c, 0x4a, 0xa6, 0xba, 0x63, 0xd1, 0xc2, 0x62,
++        0x81, 0x00, 0x39, 0xb1, 0x1c, 0x1c, 0xad, 0x96, 0x83, 0xf7, 0x99,
++        0x34, 0xc6, 0x9c, 0x93, 0xbb, 0x6a, 0x7c, 0xf5, 0x18, 0xed, 0xbd,
++        0x29, 0xe4, 0x29, 0x50, 0x3c, 0xcb, 0x94, 0x72, 0x8f, 0xad, 0x15,
++        0x91, 0x38, 0x4a, 0xb4, 0xde, 0x98, 0x3e, 0xd6, 0xb2, 0xd1, 0x2a,
++        0x8c, 0xa2, 0xc9, 0x0f, 0x2f, 0x7c, 0x4a, 0xd6, 0x56, 0x02, 0x9f,
++        0x6c, 0xda, 0xa9, 0x4c, 0x04, 0x64, 0x7c
++    };
++
++    /* CRL with critical IDP onlyCA=TRUE, empty revocation list, 459 bytes */
++    static const unsigned char crl_caonly_idp[] = {
++        0x30, 0x82, 0x01, 0xc7, 0x30, 0x81, 0xb0, 0x02, 0x01, 0x01, 0x30,
++        0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++        0x0b, 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
++        0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2d,
++        0x72, 0x6f, 0x6f, 0x74, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x34, 0x31,
++        0x36, 0x31, 0x31, 0x33, 0x38, 0x35, 0x35, 0x5a, 0x17, 0x0d, 0x33,
++        0x36, 0x30, 0x34, 0x31, 0x33, 0x31, 0x31, 0x33, 0x38, 0x35, 0x35,
++        0x5a, 0xa0, 0x67, 0x30, 0x65, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
++        0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x52, 0x97, 0x58, 0x47,
++        0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e, 0xea,
++        0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x35, 0x06, 0x03, 0x55, 0x1d,
++        0x1c, 0x01, 0x01, 0xff, 0x04, 0x2b, 0x30, 0x29, 0xa0, 0x24, 0xa0,
++        0x22, 0x86, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63,
++        0x6c, 0x61, 0x69, 0x6d, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2f, 0x63,
++        0x72, 0x6c, 0x2d, 0x63, 0x61, 0x6f, 0x6e, 0x6c, 0x79, 0x2e, 0x70,
++        0x65, 0x6d, 0x82, 0x01, 0xff, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d,
++        0x14, 0x04, 0x04, 0x02, 0x02, 0x20, 0x01, 0x30, 0x0d, 0x06, 0x09,
++        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
++        0x03, 0x82, 0x01, 0x01, 0x00, 0x9d, 0x6e, 0x0d, 0x93, 0x89, 0xab,
++        0x6e, 0x74, 0x52, 0x2c, 0xe6, 0x89, 0xcb, 0x72, 0x49, 0x90, 0x0d,
++        0x91, 0x80, 0xb5, 0xca, 0x7b, 0x95, 0x0d, 0xa8, 0x05, 0x31, 0x04,
++        0x50, 0xb8, 0xf3, 0xce, 0x9c, 0xbb, 0x05, 0x38, 0x0a, 0x64, 0x1a,
++        0x61, 0x68, 0xa7, 0xa8, 0xa0, 0x69, 0x2a, 0x79, 0x01, 0x42, 0x67,
++        0xf5, 0x72, 0xdf, 0x37, 0x5b, 0x42, 0x6d, 0x3c, 0x59, 0x95, 0x09,
++        0x34, 0xb3, 0xb6, 0x8b, 0x2b, 0xd8, 0xab, 0xb6, 0x8b, 0xff, 0x8e,
++        0xae, 0xd0, 0xc6, 0x9a, 0xbe, 0x7e, 0x29, 0xbc, 0x4d, 0xfb, 0xe1,
++        0xac, 0xd8, 0x23, 0x1a, 0xec, 0x0d, 0xa1, 0xa0, 0xf6, 0x52, 0x8e,
++        0x64, 0xc4, 0x11, 0x0f, 0x7c, 0x5b, 0x9f, 0x65, 0x4f, 0x5a, 0xd6,
++        0x64, 0xe0, 0x64, 0xf6, 0xac, 0x9d, 0xdc, 0x21, 0x3f, 0xa8, 0x5c,
++        0xd2, 0xf5, 0x87, 0xec, 0x49, 0x19, 0xff, 0x01, 0x9e, 0x8d, 0x83,
++        0x08, 0xd2, 0xdc, 0x83, 0xf6, 0x03, 0xc4, 0x6f, 0xf6, 0xa2, 0x13,
++        0x41, 0xfe, 0x66, 0xcd, 0xeb, 0xe8, 0x0f, 0x28, 0x7d, 0xd2, 0xcd,
++        0xfa, 0x7a, 0xd7, 0xae, 0x08, 0xa1, 0x31, 0x17, 0x60, 0x59, 0x39,
++        0x98, 0x85, 0xe1, 0xa4, 0xd2, 0x35, 0x70, 0xb7, 0xff, 0xf3, 0x2f,
++        0xee, 0x45, 0x9c, 0xbe, 0xcc, 0x18, 0x49, 0x94, 0xe9, 0xf6, 0xd0,
++        0x45, 0x54, 0x6f, 0xe4, 0xe8, 0x3a, 0x0d, 0x5b, 0x05, 0xe8, 0x02,
++        0x51, 0x5b, 0x63, 0xb5, 0xf2, 0x47, 0x86, 0x9b, 0xf3, 0x07, 0xc2,
++        0x49, 0x26, 0xa0, 0x77, 0x94, 0xe7, 0x4f, 0xbc, 0x5f, 0x9f, 0xf9,
++        0x06, 0x0e, 0xcb, 0x45, 0x9c, 0x02, 0x11, 0xfc, 0xcb, 0x12, 0x7f,
++        0xba, 0x7d, 0x93, 0x5b, 0x57, 0x6a, 0x15, 0x5e, 0xd2, 0xc1, 0x97,
++        0xb2, 0xbb, 0x00, 0x2c, 0xdd, 0x41, 0x97, 0x2a, 0xe4, 0x53, 0x40,
++        0xf8, 0xb5, 0x56, 0xf2, 0x9a, 0x04, 0xe6, 0x89
++    };
++
++    WOLFSSL_CERT_MANAGER* cm = NULL;
++
++    ExpectNotNull(cm = wolfSSL_CertManagerNew());
++
++    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, ca_cert_idp,
++        sizeof(ca_cert_idp), WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
++
++    ExpectIntEQ(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECKALL),
++        WOLFSSL_SUCCESS);
++
++    /* User-scope CRL has a critical IDP extension, must be rejected */
++    ExpectIntNE(wolfSSL_CertManagerLoadCRLBuffer(cm, crl_user_idp,
++        sizeof(crl_user_idp), WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
++
++    /* CA-only CRL also has a critical IDP extension, must be rejected */
++    ExpectIntNE(wolfSSL_CertManagerLoadCRLBuffer(cm, crl_caonly_idp,
++        sizeof(crl_caonly_idp), WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
++
++    wolfSSL_CertManagerFree(cm);
++#endif
++    return EXPECT_RESULT();
++}
++
++int test_wolfSSL_CRL_unknown_critical_ext(void)
++{
++    EXPECT_DECLS;
++#if !defined(NO_CERTS) && defined(HAVE_CRL) && !defined(NO_RSA)
++
++    static const unsigned char ca_cert[] = {
++        0x30, 0x82, 0x03, 0x1b, 0x30, 0x82, 0x02, 0x03, 0xa0, 0x03, 0x02,
++        0x01, 0x02, 0x02, 0x14, 0x1e, 0x25, 0xc1, 0x5d, 0x6f, 0x02, 0x21,
++        0xa0, 0xf0, 0x14, 0x15, 0x9c, 0x3b, 0x4d, 0x1d, 0x73, 0x16, 0x00,
++        0xe4, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
++        0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30,
++        0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61,
++        0x69, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x1e, 0x17, 0x0d,
++        0x32, 0x36, 0x30, 0x34, 0x31, 0x36, 0x31, 0x31, 0x33, 0x38, 0x35,
++        0x35, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x30, 0x34, 0x31, 0x33, 0x31,
++        0x31, 0x33, 0x38, 0x35, 0x35, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
++        0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61,
++        0x69, 0x6d, 0x2d, 0x72, 0x6f, 0x6f, 0x74, 0x30, 0x82, 0x01, 0x22,
++        0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
++        0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82,
++        0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xba, 0x49, 0x8c, 0xb5,
++        0x17, 0xc1, 0x01, 0x24, 0x6f, 0x56, 0x1a, 0xa9, 0x3b, 0x03, 0xe2,
++        0x9f, 0x24, 0xb1, 0x25, 0x98, 0xfb, 0x38, 0x82, 0x78, 0x54, 0xa7,
++        0x1f, 0x69, 0x87, 0xe4, 0x96, 0x1b, 0x81, 0x18, 0x10, 0xb0, 0xc0,
++        0x5b, 0x4b, 0xbf, 0xb8, 0x1d, 0xf4, 0xee, 0x75, 0x0f, 0xb5, 0x45,
++        0x72, 0x70, 0xce, 0x65, 0x84, 0x44, 0x3e, 0x30, 0x78, 0xc4, 0xf3,
++        0xec, 0xba, 0x96, 0x78, 0xa4, 0x65, 0xfc, 0x62, 0x8d, 0xf5, 0x29,
++        0xf9, 0x7c, 0x3d, 0x78, 0x6c, 0x1d, 0x4a, 0x4c, 0xc9, 0x15, 0x2d,
++        0x22, 0x10, 0xea, 0x93, 0x26, 0xb8, 0xa6, 0x17, 0xd3, 0x0e, 0xbc,
++        0x0c, 0xab, 0x83, 0x63, 0xf6, 0x1c, 0xcc, 0x83, 0x73, 0x29, 0x7e,
++        0x7f, 0x83, 0x7f, 0xbd, 0x63, 0xaa, 0x8d, 0xfa, 0x78, 0x85, 0xd2,
++        0x3e, 0x60, 0x95, 0x5a, 0x8d, 0xfa, 0x8f, 0xcd, 0x94, 0x3f, 0x13,
++        0x28, 0xd9, 0xd0, 0x87, 0x28, 0x17, 0x78, 0xe2, 0x61, 0x8d, 0x79,
++        0x97, 0x01, 0xa9, 0x7c, 0x84, 0xc0, 0x1c, 0xbe, 0x5f, 0x5d, 0xca,
++        0x28, 0x6b, 0x5e, 0xdd, 0x83, 0xa5, 0x55, 0x34, 0x11, 0xba, 0xfa,
++        0x8b, 0x92, 0xa3, 0xde, 0xb6, 0xf3, 0xba, 0xab, 0x7f, 0x1a, 0x67,
++        0xfd, 0x6f, 0x20, 0x85, 0x4c, 0x77, 0xa7, 0x8e, 0xbe, 0xb8, 0xf8,
++        0x8f, 0x70, 0xe3, 0x5a, 0xd3, 0x77, 0xc9, 0x9e, 0x10, 0x60, 0xb4,
++        0xdb, 0x0c, 0xc5, 0x05, 0xe1, 0x1f, 0xbd, 0xe6, 0x79, 0xee, 0x82,
++        0x3f, 0x51, 0x76, 0xe2, 0x7f, 0x5c, 0x11, 0x6d, 0xd3, 0x21, 0x69,
++        0xec, 0x05, 0x11, 0x8b, 0xc8, 0x39, 0xb3, 0x2c, 0xa6, 0x83, 0xb4,
++        0x6f, 0xac, 0x19, 0xd6, 0x6a, 0x65, 0x0d, 0x08, 0x94, 0x58, 0xde,
++        0x3d, 0xc9, 0x0c, 0x54, 0x03, 0x73, 0x0c, 0x8d, 0x24, 0x09, 0xf3,
++        0xb1, 0x5d, 0xd2, 0xe3, 0xeb, 0x56, 0xd6, 0x28, 0x66, 0x5b, 0x02,
++        0x03, 0x01, 0x00, 0x01, 0xa3, 0x63, 0x30, 0x61, 0x30, 0x0f, 0x06,
++        0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03,
++        0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01,
++        0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x01, 0x06, 0x30, 0x1d, 0x06,
++        0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x52, 0x97, 0x58,
++        0x47, 0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e,
++        0xea, 0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x1f, 0x06, 0x03, 0x55,
++        0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x52, 0x97, 0x58,
++        0x47, 0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e,
++        0xea, 0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x0d, 0x06, 0x09, 0x2a,
++        0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03,
++        0x82, 0x01, 0x01, 0x00, 0x7d, 0x30, 0xd4, 0x6a, 0x01, 0x89, 0x3b,
++        0x62, 0xed, 0x16, 0x46, 0x59, 0x0f, 0xf2, 0x3b, 0xb5, 0xde, 0x89,
++        0x08, 0x17, 0x68, 0xcb, 0x46, 0xdc, 0x39, 0xa6, 0xcb, 0x56, 0xb0,
++        0x91, 0xeb, 0x03, 0xb2, 0x15, 0xc4, 0x3b, 0x4d, 0x63, 0x55, 0x22,
++        0x0a, 0x26, 0xe6, 0x64, 0x46, 0xe8, 0x0f, 0xa8, 0xf3, 0xde, 0xe1,
++        0x43, 0x54, 0xe6, 0xd7, 0x8a, 0xf4, 0x4f, 0xab, 0x56, 0x93, 0x12,
++        0x71, 0x4b, 0x25, 0x71, 0x0a, 0x31, 0x18, 0x79, 0xee, 0x45, 0xa4,
++        0xf5, 0x72, 0x67, 0xfa, 0x41, 0xd9, 0x87, 0x97, 0x09, 0xef, 0x55,
++        0xad, 0x6f, 0x47, 0x1d, 0x5a, 0xb2, 0xe9, 0xf7, 0x22, 0x05, 0x2d,
++        0x5a, 0x81, 0xa8, 0xe8, 0x53, 0xb0, 0x94, 0xf6, 0x63, 0xff, 0x3f,
++        0x51, 0x7a, 0x08, 0xac, 0x27, 0x9a, 0x57, 0x11, 0x22, 0xa4, 0x00,
++        0x84, 0x70, 0x86, 0x76, 0x39, 0x0f, 0x4f, 0x57, 0xcf, 0x8e, 0x94,
++        0xd2, 0x8e, 0x43, 0xc0, 0xd5, 0x34, 0x7d, 0xf5, 0xa1, 0x45, 0x1e,
++        0xb7, 0xc8, 0x7e, 0x7c, 0xfe, 0x5d, 0x4d, 0x53, 0x43, 0x25, 0x15,
++        0x9e, 0x08, 0x01, 0x56, 0xa4, 0xff, 0x79, 0x59, 0x25, 0xc9, 0x23,
++        0x98, 0xaf, 0x05, 0xaf, 0xc1, 0x0b, 0x29, 0xf1, 0xe2, 0xc4, 0x36,
++        0x31, 0x91, 0xfa, 0xf2, 0xbb, 0x12, 0xe8, 0x67, 0xf9, 0xc7, 0xa1,
++        0x5e, 0x8c, 0xed, 0x92, 0x12, 0xa3, 0x2b, 0xe1, 0xc2, 0xe1, 0xa0,
++        0xb0, 0x0e, 0x12, 0xa7, 0xd0, 0xa2, 0xae, 0xd6, 0xfa, 0x30, 0x21,
++        0x0f, 0x73, 0xfe, 0x24, 0x21, 0x5f, 0x03, 0x86, 0x69, 0xcd, 0xec,
++        0x76, 0x18, 0xe1, 0xfd, 0xb6, 0x64, 0x90, 0xa6, 0x06, 0x2e, 0x19,
++        0x40, 0x93, 0x50, 0x37, 0xe4, 0x90, 0xe3, 0x1f, 0x07, 0xae, 0xfb,
++        0x89, 0xc3, 0xf6, 0xc4, 0x90, 0xab, 0x40, 0x67, 0x4c, 0x43, 0x2c,
++        0xa2, 0xb0, 0x3e, 0x61, 0x16, 0x69, 0x8f
++    };
++
++    /* CRL with critical obsolete extension OID 2.5.29.1, 422 bytes DER.
++     * OID 2.5.29.1 is the old X.509v2 Authority Key Identifier, permanently
++     * superseded by 2.5.29.35. No implementation will ever support it. */
++    static const unsigned char crl_obsolete_critical[] = {
++        0x30, 0x82, 0x01, 0xa6, 0x30, 0x81, 0x8f, 0x02, 0x01, 0x01, 0x30,
++        0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
++        0x0b, 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
++        0x55, 0x04, 0x03, 0x0c, 0x0a, 0x63, 0x6c, 0x61, 0x69, 0x6d, 0x2d,
++        0x72, 0x6f, 0x6f, 0x74, 0x17, 0x0d, 0x32, 0x36, 0x30, 0x34, 0x31,
++        0x36, 0x31, 0x35, 0x32, 0x31, 0x30, 0x37, 0x5a, 0x17, 0x0d, 0x33,
++        0x36, 0x30, 0x34, 0x31, 0x33, 0x31, 0x35, 0x32, 0x31, 0x30, 0x37,
++        0x5a, 0xa0, 0x46, 0x30, 0x44, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d,
++        0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x52, 0x97, 0x58, 0x47,
++        0x98, 0xca, 0xf8, 0x99, 0xa0, 0x7e, 0x8e, 0x1c, 0x38, 0x2e, 0xea,
++        0xbb, 0xea, 0x9b, 0x74, 0x30, 0x30, 0x14, 0x06, 0x03, 0x55, 0x1d,
++        0x01, 0x01, 0x01, 0xff, 0x04, 0x0a, 0x0c, 0x08, 0x6f, 0x62, 0x73,
++        0x6f, 0x6c, 0x65, 0x74, 0x65, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d,
++        0x14, 0x04, 0x04, 0x02, 0x02, 0x20, 0x02, 0x30, 0x0d, 0x06, 0x09,
++        0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00,
++        0x03, 0x82, 0x01, 0x01, 0x00, 0x05, 0xf3, 0x8f, 0xdb, 0x7f, 0x75,
++        0x2c, 0x34, 0x4b, 0x7e, 0x70, 0x17, 0x5e, 0x34, 0xc6, 0xdb, 0xcb,
++        0x54, 0x33, 0x06, 0x58, 0x6d, 0xae, 0x9c, 0xc8, 0xe3, 0xaf, 0x82,
++        0xe5, 0xf6, 0x86, 0x42, 0xb3, 0x01, 0x72, 0x1a, 0xca, 0xf9, 0x10,
++        0x5d, 0x14, 0xe6, 0x84, 0x34, 0x56, 0x55, 0x74, 0xb5, 0x06, 0x64,
++        0x49, 0x1d, 0xb3, 0xb0, 0x13, 0xff, 0x1c, 0x05, 0x4f, 0x43, 0x29,
++        0xbc, 0xfe, 0xb5, 0x92, 0x54, 0xf6, 0x9b, 0x81, 0x07, 0x5e, 0x2e,
++        0x75, 0xd8, 0xfd, 0x9b, 0x5b, 0xc9, 0xd3, 0xc2, 0x15, 0xa7, 0x6e,
++        0x2f, 0x4b, 0x3a, 0x27, 0x57, 0xef, 0x40, 0x61, 0x8c, 0x11, 0x9d,
++        0x0a, 0xb1, 0x2b, 0x0e, 0xed, 0x5d, 0xf2, 0xf5, 0x1a, 0xce, 0xdc,
++        0xd7, 0x75, 0xc6, 0x25, 0x22, 0xe4, 0x70, 0xad, 0x93, 0xff, 0x36,
++        0xa1, 0xa2, 0xa0, 0xd9, 0x82, 0x23, 0x6e, 0xc8, 0x3a, 0x80, 0x82,
++        0xbf, 0x12, 0xac, 0xa1, 0xf9, 0x03, 0x9c, 0xb9, 0x20, 0x91, 0x33,
++        0x80, 0x7b, 0xb7, 0x6e, 0xa5, 0x32, 0x98, 0xd6, 0x2c, 0x5d, 0x9d,
++        0x3b, 0x64, 0x3b, 0xb4, 0xea, 0x03, 0x2d, 0x65, 0xcf, 0x7f, 0x0f,
++        0x97, 0xef, 0x5b, 0x17, 0x8c, 0xcf, 0x98, 0x69, 0xba, 0x2d, 0x62,
++        0xe9, 0x40, 0xe2, 0x3d, 0xbd, 0xd2, 0x0f, 0x4a, 0xf8, 0xb0, 0xa7,
++        0xdb, 0x80, 0xa3, 0x47, 0x56, 0xe5, 0xe6, 0x6f, 0x93, 0x5c, 0x6f,
++        0xdd, 0x62, 0x43, 0x28, 0x5c, 0xe5, 0x8f, 0x0e, 0x11, 0xa6, 0x1f,
++        0x61, 0xaf, 0x39, 0x15, 0x40, 0xf4, 0x6e, 0x79, 0x40, 0xf6, 0x28,
++        0xf3, 0xd4, 0x30, 0x3b, 0x25, 0xb6, 0xf0, 0x4a, 0x51, 0xc3, 0x18,
++        0xff, 0xad, 0x4d, 0x6e, 0x10, 0x73, 0x68, 0xfa, 0x54, 0x9e, 0xdc,
++        0x34, 0x70, 0xe4, 0x5d, 0x9e, 0x7c, 0xfa, 0x59, 0x97, 0xde, 0x35,
++        0x17, 0xbb, 0xaf, 0xa0, 0x28, 0x78, 0x13, 0xbf
++    };
++
++    WOLFSSL_CERT_MANAGER* cm = NULL;
++
++    ExpectNotNull(cm = wolfSSL_CertManagerNew());
++    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, ca_cert,
++        sizeof(ca_cert), WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECKALL),
++        WOLFSSL_SUCCESS);
++
++    ExpectIntNE(wolfSSL_CertManagerLoadCRLBuffer(cm, crl_obsolete_critical,
++        sizeof(crl_obsolete_critical), WOLFSSL_FILETYPE_ASN1),
++        WOLFSSL_SUCCESS);
++
++    wolfSSL_CertManagerFree(cm);
++#endif
++    return EXPECT_RESULT();
++}
++
+ int test_wolfSSL_CertManagerCheckOCSPResponse(void)
+ {
+     EXPECT_DECLS;
+diff --git a/tests/api/test_certman.h b/tests/api/test_certman.h
+index a0b5d9548..3b6afd0fc 100644
+--- a/tests/api/test_certman.h
++++ b/tests/api/test_certman.h
+@@ -39,6 +39,8 @@ int test_wolfSSL_CertManagerCRL(void);
+ int test_wolfSSL_CRL_reason_extensions_cleanup(void);
+ int test_wolfSSL_CRL_static_revoked_list(void);
+ int test_wolfSSL_CRL_duplicate_extensions(void);
++int test_wolfSSL_CRL_critical_idp(void);
++int test_wolfSSL_CRL_unknown_critical_ext(void);
+ int test_wolfSSL_CertManagerCheckOCSPResponse(void);
+ int test_various_pathlen_chains(void);
+ int test_wolfSSL_CertManagerRejectMD5Cert(void);
+@@ -59,6 +61,8 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void);
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_reason_extensions_cleanup), \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_static_revoked_list),      \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_duplicate_extensions),      \
++    TEST_DECL_GROUP("certman", test_wolfSSL_CRL_critical_idp),             \
++    TEST_DECL_GROUP("certman", test_wolfSSL_CRL_unknown_critical_ext),     \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCheckOCSPResponse),  \
+     TEST_DECL_GROUP("certman", test_various_pathlen_chains),                \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerRejectMD5Cert)
+diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c
+index 8d4f40a70..f8db5c457 100644
+--- a/wolfcrypt/src/asn.c
++++ b/wolfcrypt/src/asn.c
+@@ -34497,14 +34497,17 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf, word32 idx,
+                     mp_free(m);
+                     FREE_MP_INT_SIZE(m, NULL, DYNAMIC_TYPE_TMP_BUFFER);
+                 }
++                else if (critical) {
++                    WOLFSSL_MSG("Unknown critical CRL extension");
++                    ret = ASN_CRIT_EXT_E;
++                }
+             }
+-            /* TODO: check criticality */
+             /* Move index on to next extension. */
+             idx += (word32)length;
+         }
+     }
+ 
+-    if (ret < 0) {
++    if (ret < 0 && ret != WC_NO_ERR_TRACE(ASN_CRIT_EXT_E)) {
+         ret = ASN_PARSE_E;
+     }
+ 
+diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c
+index 9ecb821d3..d6568aa5d 100644
+--- a/wolfcrypt/src/asn_orig.c
++++ b/wolfcrypt/src/asn_orig.c
+@@ -9327,6 +9327,7 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf,
+     while (idx < (word32)ext_bound) {
+         word32 localIdx;
+         int ret;
++        int critical = 0;
+ 
+         if (GetSequence(buf, &idx, &length, sz) < 0) {
+             WOLFSSL_MSG("\tfail: should be a SEQUENCE");
+@@ -9346,11 +9347,13 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf,
+         }
+ 
+         localIdx = idx;
+-        if (GetASNTag(buf, &localIdx, &tag, sz) == 0 && tag == ASN_BOOLEAN) {
++        if (GetASNTag(buf, &localIdx, &tag, sz) == 0 &&
++                tag == ASN_BOOLEAN) {
+             WOLFSSL_MSG("\tfound optional critical flag, moving past");
+             ret = GetBoolean(buf, &idx, sz);
+             if (ret < 0)
+                 return ret;
++            critical = ret;
+         }
+ 
+         ret = GetOctetString(buf, &idx, &length, sz);
+@@ -9428,6 +9431,10 @@ static int ParseCRL_Extensions(DecodedCRL* dcrl, const byte* buf,
+                 }
+             }
+         }
++        else if (critical) {
++            WOLFSSL_MSG("Unknown critical CRL extension");
++            return ASN_CRIT_EXT_E;
++        }
+ 
+         idx += length;
+     }
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-2.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-2.patch
new file mode 100644
index 0000000000..0118a8d1ab
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6450-2.patch
@@ -0,0 +1,404 @@
+From 501762b4913f744f42605f8cdb3e3ac6dd37916e Mon Sep 17 00:00:00 2001
+From: Reda Chouk <reda@wolfssl.com>
+Date: Tue, 21 Apr 2026 16:53:59 +0200
+Subject: [PATCH] reject crls with unrecognized critical entry extensions per
+ rfc 5280 section 5.3
+
+(cherry picked from commit 6111c60ea69fa02e1a74cf432c20bd6b789eae67)
+
+CVE: CVE-2026-6450
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/6111c60ea69fa02e1a74cf432c20bd6b789eae67]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ certs/crl/extra-crls/claim-root.pem         |  19 +++
+ certs/crl/extra-crls/crl_critical_entry.pem |  11 ++
+ certs/crl/include.am                        |   4 +-
+ tests/api/test_certman.c                    |  25 ++++
+ tests/api/test_certman.h                    |   2 +
+ wolfcrypt/src/asn.c                         | 133 +++++++++++++-------
+ wolfcrypt/src/asn_orig.c                    |  28 ++++-
+ 7 files changed, 171 insertions(+), 51 deletions(-)
+ create mode 100644 certs/crl/extra-crls/claim-root.pem
+ create mode 100644 certs/crl/extra-crls/crl_critical_entry.pem
+
+diff --git a/certs/crl/extra-crls/claim-root.pem b/certs/crl/extra-crls/claim-root.pem
+new file mode 100644
+index 000000000..a212501aa
+--- /dev/null
++++ b/certs/crl/extra-crls/claim-root.pem
+@@ -0,0 +1,19 @@
++-----BEGIN CERTIFICATE-----
++MIIDGzCCAgOgAwIBAgIUHiXBXW8CIaDwFBWcO00dcxYA5FEwDQYJKoZIhvcNAQEL
++BQAwFTETMBEGA1UEAwwKY2xhaW0tcm9vdDAeFw0yNjA0MTYxMTM4NTVaFw0zNjA0
++MTMxMTM4NTVaMBUxEzARBgNVBAMMCmNsYWltLXJvb3QwggEiMA0GCSqGSIb3DQEB
++AQUAA4IBDwAwggEKAoIBAQC6SYy1F8EBJG9WGqk7A+KfJLElmPs4gnhUpx9ph+SW
++G4EYELDAW0u/uB307nUPtUVycM5lhEQ+MHjE8+y6lnikZfxijfUp+Xw9eGwdSkzJ
++FS0iEOqTJrimF9MOvAyrg2P2HMyDcyl+f4N/vWOqjfp4hdI+YJVajfqPzZQ/EyjZ
++0IcoF3jiYY15lwGpfITAHL5fXcooa17dg6VVNBG6+ouSo96287qrfxpn/W8ghUx3
++p46+uPiPcONa03fJnhBgtNsMxQXhH73mee6CP1F24n9cEW3TIWnsBRGLyDmzLKaD
++tG+sGdZqZQ0IlFjePckMVANzDI0kCfOxXdLj61bWKGZbAgMBAAGjYzBhMA8GA1Ud
++EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRSl1hHmMr4maB+
++jhw4Luq76pt0MDAfBgNVHSMEGDAWgBRSl1hHmMr4maB+jhw4Luq76pt0MDANBgkq
++hkiG9w0BAQsFAAOCAQEAfTDUagGJO2LtFkZZD/I7td6JCBdoy0bcOabLVrCR6wOy
++FcQ7TWNVIgom5mRG6A+o897hQ1Tm14r0T6tWkxJxSyVxCjEYee5FpPVyZ/pB2YeX
++Ce9VrW9HHVqy6fciBS1agajoU7CU9mP/P1F6CKwnmlcRIqQAhHCGdjkPT1fPjpTS
++jkPA1TR99aFFHrfIfnz+XU1TQyUVnggBVqT/eVklySOYrwWvwQsp8eLENjGR+vK7
++Euhn+cehXoztkhKjK+HC4aCwDhKn0KKu1vowIQ9z/iQhXwOGac3sdhjh/bZkkKYG
++LhlAk1A35JDjHweu+4nD9sSQq0BnTEMsorA+YRZpjw==
++-----END CERTIFICATE-----
+diff --git a/certs/crl/extra-crls/crl_critical_entry.pem b/certs/crl/extra-crls/crl_critical_entry.pem
+new file mode 100644
+index 000000000..11d9d31ab
+--- /dev/null
++++ b/certs/crl/extra-crls/crl_critical_entry.pem
+@@ -0,0 +1,11 @@
++-----BEGIN X509 CRL-----
++MIIBjDB2AgEBMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNVBAMMCmNsYWltLXJvb3QX
++DTI2MDQyMTEyMzM0OFoXDTM2MDQxODEyMzM0OFowLTArAgIQABcNMjYwNDIxMTIz
++MzQ4WjAWMBQGA1UdAQEB/wQKDAhvYnNvbGV0ZTANBgkqhkiG9w0BAQsFAAOCAQEA
++PPG5bodrM2jK+6KcqRh9vEkWhLyxCkJij1om7R8BMO5bpvxZFOSqdN9GvIqYANYT
++ZNQzZZOer9DSXc1I9Cha179dyGnBsX33geSdhF99JxA/kZUVynfOn56El7iywkPQ
++yEpuY7uQQRfcp7D7tGz8S7mNhOMAeaN+jR2Psmn8q1Yc3W01vwYZos3qjHG1xDZ6
++97QVFX6tbnbeu/hBsF87oiAyCbXnhRQOvrVsKqjrZXGkfRKfJ1deHc1vWgio7fhr
++A1/Hb4sdfTWZUwtduTRI9Vyaw1IL41d+0ExdzTshIHbddB/dyByrRqlIzJdeiigt
++d1Gcf1EYSoWiV8Xaj9SFng==
++-----END X509 CRL-----
+diff --git a/certs/crl/include.am b/certs/crl/include.am
+index 46d0ed3e7..a0c526d91 100644
+--- a/certs/crl/include.am
++++ b/certs/crl/include.am
+@@ -27,7 +27,9 @@ EXTRA_DIST += \
+ 		certs/crl/extra-crls/large_crlnum.pem \
+ 		certs/crl/extra-crls/large_crlnum2.pem \
+ 		certs/crl/extra-crls/crlnum_57oct.pem \
+-		certs/crl/extra-crls/crlnum_64oct.pem
++		certs/crl/extra-crls/crlnum_64oct.pem \
++		certs/crl/extra-crls/claim-root.pem \
++		certs/crl/extra-crls/crl_critical_entry.pem
+ 
+ # Intermediate cert CRL's
+ EXTRA_DIST += \
+diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c
+index 7405f4bff..d9000c7cf 100644
+--- a/tests/api/test_certman.c
++++ b/tests/api/test_certman.c
+@@ -2306,6 +2306,31 @@ int test_wolfSSL_CRL_unknown_critical_ext(void)
+     return EXPECT_RESULT();
+ }
+ 
++int test_wolfSSL_CRL_unknown_critical_entry_ext(void)
++{
++    EXPECT_DECLS;
++#if !defined(NO_CERTS) && defined(HAVE_CRL) && !defined(NO_RSA) && \
++    !defined(NO_FILESYSTEM)
++    WOLFSSL_CERT_MANAGER* cm = NULL;
++
++    ExpectNotNull(cm = wolfSSL_CertManagerNew());
++    ExpectIntEQ(wolfSSL_CertManagerLoadCA(cm,
++        "./certs/crl/extra-crls/claim-root.pem", NULL), WOLFSSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_CertManagerEnableCRL(cm, WOLFSSL_CRL_CHECKALL),
++        WOLFSSL_SUCCESS);
++
++    /* CRL with a revoked entry that carries a critical unknown extension
++     * (OID 2.5.29.1, old X.509v2 AKI, permanently superseded).
++     * Per RFC 5280 Section 5.3, the CRL must not be used. */
++    ExpectIntNE(wolfSSL_CertManagerLoadCRLFile(cm,
++        "./certs/crl/extra-crls/crl_critical_entry.pem", WOLFSSL_FILETYPE_PEM),
++        WOLFSSL_SUCCESS);
++
++    wolfSSL_CertManagerFree(cm);
++#endif
++    return EXPECT_RESULT();
++}
++
+ int test_wolfSSL_CertManagerCheckOCSPResponse(void)
+ {
+     EXPECT_DECLS;
+diff --git a/tests/api/test_certman.h b/tests/api/test_certman.h
+index 3b6afd0fc..0962b0228 100644
+--- a/tests/api/test_certman.h
++++ b/tests/api/test_certman.h
+@@ -41,6 +41,7 @@ int test_wolfSSL_CRL_static_revoked_list(void);
+ int test_wolfSSL_CRL_duplicate_extensions(void);
+ int test_wolfSSL_CRL_critical_idp(void);
+ int test_wolfSSL_CRL_unknown_critical_ext(void);
++int test_wolfSSL_CRL_unknown_critical_entry_ext(void);
+ int test_wolfSSL_CertManagerCheckOCSPResponse(void);
+ int test_various_pathlen_chains(void);
+ int test_wolfSSL_CertManagerRejectMD5Cert(void);
+@@ -63,6 +64,7 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void);
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_duplicate_extensions),      \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_critical_idp),             \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_unknown_critical_ext),     \
++    TEST_DECL_GROUP("certman", test_wolfSSL_CRL_unknown_critical_entry_ext), \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCheckOCSPResponse),  \
+     TEST_DECL_GROUP("certman", test_various_pathlen_chains),                \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerRejectMD5Cert)
+diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c
+index f8db5c457..1dc27cfd0 100644
+--- a/wolfcrypt/src/asn.c
++++ b/wolfcrypt/src/asn.c
+@@ -34039,16 +34039,22 @@ enum {
+ /* CRL Reason Code OID: 2.5.29.21 */
+ static const byte crlReasonOid[] = { 0x55, 0x1d, 0x15 };
+ 
+-/* Parse CRL entry extensions to extract the reason code.
+- * Sets *reasonCode if found, otherwise leaves it unchanged. */
+-static void ParseCRL_ReasonCode(const byte* buff, word32 idx, word32 maxIdx,
+-                                int* reasonCode)
++/* Parse CRL entry extensions.
++ * Extracts the reason code into *reasonCode if the CRL Reason extension
++ * is present. Per RFC 5280 Section 5.3, returns ASN_CRIT_EXT_E if any
++ * unknown extension is marked critical. Returns 0 on success. */
++static int ParseCRL_EntryExtensions(const byte* buff, word32 idx, word32 maxIdx,
++                                    int* reasonCode)
+ {
+     while (idx < maxIdx) {
+         int len;
++        int oidLen;
+         word32 end;
+         word32 localIdx;
++        word32 oidContent;
+         byte tag;
++        int critical = 0;
++        int isReasonOid = 0;
+ 
+         /* Each extension is a SEQUENCE */
+         if (GetSequence(buff, &idx, &len, maxIdx) < 0) {
+@@ -34056,23 +34062,39 @@ static void ParseCRL_ReasonCode(const byte* buff, word32 idx, word32 maxIdx,
+         }
+         end = idx + (word32)len;
+ 
+-        /* Check for CRL Reason OID: 2.5.29.21 */
+-        if (end - idx >= (word32)(2 + sizeof(crlReasonOid)) &&
+-                buff[idx] == ASN_OBJECT_ID &&
+-                buff[idx + 1] == sizeof(crlReasonOid) &&
+-                XMEMCMP(buff + idx + 2, crlReasonOid,
++        /* Parse OID: tag, length (short or long form), content */
++        if (GetASNTag(buff, &idx, &tag, end) < 0 ||
++                tag != ASN_OBJECT_ID) {
++            break;
++        }
++        if (GetLength(buff, &idx, &oidLen, end) < 0) {
++            break;
++        }
++        oidContent = idx;
++        if (idx + (word32)oidLen > end) {
++            break;
++        }
++
++        /* Check if it's the CRL Reason OID: 2.5.29.21 */
++        if ((word32)oidLen == sizeof(crlReasonOid) &&
++                XMEMCMP(buff + oidContent, crlReasonOid,
+                         sizeof(crlReasonOid)) == 0) {
+-            /* Skip past the OID */
+-            idx += 2 + (word32)sizeof(crlReasonOid);
+-            /* Skip optional critical BOOLEAN */
+-            localIdx = idx;
+-            if (GetASNTag(buff, &localIdx, &tag, end) == 0 &&
+-                    tag == ASN_BOOLEAN) {
+-                /* Consume full BOOLEAN TLV (tag + length + value). */
+-                if (GetBoolean(buff, &idx, end) < 0) {
+-                    break;
+-                }
++            isReasonOid = 1;
++        }
++        idx = oidContent + (word32)oidLen;
++
++        /* Parse optional critical BOOLEAN */
++        localIdx = idx;
++        if (GetASNTag(buff, &localIdx, &tag, end) == 0 &&
++                tag == ASN_BOOLEAN) {
++            int ret = GetBoolean(buff, &idx, end);
++            if (ret < 0) {
++                break;
+             }
++            critical = ret;
++        }
++
++        if (isReasonOid) {
+             /* Get OCTET STRING wrapping the ENUMERATED */
+             if (GetOctetString(buff, &idx, &len, end) >= 0) {
+                 /* Parse ENUMERATED reason value */
+@@ -34088,8 +34110,15 @@ static void ParseCRL_ReasonCode(const byte* buff, word32 idx, word32 maxIdx,
+                 }
+             }
+         }
++        else if (critical) {
++            /* RFC 5280 Section 5.3: reject CRL with unknown critical
++             * entry extension. */
++            WOLFSSL_MSG("Unknown critical CRL entry extension");
++            return ASN_CRIT_EXT_E;
++        }
+         idx = end;
+     }
++    return 0;
+ }
+ 
+ #ifdef HAVE_CRL
+@@ -34102,8 +34131,7 @@ WOLFSSL_TEST_VIS int wc_ParseCRLReasonFromExtensions(const byte* ext,
+         return BAD_FUNC_ARG;
+     }
+ 
+-    ParseCRL_ReasonCode(ext, 0, extSz, reasonCode);
+-    return 0;
++    return ParseCRL_EntryExtensions(ext, 0, extSz, reasonCode);
+ }
+ #endif
+ 
+@@ -34166,49 +34194,58 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
+         /* Parse CRL entry extensions (v2 only) */
+         if (dataASN[REVOKEDASN_IDX_TIME_EXT].length > 0) {
+             word32 extOff = dataASN[REVOKEDASN_IDX_TIME_EXT].offset;
+-            word32 extLen = dataASN[REVOKEDASN_IDX_TIME_EXT].length;
+-            word32 extEnd = extOff + extLen;
+-            word32 extIdx2 = extOff;
++            word32 extTagEnd = extOff +
++                    dataASN[REVOKEDASN_IDX_TIME_EXT].length + 6;
++            int extLen;
++
++            /* .offset points at the outer SEQUENCE tag. Re-parse the
++             * SEQUENCE header to locate the content start (list of
++             * Extension SEQUENCEs), which handles long-form length.
++             * extTagEnd adds 6 to cover the worst-case tag+long-form-length
++             * header for the outer SEQUENCE. */
++            if (GetSequence(buff, &extOff, &extLen, extTagEnd) < 0) {
++                ret = ASN_PARSE_E;
++            }
++            else {
++                word32 extEnd = extOff + (word32)extLen;
+ 
+ #if defined(OPENSSL_EXTRA)
+-            /* Store raw DER of extensions for OpenSSL compat API.
+-             * Include the outer SEQUENCE tag+length. */
+-            {
+-                /* Back up to include the SEQUENCE header. We know the
+-                 * content starts at extOff, so the header is just before.
+-                 * Use the raw buffer start from before GetASN_Items. */
+-                word32 seqHdrSz = 0;
+-                /* The outer SEQUENCE header is at most 4 bytes before
+-                 * content. Rather than guess, store just the content. */
+-                rc->extensions = (byte*)XMALLOC(extLen, dcrl->heap,
++                /* Store raw DER of extension contents for OpenSSL compat. */
++                rc->extensions = (byte*)XMALLOC((size_t)extLen, dcrl->heap,
+                                                 DYNAMIC_TYPE_REVOKED);
+                 if (rc->extensions != NULL) {
+-                    XMEMCPY(rc->extensions, buff + extOff, extLen);
+-                    rc->extensionsSz = extLen;
++                    XMEMCPY(rc->extensions, buff + extOff, (size_t)extLen);
++                    rc->extensionsSz = (word32)extLen;
+                 }
+-                (void)seqHdrSz;
+-            }
+ #endif
+ 
+-            ParseCRL_ReasonCode(buff, extIdx2, extEnd, &rc->reasonCode);
++                ret = ParseCRL_EntryExtensions(buff, extOff, extEnd,
++                    &rc->reasonCode);
++            }
+         }
+ 
+-        /* Add revoked certificate to chain. */
++        if (ret == 0) {
++            /* Add revoked certificate to chain. */
+ #ifndef CRL_STATIC_REVOKED_LIST
+-        rc->next = dcrl->certs;
+-        dcrl->certs = rc;
++            rc->next = dcrl->certs;
++            dcrl->certs = rc;
+ #endif
+-        dcrl->totalCerts++;
++            dcrl->totalCerts++;
++        }
+     }
+ 
+     FREE_ASNGETDATA(dataASN, dcrl->heap);
+-#ifndef CRL_STATIC_REVOKED_LIST
+     if ((ret != 0) && (rc != NULL)) {
+ #if defined(OPENSSL_EXTRA)
+         XFREE(rc->extensions, dcrl->heap, DYNAMIC_TYPE_REVOKED);
++        rc->extensions = NULL;
++        rc->extensionsSz = 0;
+ #endif
++#ifndef CRL_STATIC_REVOKED_LIST
+         XFREE(rc, dcrl->heap, DYNAMIC_TYPE_CRL);
++#endif
+     }
++#ifndef CRL_STATIC_REVOKED_LIST
+     (void)rcert;
+ #endif
+     return ret;
+@@ -34232,7 +34269,13 @@ static int ParseCRL_RevokedCerts(RevokedCert* rcert, DecodedCRL* dcrl,
+     /* Parse each revoked certificate. */
+     while ((ret == 0) && (idx < maxIdx)) {
+         /* Parse a revoked certificate. */
+-        if (GetRevoked(rcert, buff, &idx, dcrl, maxIdx) < 0) {
++        int r = GetRevoked(rcert, buff, &idx, dcrl, maxIdx);
++        if (r == WC_NO_ERR_TRACE(ASN_CRIT_EXT_E)) {
++            /* Preserve the specific error so callers can distinguish a
++             * rejected critical extension from a generic parse failure. */
++            ret = r;
++        }
++        else if (r < 0) {
+             ret = ASN_PARSE_E;
+         }
+     }
+diff --git a/wolfcrypt/src/asn_orig.c b/wolfcrypt/src/asn_orig.c
+index d6568aa5d..bb58eb6d4 100644
+--- a/wolfcrypt/src/asn_orig.c
++++ b/wolfcrypt/src/asn_orig.c
+@@ -9061,18 +9061,17 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
+         XFREE(rc, dcrl->heap, DYNAMIC_TYPE_REVOKED);
+         return ret;
+     }
+-    /* add to list */
+-    rc->next = dcrl->certs;
+-    dcrl->certs = rc;
+ 
+     (void)rcert;
+ #endif /* CRL_STATIC_REVOKED_LIST */
+-    dcrl->totalCerts++;
+     /* get date */
+ #ifndef NO_ASN_TIME
+     ret = GetBasicDate(buff, idx, rc->revDate, &rc->revDateFormat, maxIdx);
+     if (ret < 0) {
+         WOLFSSL_MSG("Expecting Date");
++#ifndef CRL_STATIC_REVOKED_LIST
++        XFREE(rc, dcrl->heap, DYNAMIC_TYPE_REVOKED);
++#endif
+         return ret;
+     }
+ #endif
+@@ -9106,11 +9105,30 @@ static int GetRevoked(RevokedCert* rcert, const byte* buff, word32* idx,
+                 }
+ #endif
+ 
+-                ParseCRL_ReasonCode(buff, seqIdx, extEnd, &rc->reasonCode);
++                ret = ParseCRL_EntryExtensions(buff, seqIdx, extEnd,
++                    &rc->reasonCode);
++                if (ret != 0) {
++#if defined(OPENSSL_EXTRA)
++                    XFREE(rc->extensions, dcrl->heap, DYNAMIC_TYPE_REVOKED);
++                    rc->extensions = NULL;
++                    rc->extensionsSz = 0;
++#endif
++#ifndef CRL_STATIC_REVOKED_LIST
++                    XFREE(rc, dcrl->heap, DYNAMIC_TYPE_REVOKED);
++#endif
++                    return ret;
++                }
+             }
+         }
+     }
+ 
++#ifndef CRL_STATIC_REVOKED_LIST
++    /* add to list only after all parsing succeeded */
++    rc->next = dcrl->certs;
++    dcrl->certs = rc;
++#endif
++    dcrl->totalCerts++;
++
+     *idx = end;
+ 
+     return 0;
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 4ca330b029..26b86c1b2b 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -32,6 +32,8 @@ SRC_URI = " \
     file://CVE-2026-6325.patch \
     file://CVE-2026-6412-1.patch \
     file://CVE-2026-6412-2.patch \
+    file://CVE-2026-6450-1.patch \
+    file://CVE-2026-6450-2.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 32/33] wolfssl: patch CVE-2026-6731
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (29 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 31/33] wolfssl: patch CVE-2026-6450 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 33/33] wolfssl: patch CVE-2026-7531 ankur.tyagi85
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-6731

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-6731-1.patch       |  39 ++++
 .../wolfssl/files/CVE-2026-6731-2.patch       | 171 ++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   2 +
 3 files changed, 212 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-1.patch
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-2.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-1.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-1.patch
new file mode 100644
index 0000000000..c6a1762b27
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-1.patch
@@ -0,0 +1,39 @@
+From df2df57a027066708b498f41ce0b591704b579cc Mon Sep 17 00:00:00 2001
+From: Ruby Martin <ruby@wolfssl.com>
+Date: Tue, 14 Apr 2026 12:39:34 -0600
+Subject: [PATCH] Apply DNS constraints to subject CN when SAN is not
+ available.
+
+(cherry picked from commit e7b7fddacb4cc794e5dfc7693586d87a539f5aad)
+
+CVE: CVE-2026-6731
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/e7b7fddacb4cc794e5dfc7693586d87a539f5aad]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ wolfcrypt/src/asn.c | 11 +++++++++--
+ 1 file changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c
+index f8db5c457..d12a78850 100644
+--- a/wolfcrypt/src/asn.c
++++ b/wolfcrypt/src/asn.c
+@@ -17665,9 +17665,16 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
+         XMEMSET(&subjectDnsName, 0, sizeof(DNS_entry));
+         switch (nameType) {
+             case ASN_DNS_TYPE:
+-                /* Should it also consider CN in subject? It could use
+-                 * subjectDnsName too */
+                 name = cert->altNames;
++
++                /* When no SAN is present, apply DNS name constraints to the
++                 * Subject CN. */
++                if (cert->subjectCN != NULL && cert->altNames == NULL) {
++                    subjectDnsName.next = NULL;
++                    subjectDnsName.type = ASN_DNS_TYPE;
++                    subjectDnsName.len  = cert->subjectCNLen;
++                    subjectDnsName.name = cert->subjectCN;
++                }
+                 break;
+             case ASN_IP_TYPE:
+                 /* IP addresses are stored in altNames with type ASN_IP_TYPE */
diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-2.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-2.patch
new file mode 100644
index 0000000000..be5132048e
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-6731-2.patch
@@ -0,0 +1,171 @@
+From 9d1ee979f67c8e31a04b73fadac61f4697bcb7c6 Mon Sep 17 00:00:00 2001
+From: Ruby Martin <ruby@wolfssl.com>
+Date: Tue, 14 Apr 2026 12:44:21 -0600
+Subject: [PATCH] test DNS name constraints on CA are applied against Subject
+ CN name when SAN name is unavailable
+
+test correct CN with no SAN available is accepted
+
+(cherry picked from commit 797ba3f03b1a8dc05c7b91a86c2e6698d76bfc8a)
+
+CVE: CVE-2026-6731
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/797ba3f03b1a8dc05c7b91a86c2e6698d76bfc8a]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ tests/api/test_certman.c | 121 +++++++++++++++++++++++++++++++++++++++
+ tests/api/test_certman.h |   2 +
+ 2 files changed, 123 insertions(+)
+
+diff --git a/tests/api/test_certman.c b/tests/api/test_certman.c
+index 7405f4bff..c76902af2 100644
+--- a/tests/api/test_certman.c
++++ b/tests/api/test_certman.c
+@@ -1584,6 +1584,127 @@ int test_wolfSSL_CertManagerNameConstraint5(void)
+     return EXPECT_RESULT();
+ }
+ 
++int test_wolfSSL_CertManagerNameConstraint_DNS_CN(void)
++{
++    EXPECT_DECLS;
++#if !defined(NO_FILESYSTEM) && !defined(NO_CERTS) && \
++    !defined(NO_WOLFSSL_CM_VERIFY) && !defined(NO_RSA) && \
++    defined(OPENSSL_EXTRA) && defined(WOLFSSL_CERT_GEN) && \
++    defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_ALT_NAMES) && \
++    !defined(NO_SHA256)
++    /* Test that DNS name constraints are enforced against the Subject CN
++     * when no SAN extension is present. The CA cert (cert-ext-ncdns.der)
++     * permits only DNS:wolfssl.com and DNS:example.com. A leaf cert with
++     * CN=evil.attacker.com and no SAN should be REJECTED. */
++    WOLFSSL_CERT_MANAGER* cm = NULL;
++    WOLFSSL_EVP_PKEY *priv = NULL;
++    WOLFSSL_X509_NAME* name = NULL;
++    const char* ca_cert = "./certs/test/cert-ext-ncdns.der";
++    const char* server_cert = "./certs/test/server-goodcn.pem";
++
++    byte    *der = NULL;
++    int     derSz;
++    byte    *pt;
++    WOLFSSL_X509 *x509 = NULL;
++    WOLFSSL_X509 *ca = NULL;
++
++    pt = (byte*)server_key_der_2048;
++    ExpectNotNull(priv = wolfSSL_d2i_PrivateKey(EVP_PKEY_RSA, NULL,
++                (const unsigned char**)&pt, sizeof_server_key_der_2048));
++
++    ExpectNotNull(cm = wolfSSL_CertManagerNew());
++    ExpectNotNull(ca = wolfSSL_X509_load_certificate_file(ca_cert,
++                WOLFSSL_FILETYPE_ASN1));
++    ExpectNotNull((der = (byte*)wolfSSL_X509_get_der(ca, &derSz)));
++    ExpectIntEQ(wolfSSL_CertManagerLoadCABuffer(cm, der, derSz,
++                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
++
++    /* Sanity check: cert with SAN=evil.attacker.com is correctly rejected */
++    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(server_cert,
++                WOLFSSL_FILETYPE_PEM));
++    ExpectNotNull(name = wolfSSL_X509_get_subject_name(ca));
++    ExpectIntEQ(wolfSSL_X509_set_issuer_name(x509, name), WOLFSSL_SUCCESS);
++    name = NULL;
++
++    ExpectNotNull(name = X509_NAME_new());
++    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "countryName", MBSTRING_UTF8,
++                                       (byte*)"US", 2, -1, 0), SSL_SUCCESS);
++    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_UTF8,
++                             (byte*)"evil.attacker.com", 17, -1, 0),
++                SSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_X509_set_subject_name(x509, name), WOLFSSL_SUCCESS);
++    X509_NAME_free(name);
++    name = NULL;
++
++    ExpectIntEQ(wolfSSL_X509_add_altname(x509, "evil.attacker.com",
++                                         ASN_DNS_TYPE), WOLFSSL_SUCCESS);
++    ExpectIntGT(wolfSSL_X509_sign(x509, priv, EVP_sha256()), 0);
++    ExpectNotNull((der = (byte*)wolfSSL_X509_get_der(x509, &derSz)));
++    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
++                WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
++    wolfSSL_X509_free(x509);
++    x509 = NULL;
++
++    /* NOW the actual vulnerability test: cert with CN=evil.attacker.com
++     * but NO SAN. The DNS name constraint should still reject this, since
++     * wolfSSL's hostname verification falls back to CN when no SAN exists. */
++    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(server_cert,
++                WOLFSSL_FILETYPE_PEM));
++    ExpectNotNull(name = wolfSSL_X509_get_subject_name(ca));
++    ExpectIntEQ(wolfSSL_X509_set_issuer_name(x509, name), WOLFSSL_SUCCESS);
++    name = NULL;
++
++    ExpectNotNull(name = X509_NAME_new());
++    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "countryName", MBSTRING_UTF8,
++                                       (byte*)"US", 2, -1, 0), SSL_SUCCESS);
++    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_UTF8,
++                             (byte*)"evil.attacker.com", 17, -1, 0),
++                SSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_X509_set_subject_name(x509, name), WOLFSSL_SUCCESS);
++    X509_NAME_free(name);
++    name = NULL;
++
++    /* Do NOT add any SAN this is the bypass vector */
++    ExpectIntGT(wolfSSL_X509_sign(x509, priv, EVP_sha256()), 0);
++    ExpectNotNull((der = (byte*)wolfSSL_X509_get_der(x509, &derSz)));
++    /* Should be ASN_NAME_INVALID_E because CN violates the constraint */
++    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
++                WOLFSSL_FILETYPE_ASN1), WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
++    wolfSSL_X509_free(x509);
++    x509 = NULL;
++
++    /* Positive test: CN matches a permitted name (wolfssl.com) and no SAN is
++     * present. The CN fallback should accept this cert. */
++    ExpectNotNull(x509 = wolfSSL_X509_load_certificate_file(server_cert,
++                WOLFSSL_FILETYPE_PEM));
++    ExpectNotNull(name = wolfSSL_X509_get_subject_name(ca));
++    ExpectIntEQ(wolfSSL_X509_set_issuer_name(x509, name), WOLFSSL_SUCCESS);
++    name = NULL;
++
++    ExpectNotNull(name = X509_NAME_new());
++    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "countryName", MBSTRING_UTF8,
++                                       (byte*)"US", 2, -1, 0), SSL_SUCCESS);
++    ExpectIntEQ(X509_NAME_add_entry_by_txt(name, "commonName", MBSTRING_UTF8,
++                             (byte*)"wolfssl.com", 11, -1, 0),
++                SSL_SUCCESS);
++    ExpectIntEQ(wolfSSL_X509_set_subject_name(x509, name), WOLFSSL_SUCCESS);
++    X509_NAME_free(name);
++    name = NULL;
++
++    /* No SAN added; CN=wolfssl.com matches the permitted DNS constraint. */
++    ExpectIntGT(wolfSSL_X509_sign(x509, priv, EVP_sha256()), 0);
++    ExpectNotNull((der = (byte*)wolfSSL_X509_get_der(x509, &derSz)));
++    ExpectIntEQ(wolfSSL_CertManagerVerifyBuffer(cm, der, derSz,
++                WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
++
++    wolfSSL_CertManagerFree(cm);
++    wolfSSL_X509_free(x509);
++    wolfSSL_X509_free(ca);
++    wolfSSL_EVP_PKEY_free(priv);
++#endif
++    return EXPECT_RESULT();
++}
++
+ int test_wolfSSL_CertManagerCRL(void)
+ {
+     EXPECT_DECLS;
+diff --git a/tests/api/test_certman.h b/tests/api/test_certman.h
+index 3b6afd0fc..60047cfa3 100644
+--- a/tests/api/test_certman.h
++++ b/tests/api/test_certman.h
+@@ -35,6 +35,7 @@ int test_wolfSSL_CertManagerNameConstraint2(void);
+ int test_wolfSSL_CertManagerNameConstraint3(void);
+ int test_wolfSSL_CertManagerNameConstraint4(void);
+ int test_wolfSSL_CertManagerNameConstraint5(void);
++int test_wolfSSL_CertManagerNameConstraint_DNS_CN(void);
+ int test_wolfSSL_CertManagerCRL(void);
+ int test_wolfSSL_CRL_reason_extensions_cleanup(void);
+ int test_wolfSSL_CRL_static_revoked_list(void);
+@@ -57,6 +58,7 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void);
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint3),    \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint4),    \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint5),    \
++    TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint_DNS_CN), \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCRL),                \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_reason_extensions_cleanup), \
+     TEST_DECL_GROUP("certman", test_wolfSSL_CRL_static_revoked_list),      \
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index 26b86c1b2b..ef03d0c9ff 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -34,6 +34,8 @@ SRC_URI = " \
     file://CVE-2026-6412-2.patch \
     file://CVE-2026-6450-1.patch \
     file://CVE-2026-6450-2.patch \
+    file://CVE-2026-6731-1.patch \
+    file://CVE-2026-6731-2.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [oe][meta-networking][wrynose][PATCH 33/33] wolfssl: patch CVE-2026-7531
  2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
                   ` (30 preceding siblings ...)
  2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 32/33] wolfssl: patch CVE-2026-6731 ankur.tyagi85
@ 2026-09-07 10:23 ` ankur.tyagi85
  31 siblings, 0 replies; 33+ messages in thread
From: ankur.tyagi85 @ 2026-09-07 10:23 UTC (permalink / raw)
  To: openembedded-devel; +Cc: Ankur Tyagi

From: Ankur Tyagi <ankur.tyagi85@gmail.com>

Details:
https://nvd.nist.gov/vuln/detail/cve-2026-7531

Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
---
 .../wolfssl/files/CVE-2026-7531.patch         | 180 ++++++++++++++++++
 .../wolfssl/wolfssl_5.9.1.bb                  |   1 +
 2 files changed, 181 insertions(+)
 create mode 100644 meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-7531.patch

diff --git a/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-7531.patch b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-7531.patch
new file mode 100644
index 0000000000..1d4e7605b3
--- /dev/null
+++ b/meta-networking/recipes-connectivity/wolfssl/files/CVE-2026-7531.patch
@@ -0,0 +1,180 @@
+From 5ab994ddce690cc904554ff03af263ef0624d29d Mon Sep 17 00:00:00 2001
+From: David Garske <david@wolfssl.com>
+Date: Tue, 5 May 2026 11:41:43 -0700
+Subject: [PATCH] Merge pull request #10327 from embhorn/zd21704
+
+Hardening in TLSX_KeyShare_ProcessPqcHybridClient
+
+CVE: CVE-2026-7531
+Upstream-Status: Backport [https://github.com/wolfSSL/wolfssl/commit/3b7ac9fd256b26c33b66f9315c319465ba3bcfeb]
+
+Signed-off-by: Ankur Tyagi <ankur.tyagi85@gmail.com>
+---
+ src/tls.c              | 19 +++++---
+ tests/api/test_tls13.c | 98 ++++++++++++++++++++++++++++++++++++++++++
+ tests/api/test_tls13.h |  2 +
+ 3 files changed, 114 insertions(+), 5 deletions(-)
+
+diff --git a/src/tls.c b/src/tls.c
+index 18aad71d3..e5b989482 100644
+--- a/src/tls.c
++++ b/src/tls.c
+@@ -10187,15 +10187,24 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
+             ecc_kse->key = NULL;
+             pqc_kse->privKey = NULL;
+         }
++        else
+     #endif
++        {
++            /* Re-sync keyShareEntry->key with ecc_kse->key. ecc_kse->key was
++             * aliased to keyShareEntry->key above. The inner Process*_ex
++             * either ran its end-of-function cleanup and set ecc_kse->key
++             * to NULL (so the outer pointer must also become NULL to avoid
++             * UAF/double-free in TLSX_KeyShare_FreeAll), or returned early
++             * before cleanup with ecc_kse->key still pointing at the live
++             * key (so the outer pointer must keep that pointer for later
++             * freeing). Mirroring whatever the inner left in ecc_kse->key
++             * handles both cases correctly. */
++            keyShareEntry->key = ecc_kse->key;
++        }
+     }
+ 
+     if (ret == 0) {
+-        keyShareEntry->key = ecc_kse->key;
+-        ecc_kse->key = NULL;
+-
+-        if ((ret == 0) &&
+-            ((ssl->arrays->preMasterSz + ssSzPqc) > ENCRYPT_LEN)) {
++        if ((ssl->arrays->preMasterSz + ssSzPqc) > ENCRYPT_LEN) {
+             WOLFSSL_MSG("shared secret is too long.");
+             ret = LENGTH_ERROR;
+         }
+diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c
+index 63ddffb7a..af050a234 100644
+--- a/tests/api/test_tls13.c
++++ b/tests/api/test_tls13.c
+@@ -3581,6 +3581,104 @@ int test_tls13_pqc_hybrid_truncated_keyshare(void)
+     return EXPECT_RESULT();
+ }
+ 
++/* Test that a malformed ECDH portion in a correctly-sized PQC hybrid
++ * KeyShare does not leave a dangling pointer in keyShareEntry->key.
++ *
++ * The earlier truncated-keyshare test is rejected by the keLen <= ctSz
++ * check before TLSX_KeyShare_ProcessPqcHybridClient sets up the
++ * ecc_kse->key = keyShareEntry->key alias, so it does not exercise the
++ * dangling-pointer path. This test sends a SECP256R1MLKEM768 key_share
++ * whose total length is correct (65-byte ECDH point + 1088-byte ML-KEM
++ * ciphertext = 1153 bytes) but whose ECDH leading byte (0x05) is not a
++ * valid X9.63 marker. ProcessEcc_ex then fails at wc_ecc_import_x963
++ * AFTER its unconditional cleanup at the end of the function frees the
++ * aliased key. Without the fix, the outer keyShareEntry->key still
++ * holds the freed pointer; wolfSSL_free -> TLSX_KeyShare_FreeAll calls
++ * wc_ecc_free + XFREE on it, producing a use-after-free and a double
++ * free that ASAN flags. */
++int test_tls13_pqc_hybrid_malformed_ecdh(void)
++{
++    EXPECT_DECLS;
++#if defined(WOLFSSL_TLS13) && !defined(NO_WOLFSSL_CLIENT) && \
++    defined(WOLFSSL_HAVE_MLKEM) && defined(WOLFSSL_PQC_HYBRIDS) && \
++    !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
++    !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
++    !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
++    (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
++    !defined(NO_ECC_SECP)
++    WOLFSSL_CTX *ctx = NULL;
++    WOLFSSL *ssl = NULL;
++    /* 5 (record) + 4 (HS) + 1207 (ServerHello body) = 1216 bytes. */
++    static byte serverHello[1216];
++    word32 i = 0;
++    WOLFSSL_BUFFER_INFO msg;
++
++    XMEMSET(serverHello, 0, sizeof(serverHello));
++
++    /* Record: handshake, TLS 1.2 compat, length 1211 (0x04bb). */
++    serverHello[i++] = 0x16; serverHello[i++] = 0x03; serverHello[i++] = 0x03;
++    serverHello[i++] = 0x04; serverHello[i++] = 0xbb;
++    /* Handshake: ServerHello (0x02), length 1207 (0x0004b7). */
++    serverHello[i++] = 0x02;
++    serverHello[i++] = 0x00; serverHello[i++] = 0x04; serverHello[i++] = 0xb7;
++    /* legacy_version */
++    serverHello[i++] = 0x03; serverHello[i++] = 0x03;
++    /* random (32 bytes) */
++    XMEMSET(&serverHello[i], 0x42, 32); i += 32;
++    /* legacy_session_id_echo length: 0 */
++    serverHello[i++] = 0x00;
++    /* cipher_suite: TLS_AES_128_GCM_SHA256 */
++    serverHello[i++] = 0x13; serverHello[i++] = 0x01;
++    /* legacy_compression_method: null */
++    serverHello[i++] = 0x00;
++    /* extensions length: 1167 (0x048f) */
++    serverHello[i++] = 0x04; serverHello[i++] = 0x8f;
++    /* extension: supported_versions -> TLS 1.3 */
++    serverHello[i++] = 0x00; serverHello[i++] = 0x2b;
++    serverHello[i++] = 0x00; serverHello[i++] = 0x02;
++    serverHello[i++] = 0x03; serverHello[i++] = 0x04;
++    /* extension: key_share, extension_data length 1157 (0x0485) */
++    serverHello[i++] = 0x00; serverHello[i++] = 0x33;
++    serverHello[i++] = 0x04; serverHello[i++] = 0x85;
++    /* server_share.group: SECP256R1MLKEM768 (0x11eb) */
++    serverHello[i++] = 0x11; serverHello[i++] = 0xeb;
++    /* key_exchange length: 1153 (0x0481) */
++    serverHello[i++] = 0x04; serverHello[i++] = 0x81;
++    /* ECDH portion (65 bytes): leading 0x05 is not a valid X9.63 marker
++     * (valid markers: 0x04, 0x06, 0x07). The remaining 64 bytes stay zero
++     * from the initial XMEMSET. */
++    serverHello[i++] = 0x05;
++    i += 64;
++    /* PQC portion (1088 bytes): all zero from the initial XMEMSET. */
++    i += 1088;
++    AssertIntEQ((int)i, (int)sizeof(serverHello));
++
++    ExpectNotNull(ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method()));
++    wolfSSL_SetIORecv(ctx, PqcHybridUafRecv);
++    wolfSSL_SetIOSend(ctx, PqcHybridUafSend);
++
++    ExpectNotNull(ssl = wolfSSL_new(ctx));
++
++    /* Match the server's offered group so this key_share is processed. */
++    ExpectIntEQ(wolfSSL_UseKeyShare(ssl, WOLFSSL_SECP256R1MLKEM768),
++        WOLFSSL_SUCCESS);
++
++    msg.buffer = serverHello;
++    msg.length = (unsigned int)sizeof(serverHello);
++    wolfSSL_SetIOReadCtx(ssl, &msg);
++
++    /* Connect should fail gracefully on the malformed ECDH point. */
++    ExpectIntEQ(wolfSSL_connect_TLSv13(ssl),
++        WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR));
++
++    /* Without the fix, this triggers UAF + double-free in
++     * TLSX_KeyShare_FreeAll. */
++    wolfSSL_free(ssl);
++    wolfSSL_CTX_free(ctx);
++#endif
++    return EXPECT_RESULT();
++}
++
+ /* Test that a TLS 1.3 NewSessionTicket with a ticket shorter than ID_LEN
+  * (32 bytes) does not cause an unsigned integer underflow / OOB read in
+  * SetTicket. Uses a full memio handshake, then injects a crafted
+diff --git a/tests/api/test_tls13.h b/tests/api/test_tls13.h
+index c8eaa3b7f..94232f18e 100644
+--- a/tests/api/test_tls13.h
++++ b/tests/api/test_tls13.h
+@@ -43,6 +43,7 @@ int test_tls13_warning_alert_is_fatal(void);
+ int test_tls13_cert_req_sigalgs(void);
+ int test_tls13_derive_keys_no_key(void);
+ int test_tls13_pqc_hybrid_truncated_keyshare(void);
++int test_tls13_pqc_hybrid_malformed_ecdh(void);
+ int test_tls13_short_session_ticket(void);
+ 
+ #define TEST_TLS13_DECLS                                        \
+@@ -65,6 +66,7 @@ int test_tls13_short_session_ticket(void);
+     TEST_DECL_GROUP("tls13", test_tls13_cert_req_sigalgs),       \
+     TEST_DECL_GROUP("tls13", test_tls13_derive_keys_no_key),    \
+     TEST_DECL_GROUP("tls13", test_tls13_pqc_hybrid_truncated_keyshare), \
++    TEST_DECL_GROUP("tls13", test_tls13_pqc_hybrid_malformed_ecdh), \
+     TEST_DECL_GROUP("tls13", test_tls13_short_session_ticket)
+ 
+ #endif /* WOLFCRYPT_TEST_TLS13_H */
diff --git a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
index ef03d0c9ff..644c5379f5 100644
--- a/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
+++ b/meta-networking/recipes-connectivity/wolfssl/wolfssl_5.9.1.bb
@@ -36,6 +36,7 @@ SRC_URI = " \
     file://CVE-2026-6450-2.patch \
     file://CVE-2026-6731-1.patch \
     file://CVE-2026-6731-2.patch \
+    file://CVE-2026-7531.patch \
 "
 
 SRCREV = "1d363f3adceba9d1478230ede476a37b0dcdef24"


^ permalink raw reply related	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2026-09-07 10:25 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-07 10:22 [oe][meta-oe][wrynose][PATCH 1/33] libnfs: patch CVE-2026-53689 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 2/33] libnfs: patch CVE-2026-57918 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 3/33] libssh: ignore CVE-2025-14821 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 4/33] libssh: mark CVEs patched ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 5/33] libssh: ignore CVE-2025-59842 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 6/33] miniupnpd: patch CVE-2026-5720 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 7/33] python3-zeroconf: patch CVE-2026-47180 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 8/33] python3-zeroconf: patch CVE-2026-47183 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-python][wrynose][PATCH 9/33] python3-zeroconf: patch CVE-2026-47184 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 10/33] valkey: mark CVE-2026-56684 and CVE-2026-63639 patched ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-oe][wrynose][PATCH 11/33] libyang: patch CVE-2026-41401 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 12/33] tinyproxy: patch CVE-2026-31842 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 13/33] tinyproxy: patch CVE-2026-54387 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-networking][wrynose][PATCH 14/33] tinyproxy: patch CVE-2026-55202 ankur.tyagi85
2026-09-07 10:22 ` [oe][meta-webserver][wrynose][PATCH 15/33] nginx: mark CVE-2026-1642 patched ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 16/33] open62541: patch CVE-2026-11946 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 17/33] smarty: mark CVEs patched ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 18/33] tesseract: patch CVE-2026-73066 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-oe][wrynose][PATCH 19/33] tesseract: patch CVE-2026-73067 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 20/33] wolfssl: mark CVEs patched ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 21/33] wolfssl: patch CVE-2026-10098 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 22/33] wolfssl: patch CVE-2026-10512 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 23/33] wolfssl: ignore CVE-2026-12340 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 24/33] wolfssl: patch CVE-2026-55958 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 25/33] wolfssl: patch CVE-2026-6091 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 26/33] wolfssl: patch CVE-2026-6092 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 27/33] wolfssl: patch CVE-2026-6094 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 28/33] wolfssl: patch CVE-2026-6291 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 29/33] wolfssl: patch CVE-2026-6325 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 30/33] wolfssl: patch CVE-2026-6412 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 31/33] wolfssl: patch CVE-2026-6450 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 32/33] wolfssl: patch CVE-2026-6731 ankur.tyagi85
2026-09-07 10:23 ` [oe][meta-networking][wrynose][PATCH 33/33] wolfssl: patch CVE-2026-7531 ankur.tyagi85

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.