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