CA.pl.in 6.6 KB
Newer Older
1
#!{- $config{hashbangperl} -}
R
Rich Salz 已提交
2 3 4 5 6 7 8
# Copyright 2000-2016 The OpenSSL Project Authors. All Rights Reserved.
#
# Licensed under the OpenSSL license (the "License").  You may not use
# this file except in compliance with the License.  You can obtain a copy
# in the file LICENSE in the source distribution or at
# https://www.openssl.org/source/license.html

9
#
R
Rich Salz 已提交
10
# Wrapper around the ca to make it easier to use
R
Richard Levitte 已提交
11 12
#
# {- join("\n# ", @autowarntext) -}
13

R
Rich Salz 已提交
14 15 16 17 18 19
use strict;
use warnings;

my $openssl = "openssl";
if(defined $ENV{'OPENSSL'}) {
    $openssl = $ENV{'OPENSSL'};
20
} else {
R
Rich Salz 已提交
21
    $ENV{'OPENSSL'} = $openssl;
22 23
}

R
Rich Salz 已提交
24
my $verbose = 1;
25

26
my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || "";
R
Rich Salz 已提交
27 28
my $DAYS = "-days 365";
my $CADAYS = "-days 1095";	# 3 years
R
Rich Salz 已提交
29 30
my $REQ = "$openssl req $OPENSSL_CONFIG";
my $CA = "$openssl ca $OPENSSL_CONFIG";
R
Rich Salz 已提交
31 32 33
my $VERIFY = "$openssl verify";
my $X509 = "$openssl x509";
my $PKCS12 = "$openssl pkcs12";
34

R
Rich Salz 已提交
35 36 37 38 39 40 41
# default openssl.cnf file has setup as per the following
my $CATOP = "./demoCA";
my $CAKEY = "cakey.pem";
my $CAREQ = "careq.pem";
my $CACERT = "cacert.pem";
my $CACRL = "crl.pem";
my $DIRMODE = 0777;
42

R
Rich Salz 已提交
43 44 45 46 47
my $NEWKEY = "newkey.pem";
my $NEWREQ = "newreq.pem";
my $NEWCERT = "newcert.pem";
my $NEWP12 = "newcert.p12";
my $RET = 0;
48
my $WHAT = shift @ARGV || "";
R
Rich Salz 已提交
49
my $FILE;
50

R
Rich Salz 已提交
51 52 53 54
# See if reason for a CRL entry is valid; exit if not.
sub crl_reason_ok
{
    my $r = shift;
55

R
Rich Salz 已提交
56 57 58 59 60 61 62 63 64 65 66
    if ($r eq 'unspecified' || $r eq 'keyCompromise'
        || $r eq 'CACompromise' || $r eq 'affiliationChanged'
        || $r eq 'superseded' || $r eq 'cessationOfOperation'
        || $r eq 'certificateHold' || $r eq 'removeFromCRL') {
        return 1;
    }
    print STDERR "Invalid CRL reason; must be one of:\n";
    print STDERR "    unspecified, keyCompromise, CACompromise,\n";
    print STDERR "    affiliationChanged, superseded, cessationOfOperation\n";
    print STDERR "    certificateHold, removeFromCRL";
    exit 1;
67 68
}

R
Rich Salz 已提交
69 70 71 72 73
# Copy a PEM-format file; return like exit status (zero means ok)
sub copy_pemfile
{
    my ($infile, $outfile, $bound) = @_;
    my $found = 0;
74

R
Rich Salz 已提交
75 76 77 78 79 80 81 82 83 84
    open IN, $infile || die "Cannot open $infile, $!";
    open OUT, ">$outfile" || die "Cannot write to $outfile, $!";
    while (<IN>) {
        $found = 1 if /^-----BEGIN.*$bound/;
        print OUT $_ if $found;
        $found = 2, last if /^-----END.*$bound/;
    }
    close IN;
    close OUT;
    return $found == 2 ? 0 : 1;
85 86
}

R
Rich Salz 已提交
87 88 89 90 91 92 93 94
# Wrapper around system; useful for debugging.  Returns just the exit status
sub run
{
    my $cmd = shift;
    print "====\n$cmd\n" if $verbose;
    my $status = system($cmd);
    print "==> $status\n====\n" if $verbose;
    return $status >> 8;
95
}
R
Rich Salz 已提交
96 97 98


if ( $WHAT =~ /^(-\?|-h|-help)$/ ) {
99
    print STDERR "usage: CA -newcert|-newreq|-newreq-nodes|-newca|-sign|-signcert|-verify\n";
R
Rich Salz 已提交
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
    print STDERR "       CA -pkcs12 [certname]\n";
    print STDERR "       CA -crl|-revoke cert-filename [reason]\n";
    exit 0;
}
if ($WHAT eq '-newcert' ) {
    # create a certificate
    $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS");
    print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-newreq' ) {
    # create a certificate request
    $RET = run("$REQ -new -keyout $NEWKEY -out $NEWREQ $DAYS");
    print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-newreq-nodes' ) {
    # create a certificate request
    $RET = run("$REQ -new -nodes -keyout $NEWKEY -out $NEWREQ $DAYS");
    print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-newca' ) {
    # create the directory hierarchy
    mkdir ${CATOP}, $DIRMODE;
    mkdir "${CATOP}/certs", $DIRMODE;
    mkdir "${CATOP}/crl", $DIRMODE ;
    mkdir "${CATOP}/newcerts", $DIRMODE;
    mkdir "${CATOP}/private", $DIRMODE;
    open OUT, ">${CATOP}/index.txt";
    close OUT;
    open OUT, ">${CATOP}/crlnumber";
    print OUT "01\n";
    close OUT;
    # ask user for existing CA certificate
    print "CA certificate filename (or enter to create)\n";
130 131 132
    $FILE = "" unless defined($FILE = <STDIN>);
    $FILE =~ s{\R$}{};
    if ($FILE ne "") {
R
Rich Salz 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
        copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");
        copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
    } else {
        print "Making CA certificate ...\n";
        $RET = run("$REQ -new -keyout"
                . " ${CATOP}/private/$CAKEY"
                . " -out ${CATOP}/$CAREQ");
        $RET = run("$CA -create_serial"
                . " -out ${CATOP}/$CACERT $CADAYS -batch"
                . " -keyfile ${CATOP}/private/$CAKEY -selfsign"
                . " -extensions v3_ca"
                . " -infiles ${CATOP}/$CAREQ") if $RET == 0;
        print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;
    }
} elsif ($WHAT eq '-pkcs12' ) {
    my $cname = $ARGV[1];
    $cname = "My Certificate" unless defined $cname;
    $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY"
            . " -certfile ${CATOP}/$CACERT"
            . " -out $NEWP12"
            . " -export -name \"$cname\"");
    print "PKCS #12 file is in $NEWP12\n" if $RET == 0;
} elsif ($WHAT eq '-xsign' ) {
    $RET = run("$CA -policy policy_anything -infiles $NEWREQ");
} elsif ($WHAT eq '-sign' ) {
    $RET = run("$CA -policy policy_anything -out $NEWCERT -infiles $NEWREQ");
    print "Signed certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-signCA' ) {
    $RET = run("$CA -policy policy_anything -out $NEWCERT"
            . " -extensions v3_ca -infiles $NEWREQ");
    print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-signcert' ) {
    $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ"
            . " -out tmp.pem");
    $RET = run("$CA -policy policy_anything -out $NEWCERT"
            . " -infiles tmp.pem") if $RET == 0;
    print "Signed certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-verify' ) {
R
Rich Salz 已提交
171 172
    my @files = @ARGV ? @ARGV : ( $NEWCERT );
    my $file;
R
Rich Salz 已提交
173
    foreach $file (@files) {
174
        my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file");
R
Rich Salz 已提交
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
        $RET = $status if $status != 0;
    }
} elsif ($WHAT eq '-crl' ) {
    $RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL");
    print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0;
} elsif ($WHAT eq '-revoke' ) {
    my $cname = $ARGV[1];
    if (!defined $cname) {
        print "Certificate filename is required; reason optional.\n";
        exit 1;
    }
    my $reason = $ARGV[2];
    $reason = " -crl_reason $reason"
        if defined $reason && crl_reason_ok($reason);
    $RET = run("$CA -revoke \"$cname\"" . $reason);
} else {
    print STDERR "Unknown arg \"$WHAT\"\n";
    print STDERR "Use -help for help.\n";
    exit 1;
194 195
}

R
Rich Salz 已提交
196
exit $RET;