Commit 5fd4eae785 for openssl.org

commit 5fd4eae78531f9d73aebb3550eb3bdbcb4d09e8f
Author: Darren Carreras <carrerasdarren@gmail.com>
Date:   Tue Sep 1 18:32:21 2026 -0400

    X509: complete ASN.1 stream failure handling

    Use buf directly when validating canonical output pointer movement.

    Validate NDEF prefix and suffix output passes and return failure when the stream flush fails. Add a two-digest PKCS7 allocation-failure regression.

    Assisted-by: OpenAI Codex:gpt-5.6-sol
    Reviewed-by: Jakub Zelenka <jakub.zelenka@openssl.foundation>
    Reviewed-by: Mounir Idrassi <mounir.idrassi@idrix.fr>
    Merge-date: Mon Sep 14 14:13:34 2026
    Merged-from: https://github.com/openssl/openssl/pull/32047

diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c
index af79f27bda..2316618744 100644
--- a/crypto/asn1/asn_mime.c
+++ b/crypto/asn1/asn_mime.c
@@ -81,9 +81,9 @@ int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags,
         }
         if (!SMIME_crlf_copy(in, bio, flags)) {
             rv = 0;
+        } else if (BIO_flush(bio) <= 0) {
+            rv = 0;
         }
-
-        (void)BIO_flush(bio);
         /* Free up successive BIOs until we hit the old output BIO */
         do {
             tbio = BIO_pop(bio);
diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c
index 44d96fc521..9986affae3 100644
--- a/crypto/asn1/bio_ndef.c
+++ b/crypto/asn1/bio_ndef.c
@@ -139,7 +139,7 @@ static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
 {
     NDEF_SUPPORT *ndef_aux;
     unsigned char *p;
-    int derlen;
+    int derlen, outlen;

     if (parg == NULL)
         return 0;
@@ -154,7 +154,9 @@ static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)

     ndef_aux->derbuf = p;
     *pbuf = p;
-    ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
+    outlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
+    if (outlen != derlen || p != *pbuf + derlen)
+        return 0;

     if (ndef_aux->content == NULL || ndef_aux->content->data == NULL)
         return 0;
@@ -200,7 +202,7 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
 {
     NDEF_SUPPORT *ndef_aux;
     unsigned char *p;
-    int derlen;
+    int derlen, outlen;
     const ASN1_AUX *aux;
     ASN1_STREAM_ARG sarg;

@@ -228,7 +230,9 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)

     ndef_aux->derbuf = p;
     *pbuf = p;
-    derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
+    outlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
+    if (outlen != derlen || p != *pbuf + derlen)
+        return 0;

     if (ndef_aux->content == NULL || ndef_aux->content->data == NULL)
         return 0;
diff --git a/crypto/x509/x_name.c b/crypto/x509/x_name.c
index 34d1f76c93..e965dee4c8 100644
--- a/crypto/x509/x_name.c
+++ b/crypto/x509/x_name.c
@@ -315,7 +315,7 @@ static int x509_name_ex_print(BIO *out, const ASN1_VALUE **pval,

 static int x509_name_canon(X509_NAME *a)
 {
-    unsigned char *buf = NULL, *p, *start;
+    unsigned char *buf = NULL, *p;
     STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname;
     STACK_OF(X509_NAME_ENTRY) *entries = NULL;
     X509_NAME_ENTRY *entry, *tmpentry = NULL;
@@ -375,10 +375,9 @@ static int x509_name_canon(X509_NAME *a)
     if (buf == NULL)
         goto err;
     p = buf;
-    start = p;

     outlen = i2d_name_canon(intname, &p);
-    if (outlen != len || p != start + len)
+    if (outlen != len || p != buf + len)
         goto err;

     a->canon_enc = buf;
diff --git a/test/x509_test.c b/test/x509_test.c
index 23fb995934..0eb3f7060b 100644
--- a/test/x509_test.c
+++ b/test/x509_test.c
@@ -790,12 +790,10 @@ end:
     return ret;
 }

-static int test_pkcs7_digest_set_i2d_mfail(void)
+static PKCS7 *make_two_digest_pkcs7(void)
 {
     PKCS7 *p7 = NULL;
     X509_ALGOR *alg = NULL;
-    unsigned char *der = NULL, *p;
-    int len, outlen, ret = -1;

     if (!TEST_ptr(p7 = PKCS7_new())
         || !TEST_true(PKCS7_set_type(p7, NID_pkcs7_signed))
@@ -812,6 +810,23 @@ static int test_pkcs7_digest_set_i2d_mfail(void)
         goto end;
     alg = NULL;

+    return p7;
+
+end:
+    X509_ALGOR_free(alg);
+    PKCS7_free(p7);
+    return NULL;
+}
+
+static int test_pkcs7_digest_set_i2d_mfail(void)
+{
+    PKCS7 *p7 = NULL;
+    unsigned char *der = NULL, *p;
+    int len, outlen, ret = -1;
+
+    if (!TEST_ptr(p7 = make_two_digest_pkcs7()))
+        goto end;
+
     len = i2d_PKCS7(p7, NULL);
     if (!TEST_int_gt(len, 0) || !TEST_ptr(der = OPENSSL_malloc(len)))
         goto end;
@@ -827,12 +842,62 @@ static int test_pkcs7_digest_set_i2d_mfail(void)
         ret = outlen == len && p == der + len ? 1 : -1;

 end:
-    X509_ALGOR_free(alg);
     OPENSSL_free(der);
     PKCS7_free(p7);
     return ret;
 }

+static int test_pkcs7_digest_set_stream_mfail(void)
+{
+    static const unsigned char content[] = "stream content";
+    PKCS7 *p7 = NULL, *expected_p7 = NULL;
+    BIO *in = NULL, *out = NULL;
+    BIO *expected_in = NULL, *expected_out = NULL;
+    char *data = NULL, *expected_data = NULL;
+    long len, expected_len;
+    int outlen, ret = -1;
+
+    if (!TEST_ptr(expected_p7 = make_two_digest_pkcs7())
+        || !TEST_ptr(expected_in = BIO_new_mem_buf(content,
+                         sizeof(content) - 1))
+        || !TEST_ptr(expected_out = BIO_new(BIO_s_mem()))
+        || !TEST_true(i2d_PKCS7_bio_stream(expected_out, expected_p7,
+            expected_in,
+            SMIME_STREAM | PKCS7_BINARY))
+        || !TEST_long_gt(expected_len = BIO_get_mem_data(expected_out,
+                             &expected_data),
+            0)
+        || !TEST_ptr(p7 = make_two_digest_pkcs7())
+        || !TEST_ptr(in = BIO_new_mem_buf(content, sizeof(content) - 1))
+        || !TEST_ptr(out = BIO_new(BIO_s_mem())))
+        goto end;
+
+    MFAIL_start();
+    outlen = i2d_PKCS7_bio_stream(out, p7, in,
+        SMIME_STREAM | PKCS7_BINARY);
+    MFAIL_end();
+
+    if (outlen <= 0) {
+        ret = 0;
+    } else {
+        len = BIO_get_mem_data(out, &data);
+        if (!TEST_long_eq(len, expected_len)
+            || !TEST_mem_eq(data, len, expected_data, expected_len))
+            ret = -1;
+        else
+            ret = 1;
+    }
+
+end:
+    BIO_free(out);
+    BIO_free(in);
+    PKCS7_free(p7);
+    BIO_free(expected_out);
+    BIO_free(expected_in);
+    PKCS7_free(expected_p7);
+    return ret;
+}
+
 OPT_TEST_DECLARE_USAGE("<pss-self-signed-cert.pem>\n")

 int setup_tests(void)
@@ -882,6 +947,7 @@ int setup_tests(void)
     ADD_MFAIL_TEST(test_x509_name_multivalued_rdn_mfail);
     ADD_MFAIL_TEST(test_x509_attribute_i2d_mfail);
     ADD_MFAIL_TEST(test_pkcs7_digest_set_i2d_mfail);
+    ADD_MFAIL_NO_CHECK_TEST(test_pkcs7_digest_set_stream_mfail);
     return 1;
 }