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