1#! /usr/bin/env perl
2# Copyright 2015-2023 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);
28
29plan skip_all => "CMS is not supported by this OpenSSL build"
30    if disabled("cms");
31
32my $provpath = bldtop_dir("providers");
33
34# Some tests require legacy algorithms to be included.
35my @legacyprov = ("-provider-path", $provpath,
36                  "-provider", "default",
37                  "-provider", "legacy" );
38my @defaultprov = ("-provider-path", $provpath,
39                   "-provider", "default");
40
41my @config = ( );
42my $provname = 'default';
43
44my $datadir = srctop_dir("test", "recipes", "80-test_cms_data");
45my $smdir    = srctop_dir("test", "smime-certs");
46my $smcont   = srctop_file("test", "smcont.txt");
47my $smcont_zero = srctop_file("test", "smcont_zero.txt");
48my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib)
49    = disabled qw/des dh dsa ec ec2m rc2 zlib/;
50
51$no_rc2 = 1 if disabled("legacy");
52
53plan tests => 16;
54
55ok(run(test(["pkcs7_test"])), "test pkcs7");
56
57unless ($no_fips) {
58    @config = ( "-config", srctop_file("test", "fips-and-base.cnf") );
59    $provname = 'fips';
60}
61
62$ENV{OPENSSL_TEST_LIBCTX} = "1";
63my @prov = ("-provider-path", $provpath,
64            @config,
65            "-provider", $provname);
66
67my $smrsa1024 = catfile($smdir, "smrsa1024.pem");
68my $smrsa1 = catfile($smdir, "smrsa1.pem");
69my $smroot = catfile($smdir, "smroot.pem");
70
71my @smime_pkcs7_tests = (
72
73    [ "signed content DER format, RSA key",
74      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
75        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
76      [ "{cmd2}",  @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
77        "-CAfile", $smroot, "-out", "{output}.txt" ],
78      \&final_compare
79    ],
80
81    [ "signed detached content DER format, RSA key",
82      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
83        "-signer", $smrsa1, "-out", "{output}.cms" ],
84      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
85        "-CAfile", $smroot, "-out", "{output}.txt",
86        "-content", $smcont ],
87      \&final_compare
88    ],
89
90    [ "signed content test streaming BER format, RSA",
91      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
92        "-stream",
93        "-signer", $smrsa1, "-out", "{output}.cms" ],
94      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
95        "-CAfile", $smroot, "-out", "{output}.txt" ],
96      \&final_compare
97    ],
98
99    [ "signed content DER format, DSA key",
100      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
101        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
102      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
103        "-CAfile", $smroot, "-out", "{output}.txt" ],
104      \&final_compare
105    ],
106
107    [ "signed detached content DER format, DSA key",
108      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
109        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
110      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
111        "-CAfile", $smroot, "-out", "{output}.txt",
112        "-content", $smcont ],
113      \&final_compare
114    ],
115
116    [ "signed detached content DER format, add RSA signer (with DSA existing)",
117      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
118        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
119      [ "{cmd1}", @prov, "-resign", "-in", "{output}.cms", "-inform", "DER", "-outform", "DER",
120        "-signer", $smrsa1, "-out", "{output}2.cms" ],
121      [ "{cmd2}", @prov, "-verify", "-in", "{output}2.cms", "-inform", "DER",
122        "-CAfile", $smroot, "-out", "{output}.txt",
123        "-content", $smcont ],
124      \&final_compare
125    ],
126
127    [ "signed content test streaming BER format, DSA key",
128      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
129        "-nodetach", "-stream",
130        "-signer", catfile($smdir, "smdsa1.pem"), "-out", "{output}.cms" ],
131      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
132        "-CAfile", $smroot, "-out", "{output}.txt" ],
133      \&final_compare
134    ],
135
136    [ "signed content test streaming BER format, 2 DSA and 2 RSA keys",
137      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
138        "-nodetach", "-stream",
139        "-signer", $smrsa1,
140        "-signer", catfile($smdir, "smrsa2.pem"),
141        "-signer", catfile($smdir, "smdsa1.pem"),
142        "-signer", catfile($smdir, "smdsa2.pem"),
143        "-out", "{output}.cms" ],
144      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
145        "-CAfile", $smroot, "-out", "{output}.txt" ],
146      \&final_compare
147    ],
148
149    [ "signed content test streaming BER format, 2 DSA and 2 RSA keys, no attributes",
150      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
151        "-noattr", "-nodetach", "-stream",
152        "-signer", $smrsa1,
153        "-signer", catfile($smdir, "smrsa2.pem"),
154        "-signer", catfile($smdir, "smdsa1.pem"),
155        "-signer", catfile($smdir, "smdsa2.pem"),
156        "-out", "{output}.cms" ],
157      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
158        "-CAfile", $smroot, "-out", "{output}.txt" ],
159      \&final_compare
160    ],
161
162    [ "signed content S/MIME format, RSA key SHA1",
163      [ "{cmd1}", @defaultprov, "-sign", "-in", $smcont, "-md", "sha1",
164        "-certfile", $smroot,
165        "-signer", $smrsa1, "-out", "{output}.cms" ],
166      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
167        "-CAfile", $smroot, "-out", "{output}.txt" ],
168      \&final_compare
169    ],
170
171    [ "signed zero-length content S/MIME format, RSA key SHA1",
172      [ "{cmd1}", @defaultprov, "-sign", "-in", $smcont_zero, "-md", "sha1",
173        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
174      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
175        "-CAfile", $smroot, "-out", "{output}.txt" ],
176      \&zero_compare
177    ],
178
179    [ "signed content test streaming S/MIME format, 2 DSA and 2 RSA keys",
180      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-nodetach",
181        "-signer", $smrsa1,
182        "-signer", catfile($smdir, "smrsa2.pem"),
183        "-signer", catfile($smdir, "smdsa1.pem"),
184        "-signer", catfile($smdir, "smdsa2.pem"),
185        "-stream", "-out", "{output}.cms" ],
186      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
187        "-CAfile", $smroot, "-out", "{output}.txt" ],
188      \&final_compare
189    ],
190
191    [ "signed content test streaming multipart S/MIME format, 2 DSA and 2 RSA keys",
192      [ "{cmd1}", @prov, "-sign", "-in", $smcont,
193        "-signer", $smrsa1,
194        "-signer", catfile($smdir, "smrsa2.pem"),
195        "-signer", catfile($smdir, "smdsa1.pem"),
196        "-signer", catfile($smdir, "smdsa2.pem"),
197        "-stream", "-out", "{output}.cms" ],
198      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
199        "-CAfile", $smroot, "-out", "{output}.txt" ],
200      \&final_compare
201    ],
202
203    [ "enveloped content test streaming S/MIME format, DES, 3 recipients",
204      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
205        "-stream", "-out", "{output}.cms",
206        $smrsa1,
207        catfile($smdir, "smrsa2.pem"),
208        catfile($smdir, "smrsa3.pem") ],
209      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
210        "-in", "{output}.cms", "-out", "{output}.txt" ],
211      \&final_compare
212    ],
213
214    [ "enveloped content test streaming S/MIME format, DES, 3 recipients, 3rd used",
215      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
216        "-stream", "-out", "{output}.cms",
217        $smrsa1,
218        catfile($smdir, "smrsa2.pem"),
219        catfile($smdir, "smrsa3.pem") ],
220      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smrsa3.pem"),
221        "-in", "{output}.cms", "-out", "{output}.txt" ],
222      \&final_compare
223    ],
224
225    [ "enveloped content test streaming S/MIME format, DES, 3 recipients, key only used",
226      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
227        "-stream", "-out", "{output}.cms",
228        $smrsa1,
229        catfile($smdir, "smrsa2.pem"),
230        catfile($smdir, "smrsa3.pem") ],
231      [ "{cmd2}", @defaultprov, "-decrypt", "-inkey", catfile($smdir, "smrsa3.pem"),
232        "-in", "{output}.cms", "-out", "{output}.txt" ],
233      \&final_compare
234    ],
235
236    [ "enveloped content test streaming S/MIME format, AES-256 cipher, 3 recipients",
237      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
238        "-aes256", "-stream", "-out", "{output}.cms",
239        $smrsa1,
240        catfile($smdir, "smrsa2.pem"),
241        catfile($smdir, "smrsa3.pem") ],
242      [ "{cmd2}", @prov, "-decrypt", "-recip", $smrsa1,
243        "-in", "{output}.cms", "-out", "{output}.txt" ],
244      \&final_compare
245    ],
246
247);
248
249my @smime_cms_tests = (
250
251    [ "signed content test streaming BER format, 2 DSA and 2 RSA keys, keyid",
252      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "DER",
253        "-nodetach", "-keyid",
254        "-signer", $smrsa1,
255        "-signer", catfile($smdir, "smrsa2.pem"),
256        "-signer", catfile($smdir, "smdsa1.pem"),
257        "-signer", catfile($smdir, "smdsa2.pem"),
258        "-stream", "-out", "{output}.cms" ],
259      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "DER",
260        "-CAfile", $smroot, "-out", "{output}.txt" ],
261      \&final_compare
262    ],
263
264    [ "signed content test streaming PEM format, 2 DSA and 2 RSA keys",
265      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
266        "-signer", $smrsa1,
267        "-signer", catfile($smdir, "smrsa2.pem"),
268        "-signer", catfile($smdir, "smdsa1.pem"),
269        "-signer", catfile($smdir, "smdsa2.pem"),
270        "-stream", "-out", "{output}.cms" ],
271      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
272        "-CAfile", $smroot, "-out", "{output}.txt" ],
273      \&final_compare
274    ],
275
276    [ "signed content MIME format, RSA key, signed receipt request",
277      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-nodetach",
278        "-signer", $smrsa1,
279        "-receipt_request_to", "test\@openssl.org", "-receipt_request_all",
280        "-out", "{output}.cms" ],
281      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms",
282        "-CAfile", $smroot, "-out", "{output}.txt" ],
283      \&final_compare
284    ],
285
286    [ "signed receipt MIME format, RSA key",
287      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-nodetach",
288        "-signer", $smrsa1,
289        "-receipt_request_to", "test\@openssl.org", "-receipt_request_all",
290        "-out", "{output}.cms" ],
291      [ "{cmd1}", @prov, "-sign_receipt", "-in", "{output}.cms",
292        "-signer", catfile($smdir, "smrsa2.pem"), "-out", "{output}2.cms" ],
293      [ "{cmd2}", @prov, "-verify_receipt", "{output}2.cms", "-in", "{output}.cms",
294        "-CAfile", $smroot ]
295    ],
296
297    [ "enveloped content test streaming S/MIME format, DES, 3 recipients, keyid",
298      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
299        "-stream", "-out", "{output}.cms", "-keyid",
300        $smrsa1,
301        catfile($smdir, "smrsa2.pem"),
302        catfile($smdir, "smrsa3.pem") ],
303      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
304        "-in", "{output}.cms", "-out", "{output}.txt" ],
305      \&final_compare
306    ],
307
308    [ "enveloped content test streaming PEM format, AES-256-CBC cipher, KEK",
309      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
310        "-stream", "-out", "{output}.cms",
311        "-secretkey", "000102030405060708090A0B0C0D0E0F",
312        "-secretkeyid", "C0FEE0" ],
313      [ "{cmd2}", @prov, "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
314        "-inform", "PEM",
315        "-secretkey", "000102030405060708090A0B0C0D0E0F",
316        "-secretkeyid", "C0FEE0" ],
317      \&final_compare
318    ],
319
320    [ "enveloped content test streaming PEM format, AES-256-GCM cipher, KEK",
321      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes-128-gcm",
322        "-stream", "-out", "{output}.cms",
323        "-secretkey", "000102030405060708090A0B0C0D0E0F",
324        "-secretkeyid", "C0FEE0" ],
325      [ "{cmd2}", "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
326        "-inform", "PEM",
327        "-secretkey", "000102030405060708090A0B0C0D0E0F",
328        "-secretkeyid", "C0FEE0" ],
329      \&final_compare
330    ],
331
332    [ "enveloped content test streaming PEM format, KEK, key only",
333      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont, "-outform", "PEM", "-aes128",
334        "-stream", "-out", "{output}.cms",
335        "-secretkey", "000102030405060708090A0B0C0D0E0F",
336        "-secretkeyid", "C0FEE0" ],
337      [ "{cmd2}", @prov, "-decrypt", "-in", "{output}.cms", "-out", "{output}.txt",
338        "-inform", "PEM",
339        "-secretkey", "000102030405060708090A0B0C0D0E0F" ],
340      \&final_compare
341    ],
342
343    [ "data content test streaming PEM format",
344      [ "{cmd1}", @prov, "-data_create", "-in", $smcont, "-outform", "PEM",
345        "-nodetach", "-stream", "-out", "{output}.cms" ],
346      [ "{cmd2}", @prov, "-data_out", "-in", "{output}.cms", "-inform", "PEM",
347        "-out", "{output}.txt" ],
348      \&final_compare
349    ],
350
351    [ "encrypted content test streaming PEM format, 128 bit RC2 key",
352      [ "{cmd1}", @legacyprov, "-EncryptedData_encrypt",
353        "-in", $smcont, "-outform", "PEM",
354        "-rc2", "-secretkey", "000102030405060708090A0B0C0D0E0F",
355        "-stream", "-out", "{output}.cms" ],
356      [ "{cmd2}", @legacyprov, "-EncryptedData_decrypt", "-in", "{output}.cms",
357        "-inform", "PEM",
358        "-secretkey", "000102030405060708090A0B0C0D0E0F",
359        "-out", "{output}.txt" ],
360      \&final_compare
361    ],
362
363    [ "encrypted content test streaming PEM format, 40 bit RC2 key",
364      [ "{cmd1}", @legacyprov, "-EncryptedData_encrypt",
365        "-in", $smcont, "-outform", "PEM",
366        "-rc2", "-secretkey", "0001020304",
367        "-stream", "-out", "{output}.cms" ],
368      [ "{cmd2}", @legacyprov, "-EncryptedData_decrypt", "-in", "{output}.cms",
369        "-inform", "PEM",
370        "-secretkey", "0001020304", "-out", "{output}.txt" ],
371      \&final_compare
372    ],
373
374    [ "encrypted content test streaming PEM format, triple DES key",
375      [ "{cmd1}", @prov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
376        "-des3", "-secretkey", "000102030405060708090A0B0C0D0E0F1011121314151617",
377        "-stream", "-out", "{output}.cms" ],
378      [ "{cmd2}", @prov, "-EncryptedData_decrypt", "-in", "{output}.cms",
379        "-inform", "PEM",
380        "-secretkey", "000102030405060708090A0B0C0D0E0F1011121314151617",
381        "-out", "{output}.txt" ],
382      \&final_compare
383    ],
384
385    [ "encrypted content test streaming PEM format, 128 bit AES key",
386      [ "{cmd1}", @prov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
387        "-aes128", "-secretkey", "000102030405060708090A0B0C0D0E0F",
388        "-stream", "-out", "{output}.cms" ],
389      [ "{cmd2}", @prov, "-EncryptedData_decrypt", "-in", "{output}.cms",
390        "-inform", "PEM",
391        "-secretkey", "000102030405060708090A0B0C0D0E0F",
392        "-out", "{output}.txt" ],
393      \&final_compare
394    ],
395
396    [ "encrypted content test streaming PEM format -noout, 128 bit AES key",
397      [ "{cmd1}", @prov, "-EncryptedData_encrypt", "-in", $smcont, "-outform", "PEM",
398	"-aes128", "-secretkey", "000102030405060708090A0B0C0D0E0F",
399	"-stream", "-noout" ],
400      [ "{cmd2}", @prov, "-help" ]
401    ],
402);
403
404my @smime_cms_cades_tests = (
405
406    [ "signed content DER format, RSA key, CAdES-BES compatible",
407      [ "{cmd1}", @prov, "-sign", "-cades", "-in", $smcont, "-outform", "DER",
408         "-nodetach",
409        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
410      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
411        "-CAfile", $smroot, "-out", "{output}.txt" ],
412      \&final_compare
413    ],
414
415    [ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
416      [ "{cmd1}", @prov, "-sign", "-cades", "-md", "sha256", "-in", $smcont, "-outform",
417        "DER", "-nodetach", "-certfile", $smroot,
418        "-signer", $smrsa1, "-out", "{output}.cms" ],
419      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
420        "-CAfile", $smroot, "-out", "{output}.txt" ],
421      \&final_compare
422    ],
423
424    [ "signed content DER format, RSA key, SHA512 md, CAdES-BES compatible",
425      [ "{cmd1}", @prov, "-sign", "-cades", "-md", "sha512", "-in", $smcont, "-outform",
426        "DER", "-nodetach", "-certfile", $smroot,
427        "-signer", $smrsa1, "-out", "{output}.cms" ],
428      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
429        "-CAfile", $smroot, "-out", "{output}.txt" ],
430      \&final_compare
431    ],
432
433    [ "signed content DER format, RSA key, SHA256 md, CAdES-BES compatible",
434      [ "{cmd1}", @prov, "-sign", "-cades", "-binary",  "-nodetach", "-nosmimecap", "-md", "sha256",
435        "-in", $smcont, "-outform", "DER", 
436        "-certfile", $smroot, "-signer", $smrsa1,
437        "-outform", "DER", "-out", "{output}.cms"  ],
438      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
439        "-CAfile", $smroot, "-out", "{output}.txt" ],
440      \&final_compare
441    ],
442
443    [ "resigned content DER format, RSA key, SHA256 md, CAdES-BES compatible",
444      [ "{cmd1}", @prov, "-sign", "-cades", "-binary",  "-nodetach", "-nosmimecap", "-md", "sha256",
445        "-in", $smcont, "-outform", "DER", 
446        "-certfile", $smroot, "-signer", $smrsa1,
447        "-outform", "DER", "-out", "{output}.cms"  ],
448      [ "{cmd1}", @prov, "-resign", "-cades", "-binary", "-nodetach", "-nosmimecap", "-md", "sha256",
449        "-inform", "DER", "-in", "{output}.cms",
450        "-certfile", $smroot, "-signer", catfile($smdir, "smrsa2.pem"),
451        "-outform", "DER", "-out", "{output}2.cms" ],
452
453      [ "{cmd2}", @prov, "-verify", "-cades", "-in", "{output}2.cms", "-inform", "DER",
454        "-CAfile", $smroot, "-out", "{output}.txt" ],
455      \&final_compare
456    ],
457);
458
459my @smime_cms_cades_ko_tests = (
460    [ "sign content DER format, RSA key, not CAdES-BES compatible",
461      [ @prov, "-sign", "-in", $smcont, "-outform", "DER", "-nodetach",
462        "-certfile", $smroot, "-signer", $smrsa1, "-out", "{output}.cms" ],
463      "fail to verify token since requiring CAdES-BES compatibility",
464      [ @prov, "-verify", "-cades", "-in", "{output}.cms", "-inform", "DER",
465        "-CAfile", $smroot, "-out", "{output}.txt" ],
466      \&final_compare
467    ]
468);
469
470# cades options test - check that some combinations are rejected
471my @smime_cms_cades_invalid_option_tests = (
472    [
473        [ "-cades", "-noattr" ],
474    ],[
475        [ "-verify", "-cades", "-noattr" ],
476    ],[
477        [ "-verify", "-cades", "-noverify" ],
478    ],
479);
480
481my @smime_cms_comp_tests = (
482
483    [ "compressed content test streaming PEM format",
484      [ "{cmd1}", @prov, "-compress", "-in", $smcont, "-outform", "PEM", "-nodetach",
485        "-stream", "-out", "{output}.cms" ],
486      [ "{cmd2}", @prov, "-uncompress", "-in", "{output}.cms", "-inform", "PEM",
487        "-out", "{output}.txt" ],
488      \&final_compare
489    ]
490
491);
492
493my @smime_cms_param_tests = (
494    [ "signed content test streaming PEM format, RSA keys, PSS signature",
495      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
496        "-signer", $smrsa1,
497        "-keyopt", "rsa_padding_mode:pss",
498        "-out", "{output}.cms" ],
499      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
500        "-CAfile", $smroot, "-out", "{output}.txt" ],
501      \&final_compare
502    ],
503
504    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=max",
505      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
506        "-signer", $smrsa1,
507        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:max",
508        "-out", "{output}.cms" ],
509      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 222; },
510      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
511        "-CAfile", $smroot, "-out", "{output}.txt" ],
512      \&final_compare
513    ],
514
515    [ "signed content test streaming PEM format, RSA keys, PSS signature, no attributes",
516      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
517        "-noattr", "-signer", $smrsa1,
518        "-keyopt", "rsa_padding_mode:pss",
519        "-out", "{output}.cms" ],
520      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
521        "-CAfile", $smroot, "-out", "{output}.txt" ],
522      \&final_compare
523    ],
524
525    [ "signed content test streaming PEM format, RSA keys, PSS signature, SHA384 MGF1",
526      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
527        "-signer", $smrsa1,
528        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_mgf1_md:sha384",
529        "-out", "{output}.cms" ],
530      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
531        "-CAfile", $smroot, "-out", "{output}.txt" ],
532      \&final_compare
533    ],
534
535    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=16",
536      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
537        "-signer", $smrsa1, "-md", "sha256",
538        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:16",
539        "-out", "{output}.cms" ],
540      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 16; },
541      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
542        "-CAfile", $smroot, "-out", "{output}.txt" ],
543      \&final_compare
544    ],
545
546    [ "signed content test streaming PEM format, RSA keys, PSS signature, saltlen=digest",
547      [ "{cmd1}", @prov, "-sign", "-in", $smcont, "-outform", "PEM", "-nodetach",
548        "-signer", $smrsa1, "-md", "sha256",
549        "-keyopt", "rsa_padding_mode:pss", "-keyopt", "rsa_pss_saltlen:digest",
550        "-out", "{output}.cms" ],
551      # digest is SHA-256, which produces 32 bytes of output
552      sub { my %opts = @_; rsapssSaltlen("$opts{output}.cms") == 32; },
553      [ "{cmd2}", @prov, "-verify", "-in", "{output}.cms", "-inform", "PEM",
554        "-CAfile", $smroot, "-out", "{output}.txt" ],
555      \&final_compare
556    ],
557
558    [ "enveloped content test streaming S/MIME format, DES, OAEP default parameters",
559      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
560        "-stream", "-out", "{output}.cms",
561        "-recip", $smrsa1,
562        "-keyopt", "rsa_padding_mode:oaep" ],
563      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
564        "-in", "{output}.cms", "-out", "{output}.txt" ],
565      \&final_compare
566    ],
567
568    [ "enveloped content test streaming S/MIME format, DES, OAEP SHA256",
569      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
570        "-stream", "-out", "{output}.cms",
571        "-recip", $smrsa1,
572        "-keyopt", "rsa_padding_mode:oaep",
573        "-keyopt", "rsa_oaep_md:sha256" ],
574      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", $smrsa1,
575        "-in", "{output}.cms", "-out", "{output}.txt" ],
576      \&final_compare
577    ],
578
579    [ "enveloped content test streaming S/MIME format, DES, ECDH",
580      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
581        "-stream", "-out", "{output}.cms",
582        "-recip", catfile($smdir, "smec1.pem") ],
583      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
584        "-in", "{output}.cms", "-out", "{output}.txt" ],
585      \&final_compare
586    ],
587
588    [ "enveloped content test streaming S/MIME format, DES, ECDH, 2 recipients, key only used",
589      [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont,
590        "-stream", "-out", "{output}.cms",
591        catfile($smdir, "smec1.pem"),
592        catfile($smdir, "smec3.pem") ],
593      [ "{cmd2}", @defaultprov, "-decrypt", "-inkey", catfile($smdir, "smec3.pem"),
594        "-in", "{output}.cms", "-out", "{output}.txt" ],
595      \&final_compare
596    ],
597
598    [ "enveloped content test streaming S/MIME format, ECDH, DES, key identifier",
599      [ "{cmd1}", @defaultprov, "-encrypt", "-keyid", "-in", $smcont,
600        "-stream", "-out", "{output}.cms",
601        "-recip", catfile($smdir, "smec1.pem") ],
602      [ "{cmd2}", @defaultprov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
603        "-in", "{output}.cms", "-out", "{output}.txt" ],
604      \&final_compare
605    ],
606
607    [ "enveloped content test streaming S/MIME format, ECDH, AES-128-CBC, SHA256 KDF",
608      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
609        "-stream", "-out", "{output}.cms",
610        "-recip", catfile($smdir, "smec1.pem"), "-aes128",
611        "-keyopt", "ecdh_kdf_md:sha256" ],
612      [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
613        "-in", "{output}.cms", "-out", "{output}.txt" ],
614      \&final_compare
615    ],
616
617    [ "enveloped content test streaming S/MIME format, ECDH, AES-128-GCM cipher, SHA256 KDF",
618      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
619        "-stream", "-out", "{output}.cms",
620        "-recip", catfile($smdir, "smec1.pem"), "-aes-128-gcm", "-keyopt", "ecdh_kdf_md:sha256" ],
621      [ "{cmd2}", "-decrypt", "-recip", catfile($smdir, "smec1.pem"),
622        "-in", "{output}.cms", "-out", "{output}.txt" ],
623      \&final_compare
624    ],
625
626    [ "enveloped content test streaming S/MIME format, ECDH, K-283, cofactor DH",
627      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
628        "-stream", "-out", "{output}.cms",
629        "-recip", catfile($smdir, "smec2.pem"), "-aes128",
630        "-keyopt", "ecdh_kdf_md:sha256", "-keyopt", "ecdh_cofactor_mode:1" ],
631      [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smec2.pem"),
632        "-in", "{output}.cms", "-out", "{output}.txt" ],
633      \&final_compare
634    ],
635
636    [ "enveloped content test streaming S/MIME format, X9.42 DH",
637      [ "{cmd1}", @prov, "-encrypt", "-in", $smcont,
638        "-stream", "-out", "{output}.cms",
639        "-recip", catfile($smdir, "smdh.pem"), "-aes128" ],
640      [ "{cmd2}", @prov, "-decrypt", "-recip", catfile($smdir, "smdh.pem"),
641        "-in", "{output}.cms", "-out", "{output}.txt" ],
642      \&final_compare
643    ]
644);
645
646my @contenttype_cms_test = (
647    [ "signed content test - check that content type is added to additional signerinfo, RSA keys",
648      [ "{cmd1}", @prov, "-sign", "-binary", "-nodetach", "-stream", "-in", $smcont,
649        "-outform", "DER", "-signer", $smrsa1, "-md", "SHA256",
650        "-out", "{output}.cms" ],
651      [ "{cmd1}", @prov, "-resign", "-binary", "-nodetach", "-in", "{output}.cms",
652        "-inform", "DER", "-outform", "DER",
653        "-signer", catfile($smdir, "smrsa2.pem"), "-md", "SHA256",
654        "-out", "{output}2.cms" ],
655      sub { my %opts = @_; contentType_matches("$opts{output}2.cms") == 2; },
656      [ "{cmd2}", @prov, "-verify", "-in", "{output}2.cms", "-inform", "DER",
657        "-CAfile", $smroot, "-out", "{output}.txt" ]
658    ],
659);
660
661my @incorrect_attribute_cms_test = (
662    "bad_signtime_attr.cms",
663    "no_ct_attr.cms",
664    "no_md_attr.cms",
665    "ct_multiple_attr.cms"
666);
667
668# Runs a standard loop on the input array
669sub runner_loop {
670    my %opts = ( @_ );
671    my $cnt1 = 0;
672
673    foreach (@{$opts{tests}}) {
674        $cnt1++;
675        $opts{output} = "$opts{prefix}-$cnt1";
676      SKIP: {
677          my $skip_reason = check_availability($$_[0]);
678          skip $skip_reason, 1 if $skip_reason;
679          my $ok = 1;
680          1 while unlink "$opts{output}.txt";
681
682          foreach (@$_[1..$#$_]) {
683              if (ref $_ eq 'CODE') {
684                  $ok &&= $_->(%opts);
685              } else {
686                  my @cmd = map {
687                      my $x = $_;
688                      while ($x =~ /\{([^\}]+)\}/) {
689                          $x = $`.$opts{$1}.$' if exists $opts{$1};
690                      }
691                      $x;
692                  } @$_;
693
694                  diag "CMD: openssl ", join(" ", @cmd);
695                  $ok &&= run(app(["openssl", @cmd]));
696                  $opts{input} = $opts{output};
697              }
698          }
699
700          ok($ok, $$_[0]);
701        }
702    }
703}
704
705sub final_compare {
706    my %opts = @_;
707
708    diag "Comparing $smcont with $opts{output}.txt";
709    return compare_text($smcont, "$opts{output}.txt") == 0;
710}
711
712sub zero_compare {
713    my %opts = @_;
714
715    diag "Checking for zero-length file";
716    return (-e "$opts{output}.txt" && -z "$opts{output}.txt");
717}
718
719subtest "CMS => PKCS#7 compatibility tests\n" => sub {
720    plan tests => scalar @smime_pkcs7_tests;
721
722    runner_loop(prefix => 'cms2pkcs7', cmd1 => 'cms', cmd2 => 'smime',
723                tests => [ @smime_pkcs7_tests ]);
724};
725subtest "CMS <= PKCS#7 compatibility tests\n" => sub {
726    plan tests => scalar @smime_pkcs7_tests;
727
728    runner_loop(prefix => 'pkcs72cms', cmd1 => 'smime', cmd2 => 'cms',
729                tests => [ @smime_pkcs7_tests ]);
730};
731
732subtest "CMS <=> CMS consistency tests\n" => sub {
733    plan tests => (scalar @smime_pkcs7_tests) + (scalar @smime_cms_tests);
734
735    runner_loop(prefix => 'cms2cms-1', cmd1 => 'cms', cmd2 => 'cms',
736                tests => [ @smime_pkcs7_tests ]);
737    runner_loop(prefix => 'cms2cms-2', cmd1 => 'cms', cmd2 => 'cms',
738                tests => [ @smime_cms_tests ]);
739};
740
741subtest "CMS <=> CMS consistency tests, modified key parameters\n" => sub {
742    plan tests =>
743        (scalar @smime_cms_param_tests) + (scalar @smime_cms_comp_tests);
744
745    runner_loop(prefix => 'cms2cms-mod', cmd1 => 'cms', cmd2 => 'cms',
746                tests => [ @smime_cms_param_tests ]);
747  SKIP: {
748      skip("Zlib not supported: compression tests skipped",
749           scalar @smime_cms_comp_tests)
750          if $no_zlib;
751
752      runner_loop(prefix => 'cms2cms-comp', cmd1 => 'cms', cmd2 => 'cms',
753                  tests => [ @smime_cms_comp_tests ]);
754    }
755};
756
757# Returns the number of matches of a Content Type Attribute in a binary file.
758sub contentType_matches {
759  # Read in a binary file
760  my ($in) = @_;
761  open (HEX_IN, "$in") or die("open failed for $in : $!");
762  binmode(HEX_IN);
763  local $/;
764  my $str = <HEX_IN>;
765
766  # Find ASN1 data for a Content Type Attribute (with a OID of PKCS7 data)
767  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;
768
769  close(HEX_IN);
770  return scalar(@c);
771}
772
773sub rsapssSaltlen {
774  my ($in) = @_;
775  my $exit = 0;
776
777  my @asn1parse = run(app(["openssl", "asn1parse", "-in", $in, "-dump"]),
778                      capture => 1,
779                      statusvar => $exit);
780  return -1 if $exit != 0;
781
782  my $pssparam_offset = -1;
783  while ($_ = shift @asn1parse) {
784    chomp;
785    next unless /:rsassaPss/;
786    # This line contains :rsassaPss, the next line contains a raw dump of the
787    # RSA_PSS_PARAMS sequence; obtain its offset
788    $_ = shift @asn1parse;
789    if (/^\s*(\d+):/) {
790      $pssparam_offset = int($1);
791    }
792  }
793
794  if ($pssparam_offset == -1) {
795    note "Failed to determine RSA_PSS_PARAM offset in CMS. " +
796         "Was the file correctly signed with RSASSA-PSS?";
797    return -1;
798  }
799
800  my @pssparam = run(app(["openssl", "asn1parse", "-in", $in,
801                          "-strparse", $pssparam_offset]),
802                     capture => 1,
803                     statusvar => $exit);
804  return -1 if $exit != 0;
805
806  my $saltlen = -1;
807  # Can't use asn1parse -item RSA_PSS_PARAMS here, because that's deprecated.
808  # This assumes the salt length is the last field, which may possibly be
809  # incorrect if there is a non-standard trailer field, but there almost never
810  # is in PSS.
811  if ($pssparam[-1] =~ /prim:\s+INTEGER\s+:([A-Fa-f0-9]+)/) {
812    $saltlen = hex($1);
813  }
814
815  if ($saltlen == -1) {
816    note "Failed to determine salt length from RSA_PSS_PARAM struct. " +
817         "Was the file correctly signed with RSASSA-PSS?";
818    return -1;
819  }
820
821  return $saltlen;
822}
823
824subtest "CMS Check the content type attribute is added for additional signers\n" => sub {
825    plan tests => (scalar @contenttype_cms_test);
826
827    runner_loop(prefix => 'cms2cms-added', cmd1 => 'cms', cmd2 => 'cms',
828                tests => [ @contenttype_cms_test ]);
829};
830
831subtest "CMS Check that bad attributes fail when verifying signers\n" => sub {
832    plan tests =>
833        (scalar @incorrect_attribute_cms_test);
834
835    my $cnt = 0;
836    foreach my $name (@incorrect_attribute_cms_test) {
837        my $out = "incorrect-$cnt.txt";
838
839        ok(!run(app(["openssl", "cms", @prov, "-verify", "-in",
840                     catfile($datadir, $name), "-inform", "DER", "-CAfile",
841                     $smroot, "-out", $out ])),
842            $name);
843    }
844};
845
846subtest "CMS Check that bad encryption algorithm fails\n" => sub {
847    plan tests => 1;
848
849    SKIP: {
850        skip "DES or Legacy isn't supported in this build", 1
851            if disabled("des") || disabled("legacy");
852
853        my $out = "smtst.txt";
854
855        ok(!run(app(["openssl", "cms", @legacyprov, "-encrypt",
856                    "-in", $smcont,
857                    "-stream", "-recip", $smrsa1,
858                    "-des-ede3",
859                    "-out", $out ])),
860           "Decrypt message from OpenSSL 1.1.1");
861    }
862};
863
864subtest "CMS Decrypt message encrypted with OpenSSL 1.1.1\n" => sub {
865    plan tests => 1;
866
867    SKIP: {
868        skip "EC or DES isn't supported in this build", 1
869            if disabled("ec") || disabled("des");
870
871        my $out = "smtst.txt";
872
873        ok(run(app(["openssl", "cms", @defaultprov, "-decrypt",
874                    "-inkey", catfile($smdir, "smec3.pem"),
875                    "-in", catfile($datadir, "ciphertext_from_1_1_1.cms"),
876                    "-out", $out ]))
877           && compare_text($smcont, $out) == 0,
878           "Decrypt message from OpenSSL 1.1.1");
879    }
880};
881
882subtest "CAdES <=> CAdES consistency tests\n" => sub {
883    plan tests => (scalar @smime_cms_cades_tests);
884
885    runner_loop(prefix => 'cms-cades', cmd1 => 'cms', cmd2 => 'cms',
886                tests => [ @smime_cms_cades_tests ]);
887};
888
889subtest "CAdES; cms incompatible arguments tests\n" => sub {
890    plan tests => (scalar @smime_cms_cades_invalid_option_tests);
891
892    foreach (@smime_cms_cades_invalid_option_tests) {
893        ok(!run(app(["openssl", "cms", @{$$_[0]} ] )));
894    }
895};
896
897subtest "CAdES ko tests\n" => sub {
898    plan tests => 2 * scalar @smime_cms_cades_ko_tests;
899
900    foreach (@smime_cms_cades_ko_tests) {
901      SKIP: {
902        my $skip_reason = check_availability($$_[0]);
903        skip $skip_reason, 1 if $skip_reason;
904
905        ok(run(app(["openssl", "cms", @{$$_[1]}])), $$_[0]);
906        ok(!run(app(["openssl", "cms", @{$$_[3]}])), $$_[2]);
907        }
908    }
909};
910
911subtest "CMS binary input tests\n" => sub {
912    my $input = srctop_file("test", "smcont.bin");
913    my $signed = "smcont.signed";
914    my $verified = "smcont.verified";
915
916    plan tests => 11;
917
918    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-signer", $smrsa1,
919                "-binary", "-in", $input, "-out", $signed])),
920       "sign binary input with -binary");
921    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $smroot,
922                "-binary", "-in", $signed, "-out", $verified])),
923       "verify binary input with -binary");
924    is(compare($input, $verified), 0, "binary input retained with -binary");
925
926    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-signer", $smrsa1,
927                "-in", $input, "-out", $signed.".nobin"])),
928       "sign binary input without -binary");
929    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $smroot,
930                "-in", $signed.".nobin", "-out", $verified.".nobin"])),
931       "verify binary input without -binary");
932    is(compare($input, $verified.".nobin"), 1, "binary input not retained without -binary");
933    ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $smroot, "-crlfeol",
934                "-binary", "-in", $signed, "-out", $verified.".crlfeol"])),
935       "verify binary input wrong crlfeol");
936
937    ok(run(app(["openssl", "cms", "-sign", "-md", "sha256", "-signer", $smrsa1,
938                "-crlfeol",
939                "-binary", "-in", $input, "-out", $signed.".crlf"])),
940       "sign binary input with -binary -crlfeol");
941    ok(run(app(["openssl", "cms", "-verify", "-CAfile", $smroot, "-crlfeol",
942                "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf"])),
943       "verify binary input with -binary -crlfeol");
944    is(compare($input, $verified.".crlf"), 0,
945       "binary input retained with -binary -crlfeol");
946    ok(!run(app(["openssl", "cms", "-verify", "-CAfile", $smroot,
947                "-binary", "-in", $signed.".crlf", "-out", $verified.".crlf2"])),
948       "verify binary input with -binary missing -crlfeol");
949};
950
951# Test case for missing MD algorithm (must not segfault)
952
953with({ exit_checker => sub { return shift == 4; } },
954    sub {
955        ok(run(app(['openssl', 'smime', '-verify', '-noverify',
956                    '-inform', 'PEM',
957                    '-in', data_file("pkcs7-md4.pem"),
958                   ])),
959            "Check failure of EVP_DigestInit is handled correctly");
960    });
961
962sub check_availability {
963    my $tnam = shift;
964
965    return "$tnam: skipped, EC disabled\n"
966        if ($no_ec && $tnam =~ /ECDH/);
967    return "$tnam: skipped, ECDH disabled\n"
968        if ($no_ec && $tnam =~ /ECDH/);
969    return "$tnam: skipped, EC2M disabled\n"
970        if ($no_ec2m && $tnam =~ /K-283/);
971    return "$tnam: skipped, DH disabled\n"
972        if ($no_dh && $tnam =~ /X9\.42/);
973    return "$tnam: skipped, RC2 disabled\n"
974        if ($no_rc2 && $tnam =~ /RC2/);
975    return "$tnam: skipped, DES disabled\n"
976        if ($no_des && $tnam =~ /DES/);
977    return "$tnam: skipped, DSA disabled\n"
978        if ($no_dsa && $tnam =~ / DSA/);
979
980    return "";
981}
982
983# Test case for the locking problem reported in #19643.
984# This will fail if the fix is in and deadlock on Windows (and possibly
985# other platforms) if not.
986ok(!run(app(['openssl', 'cms', '-verify',
987             '-CAfile', srctop_file("test/certs", "pkitsta.pem"),
988             '-policy', 'anyPolicy',
989             '-in', srctop_file("test/smime-eml",
990                                "SignedInvalidMappingFromanyPolicyTest7.eml")
991            ])),
992   "issue#19643");
993
994# Check that we get the expected failure return code
995with({ exit_checker => sub { return shift == 6; } },
996    sub {
997        ok(run(app(['openssl', 'cms', '-encrypt',
998                    '-in', srctop_file("test", "smcont.txt"),
999                    '-aes128', '-stream', '-recip',
1000                    srctop_file("test/smime-certs", "badrsa.pem"),
1001                   ])),
1002            "Check failure during BIO setup with -stream is handled correctly");
1003    });
1004