Commit eedaf1c2c4 for openssl.org
commit eedaf1c2c46b5e511a603833a65a742085c01bb2
Author: Abel Thomas <abeltom.kernel@gmail.com>
Date: Tue Jul 28 15:02:23 2026 +0200
pkcs7: use PKCS7_get_octet_string in PKCS7_stream signed arm
Direct access to `p7->d.sign->contents->d.data` skips the content-type
check: if the inner eContentType is a non-standard OID the ADB sets
d.other (16 bytes) instead of d.data (24 bytes), and the subsequent
os->flags write lands out of bounds.
Replace with `PKCS7_get_octet_string()`, which returns NULL for any type
that is not `NID_pkcs7_data`, matching the guard already used by
`PKCS7_ctrl()` and `PKCS7_dataDecode()`.
Added a unit-test (`pkcs7_stream_non_data_test`) to validate the change.
Fixes #31681
Reviewed-by: Bob Beck <beck@openssl.org>
Reviewed-by: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
Merge-date: Tue Aug 18 07:47:41 2026
Merged-from: https://github.com/openssl/openssl/pull/31722
diff --git a/crypto/pkcs7/pk7_lib.c b/crypto/pkcs7/pk7_lib.c
index d2a9f0cea8..35d04c4f98 100644
--- a/crypto/pkcs7/pk7_lib.c
+++ b/crypto/pkcs7/pk7_lib.c
@@ -755,7 +755,13 @@ int PKCS7_stream(unsigned char ***boundary, PKCS7 *p7)
ERR_raise(ERR_LIB_PKCS7, PKCS7_R_NO_CONTENT);
break;
}
- os = p7->d.sign->contents->d.data;
+
+ if (!PKCS7_type_is_data(p7->d.sign->contents)) {
+ ERR_raise(ERR_LIB_PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
+ break;
+ }
+
+ os = PKCS7_get_octet_string(p7->d.sign->contents);
break;
default:
diff --git a/test/pkcs7_test.c b/test/pkcs7_test.c
index b48cbd847a..eafd699284 100644
--- a/test/pkcs7_test.c
+++ b/test/pkcs7_test.c
@@ -512,6 +512,44 @@ static int pkcs7_stream_enveloped_signed_no_content_test(void)
return ret;
}
+static int pkcs7_stream_non_data_test(void)
+{
+ int ret = 0;
+ PKCS7 *p7 = NULL;
+ BIO *sink = NULL;
+ BIO *bio = NULL;
+
+ /* clang-format off */
+ static const unsigned char malformed_der[] = {
+ 0x30, 0x32, /* SEQUENCE, 50 bytes */
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, /* pkcs7-signedData */
+ 0xa0, 0x25, /* [0] EXPLICIT, 37 bytes */
+ 0x30, 0x23, /* SEQUENCE PKCS7_SIGNED, 35 bytes */
+ 0x02, 0x01, 0x01, /* INTEGER version=1 */
+ 0x31, 0x00, /* SET{} md_algs */
+ 0x30, 0x1a, /* SEQUENCE inner PKCS7 (contents), 26 bytes */
+ 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x04, /* id-ct-TSTInfo */
+ 0xa0, 0x0b, /* [0] EXPLICIT, 11 bytes (makes d.other non-NULL) */
+ 0x30, 0x09, /* SEQUENCE */
+ 0x02, 0x01, 0x01, /* INTEGER 1 */
+ 0x04, 0x04, 0xde, 0xad, 0xbe, 0xef, /* OCTET STRING */
+ 0x31, 0x00, /* SET{} signer_info */
+ };
+ /* clang-format on */
+
+ const unsigned char *ptr_malformed_der = malformed_der;
+
+ ret = TEST_ptr(p7 = d2i_PKCS7(NULL, &ptr_malformed_der, sizeof(malformed_der)))
+ && TEST_ptr(sink = BIO_new(BIO_s_null()))
+ && TEST_ptr_null(bio = BIO_new_PKCS7(sink, p7))
+ && TEST_int_eq(ERR_GET_REASON(ERR_peek_last_error()), PKCS7_R_UNSUPPORTED_CONTENT_TYPE);
+
+ BIO_free(bio);
+ BIO_free(sink);
+ PKCS7_free(p7);
+ return ret;
+}
+
int setup_tests(void)
{
const char *certin, *privkeyin;
@@ -544,6 +582,7 @@ int setup_tests(void)
ADD_TEST(pkcs7_stream_enveloped_signed_no_content_test);
if (smimecap_cert != NULL && smimecap_privkey != NULL)
ADD_TEST(test_pkcs7_smimecap);
+ ADD_TEST(pkcs7_stream_non_data_test);
return 1;
}