]>
Commit | Line | Data |
---|---|---|
abe256e7 | 1 | #!{- $config{HASHBANGPERL} -} |
b0edda11 | 2 | # Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. |
e0a65194 RS |
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 | ||
8f3e97ba | 9 | # |
5a3aa852 | 10 | # Wrapper around the ca to make it easier to use |
9ab6fc59 RL |
11 | # |
12 | # {- join("\n# ", @autowarntext) -} | |
8f3e97ba | 13 | |
5a3aa852 RS |
14 | use strict; |
15 | use warnings; | |
16 | ||
17 | my $openssl = "openssl"; | |
18 | if(defined $ENV{'OPENSSL'}) { | |
19 | $openssl = $ENV{'OPENSSL'}; | |
62d27939 | 20 | } else { |
5a3aa852 | 21 | $ENV{'OPENSSL'} = $openssl; |
62d27939 AP |
22 | } |
23 | ||
5a3aa852 | 24 | my $verbose = 1; |
8f3e97ba | 25 | |
35b060fc | 26 | my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || ""; |
5a3aa852 RS |
27 | my $DAYS = "-days 365"; |
28 | my $CADAYS = "-days 1095"; # 3 years | |
b0700d2c RS |
29 | my $REQ = "$openssl req $OPENSSL_CONFIG"; |
30 | my $CA = "$openssl ca $OPENSSL_CONFIG"; | |
5a3aa852 RS |
31 | my $VERIFY = "$openssl verify"; |
32 | my $X509 = "$openssl x509"; | |
33 | my $PKCS12 = "$openssl pkcs12"; | |
8f3e97ba | 34 | |
5a3aa852 RS |
35 | # default openssl.cnf file has setup as per the following |
36 | my $CATOP = "./demoCA"; | |
37 | my $CAKEY = "cakey.pem"; | |
38 | my $CAREQ = "careq.pem"; | |
39 | my $CACERT = "cacert.pem"; | |
40 | my $CACRL = "crl.pem"; | |
41 | my $DIRMODE = 0777; | |
8f3e97ba | 42 | |
5a3aa852 RS |
43 | my $NEWKEY = "newkey.pem"; |
44 | my $NEWREQ = "newreq.pem"; | |
45 | my $NEWCERT = "newcert.pem"; | |
46 | my $NEWP12 = "newcert.p12"; | |
47 | my $RET = 0; | |
35b060fc | 48 | my $WHAT = shift @ARGV || ""; |
022696ca | 49 | my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); |
50 | my %EXTRA = extra_args(\@ARGV, "-extra-"); | |
5a3aa852 | 51 | my $FILE; |
8f3e97ba | 52 | |
022696ca | 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); | |
66 | } | |
67 | ||
5a3aa852 RS |
68 | # See if reason for a CRL entry is valid; exit if not. |
69 | sub crl_reason_ok | |
70 | { | |
71 | my $r = shift; | |
8f3e97ba | 72 | |
5a3aa852 RS |
73 | if ($r eq 'unspecified' || $r eq 'keyCompromise' |
74 | || $r eq 'CACompromise' || $r eq 'affiliationChanged' | |
75 | || $r eq 'superseded' || $r eq 'cessationOfOperation' | |
76 | || $r eq 'certificateHold' || $r eq 'removeFromCRL') { | |
77 | return 1; | |
78 | } | |
79 | print STDERR "Invalid CRL reason; must be one of:\n"; | |
80 | print STDERR " unspecified, keyCompromise, CACompromise,\n"; | |
81 | print STDERR " affiliationChanged, superseded, cessationOfOperation\n"; | |
82 | print STDERR " certificateHold, removeFromCRL"; | |
83 | exit 1; | |
8f3e97ba | 84 | } |
85 | ||
5a3aa852 RS |
86 | # Copy a PEM-format file; return like exit status (zero means ok) |
87 | sub copy_pemfile | |
88 | { | |
89 | my ($infile, $outfile, $bound) = @_; | |
90 | my $found = 0; | |
8f3e97ba | 91 | |
5a3aa852 RS |
92 | open IN, $infile || die "Cannot open $infile, $!"; |
93 | open OUT, ">$outfile" || die "Cannot write to $outfile, $!"; | |
94 | while (<IN>) { | |
95 | $found = 1 if /^-----BEGIN.*$bound/; | |
96 | print OUT $_ if $found; | |
97 | $found = 2, last if /^-----END.*$bound/; | |
98 | } | |
99 | close IN; | |
100 | close OUT; | |
101 | return $found == 2 ? 0 : 1; | |
98ecf60b D |
102 | } |
103 | ||
5a3aa852 RS |
104 | # Wrapper around system; useful for debugging. Returns just the exit status |
105 | sub run | |
106 | { | |
107 | my $cmd = shift; | |
108 | print "====\n$cmd\n" if $verbose; | |
109 | my $status = system($cmd); | |
110 | print "==> $status\n====\n" if $verbose; | |
111 | return $status >> 8; | |
8f3e97ba | 112 | } |
5a3aa852 RS |
113 | |
114 | ||
115 | if ( $WHAT =~ /^(-\?|-h|-help)$/ ) { | |
022696ca | 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"; | |
5a3aa852 RS |
120 | exit 0; |
121 | } | |
122 | if ($WHAT eq '-newcert' ) { | |
123 | # create a certificate | |
022696ca | 124 | $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS $EXTRA{req}"); |
5a3aa852 | 125 | print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; |
505fb999 | 126 | } elsif ($WHAT eq '-precert' ) { |
b6486bf7 | 127 | # create a pre-certificate |
65b3dff7 | 128 | $RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"); |
b6486bf7 | 129 | print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; |
32cd4733 | 130 | } elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) { |
5a3aa852 | 131 | # create a certificate request |
fa4dd546 | 132 | $RET = run("$REQ -new $1 -keyout $NEWKEY -out $NEWREQ $DAYS $EXTRA{req}"); |
5a3aa852 RS |
133 | print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; |
134 | } elsif ($WHAT eq '-newca' ) { | |
135 | # 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; | |
141 | open OUT, ">${CATOP}/index.txt"; | |
142 | close OUT; | |
143 | open OUT, ">${CATOP}/crlnumber"; | |
144 | print OUT "01\n"; | |
145 | close OUT; | |
146 | # ask user for existing CA certificate | |
147 | print "CA certificate filename (or enter to create)\n"; | |
ce3d25d3 VD |
148 | $FILE = "" unless defined($FILE = <STDIN>); |
149 | $FILE =~ s{\R$}{}; | |
150 | if ($FILE ne "") { | |
5a3aa852 RS |
151 | copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE"); |
152 | copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); | |
153 | } else { | |
154 | print "Making CA certificate ...\n"; | |
155 | $RET = run("$REQ -new -keyout" | |
156 | . " ${CATOP}/private/$CAKEY" | |
022696ca | 157 | . " -out ${CATOP}/$CAREQ $EXTRA{req}"); |
5a3aa852 RS |
158 | $RET = run("$CA -create_serial" |
159 | . " -out ${CATOP}/$CACERT $CADAYS -batch" | |
160 | . " -keyfile ${CATOP}/private/$CAKEY -selfsign" | |
022696ca | 161 | . " -extensions v3_ca $EXTRA{ca}" |
5a3aa852 RS |
162 | . " -infiles ${CATOP}/$CAREQ") if $RET == 0; |
163 | print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0; | |
164 | } | |
165 | } elsif ($WHAT eq '-pkcs12' ) { | |
1e2804f2 | 166 | my $cname = $ARGV[0]; |
5a3aa852 RS |
167 | $cname = "My Certificate" unless defined $cname; |
168 | $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY" | |
169 | . " -certfile ${CATOP}/$CACERT" | |
170 | . " -out $NEWP12" | |
022696ca | 171 | . " -export -name \"$cname\" $EXTRA{pkcs12}"); |
5a3aa852 RS |
172 | print "PKCS #12 file is in $NEWP12\n" if $RET == 0; |
173 | } elsif ($WHAT eq '-xsign' ) { | |
022696ca | 174 | $RET = run("$CA -policy policy_anything $EXTRA{ca} -infiles $NEWREQ"); |
5a3aa852 | 175 | } elsif ($WHAT eq '-sign' ) { |
022696ca | 176 | $RET = run("$CA -policy policy_anything -out $NEWCERT $EXTRA{ca} -infiles $NEWREQ"); |
5a3aa852 RS |
177 | print "Signed certificate is in $NEWCERT\n" if $RET == 0; |
178 | } elsif ($WHAT eq '-signCA' ) { | |
179 | $RET = run("$CA -policy policy_anything -out $NEWCERT" | |
022696ca | 180 | . " -extensions v3_ca $EXTRA{ca} -infiles $NEWREQ"); |
5a3aa852 RS |
181 | print "Signed CA certificate is in $NEWCERT\n" if $RET == 0; |
182 | } elsif ($WHAT eq '-signcert' ) { | |
183 | $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ" | |
022696ca | 184 | . " -out tmp.pem $EXTRA{x509}"); |
5a3aa852 | 185 | $RET = run("$CA -policy policy_anything -out $NEWCERT" |
022696ca | 186 | . "$EXTRA{ca} -infiles tmp.pem") if $RET == 0; |
5a3aa852 RS |
187 | print "Signed certificate is in $NEWCERT\n" if $RET == 0; |
188 | } elsif ($WHAT eq '-verify' ) { | |
33fbca83 RS |
189 | my @files = @ARGV ? @ARGV : ( $NEWCERT ); |
190 | my $file; | |
5a3aa852 | 191 | foreach $file (@files) { |
022696ca | 192 | my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}"); |
5a3aa852 RS |
193 | $RET = $status if $status != 0; |
194 | } | |
195 | } elsif ($WHAT eq '-crl' ) { | |
022696ca | 196 | $RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL $EXTRA{ca}"); |
5a3aa852 RS |
197 | print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0; |
198 | } elsif ($WHAT eq '-revoke' ) { | |
1e2804f2 | 199 | my $cname = $ARGV[0]; |
5a3aa852 RS |
200 | if (!defined $cname) { |
201 | print "Certificate filename is required; reason optional.\n"; | |
202 | exit 1; | |
203 | } | |
1e2804f2 | 204 | my $reason = $ARGV[1]; |
5a3aa852 RS |
205 | $reason = " -crl_reason $reason" |
206 | if defined $reason && crl_reason_ok($reason); | |
022696ca | 207 | $RET = run("$CA -revoke \"$cname\"" . $reason . $EXTRA{ca}); |
5a3aa852 RS |
208 | } else { |
209 | print STDERR "Unknown arg \"$WHAT\"\n"; | |
210 | print STDERR "Use -help for help.\n"; | |
211 | exit 1; | |
8f3e97ba | 212 | } |
213 | ||
5a3aa852 | 214 | exit $RET; |