xref: /freebsd/crypto/openssl/test/recipes/80-test_cms.t (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
1#! /usr/bin/env perl
2# Copyright 2015-2025 The OpenSSL Project Authors. All Rights Reserved.
3#
4# Licensed under the Apache License 2.0 (the "License").  You may not use
5# this file except in compliance with the License.  You can obtain a copy
6# in the file LICENSE in the source distribution or at
7# https://www.openssl.org/source/license.html
8
9
10use strict;
11use warnings;
12
13use POSIX;
14use File::Spec::Functions qw/catfile/;
15use File::Compare qw/compare_text compare/;
16use OpenSSL::Test qw/:DEFAULT srctop_dir srctop_file bldtop_dir bldtop_file with data_file/;
17
18use OpenSSL::Test::Utils;
19
20BEGIN {
21    setup("test_cms");
22}
23
24use lib srctop_dir('Configurations');
25use lib bldtop_dir('.');
26
27my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
28my $old_fips = 0;
29
30plan skip_all => "CMS is not supported by this OpenSSL build"
31    if disabled("cms");
32
33my $provpath = bldtop_dir("providers");
34
35# Some tests require legacy algorithms to be included.
36my @legacyprov = ("-provider-path", $provpath,
37                  "-provider", "default",
38                  "-provider", "legacy" );
39my @defaultprov = ("-provider-path", $provpath,
40                   "-provider", "default");
41
42my @config = ( );
43my $provname = 'default';
44my $dsaallow = '1';
45my $no_pqc = 0;
46
47my $datadir = srctop_dir("test", "recipes", "80-test_cms_data");
48my $smdir    = srctop_dir("test", "smime-certs");
49my $smcont   = srctop_file("test", "smcont.txt");
50my $smcont_zero = srctop_file("test", "smcont_zero.txt");
51my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
52    = disabled qw/des dh dsa ec ec2m rc2 zlib/;
53
54$no_rc2 = 1 if disabled("legacy");
55
56plan tests => 30;
57
58ok(run(test(["pkcs7_test"])), "test pkcs7");
59
60unless ($no_fips) {
61    my $provconf = srctop_file("test", "fips-and-base.cnf");
62    @config = ( "-config", $provconf );
63    $provname = 'fips';
64
65    run(test(["fips_version_test", "-config", $provconf, "<3.4.0"]),
66        capture => 1, statusvar => \$dsaallow);
67    $no_dsa = 1 if $dsaallow == '0';
68    $old_fips = 1 if $dsaallow != '0';
69    run(test(["fips_version_test", "-config", $provconf, "<3.5.0"]),
70        capture => 1, statusvar => \$no_pqc);
71}
72
73$ENV{OPENSSL_TEST_LIBCTX} = "1";
74my @prov = ("-provider-path", $provpath,
75            @config,
76            "-provider", $provname);
77
78my $smrsa1024 = catfile($smdir, "smrsa1024.pem");
79my $smrsa1 = catfile($smdir, "smrsa1.pem");
80my $smroot = catfile($smdir, "smroot.pem");
81
82my @smime_pkcs7_tests = (
83
84    [ "signed content DER format, RSA key",
85      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
86        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
87      [ "{cmd2}",  @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
88        "-CAfile", $smroot, "-out", "{output}.txt" ],
89      \&final_compare
90    ],
91
92    [ "signed text content DER format, RSA key",
93      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
94        "-certfile", $smroot, "-signer", $smrsa1, "-text",
95        "-out", "{output}.cms" ],
96      [ "{cmd2}",  @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
97        "-text", "-CAfile", $smroot, "-out", "{output}.txt" ],
98      \&final_compare
99    ],
100
101    [ "signed detached content DER format, RSA key",
102      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
103        "-signer", $smrsa1, "-out", "{output}.cms" ],
104      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
105        "-CAfile", $smroot, "-out", "{output}.txt",
106        "-content", $smcont ],
107      \&final_compare
108    ],
109
110    [ "signed content test streaming BER format, RSA",
111      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
112        "-stream",
113        "-signer", $smrsa1, "-out", "{output}.cms" ],
114      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
115        "-CAfile", $smroot, "-out", "{output}.txt" ],
116      \&final_compare
117    ],
118
119    [ "signed content DER format, DSA key",
120      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
121        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
122      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
123        "-CAfile", $smroot, "-out", "{output}.txt" ],
124      \&final_compare
125    ],
126
127    [ "signed detached content DER format, DSA key",
128      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
129        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
130      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
131        "-CAfile", $smroot, "-out", "{output}.txt",
132        "-content", $smcont ],
133      \&final_compare
134    ],
135
136    [ "signed detached content DER format, add RSA signer (with DSA existing)",
137      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
138        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
139      [ "{cmd1}", @prov, "-resign", "-in", "{output}.cms", "-inform", "DER", "-outform", "DER",
140        "-signer", $smrsa1, "-out", "{output}2.cms" ],
141      [ "{cmd2}", @prov, "-verify", "-in", "{output}2.cms", "-inform", "DER",
142        "-CAfile", $smroot, "-out", "{output}.txt",
143        "-content", $smcont ],
144      \&final_compare
145    ],
146
147    [ "signed content test streaming BER format, DSA key",
148      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
149        "-nodetach", "-stream",
150        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
151      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
152        "-CAfile", $smroot, "-out", "{output}.txt" ],
153      \&final_compare
154    ],
155
156    [ "signed content test streaming BER format, 2 DSA and 2 RSA keys",
157      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
158        "-nodetach", "-stream",
159        "-signer", $smrsa1,
160        "-signer", catfile($smdir, "smrsa2.pem"),
161        "-signer", catfile($smdir, "smdsa1.pem"),
162        "-signer", catfile($smdir, "smdsa2.pem"),
163        "-out", "{output}.cms" ],
164      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
165        "-CAfile", $smroot, "-out", "{output}.txt" ],
166      \&final_compare
167    ],
168
169    [ "signed content test streaming BER format, 2 DSA and 2 RSA keys, no attributes",
170      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
171        "-noattr", "-nodetach", "-stream",
172        "-signer", $smrsa1,
173        "-signer", catfile($smdir, "smrsa2.pem"),
174        "-signer", catfile($smdir, "smdsa1.pem"),
175        "-signer", catfile($smdir, "smdsa2.pem"),
176        "-out", "{output}.cms" ],
177      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
178        "-CAfile", $smroot, "-out", "{output}.txt" ],
179      \&final_compare
180    ],
181
182    [ "signed content S/MIME format, RSA key SHA1",
183      [ "{cmd1}", @defaultprov, "-sign", "-in", $smcont, "-md", "sha1",
184        "-certfile", $smroot,
185        "-signer", $smrsa1, "-out", "{output}.cms" ],
186      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
187        "-CAfile", $smroot, "-out", "{output}.txt" ],
188      \&final_compare
189    ],
190
191    [ "signed zero-length content S/MIME format, RSA key SHA1",
192      [ "{cmd1}", @defaultprov, "-sign", "-in", $smcont_zero, "-md", "sha1",
193        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
194      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
195        "-CAfile", $smroot, "-out", "{output}.txt" ],
196      \&zero_compare
197    ],
198
199    [ "signed content test streaming S/MIME format, 2 DSA and 2 RSA keys",
200      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-nodetach",
201        "-signer", $smrsa1,
202        "-signer", catfile($smdir, "smrsa2.pem"),
203        "-signer", catfile($smdir, "smdsa1.pem"),
204        "-signer", catfile($smdir, "smdsa2.pem"),
205        "-stream", "-out", "{output}.cms" ],
206      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
207        "-CAfile", $smroot, "-out", "{output}.txt" ],
208      \&final_compare
209    ],
210
211    [ "signed content test streaming multipart S/MIME format, 2 DSA and 2 RSA keys",
212      [ "{cmd1}", @prov, "-sign", "-in", $smcont,
213        "-signer", $smrsa1,
214        "-signer", catfile($smdir, "smrsa2.pem"),
215        "-signer", catfile($smdir, "smdsa1.pem"),
216        "-signer", catfile($smdir, "smdsa2.pem"),
217        "-stream", "-out", "{output}.cms" ],
218      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
219        "-CAfile", $smroot, "-out", "{output}.txt" ],
220      \&final_compare
221    ],
222
223    [ "enveloped content test streaming S/MIME format, DES, 3 recipients",
224      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
225        "-stream", "-out", "{output}.cms",
226        $smrsa1,
227        catfile($smdir, "smrsa2.pem"),
228        catfile($smdir, "smrsa3.pem") ],
229      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
230        "-in", "{output}.cms", "-out", "{output}.txt" ],
231      \&final_compare
232    ],
233
234    [ "enveloped text content streaming S/MIME format, DES, 1 recipient",
235      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
236        "-stream", "-text", "-out", "{output}.cms", $smrsa1 ],
237      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
238        "-in", "{output}.cms", "-text", "-out", "{output}.txt" ],
239      \&final_compare
240    ],
241
242    [ "enveloped content test streaming S/MIME format, DES, 3 recipients, 3rd used",
243      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
244        "-stream", "-out", "{output}.cms",
245        $smrsa1,
246        catfile($smdir, "smrsa2.pem"),
247        catfile($smdir, "smrsa3.pem") ],
248      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smrsa3.pem"),
249        "-in", "{output}.cms", "-out", "{output}.txt" ],
250      \&final_compare
251    ],
252
253    [ "enveloped content test streaming S/MIME format, DES, 3 recipients, cert and key files used",
254      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
255        "-stream", "-out", "{output}.cms",
256        $smrsa1,
257        catfile($smdir, "smrsa2.pem"),
258        catfile($smdir, "smrsa3-cert.pem") ],
259      [ "{cmd2}", @defaultprov, "-decrypt",
260	"-recip", catfile($smdir, "smrsa3-cert.pem"),
261	"-inkey", catfile($smdir, "smrsa3-key.pem"),
262        "-in", "{output}.cms", "-out", "{output}.txt" ],
263      \&final_compare
264    ],
265
266);
267
268if ($no_fips || $old_fips) {
269    push(@smime_pkcs7_tests,
270         [ "enveloped content test streaming S/MIME format, AES-256 cipher, 3 recipients",
271           [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
272             "-aes256", "-stream", "-out", "{output}.cms",
273             $smrsa1,
274             catfile($smdir, "smrsa2.pem"),
275             catfile($smdir, "smrsa3.pem") ],
276           [ "{cmd2}", @prov, "-decrypt", "-recip", $smrsa1,
277             "-in", "{output}.cms", "-out", "{output}.txt" ],
278           \&final_compare
279         ]
280    );
281}
282
283my @smime_cms_tests = (
284
285    [ "signed content test streaming BER format, 2 DSA and 2 RSA keys, keyid",
286      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
287        "-nodetach", "-keyid",
288        "-signer", $smrsa1,
289        "-signer", catfile($smdir, "smrsa2.pem"),
290        "-signer", catfile($smdir, "smdsa1.pem"),
291        "-signer", catfile($smdir, "smdsa2.pem"),
292        "-stream", "-out", "{output}.cms" ],
293      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
294        "-CAfile", $smroot, "-out", "{output}.txt" ],
295      \&final_compare
296    ],
297
298    [ "signed content test streaming PEM format, 2 DSA and 2 RSA keys",
299      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
300        "-signer", $smrsa1,
301        "-signer", catfile($smdir, "smrsa2.pem"),
302        "-signer", catfile($smdir, "smdsa1.pem"),
303        "-signer", catfile($smdir, "smdsa2.pem"),
304        "-stream", "-out", "{output}.cms" ],
305      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
306        "-CAfile", $smroot, "-out", "{output}.txt" ],
307      \&final_compare
308    ],
309
310    [ "signed content MIME format, RSA key, signed receipt request",
311      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-nodetach",
312        "-signer", $smrsa1,
313        "-receipt_request_to", "test\@openssl.org", "-receipt_request_all",
314        "-out", "{output}.cms" ],
315      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
316        "-CAfile", $smroot, "-out", "{output}.txt" ],
317      \&final_compare
318    ],
319
320    [ "signed receipt MIME format, RSA key",
321      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-nodetach",
322        "-signer", $smrsa1,
323        "-receipt_request_to", "test\@openssl.org", "-receipt_request_all",
324        "-out", "{output}.cms" ],
325      [ "{cmd1}", @prov, "-sign_receipt", "-in", "{output}.cms",
326        "-signer", catfile($smdir, "smrsa2.pem"), "-out", "{output}2.cms" ],
327      [ "{cmd2}", @prov, "-verify_receipt", "{output}2.cms", "-in", "{output}.cms",
328        "-CAfile", $smroot ]
329    ],
330
331    [ "enveloped content test streaming S/MIME format, DES, 3 recipients, keyid",
332      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
333        "-stream", "-out", "{output}.cms", "-keyid",
334        $smrsa1,
335        catfile($smdir, "smrsa2.pem"),
336        catfile($smdir, "smrsa3.pem") ],
337      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
338        "-in", "{output}.cms", "-out", "{output}.txt" ],
339      \&final_compare
340    ],
341
342    [ "enveloped content test streaming PEM format, AES-256-CBC cipher, KEK",
343      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
344        "-stream", "-out", "{output}.cms",
345        "-secretkey", "000102030405060708090A0B0C0D0E0F",
346        "-secretkeyid", "C0FEE0" ],
347      [ "{cmd2}", @prov, "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
348        "-inform", "PEM",
349        "-secretkey", "000102030405060708090A0B0C0D0E0F",
350        "-secretkeyid", "C0FEE0" ],
351      \&final_compare
352    ],
353
354    [ "enveloped content test streaming PEM format, AES-256-GCM cipher, KEK",
355      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes-128-gcm",
356        "-stream", "-out", "{output}.cms",
357        "-secretkey", "000102030405060708090A0B0C0D0E0F",
358        "-secretkeyid", "C0FEE0" ],
359      [ "{cmd2}", "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
360        "-inform", "PEM",
361        "-secretkey", "000102030405060708090A0B0C0D0E0F",
362        "-secretkeyid", "C0FEE0" ],
363      \&final_compare
364    ],
365
366    [ "enveloped content test streaming PEM format, KEK, key only",
367      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
368        "-stream", "-out", "{output}.cms",
369        "-secretkey", "000102030405060708090A0B0C0D0E0F",
370        "-secretkeyid", "C0FEE0" ],
371      [ "{cmd2}", @prov, "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
372        "-inform", "PEM",
373        "-secretkey", "000102030405060708090A0B0C0D0E0F" ],
374      \&final_compare
375    ],
376
377    [ "enveloped content test streaming PEM format, AES-128-CBC cipher, password",
378      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
379        "-stream", "-out", "{output}.cms",
380        "-pwri_password", "test" ],
381      [ "{cmd2}", @prov, "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
382        "-inform", "PEM",
383        "-pwri_password", "test" ],
384      \&final_compare
385    ],
386
387    [ "data content test streaming PEM format",
388      [ "{cmd1}", @prov, "-data_create", "-in", $smcont, "-outform", "PEM",
389        "-nodetach", "-stream", "-out", "{output}.cms" ],
390      [ "{cmd2}", @prov, "-data_out", "-in", "{output}.cms", "-inform", "PEM",
391        "-out", "{output}.txt" ],
392      \&final_compare
393    ],
394
395    [ "encrypted content test streaming PEM format, 128 bit RC2 key",
396      [ "{cmd1}", @legacyprov, "-EncryptedData_encrypt",
397        "-in", $smcont, "-outform", "PEM",
398        "-rc2", "-secretkey", "000102030405060708090A0B0C0D0E0F",
399        "-stream", "-out", "{output}.cms" ],
400      [ "{cmd2}", @legacyprov, "-EncryptedData_decrypt", "-in", "{output}.cms",
401        "-inform", "PEM",
402        "-secretkey", "000102030405060708090A0B0C0D0E0F",
403        "-out", "{output}.txt" ],
404      \&final_compare
405    ],
406
407    [ "encrypted content test streaming PEM format, 40 bit RC2 key",
408      [ "{cmd1}", @legacyprov, "-EncryptedData_encrypt",
409        "-in", $smcont, "-outform", "PEM",
410        "-rc2", "-secretkey", "0001020304",
411        "-stream", "-out", "{output}.cms" ],
412      [ "{cmd2}", @legacyprov, "-EncryptedData_decrypt", "-in", "{output}.cms",
413        "-inform", "PEM",
414        "-secretkey", "0001020304", "-out", "{output}.txt" ],
415      \&final_compare
416    ],
417
418    [ "encrypted content test streaming PEM format, triple DES key",
419      [ "{cmd1}", @defaultprov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
420        "-des3", "-secretkey", "000102030405060708090A0B0C0D0E0F1011121314151617",
421        "-stream", "-out", "{output}.cms" ],
422      [ "{cmd2}", @prov, "-EncryptedData_decrypt", "-in", "{output}.cms",
423        "-inform", "PEM",
424        "-secretkey", "000102030405060708090A0B0C0D0E0F1011121314151617",
425        "-out", "{output}.txt" ],
426      \&final_compare
427    ],
428
429    [ "encrypted content test streaming PEM format, 128 bit AES key",
430      [ "{cmd1}", @prov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
431        "-aes128", "-secretkey", "000102030405060708090A0B0C0D0E0F",
432        "-stream", "-out", "{output}.cms" ],
433      [ "{cmd2}", @prov, "-EncryptedData_decrypt", "-in", "{output}.cms",
434        "-inform", "PEM",
435        "-secretkey", "000102030405060708090A0B0C0D0E0F",
436        "-out", "{output}.txt" ],
437      \&final_compare
438    ],
439
440    [ "encrypted content test streaming PEM format -noout, 128 bit AES key",
441      [ "{cmd1}", @prov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
442	"-aes128", "-secretkey", "000102030405060708090A0B0C0D0E0F",
443	"-stream", "-noout" ],
444      [ "{cmd2}", @prov, "-help" ]
445    ],
446);
447
448my @smime_cms_cades_tests = (
449
450    [ "signed content DER format, RSA key, CAdES-BES compatible",
451      [ "{cmd1}", @prov, "-sign", "-cades", "-in", $smcont, "-outform", "DER",
452         "-nodetach",
453        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
454      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
455        "-CAfile", $smroot, "-out", "{output}.txt" ],
456      \&final_compare
457    ],
458
459    [ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
460      [ "{cmd1}", @prov, "-sign", "-cades", "-md", "sha256", "-in", $smcont, "-outform",
461        "DER", "-nodetach", "-certfile", $smroot,
462        "-signer", $smrsa1, "-out", "{output}.cms" ],
463      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
464        "-CAfile", $smroot, "-out", "{output}.txt" ],
465      \&final_compare
466    ],
467
468    [ "signed content DER format, RSA key, SHA512 md, CAdES-BES compatible",
469      [ "{cmd1}", @prov, "-sign", "-cades", "-md", "sha512", "-in", $smcont, "-outform",
470        "DER", "-nodetach", "-certfile", $smroot,
471        "-signer", $smrsa1, "-out", "{output}.cms" ],
472      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
473        "-CAfile", $smroot, "-out", "{output}.txt" ],
474      \&final_compare
475    ],
476
477    [ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
478      [ "{cmd1}", @prov, "-sign", "-cades", "-binary",  "-nodetach", "-nosmimecap", "-md", "sha256",
479        "-in", $smcont, "-outform", "DER",
480        "-certfile", $smroot, "-signer", $smrsa1,
481        "-outform", "DER", "-out", "{output}.cms"  ],
482      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
483        "-CAfile", $smroot, "-out", "{output}.txt" ],
484      \&final_compare
485    ],
486
487    [ "resigned content DER format, RSA key, SHA256 md, CAdES-BES compatible",
488      [ "{cmd1}", @prov, "-sign", "-cades", "-binary",  "-nodetach", "-nosmimecap", "-md", "sha256",
489        "-in", $smcont, "-outform", "DER",
490        "-certfile", $smroot, "-signer", $smrsa1,
491        "-outform", "DER", "-out", "{output}.cms"  ],
492      [ "{cmd1}", @prov, "-resign", "-cades", "-binary", "-nodetach", "-nosmimecap", "-md", "sha256",
493        "-inform", "DER", "-in", "{output}.cms",
494        "-certfile", $smroot, "-signer", catfile($smdir, "smrsa2.pem"),
495        "-outform", "DER", "-out", "{output}2.cms" ],
496
497      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}2.cms", "-inform", "DER",
498        "-CAfile", $smroot, "-out", "{output}.txt" ],
499      \&final_compare
500    ],
501);
502
503my @smime_cms_cades_ko_tests = (
504    [ "sign content DER format, RSA key, not CAdES-BES compatible",
505      [ @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
506        "-certfile", $smroot, "-signer", $smrsa1, "-out", "cades-ko.cms" ],
507      "fail to verify token since requiring CAdES-BES compatibility",
508      [ @prov, "-verify", "-cades", "-in", "cades-ko.cms", "-inform", "DER",
509        "-CAfile", $smroot, "-out", "cades-ko.txt" ],
510      \&final_compare
511    ]
512);
513
514# cades options test - check that some combinations are rejected
515my @smime_cms_cades_invalid_option_tests = (
516    [
517        [ "-cades", "-noattr" ],
518    ],[
519        [ "-verify", "-cades", "-noattr" ],
520    ],[
521        [ "-verify", "-cades", "-noverify" ],
522    ],
523);
524
525my @smime_cms_comp_tests = (
526
527    [ "compressed content test streaming PEM format",
528      [ "{cmd1}", @prov, "-compress", "-in", $smcont, "-outform", "PEM", "-nodetach",
529        "-stream", "-out", "{output}.cms" ],
530      [ "{cmd2}", @prov, "-uncompress", "-in", "{output}.cms", "-inform", "PEM",
531        "-out", "{output}.txt" ],
532      \&final_compare
533    ]
534
535);
536
537my @smime_cms_param_tests = (
538    [ "signed content test streaming PEM format, RSA keys, PSS signature",
539      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
540        "-signer", $smrsa1,
541        "-keyopt", "rsa_padding_mode:pss",
542        "-out", "{output}.cms" ],
543      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
544        "-CAfile", $smroot, "-out", "{output}.txt" ],
545      \&final_compare
546    ],
547
548    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=max",
549      [ "{cmd1}", @defaultprov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
550        "-signer", $smrsa1,
551        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:max",
552        "-out", "{output}.cms" ],
553      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 222; },
554      [ "{cmd2}", @defaultprov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
555        "-CAfile", $smroot, "-out", "{output}.txt" ],
556      \&final_compare
557    ],
558
559    [ "signed content test streaming PEM format, RSA keys, PSS signature, no attributes",
560      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
561        "-noattr", "-signer", $smrsa1,
562        "-keyopt", "rsa_padding_mode:pss",
563        "-out", "{output}.cms" ],
564      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
565        "-CAfile", $smroot, "-out", "{output}.txt" ],
566      \&final_compare
567    ],
568
569    [ "signed content test streaming PEM format, RSA keys, PSS signature, SHA384 MGF1",
570      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
571        "-signer", $smrsa1,
572        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_mgf1_md:sha384",
573        "-out", "{output}.cms" ],
574      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
575        "-CAfile", $smroot, "-out", "{output}.txt" ],
576      \&final_compare
577    ],
578
579    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=16",
580      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
581        "-signer", $smrsa1, "-md", "sha256",
582        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:16",
583        "-out", "{output}.cms" ],
584      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 16; },
585      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
586        "-CAfile", $smroot, "-out", "{output}.txt" ],
587      \&final_compare
588    ],
589
590    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=digest",
591      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
592        "-signer", $smrsa1, "-md", "sha256",
593        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:digest",
594        "-out", "{output}.cms" ],
595      # digest is SHA-256, which produces 32 bytes of output
596      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 32; },
597      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
598        "-CAfile", $smroot, "-out", "{output}.txt" ],
599      \&final_compare
600    ],
601
602    [ "enveloped content test streaming S/MIME format, DES, OAEP default parameters",
603      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
604        "-stream", "-out", "{output}.cms",
605        "-recip", $smrsa1,
606        "-keyopt", "rsa_padding_mode:oaep" ],
607      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
608        "-in", "{output}.cms", "-out", "{output}.txt" ],
609      \&final_compare
610    ],
611
612    [ "enveloped content test streaming S/MIME format, DES, OAEP SHA256",
613      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
614        "-stream", "-out", "{output}.cms",
615        "-recip", $smrsa1,
616        "-keyopt", "rsa_padding_mode:oaep",
617        "-keyopt", "rsa_oaep_md:sha256" ],
618      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
619        "-in", "{output}.cms", "-out", "{output}.txt" ],
620      \&final_compare
621    ],
622
623    [ "enveloped content test streaming S/MIME format, DES, ECDH",
624      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
625        "-stream", "-out", "{output}.cms",
626        "-recip", catfile($smdir, "smec1.pem") ],
627      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
628        "-in", "{output}.cms", "-out", "{output}.txt" ],
629      \&final_compare
630    ],
631
632    [ "enveloped content test streaming S/MIME format, DES, ECDH, 2 recipients, key only used",
633      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
634        "-stream", "-out", "{output}.cms",
635        catfile($smdir, "smec1.pem"),
636        catfile($smdir, "smec3.pem") ],
637      [ "{cmd2}", @defaultprov, "-decrypt", "-inkey", catfile($smdir, "smec3.pem"),
638        "-in", "{output}.cms", "-out", "{output}.txt" ],
639      \&final_compare
640    ],
641
642    [ "enveloped content test streaming S/MIME format, ECDH, DES, key identifier",
643      [ "{cmd1}", @defaultprov, "-encrypt", "-keyid", "-in", $smcont,
644        "-stream", "-out", "{output}.cms",
645        "-recip", catfile($smdir, "smec1.pem") ],
646      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
647        "-in", "{output}.cms", "-out", "{output}.txt" ],
648      \&final_compare
649    ],
650
651    [ "enveloped content test streaming S/MIME format, ECDH, AES-128-CBC, SHA256 KDF",
652      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
653        "-stream", "-out", "{output}.cms",
654        "-recip", catfile($smdir, "smec1.pem"), "-aes128",
655        "-keyopt", "ecdh_kdf_md:sha256" ],
656      sub { my %opts = @_; smimeType_matches("$opts{output}.cms", "enveloped-data"); },
657      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
658        "-in", "{output}.cms", "-out", "{output}.txt" ],
659      \&final_compare
660    ],
661
662    [ "enveloped content test streaming S/MIME format, ECDH, AES-128-GCM cipher, SHA256 KDF",
663      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
664        "-stream", "-out", "{output}.cms",
665        "-recip", catfile($smdir, "smec1.pem"), "-aes-128-gcm", "-keyopt", "ecdh_kdf_md:sha256" ],
666      sub { my %opts = @_; smimeType_matches("$opts{output}.cms", "authEnveloped-data"); },
667      [ "{cmd2}", "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
668        "-in", "{output}.cms", "-out", "{output}.txt" ],
669      \&final_compare
670    ],
671
672    [ "enveloped content test streaming S/MIME format, ECDH, K-283, cofactor DH",
673      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
674        "-stream", "-out", "{output}.cms",
675        "-recip", catfile($smdir, "smec2.pem"), "-aes128",
676        "-keyopt", "ecdh_kdf_md:sha256", "-keyopt", "ecdh_cofactor_mode:1" ],
677      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec2.pem"),
678        "-in", "{output}.cms", "-out", "{output}.txt" ],
679      \&final_compare
680    ]
681);
682
683if ($no_fips || $old_fips) {
684    # Only SHA1 supported in dh_cms_encrypt()
685    push(@smime_cms_param_tests,
686
687	 [ "enveloped content test streaming S/MIME format, X9.42 DH",
688	   [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
689	     "-stream", "-out", "{output}.cms",
690	     "-recip", catfile($smdir, "smdh.pem"), "-aes128" ],
691	   [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smdh.pem"),
692	     "-in", "{output}.cms", "-out", "{output}.txt" ],
693	   \&final_compare
694	 ]
695    );
696}
697
698my @smime_cms_param_tests_autodigestmax = (
699    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=auto-digestmax, digestsize < maximum salt length",
700      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
701        "-signer", $smrsa1, "-md", "sha256",
702        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:auto-digestmax",
703        "-out", "{output}.cms" ],
704      # digest is SHA-256, which produces 32, bytes of output
705      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 32; },
706      [ "{cmd2}", @defaultprov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
707        "-CAfile", $smroot, "-out", "{output}.txt" ],
708      \&final_compare
709    ],
710
711    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=auto-digestmax, digestsize > maximum salt length",
712      [ "{cmd1}", @defaultprov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
713        "-signer", $smrsa1024, "-md", "sha512",
714        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:auto-digestmax",
715        "-out", "{output}.cms" ],
716      # digest is SHA-512, which produces 64, bytes of output, but an RSA-PSS
717      # signature with a 1024 bit RSA key can only accommodate 62
718      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 62; },
719      [ "{cmd2}", @defaultprov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
720        "-CAfile", $smroot, "-out", "{output}.txt" ],
721      \&final_compare
722    ]
723);
724
725
726my @contenttype_cms_test = (
727    [ "signed content test - check that content type is added to additional signerinfo, RSA keys",
728      [ "{cmd1}", @prov, "-sign", "-binary", "-nodetach", "-stream", "-in", $smcont,
729        "-outform", "DER", "-signer", $smrsa1, "-md", "SHA256",
730        "-out", "{output}.cms" ],
731      [ "{cmd1}", @prov, "-resign", "-binary", "-nodetach", "-in", "{output}.cms",
732        "-inform", "DER", "-outform", "DER",
733        "-signer", catfile($smdir, "smrsa2.pem"), "-md", "SHA256",
734        "-out", "{output}2.cms" ],
735      sub { my %opts = @_; contentType_matches("$opts{output}2.cms") == 2; },
736      [ "{cmd2}", @prov, "-verify", "-in", "{output}2.cms", "-inform", "DER",
737        "-CAfile", $smroot, "-out", "{output}.txt" ]
738    ],
739);
740
741my @incorrect_attribute_cms_test = (
742    "bad_signtime_attr.cms",
743    "no_ct_attr.cms",
744    "no_md_attr.cms",
745    "ct_multiple_attr.cms"
746);
747
748# Runs a standard loop on the input array
749sub runner_loop {
750    my %opts = ( @_ );
751    my $cnt1 = 0;
752
753    foreach (@{$opts{tests}}) {
754        $cnt1++;
755        $opts{output} = "$opts{prefix}-$cnt1";
756      SKIP: {
757          my $skip_reason = check_availability($$_[0]);
758          skip $skip_reason, 1 if $skip_reason;
759          my $ok = 1;
760          1 while unlink "$opts{output}.txt";
761
762          foreach (@$_[1..$#$_]) {
763              if (ref $_ eq 'CODE') {
764                  $ok &&= $_->(%opts);
765              } else {
766                  my @cmd = map {
767                      my $x = $_;
768                      while ($x =~ /\{([^\}]+)\}/) {
769                          $x = $`.$opts{$1}.$' if exists $opts{$1};
770                      }
771                      $x;
772                  } @$_;
773
774                  diag "CMD: openssl ", join(" ", @cmd);
775                  $ok &&= run(app(["openssl", @cmd]));
776                  $opts{input} = $opts{output};
777              }
778          }
779
780          ok($ok, $$_[0]);
781        }
782    }
783}
784
785sub final_compare {
786    my %opts = @_;
787
788    diag "Comparing $smcont with $opts{output}.txt";
789    return compare_text($smcont, "$opts{output}.txt") == 0;
790}
791
792sub zero_compare {
793    my %opts = @_;
794
795    diag "Checking for zero-length file";
796    return (-e "$opts{output}.txt" && -z "$opts{output}.txt");
797}
798
799subtest "CMS => PKCS#7 compatibility tests\n" => sub {
800    plan tests => scalar @smime_pkcs7_tests;
801
802    runner_loop(prefix => 'cms2pkcs7', cmd1 => 'cms', cmd2 => 'smime',
803                tests => [ @smime_pkcs7_tests ]);
804};
805subtest "CMS <= PKCS#7 compatibility tests\n" => sub {
806    plan tests => scalar @smime_pkcs7_tests;
807
808    runner_loop(prefix => 'pkcs72cms', cmd1 => 'smime', cmd2 => 'cms',
809                tests => [ @smime_pkcs7_tests ]);
810};
811
812subtest "CMS <=> CMS consistency tests\n" => sub {
813    plan tests => (scalar @smime_pkcs7_tests) + (scalar @smime_cms_tests);
814
815    runner_loop(prefix => 'cms2cms-1', cmd1 => 'cms', cmd2 => 'cms',
816                tests => [ @smime_pkcs7_tests ]);
817    runner_loop(prefix => 'cms2cms-2', cmd1 => 'cms', cmd2 => 'cms',
818                tests => [ @smime_cms_tests ]);
819};
820
821subtest "CMS <=> CMS consistency tests, modified key parameters\n" => sub {
822    plan tests =>
823        (scalar @smime_cms_param_tests) + (scalar @smime_cms_comp_tests) +
824        (scalar @smime_cms_param_tests_autodigestmax) + 1;
825
826    ok(run(app(["openssl", "cms", @prov,
827                "-sign", "-in", $smcont,
828                "-outform", "PEM",
829                "-nodetach",
830                "-signer", $smrsa1,
831                "-keyopt", "rsa_padding_mode:pss",
832                "-keyopt", "rsa_pss_saltlen:auto-digestmax",
833                "-out", "digestmaxtest.cms"])));
834    # Providers that do not support rsa_pss_saltlen:auto-digestmax will parse
835    # it as 0
836    my $no_autodigestmax = rsapssSaltlen("digestmaxtest.cms") == 0;
837    1 while unlink "digestmaxtest.cms";
838
839    runner_loop(prefix => 'cms2cms-mod', cmd1 => 'cms', cmd2 => 'cms',
840                tests => [ @smime_cms_param_tests ]);
841  SKIP: {
842      skip("Zlib not supported: compression tests skipped",
843           scalar @smime_cms_comp_tests)
844          if $no_zlib;
845
846      runner_loop(prefix => 'cms2cms-comp', cmd1 => 'cms', cmd2 => 'cms',
847                  tests => [ @smime_cms_comp_tests ]);
848    }
849
850  SKIP: {
851    skip("rsa_pss_saltlen:auto-digestmax not supported",
852         scalar @smime_cms_param_tests_autodigestmax)
853       if $no_autodigestmax;
854
855       runner_loop(prefix => 'cms2cms-comp', 'cmd1' => 'cms', cmd2 => 'cms',
856                   tests => [ @smime_cms_param_tests_autodigestmax ]);
857  }
858};
859
860# Returns the number of matches of a Content Type Attribute in a binary file.
861sub contentType_matches {
862  # Read in a binary file
863  my ($in) = @_;
864  open (HEX_IN, "$in") or die("open failed for $in : $!");
865  binmode(HEX_IN);
866  local $/;
867  my $str = <HEX_IN>;
868
869  # Find ASN1 data for a Content Type Attribute (with a OID of PKCS7 data)
870  my @c = $str =~ /\x30\x18\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x09\x03\x31\x0B\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x07\x01/gs;
871
872  close(HEX_IN);
873  return scalar(@c);
874}
875
876# Returns 1 if the smime-type matches the passed parameter, otherwise 0.
877sub smimeType_matches {
878  my ($in, $expected_smime_type) = @_;
879
880  # Read the text file
881  open(my $fh, '<', $in) or die("open failed for $in : $!");
882  local $/;
883  my $content = <$fh>;
884  close($fh);
885
886  # Extract the Content-Type line with the smime-type attribute
887  if ($content =~ /Content-Type:\s*application\/pkcs7-mime.*smime-type=([^\s;]+)/) {
888    my $smime_type = $1;
889
890    # Compare the extracted smime-type with the expected value
891    return ($smime_type eq $expected_smime_type) ? 1 : 0;
892  }
893
894  # If no smime-type is found, return 0
895  return 0;
896}
897
898sub rsapssSaltlen {
899  my ($in) = @_;
900  my $exit = 0;
901
902  my @asn1parse = run(app(["openssl", "asn1parse", "-in", $in, "-dump"]),
903                      capture => 1,
904                      statusvar => $exit);
905  return -1 if $exit != 0;
906
907  my $pssparam_offset = -1;
908  while ($_ = shift @asn1parse) {
909    chomp;
910    next unless /:rsassaPss/;
911    # This line contains :rsassaPss, the next line contains a raw dump of the
912    # RSA_PSS_PARAMS sequence; obtain its offset
913    $_ = shift @asn1parse;
914    if (/^\s*(\d+):/) {
915      $pssparam_offset = int($1);
916    }
917  }
918
919  if ($pssparam_offset == -1) {
920    note "Failed to determine RSA_PSS_PARAM offset in CMS. " +
921         "Was the file correctly signed with RSASSA-PSS?";
922    return -1;
923  }
924
925  my @pssparam = run(app(["openssl", "asn1parse", "-in", $in,
926                          "-strparse", $pssparam_offset]),
927                     capture => 1,
928                     statusvar => $exit);
929  return -1 if $exit != 0;
930
931  my $saltlen = -1;
932  # Can't use asn1parse -item RSA_PSS_PARAMS here, because that's deprecated.
933  # This assumes the salt length is the last field, which may possibly be
934  # incorrect if there is a non-standard trailer field, but there almost never
935  # is in PSS.
936  if ($pssparam[-1] =~ /prim:\s+INTEGER\s+:([A-Fa-f0-9]+)/) {
937    $saltlen = hex($1);
938  }
939
940  if ($saltlen == -1) {
941    note "Failed to determine salt length from RSA_PSS_PARAM struct. " +
942         "Was the file correctly signed with RSASSA-PSS?";
943    return -1;
944  }
945
946  return $saltlen;
947}
948
949subtest "CMS Check the content type attribute is added for additional signers\n" => sub {
950    plan tests => (scalar @contenttype_cms_test);
951
952    runner_loop(prefix => 'cms2cms-added', cmd1 => 'cms', cmd2 => 'cms',
953                tests => [ @contenttype_cms_test ]);
954};
955
956subtest "CMS Check that bad attributes fail when verifying signers\n" => sub {
957    plan tests =>
958        (scalar @incorrect_attribute_cms_test);
959
960    my $cnt = 0;
961    foreach my $name (@incorrect_attribute_cms_test) {
962        my $out = "incorrect-$cnt.txt";
963
964        ok(!run(app(["openssl", "cms", @prov, "-verify", "-in",
965                     catfile($datadir, $name), "-inform", "DER", "-CAfile",
966                     $smroot, "-out", $out ])),
967            $name);
968    }
969};
970
971subtest "CMS Check that bad encryption algorithm fails\n" => sub {
972    plan tests => 1;
973
974    SKIP: {
975        skip "DES or Legacy isn't supported in this build", 1
976            if disabled("des") || disabled("legacy");
977
978        my $out = "smtst.txt";
979
980        ok(!run(app(["openssl", "cms", @legacyprov, "-encrypt",
981                    "-in", $smcont,
982                    "-stream", "-recip", $smrsa1,
983                    "-des-ede3",
984                    "-out", $out ])),
985           "Decrypt message from OpenSSL 1.1.1");
986    }
987};
988
989subtest "CMS Decrypt message encrypted with OpenSSL 1.1.1\n" => sub {
990    plan tests => 1;
991
992    SKIP: {
993        skip "EC or DES isn't supported in this build", 1
994            if disabled("ec") || disabled("des");
995
996        my $out = "smtst.txt";
997
998        ok(run(app(["openssl", "cms", @defaultprov, "-decrypt",
999                    "-inkey", catfile($smdir, "smec3.pem"),
1000                    "-in", catfile($datadir, "ciphertext_from_1_1_1.cms"),
1001                    "-out", $out ]))
1002           && compare_text($smcont, $out) == 0,
1003           "Decrypt message from OpenSSL 1.1.1");
1004    }
1005};
1006
1007subtest "CAdES <=> CAdES consistency tests\n" => sub {
1008    plan tests => (scalar @smime_cms_cades_tests);
1009
1010    runner_loop(prefix => 'cms-cades', cmd1 => 'cms', cmd2 => 'cms',
1011                tests => [ @smime_cms_cades_tests ]);
1012};
1013
1014subtest "CAdES; cms incompatible arguments tests\n" => sub {
1015    plan tests => (scalar @smime_cms_cades_invalid_option_tests);
1016
1017    foreach (@smime_cms_cades_invalid_option_tests) {
1018        ok(!run(app(["openssl", "cms", @{$$_[0]} ] )));
1019    }
1020};
1021
1022subtest "CAdES ko tests\n" => sub {
1023    plan tests => 2 * scalar @smime_cms_cades_ko_tests;
1024
1025    foreach (@smime_cms_cades_ko_tests) {
1026      SKIP: {
1027        my $skip_reason = check_availability($$_[0]);
1028        skip $skip_reason, 1 if $skip_reason;
1029        1 while unlink "cades-ko.txt";
1030
1031        ok(run(app(["openssl", "cms", @{$$_[1]}])), $$_[0]);
1032        ok(!run(app(["openssl", "cms", @{$$_[3]}])), $$_[2]);
1033        }
1034    }
1035};
1036
1037subtest "CMS binary input tests\n" => sub {
1038    my $input = srctop_file("test", "smcont.bin");
1039    my $signed = "smcont.signed";
1040    my $verified = "smcont.verified";
1041
1042    plan tests => 11;
1043
1044    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-signer", $smrsa1,
1045                "-binary", "-in", $input, "-out", $signed])),
1046       "sign binary input with -binary");
1047    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $smroot,
1048                "-binary", "-in", $signed, "-out", $verified])),
1049       "verify binary input with -binary");
1050    is(compare($input, $verified), 0, "binary input retained with -binary");
1051
1052    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-signer", $smrsa1,
1053                "-in", $input, "-out", $signed.".nobin"])),
1054       "sign binary input without -binary");
1055    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $smroot,
1056                "-in", $signed.".nobin", "-out", $verified.".nobin"])),
1057       "verify binary input without -binary");
1058    is(compare($input, $verified.".nobin"), 1, "binary input not retained without -binary");
1059    ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $smroot, "-crlfeol",
1060                "-binary", "-in", $signed, "-out", $verified.".crlfeol"])),
1061       "verify binary input wrong crlfeol");
1062
1063    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-signer", $smrsa1,
1064                "-crlfeol",
1065                "-binary", "-in", $input, "-out", $signed.".crlf"])),
1066       "sign binary input with -binary -crlfeol");
1067    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $smroot, "-crlfeol",
1068                "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf"])),
1069       "verify binary input with -binary -crlfeol");
1070    is(compare($input, $verified.".crlf"), 0,
1071       "binary input retained with -binary -crlfeol");
1072    ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $smroot,
1073                "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf2"])),
1074       "verify binary input with -binary missing -crlfeol");
1075};
1076
1077subtest "CMS signed digest, DER format" => sub {
1078    plan tests => 2;
1079
1080    # Pre-computed SHA256 digest of $smcont in hexadecimal form
1081    my $digest = "ff236ef61b396355f75a4cc6e1c306d4c309084ae271a9e2ad6888f10a101b32";
1082
1083    my $sig_file = "signature.der";
1084    ok(run(app(["openssl", "cms", @prov, "-sign", "-digest", $digest,
1085                    "-outform", "DER",
1086                    "-certfile", catfile($smdir, "smroot.pem"),
1087                    "-signer", catfile($smdir, "smrsa1.pem"),
1088                    "-out", $sig_file])),
1089        "CMS sign pre-computed digest, DER format");
1090
1091    ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1092                    "-inform", "DER",
1093                    "-CAfile", catfile($smdir, "smroot.pem"),
1094                    "-content", $smcont])),
1095       "Verify CMS signed digest, DER format");
1096};
1097
1098subtest "CMS signed digest, DER format, no signing time" => sub {
1099    # This test also enables CAdES mode and disables S/MIME capabilities
1100    # to approximate the kind of signature required for a PAdES-compliant
1101    # PDF signature.
1102    plan tests => 4;
1103
1104    # Pre-computed SHA256 digest of $smcont in hexadecimal form
1105    my $digest = "ff236ef61b396355f75a4cc6e1c306d4c309084ae271a9e2ad6888f10a101b32";
1106
1107    my $sig_file = "signature.der";
1108    ok(run(app(["openssl", "cms", @prov, "-sign", "-digest", $digest,
1109                    "-outform", "DER",
1110                    "-no_signing_time",
1111                    "-nosmimecap",
1112                    "-cades",
1113                    "-certfile", catfile($smdir, "smroot.pem"),
1114                    "-signer", catfile($smdir, "smrsa1.pem"),
1115                    "-out", $sig_file])),
1116        "CMS sign pre-computed digest, DER format, no signing time");
1117
1118    my $exit = 0;
1119    my $dump = join "\n",
1120               run(app(["openssl", "cms", @prov, "-cmsout", "-noout", "-print",
1121                            "-in", $sig_file,
1122                            "-inform", "DER"]),
1123                   capture => 1,
1124                   statusvar => $exit);
1125
1126    is($exit, 0, "Parse CMS signed digest, DER format, no signing time");
1127    is(index($dump, 'signingTime'), -1,
1128        "Check that CMS signed digest does not contain signing time");
1129
1130    ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1131                    "-inform", "DER",
1132                    "-CAfile", catfile($smdir, "smroot.pem"),
1133                    "-content", $smcont])),
1134       "Verify CMS signed digest, DER format, no signing time");
1135};
1136
1137
1138subtest "CMS signed digest, S/MIME format" => sub {
1139    plan tests => 2;
1140
1141    # Pre-computed SHA256 digest of $smcont in hexadecimal form
1142    my $digest = "ff236ef61b396355f75a4cc6e1c306d4c309084ae271a9e2ad6888f10a101b32";
1143
1144    my $sig_file = "signature.smime";
1145    ok(run(app(["openssl", "cms", @prov, "-sign", "-digest", $digest,
1146                    "-outform", "SMIME",
1147                    "-certfile", catfile($smdir, "smroot.pem"),
1148                    "-signer", catfile($smdir, "smrsa1.pem"),
1149                    "-out", $sig_file])),
1150        "CMS sign pre-computed digest, S/MIME format");
1151
1152    ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1153                    "-inform", "SMIME",
1154                    "-CAfile", catfile($smdir, "smroot.pem"),
1155                    "-content", $smcont])),
1156       "Verify CMS signed digest, S/MIME format");
1157};
1158
1159sub path_tests {
1160    our $app = shift;
1161    our @path = qw(test certs);
1162    our $key = srctop_file(@path, "ee-key.pem");
1163    our $ee = srctop_file(@path, "ee-cert.pem");
1164    our $ca = srctop_file(@path, "ca-cert.pem");
1165    our $root = srctop_file(@path, "root-cert.pem");
1166    our $sig_file = "signature.p7s";
1167
1168    sub sign {
1169        my $inter = shift;
1170        my @inter = $inter ? ("-certfile", $inter) : ();
1171        my $msg = shift;
1172        ok(run(app(["openssl", $app, @prov, "-sign", "-in", $smcont,
1173                    "-inkey", $key, "-signer", $ee, @inter,
1174                    "-out", $sig_file],
1175                   "accept $app sign with EE $msg".
1176                   " intermediate CA certificates")));
1177    }
1178    sub verify {
1179        my $inter = shift;
1180        my @inter = $inter ? ("-certfile", $inter) : ();
1181        my $msg = shift;
1182        my $res = shift;
1183        ok($res == run(app(["openssl", $app, @prov, "-verify", "-in", $sig_file,
1184                            "-purpose", "sslserver", "-CAfile", $root, @inter,
1185                            "-content", $smcont],
1186                           "accept $app verify with EE ".
1187                           "$msg intermediate CA certificates")));
1188    }
1189    sign($ca, "and");
1190    verify(0, "with included", 1);
1191    sign(0, "without");
1192    verify(0, "without", 0);
1193    verify($ca, "with added", 1);
1194};
1195subtest "CMS sign+verify cert path tests" => sub {
1196    plan tests => 5;
1197
1198    path_tests("cms");
1199};
1200subtest "PKCS7 sign+verify cert path tests" => sub {
1201    plan tests => 5;
1202
1203    path_tests("smime");
1204};
1205
1206subtest "CMS code signing test" => sub {
1207    plan tests => 7;
1208    my $sig_file = "signature.p7s";
1209    ok(run(app(["openssl", "cms", @prov, "-sign", "-in", $smcont,
1210                   "-certfile", catfile($smdir, "smroot.pem"),
1211                   "-signer", catfile($smdir, "smrsa1.pem"),
1212                   "-out", $sig_file])),
1213       "accept perform CMS signature with smime certificate");
1214
1215    ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1216                    "-CAfile", catfile($smdir, "smroot.pem"),
1217                    "-content", $smcont])),
1218       "accept verify CMS signature with smime certificate");
1219
1220    ok(!run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1221                    "-CAfile", catfile($smdir, "smroot.pem"),
1222                    "-purpose", "codesign",
1223                    "-content", $smcont])),
1224       "fail verify CMS signature with smime certificate for purpose code signing");
1225
1226    ok(!run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1227                    "-CAfile", catfile($smdir, "smroot.pem"),
1228                    "-purpose", "football",
1229                    "-content", $smcont])),
1230       "fail verify CMS signature with invalid purpose argument");
1231
1232    ok(run(app(["openssl", "cms", @prov, "-sign", "-in", $smcont,
1233                   "-certfile", catfile($smdir, "smroot.pem"),
1234                   "-signer", catfile($smdir, "csrsa1.pem"),
1235                   "-out", $sig_file])),
1236        "accept perform CMS signature with code signing certificate");
1237
1238    ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1239                    "-CAfile", catfile($smdir, "smroot.pem"),
1240                    "-purpose", "codesign",
1241                    "-content", $smcont])),
1242       "accept verify CMS signature with code signing certificate for purpose code signing");
1243
1244    ok(!run(app(["openssl", "cms", @prov, "-verify", "-in", $sig_file,
1245                    "-CAfile", catfile($smdir, "smroot.pem"),
1246                    "-content", $smcont])),
1247       "fail verify CMS signature with code signing certificate for purpose smime_sign");
1248};
1249
1250# Test case for missing MD algorithm (must not segfault)
1251
1252with({ exit_checker => sub { return shift == 4; } },
1253    sub {
1254        ok(run(app(['openssl', 'smime', '-verify', '-noverify',
1255                    '-inform', 'PEM',
1256                    '-in', data_file("pkcs7-md4.pem"),
1257                   ])),
1258            "Check failure of EVP_DigestInit in PKCS7 signed is handled");
1259
1260        ok(run(app(['openssl', 'smime', '-decrypt',
1261                    '-inform', 'PEM',
1262                    '-in', data_file("pkcs7-md4-encrypted.pem"),
1263                    '-recip', srctop_file("test", "certs", "ee-cert.pem"),
1264                    '-inkey', srctop_file("test", "certs", "ee-key.pem")
1265                   ])),
1266            "Check failure of EVP_DigestInit in PKCS7 signedAndEnveloped is handled");
1267    });
1268
1269sub check_availability {
1270    my $tnam = shift;
1271
1272    return "$tnam: skipped, EC disabled\n"
1273        if ($no_ec && $tnam =~ /ECDH/);
1274    return "$tnam: skipped, ECDH disabled\n"
1275        if ($no_ec && $tnam =~ /ECDH/);
1276    return "$tnam: skipped, EC2M disabled\n"
1277        if ($no_ec2m && $tnam =~ /K-283/);
1278    return "$tnam: skipped, DH disabled\n"
1279        if ($no_dh && $tnam =~ /X9\.42/);
1280    return "$tnam: skipped, RC2 disabled\n"
1281        if ($no_rc2 && $tnam =~ /RC2/);
1282    return "$tnam: skipped, DES disabled\n"
1283        if ($no_des && $tnam =~ /DES/);
1284    return "$tnam: skipped, DSA disabled\n"
1285        if ($no_dsa && $tnam =~ / DSA/);
1286
1287    return "";
1288}
1289
1290# Test case for the locking problem reported in #19643.
1291# This will fail if the fix is in and deadlock on Windows (and possibly
1292# other platforms) if not.
1293ok(!run(app(['openssl', 'cms', '-verify',
1294             '-CAfile', srctop_file("test/certs", "pkitsta.pem"),
1295             '-policy', 'anyPolicy',
1296             '-in', srctop_file("test/smime-eml",
1297                                "SignedInvalidMappingFromanyPolicyTest7.eml")
1298            ])),
1299   "issue#19643");
1300
1301# Check that kari encryption with originator does not segfault
1302with({ exit_checker => sub { return shift == 3; } },
1303  sub {
1304    SKIP: {
1305      skip "EC is not supported in this build", 1 if $no_ec;
1306
1307      ok(run(app(['openssl', 'cms', '-encrypt',
1308                  '-in', srctop_file("test", "smcont.txt"), '-aes128',
1309                  '-recip', catfile($smdir, "smec1.pem"),
1310                  '-originator', catfile($smdir, "smec3.pem"),
1311                  '-inkey', catfile($smdir, "smec3.pem")
1312                ])),
1313          "Check failure for currently not supported kari encryption with static originator");
1314    }
1315  });
1316
1317# Check that we get the expected failure return code
1318with({ exit_checker => sub { return shift == 6; } },
1319    sub {
1320        ok(run(app(['openssl', 'cms', '-encrypt',
1321                    '-in', srctop_file("test", "smcont.txt"),
1322                    '-aes128', '-stream', '-recip',
1323                    srctop_file("test/smime-certs", "badrsa.pem"),
1324                   ])),
1325            "Check failure during BIO setup with -stream is handled correctly");
1326    });
1327
1328# Test case for return value mis-check reported in #21986
1329with({ exit_checker => sub { return shift == 3; } },
1330    sub {
1331        SKIP: {
1332          skip "DSA is not supported in this build", 1 if $no_dsa;
1333
1334          ok(run(app(['openssl', 'cms', '-sign',
1335                      '-in', srctop_file("test", "smcont.txt"),
1336                      '-signer', srctop_file("test/smime-certs", "smdsa1.pem"),
1337                      '-md', 'SHAKE256'])),
1338            "issue#21986");
1339        }
1340    });
1341
1342# Test for problem reported in #22225
1343with({ exit_checker => sub { return shift == 3; } },
1344    sub {
1345	ok(run(app(['openssl', 'cms', '-encrypt',
1346		    '-in', srctop_file("test", "smcont.txt"),
1347		    '-aes-256-ctr', '-recip',
1348		    catfile($smdir, "smec1.pem"),
1349		   ])),
1350	   "Check for failure when cipher does not have an assigned OID (issue#22225)");
1351     });
1352
1353# Test encrypt to three recipients, and decrypt using key-only;
1354# i.e. do not follow the recommended practice of providing the
1355# recipient cert in the decrypt op.
1356#
1357# Use RSAES-OAEP for key-transport, not RSAES-PKCS-v1_5.
1358#
1359# Because the cert is not provided during decrypt, all RSA ciphertexts
1360# are decrypted in turn, and when/if there is a valid decryption, it
1361# is assumed the correct content-key has been recovered.
1362#
1363# That process may fail with RSAES-PKCS-v1_5 b/c there is a
1364# non-negligible chance that decrypting a random input using
1365# RSAES-PKCS-v1_5 can result in a valid plaintext (so two content-keys
1366# could be recovered and the wrong one might be used).
1367#
1368# See https://github.com/openssl/project/issues/380
1369subtest "encrypt to three recipients with RSA-OAEP, key only decrypt" => sub {
1370    plan tests => 3;
1371
1372    my $pt = srctop_file("test", "smcont.txt");
1373    my $ct = "smtst.cms";
1374    my $ptpt = "smtst.txt";
1375
1376    ok(run(app(['openssl', 'cms',
1377		@defaultprov,
1378		'-encrypt', '-aes128',
1379		'-in', $pt,
1380		'-out', $ct,
1381		'-stream',
1382		'-recip', catfile($smdir, "smrsa1.pem"),
1383		'-keyopt', 'rsa_padding_mode:oaep',
1384		'-recip', catfile($smdir, "smrsa2.pem"),
1385		'-keyopt', 'rsa_padding_mode:oaep',
1386		'-recip', catfile($smdir, "smrsa3-cert.pem"),
1387		'-keyopt', 'rsa_padding_mode:oaep',
1388	       ])),
1389       "encrypt to three recipients with RSA-OAEP (avoid openssl/project issue#380)");
1390    ok(run(app(['openssl', 'cms',
1391		@defaultprov,
1392		'-decrypt', '-aes128',
1393		'-in', $ct,
1394		'-out', $ptpt,
1395		'-inkey', catfile($smdir, "smrsa3-key.pem"),
1396	       ])),
1397       "decrypt with key only");
1398    is(compare($pt, $ptpt), 0, "compare original message with decrypted ciphertext");
1399};
1400
1401subtest "EdDSA tests for CMS" => sub {
1402    plan tests => 2;
1403
1404    SKIP: {
1405        skip "ECX (EdDSA) is not supported in this build", 2
1406            if disabled("ecx");
1407
1408        my $crt1 = srctop_file("test", "certs", "root-ed25519.pem");
1409        my $key1 = srctop_file("test", "certs", "root-ed25519.privkey.pem");
1410        my $sig1 = "sig1.cms";
1411
1412        ok(run(app(["openssl", "cms", @prov, "-sign", "-md", "sha512", "-in", $smcont,
1413                    "-signer", $crt1, "-inkey", $key1, "-out", $sig1])),
1414           "accept CMS signature with Ed25519");
1415
1416        ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig1,
1417                    "-CAfile", $crt1, "-content", $smcont])),
1418           "accept CMS verify with Ed25519");
1419    }
1420};
1421
1422subtest "ML-DSA tests for CMS" => sub {
1423    plan tests => 2;
1424
1425    SKIP: {
1426        skip "ML-DSA is not supported in this build", 2
1427            if disabled("ml-dsa") || $no_pqc;
1428
1429        my $sig1 = "sig1.cms";
1430
1431        # draft-ietf-lamps-cms-ml-dsa: use SHA512 with ML-DSA
1432        ok(run(app(["openssl", "cms", @prov, "-sign", "-md", "sha512", "-in", $smcont,
1433                    "-certfile", $smroot, "-signer", catfile($smdir, "sm_mldsa44.pem"),
1434                    "-out", $sig1])),
1435           "accept CMS signature with ML-DSA-44");
1436
1437        ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig1,
1438                    "-CAfile", $smroot, "-content", $smcont])),
1439           "accept CMS verify with ML-DSA-44");
1440    }
1441};
1442
1443subtest "SLH-DSA tests for CMS" => sub {
1444    plan tests => 6;
1445
1446    SKIP: {
1447        skip "SLH-DSA is not supported in this build", 6
1448            if disabled("slh-dsa") || $no_pqc;
1449
1450        my $sig1 = "sig1.cms";
1451
1452        # draft-ietf-lamps-cms-sphincs-plus: use SHA512 with SLH-DSA-SHA2
1453        ok(run(app(["openssl", "cms", @prov, "-sign", "-md", "sha512", "-in", $smcont,
1454                    "-certfile", $smroot, "-signer", catfile($smdir, "sm_slhdsa_sha2_128s.pem"),
1455                    "-out", $sig1])),
1456           "accept CMS signature with SLH-DSA-SHA2-128s");
1457
1458        ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig1,
1459                    "-CAfile", $smroot, "-content", $smcont])),
1460           "accept CMS verify with SLH-DSA-SHA2-128s");
1461
1462        # draft-ietf-lamps-cms-sphincs-plus: use SHAKE128 with SLH-DSA-SHAKE-128*
1463        ok(run(app(["openssl", "cms", @prov, "-sign", "-md", "shake128", "-in", $smcont,
1464                    "-certfile", $smroot, "-signer", catfile($smdir, "sm_slhdsa_shake_128s.pem"),
1465                    "-out", $sig1])),
1466           "accept CMS signature with SLH-DSA-SHAKE-128s");
1467
1468        ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig1,
1469                    "-CAfile", $smroot, "-content", $smcont])),
1470           "accept CMS verify with SLH-DSA-SHAKE-128s");
1471
1472        # draft-ietf-lamps-cms-sphincs-plus: use SHAKE256 with SLH-DSA-SHAKE-256*
1473        ok(run(app(["openssl", "cms", @prov, "-sign", "-md", "shake256", "-in", $smcont,
1474                    "-certfile", $smroot, "-signer", catfile($smdir, "sm_slhdsa_shake_256s.pem"),
1475                    "-out", $sig1])),
1476           "accept CMS signature with SLH-DSA-SHAKE-256s");
1477
1478        ok(run(app(["openssl", "cms", @prov, "-verify", "-in", $sig1,
1479                    "-CAfile", $smroot, "-content", $smcont])),
1480           "accept CMS verify with SLH-DSA-SHAKE-256s");
1481    }
1482};
1483