Home | History | Annotate | Line # | Download | only in recipes
      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 
     10 use strict;
     11 use warnings;
     12 
     13 use OpenSSL::Test::Utils;
     14 use OpenSSL::Test qw/:DEFAULT srctop_file/;
     15 
     16 setup("test_req");
     17 
     18 plan tests => 113;
     19 
     20 require_ok(srctop_file('test', 'recipes', 'tconversion.pl'));
     21 
     22 my @certs = qw(test certs);
     23 
     24 # What type of key to generate?
     25 my @req_new;
     26 if (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.
     39 my @addext_args = ( "openssl", "req", "-new", "-out", "testreq-addexts.pem",
     40                     "-key",  srctop_file(@certs, "ee-key.pem"),
     41     "-config", srctop_file("test", "test.cnf"), @req_new );
     42 my $val = "subjectAltName=DNS:example.com";
     43 my $val1 = "subjectAltName=otherName:1.2.3.4;UTF8:test,email:info\@example.com";
     44 my $val2 = " " . $val;
     45 my $val3 = $val;
     46 $val3 =~ s/=/    =/;
     47 ok( run(app([@addext_args, "-addext", $val])));
     48 ok( run(app([@addext_args, "-addext", $val1])));
     49 $val1 =~ s/UTF8/XXXX/; # execute the error handling in do_othername
     50 ok(!run(app([@addext_args, "-addext", $val1])));
     51 ok(!run(app([@addext_args, "-addext", $val, "-addext", $val])));
     52 ok(!run(app([@addext_args, "-addext", $val, "-addext", $val2])));
     53 ok(!run(app([@addext_args, "-addext", $val, "-addext", $val3])));
     54 ok(!run(app([@addext_args, "-addext", $val2, "-addext", $val3])));
     55 ok(run(app([@addext_args, "-addext", "SXNetID=1:one, 2:two, 3:three"])));
     56 ok(run(app([@addext_args, "-addext", "subjectAltName=dirName:dirname_sec"])));
     57 
     58 ok(run(app([@addext_args, "-addext", "keyUsage=digitalSignature",
     59            "-reqexts", "reqexts"]))); # referring to section in test.cnf
     60 
     61 # If a CSR is provided with neither of -key or -CA/-CAkey, this should fail.
     62 ok(!run(app(["openssl", "req", "-x509",
     63                 "-in", srctop_file(@certs, "x509-check.csr"),
     64                 "-out", "testreq.pem"])));
     65 
     66 subtest "generating alt certificate requests with RSA" => sub {
     67     plan tests => 3;
     68 
     69     SKIP: {
     70         skip "RSA is not supported by this OpenSSL build", 2
     71             if disabled("rsa");
     72 
     73         ok(run(app(["openssl", "req",
     74                     "-config", srctop_file("test", "test.cnf"),
     75                     "-section", "altreq",
     76                     "-new", "-out", "testreq-rsa.pem", "-utf8",
     77                     "-key", srctop_file("test", "testrsa.pem")])),
     78            "Generating request");
     79 
     80         ok(run(app(["openssl", "req",
     81                     "-config", srctop_file("test", "test.cnf"),
     82                     "-verify", "-in", "testreq-rsa.pem", "-noout"])),
     83            "Verifying signature on request");
     84 
     85         ok(run(app(["openssl", "req",
     86                     "-config", srctop_file("test", "test.cnf"),
     87                     "-section", "altreq",
     88                     "-verify", "-in", "testreq-rsa.pem", "-noout"])),
     89            "Verifying signature on request");
     90     }
     91 };
     92 
     93 
     94 subtest "generating certificate requests with RSA" => sub {
     95     plan tests => 8;
     96 
     97     SKIP: {
     98         skip "RSA is not supported by this OpenSSL build", 2
     99             if disabled("rsa");
    100 
    101         ok(!run(app(["openssl", "req",
    102                      "-config", srctop_file("test", "test.cnf"),
    103                      "-new", "-out", "testreq-rsa.pem", "-utf8",
    104                      "-key", srctop_file("test", "testrsa.pem"),
    105                      "-keyform", "DER"])),
    106            "Checking that mismatching keyform fails");
    107 
    108         ok(run(app(["openssl", "req",
    109                     "-config", srctop_file("test", "test.cnf"),
    110                     "-new", "-out", "testreq-rsa.pem", "-utf8",
    111                     "-key", srctop_file("test", "testrsa.pem"),
    112                     "-keyform", "PEM"])),
    113            "Generating request");
    114 
    115         ok(run(app(["openssl", "req",
    116                     "-config", srctop_file("test", "test.cnf"),
    117                     "-verify", "-in", "testreq-rsa.pem", "-noout"])),
    118            "Verifying signature on request");
    119 
    120         ok(run(app(["openssl", "req",
    121                     "-config", srctop_file("test", "test.cnf"),
    122                     "-modulus", "-in", "testreq-rsa.pem", "-noout"])),
    123            "Printing a modulus of the request key");
    124 
    125         ok(run(app(["openssl", "req",
    126                     "-config", srctop_file("test", "test.cnf"),
    127                     "-new", "-out", "testreq_withattrs_pem.pem", "-utf8",
    128                     "-key", srctop_file("test", "testrsa_withattrs.pem")])),
    129            "Generating request from a key with extra attributes - PEM");
    130 
    131         ok(run(app(["openssl", "req",
    132                     "-config", srctop_file("test", "test.cnf"),
    133                     "-verify", "-in", "testreq_withattrs_pem.pem", "-noout"])),
    134            "Verifying signature on request from a key with extra attributes - PEM");
    135 
    136         ok(run(app(["openssl", "req",
    137                     "-config", srctop_file("test", "test.cnf"),
    138                     "-new", "-out", "testreq_withattrs_der.pem", "-utf8",
    139                     "-key", srctop_file("test", "testrsa_withattrs.der"),
    140                     "-keyform", "DER"])),
    141            "Generating request from a key with extra attributes - PEM");
    142 
    143         ok(run(app(["openssl", "req",
    144                     "-config", srctop_file("test", "test.cnf"),
    145                     "-verify", "-in", "testreq_withattrs_der.pem", "-noout"])),
    146            "Verifying signature on request from a key with extra attributes - PEM");
    147     }
    148 };
    149 
    150 subtest "generating certificate requests with RSA-PSS" => sub {
    151     plan tests => 12;
    152 
    153     SKIP: {
    154         skip "RSA is not supported by this OpenSSL build", 2
    155             if disabled("rsa");
    156 
    157         ok(run(app(["openssl", "req",
    158                     "-config", srctop_file("test", "test.cnf"),
    159                     "-new", "-out", "testreq-rsapss.pem", "-utf8",
    160                     "-key", srctop_file("test", "testrsapss.pem")])),
    161            "Generating request");
    162         ok(run(app(["openssl", "req",
    163                     "-config", srctop_file("test", "test.cnf"),
    164                     "-verify", "-in", "testreq-rsapss.pem", "-noout"])),
    165            "Verifying signature on request");
    166 
    167         ok(run(app(["openssl", "req",
    168                     "-config", srctop_file("test", "test.cnf"),
    169                     "-new", "-out", "testreq-rsapss2.pem", "-utf8",
    170                     "-sigopt", "rsa_padding_mode:pss",
    171                     "-sigopt", "rsa_pss_saltlen:-1",
    172                     "-key", srctop_file("test", "testrsapss.pem")])),
    173            "Generating request");
    174         ok(run(app(["openssl", "req",
    175                     "-config", srctop_file("test", "test.cnf"),
    176                     "-verify", "-in", "testreq-rsapss2.pem", "-noout"])),
    177            "Verifying signature on request");
    178 
    179         ok(run(app(["openssl", "req",
    180                     "-config", srctop_file("test", "test.cnf"),
    181                     "-new", "-out", "testreq-rsapssmand.pem", "-utf8",
    182                     "-sigopt", "rsa_padding_mode:pss",
    183                     "-key", srctop_file("test", "testrsapssmandatory.pem")])),
    184            "Generating request");
    185         ok(run(app(["openssl", "req",
    186                     "-config", srctop_file("test", "test.cnf"),
    187                     "-verify", "-in", "testreq-rsapssmand.pem", "-noout"])),
    188            "Verifying signature on request");
    189 
    190         ok(run(app(["openssl", "req",
    191                     "-config", srctop_file("test", "test.cnf"),
    192                     "-new", "-out", "testreq-rsapssmand2.pem", "-utf8",
    193                     "-sigopt", "rsa_pss_saltlen:100",
    194                     "-key", srctop_file("test", "testrsapssmandatory.pem")])),
    195            "Generating request");
    196         ok(run(app(["openssl", "req",
    197                     "-config", srctop_file("test", "test.cnf"),
    198                     "-verify", "-in", "testreq-rsapssmand2.pem", "-noout"])),
    199            "Verifying signature on request");
    200 
    201         ok(!run(app(["openssl", "req",
    202                      "-config", srctop_file("test", "test.cnf"),
    203                      "-new", "-out", "testreq-rsapss3.pem", "-utf8",
    204                      "-sigopt", "rsa_padding_mode:pkcs1",
    205                      "-key", srctop_file("test", "testrsapss.pem")])),
    206            "Generating request with expected failure");
    207 
    208         ok(!run(app(["openssl", "req",
    209                      "-config", srctop_file("test", "test.cnf"),
    210                      "-new", "-out", "testreq-rsapss3.pem", "-utf8",
    211                      "-sigopt", "rsa_pss_saltlen:-5",
    212                      "-key", srctop_file("test", "testrsapss.pem")])),
    213            "Generating request with expected failure");
    214 
    215         ok(!run(app(["openssl", "req",
    216                      "-config", srctop_file("test", "test.cnf"),
    217                      "-new", "-out", "testreq-rsapssmand3.pem", "-utf8",
    218                      "-sigopt", "rsa_pss_saltlen:10",
    219                      "-key", srctop_file("test", "testrsapssmandatory.pem")])),
    220            "Generating request with expected failure");
    221 
    222         ok(!run(app(["openssl", "req",
    223                      "-config", srctop_file("test", "test.cnf"),
    224                      "-new", "-out", "testreq-rsapssmand3.pem", "-utf8",
    225                      "-sha256",
    226                      "-key", srctop_file("test", "testrsapssmandatory.pem")])),
    227            "Generating request with expected failure");
    228     }
    229 };
    230 
    231 subtest "generating certificate requests with DSA" => sub {
    232     plan tests => 2;
    233 
    234     SKIP: {
    235         skip "DSA is not supported by this OpenSSL build", 2
    236             if disabled("dsa");
    237 
    238         ok(run(app(["openssl", "req",
    239                     "-config", srctop_file("test", "test.cnf"),
    240                     "-new", "-out", "testreq-dsa.pem", "-utf8",
    241                     "-key", srctop_file("test", "testdsa.pem")])),
    242            "Generating request");
    243 
    244         ok(run(app(["openssl", "req",
    245                     "-config", srctop_file("test", "test.cnf"),
    246                     "-verify", "-in", "testreq-dsa.pem", "-noout"])),
    247            "Verifying signature on request");
    248     }
    249 };
    250 
    251 subtest "generating certificate requests with ECDSA" => sub {
    252     plan tests => 2;
    253 
    254     SKIP: {
    255         skip "ECDSA is not supported by this OpenSSL build", 2
    256             if disabled("ec");
    257 
    258         ok(run(app(["openssl", "req",
    259                     "-config", srctop_file("test", "test.cnf"),
    260                     "-new", "-out", "testreq-ec.pem", "-utf8",
    261                     "-key", srctop_file("test", "testec-p256.pem")])),
    262            "Generating request");
    263 
    264         ok(run(app(["openssl", "req",
    265                     "-config", srctop_file("test", "test.cnf"),
    266                     "-verify", "-in", "testreq-ec.pem", "-noout"])),
    267            "Verifying signature on request");
    268     }
    269 };
    270 
    271 subtest "generating certificate requests with Ed25519" => sub {
    272     plan tests => 2;
    273 
    274     SKIP: {
    275         skip "Ed25519 is not supported by this OpenSSL build", 2
    276             if disabled("ecx");
    277 
    278         ok(run(app(["openssl", "req",
    279                     "-config", srctop_file("test", "test.cnf"),
    280                     "-new", "-out", "testreq-ed25519.pem", "-utf8",
    281                     "-key", srctop_file("test", "tested25519.pem")])),
    282            "Generating request");
    283 
    284         ok(run(app(["openssl", "req",
    285                     "-config", srctop_file("test", "test.cnf"),
    286                     "-verify", "-in", "testreq-ed25519.pem", "-noout"])),
    287            "Verifying signature on request");
    288     }
    289 };
    290 
    291 subtest "generating certificate requests with Ed448" => sub {
    292     plan tests => 2;
    293 
    294     SKIP: {
    295         skip "Ed448 is not supported by this OpenSSL build", 2
    296             if disabled("ecx");
    297 
    298         ok(run(app(["openssl", "req",
    299                     "-config", srctop_file("test", "test.cnf"),
    300                     "-new", "-out", "testreq-ed448.pem", "-utf8",
    301                     "-key", srctop_file("test", "tested448.pem")])),
    302            "Generating request");
    303 
    304         ok(run(app(["openssl", "req",
    305                     "-config", srctop_file("test", "test.cnf"),
    306                     "-verify", "-in", "testreq-ed448.pem", "-noout"])),
    307            "Verifying signature on request");
    308     }
    309 };
    310 
    311 subtest "generating certificate requests" => sub {
    312     plan tests => 2;
    313 
    314     ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"),
    315                 "-key", srctop_file(@certs, "ee-key.pem"),
    316                 @req_new, "-out", "testreq.pem"])),
    317        "Generating request");
    318 
    319     ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"),
    320                 "-verify", "-in", "testreq.pem", "-noout"])),
    321        "Verifying signature on request");
    322 };
    323 
    324 subtest "generating SM2 certificate requests" => sub {
    325     plan tests => 4;
    326 
    327     SKIP: {
    328         skip "SM2 is not supported by this OpenSSL build", 4
    329         if disabled("sm2");
    330         ok(run(app(["openssl", "req",
    331                     "-config", srctop_file("test", "test.cnf"),
    332                     "-new", "-key", srctop_file(@certs, "sm2.key"),
    333                     "-sigopt", "distid:1234567812345678",
    334                     "-out", "testreq-sm2.pem", "-sm3"])),
    335            "Generating SM2 certificate request");
    336 
    337         ok(run(app(["openssl", "req",
    338                     "-config", srctop_file("test", "test.cnf"),
    339                     "-verify", "-in", "testreq-sm2.pem", "-noout",
    340                     "-vfyopt", "distid:1234567812345678", "-sm3"])),
    341            "Verifying signature on SM2 certificate request");
    342 
    343         ok(run(app(["openssl", "req",
    344                     "-config", srctop_file("test", "test.cnf"),
    345                     "-new", "-key", srctop_file(@certs, "sm2.key"),
    346                     "-sigopt", "hexdistid:DEADBEEF",
    347                     "-out", "testreq-sm2.pem", "-sm3"])),
    348            "Generating SM2 certificate request with hex id");
    349 
    350         ok(run(app(["openssl", "req",
    351                     "-config", srctop_file("test", "test.cnf"),
    352                     "-verify", "-in", "testreq-sm2.pem", "-noout",
    353                     "-vfyopt", "hexdistid:DEADBEEF", "-sm3"])),
    354            "Verifying signature on SM2 certificate request");
    355     }
    356 };
    357 
    358 subtest "generating certificate requests with ML-DSA" => sub {
    359     plan tests => 5;
    360 
    361     SKIP: {
    362         skip "ML-DSA is not supported by this OpenSSL build", 5
    363             if disabled("ml-dsa");
    364 
    365         ok(run(app(["openssl", "req",
    366                     "-config", srctop_file("test", "test.cnf"),
    367                     "-x509", "-sha256", "-nodes", "-days", "365",
    368                     "-newkey", "ML-DSA-44",
    369                     "-keyout",  "privatekey_ml_dsa_44.pem",
    370                     "-out",  "cert_ml_dsa_44.pem",
    371                     "-subj", "/CN=test-self-signed",
    372                     "-addext","keyUsage=digitalSignature"])),
    373                     "Generating self signed ML-DSA-44 cert and private key");
    374         ok(run(app(["openssl", "req",
    375                     "-config", srctop_file("test", "test.cnf"),
    376                     "-x509", "-sha256", "-nodes", "-days", "365",
    377                     "-newkey", "ML-DSA-65",
    378                     "-keyout",  "privatekey_ml_dsa_65.pem",
    379                     "-out",  "cert_ml_dsa_65.pem",
    380                     "-subj", "/CN=test-self-signed",
    381                     "-addext","keyUsage=digitalSignature"])),
    382                     "Generating self signed ML-DSA-65 cert and private key");
    383         ok(run(app(["openssl", "req",
    384                     "-config", srctop_file("test", "test.cnf"),
    385                     "-x509", "-sha256", "-nodes", "-days", "365",
    386                     "-newkey", "ML-DSA-44",
    387                     "-keyout",  "privatekey_ml_dsa_87.pem",
    388                     "-out",  "cert_ml_dsa_87.pem",
    389                     "-subj", "/CN=test-self-signed",
    390                     "-addext","keyUsage=digitalSignature"])),
    391                     "Generating self signed ML-DSA-87 cert and private key");
    392         ok(run(app(["openssl", "req",
    393                     "-config", srctop_file("test", "test.cnf"),
    394                     "-new",
    395                     "-sigopt","hextest-entropy:000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
    396                     "-out", "csr_ml_dsa_87.pem",
    397                     "-newkey", "ML-DSA-87",
    398                     "-passout", "pass:x"])),
    399                     "Generating ML-DSA-87 csr");
    400         ok(run(app(["openssl", "req",
    401                     "-config", srctop_file("test", "test.cnf"),
    402                     "-in", "csr_ml_dsa_87.pem"])),
    403                     "verifying ML-DSA-87 csr");
    404     }
    405 };
    406 
    407 subtest "generating certificate requests with -cipher flag" => sub {
    408     plan tests => 6;
    409 
    410     diag("Testing -cipher flag with aes-256-cbc...");
    411     ok(run(app(["openssl", "req",
    412                 "-config", srctop_file("test", "test.cnf"),
    413                 "-newkey", "rsa:2048",
    414                 "-keyout", "privatekey-aes256.pem",
    415                 "-out", "testreq-rsa-cipher.pem",
    416                 "-utf8",
    417                 "-cipher", "aes-256-cbc",
    418                 "-passout", "pass:password"])),
    419        "Generating request with -cipher flag (AES-256-CBC)");
    420 
    421     diag("Verifying signature for aes-256-cbc...");
    422     ok(run(app(["openssl", "req",
    423                 "-config", srctop_file("test", "test.cnf"),
    424                 "-verify", "-in", "testreq-rsa-cipher.pem", "-noout"])),
    425        "Verifying signature on request with -cipher (AES-256-CBC)");
    426 
    427     open my $fh, '<', "privatekey-aes256.pem" or BAIL_OUT("Could not open key file: $!");
    428     my $first_line = <$fh>;
    429     close $fh;
    430     ok($first_line =~ /^-----BEGIN ENCRYPTED PRIVATE KEY-----/,
    431        "Check that the key file is encrypted (AES-256-CBC)");
    432 
    433     diag("Testing -cipher flag with aes-128-cbc...");
    434     ok(run(app(["openssl", "req",
    435                 "-config", srctop_file("test", "test.cnf"),
    436                 "-newkey", "rsa:2048",
    437                 "-keyout", "privatekey-aes128.pem",
    438                 "-out", "testreq-rsa-cipher-aes128.pem",
    439                 "-utf8",
    440                 "-cipher", "aes-128-cbc",
    441                 "-passout", "pass:password"])),
    442        "Generating request with -cipher flag (AES-128-CBC)");
    443 
    444     diag("Verifying signature for aes-128-cbc...");
    445     ok(run(app(["openssl", "req",
    446                 "-config", srctop_file("test", "test.cnf"),
    447                 "-verify", "-in", "testreq-rsa-cipher-aes128.pem", "-noout"])),
    448        "Verifying signature on request with -cipher (AES-128-CBC)");
    449 
    450     open my $fh_aes128, '<', "privatekey-aes128.pem" or BAIL_OUT("Could not open key file: $!");
    451     my $first_line_aes128 = <$fh_aes128>;
    452     close $fh_aes128;
    453     ok($first_line_aes128 =~ /^-----BEGIN ENCRYPTED PRIVATE KEY-----/,
    454        "Check that the key file is encrypted (AES-128-CBC)");
    455 };
    456 
    457 subtest "generating certificate requests with SLH-DSA" => sub {
    458     plan tests => 5;
    459 
    460     SKIP: {
    461         skip "SLH-DSA is not supported by this OpenSSL build", 5
    462             if disabled("slh-dsa");
    463 
    464         ok(run(app(["openssl", "req",
    465                     "-config", srctop_file("test", "test.cnf"),
    466                     "-x509", "-sha256", "-nodes", "-days", "365",
    467                     "-newkey", "SLH-DSA-SHA2-128f",
    468                     "-keyout",  "privatekey_slh_dsa_sha2_128f.pem",
    469                     "-out",  "cert_slh_dsa_sha2_128f.pem",
    470                     "-subj", "/CN=test-self-signed",
    471                     "-addext","keyUsage=digitalSignature"])),
    472                     "Generating self signed SLH-DSA-SHA2-128f cert and private key");
    473         ok(run(app(["openssl", "req",
    474                     "-config", srctop_file("test", "test.cnf"),
    475                     "-x509", "-sha256", "-nodes", "-days", "365",
    476                     "-newkey", "SLH-DSA-SHA2-256s",
    477                     "-keyout",  "privatekey_slh_dsa_sha2_256s.pem",
    478                     "-out",  "cert_slh_dsa_sha2_256s.pem",
    479                     "-subj", "/CN=test-self-signed",
    480                     "-addext","keyUsage=digitalSignature"])),
    481                     "Generating self signed SLH-DSA-SHA2-256s cert and private key");
    482         ok(run(app(["openssl", "req",
    483                     "-config", srctop_file("test", "test.cnf"),
    484                     "-x509", "-sha256", "-nodes", "-days", "365",
    485                     "-newkey", "SLH-DSA-SHAKE-256f",
    486                     "-keyout",  "privatekey_slh_dsa_shake_256f.pem",
    487                     "-out",  "cert_slh_dsa_shake_256f.pem",
    488                     "-subj", "/CN=test-self-signed",
    489                     "-addext","keyUsage=digitalSignature"])),
    490                     "Generating self signed SLH-DSA-SHAKE-256f cert and private key");
    491         ok(run(app(["openssl", "req",
    492                     "-config", srctop_file("test", "test.cnf"),
    493                     "-new",
    494                     "-sigopt","hextest-entropy:000102030405060708090a0b0c0d0e0f",
    495                     "-out", "csr_slh_dsa_shake128.pem",
    496                     "-newkey", "SLH-DSA-SHAKE-128s",
    497                     "-passout", "pass:x"])),
    498                     "Generating SLH-DSA-SHAKE-128s csr");
    499         ok(run(app(["openssl", "req",
    500                     "-config", srctop_file("test", "test.cnf"),
    501                     "-in", "csr_slh_dsa_shake128.pem"])),
    502                     "verifying SLH-DSA-SHAKE-128s csr");
    503     }
    504 };
    505 
    506 my @openssl_args = ("req", "-config", srctop_file("apps", "openssl.cnf"));
    507 
    508 run_conversion('req conversions',
    509                "testreq.pem");
    510 run_conversion('req conversions -- testreq2',
    511                srctop_file("test", "testreq2.pem"));
    512 
    513 sub run_conversion {
    514     my $title = shift;
    515     my $reqfile = shift;
    516 
    517     subtest $title => sub {
    518         run(app(["openssl", @openssl_args,
    519                  "-in", $reqfile, "-inform", "p",
    520                  "-noout", "-text"],
    521                 stderr => "req-check.err", stdout => undef));
    522         open DATA, "req-check.err";
    523         SKIP: {
    524             plan skip_all => "skipping req conversion test for $reqfile"
    525                 if grep /Unknown Public Key/, map { s/\R//; } <DATA>;
    526 
    527             tconversion( -type => 'req', -in => $reqfile,
    528                          -args => [ @openssl_args ] );
    529         }
    530         close DATA;
    531         unlink "req-check.err";
    532 
    533         done_testing();
    534     };
    535 }
    536 
    537 # Test both generation and verification of certs w.r.t. RFC 5280 requirements
    538 
    539 my $ca_cert; # will be set below
    540 sub generate_cert {
    541     my $cert = shift @_;
    542     my $ss = $cert =~ m/self-signed/;
    543     my $is_ca = $cert =~ m/CA/;
    544     my $cn = $is_ca ? "CA" : "EE";
    545     my $ca_key = srctop_file(@certs, "ca-key.pem");
    546     my $key = $is_ca ? $ca_key : srctop_file(@certs, "ee-key.pem");
    547     my @cmd = ("openssl", "req", "-config", "", "-x509",
    548                "-subj", "/CN=$cn", @_, "-out", $cert);
    549     push(@cmd, ("-key", $key)) if $ss;
    550     push(@cmd, ("-CA", $ca_cert, "-CAkey", $ca_key)) unless $ss;
    551     ok(run(app([@cmd])), "generate $cert");
    552 }
    553 
    554 sub has_keyUsage {
    555     my $cert = shift @_;
    556     my $expect = shift @_;
    557     cert_contains($cert, "Key Usage", $expect);
    558 }
    559 sub strict_verify {
    560     my $cert = shift @_;
    561     my $expect = shift @_;
    562     my $trusted = shift @_;
    563     $trusted = $cert unless $trusted;
    564     ok(run(app(["openssl", "verify", "-x509_strict", "-trusted", $trusted,
    565                 "-partial_chain", $cert])) == $expect,
    566        "strict verify allow $cert");
    567 }
    568 
    569 my @v3_ca = ("-addext", "basicConstraints = critical,CA:true",
    570              "-addext", "keyUsage = keyCertSign");
    571 my $SKID_AKID = "subjectKeyIdentifier,authorityKeyIdentifier";
    572 
    573 # # SKID
    574 
    575 my $cert = "self-signed_default_SKID_no_explicit_exts.pem";
    576 generate_cert($cert);
    577 has_version($cert, 3);
    578 has_SKID($cert, 1); # SKID added, though no explicit extensions given
    579 has_AKID($cert, 0);
    580 
    581 my $cert = "self-signed_v3_CA_hash_SKID.pem";
    582 generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = hash");
    583 has_SKID($cert, 1); # explicit hash SKID
    584 
    585 $cert = "self-signed_v3_CA_no_SKID.pem";
    586 generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = none");
    587 cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID
    588 #TODO strict_verify($cert, 0);
    589 
    590 $cert = "self-signed_v3_CA_given_SKID.pem";
    591 generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = 45");
    592 cert_contains($cert, "Subject Key Identifier: 45 ", 1); # given SKID
    593 strict_verify($cert, 1);
    594 
    595 # AKID of self-signed certs
    596 
    597 $cert = "self-signed_v1_CA_no_KIDs.pem";
    598 generate_cert($cert, "-x509v1");
    599 has_version($cert, 1);
    600 cert_ext_has_n_different_lines($cert, 0, $SKID_AKID); # no SKID and no AKID
    601 #TODO strict_verify($cert, 1); # self-signed v1 root cert should be accepted as CA
    602 
    603 $ca_cert = "self-signed_v3_CA_default_SKID.pem"; # will also be used below
    604 generate_cert($ca_cert, @v3_ca);
    605 has_SKID($ca_cert, 1); # default SKID
    606 has_AKID($ca_cert, 0); # no default AKID
    607 strict_verify($ca_cert, 1);
    608 
    609 $cert = "self-signed_v3_CA_no_AKID.pem";
    610 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = none");
    611 has_AKID($cert, 0); # forced no AKID
    612 
    613 $cert = "self-signed_v3_CA_explicit_AKID.pem";
    614 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid");
    615 has_AKID($cert, 0); # for self-signed cert, AKID suppressed and not forced
    616 
    617 $cert = "self-signed_v3_CA_forced_AKID.pem";
    618 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid:always");
    619 cert_ext_has_n_different_lines($cert, 3, $SKID_AKID); # forced AKID, AKID == SKID
    620 strict_verify($cert, 1);
    621 
    622 $cert = "self-signed_v3_CA_issuer_AKID.pem";
    623 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = issuer");
    624 has_AKID($cert, 0); # suppressed AKID since not forced
    625 
    626 $cert = "self-signed_v3_CA_forced_issuer_AKID.pem";
    627 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = issuer:always");
    628 cert_contains($cert, "Authority Key Identifier: DirName:/CN=CA serial:", 1); # forced issuer AKID
    629 
    630 $cert = "self-signed_v3_CA_nonforced_keyid_issuer_AKID.pem";
    631 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid, issuer");
    632 has_AKID($cert, 0); # AKID not present because not forced and cert self-signed
    633 
    634 $cert = "self-signed_v3_CA_keyid_forced_issuer_AKID.pem";
    635 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid, issuer:always");
    636 cert_contains($cert, "Authority Key Identifier: DirName:/CN=CA serial:", 1); # issuer AKID forced, with keyid not forced
    637 
    638 $cert = "self-signed_v3_CA_forced_keyid_issuer_AKID.pem";
    639 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid:always, issuer");
    640 has_AKID($cert, 1); # AKID with keyid forced
    641 cert_contains($cert, "Authority Key Identifier: DirName:/CN=CA serial:", 0); # no issuer AKID
    642 
    643 $cert = "self-signed_v3_CA_forced_keyid_forced_issuer_AKID.pem";
    644 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = keyid:always, issuer:always");
    645 cert_contains($cert, "Authority Key Identifier: keyid(:[0-9A-Fa-f]{2})+ DirName:/CN=CA serial:", 1); # AKID with keyid and issuer forced
    646 
    647 $cert = "self-signed_v3_EE_wrong_keyUsage.pem";
    648 generate_cert($cert, "-addext", "keyUsage = keyCertSign");
    649 #TODO strict_verify($cert, 1); # should be accepted because RFC 5280 does not apply
    650 
    651 # AKID of self-issued but not self-signed certs
    652 
    653 $cert = "self-issued_x509_v3_CA_default_KIDs.pem";
    654 ok(run(app([("openssl", "x509", "-copy_extensions", "copy",
    655              "-req", "-in", srctop_file(@certs, "ext-check.csr"),
    656              "-key", srctop_file(@certs, "ca-key.pem"),
    657              "-force_pubkey", srctop_file("test", "testrsapub.pem"),
    658              "-out", $cert)])), "generate using x509: $cert");
    659 cert_contains($cert, "Issuer: CN=test .*? Subject: CN=test", 1);
    660 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    661 strict_verify($cert, 1);
    662 
    663 $cert = "self-issued_v3_CA_default_KIDs.pem";
    664 generate_cert($cert, "-addext", "keyUsage = dataEncipherment",
    665     "-in", srctop_file(@certs, "x509-check.csr"));
    666 cert_contains($cert, "Issuer: CN=CA .*? Subject: CN=CA", 1);
    667 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    668 strict_verify($cert, 1);
    669 
    670 $cert = "self-issued_v3_CA_no_AKID.pem";
    671 generate_cert($cert, "-addext", "authorityKeyIdentifier = none",
    672     "-in", srctop_file(@certs, "x509-check.csr"));
    673 has_version($cert, 3);
    674 has_SKID($cert, 1); # SKID added, though no explicit extensions given
    675 has_AKID($cert, 0);
    676 strict_verify($cert, 1);
    677 
    678 $cert = "self-issued_v3_CA_explicit_AKID.pem";
    679 generate_cert($cert, "-addext", "authorityKeyIdentifier = keyid",
    680     "-in", srctop_file(@certs, "x509-check.csr"));
    681 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    682 strict_verify($cert, 1);
    683 
    684 $cert = "self-issued_v3_CA_forced_AKID.pem";
    685 generate_cert($cert, "-addext", "authorityKeyIdentifier = keyid:always",
    686     "-in", srctop_file(@certs, "x509-check.csr"));
    687 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    688 
    689 $cert = "self-issued_v3_CA_issuer_AKID.pem";
    690 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = issuer",
    691     "-in", srctop_file(@certs, "x509-check.csr"));
    692 cert_contains($cert, "Authority Key Identifier: DirName:/CN=CA serial:", 1); # just issuer AKID
    693 
    694 $cert = "self-issued_v3_CA_forced_issuer_AKID.pem";
    695 generate_cert($cert, @v3_ca, "-addext", "authorityKeyIdentifier = issuer:always",
    696     "-in", srctop_file(@certs, "x509-check.csr"));
    697 cert_contains($cert, "Authority Key Identifier: DirName:/CN=CA serial:", 1); # just issuer AKID
    698 
    699 $cert = "self-issued_v3_CA_keyid_issuer_AKID.pem";
    700 generate_cert($cert, "-addext", "authorityKeyIdentifier = keyid, issuer",
    701     "-in", srctop_file(@certs, "x509-check.csr"));
    702 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID, not forced
    703 
    704 $cert = "self-issued_v3_CA_keyid_forced_issuer_AKID.pem";
    705 generate_cert($cert, "-addext", "authorityKeyIdentifier = keyid, issuer:always",
    706     "-in", srctop_file(@certs, "x509-check.csr"));
    707 cert_ext_has_n_different_lines($cert, 6, $SKID_AKID); # SKID != AKID, with forced issuer
    708 
    709 $cert = "self-issued_v3_CA_forced_keyid_and_issuer_AKID.pem";
    710 generate_cert($cert, "-addext", "authorityKeyIdentifier = keyid:always, issuer:always",
    711     "-in", srctop_file(@certs, "x509-check.csr"));
    712 cert_ext_has_n_different_lines($cert, 6, $SKID_AKID); # SKID != AKID, both forced
    713 
    714 # AKID of not self-issued certs
    715 
    716 $cert = "regular_v3_EE_default_KIDs_no_other_exts.pem";
    717 generate_cert($cert, "-key", srctop_file(@certs, "ee-key.pem"));
    718 has_version($cert, 3);
    719 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    720 
    721 $cert = "regular_v3_EE_default_KIDs.pem";
    722 generate_cert($cert, "-addext", "keyUsage = dataEncipherment",
    723     "-key", srctop_file(@certs, "ee-key.pem"));
    724 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    725 strict_verify($cert, 1, $ca_cert);
    726 
    727 $cert = "regular_v3_EE_copied_exts_default_KIDs.pem";
    728 generate_cert($cert, "-copy_extensions", "copy",
    729               "-in", srctop_file(@certs, "ext-check.csr"));
    730 cert_ext_has_n_different_lines($cert, 4, $SKID_AKID); # SKID != AKID
    731 strict_verify($cert, 1);
    732 
    733 $cert = "v3_EE_no_AKID.pem";
    734 generate_cert($cert, "-addext", "authorityKeyIdentifier = none",
    735     "-key", srctop_file(@certs, "ee-key.pem"));
    736 has_SKID($cert, 1);
    737 has_AKID($cert, 0);
    738 strict_verify($cert, 0, $ca_cert);
    739 
    740 
    741 # Key Usage
    742 
    743 $cert = "self-signed_CA_no_keyUsage.pem";
    744 generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr"));
    745 has_keyUsage($cert, 0);
    746 $cert = "self-signed_CA_with_keyUsages.pem";
    747 generate_cert($cert, "-in", srctop_file(@certs, "ext-check.csr"),
    748     "-copy_extensions", "copy");
    749 has_keyUsage($cert, 1);
    750 
    751 # Generate cert using req with '-modulus'
    752 ok(run(app(["openssl", "req", "-x509", "-new", "-days", "365",
    753             "-key", srctop_file("test", "testrsa.pem"),
    754             "-config", srctop_file('test', 'test.cnf'),
    755             "-out", "testreq-cert.pem",
    756             "-modulus"])), "cert req creation - with -modulus");
    757 
    758 # Verify cert
    759 ok(run(app(["openssl", "x509", "-in", "testreq-cert.pem",
    760             "-noout", "-text"])), "cert verification");
    761 
    762 # Generate cert with explicit start and end dates
    763 my %today = (strftime("%Y-%m-%d", gmtime) => 1);
    764 my $cert = "self-signed_explicit_date.pem";
    765 ok(run(app(["openssl", "req", "-x509", "-new", "-text",
    766             "-config", srctop_file('test', 'test.cnf'),
    767             "-key", srctop_file("test", "testrsa.pem"),
    768             "-not_before", "today",
    769             "-not_after", "today",
    770             "-out", $cert]))
    771 && ++$today{strftime("%Y-%m-%d", gmtime)}
    772 && (grep { defined $today{$_} } get_not_before_date($cert))
    773 && (grep { defined $today{$_} } get_not_after_date($cert)), "explicit start and end dates");
    774