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;
}