From f1d663df044f339b954b1cc4da10dceb9675130e Mon Sep 17 00:00:00 2001 From: tb <> Date: Sun, 30 Aug 2026 16:52:07 +0000 Subject: "Stream" valid PKCS7 objects with omitted content The PKCS#7 standard marks the content element of the ContentInfo OPTIONAL. Accordingly, a PKCS#7 object only containing a Content Type OID is valid: SEQUENCE { OBJECT_IDENTIFIER { 1.2.840.113549.1.7.4 } } Deserializing such an object works and therefore streaming should at least have the decency of not segfaulting. Of course there's nothing decent about PKCS#7 be it the standard or its OpenSSL "implementation". Exercises a problem reported by Acts1361 and currently crashes. To be fixed in pk7_lib.c r1.32. --- src/regress/lib/libcrypto/pkcs7/pkcs7test.c | 108 ++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/regress/lib/libcrypto/pkcs7/pkcs7test.c b/src/regress/lib/libcrypto/pkcs7/pkcs7test.c index 88126ea082..ae7c41299b 100644 --- a/src/regress/lib/libcrypto/pkcs7/pkcs7test.c +++ b/src/regress/lib/libcrypto/pkcs7/pkcs7test.c @@ -1,6 +1,7 @@ -/* $OpenBSD: pkcs7test.c,v 1.6 2026/04/21 05:18:35 tb Exp $ */ +/* $OpenBSD: pkcs7test.c,v 1.7 2026/08/30 16:52:07 tb Exp $ */ /* * Copyright (c) 2014 Joel Sing + * Copyright (c) 2026 Theo Buehler * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,13 +17,16 @@ */ #include +#include +#include #include #include -#include +#include #include #include #include +#include #include #include #include @@ -100,9 +104,13 @@ x509_store_callback(int ok, X509_STORE_CTX *ctx) } static void -fatal(const char *msg) +fatal(const char *msg, ...) { - warnx("%s", msg); + va_list ap; + + va_start(ap, msg); + vwarnx("%s", ap); + va_end(ap); ERR_print_errors_fp(stderr); exit(1); } @@ -300,12 +308,104 @@ pkcs7_basics(void) return 0; } +static int +pkcs7_stream_missing_content_nid(int nid) +{ + PKCS7 *p7 = NULL; + const unsigned char *p, *name; + unsigned char **boundary = NULL; + unsigned char *der = NULL; + int der_len = 0; + int ret; + int failed = 1; + + name = OBJ_nid2sn(nid); + + /* + * Create PKCS7 object with Content Type corresponding to nid + * and omit the optional content. + */ + + if ((p7 = PKCS7_new()) == NULL) + fatal("PKCS7_new NID %d (%s)", nid, name); + ASN1_OBJECT_free(p7->type); + if ((p7->type = OBJ_nid2obj(nid)) == NULL) + fatal("OBJ_nid2obj NID %d (%s)", nid, name); + + /* + * Round trip this through DER. + */ + + if ((der_len = i2d_PKCS7(p7, &der)) <= 0) + fatal("i2d_PKCS7 NID %d (%s)", nid, name); + + PKCS7_free(p7); + p7 = NULL; + + p = der; + if ((p7 = d2i_PKCS7(NULL, &p, der_len)) == NULL) + fatal("d2i_PKCS7 NID %d (%s)", nid, name); + + /* + * It deserialized, so we can safely stream it, right? + */ + + if ((ret = PKCS7_stream(&boundary, p7)) != 0) { + fprintf(stderr, "FAILURE: PKCS7_stream for NID %d (%s) " + "want 0, got %d\n", nid, name, ret); + goto out; + } + + failed = 0; + + out: + PKCS7_free(p7); + freezero(der, der_len); + + return failed; +} + +/* + * For each Content Type OID (RFC 2315, section 14), create a PKCS7 object that + * d2i_PKCS7() accepts. For x in [1..6] we use an object that encodes to + * + * SEQUENCE { + * OBJECT_IDENTIFIER { 1.2.840.113549.1.7.x } + * } + * + * This works because RFC 2315 section 7 marks the content optional: + * + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + * + * reflected in the ASN1_TFLG_OPTIONAL in pk7_asn1.c's p7default_tt. + */ + +static int +pkcs7_stream_missing_content(void) +{ + int failed = 0; + + /* NID naming consistency is king. */ + failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_data); + failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_signed); + failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_enveloped); + failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_signedAndEnveloped); + failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_digest); + failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_encrypted); + + return failed; +} + int main(int argc, char **argv) { int failed = 0; failed |= pkcs7_basics(); + failed |= pkcs7_stream_missing_content(); return failed; } -- cgit v1.2.3-55-g6feb