Home | History | Annotate | Line # | Download | only in recipes
      1 #! /usr/bin/env perl
      2 # Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved.
      3 #
      4 # Licensed under the Apache License 2.0 (the "License").  You may not use
      5 # this file except in compliance with the License.  You can obtain a copy
      6 # in the file LICENSE in the source distribution or at
      7 # https://www.openssl.org/source/license.html
      8 
      9 use File::Spec::Functions;
     10 use File::Copy;
     11 use MIME::Base64;
     12 use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_file bldtop_dir
     13                      data_file);
     14 use OpenSSL::Test::Utils;
     15 
     16 my $test_name = "test_store";
     17 setup($test_name);
     18 
     19 require(srctop_file("test", "recipes", "tconversion.pl")); # for test_file_contains()
     20 
     21 my $use_md5 = !disabled("md5");
     22 my $use_des = !(disabled("des") || disabled("legacy")); # also affects 3des and pkcs12 app
     23 my $use_dsa = !disabled("dsa");
     24 my $use_ecc = !disabled("ec");
     25 
     26 my @noexist_files =
     27     ( "test/blahdiblah.pem",
     28       "test/blahdibleh.der" );
     29 my @src_files =
     30     ( "test/testx509.pem",
     31       "test/testrsa.pem",
     32       "test/testrsapub.pem",
     33       "test/testcrl.pem",
     34       "apps/server.pem" );
     35 my @data_files =
     36     ( "testrsa.msb" );
     37 push(@data_files,
     38      ( "testrsa.pvk" ))
     39     unless disabled("legacy") || disabled("rc4");
     40 my @src_rsa_files =
     41     ( "test/testrsa.pem",
     42       "test/testrsapub.pem" );
     43 my @generated_files =
     44     (
     45      ### generated from the source files
     46 
     47      "testx509.der",
     48      "testrsa.der",
     49      "testrsapub.der",
     50      "testcrl.der",
     51 
     52      ### generated locally
     53 
     54      "rsa-key-pkcs1.pem", "rsa-key-pkcs1.der",
     55      "rsa-key-pkcs1-aes128.pem",
     56      "rsa-key-pkcs8.pem", "rsa-key-pkcs8.der",
     57      "rsa-key-pkcs8-pbes2-sha1.pem", "rsa-key-pkcs8-pbes2-sha1.der",
     58      "rsa-key-pkcs8-pbes2-sha256.pem", "rsa-key-pkcs8-pbes2-sha256.der",
     59     );
     60 push(@generated_files, (
     61      "rsa-key-pkcs8-pbes1-sha1-3des.pem", "rsa-key-pkcs8-pbes1-sha1-3des.der",
     62     )) if $use_des;
     63 push(@generated_files, (
     64      "rsa-key-sha1-3des-sha1.p12", "rsa-key-sha1-3des-sha256.p12",
     65      "rsa-key-aes256-cbc-sha256.p12",
     66      "rsa-key-md5-des-sha1.p12",
     67      "rsa-key-aes256-cbc-md5-des-sha256.p12"
     68      )) if $use_des;
     69 push(@generated_files, (
     70      "rsa-key-pkcs8-pbes1-md5-des.pem", "rsa-key-pkcs8-pbes1-md5-des.der"
     71      )) if $use_md5 && $use_des;
     72 push(@generated_files, (
     73      "dsa-key-pkcs1.pem", "dsa-key-pkcs1.der",
     74      "dsa-key-pkcs1-aes128.pem",
     75      "dsa-key-pkcs8.pem", "dsa-key-pkcs8.der",
     76      "dsa-key-pkcs8-pbes2-sha1.pem", "dsa-key-pkcs8-pbes2-sha1.der",
     77      )) if $use_dsa;
     78 push(@generated_files, "dsa-key-aes256-cbc-sha256.p12") if $use_dsa && $use_des;
     79 push(@generated_files, (
     80      "ec-key-pkcs1.pem", "ec-key-pkcs1.der",
     81      "ec-key-pkcs1-aes128.pem",
     82      "ec-key-pkcs8.pem", "ec-key-pkcs8.der",
     83      "ec-key-pkcs8-pbes2-sha1.pem", "ec-key-pkcs8-pbes2-sha1.der",
     84      )) if $use_ecc;
     85 push(@generated_files, "ec-key-aes256-cbc-sha256.p12") if $use_ecc && $use_des;
     86 my %generated_file_files =
     87     $^O eq 'linux'
     88     ? ( "test/testx509.pem" => "file:testx509.pem",
     89         "test/testrsa.pem" => "file:testrsa.pem",
     90         "test/testrsapub.pem" => "file:testrsapub.pem",
     91         "test/testcrl.pem" => "file:testcrl.pem",
     92         "apps/server.pem" => "file:server.pem" )
     93     : ();
     94 my @noexist_file_files =
     95     ( "file:blahdiblah.pem",
     96       "file:test/blahdibleh.der" );
     97 
     98 # There is more than one method to get a 'file:' loader.
     99 # The default is a built-in provider implementation.
    100 # However, there is also an engine, specially for testing purposes.
    101 #
    102 # @methods is a collection of extra 'openssl storeutl' arguments used to
    103 # try the different methods.
    104 my @methods;
    105 my @prov_method = qw(-provider default);
    106 push @prov_method, qw(-provider legacy) unless disabled('legacy');
    107 push @methods, [ @prov_method ];
    108 push @methods, [qw(-engine loader_attic)]
    109     unless disabled('loadereng');
    110 
    111 my $n = 4 + scalar @methods
    112     * ( (3 * scalar @noexist_files)
    113         + (6 * scalar @src_files)
    114         + (2 * scalar @data_files)
    115         + (4 * scalar @generated_files)
    116         + (scalar keys %generated_file_files)
    117         + (scalar @noexist_file_files)
    118         + 3
    119         + 11 );
    120 
    121 # Test doesn't work under msys because the file name munging doesn't work
    122 # correctly with the "ot:" prefix
    123 my $do_test_ossltest_store =
    124     !(disabled("engine") || disabled("dynamic-engine") || $^O =~ /^msys$/);
    125 
    126 if ($do_test_ossltest_store) {
    127     # test loading with apps 'org.openssl.engine:' loader, using the
    128     # ossltest engine.
    129     $n += 4 * scalar @src_rsa_files;
    130 }
    131 
    132 plan skip_all => "No plan" if $n == 0;
    133 
    134 plan tests => $n;
    135 
    136 my $test_x509 = srctop_file('test', 'testx509.pem');
    137 
    138 ok(run(app(["openssl", "storeutl",  "-crls", $test_x509])),
    139    "storeutil with -crls option");
    140 
    141 ok(!run(app(["openssl", "storeutl", $test_x509, "-crls"])),
    142    "storeutil with extra parameter (at end) should fail");
    143 
    144 indir "store_$$" => sub {
    145     if ($do_test_ossltest_store) {
    146         # ossltest loads PEM files, with names prefixed with 'ot:'.
    147         # This prefix ensures that the files are, in fact, loaded through
    148         # that engine and not mistakenly going through the 'file:' loader.
    149 
    150         my $engine_scheme = 'org.openssl.engine:';
    151         $ENV{OPENSSL_ENGINES} = bldtop_dir("engines");
    152 
    153         foreach (@src_rsa_files) {
    154             my $file = srctop_file($_);
    155             my $file_abs = to_abs_file($file);
    156             my @pubin = $_ =~ m|pub\.pem$| ? ("-pubin") : ();
    157 
    158             ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
    159                         "-engine", "ossltest", "-inform", "engine",
    160                         "-in", "ot:$file"])));
    161             ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
    162                         "-engine", "ossltest", "-inform", "engine",
    163                         "-in", "ot:$file_abs"])));
    164             ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
    165                         "-in", "${engine_scheme}ossltest:ot:$file"])));
    166             ok(run(app(["openssl", "rsa", "-text", "-noout", @pubin,
    167                         "-in", "${engine_scheme}ossltest:ot:$file_abs"])));
    168         }
    169     }
    170 
    171  SKIP:
    172     {
    173         init() or die "init failed";
    174 
    175         my $rehash = init_rehash();
    176 
    177         ok(run(app(["openssl", "storeutl", "-out", "cacert.pem", "cacert.pem"])),
    178             "identical infile and outfile");
    179         test_file_contains("storeutl output on same input",
    180                            "cacert.pem", "Total found: 1");
    181 
    182         foreach my $method (@methods) {
    183             my @storeutl = ( qw(openssl storeutl), @$method );
    184 
    185             foreach (@noexist_files) {
    186                 my $file = srctop_file($_);
    187 
    188                 ok(!run(app([@storeutl, "-noout", $file])));
    189                 ok(!run(app([@storeutl, "-noout", to_abs_file($file)])));
    190                 {
    191                     local $ENV{MSYS2_ARG_CONV_EXCL} = "file:";
    192 
    193                     ok(!run(app([@storeutl, "-noout",
    194                                  to_abs_file_uri($file)])));
    195                 }
    196             }
    197             foreach (@src_files) {
    198                 my $file = srctop_file($_);
    199 
    200                 ok(run(app([@storeutl, "-noout", $file])));
    201                 ok(run(app([@storeutl, "-noout", to_abs_file($file)])));
    202               SKIP:
    203                 {
    204                     skip "file: tests disabled on MingW", 4  if $^O =~ /^msys$/;
    205 
    206                     ok(run(app([@storeutl, "-noout",
    207                                 to_abs_file_uri($file)])));
    208                     ok(run(app([@storeutl, "-noout",
    209                                 to_abs_file_uri($file, 0, "")])));
    210                     ok(run(app([@storeutl, "-noout",
    211                                 to_abs_file_uri($file, 0, "localhost")])));
    212                     ok(!run(app([@storeutl, "-noout",
    213                                  to_abs_file_uri($file, 0, "dummy")])));
    214                 }
    215             }
    216             foreach (@data_files) {
    217                 my $file = data_file($_);
    218 
    219                 ok(run(app([@storeutl, "-noout", "-passin", "pass:password",
    220                             $file])));
    221                 ok(run(app([@storeutl, "-noout", "-passin", "pass:password",
    222                             to_abs_file($file)])));
    223             }
    224             foreach (@generated_files) {
    225                 ok(run(app([@storeutl, "-noout", "-passin", "pass:password",
    226                             $_])));
    227                 ok(run(app([@storeutl,  "-noout", "-passin", "pass:password",
    228                             to_abs_file($_)])));
    229 
    230               SKIP:
    231                 {
    232                     skip "file: tests disabled on MingW", 2  if $^O =~ /^msys$/;
    233 
    234                     ok(run(app([@storeutl, "-noout", "-passin",
    235                                 "pass:password", to_abs_file_uri($_)])));
    236                     ok(!run(app([@storeutl, "-noout", "-passin",
    237                                  "pass:password", to_file_uri($_)])));
    238                 }
    239             }
    240             foreach (values %generated_file_files) {
    241               SKIP:
    242                 {
    243                     skip "file: tests disabled on MingW", 1  if $^O =~ /^msys$/;
    244 
    245                     ok(run(app([@storeutl,  "-noout", $_])));
    246                 }
    247             }
    248             foreach (@noexist_file_files) {
    249               SKIP:
    250                 {
    251                     skip "file: tests disabled on MingW", 1  if $^O =~ /^msys$/;
    252 
    253                     ok(!run(app([@storeutl,  "-noout", $_])));
    254                 }
    255             }
    256             {
    257                 my $dir = srctop_dir("test", "certs");
    258 
    259                 ok(run(app([@storeutl,  "-noout", $dir])));
    260                 ok(run(app([@storeutl,  "-noout", to_abs_file($dir, 1)])));
    261               SKIP:
    262                 {
    263                     skip "file: tests disabled on MingW", 1  if $^O =~ /^msys$/;
    264 
    265                     ok(run(app([@storeutl,  "-noout",
    266                                 to_abs_file_uri($dir, 1)])));
    267                 }
    268             }
    269 
    270             ok(!run(app([@storeutl, '-noout',
    271                          '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
    272                          srctop_file('test', 'testx509.pem')])),
    273                "Checking that -subject can't be used with a single file");
    274 
    275             ok(run(app([@storeutl, '-certs', '-noout',
    276                         srctop_file('test', 'testx509.pem')])),
    277                "Checking that -certs returns 1 object on a certificate file");
    278             ok(run(app([@storeutl, '-certs', '-noout',
    279                         srctop_file('test', 'testcrl.pem')])),
    280                "Checking that -certs returns 0 objects on a CRL file");
    281 
    282             ok(run(app([@storeutl, '-crls', '-noout',
    283                         srctop_file('test', 'testx509.pem')])),
    284                "Checking that -crls returns 0 objects on a certificate file");
    285             ok(run(app([@storeutl, '-crls', '-noout',
    286                         srctop_file('test', 'testcrl.pem')])),
    287                "Checking that -crls returns 1 object on a CRL file");
    288 
    289           SKIP: {
    290               skip "failed rehash initialisation", 6 unless $rehash;
    291 
    292               # subject from testx509.pem:
    293               # '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert'
    294               # issuer from testcrl.pem:
    295               # '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority'
    296               ok(run(app([@storeutl, '-noout',
    297                           '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
    298                           catdir(curdir(), 'rehash')])));
    299               ok(run(app([@storeutl, '-noout',
    300                           '-subject',
    301                           '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority',
    302                           catdir(curdir(), 'rehash')])));
    303               ok(run(app([@storeutl, '-noout', '-certs',
    304                           '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
    305                           catdir(curdir(), 'rehash')])));
    306               ok(run(app([@storeutl, '-noout', '-crls',
    307                           '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
    308                           catdir(curdir(), 'rehash')])));
    309               ok(run(app([@storeutl, '-noout', '-certs',
    310                           '-subject',
    311                           '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority',
    312                           catdir(curdir(), 'rehash')])));
    313               ok(run(app([@storeutl, '-noout', '-crls',
    314                           '-subject',
    315                           '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority',
    316                           catdir(curdir(), 'rehash')])));
    317             }
    318         }
    319     }
    320 }, create => 1, cleanup => 1;
    321 
    322 sub init {
    323     my $cnf = srctop_file('test', 'ca-and-certs.cnf');
    324     my $cakey = srctop_file('test', 'certs', 'ca-key.pem');
    325     my @std_args = qw(-provider default);
    326     push @std_args, qw(-provider legacy)
    327         unless disabled('legacy');
    328     return (
    329             # rsa-key-pkcs1.pem
    330             run(app(["openssl", "pkey", @std_args,
    331                      "-in", data_file("rsa-key-2432.pem"),
    332                      "-out", "rsa-key-pkcs1.pem"]))
    333             # rsa-key-pkcs1-aes128.pem
    334             && run(app(["openssl", "rsa", @std_args,
    335                         "-passout", "pass:password", "-aes128",
    336                         "-in", "rsa-key-pkcs1.pem",
    337                         "-out", "rsa-key-pkcs1-aes128.pem"]))
    338             # dsa-key-pkcs1.pem
    339             && (!$use_dsa
    340                 || run(app(["openssl", "gendsa", @std_args,
    341                             "-out", "dsa-key-pkcs1.pem",
    342                             data_file("dsaparam.pem")])))
    343             # dsa-key-pkcs1-aes128.pem
    344             && (!$use_dsa
    345                 || run(app(["openssl", "dsa", @std_args,
    346                             "-passout", "pass:password", "-aes128",
    347                             "-in", "dsa-key-pkcs1.pem",
    348                             "-out", "dsa-key-pkcs1-aes128.pem"])))
    349             # ec-key-pkcs1.pem (one might think that 'genec' would be practical)
    350             && (!$use_ecc
    351                 || run(app(["openssl", "ecparam", @std_args,
    352                             "-genkey",
    353                             "-name", "prime256v1",
    354                             "-out", "ec-key-pkcs1.pem"])))
    355             # ec-key-pkcs1-aes128.pem
    356             && (!$use_ecc
    357                 || run(app(["openssl", "ec", @std_args,
    358                             "-passout", "pass:password", "-aes128",
    359                             "-in", "ec-key-pkcs1.pem",
    360                             "-out", "ec-key-pkcs1-aes128.pem"])))
    361             # *-key-pkcs8.pem
    362             && runall(sub {
    363                           my $dstfile = shift;
    364                           (my $srcfile = $dstfile)
    365                               =~ s/-key-pkcs8\.pem$/-key-pkcs1.pem/i;
    366                           run(app(["openssl", "pkcs8", @std_args,
    367                                    "-topk8", "-nocrypt",
    368                                    "-in", $srcfile, "-out", $dstfile]));
    369                       }, grep(/-key-pkcs8\.pem$/, @generated_files))
    370             # *-key-pkcs8-pbes1-sha1-3des.pem
    371             && runall(sub {
    372                           my $dstfile = shift;
    373                           (my $srcfile = $dstfile)
    374                               =~ s/-key-pkcs8-pbes1-sha1-3des\.pem$
    375                                   /-key-pkcs8.pem/ix;
    376                           run(app(["openssl", "pkcs8", @std_args,
    377                                    "-topk8",
    378                                    "-passout", "pass:password",
    379                                    "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
    380                                    "-in", $srcfile, "-out", $dstfile]));
    381                       }, grep(/-key-pkcs8-pbes1-sha1-3des\.pem$/, @generated_files))
    382             # *-key-pkcs8-pbes1-md5-des.pem
    383             && runall(sub {
    384                           my $dstfile = shift;
    385                           (my $srcfile = $dstfile)
    386                               =~ s/-key-pkcs8-pbes1-md5-des\.pem$
    387                                   /-key-pkcs8.pem/ix;
    388                           run(app(["openssl", "pkcs8", @std_args,
    389                                    "-topk8",
    390                                    "-passout", "pass:password",
    391                                    "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
    392                                    "-in", $srcfile, "-out", $dstfile]));
    393                       }, grep(/-key-pkcs8-pbes1-md5-des\.pem$/, @generated_files))
    394             # *-key-pkcs8-pbes2-sha1.pem
    395             && runall(sub {
    396                           my $dstfile = shift;
    397                           (my $srcfile = $dstfile)
    398                               =~ s/-key-pkcs8-pbes2-sha1\.pem$
    399                                   /-key-pkcs8.pem/ix;
    400                           run(app(["openssl", "pkcs8", @std_args,
    401                                    "-topk8",
    402                                    "-passout", "pass:password",
    403                                    "-v2", "aes256", "-v2prf", "hmacWithSHA1",
    404                                    "-in", $srcfile, "-out", $dstfile]));
    405                       }, grep(/-key-pkcs8-pbes2-sha1\.pem$/, @generated_files))
    406             # *-key-pkcs8-pbes2-sha1.pem
    407             && runall(sub {
    408                           my $dstfile = shift;
    409                           (my $srcfile = $dstfile)
    410                               =~ s/-key-pkcs8-pbes2-sha256\.pem$
    411                                   /-key-pkcs8.pem/ix;
    412                           run(app(["openssl", "pkcs8", @std_args,
    413                                    "-topk8",
    414                                    "-passout", "pass:password",
    415                                    "-v2", "aes256", "-v2prf", "hmacWithSHA256",
    416                                    "-in", $srcfile, "-out", $dstfile]));
    417                       }, grep(/-key-pkcs8-pbes2-sha256\.pem$/, @generated_files))
    418             # *-cert.pem (intermediary for the .p12 inits)
    419             && run(app(["openssl", "req", "-x509", @std_args,
    420                         "-config", $cnf, "-reqexts", "v3_ca", "-noenc",
    421                         "-key", $cakey, "-out", "cacert.pem"]))
    422             && runall(sub {
    423                           my $srckey = shift;
    424                           (my $dstfile = $srckey) =~ s|-key-pkcs8\.|-cert.|;
    425                           (my $csr = $dstfile) =~ s|\.pem|.csr|;
    426 
    427                           (run(app(["openssl", "req", "-new", @std_args,
    428                                     "-config", $cnf, "-section", "userreq",
    429                                     "-key", $srckey, "-out", $csr]))
    430                            &&
    431                            run(app(["openssl", "x509", @std_args,
    432                                     "-days", "3650",
    433                                     "-CA", "cacert.pem",
    434                                     "-CAkey", $cakey,
    435                                     "-set_serial", time(), "-req",
    436                                     "-in", $csr, "-out", $dstfile])));
    437                       }, grep(/-key-pkcs8\.pem$/, @generated_files))
    438             # *.p12
    439             && runall(sub {
    440                           my $dstfile = shift;
    441                           my ($type, $certpbe_index, $keypbe_index,
    442                               $macalg_index) =
    443                               $dstfile =~ m{^(.*)-key-(?|
    444                                                 # cert and key PBE are same
    445                                                 ()             #
    446                                                 ([^-]*-[^-]*)- # key & cert PBE
    447                                                 ([^-]*)        # MACalg
    448                                             |
    449                                                 # cert and key PBE are not same
    450                                                 ([^-]*-[^-]*)- # cert PBE
    451                                                 ([^-]*-[^-]*)- # key PBE
    452                                                 ([^-]*)        # MACalg
    453                                             )\.}x;
    454                           if (!$certpbe_index) {
    455                               $certpbe_index = $keypbe_index;
    456                           }
    457                           my $srckey = "$type-key-pkcs8.pem";
    458                           my $srccert = "$type-cert.pem";
    459                           my %pbes =
    460                               (
    461                                "sha1-3des" => "pbeWithSHA1And3-KeyTripleDES-CBC",
    462                                "md5-des" => "pbeWithMD5AndDES-CBC",
    463                                "aes256-cbc" => "AES-256-CBC",
    464                               );
    465                           my %macalgs =
    466                               (
    467                                "sha1" => "SHA1",
    468                                "sha256" => "SHA256",
    469                               );
    470                           my $certpbe = $pbes{$certpbe_index};
    471                           my $keypbe = $pbes{$keypbe_index};
    472                           my $macalg = $macalgs{$macalg_index};
    473                           if (!defined($certpbe) || !defined($keypbe)
    474                               || !defined($macalg)) {
    475                               print STDERR "Cert PBE for $certpbe_index not defined\n"
    476                                   unless defined $certpbe;
    477                               print STDERR "Key PBE for $keypbe_index not defined\n"
    478                                   unless defined $keypbe;
    479                               print STDERR "MACALG for $macalg_index not defined\n"
    480                                   unless defined $macalg;
    481                               print STDERR "(destination file was $dstfile)\n";
    482                               return 0;
    483                           }
    484                           run(app(["openssl", "pkcs12", @std_args,
    485                                    "-inkey", $srckey,
    486                                    "-in", $srccert, "-passout", "pass:password",
    487                                    "-chain", "-CAfile", "cacert.pem",
    488                                    "-export", "-macalg", $macalg,
    489                                    "-certpbe", $certpbe, "-keypbe", $keypbe,
    490                                    "-out", $dstfile]));
    491                       }, grep(/\.p12/, @generated_files))
    492             # *.der (the end all init)
    493             && runall(sub {
    494                           my $dstfile = shift;
    495                           (my $srcfile = $dstfile) =~ s/\.der$/.pem/i;
    496                           if (! -f $srcfile) {
    497                               $srcfile = srctop_file("test", $srcfile);
    498                           }
    499                           my $infh;
    500                           unless (open $infh, $srcfile) {
    501                               return 0;
    502                           }
    503                           my $l;
    504                           while (($l = <$infh>) !~ /^-----BEGIN\s/
    505                                  || $l =~ /^-----BEGIN.*PARAMETERS-----/) {
    506                           }
    507                           my $b64 = "";
    508                           while (($l = <$infh>) !~ /^-----END\s/) {
    509                               $l =~ s|\R$||;
    510                               $b64 .= $l unless $l =~ /:/;
    511                           }
    512                           close $infh;
    513                           my $der = decode_base64($b64);
    514                           unless (length($b64) / 4 * 3 - length($der) < 3) {
    515                               print STDERR "Length error, ",length($b64),
    516                                   " bytes of base64 became ",length($der),
    517                                   " bytes of der? ($srcfile => $dstfile)\n";
    518                               return 0;
    519                           }
    520                           my $outfh;
    521                           unless (open $outfh, ">:raw", $dstfile) {
    522                               return 0;
    523                           }
    524                           print $outfh $der;
    525                           close $outfh;
    526                           return 1;
    527                       }, grep(/\.der$/, @generated_files))
    528             && runall(sub {
    529                           my $srcfile = shift;
    530                           my $dstfile = $generated_file_files{$srcfile};
    531 
    532                           unless (copy srctop_file($srcfile), $dstfile) {
    533                               warn "$!\n";
    534                               return 0;
    535                           }
    536                           return 1;
    537                       }, keys %generated_file_files)
    538            );
    539 }
    540 
    541 sub init_rehash {
    542     return (
    543             mkdir(catdir(curdir(), 'rehash'))
    544             && copy(srctop_file('test', 'testx509.pem'),
    545                     catdir(curdir(), 'rehash'))
    546             && copy(srctop_file('test', 'testcrl.pem'),
    547                     catdir(curdir(), 'rehash'))
    548             && run(app(['openssl', 'rehash', catdir(curdir(), 'rehash')]))
    549            );
    550 }
    551 
    552 sub runall {
    553     my ($function, @items) = @_;
    554 
    555     foreach (@items) {
    556         return 0 unless $function->($_);
    557     }
    558     return 1;
    559 }
    560 
    561 # According to RFC8089, a relative file: path is invalid.  We still produce
    562 # them for testing purposes.
    563 sub to_file_uri {
    564     my ($file, $isdir, $authority) = @_;
    565     my $vol;
    566     my $dir;
    567 
    568     die "to_file_uri: No file given\n" if !defined($file) || $file eq '';
    569 
    570     ($vol, $dir, $file) = File::Spec->splitpath($file, $isdir // 0);
    571 
    572     # Make sure we have a Unix style directory.
    573     $dir = join('/', File::Spec->splitdir($dir));
    574     # Canonicalise it (note: it seems to be only needed on Unix)
    575     while (1) {
    576         my $newdir = $dir;
    577         $newdir =~ s|/[^/]*[^/\.]+[^/]*/\.\./|/|g;
    578         last if $newdir eq $dir;
    579         $dir = $newdir;
    580     }
    581     # Take care of the corner cases the loop can't handle, and that $dir
    582     # ends with a / unless it's empty
    583     $dir =~ s|/[^/]*[^/\.]+[^/]*/\.\.$|/|;
    584     $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\./|/|;
    585     $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\.$||;
    586     if ($isdir // 0) {
    587         $dir =~ s|/$|| if $dir ne '/';
    588     } else {
    589         $dir .= '/' if $dir ne '' && $dir !~ m|/$|;
    590     }
    591 
    592     # If the file system has separate volumes (at present, Windows and VMS)
    593     # we need to handle them.  In URIs, they are invariably the first
    594     # component of the path, which is always absolute.
    595     # On VMS, user:[foo.bar] translates to /user/foo/bar
    596     # On Windows, c:\Users\Foo translates to /c:/Users/Foo
    597     if ($vol ne '') {
    598         $vol =~ s|:||g if ($^O eq "VMS");
    599         $dir = '/' . $dir if $dir ne '' && $dir !~ m|^/|;
    600         $dir = '/' . $vol . $dir;
    601     }
    602     $file = $dir . $file;
    603 
    604     return "file://$authority$file" if defined $authority;
    605     return "file:$file";
    606 }
    607 
    608 sub to_abs_file {
    609     my ($file) = @_;
    610 
    611     return File::Spec->rel2abs($file);
    612 }
    613 
    614 sub to_abs_file_uri {
    615     my ($file, $isdir, $authority) = @_;
    616 
    617     die "to_abs_file_uri: No file given\n" if !defined($file) || $file eq '';
    618     return to_file_uri(to_abs_file($file), $isdir, $authority);
    619 }
    620