]>
Commit | Line | Data |
---|---|---|
1 | #! /usr/bin/env perl | |
2 | # Copyright 2016-2024 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 strict; | |
10 | use warnings; | |
11 | ||
12 | use OpenSSL::Test qw/:DEFAULT srctop_file with/; | |
13 | use OpenSSL::Test::Utils; | |
14 | ||
15 | use Encode; | |
16 | ||
17 | setup("test_pkcs12"); | |
18 | ||
19 | my $pass = "σύνθημα γνώρισμα"; | |
20 | ||
21 | my $savedcp; | |
22 | if (eval { require Win32::API; 1; }) { | |
23 | # Trouble is that Win32 perl uses CreateProcessA, which | |
24 | # makes it problematic to pass non-ASCII arguments, from perl[!] | |
25 | # that is. This is because CreateProcessA is just a wrapper for | |
26 | # CreateProcessW and will call MultiByteToWideChar and use | |
27 | # system default locale. Since we attempt Greek pass-phrase | |
28 | # conversion can be done only with Greek locale. | |
29 | ||
30 | Win32::API->Import("kernel32","UINT GetSystemDefaultLCID()"); | |
31 | if (GetSystemDefaultLCID() != 0x408) { | |
32 | plan skip_all => "Non-Greek system locale"; | |
33 | } else { | |
34 | # Ensure correct code page so that VERBOSE output is right. | |
35 | Win32::API->Import("kernel32","UINT GetConsoleOutputCP()"); | |
36 | Win32::API->Import("kernel32","BOOL SetConsoleOutputCP(UINT cp)"); | |
37 | $savedcp = GetConsoleOutputCP(); | |
38 | SetConsoleOutputCP(1253); | |
39 | $pass = Encode::encode("cp1253",Encode::decode("utf-8",$pass)); | |
40 | } | |
41 | } elsif ($^O eq "MSWin32") { | |
42 | plan skip_all => "Win32::API unavailable"; | |
43 | } elsif ($^O ne "VMS") { | |
44 | # Running MinGW tests transparently under Wine apparently requires | |
45 | # UTF-8 locale... | |
46 | ||
47 | foreach(`locale -a`) { | |
48 | s/\R$//; | |
49 | if ($_ =~ m/^C\.UTF\-?8/i) { | |
50 | $ENV{LC_ALL} = $_; | |
51 | last; | |
52 | } | |
53 | } | |
54 | } | |
55 | $ENV{OPENSSL_WIN32_UTF8}=1; | |
56 | ||
57 | plan tests => 31; | |
58 | ||
59 | # Test different PKCS#12 formats | |
60 | ok(run(test(["pkcs12_format_test"])), "test pkcs12 formats"); | |
61 | # Test with legacy APIs | |
62 | ok(run(test(["pkcs12_format_test", "-legacy"])), "test pkcs12 formats using legacy APIs"); | |
63 | # Test with a non-default library context (and no loaded providers in the default context) | |
64 | ok(run(test(["pkcs12_format_test", "-context"])), "test pkcs12 formats using a non-default library context"); | |
65 | ||
66 | SKIP: { | |
67 | skip "VMS doesn't have command line UTF-8 support yet in DCL", 1 | |
68 | if $^O eq "VMS"; | |
69 | ||
70 | # just see that we can read shibboleth.pfx protected with $pass | |
71 | ok(run(app(["openssl", "pkcs12", "-noout", | |
72 | "-password", "pass:$pass", | |
73 | "-in", srctop_file("test", "shibboleth.pfx")])), | |
74 | "test_load_cert_pkcs12"); | |
75 | } | |
76 | ||
77 | my @path = qw(test certs); | |
78 | my $outfile1 = "out1.p12"; | |
79 | my $outfile2 = "out2.p12"; | |
80 | my $outfile3 = "out3.p12"; | |
81 | my $outfile4 = "out4.p12"; | |
82 | my $outfile5 = "out5.p12"; | |
83 | my $outfile6 = "out6.p12"; | |
84 | my $outfile7 = "out7.p12"; | |
85 | ||
86 | # Test the -chain option with -untrusted | |
87 | ok(run(app(["openssl", "pkcs12", "-export", "-chain", | |
88 | "-CAfile", srctop_file(@path, "sroot-cert.pem"), | |
89 | "-untrusted", srctop_file(@path, "ca-cert.pem"), | |
90 | "-in", srctop_file(@path, "ee-cert.pem"), | |
91 | "-nokeys", "-passout", "pass:", "-out", $outfile1])), | |
92 | "test_pkcs12_chain_untrusted"); | |
93 | ||
94 | # Test the -passcerts option | |
95 | SKIP: { | |
96 | skip "Skipping PKCS#12 test because DES is disabled in this build", 1 | |
97 | if disabled("des"); | |
98 | ok(run(app(["openssl", "pkcs12", "-export", | |
99 | "-in", srctop_file(@path, "ee-cert.pem"), | |
100 | "-certfile", srctop_file(@path, "v3-certs-TDES.p12"), | |
101 | "-passcerts", "pass:v3-certs", | |
102 | "-nokeys", "-passout", "pass:v3-certs", "-descert", | |
103 | "-out", $outfile2])), | |
104 | "test_pkcs12_passcerts"); | |
105 | } | |
106 | ||
107 | SKIP: { | |
108 | skip "Skipping legacy PKCS#12 test because the required algorithms are disabled", 1 | |
109 | if disabled("des") || disabled("rc2") || disabled("legacy"); | |
110 | # Test reading legacy PKCS#12 file | |
111 | ok(run(app(["openssl", "pkcs12", "-export", | |
112 | "-in", srctop_file(@path, "v3-certs-RC2.p12"), | |
113 | "-passin", "pass:v3-certs", | |
114 | "-provider", "default", "-provider", "legacy", | |
115 | "-nokeys", "-passout", "pass:v3-certs", "-descert", | |
116 | "-out", $outfile3])), | |
117 | "test_pkcs12_passcerts_legacy"); | |
118 | } | |
119 | ||
120 | # Test export of PEM file with both cert and key | |
121 | # -nomac necessary to avoid legacy provider requirement | |
122 | ok(run(app(["openssl", "pkcs12", "-export", | |
123 | "-inkey", srctop_file(@path, "cert-key-cert.pem"), | |
124 | "-in", srctop_file(@path, "cert-key-cert.pem"), | |
125 | "-passout", "pass:v3-certs", | |
126 | "-nomac", "-out", $outfile4], stderr => "outerr.txt")), | |
127 | "test_export_pkcs12_cert_key_cert"); | |
128 | open DATA, "outerr.txt"; | |
129 | my @match = grep /:error:/, <DATA>; | |
130 | close DATA; | |
131 | ok(scalar @match > 0 ? 0 : 1, "test_export_pkcs12_outerr_empty"); | |
132 | ||
133 | ok(run(app(["openssl", "pkcs12", | |
134 | "-in", $outfile4, | |
135 | "-passin", "pass:v3-certs", | |
136 | "-nomacver", "-nodes"])), | |
137 | "test_import_pkcs12_cert_key_cert"); | |
138 | ||
139 | ok(run(app(["openssl", "pkcs12", "-export", "-out", $outfile5, | |
140 | "-in", srctop_file(@path, "ee-cert.pem"), "-caname", "testname", | |
141 | "-nokeys", "-passout", "pass:", "-certpbe", "NONE"])), | |
142 | "test nokeys single cert"); | |
143 | ||
144 | my @pkcs12info = run(app(["openssl", "pkcs12", "-info", "-in", $outfile5, | |
145 | "-passin", "pass:"]), capture => 1); | |
146 | ||
147 | # Test that with one input certificate, we get one output certificate | |
148 | ok(grep(/subject=CN\s*=\s*server.example/, @pkcs12info) == 1, | |
149 | "test one cert in output"); | |
150 | ||
151 | # Test that the expected friendly name is present in the output | |
152 | ok(grep(/testname/, @pkcs12info) == 1, "test friendly name in output"); | |
153 | ||
154 | # Test there's no Oracle Trusted Key Usage bag attribute | |
155 | ok(grep(/Trusted key usage (Oracle)/, @pkcs12info) == 0, | |
156 | "test no oracle trusted key usage"); | |
157 | ||
158 | # Test export of PEM file with both cert and key, without password. | |
159 | # -nomac necessary to avoid legacy provider requirement | |
160 | { | |
161 | ok(run(app(["openssl", "pkcs12", "-export", | |
162 | "-inkey", srctop_file(@path, "cert-key-cert.pem"), | |
163 | "-in", srctop_file(@path, "cert-key-cert.pem"), | |
164 | "-passout", "pass:", | |
165 | "-nomac", "-out", $outfile6], stderr => "outerr6.txt")), | |
166 | "test_export_pkcs12_cert_key_cert_no_pass"); | |
167 | open DATA, "outerr6.txt"; | |
168 | my @match = grep /:error:/, <DATA>; | |
169 | close DATA; | |
170 | ok(scalar @match > 0 ? 0 : 1, "test_export_pkcs12_outerr6_empty"); | |
171 | } | |
172 | ||
173 | # Test some bad pkcs12 files | |
174 | my $bad1 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad1.p12"); | |
175 | my $bad2 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad2.p12"); | |
176 | my $bad3 = srctop_file("test", "recipes", "80-test_pkcs12_data", "bad3.p12"); | |
177 | ||
178 | with({ exit_checker => sub { return shift == 1; } }, | |
179 | sub { | |
180 | ok(run(app(["openssl", "pkcs12", "-in", $bad1, "-password", "pass:"])), | |
181 | "test bad pkcs12 file 1"); | |
182 | ||
183 | ok(run(app(["openssl", "pkcs12", "-in", $bad1, "-password", "pass:", | |
184 | "-nomacver"])), | |
185 | "test bad pkcs12 file 1 (nomacver)"); | |
186 | ||
187 | ok(run(app(["openssl", "pkcs12", "-in", $bad1, "-password", "pass:", | |
188 | "-info"])), | |
189 | "test bad pkcs12 file 1 (info)"); | |
190 | ||
191 | ok(run(app(["openssl", "pkcs12", "-in", $bad2, "-password", "pass:"])), | |
192 | "test bad pkcs12 file 2"); | |
193 | ||
194 | ok(run(app(["openssl", "pkcs12", "-in", $bad2, "-password", "pass:", | |
195 | "-info"])), | |
196 | "test bad pkcs12 file 2 (info)"); | |
197 | ||
198 | ok(run(app(["openssl", "pkcs12", "-in", $bad3, "-password", "pass:"])), | |
199 | "test bad pkcs12 file 3"); | |
200 | ||
201 | ok(run(app(["openssl", "pkcs12", "-in", $bad3, "-password", "pass:", | |
202 | "-info"])), | |
203 | "test bad pkcs12 file 3 (info)"); | |
204 | }); | |
205 | ||
206 | # Test with Oracle Trusted Key Usage specified in openssl.cnf | |
207 | { | |
208 | ok(run(app(["openssl", "pkcs12", "-export", "-out", $outfile7, | |
209 | "-jdktrust", "anyExtendedKeyUsage", "-in", srctop_file(@path, "ee-cert.pem"), | |
210 | "-nokeys", "-passout", "pass:", "-certpbe", "NONE"])), | |
211 | "test nokeys single cert"); | |
212 | ||
213 | my @pkcs12info = run(app(["openssl", "pkcs12", "-info", "-in", $outfile7, | |
214 | "-passin", "pass:"]), capture => 1); | |
215 | ok(grep(/Trusted key usage \(Oracle\): Any Extended Key Usage \(2.5.29.37.0\)/, @pkcs12info) == 1, | |
216 | "test oracle trusted key usage is set"); | |
217 | ||
218 | delete $ENV{OPENSSL_CONF} | |
219 | } | |
220 | ||
221 | # Tests for pkcs12_parse | |
222 | ok(run(test(["pkcs12_api_test", | |
223 | "-in", $outfile1, | |
224 | "-has-ca", 1, | |
225 | ])), "Test pkcs12_parse()"); | |
226 | ||
227 | SKIP: { | |
228 | skip "Skipping PKCS#12 parse test because DES is disabled in this build", 1 | |
229 | if disabled("des"); | |
230 | ok(run(test(["pkcs12_api_test", | |
231 | "-in", $outfile2, | |
232 | "-pass", "v3-certs", | |
233 | "-has-ca", 1, | |
234 | ])), "Test pkcs12_parse()"); | |
235 | } | |
236 | ||
237 | SKIP: { | |
238 | skip "Skipping PKCS#12 parse test because the required algorithms are disabled", 1 | |
239 | if disabled("des") || disabled("rc2") || disabled("legacy"); | |
240 | ok(run(test(["pkcs12_api_test", | |
241 | "-in", $outfile3, | |
242 | "-pass", "v3-certs", | |
243 | "-has-ca", 1, | |
244 | ])), "Test pkcs12_parse()"); | |
245 | } | |
246 | ||
247 | ok(run(test(["pkcs12_api_test", | |
248 | "-in", $outfile4, | |
249 | "-pass", "v3-certs", | |
250 | "-has-ca", 1, | |
251 | "-has-key", 1, | |
252 | "-has-cert", 1, | |
253 | ])), "Test pkcs12_parse()"); | |
254 | ||
255 | ok(run(test(["pkcs12_api_test", | |
256 | "-in", $outfile5, | |
257 | "-has-ca", 1, | |
258 | ])), "Test pkcs12_parse()"); | |
259 | ||
260 | ok(run(test(["pkcs12_api_test", | |
261 | "-in", $outfile6, | |
262 | "-pass", "", | |
263 | "-has-ca", 1, | |
264 | "-has-key", 1, | |
265 | "-has-cert", 1, | |
266 | ])), "Test pkcs12_parse()"); | |
267 | ||
268 | SetConsoleOutputCP($savedcp) if (defined($savedcp)); |