1#! /usr/bin/env perl 2# Copyright 2015-2024 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 OpenSSL::Test::Utils; 14use OpenSSL::Test qw/:DEFAULT srctop_file/; 15 16setup("test_req"); 17 18plan tests => 50; 19 20require_ok(srctop_file('test', 'recipes', 'tconversion.pl')); 21 22my @certs = qw(test certs); 23 24# What type of key to generate? 25my @req_new; 26if (disabled("rsa")) { 27 @req_new = ("-newkey", "dsa:".srctop_file("apps", "dsa512.pem")); 28} else { 29 @req_new = ("-new"); 30 note("There should be a 2 sequences of .'s and some +'s."); 31 note("There should not be more that at most 80 per line"); 32} 33 34# Prevent MSys2 filename munging for arguments that look like file paths but 35# aren't 36$ENV{MSYS2_ARG_CONV_EXCL} = "/CN="; 37 38# Check for duplicate -addext parameters, and one "working" case. 39my @addext_args = ( "openssl", "req", "-new", "-out", "testreq.pem", 40 "-key", srctop_file("test", "certs", "ee-key.pem"), 41 "-config", srctop_file("test", "test.cnf"), @req_new ); 42my $val = "subjectAltName=DNS:example.com"; 43my $val1 = "subjectAltName=otherName:1.2.3.4;UTF8:test,email:info\@example.com"; 44my $val2 = " " . $val; 45my $val3 = $val; 46$val3 =~ s/=/ =/; 47ok( run(app([@addext_args, "-addext", $val]))); 48ok( run(app([@addext_args, "-addext", $val1]))); 49$val1 =~ s/UTF8/XXXX/; # execute the error handling in do_othername 50ok(!run(app([@addext_args, "-addext", $val1]))); 51ok(!run(app([@addext_args, "-addext", $val, "-addext", $val]))); 52ok(!run(app([@addext_args, "-addext", $val, "-addext", $val2]))); 53ok(!run(app([@addext_args, "-addext", $val, "-addext", $val3]))); 54ok(!run(app([@addext_args, "-addext", $val2, "-addext", $val3]))); 55ok(run(app([@addext_args, "-addext", "SXNetID=1:one, 2:two, 3:three"]))); 56ok(run(app([@addext_args, "-addext", "subjectAltName=dirName:dirname_sec"]))); 57 58# If a CSR is provided with neither of -key or -CA/-CAkey, this should fail. 59ok(!run(app(["openssl", "req", "-x509", 60 "-in", srctop_file(@certs, "x509-check.csr"), 61 "-out", "testreq.pem"]))); 62 63subtest "generating alt certificate requests with RSA" => sub { 64 plan tests => 3; 65 66 SKIP: { 67 skip "RSA is not supported by this OpenSSL build", 2 68 if disabled("rsa"); 69 70 ok(run(app(["openssl", "req", 71 "-config", srctop_file("test", "test.cnf"), 72 "-section", "altreq", 73 "-new", "-out", "testreq-rsa.pem", "-utf8", 74 "-key", srctop_file("test", "testrsa.pem")])), 75 "Generating request"); 76 77 ok(run(app(["openssl", "req", 78 "-config", srctop_file("test", "test.cnf"), 79 "-verify", "-in", "testreq-rsa.pem", "-noout"])), 80 "Verifying signature on request"); 81 82 ok(run(app(["openssl", "req", 83 "-config", srctop_file("test", "test.cnf"), 84 "-section", "altreq", 85 "-verify", "-in", "testreq-rsa.pem", "-noout"])), 86 "Verifying signature on request"); 87 } 88}; 89 90 91subtest "generating certificate requests with RSA" => sub { 92 plan tests => 8; 93 94 SKIP: { 95 skip "RSA is not supported by this OpenSSL build", 2 96 if disabled("rsa"); 97 98 ok(!run(app(["openssl", "req", 99 "-config", srctop_file("test", "test.cnf"), 100 "-new", "-out", "testreq-rsa.pem", "-utf8", 101 "-key", srctop_file("test", "testrsa.pem"), 102 "-keyform", "DER"])), 103 "Checking that mismatching keyform fails"); 104 105 ok(run(app(["openssl", "req", 106 "-config", srctop_file("test", "test.cnf"), 107 "-new", "-out", "testreq-rsa.pem", "-utf8", 108 "-key", srctop_file("test", "testrsa.pem"), 109 "-keyform", "PEM"])), 110 "Generating request"); 111 112 ok(run(app(["openssl", "req", 113 "-config", srctop_file("test", "test.cnf"), 114 "-verify", "-in", "testreq-rsa.pem", "-noout"])), 115 "Verifying signature on request"); 116 117 ok(run(app(["openssl", "req", 118 "-config", srctop_file("test", "test.cnf"), 119 "-modulus", "-in", "testreq-rsa.pem", "-noout"])), 120 "Printing a modulus of the request key"); 121 122 ok(run(app(["openssl", "req", 123 "-config", srctop_file("test", "test.cnf"), 124 "-new", "-out", "testreq_withattrs_pem.pem", "-utf8", 125 "-key", srctop_file("test", "testrsa_withattrs.pem")])), 126 "Generating request from a key with extra attributes - PEM"); 127 128 ok(run(app(["openssl", "req", 129 "-config", srctop_file("test", "test.cnf"), 130 "-verify", "-in", "testreq_withattrs_pem.pem", "-noout"])), 131 "Verifying signature on request from a key with extra attributes - PEM"); 132 133 ok(run(app(["openssl", "req", 134 "-config", srctop_file("test", "test.cnf"), 135 "-new", "-out", "testreq_withattrs_der.pem", "-utf8", 136 "-key", srctop_file("test", "testrsa_withattrs.der"), 137 "-keyform", "DER"])), 138 "Generating request from a key with extra attributes - PEM"); 139 140 ok(run(app(["openssl", "req", 141 "-config", srctop_file("test", "test.cnf"), 142 "-verify", "-in", "testreq_withattrs_der.pem", "-noout"])), 143 "Verifying signature on request from a key with extra attributes - PEM"); 144 } 145}; 146 147subtest "generating certificate requests with RSA-PSS" => sub { 148 plan tests => 12; 149 150 SKIP: { 151 skip "RSA is not supported by this OpenSSL build", 2 152 if disabled("rsa"); 153 154 ok(run(app(["openssl", "req", 155 "-config", srctop_file("test", "test.cnf"), 156 "-new", "-out", "testreq-rsapss.pem", "-utf8", 157 "-key", srctop_file("test", "testrsapss.pem")])), 158 "Generating request"); 159 ok(run(app(["openssl", "req", 160 "-config", srctop_file("test", "test.cnf"), 161 "-verify", "-in", "testreq-rsapss.pem", "-noout"])), 162 "Verifying signature on request"); 163 164 ok(run(app(["openssl", "req", 165 "-config", srctop_file("test", "test.cnf"), 166 "-new", "-out", "testreq-rsapss2.pem", "-utf8", 167 "-sigopt", "rsa_padding_mode:pss", 168 "-sigopt", "rsa_pss_saltlen:-1", 169 "-key", srctop_file("test", "testrsapss.pem")])), 170 "Generating request"); 171 ok(run(app(["openssl", "req", 172 "-config", srctop_file("test", "test.cnf"), 173 "-verify", "-in", "testreq-rsapss2.pem", "-noout"])), 174 "Verifying signature on request"); 175 176 ok(run(app(["openssl", "req", 177 "-config", srctop_file("test", "test.cnf"), 178 "-new", "-out", "testreq-rsapssmand.pem", "-utf8", 179 "-sigopt", "rsa_padding_mode:pss", 180 "-key", srctop_file("test", "testrsapssmandatory.pem")])), 181 "Generating request"); 182 ok(run(app(["openssl", "req", 183 "-config", srctop_file("test", "test.cnf"), 184 "-verify", "-in", "testreq-rsapssmand.pem", "-noout"])), 185 "Verifying signature on request"); 186 187 ok(run(app(["openssl", "req", 188 "-config", srctop_file("test", "test.cnf"), 189 "-new", "-out", "testreq-rsapssmand2.pem", "-utf8", 190 "-sigopt", "rsa_pss_saltlen:100", 191 "-key", srctop_file("test", "testrsapssmandatory.pem")])), 192 "Generating request"); 193 ok(run(app(["openssl", "req", 194 "-config", srctop_file("test", "test.cnf"), 195 "-verify", "-in", "testreq-rsapssmand2.pem", "-noout"])), 196 "Verifying signature on request"); 197 198 ok(!run(app(["openssl", "req", 199 "-config", srctop_file("test", "test.cnf"), 200 "-new", "-out", "testreq-rsapss3.pem", "-utf8", 201 "-sigopt", "rsa_padding_mode:pkcs1", 202 "-key", srctop_file("test", "testrsapss.pem")])), 203 "Generating request with expected failure"); 204 205 ok(!run(app(["openssl", "req", 206 "-config", srctop_file("test", "test.cnf"), 207 "-new", "-out", "testreq-rsapss3.pem", "-utf8", 208 "-sigopt", "rsa_pss_saltlen:-4", 209 "-key", srctop_file("test", "testrsapss.pem")])), 210 "Generating request with expected failure"); 211 212 ok(!run(app(["openssl", "req", 213 "-config", srctop_file("test", "test.cnf"), 214 "-new", "-out", "testreq-rsapssmand3.pem", "-utf8", 215 "-sigopt", "rsa_pss_saltlen:10", 216 "-key", srctop_file("test", "testrsapssmandatory.pem")])), 217 "Generating request with expected failure"); 218 219 ok(!run(app(["openssl", "req", 220 "-config", srctop_file("test", "test.cnf"), 221 "-new", "-out", "testreq-rsapssmand3.pem", "-utf8", 222 "-sha256", 223 "-key", srctop_file("test", "testrsapssmandatory.pem")])), 224 "Generating request with expected failure"); 225 } 226}; 227 228subtest "generating certificate requests with DSA" => sub { 229 plan tests => 2; 230 231 SKIP: { 232 skip "DSA is not supported by this OpenSSL build", 2 233 if disabled("dsa"); 234 235 ok(run(app(["openssl", "req", 236 "-config", srctop_file("test", "test.cnf"), 237 "-new", "-out", "testreq-dsa.pem", "-utf8", 238 "-key", srctop_file("test", "testdsa.pem")])), 239 "Generating request"); 240 241 ok(run(app(["openssl", "req", 242 "-config", srctop_file("test", "test.cnf"), 243 "-verify", "-in", "testreq-dsa.pem", "-noout"])), 244 "Verifying signature on request"); 245 } 246}; 247 248subtest "generating certificate requests with ECDSA" => sub { 249 plan tests => 2; 250 251 SKIP: { 252 skip "ECDSA is not supported by this OpenSSL build", 2 253 if disabled("ec"); 254 255 ok(run(app(["openssl", "req", 256 "-config", srctop_file("test", "test.cnf"), 257 "-new", "-out", "testreq-ec.pem", "-utf8", 258 "-key", srctop_file("test", "testec-p256.pem")])), 259 "Generating request"); 260 261 ok(run(app(["openssl", "req", 262 "-config", srctop_file("test", "test.cnf"), 263 "-verify", "-in", "testreq-ec.pem", "-noout"])), 264 "Verifying signature on request"); 265 } 266}; 267 268subtest "generating certificate requests with Ed25519" => sub { 269 plan tests => 2; 270 271 SKIP: { 272 skip "Ed25519 is not supported by this OpenSSL build", 2 273 if disabled("ec"); 274 275 ok(run(app(["openssl", "req", 276 "-config", srctop_file("test", "test.cnf"), 277 "-new", "-out", "testreq-ed25519.pem", "-utf8", 278 "-key", srctop_file("test", "tested25519.pem")])), 279 "Generating request"); 280 281 ok(run(app(["openssl", "req", 282 "-config", srctop_file("test", "test.cnf"), 283 "-verify", "-in", "testreq-ed25519.pem", "-noout"])), 284 "Verifying signature on request"); 285 } 286}; 287 288subtest "generating certificate requests with Ed448" => sub { 289 plan tests => 2; 290 291 SKIP: { 292 skip "Ed448 is not supported by this OpenSSL build", 2 293 if disabled("ec"); 294 295 ok(run(app(["openssl", "req", 296 "-config", srctop_file("test", "test.cnf"), 297 "-new", "-out", "testreq-ed448.pem", "-utf8", 298 "-key", srctop_file("test", "tested448.pem")])), 299 "Generating request"); 300 301 ok(run(app(["openssl", "req", 302 "-config", srctop_file("test", "test.cnf"), 303 "-verify", "-in", "testreq-ed448.pem", "-noout"])), 304 "Verifying signature on request"); 305 } 306}; 307 308subtest "generating certificate requests" => sub { 309 plan tests => 2; 310 311 ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), 312 "-key", srctop_file("test", "certs", "ee-key.pem"), 313 @req_new, "-out", "testreq.pem"])), 314 "Generating request"); 315 316 ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"), 317 "-verify", "-in", "testreq.pem", "-noout"])), 318 "Verifying signature on request"); 319}; 320 321subtest "generating SM2 certificate requests" => sub { 322 plan tests => 4; 323 324 SKIP: { 325 skip "SM2 is not supported by this OpenSSL build", 4 326 if disabled("sm2"); 327 ok(run(app(["openssl", "req", 328 "-config", srctop_file("test", "test.cnf"), 329 "-new", "-key", srctop_file(@certs, "sm2.key"), 330 "-sigopt", "distid:1234567812345678", 331 "-out", "testreq-sm2.pem", "-sm3"])), 332 "Generating SM2 certificate request"); 333 334 ok(run(app(["openssl", "req", 335 "-config", srctop_file("test", "test.cnf"), 336 "-verify", "-in", "testreq-sm2.pem", "-noout", 337 "-vfyopt", "distid:1234567812345678", "-sm3"])), 338 "Verifying signature on SM2 certificate request"); 339 340 ok(run(app(["openssl", "req", 341 "-config", srctop_file("test", "test.cnf"), 342 "-new", "-key", srctop_file(@certs, "sm2.key"), 343 "-sigopt", "hexdistid:DEADBEEF", 344 "-out", "testreq-sm2.pem", "-sm3"])), 345 "Generating SM2 certificate request with hex id"); 346 347 ok(run(app(["openssl", "req", 348 "-config", srctop_file("test", "test.cnf"), 349 "-verify", "-in", "testreq-sm2.pem", "-noout", 350 "-vfyopt", "hexdistid:DEADBEEF", "-sm3"])), 351 "Verifying signature on SM2 certificate request"); 352 } 353}; 354 355my @openssl_args = ("req", "-config", srctop_file("apps", "openssl.cnf")); 356 357run_conversion('req conversions', 358 "testreq.pem"); 359run_conversion('req conversions -- testreq2', 360 srctop_file("test", "testreq2.pem")); 361 362sub run_conversion { 363 my $title = shift; 364 my $reqfile = shift; 365 366 subtest $title => sub { 367 run(app(["openssl", @openssl_args, 368 "-in", $reqfile, "-inform", "p", 369 "-noout", "-text"], 370 stderr => "req-check.err", stdout => undef)); 371 open DATA, "req-check.err"; 372 SKIP: { 373 plan skip_all => "skipping req conversion test for $reqfile" 374 if grep /Unknown Public Key/, map { s/\R//; } <DATA>; 375 376 tconversion( -type => 'req', -in => $reqfile, 377 -args => [ @openssl_args ] ); 378 } 379 close DATA; 380 unlink "req-check.err"; 381 382 done_testing(); 383 }; 384} 385 386# Test both generation and verification of certs w.r.t. RFC 5280 requirements 387 388my $ca_cert; # will be set below 389sub generate_cert { 390 my $cert = shift @_; 391 my $ss = $cert =~ m/self-signed/; 392 my $is_ca = $cert =~ m/CA/; 393 my $cn = $is_ca ? "CA" : "EE"; 394 my $ca_key = srctop_file(@certs, "ca-key.pem"); 395 my $key = $is_ca ? $ca_key : srctop_file(@certs, "ee-key.pem"); 396 my @cmd = ("openssl", "req", "-config", "", "-x509", 397 "-subj", "/CN=$cn", @_, "-out", $cert); 398 push(@cmd, ("-key", $key)) if $ss; 399 push(@cmd, ("-CA", $ca_cert, "-CAkey", $ca_key)) unless $ss; 400 ok(run(app([@cmd])), "generate $cert"); 401} 402sub has_SKID { 403 my $cert = shift @_; 404 my $expect = shift @_; 405 cert_contains($cert, "Subject Key Identifier", $expect); 406} 407sub has_AKID { 408 my $cert = shift @_; 409 my $expect = shift @_; 410 cert_contains($cert, "Authority Key Identifier", $expect); 411} 412sub has_keyUsage { 413 my $cert = shift @_; 414 my $expect = shift @_; 415 cert_contains($cert, "Key Usage", $expect); 416} 417sub strict_verify { 418 my $cert = shift @_; 419 my $expect = shift @_; 420 my $trusted = shift @_; 421 $trusted = $cert unless $trusted; 422 ok(run(app(["openssl", "verify", "-x509_strict", "-trusted", $trusted, 423 "-partial_chain", $cert])) == $expect, 424 "strict verify allow $cert"); 425} 426 427my @v3_ca = ("-addext", "basicConstraints = critical,CA:true", 428 "-addext", "keyUsage = keyCertSign"); 429my $SKID_AKID = "subjectKeyIdentifier,authorityKeyIdentifier"; 430my $cert = "self-signed_v1_CA_no_KIDs.pem"; 431generate_cert($cert); 432cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID 433#TODO strict_verify($cert, 1); # self-signed v1 root cert should be accepted as CA 434 435$ca_cert = "self-signed_v3_CA_default_SKID.pem"; 436generate_cert($ca_cert, @v3_ca); 437has_SKID($ca_cert, 1); 438has_AKID($ca_cert, 0); 439strict_verify($ca_cert, 1); 440 441$cert = "self-signed_v3_CA_no_SKID.pem"; 442generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = none"); 443cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID 444#TODO strict_verify($cert, 0); 445 446$cert = "self-signed_v3_CA_both_KIDs.pem"; 447generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = hash", 448 "-addext", "authorityKeyIdentifier = keyid:always"); 449cert_ext_has_n_different_lines($cert, 3, $SKID_AKID); # SKID == AKID 450strict_verify($cert, 1); 451 452$cert = "self-signed_v3_EE_wrong_keyUsage.pem"; 453generate_cert($cert, "-addext", "keyUsage = keyCertSign"); 454#TODO strict_verify($cert, 1); # should be accepted because RFC 5280 does not apply 455 456$cert = "v3_EE_default_KIDs.pem"; 457generate_cert($cert, "-addext", "keyUsage = dataEncipherment", 458 "-key", srctop_file(@certs, "ee-key.pem")); 459cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID 460strict_verify($cert, 1, $ca_cert); 461 462$cert = "v3_EE_no_AKID.pem"; 463generate_cert($cert, "-addext", "authorityKeyIdentifier = none", 464 "-key", srctop_file(@certs, "ee-key.pem")); 465has_SKID($cert, 1); 466has_AKID($cert, 0); 467strict_verify($cert, 0, $ca_cert); 468 469$cert = "self-issued_v3_EE_default_KIDs.pem"; 470generate_cert($cert, "-addext", "keyUsage = dataEncipherment", 471 "-in", srctop_file(@certs, "x509-check.csr")); 472cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID 473strict_verify($cert, 1); 474 475my $cert = "self-signed_CA_no_keyUsage.pem"; 476generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr")); 477has_keyUsage($cert, 0); 478my $cert = "self-signed_CA_with_keyUsages.pem"; 479generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr"), 480 "-copy_extensions", "copy"); 481has_keyUsage($cert, 1); 482 483# Generate cert using req with '-modulus' 484ok(run(app(["openssl", "req", "-x509", "-new", "-days", "365", 485 "-key", srctop_file("test", "testrsa.pem"), 486 "-config", srctop_file('test', 'test.cnf'), 487 "-out", "testreq-cert.pem", 488 "-modulus"])), "cert req creation - with -modulus"); 489 490# Verify cert 491ok(run(app(["openssl", "x509", "-in", "testreq-cert.pem", 492 "-noout", "-text"])), "cert verification"); 493