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