xref: /freebsd/crypto/openssl/apps/CA.pl (revision 267f8c1f4b09431b335d5f48d84586047471f978)
1*267f8c1fSEnji Cooper#!/usr/bin/env perl
24757b351SPierre Pronchery# Copyright 2000-2025 The OpenSSL Project Authors. All Rights Reserved.
34757b351SPierre Pronchery#
44757b351SPierre Pronchery# Licensed under the Apache License 2.0 (the "License").  You may not use
54757b351SPierre Pronchery# this file except in compliance with the License.  You can obtain a copy
64757b351SPierre Pronchery# in the file LICENSE in the source distribution or at
74757b351SPierre Pronchery# https://www.openssl.org/source/license.html
84757b351SPierre Pronchery
94757b351SPierre Pronchery#
104757b351SPierre Pronchery# Wrapper around the ca to make it easier to use
114757b351SPierre Pronchery#
124757b351SPierre Pronchery# WARNING: do not edit!
134757b351SPierre Pronchery# Generated by Makefile from apps/CA.pl.in
144757b351SPierre Pronchery
154757b351SPierre Proncheryuse strict;
164757b351SPierre Proncheryuse warnings;
174757b351SPierre Pronchery
184757b351SPierre Proncherymy $verbose = 1;
194757b351SPierre Proncherymy @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify");
204757b351SPierre Pronchery
214757b351SPierre Proncherymy $openssl = $ENV{'OPENSSL'} // "openssl";
224757b351SPierre Pronchery$ENV{'OPENSSL'} = $openssl;
234757b351SPierre Proncherymy @openssl = split_val($openssl);
244757b351SPierre Pronchery
254757b351SPierre Proncherymy $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // "";
264757b351SPierre Proncherymy @OPENSSL_CONFIG = split_val($OPENSSL_CONFIG);
274757b351SPierre Pronchery
284757b351SPierre Pronchery# Command invocations.
294757b351SPierre Proncherymy @REQ = (@openssl, "req", @OPENSSL_CONFIG);
304757b351SPierre Proncherymy @CA = (@openssl, "ca", @OPENSSL_CONFIG);
314757b351SPierre Proncherymy @VERIFY = (@openssl, "verify");
324757b351SPierre Proncherymy @X509 = (@openssl, "x509");
334757b351SPierre Proncherymy @PKCS12 = (@openssl, "pkcs12");
344757b351SPierre Pronchery
354757b351SPierre Pronchery# Default values for various configuration settings.
364757b351SPierre Proncherymy $CATOP = "./demoCA";
374757b351SPierre Proncherymy $CAKEY = "cakey.pem";
384757b351SPierre Proncherymy $CAREQ = "careq.pem";
394757b351SPierre Proncherymy $CACERT = "cacert.pem";
404757b351SPierre Proncherymy $CACRL = "crl.pem";
414757b351SPierre Proncherymy @DAYS = qw(-days 365);
424757b351SPierre Proncherymy @CADAYS = qw(-days 1095);	# 3 years
434757b351SPierre Proncherymy @EXTENSIONS = qw(-extensions v3_ca);
444757b351SPierre Proncherymy @POLICY = qw(-policy policy_anything);
454757b351SPierre Proncherymy $NEWKEY = "newkey.pem";
464757b351SPierre Proncherymy $NEWREQ = "newreq.pem";
474757b351SPierre Proncherymy $NEWCERT = "newcert.pem";
484757b351SPierre Proncherymy $NEWP12 = "newcert.p12";
494757b351SPierre Pronchery
504757b351SPierre Pronchery# Commandline parsing
514757b351SPierre Proncherymy %EXTRA;
524757b351SPierre Proncherymy $WHAT = shift @ARGV // "";
534757b351SPierre Pronchery@ARGV = parse_extra(@ARGV);
544757b351SPierre Proncherymy $RET = 0;
554757b351SPierre Pronchery
564757b351SPierre Proncherysub split_val {
574757b351SPierre Pronchery    return split_val_win32(@_) if ($^O eq 'MSWin32');
584757b351SPierre Pronchery    my ($val) = @_;
594757b351SPierre Pronchery    my (@ret, @frag);
604757b351SPierre Pronchery
614757b351SPierre Pronchery    # Skip leading whitespace
624757b351SPierre Pronchery    $val =~ m{\A[ \t]*}ogc;
634757b351SPierre Pronchery
644757b351SPierre Pronchery    # Unix shell-compatible split
654757b351SPierre Pronchery    #
664757b351SPierre Pronchery    # Handles backslash escapes outside quotes and
674757b351SPierre Pronchery    # in double-quoted strings.  Parameter and
684757b351SPierre Pronchery    # command-substitution is silently ignored.
694757b351SPierre Pronchery    # Bare newlines outside quotes and (trailing) backslashes are disallowed.
704757b351SPierre Pronchery
714757b351SPierre Pronchery    while (1) {
724757b351SPierre Pronchery        last if (pos($val) == length($val));
734757b351SPierre Pronchery
744757b351SPierre Pronchery        # The first char is never a SPACE or TAB.  Possible matches are:
754757b351SPierre Pronchery        # 1. Ordinary string fragment
764757b351SPierre Pronchery        # 2. Single-quoted string
774757b351SPierre Pronchery        # 3. Double-quoted string
784757b351SPierre Pronchery        # 4. Backslash escape
794757b351SPierre Pronchery        # 5. Bare backlash or newline (rejected)
804757b351SPierre Pronchery        #
814757b351SPierre Pronchery        if ($val =~ m{\G([^'" \t\n\\]+)}ogc) {
824757b351SPierre Pronchery            # Ordinary string
834757b351SPierre Pronchery            push @frag, $1;
844757b351SPierre Pronchery        } elsif ($val =~ m{\G'([^']*)'}ogc) {
854757b351SPierre Pronchery            # Single-quoted string
864757b351SPierre Pronchery            push @frag, $1;
874757b351SPierre Pronchery        } elsif ($val =~ m{\G"}ogc) {
884757b351SPierre Pronchery            # Double-quoted string
894757b351SPierre Pronchery            push @frag, "";
904757b351SPierre Pronchery            while (1) {
914757b351SPierre Pronchery                last if ($val =~ m{\G"}ogc);
924757b351SPierre Pronchery                if ($val =~ m{\G([^"\\]+)}ogcs) {
934757b351SPierre Pronchery                    # literals
944757b351SPierre Pronchery                    push @frag, $1;
954757b351SPierre Pronchery                } elsif ($val =~ m{\G.(["\`\$\\])}ogc) {
964757b351SPierre Pronchery                    # backslash-escaped special
974757b351SPierre Pronchery                    push @frag, $1;
984757b351SPierre Pronchery                } elsif ($val =~ m{\G.(.)}ogcs) {
994757b351SPierre Pronchery                    # backslashed non-special
1004757b351SPierre Pronchery                    push @frag, "\\$1" unless $1 eq "\n";
1014757b351SPierre Pronchery                } else {
1024757b351SPierre Pronchery                    die sprintf("Malformed quoted string: %s\n", $val);
1034757b351SPierre Pronchery                }
1044757b351SPierre Pronchery            }
1054757b351SPierre Pronchery        } elsif ($val =~ m{\G\\(.)}ogc) {
1064757b351SPierre Pronchery            # Backslash is unconditional escape outside quoted strings
1074757b351SPierre Pronchery            push @frag, $1 unless $1 eq "\n";
1084757b351SPierre Pronchery        } else {
1094757b351SPierre Pronchery            die sprintf("Bare backslash or newline in: '%s'\n", $val);
1104757b351SPierre Pronchery        }
1114757b351SPierre Pronchery        # Done if at SPACE, TAB or end, otherwise continue current fragment
1124757b351SPierre Pronchery        #
1134757b351SPierre Pronchery        next unless ($val =~ m{\G(?:[ \t]+|\z)}ogcs);
1144757b351SPierre Pronchery        push @ret, join("", splice(@frag)) if (@frag > 0);
1154757b351SPierre Pronchery    }
1164757b351SPierre Pronchery    # Handle final fragment
1174757b351SPierre Pronchery    push @ret, join("", splice(@frag)) if (@frag > 0);
1184757b351SPierre Pronchery    return @ret;
1194757b351SPierre Pronchery}
1204757b351SPierre Pronchery
1214757b351SPierre Proncherysub split_val_win32 {
1224757b351SPierre Pronchery    my ($val) = @_;
1234757b351SPierre Pronchery    my (@ret, @frag);
1244757b351SPierre Pronchery
1254757b351SPierre Pronchery    # Skip leading whitespace
1264757b351SPierre Pronchery    $val =~ m{\A[ \t]*}ogc;
1274757b351SPierre Pronchery
1284757b351SPierre Pronchery    # Windows-compatible split
1294757b351SPierre Pronchery    # See: "Parsing C++ command-line arguments" in:
1304757b351SPierre Pronchery    # https://learn.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-170
1314757b351SPierre Pronchery    #
1324757b351SPierre Pronchery    # Backslashes are special only when followed by a double-quote
1334757b351SPierre Pronchery    # Pairs of double-quotes make a single double-quote.
1344757b351SPierre Pronchery    # Closing double-quotes may be omitted.
1354757b351SPierre Pronchery
1364757b351SPierre Pronchery    while (1) {
1374757b351SPierre Pronchery        last if (pos($val) == length($val));
1384757b351SPierre Pronchery
1394757b351SPierre Pronchery        # The first char is never a SPACE or TAB.
1404757b351SPierre Pronchery        # 1. Ordinary string fragment
1414757b351SPierre Pronchery        # 2. Double-quoted string
1424757b351SPierre Pronchery        # 3. Backslashes preceding a double-quote
1434757b351SPierre Pronchery        # 4. Literal backslashes
1444757b351SPierre Pronchery        # 5. Bare newline (rejected)
1454757b351SPierre Pronchery        #
1464757b351SPierre Pronchery        if ($val =~ m{\G([^" \t\n\\]+)}ogc) {
1474757b351SPierre Pronchery            # Ordinary string
1484757b351SPierre Pronchery            push @frag, $1;
1494757b351SPierre Pronchery        } elsif ($val =~ m{\G"}ogc) {
1504757b351SPierre Pronchery            # Double-quoted string
1514757b351SPierre Pronchery            push @frag, "";
1524757b351SPierre Pronchery            while (1) {
1534757b351SPierre Pronchery                if ($val =~ m{\G("+)}ogc) {
1544757b351SPierre Pronchery                    # Two double-quotes make one literal double-quote
1554757b351SPierre Pronchery                    my $l = length($1);
1564757b351SPierre Pronchery                    push @frag, q{"} x int($l/2) if ($l > 1);
1574757b351SPierre Pronchery                    next if ($l % 2 == 0);
1584757b351SPierre Pronchery                    last;
1594757b351SPierre Pronchery                }
1604757b351SPierre Pronchery                if ($val =~ m{\G([^"\\]+)}ogc) {
1614757b351SPierre Pronchery                    push @frag, $1;
1624757b351SPierre Pronchery                } elsif ($val =~ m{\G((?>[\\]+))(?=")}ogc) {
1634757b351SPierre Pronchery                    # Backslashes before a double-quote are escapes
1644757b351SPierre Pronchery                    my $l = length($1);
1654757b351SPierre Pronchery                    push @frag, q{\\} x int($l / 2);
1664757b351SPierre Pronchery                    if ($l % 2 == 1) {
1674757b351SPierre Pronchery                        ++pos($val);
1684757b351SPierre Pronchery                        push @frag, q{"};
1694757b351SPierre Pronchery                    }
1704757b351SPierre Pronchery                } elsif ($val =~ m{\G((?:(?>[\\]+)[^"\\]+)+)}ogc) {
1714757b351SPierre Pronchery                    # Backslashes not before a double-quote are not special
1724757b351SPierre Pronchery                    push @frag, $1;
1734757b351SPierre Pronchery                } else {
1744757b351SPierre Pronchery                    # Tolerate missing closing double-quote
1754757b351SPierre Pronchery                    last;
1764757b351SPierre Pronchery                }
1774757b351SPierre Pronchery            }
1784757b351SPierre Pronchery        } elsif ($val =~ m{\G((?>[\\]+))(?=")}ogc) {
1794757b351SPierre Pronchery            my $l = length($1);
1804757b351SPierre Pronchery            push @frag, q{\\} x int($l / 2);
1814757b351SPierre Pronchery            if ($l % 2 == 1) {
1824757b351SPierre Pronchery                ++pos($val);
1834757b351SPierre Pronchery                push @frag, q{"};
1844757b351SPierre Pronchery            }
1854757b351SPierre Pronchery        } elsif ($val =~ m{\G([\\]+)}ogc) {
1864757b351SPierre Pronchery            # Backslashes not before a double-quote are not special
1874757b351SPierre Pronchery            push @frag, $1;
1884757b351SPierre Pronchery        } else {
1894757b351SPierre Pronchery            die sprintf("Bare newline in: '%s'\n", $val);
1904757b351SPierre Pronchery        }
1914757b351SPierre Pronchery        # Done if at SPACE, TAB or end, otherwise continue current fragment
1924757b351SPierre Pronchery        #
1934757b351SPierre Pronchery        next unless ($val =~ m{\G(?:[ \t]+|\z)}ogcs);
1944757b351SPierre Pronchery        push @ret, join("", splice(@frag)) if (@frag > 0);
1954757b351SPierre Pronchery    }
1964757b351SPierre Pronchery    # Handle final fragment
1974757b351SPierre Pronchery    push @ret, join("", splice(@frag)) if (@frag);
1984757b351SPierre Pronchery    return @ret;
1994757b351SPierre Pronchery}
2004757b351SPierre Pronchery
2014757b351SPierre Pronchery# Split out "-extra-CMD value", and return new |@ARGV|. Fill in
2024757b351SPierre Pronchery# |EXTRA{CMD}| with list of values.
2034757b351SPierre Proncherysub parse_extra
2044757b351SPierre Pronchery{
2054757b351SPierre Pronchery    my @args;
2064757b351SPierre Pronchery    foreach ( @OPENSSL_CMDS ) {
2074757b351SPierre Pronchery        $EXTRA{$_} = [];
2084757b351SPierre Pronchery    }
2094757b351SPierre Pronchery    while (@_) {
2104757b351SPierre Pronchery        my $arg = shift(@_);
2114757b351SPierre Pronchery        if ( $arg !~ m{^-extra-(\w+)$} ) {
2124757b351SPierre Pronchery            push @args, split_val($arg);
2134757b351SPierre Pronchery            next;
2144757b351SPierre Pronchery        }
2154757b351SPierre Pronchery        $arg = $1;
2164757b351SPierre Pronchery        die "Unknown \"-extra-${arg}\" option, exiting\n"
2174757b351SPierre Pronchery            unless grep { $arg eq $_ } @OPENSSL_CMDS;
2184757b351SPierre Pronchery        die "Missing \"-extra-${arg}\" option value, exiting\n"
2194757b351SPierre Pronchery            unless (@_ > 0);
2204757b351SPierre Pronchery        push @{$EXTRA{$arg}}, split_val(shift(@_));
2214757b351SPierre Pronchery    }
2224757b351SPierre Pronchery    return @args;
2234757b351SPierre Pronchery}
2244757b351SPierre Pronchery
2254757b351SPierre Pronchery
2264757b351SPierre Pronchery# See if reason for a CRL entry is valid; exit if not.
2274757b351SPierre Proncherysub crl_reason_ok
2284757b351SPierre Pronchery{
2294757b351SPierre Pronchery    my $r = shift;
2304757b351SPierre Pronchery
2314757b351SPierre Pronchery    if ($r eq 'unspecified' || $r eq 'keyCompromise'
2324757b351SPierre Pronchery        || $r eq 'CACompromise' || $r eq 'affiliationChanged'
2334757b351SPierre Pronchery        || $r eq 'superseded' || $r eq 'cessationOfOperation'
2344757b351SPierre Pronchery        || $r eq 'certificateHold' || $r eq 'removeFromCRL') {
2354757b351SPierre Pronchery        return 1;
2364757b351SPierre Pronchery    }
2374757b351SPierre Pronchery    print STDERR "Invalid CRL reason; must be one of:\n";
2384757b351SPierre Pronchery    print STDERR "    unspecified, keyCompromise, CACompromise,\n";
2394757b351SPierre Pronchery    print STDERR "    affiliationChanged, superseded, cessationOfOperation\n";
2404757b351SPierre Pronchery    print STDERR "    certificateHold, removeFromCRL";
2414757b351SPierre Pronchery    exit 1;
2424757b351SPierre Pronchery}
2434757b351SPierre Pronchery
2444757b351SPierre Pronchery# Copy a PEM-format file; return like exit status (zero means ok)
2454757b351SPierre Proncherysub copy_pemfile
2464757b351SPierre Pronchery{
2474757b351SPierre Pronchery    my ($infile, $outfile, $bound) = @_;
2484757b351SPierre Pronchery    my $found = 0;
2494757b351SPierre Pronchery
2504757b351SPierre Pronchery    open IN, $infile || die "Cannot open $infile, $!";
2514757b351SPierre Pronchery    open OUT, ">$outfile" || die "Cannot write to $outfile, $!";
2524757b351SPierre Pronchery    while (<IN>) {
2534757b351SPierre Pronchery        $found = 1 if /^-----BEGIN.*$bound/;
2544757b351SPierre Pronchery        print OUT $_ if $found;
2554757b351SPierre Pronchery        $found = 2, last if /^-----END.*$bound/;
2564757b351SPierre Pronchery    }
2574757b351SPierre Pronchery    close IN;
2584757b351SPierre Pronchery    close OUT;
2594757b351SPierre Pronchery    return $found == 2 ? 0 : 1;
2604757b351SPierre Pronchery}
2614757b351SPierre Pronchery
2624757b351SPierre Pronchery# Wrapper around system; useful for debugging.  Returns just the exit status
2634757b351SPierre Proncherysub run
2644757b351SPierre Pronchery{
2654757b351SPierre Pronchery    my ($cmd, @args) = @_;
2664757b351SPierre Pronchery    print "====\n$cmd @args\n" if $verbose;
2674757b351SPierre Pronchery    my $status = system {$cmd} $cmd, @args;
2684757b351SPierre Pronchery    print "==> $status\n====\n" if $verbose;
2694757b351SPierre Pronchery    return $status >> 8;
2704757b351SPierre Pronchery}
2714757b351SPierre Pronchery
2724757b351SPierre Pronchery
2734757b351SPierre Proncheryif ( $WHAT =~ /^(-\?|-h|-help)$/ ) {
2744757b351SPierre Pronchery    print STDERR <<EOF;
2754757b351SPierre ProncheryUsage:
2764757b351SPierre Pronchery    CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter]
2774757b351SPierre Pronchery    CA.pl -pkcs12 [certname]
2784757b351SPierre Pronchery    CA.pl -verify certfile ...
2794757b351SPierre Pronchery    CA.pl -revoke certfile [reason]
2804757b351SPierre ProncheryEOF
2814757b351SPierre Pronchery    exit 0;
2824757b351SPierre Pronchery}
2834757b351SPierre Pronchery
2844757b351SPierre Proncheryif ($WHAT eq '-newcert' ) {
2854757b351SPierre Pronchery    # create a certificate
2864757b351SPierre Pronchery    $RET = run(@REQ, qw(-new -x509 -keyout), $NEWKEY, "-out", $NEWCERT, @DAYS, @{$EXTRA{req}});
2874757b351SPierre Pronchery    print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
2884757b351SPierre Pronchery} elsif ($WHAT eq '-precert' ) {
2894757b351SPierre Pronchery    # create a pre-certificate
2904757b351SPierre Pronchery    $RET = run(@REQ, qw(-x509 -precert -keyout), $NEWKEY, "-out", $NEWCERT, @DAYS, @{$EXTRA{req}});
2914757b351SPierre Pronchery    print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
2924757b351SPierre Pronchery} elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) {
2934757b351SPierre Pronchery    # create a certificate request
2944757b351SPierre Pronchery    $RET = run(@REQ, "-new", (defined $1 ? ($1,) : ()), "-keyout", $NEWKEY, "-out", $NEWREQ, @{$EXTRA{req}});
2954757b351SPierre Pronchery    print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
2964757b351SPierre Pronchery} elsif ($WHAT eq '-newca' ) {
2974757b351SPierre Pronchery    # create the directory hierarchy
2984757b351SPierre Pronchery    my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl",
2994757b351SPierre Pronchery                "${CATOP}/newcerts", "${CATOP}/private" );
3004757b351SPierre Pronchery    die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed,"
3014757b351SPierre Pronchery        if -f "${CATOP}/index.txt";
3024757b351SPierre Pronchery    die "${CATOP}/serial exists.\nRemove old sub-tree to proceed,"
3034757b351SPierre Pronchery        if -f "${CATOP}/serial";
3044757b351SPierre Pronchery    foreach my $d ( @dirs ) {
3054757b351SPierre Pronchery        if ( -d $d ) {
3064757b351SPierre Pronchery            warn "Directory $d exists" if -d $d;
3074757b351SPierre Pronchery        } else {
3084757b351SPierre Pronchery            mkdir $d or die "Can't mkdir $d, $!";
3094757b351SPierre Pronchery        }
3104757b351SPierre Pronchery    }
3114757b351SPierre Pronchery
3124757b351SPierre Pronchery    open OUT, ">${CATOP}/index.txt";
3134757b351SPierre Pronchery    close OUT;
3144757b351SPierre Pronchery    open OUT, ">${CATOP}/crlnumber";
3154757b351SPierre Pronchery    print OUT "01\n";
3164757b351SPierre Pronchery    close OUT;
3174757b351SPierre Pronchery    # ask user for existing CA certificate
3184757b351SPierre Pronchery    print "CA certificate filename (or enter to create)\n";
3194757b351SPierre Pronchery    my $FILE;
3204757b351SPierre Pronchery    $FILE = "" unless defined($FILE = <STDIN>);
3214757b351SPierre Pronchery    $FILE =~ s{\R$}{};
3224757b351SPierre Pronchery    if ($FILE ne "") {
3234757b351SPierre Pronchery        copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");
3244757b351SPierre Pronchery        copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
3254757b351SPierre Pronchery    } else {
3264757b351SPierre Pronchery        print "Making CA certificate ...\n";
3274757b351SPierre Pronchery        $RET = run(@REQ, qw(-new -keyout), "${CATOP}/private/$CAKEY",
3284757b351SPierre Pronchery                   "-out", "${CATOP}/$CAREQ", @{$EXTRA{req}});
3294757b351SPierre Pronchery        $RET = run(@CA, qw(-create_serial -out), "${CATOP}/$CACERT", @CADAYS,
3304757b351SPierre Pronchery                   qw(-batch -keyfile), "${CATOP}/private/$CAKEY", "-selfsign",
3314757b351SPierre Pronchery                   @EXTENSIONS, "-infiles", "${CATOP}/$CAREQ", @{$EXTRA{ca}})
3324757b351SPierre Pronchery            if $RET == 0;
3334757b351SPierre Pronchery        print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;
3344757b351SPierre Pronchery    }
3354757b351SPierre Pronchery} elsif ($WHAT eq '-pkcs12' ) {
3364757b351SPierre Pronchery    my $cname = $ARGV[0];
3374757b351SPierre Pronchery    $cname = "My Certificate" unless defined $cname;
3384757b351SPierre Pronchery    $RET = run(@PKCS12, "-in", $NEWCERT, "-inkey", $NEWKEY,
3394757b351SPierre Pronchery               "-certfile", "${CATOP}/$CACERT", "-out", $NEWP12,
3404757b351SPierre Pronchery               qw(-export -name), $cname, @{$EXTRA{pkcs12}});
3414757b351SPierre Pronchery    print "PKCS#12 file is in $NEWP12\n" if $RET == 0;
3424757b351SPierre Pronchery} elsif ($WHAT eq '-xsign' ) {
3434757b351SPierre Pronchery    $RET = run(@CA, @POLICY, "-infiles", $NEWREQ, @{$EXTRA{ca}});
3444757b351SPierre Pronchery} elsif ($WHAT eq '-sign' ) {
3454757b351SPierre Pronchery    $RET = run(@CA, @POLICY, "-out", $NEWCERT,
3464757b351SPierre Pronchery               "-infiles", $NEWREQ, @{$EXTRA{ca}});
3474757b351SPierre Pronchery    print "Signed certificate is in $NEWCERT\n" if $RET == 0;
3484757b351SPierre Pronchery} elsif ($WHAT eq '-signCA' ) {
3494757b351SPierre Pronchery    $RET = run(@CA, @POLICY, "-out", $NEWCERT, @EXTENSIONS,
3504757b351SPierre Pronchery               "-infiles", $NEWREQ, @{$EXTRA{ca}});
3514757b351SPierre Pronchery    print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;
3524757b351SPierre Pronchery} elsif ($WHAT eq '-signcert' ) {
3534757b351SPierre Pronchery    $RET = run(@X509, qw(-x509toreq -in), $NEWREQ, "-signkey", $NEWREQ,
3544757b351SPierre Pronchery               qw(-out tmp.pem), @{$EXTRA{x509}});
3554757b351SPierre Pronchery    $RET = run(@CA, @POLICY, "-out", $NEWCERT,
3564757b351SPierre Pronchery               qw(-infiles tmp.pem), @{$EXTRA{ca}}) if $RET == 0;
3574757b351SPierre Pronchery    print "Signed certificate is in $NEWCERT\n" if $RET == 0;
3584757b351SPierre Pronchery} elsif ($WHAT eq '-verify' ) {
3594757b351SPierre Pronchery    my @files = @ARGV ? @ARGV : ( $NEWCERT );
3604757b351SPierre Pronchery    foreach my $file (@files) {
3614757b351SPierre Pronchery        my $status = run(@VERIFY, "-CAfile", "${CATOP}/$CACERT", $file, @{$EXTRA{verify}});
3624757b351SPierre Pronchery        $RET = $status if $status != 0;
3634757b351SPierre Pronchery    }
3644757b351SPierre Pronchery} elsif ($WHAT eq '-crl' ) {
3654757b351SPierre Pronchery    $RET = run(@CA, qw(-gencrl -out), "${CATOP}/crl/$CACRL", @{$EXTRA{ca}});
3664757b351SPierre Pronchery    print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0;
3674757b351SPierre Pronchery} elsif ($WHAT eq '-revoke' ) {
3684757b351SPierre Pronchery    my $cname = $ARGV[0];
3694757b351SPierre Pronchery    if (!defined $cname) {
3704757b351SPierre Pronchery        print "Certificate filename is required; reason optional.\n";
3714757b351SPierre Pronchery        exit 1;
3724757b351SPierre Pronchery    }
3734757b351SPierre Pronchery    my @reason;
3744757b351SPierre Pronchery    @reason = ("-crl_reason", $ARGV[1])
3754757b351SPierre Pronchery        if defined $ARGV[1] && crl_reason_ok($ARGV[1]);
3764757b351SPierre Pronchery    $RET = run(@CA, "-revoke", $cname, @reason, @{$EXTRA{ca}});
3774757b351SPierre Pronchery} else {
3784757b351SPierre Pronchery    print STDERR "Unknown arg \"$WHAT\"\n";
3794757b351SPierre Pronchery    print STDERR "Use -help for help.\n";
3804757b351SPierre Pronchery    exit 1;
3814757b351SPierre Pronchery}
3824757b351SPierre Pronchery
3834757b351SPierre Proncheryexit $RET;
384