OSSL_STORE: Avoid testing with URIs on the mingw command line
[openssl.git] / test / recipes / 90-test_store.t
1 #! /usr/bin/env perl
2 # Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
3 #
4 # Licensed under the OpenSSL license (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;
10 use File::Copy;
11 use MIME::Base64;
12 use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_file data_file);
13
14 my $test_name = "test_store";
15 setup($test_name);
16
17 # The MSYS2 run-time convert arguments that look like paths when executing
18 # a program unless that application is linked with the MSYS run-time.  The
19 # exact conversion rules are listed here:
20 #
21 #       http://www.mingw.org/wiki/Posix_path_conversion
22 #
23 # With the built-in configurations (all having names starting with "mingw"),
24 # the openssl application is not linked with the MSYS2 run-time, and therefore,
25 # it will receive possibly converted arguments from the process that executes
26 # it.  This conversion is fine for normal path arguments, but when those
27 # arguments are URIs, they sometimes aren't converted right (typically for
28 # URIs without an authority component, 'cause the conversion mechanism doesn't
29 # recognise them as URIs) or aren't converted at all (which gives perfectly
30 # normal absolute paths from the MSYS viewpoint, but don't work for the
31 # Windows run-time we're linked with).
32 #
33 # It's also possible to avoid conversion by defining MSYS2_ARG_CONV_EXCL with
34 # some suitable pattern ("*" to avoid conversions entirely), but that will
35 # again give us unconverted paths that don't work with the Windows run-time
36 # we're linked with.
37 #
38 # Checking for both msys perl operating environment and that the target name
39 # starts with "mingw", we're doing what we can to assure that other configs
40 # that might link openssl.exe with the MSYS run-time are not disturbed.
41 my $msys_mingw = ($^O eq 'msys') && (config('target') =~ m|^mingw|);
42
43 my @noexist_files =
44     ( "test/blahdiblah.pem",
45       "test/blahdibleh.der" );
46 my @src_files =
47     ( "test/testx509.pem",
48       "test/testrsa.pem",
49       "test/testrsapub.pem",
50       "test/testcrl.pem",
51       "apps/server.pem" );
52 my @generated_files =
53     (
54      ### generated from the source files
55
56      "testx509.der",
57      "testrsa.der",
58      "testrsapub.der",
59      "testcrl.der",
60
61      ### generated locally
62
63      "rsa-key-pkcs1.pem", "rsa-key-pkcs1.der",
64      "rsa-key-pkcs1-aes128.pem",
65      "rsa-key-pkcs8.pem", "rsa-key-pkcs8.der",
66      "rsa-key-pkcs8-pbes1-sha1-3des.pem", "rsa-key-pkcs8-pbes1-sha1-3des.der",
67      "rsa-key-pkcs8-pbes2-sha1.pem", "rsa-key-pkcs8-pbes2-sha1.der",
68      "rsa-key-sha1-3des-sha1.p12", "rsa-key-sha1-3des-sha256.p12",
69      "rsa-key-aes256-cbc-sha256.p12",
70      "rsa-key-md5-des-sha1.p12",
71      "rsa-key-aes256-cbc-md5-des-sha256.p12",
72      "rsa-key-pkcs8-pbes2-sha256.pem", "rsa-key-pkcs8-pbes2-sha256.der",
73      "rsa-key-pkcs8-pbes1-md5-des.pem", "rsa-key-pkcs8-pbes1-md5-des.der",
74      "dsa-key-pkcs1.pem", "dsa-key-pkcs1.der",
75      "dsa-key-pkcs1-aes128.pem",
76      "dsa-key-pkcs8.pem", "dsa-key-pkcs8.der",
77      "dsa-key-pkcs8-pbes2-sha1.pem", "dsa-key-pkcs8-pbes2-sha1.der",
78      "dsa-key-aes256-cbc-sha256.p12",
79      "ec-key-pkcs1.pem", "ec-key-pkcs1.der",
80      "ec-key-pkcs1-aes128.pem",
81      "ec-key-pkcs8.pem", "ec-key-pkcs8.der",
82      "ec-key-pkcs8-pbes2-sha1.pem", "ec-key-pkcs8-pbes2-sha1.der",
83      "ec-key-aes256-cbc-sha256.p12",
84     );
85 my %generated_file_files =
86     $^O eq 'linux'
87     ? ( "test/testx509.pem" => "file:testx509.pem",
88         "test/testrsa.pem" => "file:testrsa.pem",
89         "test/testrsapub.pem" => "file:testrsapub.pem",
90         "test/testcrl.pem" => "file:testcrl.pem",
91         "apps/server.pem" => "file:server.pem" )
92     : ();
93 my @noexist_file_files =
94     ( "file:blahdiblah.pem",
95       "file:test/blahdibleh.der" );
96
97
98 my $n = (3 * scalar @noexist_files)
99     + (6 * scalar @src_files)
100     + (4 * scalar @generated_files)
101     + (scalar keys %generated_file_files)
102     + (scalar @noexist_file_files)
103     + 4;
104
105 plan tests => $n;
106
107 indir "store_$$" => sub {
108  SKIP:
109     {
110         skip "failed initialisation", $n unless init();
111
112         # test PEM_read_bio_PrivateKey
113         ok(run(app(["openssl", "rsa", "-in", "rsa-key-pkcs8-pbes2-sha256.pem",
114                     "-passin", "pass:password"])));
115
116         foreach (@noexist_files) {
117             my $file = srctop_file($_);
118         SKIP: {
119                 ok(!run(app(["openssl", "storeutl", $file])));
120                 ok(!run(app(["openssl", "storeutl", to_abs_file($file)])));
121
122                 skip "No test of URI form of $file for mingw", 1 if $msys_mingw;
123
124                 ok(!run(app(["openssl", "storeutl", to_abs_file_uri($file)])));
125             }
126         }
127         foreach (@src_files) {
128             my $file = srctop_file($_);
129         SKIP: {
130                 ok(run(app(["openssl", "storeutl", $file])));
131                 ok(run(app(["openssl", "storeutl", to_abs_file($file)])));
132
133                 skip "No test of URI form of $file for mingw", 4 if $msys_mingw;
134
135                 ok(run(app(["openssl", "storeutl", to_abs_file_uri($file)])));
136                 ok(run(app(["openssl", "storeutl",
137                             to_abs_file_uri($file, 0, "")])));
138                 ok(run(app(["openssl", "storeutl",
139                             to_abs_file_uri($file, 0, "localhost")])));
140                 ok(!run(app(["openssl", "storeutl",
141                              to_abs_file_uri($file, 0, "dummy")])));
142             }
143         }
144         foreach (@generated_files) {
145         SKIP: {
146                 ok(run(app(["openssl", "storeutl", "-passin", "pass:password",
147                             $_])));
148                 ok(run(app(["openssl", "storeutl", "-passin", "pass:password",
149                             to_abs_file($_)])));
150
151                 skip "No test of URI form of $_ for mingw", 2 if $msys_mingw;
152
153                 ok(run(app(["openssl", "storeutl", "-passin", "pass:password",
154                             to_abs_file_uri($_)])));
155                 ok(!run(app(["openssl", "storeutl", "-passin", "pass:password",
156                              to_file_uri($_)])));
157             }
158         }
159         foreach (values %generated_file_files) {
160         SKIP: {
161                 skip "No test of $_ for mingw", 1 if $msys_mingw;
162
163                 ok(run(app(["openssl", "storeutl", $_])));
164             }
165         }
166         foreach (@noexist_file_files) {
167         SKIP: {
168                 skip "No test of $_ for mingw", 1 if $msys_mingw;
169
170                 ok(!run(app(["openssl", "storeutl", $_])));
171             }
172         }
173         {
174             my $dir = srctop_dir("test", "certs");
175         SKIP: {
176                 ok(run(app(["openssl", "storeutl", $dir])));
177                 ok(run(app(["openssl", "storeutl", to_abs_file($dir, 1)])));
178
179                 skip "No test of URI form of $dir for mingw", 1 if $msys_mingw;
180
181                 ok(run(app(["openssl", "storeutl", to_abs_file_uri($dir, 1)])));
182             }
183         }
184     }
185 }, create => 1, cleanup => 1;
186
187 sub init {
188     return (
189             # rsa-key-pkcs1.pem
190             run(app(["openssl", "genrsa",
191                      "-out", "rsa-key-pkcs1.pem", "2432"]))
192             # dsa-key-pkcs1.pem
193             && run(app(["openssl", "dsaparam", "-genkey",
194                         "-out", "dsa-key-pkcs1.pem", "1024"]))
195             # ec-key-pkcs1.pem (one might think that 'genec' would be practical)
196             && run(app(["openssl", "ecparam", "-genkey", "-name", "prime256v1",
197                         "-out", "ec-key-pkcs1.pem"]))
198             # rsa-key-pkcs1-aes128.pem
199             && run(app(["openssl", "rsa", "-passout", "pass:password", "-aes128",
200                         "-in", "rsa-key-pkcs1.pem",
201                         "-out", "rsa-key-pkcs1-aes128.pem"]))
202             # dsa-key-pkcs1-aes128.pem
203             && run(app(["openssl", "dsa", "-passout", "pass:password", "-aes128",
204                         "-in", "dsa-key-pkcs1.pem",
205                         "-out", "dsa-key-pkcs1-aes128.pem"]))
206             # ec-key-pkcs1-aes128.pem
207             && run(app(["openssl", "ec", "-passout", "pass:password", "-aes128",
208                         "-in", "ec-key-pkcs1.pem",
209                         "-out", "ec-key-pkcs1-aes128.pem"]))
210             # *-key-pkcs8.pem
211             && runall(sub {
212                           my $dstfile = shift;
213                           (my $srcfile = $dstfile)
214                               =~ s/-key-pkcs8\.pem$/-key-pkcs1.pem/i;
215                           run(app(["openssl", "pkcs8", "-topk8", "-nocrypt",
216                                    "-in", $srcfile, "-out", $dstfile]));
217                       }, grep(/-key-pkcs8\.pem$/, @generated_files))
218             # *-key-pkcs8-pbes1-sha1-3des.pem
219             && runall(sub {
220                           my $dstfile = shift;
221                           (my $srcfile = $dstfile)
222                               =~ s/-key-pkcs8-pbes1-sha1-3des\.pem$
223                                   /-key-pkcs8.pem/ix;
224                           run(app(["openssl", "pkcs8", "-topk8",
225                                    "-passout", "pass:password",
226                                    "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
227                                    "-in", $srcfile, "-out", $dstfile]));
228                       }, grep(/-key-pkcs8-pbes1-sha1-3des\.pem$/, @generated_files))
229             # *-key-pkcs8-pbes1-md5-des.pem
230             && runall(sub {
231                           my $dstfile = shift;
232                           (my $srcfile = $dstfile)
233                               =~ s/-key-pkcs8-pbes1-md5-des\.pem$
234                                   /-key-pkcs8.pem/ix;
235                           run(app(["openssl", "pkcs8", "-topk8",
236                                    "-passout", "pass:password",
237                                    "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
238                                    "-in", $srcfile, "-out", $dstfile]));
239                       }, grep(/-key-pkcs8-pbes1-md5-des\.pem$/, @generated_files))
240             # *-key-pkcs8-pbes2-sha1.pem
241             && runall(sub {
242                           my $dstfile = shift;
243                           (my $srcfile = $dstfile)
244                               =~ s/-key-pkcs8-pbes2-sha1\.pem$
245                                   /-key-pkcs8.pem/ix;
246                           run(app(["openssl", "pkcs8", "-topk8",
247                                    "-passout", "pass:password",
248                                    "-v2", "aes256", "-v2prf", "hmacWithSHA1",
249                                    "-in", $srcfile, "-out", $dstfile]));
250                       }, grep(/-key-pkcs8-pbes2-sha1\.pem$/, @generated_files))
251             # *-key-pkcs8-pbes2-sha1.pem
252             && runall(sub {
253                           my $dstfile = shift;
254                           (my $srcfile = $dstfile)
255                               =~ s/-key-pkcs8-pbes2-sha256\.pem$
256                                   /-key-pkcs8.pem/ix;
257                           run(app(["openssl", "pkcs8", "-topk8",
258                                    "-passout", "pass:password",
259                                    "-v2", "aes256", "-v2prf", "hmacWithSHA256",
260                                    "-in", $srcfile, "-out", $dstfile]));
261                       }, grep(/-key-pkcs8-pbes2-sha256\.pem$/, @generated_files))
262             # *-cert.pem (intermediary for the .p12 inits)
263             && run(app(["openssl", "req", "-x509",
264                         "-config", data_file("ca.cnf"), "-nodes",
265                         "-out", "cacert.pem", "-keyout", "cakey.pem"]))
266             && runall(sub {
267                           my $srckey = shift;
268                           (my $dstfile = $srckey) =~ s|-key-pkcs8\.|-cert.|;
269                           (my $csr = $dstfile) =~ s|\.pem|.csr|;
270
271                           (run(app(["openssl", "req", "-new",
272                                     "-config", data_file("user.cnf"),
273                                     "-key", $srckey, "-out", $csr]))
274                            &&
275                            run(app(["openssl", "x509", "-days", "3650",
276                                     "-CA", "cacert.pem",
277                                     "-CAkey", "cakey.pem",
278                                     "-set_serial", time(), "-req",
279                                     "-in", $csr, "-out", $dstfile])));
280                       }, grep(/-key-pkcs8\.pem$/, @generated_files))
281             # *.p12
282             && runall(sub {
283                           my $dstfile = shift;
284                           my ($type, $certpbe_index, $keypbe_index,
285                               $macalg_index) =
286                               $dstfile =~ m{^(.*)-key-(?|
287                                                 # cert and key PBE are same
288                                                 ()             #
289                                                 ([^-]*-[^-]*)- # key & cert PBE
290                                                 ([^-]*)        # MACalg
291                                             |
292                                                 # cert and key PBE are not same
293                                                 ([^-]*-[^-]*)- # cert PBE
294                                                 ([^-]*-[^-]*)- # key PBE
295                                                 ([^-]*)        # MACalg
296                                             )\.}x;
297                           if (!$certpbe_index) {
298                               $certpbe_index = $keypbe_index;
299                           }
300                           my $srckey = "$type-key-pkcs8.pem";
301                           my $srccert = "$type-cert.pem";
302                           my %pbes =
303                               (
304                                "sha1-3des" => "pbeWithSHA1And3-KeyTripleDES-CBC",
305                                "md5-des" => "pbeWithMD5AndDES-CBC",
306                                "aes256-cbc" => "AES-256-CBC",
307                               );
308                           my %macalgs =
309                               (
310                                "sha1" => "SHA1",
311                                "sha256" => "SHA256",
312                               );
313                           my $certpbe = $pbes{$certpbe_index};
314                           my $keypbe = $pbes{$keypbe_index};
315                           my $macalg = $macalgs{$macalg_index};
316                           if (!defined($certpbe) || !defined($keypbe)
317                               || !defined($macalg)) {
318                               print STDERR "Cert PBE for $pbe_index not defined\n"
319                                   unless defined $certpbe;
320                               print STDERR "Key PBE for $pbe_index not defined\n"
321                                   unless defined $keypbe;
322                               print STDERR "MACALG for $macalg_index not defined\n"
323                                   unless defined $macalg;
324                               print STDERR "(destination file was $dstfile)\n";
325                               return 0;
326                           }
327                           run(app(["openssl", "pkcs12", "-inkey", $srckey,
328                                    "-in", $srccert, "-passout", "pass:password",
329                                    "-export", "-macalg", $macalg,
330                                    "-certpbe", $certpbe, "-keypbe", $keypbe,
331                                    "-out", $dstfile]));
332                       }, grep(/\.p12/, @generated_files))
333             # *.der (the end all init)
334             && runall(sub {
335                           my $dstfile = shift;
336                           (my $srcfile = $dstfile) =~ s/\.der$/.pem/i;
337                           if (! -f $srcfile) {
338                               $srcfile = srctop_file("test", $srcfile);
339                           }
340                           my $infh;
341                           unless (open $infh, $srcfile) {
342                               return 0;
343                           }
344                           my $l;
345                           while (($l = <$infh>) !~ /^-----BEGIN\s/
346                                  || $l =~ /^-----BEGIN.*PARAMETERS-----/) {
347                           }
348                           my $b64 = "";
349                           while (($l = <$infh>) !~ /^-----END\s/) {
350                               $l =~ s|\R$||;
351                               $b64 .= $l unless $l =~ /:/;
352                           }
353                           close $infh;
354                           my $der = decode_base64($b64);
355                           unless (length($b64) / 4 * 3 - length($der) < 3) {
356                               print STDERR "Length error, ",length($b64),
357                                   " bytes of base64 became ",length($der),
358                                   " bytes of der? ($srcfile => $dstfile)\n";
359                               return 0;
360                           }
361                           my $outfh;
362                           unless (open $outfh, ">:raw", $dstfile) {
363                               return 0;
364                           }
365                           print $outfh $der;
366                           close $outfh;
367                           return 1;
368                       }, grep(/\.der$/, @generated_files))
369             && runall(sub {
370                           my $srcfile = shift;
371                           my $dstfile = $generated_file_files{$srcfile};
372
373                           unless (copy srctop_file($srcfile), $dstfile) {
374                               warn "$!\n";
375                               return 0;
376                           }
377                           return 1;
378                       }, keys %generated_file_files)
379            );
380 }
381
382 sub runall {
383     my ($function, @items) = @_;
384
385     foreach (@items) {
386         return 0 unless $function->($_);
387     }
388     return 1;
389 }
390
391 # According to RFC8089, a relative file: path is invalid.  We still produce
392 # them for testing purposes.
393 sub to_file_uri {
394     my ($file, $isdir, $authority) = @_;
395     my $vol;
396     my $dir;
397
398     die "to_file_uri: No file given\n" if !defined($file) || $file eq '';
399
400     ($vol, $dir, $file) = File::Spec->splitpath($file, $isdir // 0);
401
402     # Make sure we have a Unix style directory.
403     $dir = join('/', File::Spec->splitdir($dir));
404     # Canonicalise it (note: it seems to be only needed on Unix)
405     while (1) {
406         my $newdir = $dir;
407         $newdir =~ s|/[^/]*[^/\.]+[^/]*/\.\./|/|g;
408         last if $newdir eq $dir;
409         $dir = $newdir;
410     }
411     # Take care of the corner cases the loop can't handle, and that $dir
412     # ends with a / unless it's empty
413     $dir =~ s|/[^/]*[^/\.]+[^/]*/\.\.$|/|;
414     $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\./|/|;
415     $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\.$||;
416     if ($isdir // 0) {
417         $dir =~ s|/$|| if $dir ne '/';
418     } else {
419         $dir .= '/' if $dir ne '' && $dir !~ m|/$|;
420     }
421
422     # If the file system has separate volumes (at present, Windows and VMS)
423     # we need to handle them.  In URIs, they are invariably the first
424     # component of the path, which is always absolute.
425     # On VMS, user:[foo.bar] translates to /user/foo/bar
426     # On Windows, c:\Users\Foo translates to /c:/Users/Foo
427     if ($vol ne '') {
428         $vol =~ s|:||g if ($^O eq "VMS");
429         $dir = '/' . $dir if $dir ne '' && $dir !~ m|^/|;
430         $dir = '/' . $vol . $dir;
431     }
432     $file = $dir . $file;
433
434     return "file://$authority$file" if defined $authority;
435     return "file:$file";
436 }
437
438 sub to_abs_file {
439     my ($file) = @_;
440
441     return File::Spec->rel2abs($file);
442 }
443
444 sub to_abs_file_uri {
445     my ($file, $isdir, $authority) = @_;
446
447     die "to_abs_file_uri: No file given\n" if !defined($file) || $file eq '';
448     return to_file_uri(to_abs_file($file), $isdir, $authority);
449 }