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