]>
Commit | Line | Data |
---|---|---|
5a3aa852 | 1 | #!/usr/bin/perl |
8f3e97ba | 2 | # |
5a3aa852 RS |
3 | # Wrapper around the ca to make it easier to use |
4 | # Edit CA.pl.in not CA.pl! | |
8f3e97ba | 5 | |
8f3e97ba | 6 | |
5a3aa852 RS |
7 | use strict; |
8 | use warnings; | |
9 | ||
10 | my $openssl = "openssl"; | |
11 | if(defined $ENV{'OPENSSL'}) { | |
12 | $openssl = $ENV{'OPENSSL'}; | |
62d27939 | 13 | } else { |
5a3aa852 | 14 | $ENV{'OPENSSL'} = $openssl; |
62d27939 AP |
15 | } |
16 | ||
5a3aa852 | 17 | my $verbose = 1; |
8f3e97ba | 18 | |
b0700d2c | 19 | my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"}; |
5a3aa852 RS |
20 | my $DAYS = "-days 365"; |
21 | my $CADAYS = "-days 1095"; # 3 years | |
b0700d2c RS |
22 | my $REQ = "$openssl req $OPENSSL_CONFIG"; |
23 | my $CA = "$openssl ca $OPENSSL_CONFIG"; | |
5a3aa852 RS |
24 | my $VERIFY = "$openssl verify"; |
25 | my $X509 = "$openssl x509"; | |
26 | my $PKCS12 = "$openssl pkcs12"; | |
8f3e97ba | 27 | |
5a3aa852 RS |
28 | # default openssl.cnf file has setup as per the following |
29 | my $CATOP = "./demoCA"; | |
30 | my $CAKEY = "cakey.pem"; | |
31 | my $CAREQ = "careq.pem"; | |
32 | my $CACERT = "cacert.pem"; | |
33 | my $CACRL = "crl.pem"; | |
34 | my $DIRMODE = 0777; | |
8f3e97ba | 35 | |
5a3aa852 RS |
36 | my $NEWKEY = "newkey.pem"; |
37 | my $NEWREQ = "newreq.pem"; | |
38 | my $NEWCERT = "newcert.pem"; | |
39 | my $NEWP12 = "newcert.p12"; | |
40 | my $RET = 0; | |
41 | my $WHAT = shift @ARGV; | |
42 | my $FILE; | |
8f3e97ba | 43 | |
5a3aa852 RS |
44 | # See if reason for a CRL entry is valid; exit if not. |
45 | sub crl_reason_ok | |
46 | { | |
47 | my $r = shift; | |
8f3e97ba | 48 | |
5a3aa852 RS |
49 | if ($r eq 'unspecified' || $r eq 'keyCompromise' |
50 | || $r eq 'CACompromise' || $r eq 'affiliationChanged' | |
51 | || $r eq 'superseded' || $r eq 'cessationOfOperation' | |
52 | || $r eq 'certificateHold' || $r eq 'removeFromCRL') { | |
53 | return 1; | |
54 | } | |
55 | print STDERR "Invalid CRL reason; must be one of:\n"; | |
56 | print STDERR " unspecified, keyCompromise, CACompromise,\n"; | |
57 | print STDERR " affiliationChanged, superseded, cessationOfOperation\n"; | |
58 | print STDERR " certificateHold, removeFromCRL"; | |
59 | exit 1; | |
8f3e97ba | 60 | } |
61 | ||
5a3aa852 RS |
62 | # Copy a PEM-format file; return like exit status (zero means ok) |
63 | sub copy_pemfile | |
64 | { | |
65 | my ($infile, $outfile, $bound) = @_; | |
66 | my $found = 0; | |
8f3e97ba | 67 | |
5a3aa852 RS |
68 | open IN, $infile || die "Cannot open $infile, $!"; |
69 | open OUT, ">$outfile" || die "Cannot write to $outfile, $!"; | |
70 | while (<IN>) { | |
71 | $found = 1 if /^-----BEGIN.*$bound/; | |
72 | print OUT $_ if $found; | |
73 | $found = 2, last if /^-----END.*$bound/; | |
74 | } | |
75 | close IN; | |
76 | close OUT; | |
77 | return $found == 2 ? 0 : 1; | |
98ecf60b D |
78 | } |
79 | ||
5a3aa852 RS |
80 | # Wrapper around system; useful for debugging. Returns just the exit status |
81 | sub run | |
82 | { | |
83 | my $cmd = shift; | |
84 | print "====\n$cmd\n" if $verbose; | |
85 | my $status = system($cmd); | |
86 | print "==> $status\n====\n" if $verbose; | |
87 | return $status >> 8; | |
8f3e97ba | 88 | } |
5a3aa852 RS |
89 | |
90 | ||
91 | if ( $WHAT =~ /^(-\?|-h|-help)$/ ) { | |
92 | print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-verify\n"; | |
93 | print STDERR " CA -pkcs12 [certname]\n"; | |
94 | print STDERR " CA -crl|-revoke cert-filename [reason]\n"; | |
95 | exit 0; | |
96 | } | |
97 | if ($WHAT eq '-newcert' ) { | |
98 | # create a certificate | |
99 | $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS"); | |
100 | print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; | |
101 | } elsif ($WHAT eq '-newreq' ) { | |
102 | # create a certificate request | |
103 | $RET = run("$REQ -new -keyout $NEWKEY -out $NEWREQ $DAYS"); | |
104 | print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; | |
105 | } elsif ($WHAT eq '-newreq-nodes' ) { | |
106 | # create a certificate request | |
107 | $RET = run("$REQ -new -nodes -keyout $NEWKEY -out $NEWREQ $DAYS"); | |
108 | print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; | |
109 | } elsif ($WHAT eq '-newca' ) { | |
110 | # create the directory hierarchy | |
111 | mkdir ${CATOP}, $DIRMODE; | |
112 | mkdir "${CATOP}/certs", $DIRMODE; | |
113 | mkdir "${CATOP}/crl", $DIRMODE ; | |
114 | mkdir "${CATOP}/newcerts", $DIRMODE; | |
115 | mkdir "${CATOP}/private", $DIRMODE; | |
116 | open OUT, ">${CATOP}/index.txt"; | |
117 | close OUT; | |
118 | open OUT, ">${CATOP}/crlnumber"; | |
119 | print OUT "01\n"; | |
120 | close OUT; | |
121 | # ask user for existing CA certificate | |
122 | print "CA certificate filename (or enter to create)\n"; | |
123 | $FILE = <STDIN>; | |
0fd75c7e | 124 | chop $FILE if $FILE; |
5a3aa852 RS |
125 | if ($FILE) { |
126 | copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE"); | |
127 | copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); | |
128 | } else { | |
129 | print "Making CA certificate ...\n"; | |
130 | $RET = run("$REQ -new -keyout" | |
131 | . " ${CATOP}/private/$CAKEY" | |
132 | . " -out ${CATOP}/$CAREQ"); | |
133 | $RET = run("$CA -create_serial" | |
134 | . " -out ${CATOP}/$CACERT $CADAYS -batch" | |
135 | . " -keyfile ${CATOP}/private/$CAKEY -selfsign" | |
136 | . " -extensions v3_ca" | |
137 | . " -infiles ${CATOP}/$CAREQ") if $RET == 0; | |
138 | print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0; | |
139 | } | |
140 | } elsif ($WHAT eq '-pkcs12' ) { | |
141 | my $cname = $ARGV[1]; | |
142 | $cname = "My Certificate" unless defined $cname; | |
143 | $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY" | |
144 | . " -certfile ${CATOP}/$CACERT" | |
145 | . " -out $NEWP12" | |
146 | . " -export -name \"$cname\""); | |
147 | print "PKCS #12 file is in $NEWP12\n" if $RET == 0; | |
148 | } elsif ($WHAT eq '-xsign' ) { | |
149 | $RET = run("$CA -policy policy_anything -infiles $NEWREQ"); | |
150 | } elsif ($WHAT eq '-sign' ) { | |
151 | $RET = run("$CA -policy policy_anything -out $NEWCERT -infiles $NEWREQ"); | |
152 | print "Signed certificate is in $NEWCERT\n" if $RET == 0; | |
153 | } elsif ($WHAT eq '-signCA' ) { | |
154 | $RET = run("$CA -policy policy_anything -out $NEWCERT" | |
155 | . " -extensions v3_ca -infiles $NEWREQ"); | |
156 | print "Signed CA certificate is in $NEWCERT\n" if $RET == 0; | |
157 | } elsif ($WHAT eq '-signcert' ) { | |
158 | $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ" | |
159 | . " -out tmp.pem"); | |
160 | $RET = run("$CA -policy policy_anything -out $NEWCERT" | |
161 | . " -infiles tmp.pem") if $RET == 0; | |
162 | print "Signed certificate is in $NEWCERT\n" if $RET == 0; | |
163 | } elsif ($WHAT eq '-verify' ) { | |
33fbca83 RS |
164 | my @files = @ARGV ? @ARGV : ( $NEWCERT ); |
165 | my $file; | |
5a3aa852 | 166 | foreach $file (@files) { |
ac33c5a4 | 167 | my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file"); |
5a3aa852 RS |
168 | $RET = $status if $status != 0; |
169 | } | |
170 | } elsif ($WHAT eq '-crl' ) { | |
171 | $RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL"); | |
172 | print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0; | |
173 | } elsif ($WHAT eq '-revoke' ) { | |
174 | my $cname = $ARGV[1]; | |
175 | if (!defined $cname) { | |
176 | print "Certificate filename is required; reason optional.\n"; | |
177 | exit 1; | |
178 | } | |
179 | my $reason = $ARGV[2]; | |
180 | $reason = " -crl_reason $reason" | |
181 | if defined $reason && crl_reason_ok($reason); | |
182 | $RET = run("$CA -revoke \"$cname\"" . $reason); | |
183 | } else { | |
184 | print STDERR "Unknown arg \"$WHAT\"\n"; | |
185 | print STDERR "Use -help for help.\n"; | |
186 | exit 1; | |
8f3e97ba | 187 | } |
188 | ||
5a3aa852 | 189 | exit $RET; |