Update CA.pl podpage, and script

Merge the NOTES section into the relevant parts of the manpage.
Add the $EXTRA parameter in consistent places (the end) to call
commands.  Document that multiple -extra-XXX might be needed.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/11338)
This commit is contained in:
Rich Salz 2020-03-16 15:53:00 -04:00 committed by Dmitry Belyavskiy
parent 55ca81259a
commit cab33afb71
2 changed files with 110 additions and 116 deletions

View File

@ -14,56 +14,62 @@
use strict; use strict;
use warnings; use warnings;
my $openssl = "openssl";
if(defined $ENV{'OPENSSL'}) {
$openssl = $ENV{'OPENSSL'};
} else {
$ENV{'OPENSSL'} = $openssl;
}
my $verbose = 1; my $verbose = 1;
my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify");
my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || ""; my $openssl = $ENV{'OPENSSL'} // "openssl";
my $DAYS = "-days 365"; $ENV{'OPENSSL'} = $openssl;
my $CADAYS = "-days 1095"; # 3 years my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // "";
# Command invocations.
my $REQ = "$openssl req $OPENSSL_CONFIG"; my $REQ = "$openssl req $OPENSSL_CONFIG";
my $CA = "$openssl ca $OPENSSL_CONFIG"; my $CA = "$openssl ca $OPENSSL_CONFIG";
my $VERIFY = "$openssl verify"; my $VERIFY = "$openssl verify";
my $X509 = "$openssl x509"; my $X509 = "$openssl x509";
my $PKCS12 = "$openssl pkcs12"; my $PKCS12 = "$openssl pkcs12";
# default openssl.cnf file has setup as per the following # Default values for various configuration settings.
my $CATOP = "./demoCA"; my $CATOP = "./demoCA";
my $CAKEY = "cakey.pem"; my $CAKEY = "cakey.pem";
my $CAREQ = "careq.pem"; my $CAREQ = "careq.pem";
my $CACERT = "cacert.pem"; my $CACERT = "cacert.pem";
my $CACRL = "crl.pem"; my $CACRL = "crl.pem";
my $DIRMODE = 0777; my $DAYS = "-days 365";
my $CADAYS = "-days 1095"; # 3 years
my $NEWKEY = "newkey.pem"; my $NEWKEY = "newkey.pem";
my $NEWREQ = "newreq.pem"; my $NEWREQ = "newreq.pem";
my $NEWCERT = "newcert.pem"; my $NEWCERT = "newcert.pem";
my $NEWP12 = "newcert.p12"; my $NEWP12 = "newcert.p12";
my $RET = 0;
my $WHAT = shift @ARGV || "";
my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify");
my %EXTRA = extra_args(\@ARGV, "-extra-");
my $FILE;
sub extra_args { # Commandline parsing
my ($args_ref, $arg_prefix) = @_; my %EXTRA;
my %eargs = map { my $WHAT = shift @ARGV || "";
if ($_ < $#$args_ref) { @ARGV = parse_extra(@ARGV);
my ($arg, $value) = splice(@$args_ref, $_, 2); my $RET = 0;
$arg =~ s/$arg_prefix//;
($arg, $value); # Split out "-extra-CMD value", and return new |@ARGV|. Fill in
} else { # |EXTRA{CMD}| with list of values.
(); sub parse_extra
{
foreach ( @OPENSSL_CMDS ) {
$EXTRA{$_} = '';
} }
} reverse grep($$args_ref[$_] =~ /$arg_prefix/, 0..$#$args_ref);
my %empty = map { ($_, "") } @OPENSSL_CMDS; my @result;
return (%empty, %eargs); while ( scalar(@_) > 0 ) {
my $arg = shift;
if ( $arg !~ m/-extra-([a-z0-9]+)/ ) {
push @result, $arg;
next;
} }
$arg =~ s/-extra-//;
die("Unknown \"-${arg}-extra\" option, exiting")
unless scalar grep { $arg eq $_ } @OPENSSL_CMDS;
$EXTRA{$arg} .= " " . shift;
}
return @result;
}
# See if reason for a CRL entry is valid; exit if not. # See if reason for a CRL entry is valid; exit if not.
sub crl_reason_ok sub crl_reason_ok
@ -113,19 +119,25 @@ sub run
if ( $WHAT =~ /^(-\?|-h|-help)$/ ) { if ( $WHAT =~ /^(-\?|-h|-help)$/ ) {
print STDERR "usage: CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd extra-params]\n"; print STDERR <<EOF;
print STDERR " CA.pl -pkcs12 [-extra-pkcs12 extra-params] [certname]\n"; Usage:
print STDERR " CA.pl -verify [-extra-verify extra-params] certfile ...\n"; CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter]
print STDERR " CA.pl -revoke [-extra-ca extra-params] certfile [reason]\n"; CA.pl -pkcs12 [-extra-pkcs12 parameter] [certname]
CA.pl -verify [-extra-verify parameter] certfile ...
CA.pl -revoke [-extra-ca parameter] certfile [reason]
EOF
exit 0; exit 0;
} }
if ($WHAT eq '-newcert' ) { if ($WHAT eq '-newcert' ) {
# create a certificate # create a certificate
$RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS $EXTRA{req}"); $RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS"
. " $EXTRA{req}");
print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-precert' ) { } elsif ($WHAT eq '-precert' ) {
# create a pre-certificate # create a pre-certificate
$RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"); $RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"
. " $EXTRA{req}");
print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0; print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) { } elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) {
# create a certificate request # create a certificate request
@ -133,11 +145,20 @@ if ($WHAT eq '-newcert' ) {
print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0; print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
} elsif ($WHAT eq '-newca' ) { } elsif ($WHAT eq '-newca' ) {
# create the directory hierarchy # create the directory hierarchy
mkdir ${CATOP}, $DIRMODE; my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl",
mkdir "${CATOP}/certs", $DIRMODE; "${CATOP}/newcerts", "${CATOP}/private" );
mkdir "${CATOP}/crl", $DIRMODE ; die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed,"
mkdir "${CATOP}/newcerts", $DIRMODE; if -f "${CATOP}/index.txt";
mkdir "${CATOP}/private", $DIRMODE; die "${CATOP}/serial exists.\nRemove old sub-tree to proceed,"
if -f "${CATOP}/serial";
foreach my $d ( @dirs ) {
if ( -d $d ) {
warn "Directory $d exists" if -d $d;
} else {
mkdir $d or die "Can't mkdir $d, $!";
}
}
open OUT, ">${CATOP}/index.txt"; open OUT, ">${CATOP}/index.txt";
close OUT; close OUT;
open OUT, ">${CATOP}/crlnumber"; open OUT, ">${CATOP}/crlnumber";
@ -145,6 +166,7 @@ if ($WHAT eq '-newcert' ) {
close OUT; close OUT;
# ask user for existing CA certificate # ask user for existing CA certificate
print "CA certificate filename (or enter to create)\n"; print "CA certificate filename (or enter to create)\n";
my $FILE;
$FILE = "" unless defined($FILE = <STDIN>); $FILE = "" unless defined($FILE = <STDIN>);
$FILE =~ s{\R$}{}; $FILE =~ s{\R$}{};
if ($FILE ne "") { if ($FILE ne "") {
@ -152,44 +174,42 @@ if ($WHAT eq '-newcert' ) {
copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
} else { } else {
print "Making CA certificate ...\n"; print "Making CA certificate ...\n";
$RET = run("$REQ -new -keyout" $RET = run("$REQ -new -keyout ${CATOP}/private/$CAKEY"
. " ${CATOP}/private/$CAKEY"
. " -out ${CATOP}/$CAREQ $EXTRA{req}"); . " -out ${CATOP}/$CAREQ $EXTRA{req}");
$RET = run("$CA -create_serial" $RET = run("$CA -create_serial"
. " -out ${CATOP}/$CACERT $CADAYS -batch" . " -out ${CATOP}/$CACERT $CADAYS -batch"
. " -keyfile ${CATOP}/private/$CAKEY -selfsign" . " -keyfile ${CATOP}/private/$CAKEY -selfsign"
. " -extensions v3_ca $EXTRA{ca}" . " -extensions v3_ca"
. " -infiles ${CATOP}/$CAREQ") if $RET == 0; . " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0;
print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0; print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;
} }
} elsif ($WHAT eq '-pkcs12' ) { } elsif ($WHAT eq '-pkcs12' ) {
my $cname = $ARGV[0]; my $cname = $ARGV[0];
$cname = "My Certificate" unless defined $cname; $cname = "My Certificate" unless defined $cname;
$RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY" $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY"
. " -certfile ${CATOP}/$CACERT" . " -certfile ${CATOP}/$CACERT -out $NEWP12"
. " -out $NEWP12"
. " -export -name \"$cname\" $EXTRA{pkcs12}"); . " -export -name \"$cname\" $EXTRA{pkcs12}");
print "PKCS #12 file is in $NEWP12\n" if $RET == 0; print "PKCS #12 file is in $NEWP12\n" if $RET == 0;
} elsif ($WHAT eq '-xsign' ) { } elsif ($WHAT eq '-xsign' ) {
$RET = run("$CA -policy policy_anything $EXTRA{ca} -infiles $NEWREQ"); $RET = run("$CA -policy policy_anything -infiles $NEWREQ $EXTRA{ca}");
} elsif ($WHAT eq '-sign' ) { } elsif ($WHAT eq '-sign' ) {
$RET = run("$CA -policy policy_anything -out $NEWCERT $EXTRA{ca} -infiles $NEWREQ"); $RET = run("$CA -policy policy_anything -out $NEWCERT"
. " -infiles $NEWREQ $EXTRA{ca}");
print "Signed certificate is in $NEWCERT\n" if $RET == 0; print "Signed certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-signCA' ) { } elsif ($WHAT eq '-signCA' ) {
$RET = run("$CA -policy policy_anything -out $NEWCERT" $RET = run("$CA -policy policy_anything -out $NEWCERT"
. " -extensions v3_ca $EXTRA{ca} -infiles $NEWREQ"); . " -extensions v3_ca -infiles $NEWREQ $EXTRA{ca}");
print "Signed CA certificate is in $NEWCERT\n" if $RET == 0; print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-signcert' ) { } elsif ($WHAT eq '-signcert' ) {
$RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ" $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ"
. " -out tmp.pem $EXTRA{x509}"); . " -out tmp.pem $EXTRA{x509}");
$RET = run("$CA -policy policy_anything -out $NEWCERT" $RET = run("$CA -policy policy_anything -out $NEWCERT"
. "$EXTRA{ca} -infiles tmp.pem") if $RET == 0; . "-infiles tmp.pem $EXTRA{ca}") if $RET == 0;
print "Signed certificate is in $NEWCERT\n" if $RET == 0; print "Signed certificate is in $NEWCERT\n" if $RET == 0;
} elsif ($WHAT eq '-verify' ) { } elsif ($WHAT eq '-verify' ) {
my @files = @ARGV ? @ARGV : ( $NEWCERT ); my @files = @ARGV ? @ARGV : ( $NEWCERT );
my $file; foreach my $file (@files) {
foreach $file (@files) { my $status = run("$VERIFY -CAfile ${CATOP}/$CACERT $file $EXTRA{verify}");
my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}");
$RET = $status if $status != 0; $RET = $status if $status != 0;
} }
} elsif ($WHAT eq '-crl' ) { } elsif ($WHAT eq '-crl' ) {

View File

@ -21,13 +21,13 @@ B<-signCA> |
B<-signcert> | B<-signcert> |
B<-crl> | B<-crl> |
B<-newca> B<-newca>
[B<-extra-cmd> I<extra-params>] [B<-extra-I<cmd>> I<parameter>]
B<CA.pl> B<-pkcs12> [B<-extra-pkcs12> I<extra-params>] [I<certname>] B<CA.pl> B<-pkcs12> [B<-extra-pkcs12> I<parameter>] [I<certname>]
B<CA.pl> B<-verify> [B<-extra-verify> I<extra-params>] I<certfile> ... B<CA.pl> B<-verify> [B<-extra-verify> I<parameter>] I<certfile> ...
B<CA.pl> B<-revoke> [B<-extra-ca> I<extra-params>] I<certfile> [I<reason>] B<CA.pl> B<-revoke> [B<-extra-ca> I<parameter>] I<certfile> [I<reason>]
=head1 DESCRIPTION =head1 DESCRIPTION
@ -36,6 +36,23 @@ arguments to the L<openssl(1)> command for some common certificate operations.
It is intended to simplify the process of certificate creation and management It is intended to simplify the process of certificate creation and management
by the use of some simple options. by the use of some simple options.
The script is intended as a simple front end for the L<openssl(1)> program for
use by a beginner. Its behaviour isn't always what is wanted. For more control
over the behaviour of the certificate commands call the L<openssl(1)> command
directly.
Most of the filenames mentioned below can be modified by editing the
B<CA.pl> script.
Under some environments it may not be possible to run the B<CA.pl> script
directly (for example Win32) and the default configuration file location may
be wrong. In this case the command:
perl -S CA.pl
can be used and the B<OPENSSL_CONF> environment variable can be set to point to
the correct path of the configuration file.
=head1 OPTIONS =head1 OPTIONS
=over 4 =over 4
@ -70,6 +87,11 @@ details of the CA will be prompted for. The relevant files and directories
are created in a directory called F<demoCA> in the current directory. are created in a directory called F<demoCA> in the current directory.
Uses L<openssl-req(1)> and L<openssl-ca(1)>. Uses L<openssl-req(1)> and L<openssl-ca(1)>.
If the F<demoCA> directory already exists then the B<-newca> command will not
overwrite it and will do nothing. This can happen if a previous call using
the B<-newca> option terminated abnormally. To get the correct behaviour
delete the directory if it already exists.
=item B<-pkcs12> =item B<-pkcs12>
Create a PKCS#12 file containing the user certificate, private key and CA Create a PKCS#12 file containing the user certificate, private key and CA
@ -120,13 +142,15 @@ Verifies certificates against the CA certificate for F<demoCA>. If no
certificates are specified on the command line it tries to verify the file certificates are specified on the command line it tries to verify the file
F<newcert.pem>. Invokes L<openssl-verify(1)>. F<newcert.pem>. Invokes L<openssl-verify(1)>.
=item B<-extra-req> | B<-extra-ca> | B<-extra-pkcs12> | B<-extra-x509> | B<-extra-verify> I<extra-params> =item B<-extra-I<cmd>> I<parameter>
For each option B<extra-I<cmd>>, pass I<extra-params> to the L<openssl(1)> For each option B<extra-I<cmd>>, pass I<parameter> to the L<openssl(1)>
sub-command with the same name as I<cmd>, if that sub-command is invoked. sub-command with the same name as I<cmd>, if that sub-command is invoked.
For example, if L<openssl-req(1)> is invoked, the I<extra-params> given with For example, if L<openssl-req(1)> is invoked, the I<parameter> given with
B<-extra-req> will be passed to it. B<-extra-req> will be passed to it.
Users should consult L<openssl(1)> command documentation for more information. For multi-word parameters, either repeat the option or quote the I<parameters>
so it looks like one word to your shell.
See the individual command documentation for more information.
=back =back
@ -144,66 +168,16 @@ the request and finally create a PKCS#12 file containing it.
CA.pl -signreq CA.pl -signreq
CA.pl -pkcs12 "My Test Certificate" CA.pl -pkcs12 "My Test Certificate"
=head1 DSA CERTIFICATES
Although the B<CA.pl> creates RSA CAs and requests it is still possible to
use it with DSA certificates and requests using the L<openssl-req(1)> command
directly. The following example shows the steps that would typically be taken.
Create some DSA parameters:
openssl dsaparam -out dsap.pem 1024
Create a DSA CA certificate and private key:
openssl req -x509 -newkey dsa:dsap.pem -keyout cacert.pem -out cacert.pem
Create the CA directories and files:
CA.pl -newca
enter a filename (for example, F<cacert.pem>) when prompted for the CA file
name.
Create a DSA certificate request and private key (a different set of parameters
can optionally be created first):
openssl req -out newreq.pem -newkey dsa:dsap.pem
Sign the request:
CA.pl -signreq
=head1 ENVIRONMENT =head1 ENVIRONMENT
The environment variable B<OPENSSL> may be used to specify the name of
the OpenSSL program. It can be a full pathname, or a relative one.
The environment variable B<OPENSSL_CONFIG> may be used to specify a The environment variable B<OPENSSL_CONFIG> may be used to specify a
configuration option and value to the B<req> and B<ca> commands invoked by configuration option and value to the B<req> and B<ca> commands invoked by
this script. It's value should be the option and pathname, as in this script. It's value should be the option and pathname, as in
C<-config /path/to/conf-file>. C<-config /path/to/conf-file>.
=head1 NOTES
Most of the filenames mentioned can be modified by editing the B<CA.pl> script.
If the F<demoCA> directory already exists then the B<-newca> command will not
overwrite it and will do nothing. This can happen if a previous call using
the B<-newca> option terminated abnormally. To get the correct behaviour
delete the demoCA directory if it already exists.
Under some environments it may not be possible to run the B<CA.pl> script
directly (for example Win32) and the default configuration file location may
be wrong. In this case the command:
perl -S CA.pl
can be used and the B<OPENSSL_CONF> environment variable changed to point to
the correct path of the configuration file.
The script is intended as a simple front end for the L<openssl(1)> program for
use by a beginner. Its behaviour isn't always what is wanted. For more control
over the behaviour of the certificate commands call the L<openssl(1)> command
directly.
=head1 SEE ALSO =head1 SEE ALSO
L<openssl(1)>, L<openssl(1)>,