From 6fb25be77b1228e40e202a6b5141865b8a30d4d7 Mon Sep 17 00:00:00 2001
From: Ken Zalewski <ken.zalewski@gmail.com>
Date: Fri, 6 Feb 2026 01:39:02 -0500
Subject: [PATCH] Patch to openssl-1.1.1ze.  This version addresses seven
 vulnerabilities:  CVE-2025-68160, CVE-2025-69418, CVE-2025-69419,
 CVE-2025-69420, CVE-2025-69421, CVE-2026-22795, and CVE-2026-22796

---
 CHANGES                    | 127 +++++++++++++++++++++++++++++++++++++
 NEWS                       |  16 +++++
 README                     |   4 +-
 apps/s_client.c            |   3 +-
 crypto/asn1/a_strex.c      |   6 +-
 crypto/bio/bf_lbuf.c       |  32 ++++++++--
 crypto/modes/ocb128.c      |  10 ++-
 crypto/pkcs12/p12_decr.c   |   5 ++
 crypto/pkcs12/p12_kiss.c   |  10 ++-
 crypto/pkcs12/p12_utl.c    |  13 +++-
 crypto/pkcs7/pk7_doit.c    |   2 +
 crypto/ts/ts_rsp_verify.c  |   4 +-
 include/openssl/opensslv.h |   4 +-
 13 files changed, 214 insertions(+), 22 deletions(-)

diff --git a/CHANGES b/CHANGES
index b9e5e61..1abcd76 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,133 @@
  https://github.com/openssl/openssl/commits/ and pick the appropriate
  release branch.
 
+ Changes between 1.1.1zd and 1.1.1ze [27 Jan 2026]
+
+ *) Fixed Heap out-of-bounds write in BIO_f_linebuffer on short writes.
+
+    Severity: Low
+
+    Issue summary: Writing large, newline-free data into a BIO chain using the
+    line-buffering filter where the next BIO performs short writes can trigger
+    a heap-based out-of-bounds write.
+
+    Impact summary: This out-of-bounds write can cause memory corruption
+    which typically results in a crash, leading to Denial of Service for
+    an application.
+
+    Reported by: Petr Simecek (Aisle Research) and Stanislav Fort (Aisle
+    Research)
+
+    (CVE-2025-68160)
+    [Stanislav Fort]
+    [Neil Horman]
+
+ *) Fixed Unauthenticated/unencrypted trailing bytes with low-level OCB
+    function calls.
+
+    Severity: Low
+
+    Issue summary: When using the low-level OCB API directly with AES-NI or
+    other hardware-accelerated code paths, inputs whose length is not a multiple
+    of 16 bytes can leave the final partial block unencrypted and
+    unauthenticated.
+
+    Impact summary: The trailing 1-15 bytes of a message may be exposed in
+    cleartext on encryption and are not covered by the authentication tag,
+    allowing an attacker to read or tamper with those bytes without detection.
+
+    Reported by: Stanislav Fort (Aisle Research)
+
+    (CVE-2025-69418)
+    [Stanislav Fort]
+
+ *) Fixed Out of bounds write in PKCS12_get_friendlyname() UTF-8 conversion.
+
+    Severity: Low
+
+    Issue summary: Calling PKCS12_get_friendlyname() function on a maliciously
+    crafted PKCS#12 file with a BMPString (UTF-16BE) friendly name containing
+    non-ASCII BMP code point can trigger a one byte write before the allocated
+    buffer.
+
+    Impact summary: The out-of-bounds write can cause a memory corruption
+    which can have various consequences including a Denial of Service.
+
+    Reported by: Stanislav Fort (Aisle Research)
+
+    (CVE-2025-69419)
+    [Norbert Pócs]
+
+ *) Fixed Missing ASN1_TYPE validation in TS_RESP_verify_response() function.
+
+    Severity: Low
+
+    Issue summary: A type confusion vulnerability exists in the TimeStamp
+    Response verification code where an ASN1_TYPE union member is accessed
+    without first validating the type, causing an invalid or NULL pointer
+    dereference when processing a malformed TimeStamp Response file.
+
+    Impact summary: An application calling TS_RESP_verify_response()
+    with a malformed TimeStamp Response can be caused to dereference an invalid
+    or NULL pointer when reading, resulting in a Denial of Service.
+
+    Reported by: Luigino Camastra (Aisle Research)
+
+    (CVE-2025-69420)
+    [Bob Beck]
+
+ *) Fixed NULL Pointer Dereference in PKCS12_item_decrypt_d2i_ex() function.
+
+    Severity: Low
+
+    Issue summary: Processing a malformed PKCS#12 file can trigger a NULL
+    pointer dereference in the PKCS12_item_decrypt_d2i_ex() function.
+
+    Impact summary: A NULL pointer dereference can trigger a crash which leads
+    to Denial of Service for an application processing PKCS#12 files.
+
+    Reported by: Luigino Camastra (Aisle Research)
+
+    (CVE-2025-69421)
+    [Luigino Camastra]
+
+ *) Fixed Missing ASN1_TYPE validation in PKCS#12 parsing.
+
+    Severity: Low
+
+    Issue summary: An invalid or NULL pointer dereference can happen in
+    an application processing a malformed PKCS#12 file.
+
+    Impact summary: An application processing a malformed PKCS#12 file can be
+    caused to dereference an invalid or NULL pointer on memory read, resulting
+    in a Denial of Service.
+
+    Reported by: Luigino Camastra (Aisle Research)
+
+    (CVE-2026-22795)
+    [Bob Beck]
+
+ *) Fixed ASN1_TYPE Type Confusion in the PKCS7_digest_from_attributes()
+    function.
+
+    Severity: Low
+
+    Issue summary: A type confusion vulnerability exists in the signature
+    verification of signed PKCS#7 data where an ASN1_TYPE union member
+    is accessed without first validating the type, causing an invalid or NULL
+    pointer dereference when processing malformed PKCS#7 data.
+
+    Impact summary: An application performing signature verification of PKCS#7
+    data or calling directly the PKCS7_digest_from_attributes() function can be
+    caused to dereference an invalid or NULL pointer when reading, resulting in
+    a Denial of Service.
+
+    Reported by: Luigino Camastra (Aisle Research)
+
+    (CVE-2026-22796)
+    [Bob Beck]
+
+
  Changes between 1.1.1zb_p2 and 1.1.1zd [30 Sep 2025]
 
  *) Fix incorrect check of unwrapped key size in kek_unwrap_key()
diff --git a/NEWS b/NEWS
index 19b7aa3..c9d06c5 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,22 @@
   This file gives a brief overview of the major changes between each OpenSSL
   release. For more details please read the CHANGES file.
 
+  Major changes between 1.1.1zd and 1.1.1ze [27 Jan 2026]
+
+      o Fixed Heap out-of-bounds write in BIO_f_linebuffer on short writes.
+        (CVE-2025-68160)
+      o Fixed Unauthenticated/unencrypted trailing bytes with low-level OCB
+        function calls. (CVE-2025-69418)
+      o Fixed Out of bounds write in PKCS12_get_friendlyname() UTF-8 conversion.
+        (CVE-2025-69419)
+      o Fixed Missing ASN1_TYPE validation in TS_RESP_verify_response()
+        function. (CVE-2025-69420)
+      o Fixed NULL Pointer Dereference in PKCS12_item_decrypt_d2i_ex() function.
+        (CVE-2025-69421)
+      o Fixed Missing ASN1_TYPE validation in PKCS#12 parsing. (CVE-2026-22795)
+      o Fixed ASN1_TYPE Type Confusion in the PKCS7_digest_from_attributes()
+        function. (CVE-2026-22796)
+
   Major changes between 1.1.1zb_p2 and 1.1.1zd [30 Sep 2025]
 
       o Fix out-of-bounds read & write in RFC 3211 KEK Unwrap (CVE-2025-9230)
diff --git a/README b/README
index 6eaa1e0..f388077 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
 
- OpenSSL 1.1.1zd 30 Sep 2025
+ OpenSSL 1.1.1ze 27 Jan 2026
 
- Copyright (c) 1998-2023 The OpenSSL Project
+ Copyright (c) 1998-2026 The OpenSSL Project
  Copyright (c) 1995-1998 Eric A. Young, Tim J. Hudson
  All rights reserved.
 
diff --git a/apps/s_client.c b/apps/s_client.c
index 00effc8..39df178 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -2698,8 +2698,9 @@ int s_client_main(int argc, char **argv)
                 goto end;
             }
             atyp = ASN1_generate_nconf(genstr, cnf);
-            if (atyp == NULL) {
+            if (atyp == NULL || atyp->type != V_ASN1_SEQUENCE) {
                 NCONF_free(cnf);
+                ASN1_TYPE_free(atyp);
                 BIO_printf(bio_err, "ASN1_generate_nconf failed\n");
                 goto end;
             }
diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c
index 284dde2..60b8395 100644
--- a/crypto/asn1/a_strex.c
+++ b/crypto/asn1/a_strex.c
@@ -203,8 +203,10 @@ static int do_buf(unsigned char *buf, int buflen,
             orflags = CHARTYPE_LAST_ESC_2253;
         if (type & BUF_TYPE_CONVUTF8) {
             unsigned char utfbuf[6];
-            int utflen;
-            utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c);
+            int utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c);
+            if (utflen < 0)
+                return -1; /* error happened with UTF8 */
+
             for (i = 0; i < utflen; i++) {
                 /*
                  * We don't need to worry about setting orflags correctly
diff --git a/crypto/bio/bf_lbuf.c b/crypto/bio/bf_lbuf.c
index 72f9901..34dd035 100644
--- a/crypto/bio/bf_lbuf.c
+++ b/crypto/bio/bf_lbuf.c
@@ -191,14 +191,34 @@ static int linebuffer_write(BIO *b, const char *in, int inl)
     while (foundnl && inl > 0);
     /*
      * We've written as much as we can.  The rest of the input buffer, if
-     * any, is text that doesn't and with a NL and therefore needs to be
-     * saved for the next trip.
+     * any, is text that doesn't end with a NL and therefore we need to try
+     * free up some space in our obuf so we can make forward progress.
      */
-    if (inl > 0) {
-        memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl);
-        ctx->obuf_len += inl;
-        num += inl;
+    while (inl > 0) {
+        size_t avail = (size_t)ctx->obuf_size - (size_t)ctx->obuf_len;
+        size_t to_copy;
+
+        if (avail == 0) {
+            /* Flush buffered data to make room */
+            i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len);
+            if (i <= 0) {
+                BIO_copy_next_retry(b);
+                return num > 0 ? num : i;
+            }
+            if (i < ctx->obuf_len)
+                memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i);
+            ctx->obuf_len -= i;
+            continue;
+        }
+
+        to_copy = inl > (int)avail ? avail : (size_t)inl;
+        memcpy(&(ctx->obuf[ctx->obuf_len]), in, to_copy);
+        ctx->obuf_len += (int)to_copy;
+        in += to_copy;
+        inl -= (int)to_copy;
+        num += (int)to_copy;
     }
+
     return num;
 }
 
diff --git a/crypto/modes/ocb128.c b/crypto/modes/ocb128.c
index b39a55a..2ef3982 100644
--- a/crypto/modes/ocb128.c
+++ b/crypto/modes/ocb128.c
@@ -342,7 +342,7 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
 
     if (num_blocks && all_num_blocks == (size_t)all_num_blocks
         && ctx->stream != NULL) {
-        size_t max_idx = 0, top = (size_t)all_num_blocks;
+        size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0;
 
         /*
          * See how many L_{i} entries we need to process data at hand
@@ -356,6 +356,9 @@ int CRYPTO_ocb128_encrypt(OCB128_CONTEXT *ctx,
         ctx->stream(in, out, num_blocks, ctx->keyenc,
                     (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c,
                     (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c);
+        processed_bytes = num_blocks * 16;
+        in += processed_bytes;
+        out += processed_bytes;
     } else {
         /* Loop through all full blocks to be encrypted */
         for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) {
@@ -434,7 +437,7 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
 
     if (num_blocks && all_num_blocks == (size_t)all_num_blocks
         && ctx->stream != NULL) {
-        size_t max_idx = 0, top = (size_t)all_num_blocks;
+        size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0;
 
         /*
          * See how many L_{i} entries we need to process data at hand
@@ -448,6 +451,9 @@ int CRYPTO_ocb128_decrypt(OCB128_CONTEXT *ctx,
         ctx->stream(in, out, num_blocks, ctx->keydec,
                     (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c,
                     (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c);
+        processed_bytes = num_blocks * 16;
+        in += processed_bytes;
+        out += processed_bytes;
     } else {
         OCB_BLOCK tmp;
 
diff --git a/crypto/pkcs12/p12_decr.c b/crypto/pkcs12/p12_decr.c
index 3c86058..e3d1b8b 100644
--- a/crypto/pkcs12/p12_decr.c
+++ b/crypto/pkcs12/p12_decr.c
@@ -88,6 +88,11 @@ void *PKCS12_item_decrypt_d2i(const X509_ALGOR *algor, const ASN1_ITEM *it,
     void *ret;
     int outlen;
 
+    if (oct == NULL) {
+        PKCS12err(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I, PKCS12_R_INVALID_NULL_ARGUMENT);
+        return NULL;
+    }
+
     if (!PKCS12_pbe_crypt(algor, pass, passlen, oct->data, oct->length,
                           &out, &outlen, 0)) {
         PKCS12err(PKCS12_F_PKCS12_ITEM_DECRYPT_D2I,
diff --git a/crypto/pkcs12/p12_kiss.c b/crypto/pkcs12/p12_kiss.c
index 7ab9838..d90404d 100644
--- a/crypto/pkcs12/p12_kiss.c
+++ b/crypto/pkcs12/p12_kiss.c
@@ -183,11 +183,17 @@ static int parse_bag(PKCS12_SAFEBAG *bag, const char *pass, int passlen,
     ASN1_BMPSTRING *fname = NULL;
     ASN1_OCTET_STRING *lkid = NULL;
 
-    if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName)))
+    if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName))) {
+        if (attrib->type != V_ASN1_BMPSTRING)
+            return 0;
         fname = attrib->value.bmpstring;
+    }
 
-    if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID)))
+    if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID))) {
+        if (attrib->type != V_ASN1_OCTET_STRING)
+            return 0;
         lkid = attrib->value.octet_string;
+    }
 
     switch (PKCS12_SAFEBAG_get_nid(bag)) {
     case NID_keyBag:
diff --git a/crypto/pkcs12/p12_utl.c b/crypto/pkcs12/p12_utl.c
index 43b9e3a..b71e9b1 100644
--- a/crypto/pkcs12/p12_utl.c
+++ b/crypto/pkcs12/p12_utl.c
@@ -206,9 +206,16 @@ char *OPENSSL_uni2utf8(const unsigned char *uni, int unilen)
 
     /* re-run the loop emitting UTF-8 string */
     for (asclen = 0, i = 0; i < unilen; ) {
-        j = bmp_to_utf8(asctmp+asclen, uni+i, unilen-i);
-        if (j == 4) i += 4;
-        else        i += 2;
+        j = bmp_to_utf8(asctmp + asclen, uni + i, unilen - i);
+        /* when UTF8_putc fails */
+        if (j < 0) {
+            OPENSSL_free(asctmp);
+            return NULL;
+        }
+        if (j == 4)
+            i += 4;
+        else
+            i += 2;
         asclen += j;
     }
 
diff --git a/crypto/pkcs7/pk7_doit.c b/crypto/pkcs7/pk7_doit.c
index f63fbc5..4e0eb1e 100644
--- a/crypto/pkcs7/pk7_doit.c
+++ b/crypto/pkcs7/pk7_doit.c
@@ -1092,6 +1092,8 @@ ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk)
     ASN1_TYPE *astype;
     if ((astype = get_attribute(sk, NID_pkcs9_messageDigest)) == NULL)
         return NULL;
+    if (astype->type != V_ASN1_OCTET_STRING)
+        return NULL;
     return astype->value.octet_string;
 }
 
diff --git a/crypto/ts/ts_rsp_verify.c b/crypto/ts/ts_rsp_verify.c
index 7fe3d27..5d452d2 100644
--- a/crypto/ts/ts_rsp_verify.c
+++ b/crypto/ts/ts_rsp_verify.c
@@ -262,7 +262,7 @@ static ESS_SIGNING_CERT *ess_get_signing_cert(PKCS7_SIGNER_INFO *si)
     ASN1_TYPE *attr;
     const unsigned char *p;
     attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate);
-    if (!attr)
+    if (attr == NULL || attr->type != V_ASN1_SEQUENCE)
         return NULL;
     p = attr->value.sequence->data;
     return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length);
@@ -274,7 +274,7 @@ static ESS_SIGNING_CERT_V2 *ess_get_signing_cert_v2(PKCS7_SIGNER_INFO *si)
     const unsigned char *p;
 
     attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificateV2);
-    if (attr == NULL)
+    if (attr == NULL || attr->type != V_ASN1_SEQUENCE)
         return NULL;
     p = attr->value.sequence->data;
     return d2i_ESS_SIGNING_CERT_V2(NULL, &p, attr->value.sequence->length);
diff --git a/include/openssl/opensslv.h b/include/openssl/opensslv.h
index af85ab0..7ea9cd7 100644
--- a/include/openssl/opensslv.h
+++ b/include/openssl/opensslv.h
@@ -39,8 +39,8 @@ extern "C" {
  * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
  *  major minor fix final patch/beta)
  */
-# define OPENSSL_VERSION_NUMBER  0x101011bfL
-# define OPENSSL_VERSION_TEXT    "OpenSSL 1.1.1zd  30 Sep 2025"
+# define OPENSSL_VERSION_NUMBER  0x101011efL
+# define OPENSSL_VERSION_TEXT    "OpenSSL 1.1.1ze  27 Jan 2026"
 
 /*-
  * The macros below are to be used for shared library (.so, .dll, ...)
