Update manpage to fix examples, other minor tweaks
[openssl.git] / test / recipes / 90-test_store.t
1 #! /usr/bin/env perl
2 # Copyright 2016-2018 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 data_file);
13 use OpenSSL::Test::Utils;
14
15 my $test_name = "test_store";
16 setup($test_name);
17
18 my $mingw = config('target') =~ m|^mingw|;
19 my $cnf = srctop_file("test", "ca-and-certs.cnf");
20
21 my @noexist_files =
22     ( "test/blahdiblah.pem",
23       "test/blahdibleh.der" );
24 my @src_files =
25     ( "test/testx509.pem",
26       "test/testrsa.pem",
27       "test/testrsapub.pem",
28       "test/testcrl.pem",
29       "apps/server.pem" );
30 my @generated_files =
31     (
32      ### generated from the source files
33
34      "testx509.der",
35      "testrsa.der",
36      "testrsapub.der",
37      "testcrl.der",
38
39      ### generated locally
40
41      "rsa-key-pkcs1.pem", "rsa-key-pkcs1.der",
42      "rsa-key-pkcs1-aes128.pem",
43      "rsa-key-pkcs8.pem", "rsa-key-pkcs8.der",
44      "rsa-key-pkcs8-pbes1-sha1-3des.pem", "rsa-key-pkcs8-pbes1-sha1-3des.der",
45      "rsa-key-pkcs8-pbes2-sha1.pem", "rsa-key-pkcs8-pbes2-sha1.der",
46      "rsa-key-sha1-3des-sha1.p12", "rsa-key-sha1-3des-sha256.p12",
47      "rsa-key-aes256-cbc-sha256.p12",
48      "rsa-key-md5-des-sha1.p12",
49      "rsa-key-aes256-cbc-md5-des-sha256.p12",
50      "rsa-key-pkcs8-pbes2-sha256.pem", "rsa-key-pkcs8-pbes2-sha256.der",
51      "rsa-key-pkcs8-pbes1-md5-des.pem", "rsa-key-pkcs8-pbes1-md5-des.der",
52      "dsa-key-pkcs1.pem", "dsa-key-pkcs1.der",
53      "dsa-key-pkcs1-aes128.pem",
54      "dsa-key-pkcs8.pem", "dsa-key-pkcs8.der",
55      "dsa-key-pkcs8-pbes2-sha1.pem", "dsa-key-pkcs8-pbes2-sha1.der",
56      "dsa-key-aes256-cbc-sha256.p12",
57      "ec-key-pkcs1.pem", "ec-key-pkcs1.der",
58      "ec-key-pkcs1-aes128.pem",
59      "ec-key-pkcs8.pem", "ec-key-pkcs8.der",
60      "ec-key-pkcs8-pbes2-sha1.pem", "ec-key-pkcs8-pbes2-sha1.der",
61      "ec-key-aes256-cbc-sha256.p12",
62     );
63 my %generated_file_files =
64     $^O eq 'linux'
65     ? ( "test/testx509.pem" => "file:testx509.pem",
66         "test/testrsa.pem" => "file:testrsa.pem",
67         "test/testrsapub.pem" => "file:testrsapub.pem",
68         "test/testcrl.pem" => "file:testcrl.pem",
69         "apps/server.pem" => "file:server.pem" )
70     : ();
71 my @noexist_file_files =
72     ( "file:blahdiblah.pem",
73       "file:test/blahdibleh.der" );
74
75 my $n = (3 * scalar @noexist_files)
76     + (6 * scalar @src_files)
77     + (4 * scalar @generated_files)
78     + (scalar keys %generated_file_files)
79     + (scalar @noexist_file_files)
80     + 3
81     + 11;
82
83 plan tests => $n;
84
85 indir "store_$$" => sub {
86  SKIP:
87     {
88         skip "failed initialisation", $n unless init();
89
90         my $rehash = init_rehash();
91
92         foreach (@noexist_files) {
93             my $file = srctop_file($_);
94
95             ok(!run(app(["openssl", "storeutl", "-noout", $file])));
96             ok(!run(app(["openssl", "storeutl", "-noout",
97                          to_abs_file($file)])));
98             {
99                 local $ENV{MSYS2_ARG_CONV_EXCL} = "file:";
100
101                 ok(!run(app(["openssl", "storeutl", "-noout",
102                              to_abs_file_uri($file)])));
103             }
104         }
105         foreach (@src_files) {
106             my $file = srctop_file($_);
107
108             ok(run(app(["openssl", "storeutl", "-noout", $file])));
109             ok(run(app(["openssl", "storeutl", "-noout", to_abs_file($file)])));
110         SKIP:
111             {
112                 skip "file: tests disabled on MingW", 4 if $mingw;
113
114                 ok(run(app(["openssl", "storeutl", "-noout",
115                             to_abs_file_uri($file)])));
116                 ok(run(app(["openssl", "storeutl", "-noout",
117                             to_abs_file_uri($file, 0, "")])));
118                 ok(run(app(["openssl", "storeutl", "-noout",
119                             to_abs_file_uri($file, 0, "localhost")])));
120                 ok(!run(app(["openssl", "storeutl", "-noout",
121                              to_abs_file_uri($file, 0, "dummy")])));
122             }
123         }
124         foreach (@generated_files) {
125             ok(run(app(["openssl", "storeutl", "-noout", "-passin",
126                         "pass:password", $_])));
127             ok(run(app(["openssl", "storeutl",  "-noout", "-passin",
128                         "pass:password", to_abs_file($_)])));
129
130         SKIP:
131             {
132                 skip "file: tests disabled on MingW", 2 if $mingw;
133
134                 ok(run(app(["openssl", "storeutl", "-noout", "-passin",
135                             "pass:password", to_abs_file_uri($_)])));
136                 ok(!run(app(["openssl", "storeutl", "-noout", "-passin",
137                              "pass:password", to_file_uri($_)])));
138             }
139         }
140         foreach (values %generated_file_files) {
141         SKIP:
142             {
143                 skip "file: tests disabled on MingW", 1 if $mingw;
144
145                 ok(run(app(["openssl", "storeutl",  "-noout", $_])));
146             }
147         }
148         foreach (@noexist_file_files) {
149         SKIP:
150             {
151                 skip "file: tests disabled on MingW", 1 if $mingw;
152
153                 ok(!run(app(["openssl", "storeutl",  "-noout", $_])));
154             }
155         }
156         {
157             my $dir = srctop_dir("test", "certs");
158
159             ok(run(app(["openssl", "storeutl",  "-noout", $dir])));
160             ok(run(app(["openssl", "storeutl",  "-noout",
161                         to_abs_file($dir, 1)])));
162         SKIP:
163             {
164                 skip "file: tests disabled on MingW", 1 if $mingw;
165
166                 ok(run(app(["openssl", "storeutl",  "-noout",
167                             to_abs_file_uri($dir, 1)])));
168             }
169         }
170
171         ok(!run(app(['openssl', 'storeutl', '-noout',
172                      '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
173                      srctop_file('test', 'testx509.pem')])),
174            "Checking that -subject can't be used with a single file");
175
176         ok(run(app(['openssl', 'storeutl', '-certs', '-noout',
177                     srctop_file('test', 'testx509.pem')])),
178            "Checking that -certs returns 1 object on a certificate file");
179         ok(run(app(['openssl', 'storeutl', '-certs', '-noout',
180                      srctop_file('test', 'testcrl.pem')])),
181            "Checking that -certs returns 0 objects on a CRL file");
182
183         ok(run(app(['openssl', 'storeutl', '-crls', '-noout',
184                      srctop_file('test', 'testx509.pem')])),
185            "Checking that -crls returns 0 objects on a certificate file");
186         ok(run(app(['openssl', 'storeutl', '-crls', '-noout',
187                     srctop_file('test', 'testcrl.pem')])),
188            "Checking that -crls returns 1 object on a CRL file");
189
190     SKIP: {
191             skip "failed rehash initialisation", 6 unless $rehash;
192
193             # subject from testx509.pem:
194             # '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert'
195             # issuer from testcrl.pem:
196             # '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority'
197             ok(run(app(['openssl', 'storeutl', '-noout',
198                         '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
199                         catdir(curdir(), 'rehash')])));
200             ok(run(app(['openssl', 'storeutl', '-noout',
201                         '-subject',
202                         '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority',
203                         catdir(curdir(), 'rehash')])));
204             ok(run(app(['openssl', 'storeutl', '-noout', '-certs',
205                         '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
206                         catdir(curdir(), 'rehash')])));
207             ok(run(app(['openssl', 'storeutl', '-noout', '-crls',
208                         '-subject', '/C=AU/ST=QLD/CN=SSLeay\/rsa test cert',
209                         catdir(curdir(), 'rehash')])));
210             ok(run(app(['openssl', 'storeutl', '-noout', '-certs',
211                         '-subject',
212                         '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority',
213                         catdir(curdir(), 'rehash')])));
214             ok(run(app(['openssl', 'storeutl', '-noout', '-crls',
215                         '-subject',
216                         '/C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority',
217                         catdir(curdir(), 'rehash')])));
218         }
219     }
220 }, create => 1, cleanup => 1;
221
222 sub init {
223     return (
224             # rsa-key-pkcs1.pem
225             run(app(["openssl", "genrsa",
226                      "-out", "rsa-key-pkcs1.pem", "2432"]))
227             # dsa-key-pkcs1.pem
228             && run(app(["openssl", "dsaparam", "-genkey",
229                         "-out", "dsa-key-pkcs1.pem", "1024"]))
230             # ec-key-pkcs1.pem (one might think that 'genec' would be practical)
231             && run(app(["openssl", "ecparam", "-genkey", "-name", "prime256v1",
232                         "-out", "ec-key-pkcs1.pem"]))
233             # rsa-key-pkcs1-aes128.pem
234             && run(app(["openssl", "rsa", "-passout", "pass:password", "-aes128",
235                         "-in", "rsa-key-pkcs1.pem",
236                         "-out", "rsa-key-pkcs1-aes128.pem"]))
237             # dsa-key-pkcs1-aes128.pem
238             && run(app(["openssl", "dsa", "-passout", "pass:password", "-aes128",
239                         "-in", "dsa-key-pkcs1.pem",
240                         "-out", "dsa-key-pkcs1-aes128.pem"]))
241             # ec-key-pkcs1-aes128.pem
242             && run(app(["openssl", "ec", "-passout", "pass:password", "-aes128",
243                         "-in", "ec-key-pkcs1.pem",
244                         "-out", "ec-key-pkcs1-aes128.pem"]))
245             # *-key-pkcs8.pem
246             && runall(sub {
247                           my $dstfile = shift;
248                           (my $srcfile = $dstfile)
249                               =~ s/-key-pkcs8\.pem$/-key-pkcs1.pem/i;
250                           run(app(["openssl", "pkcs8", "-topk8", "-nocrypt",
251                                    "-in", $srcfile, "-out", $dstfile]));
252                       }, grep(/-key-pkcs8\.pem$/, @generated_files))
253             # *-key-pkcs8-pbes1-sha1-3des.pem
254             && runall(sub {
255                           my $dstfile = shift;
256                           (my $srcfile = $dstfile)
257                               =~ s/-key-pkcs8-pbes1-sha1-3des\.pem$
258                                   /-key-pkcs8.pem/ix;
259                           run(app(["openssl", "pkcs8", "-topk8",
260                                    "-passout", "pass:password",
261                                    "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
262                                    "-in", $srcfile, "-out", $dstfile]));
263                       }, grep(/-key-pkcs8-pbes1-sha1-3des\.pem$/, @generated_files))
264             # *-key-pkcs8-pbes1-md5-des.pem
265             && runall(sub {
266                           my $dstfile = shift;
267                           (my $srcfile = $dstfile)
268                               =~ s/-key-pkcs8-pbes1-md5-des\.pem$
269                                   /-key-pkcs8.pem/ix;
270                           run(app(["openssl", "pkcs8", "-topk8",
271                                    "-passout", "pass:password",
272                                    "-v1", "pbeWithSHA1And3-KeyTripleDES-CBC",
273                                    "-in", $srcfile, "-out", $dstfile]));
274                       }, grep(/-key-pkcs8-pbes1-md5-des\.pem$/, @generated_files))
275             # *-key-pkcs8-pbes2-sha1.pem
276             && runall(sub {
277                           my $dstfile = shift;
278                           (my $srcfile = $dstfile)
279                               =~ s/-key-pkcs8-pbes2-sha1\.pem$
280                                   /-key-pkcs8.pem/ix;
281                           run(app(["openssl", "pkcs8", "-topk8",
282                                    "-passout", "pass:password",
283                                    "-v2", "aes256", "-v2prf", "hmacWithSHA1",
284                                    "-in", $srcfile, "-out", $dstfile]));
285                       }, grep(/-key-pkcs8-pbes2-sha1\.pem$/, @generated_files))
286             # *-key-pkcs8-pbes2-sha1.pem
287             && runall(sub {
288                           my $dstfile = shift;
289                           (my $srcfile = $dstfile)
290                               =~ s/-key-pkcs8-pbes2-sha256\.pem$
291                                   /-key-pkcs8.pem/ix;
292                           run(app(["openssl", "pkcs8", "-topk8",
293                                    "-passout", "pass:password",
294                                    "-v2", "aes256", "-v2prf", "hmacWithSHA256",
295                                    "-in", $srcfile, "-out", $dstfile]));
296                       }, grep(/-key-pkcs8-pbes2-sha256\.pem$/, @generated_files))
297             # *-cert.pem (intermediary for the .p12 inits)
298             && run(app(["openssl", "req", "-x509",
299                         "-config", $cnf, "-nodes",
300                         "-out", "cacert.pem", "-keyout", "cakey.pem"]))
301             && runall(sub {
302                           my $srckey = shift;
303                           (my $dstfile = $srckey) =~ s|-key-pkcs8\.|-cert.|;
304                           (my $csr = $dstfile) =~ s|\.pem|.csr|;
305
306                           (run(app(["openssl", "req", "-new",
307                                     "-config", $cnf,
308                                     "-key", $srckey, "-out", $csr]))
309                            &&
310                            run(app(["openssl", "x509", "-days", "3650",
311                                     "-CA", "cacert.pem",
312                                     "-CAkey", "cakey.pem",
313                                     "-set_serial", time(), "-req",
314                                     "-in", $csr, "-out", $dstfile])));
315                       }, grep(/-key-pkcs8\.pem$/, @generated_files))
316             # *.p12
317             && runall(sub {
318                           my $dstfile = shift;
319                           my ($type, $certpbe_index, $keypbe_index,
320                               $macalg_index) =
321                               $dstfile =~ m{^(.*)-key-(?|
322                                                 # cert and key PBE are same
323                                                 ()             #
324                                                 ([^-]*-[^-]*)- # key & cert PBE
325                                                 ([^-]*)        # MACalg
326                                             |
327                                                 # cert and key PBE are not same
328                                                 ([^-]*-[^-]*)- # cert PBE
329                                                 ([^-]*-[^-]*)- # key PBE
330                                                 ([^-]*)        # MACalg
331                                             )\.}x;
332                           if (!$certpbe_index) {
333                               $certpbe_index = $keypbe_index;
334                           }
335                           my $srckey = "$type-key-pkcs8.pem";
336                           my $srccert = "$type-cert.pem";
337                           my %pbes =
338                               (
339                                "sha1-3des" => "pbeWithSHA1And3-KeyTripleDES-CBC",
340                                "md5-des" => "pbeWithMD5AndDES-CBC",
341                                "aes256-cbc" => "AES-256-CBC",
342                               );
343                           my %macalgs =
344                               (
345                                "sha1" => "SHA1",
346                                "sha256" => "SHA256",
347                               );
348                           my $certpbe = $pbes{$certpbe_index};
349                           my $keypbe = $pbes{$keypbe_index};
350                           my $macalg = $macalgs{$macalg_index};
351                           if (!defined($certpbe) || !defined($keypbe)
352                               || !defined($macalg)) {
353                               print STDERR "Cert PBE for $pbe_index not defined\n"
354                                   unless defined $certpbe;
355                               print STDERR "Key PBE for $pbe_index not defined\n"
356                                   unless defined $keypbe;
357                               print STDERR "MACALG for $macalg_index not defined\n"
358                                   unless defined $macalg;
359                               print STDERR "(destination file was $dstfile)\n";
360                               return 0;
361                           }
362                           run(app(["openssl", "pkcs12", "-inkey", $srckey,
363                                    "-in", $srccert, "-passout", "pass:password",
364                                    "-export", "-macalg", $macalg,
365                                    "-certpbe", $certpbe, "-keypbe", $keypbe,
366                                    "-out", $dstfile]));
367                       }, grep(/\.p12/, @generated_files))
368             # *.der (the end all init)
369             && runall(sub {
370                           my $dstfile = shift;
371                           (my $srcfile = $dstfile) =~ s/\.der$/.pem/i;
372                           if (! -f $srcfile) {
373                               $srcfile = srctop_file("test", $srcfile);
374                           }
375                           my $infh;
376                           unless (open $infh, $srcfile) {
377                               return 0;
378                           }
379                           my $l;
380                           while (($l = <$infh>) !~ /^-----BEGIN\s/
381                                  || $l =~ /^-----BEGIN.*PARAMETERS-----/) {
382                           }
383                           my $b64 = "";
384                           while (($l = <$infh>) !~ /^-----END\s/) {
385                               $l =~ s|\R$||;
386                               $b64 .= $l unless $l =~ /:/;
387                           }
388                           close $infh;
389                           my $der = decode_base64($b64);
390                           unless (length($b64) / 4 * 3 - length($der) < 3) {
391                               print STDERR "Length error, ",length($b64),
392                                   " bytes of base64 became ",length($der),
393                                   " bytes of der? ($srcfile => $dstfile)\n";
394                               return 0;
395                           }
396                           my $outfh;
397                           unless (open $outfh, ">:raw", $dstfile) {
398                               return 0;
399                           }
400                           print $outfh $der;
401                           close $outfh;
402                           return 1;
403                       }, grep(/\.der$/, @generated_files))
404             && runall(sub {
405                           my $srcfile = shift;
406                           my $dstfile = $generated_file_files{$srcfile};
407
408                           unless (copy srctop_file($srcfile), $dstfile) {
409                               warn "$!\n";
410                               return 0;
411                           }
412                           return 1;
413                       }, keys %generated_file_files)
414            );
415 }
416
417 sub init_rehash {
418     return (
419             mkdir(catdir(curdir(), 'rehash'))
420             && copy(srctop_file('test', 'testx509.pem'),
421                     catdir(curdir(), 'rehash'))
422             && copy(srctop_file('test', 'testcrl.pem'),
423                     catdir(curdir(), 'rehash'))
424             && run(app(['openssl', 'rehash', catdir(curdir(), 'rehash')]))
425            );
426 }
427
428 sub runall {
429     my ($function, @items) = @_;
430
431     foreach (@items) {
432         return 0 unless $function->($_);
433     }
434     return 1;
435 }
436
437 # According to RFC8089, a relative file: path is invalid.  We still produce
438 # them for testing purposes.
439 sub to_file_uri {
440     my ($file, $isdir, $authority) = @_;
441     my $vol;
442     my $dir;
443
444     die "to_file_uri: No file given\n" if !defined($file) || $file eq '';
445
446     ($vol, $dir, $file) = File::Spec->splitpath($file, $isdir // 0);
447
448     # Make sure we have a Unix style directory.
449     $dir = join('/', File::Spec->splitdir($dir));
450     # Canonicalise it (note: it seems to be only needed on Unix)
451     while (1) {
452         my $newdir = $dir;
453         $newdir =~ s|/[^/]*[^/\.]+[^/]*/\.\./|/|g;
454         last if $newdir eq $dir;
455         $dir = $newdir;
456     }
457     # Take care of the corner cases the loop can't handle, and that $dir
458     # ends with a / unless it's empty
459     $dir =~ s|/[^/]*[^/\.]+[^/]*/\.\.$|/|;
460     $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\./|/|;
461     $dir =~ s|^[^/]*[^/\.]+[^/]*/\.\.$||;
462     if ($isdir // 0) {
463         $dir =~ s|/$|| if $dir ne '/';
464     } else {
465         $dir .= '/' if $dir ne '' && $dir !~ m|/$|;
466     }
467
468     # If the file system has separate volumes (at present, Windows and VMS)
469     # we need to handle them.  In URIs, they are invariably the first
470     # component of the path, which is always absolute.
471     # On VMS, user:[foo.bar] translates to /user/foo/bar
472     # On Windows, c:\Users\Foo translates to /c:/Users/Foo
473     if ($vol ne '') {
474         $vol =~ s|:||g if ($^O eq "VMS");
475         $dir = '/' . $dir if $dir ne '' && $dir !~ m|^/|;
476         $dir = '/' . $vol . $dir;
477     }
478     $file = $dir . $file;
479
480     return "file://$authority$file" if defined $authority;
481     return "file:$file";
482 }
483
484 sub to_abs_file {
485     my ($file) = @_;
486
487     return File::Spec->rel2abs($file);
488 }
489
490 sub to_abs_file_uri {
491     my ($file, $isdir, $authority) = @_;
492
493     die "to_abs_file_uri: No file given\n" if !defined($file) || $file eq '';
494     return to_file_uri(to_abs_file($file), $isdir, $authority);
495 }