|
1 | 1 | #!{- $config{HASHBANGPERL} -}
|
2 |
| -# Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. |
| 2 | +# Copyright 2000-2020 The OpenSSL Project Authors. All Rights Reserved. |
3 | 3 | #
|
4 |
| -# Licensed under the OpenSSL license (the "License"). You may not use |
| 4 | +# Licensed under the Apache License 2.0 (the "License"). You may not use |
5 | 5 | # this file except in compliance with the License. You can obtain a copy
|
6 | 6 | # in the file LICENSE in the source distribution or at
|
7 | 7 | # https://www.openssl.org/source/license.html
|
|
14 | 14 | use strict;
|
15 | 15 | use warnings;
|
16 | 16 |
|
17 |
| -my $openssl = "openssl"; |
18 |
| -if(defined $ENV{'OPENSSL'}) { |
19 |
| - $openssl = $ENV{'OPENSSL'}; |
20 |
| -} else { |
21 |
| - $ENV{'OPENSSL'} = $openssl; |
22 |
| -} |
23 |
| - |
24 | 17 | my $verbose = 1;
|
| 18 | +my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); |
25 | 19 |
|
26 |
| -my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || ""; |
27 |
| -my $DAYS = "-days 365"; |
28 |
| -my $CADAYS = "-days 1095"; # 3 years |
| 20 | +my $openssl = $ENV{'OPENSSL'} // "openssl"; |
| 21 | +$ENV{'OPENSSL'} = $openssl; |
| 22 | +my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // ""; |
| 23 | + |
| 24 | +# Command invocations. |
29 | 25 | my $REQ = "$openssl req $OPENSSL_CONFIG";
|
30 | 26 | my $CA = "$openssl ca $OPENSSL_CONFIG";
|
31 | 27 | my $VERIFY = "$openssl verify";
|
32 | 28 | my $X509 = "$openssl x509";
|
33 | 29 | my $PKCS12 = "$openssl pkcs12";
|
34 | 30 |
|
35 |
| -# default openssl.cnf file has setup as per the following |
| 31 | +# Default values for various configuration settings. |
36 | 32 | my $CATOP = "./demoCA";
|
37 | 33 | my $CAKEY = "cakey.pem";
|
38 | 34 | my $CAREQ = "careq.pem";
|
39 | 35 | my $CACERT = "cacert.pem";
|
40 | 36 | my $CACRL = "crl.pem";
|
41 |
| -my $DIRMODE = 0777; |
42 |
| - |
| 37 | +my $DAYS = "-days 365"; |
| 38 | +my $CADAYS = "-days 1095"; # 3 years |
43 | 39 | my $NEWKEY = "newkey.pem";
|
44 | 40 | my $NEWREQ = "newreq.pem";
|
45 | 41 | my $NEWCERT = "newcert.pem";
|
46 | 42 | my $NEWP12 = "newcert.p12";
|
47 |
| -my $RET = 0; |
| 43 | + |
| 44 | +# Commandline parsing |
| 45 | +my %EXTRA; |
48 | 46 | my $WHAT = shift @ARGV || "";
|
49 |
| -my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); |
50 |
| -my %EXTRA = extra_args(\@ARGV, "-extra-"); |
51 |
| -my $FILE; |
52 |
| - |
53 |
| -sub extra_args { |
54 |
| - my ($args_ref, $arg_prefix) = @_; |
55 |
| - my %eargs = map { |
56 |
| - if ($_ < $#$args_ref) { |
57 |
| - my ($arg, $value) = splice(@$args_ref, $_, 2); |
58 |
| - $arg =~ s/$arg_prefix//; |
59 |
| - ($arg, $value); |
60 |
| - } else { |
61 |
| - (); |
62 |
| - } |
63 |
| - } reverse grep($$args_ref[$_] =~ /$arg_prefix/, 0..$#$args_ref); |
64 |
| - my %empty = map { ($_, "") } @OPENSSL_CMDS; |
65 |
| - return (%empty, %eargs); |
| 47 | +@ARGV = parse_extra(@ARGV); |
| 48 | +my $RET = 0; |
| 49 | + |
| 50 | +# Split out "-extra-CMD value", and return new |@ARGV|. Fill in |
| 51 | +# |EXTRA{CMD}| with list of values. |
| 52 | +sub parse_extra |
| 53 | +{ |
| 54 | + foreach ( @OPENSSL_CMDS ) { |
| 55 | + $EXTRA{$_} = ''; |
| 56 | + } |
| 57 | + |
| 58 | + my @result; |
| 59 | + while ( scalar(@_) > 0 ) { |
| 60 | + my $arg = shift; |
| 61 | + if ( $arg !~ m/-extra-([a-z0-9]+)/ ) { |
| 62 | + push @result, $arg; |
| 63 | + next; |
| 64 | + } |
| 65 | + $arg =~ s/-extra-//; |
| 66 | + die("Unknown \"-${arg}-extra\" option, exiting") |
| 67 | + unless scalar grep { $arg eq $_ } @OPENSSL_CMDS; |
| 68 | + $EXTRA{$arg} .= " " . shift; |
| 69 | + } |
| 70 | + return @result; |
66 | 71 | }
|
67 | 72 |
|
| 73 | + |
68 | 74 | # See if reason for a CRL entry is valid; exit if not.
|
69 | 75 | sub crl_reason_ok
|
70 | 76 | {
|
@@ -113,83 +119,97 @@ sub run
|
113 | 119 |
|
114 | 120 |
|
115 | 121 | if ( $WHAT =~ /^(-\?|-h|-help)$/ ) {
|
116 |
| - print STDERR "usage: CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd extra-params]\n"; |
117 |
| - print STDERR " CA.pl -pkcs12 [-extra-pkcs12 extra-params] [certname]\n"; |
118 |
| - print STDERR " CA.pl -verify [-extra-verify extra-params] certfile ...\n"; |
119 |
| - print STDERR " CA.pl -revoke [-extra-ca extra-params] certfile [reason]\n"; |
| 122 | + print STDERR <<EOF; |
| 123 | +Usage: |
| 124 | + CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter] |
| 125 | + CA.pl -pkcs12 [-extra-pkcs12 parameter] [certname] |
| 126 | + CA.pl -verify [-extra-verify parameter] certfile ... |
| 127 | + CA.pl -revoke [-extra-ca parameter] certfile [reason] |
| 128 | +EOF |
120 | 129 | exit 0;
|
121 | 130 | }
|
| 131 | + |
122 | 132 | if ($WHAT eq '-newcert' ) {
|
123 | 133 | # create a certificate
|
124 |
| - $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS $EXTRA{req}"); |
| 134 | + $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS" |
| 135 | + . " $EXTRA{req}"); |
125 | 136 | print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
|
126 | 137 | } elsif ($WHAT eq '-precert' ) {
|
127 | 138 | # create a pre-certificate
|
128 |
| - $RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"); |
| 139 | + $RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS" |
| 140 | + . " $EXTRA{req}"); |
129 | 141 | print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
|
130 | 142 | } elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) {
|
131 | 143 | # create a certificate request
|
132 | 144 | $RET = run("$REQ -new $1 -keyout $NEWKEY -out $NEWREQ $DAYS $EXTRA{req}");
|
133 | 145 | print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
|
134 | 146 | } elsif ($WHAT eq '-newca' ) {
|
135 | 147 | # create the directory hierarchy
|
136 |
| - mkdir ${CATOP}, $DIRMODE; |
137 |
| - mkdir "${CATOP}/certs", $DIRMODE; |
138 |
| - mkdir "${CATOP}/crl", $DIRMODE ; |
139 |
| - mkdir "${CATOP}/newcerts", $DIRMODE; |
140 |
| - mkdir "${CATOP}/private", $DIRMODE; |
| 148 | + my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl", |
| 149 | + "${CATOP}/newcerts", "${CATOP}/private" ); |
| 150 | + die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed," |
| 151 | + if -f "${CATOP}/index.txt"; |
| 152 | + die "${CATOP}/serial exists.\nRemove old sub-tree to proceed," |
| 153 | + if -f "${CATOP}/serial"; |
| 154 | + foreach my $d ( @dirs ) { |
| 155 | + if ( -d $d ) { |
| 156 | + warn "Directory $d exists" if -d $d; |
| 157 | + } else { |
| 158 | + mkdir $d or die "Can't mkdir $d, $!"; |
| 159 | + } |
| 160 | + } |
| 161 | + |
141 | 162 | open OUT, ">${CATOP}/index.txt";
|
142 | 163 | close OUT;
|
143 | 164 | open OUT, ">${CATOP}/crlnumber";
|
144 | 165 | print OUT "01\n";
|
145 | 166 | close OUT;
|
146 | 167 | # ask user for existing CA certificate
|
147 | 168 | print "CA certificate filename (or enter to create)\n";
|
| 169 | + my $FILE; |
148 | 170 | $FILE = "" unless defined($FILE = <STDIN>);
|
149 | 171 | $FILE =~ s{\R$}{};
|
150 | 172 | if ($FILE ne "") {
|
151 | 173 | copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");
|
152 | 174 | copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
|
153 | 175 | } else {
|
154 | 176 | print "Making CA certificate ...\n";
|
155 |
| - $RET = run("$REQ -new -keyout" |
156 |
| - . " ${CATOP}/private/$CAKEY" |
| 177 | + $RET = run("$REQ -new -keyout ${CATOP}/private/$CAKEY" |
157 | 178 | . " -out ${CATOP}/$CAREQ $EXTRA{req}");
|
158 | 179 | $RET = run("$CA -create_serial"
|
159 | 180 | . " -out ${CATOP}/$CACERT $CADAYS -batch"
|
160 | 181 | . " -keyfile ${CATOP}/private/$CAKEY -selfsign"
|
161 |
| - . " -extensions v3_ca $EXTRA{ca}" |
162 |
| - . " -infiles ${CATOP}/$CAREQ") if $RET == 0; |
| 182 | + . " -extensions v3_ca" |
| 183 | + . " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0; |
163 | 184 | print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;
|
164 | 185 | }
|
165 | 186 | } elsif ($WHAT eq '-pkcs12' ) {
|
166 | 187 | my $cname = $ARGV[0];
|
167 | 188 | $cname = "My Certificate" unless defined $cname;
|
168 | 189 | $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY"
|
169 |
| - . " -certfile ${CATOP}/$CACERT" |
170 |
| - . " -out $NEWP12" |
| 190 | + . " -certfile ${CATOP}/$CACERT -out $NEWP12" |
171 | 191 | . " -export -name \"$cname\" $EXTRA{pkcs12}");
|
172 | 192 | print "PKCS #12 file is in $NEWP12\n" if $RET == 0;
|
173 | 193 | } elsif ($WHAT eq '-xsign' ) {
|
174 |
| - $RET = run("$CA -policy policy_anything $EXTRA{ca} -infiles $NEWREQ"); |
| 194 | + $RET = run("$CA -policy policy_anything -infiles $NEWREQ $EXTRA{ca}"); |
175 | 195 | } elsif ($WHAT eq '-sign' ) {
|
176 |
| - $RET = run("$CA -policy policy_anything -out $NEWCERT $EXTRA{ca} -infiles $NEWREQ"); |
| 196 | + $RET = run("$CA -policy policy_anything -out $NEWCERT" |
| 197 | + . " -infiles $NEWREQ $EXTRA{ca}"); |
177 | 198 | print "Signed certificate is in $NEWCERT\n" if $RET == 0;
|
178 | 199 | } elsif ($WHAT eq '-signCA' ) {
|
179 | 200 | $RET = run("$CA -policy policy_anything -out $NEWCERT"
|
180 |
| - . " -extensions v3_ca $EXTRA{ca} -infiles $NEWREQ"); |
| 201 | + . " -extensions v3_ca -infiles $NEWREQ $EXTRA{ca}"); |
181 | 202 | print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;
|
182 | 203 | } elsif ($WHAT eq '-signcert' ) {
|
183 | 204 | $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ"
|
184 | 205 | . " -out tmp.pem $EXTRA{x509}");
|
185 | 206 | $RET = run("$CA -policy policy_anything -out $NEWCERT"
|
186 |
| - . "$EXTRA{ca} -infiles tmp.pem") if $RET == 0; |
| 207 | + . "-infiles tmp.pem $EXTRA{ca}") if $RET == 0; |
187 | 208 | print "Signed certificate is in $NEWCERT\n" if $RET == 0;
|
188 | 209 | } elsif ($WHAT eq '-verify' ) {
|
189 | 210 | my @files = @ARGV ? @ARGV : ( $NEWCERT );
|
190 |
| - my $file; |
191 |
| - foreach $file (@files) { |
192 |
| - my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}"); |
| 211 | + foreach my $file (@files) { |
| 212 | + my $status = run("$VERIFY -CAfile ${CATOP}/$CACERT $file $EXTRA{verify}"); |
193 | 213 | $RET = $status if $status != 0;
|
194 | 214 | }
|
195 | 215 | } elsif ($WHAT eq '-crl' ) {
|
|
0 commit comments