diff options
author | Rich Salz <rsalz@akamai.com> | 2020-03-16 15:53:00 -0400 |
---|---|---|
committer | Dmitry Belyavskiy <beldmit@gmail.com> | 2020-03-23 14:20:21 +0300 |
commit | cab33afb711e467f459e5b5e669bf7a5c4fe797a (patch) | |
tree | 7e470e3b1470a31092a4852559ffc514cf6f7f53 | |
parent | 55ca81259a63286a88dd1f53ef14f7830f444c7e (diff) |
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)
-rw-r--r-- | apps/CA.pl.in | 130 | ||||
-rw-r--r-- | doc/man1/CA.pl.pod | 96 |
2 files changed, 110 insertions, 116 deletions
diff --git a/apps/CA.pl.in b/apps/CA.pl.in index 12c9452444..918534d6a1 100644 --- a/apps/CA.pl.in +++ b/apps/CA.pl.in @@ -14,57 +14,63 @@ use strict; use warnings; -my $openssl = "openssl"; -if(defined $ENV{'OPENSSL'}) { - $openssl = $ENV{'OPENSSL'}; -} else { - $ENV{'OPENSSL'} = $openssl; -} - my $verbose = 1; +my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); -my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} || ""; -my $DAYS = "-days 365"; -my $CADAYS = "-days 1095"; # 3 years +my $openssl = $ENV{'OPENSSL'} // "openssl"; +$ENV{'OPENSSL'} = $openssl; +my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // ""; + +# Command invocations. my $REQ = "$openssl req $OPENSSL_CONFIG"; my $CA = "$openssl ca $OPENSSL_CONFIG"; my $VERIFY = "$openssl verify"; my $X509 = "$openssl x509"; my $PKCS12 = "$openssl pkcs12"; -# default openssl.cnf file has setup as per the following +# Default values for various configuration settings. my $CATOP = "./demoCA"; my $CAKEY = "cakey.pem"; my $CAREQ = "careq.pem"; my $CACERT = "cacert.pem"; my $CACRL = "crl.pem"; -my $DIRMODE = 0777; - +my $DAYS = "-days 365"; +my $CADAYS = "-days 1095"; # 3 years my $NEWKEY = "newkey.pem"; my $NEWREQ = "newreq.pem"; my $NEWCERT = "newcert.pem"; my $NEWP12 = "newcert.p12"; -my $RET = 0; + +# Commandline parsing +my %EXTRA; my $WHAT = shift @ARGV || ""; -my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify"); -my %EXTRA = extra_args(\@ARGV, "-extra-"); -my $FILE; - -sub extra_args { - my ($args_ref, $arg_prefix) = @_; - my %eargs = map { - if ($_ < $#$args_ref) { - my ($arg, $value) = splice(@$args_ref, $_, 2); - $arg =~ s/$arg_prefix//; - ($arg, $value); - } else { - (); - } - } reverse grep($$args_ref[$_] =~ /$arg_prefix/, 0..$#$args_ref); - my %empty = map { ($_, "") } @OPENSSL_CMDS; - return (%empty, %eargs); +@ARGV = parse_extra(@ARGV); +my $RET = 0; + +# Split out "-extra-CMD value", and return new |@ARGV|. Fill in +# |EXTRA{CMD}| with list of values. +sub parse_extra +{ + foreach ( @OPENSSL_CMDS ) { + $EXTRA{$_} = ''; + } + + my @result; + 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. sub crl_reason_ok { @@ -113,19 +119,25 @@ sub run 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 " CA.pl -pkcs12 [-extra-pkcs12 extra-params] [certname]\n"; - print STDERR " CA.pl -verify [-extra-verify extra-params] certfile ...\n"; - print STDERR " CA.pl -revoke [-extra-ca extra-params] certfile [reason]\n"; + print STDERR <<EOF; +Usage: + CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter] + 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; } + if ($WHAT eq '-newcert' ) { # 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; } elsif ($WHAT eq '-precert' ) { # 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; } elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) { # 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; } 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; + my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl", + "${CATOP}/newcerts", "${CATOP}/private" ); + die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed," + if -f "${CATOP}/index.txt"; + 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"; close OUT; open OUT, ">${CATOP}/crlnumber"; @@ -145,6 +166,7 @@ if ($WHAT eq '-newcert' ) { close OUT; # ask user for existing CA certificate print "CA certificate filename (or enter to create)\n"; + my $FILE; $FILE = "" unless defined($FILE = <STDIN>); $FILE =~ s{\R$}{}; if ($FILE ne "") { @@ -152,44 +174,42 @@ if ($WHAT eq '-newcert' ) { copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE"); } else { print "Making CA certificate ...\n"; - $RET = run("$REQ -new -keyout" - . " ${CATOP}/private/$CAKEY" + $RET = run("$REQ -new -keyout ${CATOP}/private/$CAKEY" . " -out ${CATOP}/$CAREQ $EXTRA{req}"); $RET = run("$CA -create_serial" . " -out ${CATOP}/$CACERT $CADAYS -batch" . " -keyfile ${CATOP}/private/$CAKEY -selfsign" - . " -extensions v3_ca $EXTRA{ca}" - . " -infiles ${CATOP}/$CAREQ") if $RET == 0; + . " -extensions v3_ca" + . " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0; print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0; } } elsif ($WHAT eq '-pkcs12' ) { my $cname = $ARGV[0]; $cname = "My Certificate" unless defined $cname; $RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY" - . " -certfile ${CATOP}/$CACERT" - . " -out $NEWP12" + . " -certfile ${CATOP}/$CACERT -out $NEWP12" . " -export -name \"$cname\" $EXTRA{pkcs12}"); print "PKCS #12 file is in $NEWP12\n" if $RET == 0; } 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' ) { - $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; } elsif ($WHAT eq '-signCA' ) { $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; } elsif ($WHAT eq '-signcert' ) { $RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ" . " -out tmp.pem $EXTRA{x509}"); $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; } elsif ($WHAT eq '-verify' ) { my @files = @ARGV ? @ARGV : ( $NEWCERT ); - my $file; - foreach $file (@files) { - my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}"); + foreach my $file (@files) { + my $status = run("$VERIFY -CAfile ${CATOP}/$CACERT $file $EXTRA{verify}"); $RET = $status if $status != 0; } } elsif ($WHAT eq '-crl' ) { diff --git a/doc/man1/CA.pl.pod b/doc/man1/CA.pl.pod index 4c53970890..fa07c8926c 100644 --- a/doc/man1/CA.pl.pod +++ b/doc/man1/CA.pl.pod @@ -21,13 +21,13 @@ B<-signCA> | B<-signcert> | B<-crl> | 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 @@ -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 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 =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. 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> 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 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. -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. -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 @@ -144,66 +168,16 @@ the request and finally create a PKCS#12 file containing it. CA.pl -signreq 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 +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 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 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 L<openssl(1)>, |