Add tests for (non-)default SKID and AKID inclusion by apps/{req,x509,ca}.c
[openssl.git] / test / recipes / 25-test_req.t
1 #! /usr/bin/env perl
2 # Copyright 2015-2020 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
10 use strict;
11 use warnings;
12
13 use OpenSSL::Test::Utils;
14 use OpenSSL::Test qw/:DEFAULT srctop_file/;
15
16 setup("test_req");
17
18 plan tests => 39;
19
20 require_ok(srctop_file('test','recipes','tconversion.pl'));
21
22 my @certs = qw(test certs);
23
24 # What type of key to generate?
25 my @req_new;
26 if (disabled("rsa")) {
27     @req_new = ("-newkey", "dsa:".srctop_file("apps", "dsa512.pem"));
28 } else {
29     @req_new = ("-new");
30     note("There should be a 2 sequences of .'s and some +'s.");
31     note("There should not be more that at most 80 per line");
32 }
33
34 # Check for duplicate -addext parameters, and one "working" case.
35 my @addext_args = ( "openssl", "req", "-new", "-out", "testreq.pem",
36     "-config", srctop_file("test", "test.cnf"), @req_new );
37 my $val = "subjectAltName=DNS:example.com";
38 my $val2 = " " . $val;
39 my $val3 = $val;
40 $val3 =~ s/=/    =/;
41 ok( run(app([@addext_args, "-addext", $val])));
42 ok(!run(app([@addext_args, "-addext", $val, "-addext", $val])));
43 ok(!run(app([@addext_args, "-addext", $val, "-addext", $val2])));
44 ok(!run(app([@addext_args, "-addext", $val, "-addext", $val3])));
45 ok(!run(app([@addext_args, "-addext", $val2, "-addext", $val3])));
46
47 subtest "generating alt certificate requests with RSA" => sub {
48     plan tests => 3;
49
50     SKIP: {
51         skip "RSA is not supported by this OpenSSL build", 2
52             if disabled("rsa");
53
54         ok(run(app(["openssl", "req",
55                     "-config", srctop_file("test", "test.cnf"),
56                     "-section", "altreq",
57                     "-new", "-out", "testreq-rsa.pem", "-utf8",
58                     "-key", srctop_file("test", "testrsa.pem")])),
59            "Generating request");
60
61         ok(run(app(["openssl", "req",
62                     "-config", srctop_file("test", "test.cnf"),
63                     "-verify", "-in", "testreq-rsa.pem", "-noout"])),
64            "Verifying signature on request");
65
66         ok(run(app(["openssl", "req",
67                     "-config", srctop_file("test", "test.cnf"),
68                     "-section", "altreq",
69                     "-verify", "-in", "testreq-rsa.pem", "-noout"])),
70            "Verifying signature on request");
71     }
72 };
73
74
75 subtest "generating certificate requests with RSA" => sub {
76     plan tests => 2;
77
78     SKIP: {
79         skip "RSA is not supported by this OpenSSL build", 2
80             if disabled("rsa");
81
82         ok(run(app(["openssl", "req",
83                     "-config", srctop_file("test", "test.cnf"),
84                     "-new", "-out", "testreq-rsa.pem", "-utf8",
85                     "-key", srctop_file("test", "testrsa.pem")])),
86            "Generating request");
87
88         ok(run(app(["openssl", "req",
89                     "-config", srctop_file("test", "test.cnf"),
90                     "-verify", "-in", "testreq-rsa.pem", "-noout"])),
91            "Verifying signature on request");
92     }
93 };
94
95 subtest "generating certificate requests with DSA" => sub {
96     plan tests => 2;
97
98     SKIP: {
99         skip "DSA is not supported by this OpenSSL build", 2
100             if disabled("dsa");
101
102         ok(run(app(["openssl", "req",
103                     "-config", srctop_file("test", "test.cnf"),
104                     "-new", "-out", "testreq-dsa.pem", "-utf8",
105                     "-key", srctop_file("test", "testdsa.pem")])),
106            "Generating request");
107
108         ok(run(app(["openssl", "req",
109                     "-config", srctop_file("test", "test.cnf"),
110                     "-verify", "-in", "testreq-dsa.pem", "-noout"])),
111            "Verifying signature on request");
112     }
113 };
114
115 subtest "generating certificate requests with ECDSA" => sub {
116     plan tests => 2;
117
118     SKIP: {
119         skip "ECDSA is not supported by this OpenSSL build", 2
120             if disabled("ec");
121
122         ok(run(app(["openssl", "req",
123                     "-config", srctop_file("test", "test.cnf"),
124                     "-new", "-out", "testreq-ec.pem", "-utf8",
125                     "-key", srctop_file("test", "testec-p256.pem")])),
126            "Generating request");
127
128         ok(run(app(["openssl", "req",
129                     "-config", srctop_file("test", "test.cnf"),
130                     "-verify", "-in", "testreq-ec.pem", "-noout"])),
131            "Verifying signature on request");
132     }
133 };
134
135 subtest "generating certificate requests with Ed25519" => sub {
136     plan tests => 2;
137
138     SKIP: {
139         skip "Ed25519 is not supported by this OpenSSL build", 2
140             if disabled("ec");
141
142         ok(run(app(["openssl", "req",
143                     "-config", srctop_file("test", "test.cnf"),
144                     "-new", "-out", "testreq-ed25519.pem", "-utf8",
145                     "-key", srctop_file("test", "tested25519.pem")])),
146            "Generating request");
147
148         ok(run(app(["openssl", "req",
149                     "-config", srctop_file("test", "test.cnf"),
150                     "-verify", "-in", "testreq-ed25519.pem", "-noout"])),
151            "Verifying signature on request");
152     }
153 };
154
155 subtest "generating certificate requests with Ed448" => sub {
156     plan tests => 2;
157
158     SKIP: {
159         skip "Ed448 is not supported by this OpenSSL build", 2
160             if disabled("ec");
161
162         ok(run(app(["openssl", "req",
163                     "-config", srctop_file("test", "test.cnf"),
164                     "-new", "-out", "testreq-ed448.pem", "-utf8",
165                     "-key", srctop_file("test", "tested448.pem")])),
166            "Generating request");
167
168         ok(run(app(["openssl", "req",
169                     "-config", srctop_file("test", "test.cnf"),
170                     "-verify", "-in", "testreq-ed448.pem", "-noout"])),
171            "Verifying signature on request");
172     }
173 };
174
175 subtest "generating certificate requests" => sub {
176     plan tests => 2;
177
178     ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"),
179                 @req_new, "-out", "testreq.pem"])),
180        "Generating request");
181
182     ok(run(app(["openssl", "req", "-config", srctop_file("test", "test.cnf"),
183                 "-verify", "-in", "testreq.pem", "-noout"])),
184        "Verifying signature on request");
185 };
186
187 subtest "generating SM2 certificate requests" => sub {
188     plan tests => 4;
189
190     SKIP: {
191         skip "SM2 is not supported by this OpenSSL build", 4
192         if disabled("sm2");
193         ok(run(app(["openssl", "req",
194                     "-config", srctop_file("test", "test.cnf"),
195                     "-new", "-key", srctop_file(@certs, "sm2.key"),
196                     "-sigopt", "distid:1234567812345678",
197                     "-out", "testreq-sm2.pem", "-sm3"])),
198            "Generating SM2 certificate request");
199
200         ok(run(app(["openssl", "req",
201                     "-config", srctop_file("test", "test.cnf"),
202                     "-verify", "-in", "testreq-sm2.pem", "-noout",
203                     "-vfyopt", "distid:1234567812345678", "-sm3"])),
204            "Verifying signature on SM2 certificate request");
205
206         ok(run(app(["openssl", "req",
207                     "-config", srctop_file("test", "test.cnf"),
208                     "-new", "-key", srctop_file(@certs, "sm2.key"),
209                     "-sigopt", "hexdistid:DEADBEEF",
210                     "-out", "testreq-sm2.pem", "-sm3"])),
211            "Generating SM2 certificate request with hex id");
212
213         ok(run(app(["openssl", "req",
214                     "-config", srctop_file("test", "test.cnf"),
215                     "-verify", "-in", "testreq-sm2.pem", "-noout",
216                     "-vfyopt", "hexdistid:DEADBEEF", "-sm3"])),
217            "Verifying signature on SM2 certificate request");
218     }
219 };
220
221 my @openssl_args = ("req", "-config", srctop_file("apps", "openssl.cnf"));
222
223 run_conversion('req conversions',
224                "testreq.pem");
225 run_conversion('req conversions -- testreq2',
226                srctop_file("test", "testreq2.pem"));
227
228 sub run_conversion {
229     my $title = shift;
230     my $reqfile = shift;
231
232     subtest $title => sub {
233         run(app(["openssl", @openssl_args,
234                  "-in", $reqfile, "-inform", "p",
235                  "-noout", "-text"],
236                 stderr => "req-check.err", stdout => undef));
237         open DATA, "req-check.err";
238         SKIP: {
239             plan skip_all => "skipping req conversion test for $reqfile"
240                 if grep /Unknown Public Key/, map { s/\R//; } <DATA>;
241
242             tconversion( -type => 'req', -in => $reqfile,
243                          -args => [ @openssl_args ] );
244         }
245         close DATA;
246         unlink "req-check.err";
247
248         done_testing();
249     };
250 }
251
252 # Test both generation and verification of certs w.r.t. RFC 5280 requirements
253
254 my $ca_cert; # will be set below
255 sub generate_cert {
256     my $cert = shift @_;
257     my $ss = $cert =~ m/self-signed/;
258     my $is_ca = $cert =~ m/CA/;
259     my $cn = $is_ca ? "CA" : "EE";
260     my $ca_key = srctop_file(@certs, "ca-key.pem");
261     my $key = $is_ca ? $ca_key : srctop_file(@certs, "ee-key.pem");
262     my @cmd = ("openssl", "req", "-config", "\"\"","-x509",
263                "-key", $key, "-subj", "/CN=$cn", @_, "-out", $cert);
264     push(@cmd, ("-CA", $ca_cert, "-CAkey", $ca_key)) unless $ss;
265     ok(run(app([@cmd])), "generate $cert");
266 }
267 sub has_SKID {
268     my $cert = shift @_;
269     my $expect = shift @_;
270     cert_contains($cert, "Subject Key Identifier", $expect);
271 }
272 sub has_AKID {
273     my $cert = shift @_;
274     my $expect = shift @_;
275     cert_contains($cert, "Authority Key Identifier", $expect);
276 }
277 sub strict_verify {
278     my $cert = shift @_;
279     my $expect = shift @_;
280     my $trusted = shift @_;
281     $trusted = $cert unless $trusted;
282     ok(run(app(["openssl", "verify", "-x509_strict", "-trusted", $trusted,
283                 "-partial_chain", $cert])) == $expect,
284        "strict verify allow $cert");
285 }
286
287 my @v3_ca = ("-addext", "basicConstraints = critical,CA:true",
288              "-addext", "keyUsage = keyCertSign");
289 my $cert = "self-signed_v1_CA_no_KIDs.pem";
290 generate_cert($cert);
291 has_SKID($ca_cert, 0);
292 has_AKID($ca_cert, 0);
293 #TODO strict_verify($cert, 1); # self-signed v1 root cert should be accepted as CA
294
295 $ca_cert = "self-signed_v3_CA_default_SKID.pem";
296 generate_cert($ca_cert, @v3_ca);
297 has_SKID($ca_cert, 1);
298 has_AKID($ca_cert, 0);
299 strict_verify($ca_cert, 1);
300
301 $cert = "self-signed_v3_CA_no_SKID.pem";
302 generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = none");
303 has_SKID($cert, 0);
304 has_AKID($cert, 0);
305 #TODO strict_verify($cert, 0);
306
307 $cert = "self-signed_v3_CA_both_KIDs.pem";
308 generate_cert($cert, @v3_ca, "-addext", "subjectKeyIdentifier = hash",
309             "-addext", "authorityKeyIdentifier = keyid");
310 has_SKID($cert, 1);
311 has_AKID($cert, 1);
312 strict_verify($cert, 1);
313
314 $cert = "self-signed_v3_EE_wrong_keyUsage.pem";
315 generate_cert($cert, "-addext", "keyUsage = keyCertSign");
316 #TODO strict_verify($cert, 1); # should be accepted because RFC 5280 does not apply
317
318 $cert = "v3_EE_default_KIDs.pem";
319 generate_cert($cert, "-addext", "keyUsage = dataEncipherment");
320 has_SKID($cert, 1);
321 has_AKID($cert, 1);
322 strict_verify($cert, 1, $ca_cert);
323
324 $cert = "v3_EE_no_AKID.pem";
325 generate_cert($cert, "-addext", "authorityKeyIdentifier = none");
326 has_SKID($cert, 1);
327 has_AKID($cert, 0);
328 strict_verify($cert, 0, $ca_cert);