summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2026-08-30 16:52:07 +0000
committertb <>2026-08-30 16:52:07 +0000
commitf1d663df044f339b954b1cc4da10dceb9675130e (patch)
treee7192542c7c13523b2585c40d9c1c6d40ce83694 /src
parent243bc4037954a2ed4a91d6ec8f2c796c1c5da943 (diff)
downloadopenbsd-f1d663df044f339b954b1cc4da10dceb9675130e.tar.gz
openbsd-f1d663df044f339b954b1cc4da10dceb9675130e.tar.bz2
openbsd-f1d663df044f339b954b1cc4da10dceb9675130e.zip
"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.
Diffstat (limited to 'src')
-rw-r--r--src/regress/lib/libcrypto/pkcs7/pkcs7test.c108
1 files changed, 104 insertions, 4 deletions
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 @@
1/* $OpenBSD: pkcs7test.c,v 1.6 2026/04/21 05:18:35 tb Exp $ */ 1/* $OpenBSD: pkcs7test.c,v 1.7 2026/08/30 16:52:07 tb Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2026 Theo Buehler <tb@openbsd.org>
4 * 5 *
5 * Permission to use, copy, modify, and distribute this software for any 6 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
@@ -16,13 +17,16 @@
16 */ 17 */
17 18
18#include <err.h> 19#include <err.h>
20#include <stdarg.h>
21#include <stdio.h>
19#include <stdlib.h> 22#include <stdlib.h>
20#include <string.h> 23#include <string.h>
21#include <unistd.h>
22 24
25#include <openssl/asn1.h>
23#include <openssl/bio.h> 26#include <openssl/bio.h>
24#include <openssl/err.h> 27#include <openssl/err.h>
25#include <openssl/evp.h> 28#include <openssl/evp.h>
29#include <openssl/objects.h>
26#include <openssl/pem.h> 30#include <openssl/pem.h>
27#include <openssl/pkcs7.h> 31#include <openssl/pkcs7.h>
28#include <openssl/x509.h> 32#include <openssl/x509.h>
@@ -100,9 +104,13 @@ x509_store_callback(int ok, X509_STORE_CTX *ctx)
100} 104}
101 105
102static void 106static void
103fatal(const char *msg) 107fatal(const char *msg, ...)
104{ 108{
105 warnx("%s", msg); 109 va_list ap;
110
111 va_start(ap, msg);
112 vwarnx("%s", ap);
113 va_end(ap);
106 ERR_print_errors_fp(stderr); 114 ERR_print_errors_fp(stderr);
107 exit(1); 115 exit(1);
108} 116}
@@ -300,12 +308,104 @@ pkcs7_basics(void)
300 return 0; 308 return 0;
301} 309}
302 310
311static int
312pkcs7_stream_missing_content_nid(int nid)
313{
314 PKCS7 *p7 = NULL;
315 const unsigned char *p, *name;
316 unsigned char **boundary = NULL;
317 unsigned char *der = NULL;
318 int der_len = 0;
319 int ret;
320 int failed = 1;
321
322 name = OBJ_nid2sn(nid);
323
324 /*
325 * Create PKCS7 object with Content Type corresponding to nid
326 * and omit the optional content.
327 */
328
329 if ((p7 = PKCS7_new()) == NULL)
330 fatal("PKCS7_new NID %d (%s)", nid, name);
331 ASN1_OBJECT_free(p7->type);
332 if ((p7->type = OBJ_nid2obj(nid)) == NULL)
333 fatal("OBJ_nid2obj NID %d (%s)", nid, name);
334
335 /*
336 * Round trip this through DER.
337 */
338
339 if ((der_len = i2d_PKCS7(p7, &der)) <= 0)
340 fatal("i2d_PKCS7 NID %d (%s)", nid, name);
341
342 PKCS7_free(p7);
343 p7 = NULL;
344
345 p = der;
346 if ((p7 = d2i_PKCS7(NULL, &p, der_len)) == NULL)
347 fatal("d2i_PKCS7 NID %d (%s)", nid, name);
348
349 /*
350 * It deserialized, so we can safely stream it, right?
351 */
352
353 if ((ret = PKCS7_stream(&boundary, p7)) != 0) {
354 fprintf(stderr, "FAILURE: PKCS7_stream for NID %d (%s) "
355 "want 0, got %d\n", nid, name, ret);
356 goto out;
357 }
358
359 failed = 0;
360
361 out:
362 PKCS7_free(p7);
363 freezero(der, der_len);
364
365 return failed;
366}
367
368/*
369 * For each Content Type OID (RFC 2315, section 14), create a PKCS7 object that
370 * d2i_PKCS7() accepts. For x in [1..6] we use an object that encodes to
371 *
372 * SEQUENCE {
373 * OBJECT_IDENTIFIER { 1.2.840.113549.1.7.x }
374 * }
375 *
376 * This works because RFC 2315 section 7 marks the content optional:
377 *
378 * ContentInfo ::= SEQUENCE {
379 * contentType ContentType,
380 * content
381 * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
382 *
383 * reflected in the ASN1_TFLG_OPTIONAL in pk7_asn1.c's p7default_tt.
384 */
385
386static int
387pkcs7_stream_missing_content(void)
388{
389 int failed = 0;
390
391 /* NID naming consistency is king. */
392 failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_data);
393 failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_signed);
394 failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_enveloped);
395 failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_signedAndEnveloped);
396 failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_digest);
397 failed |= pkcs7_stream_missing_content_nid(NID_pkcs7_encrypted);
398
399 return failed;
400}
401
303int 402int
304main(int argc, char **argv) 403main(int argc, char **argv)
305{ 404{
306 int failed = 0; 405 int failed = 0;
307 406
308 failed |= pkcs7_basics(); 407 failed |= pkcs7_basics();
408 failed |= pkcs7_stream_missing_content();
309 409
310 return failed; 410 return failed;
311} 411}