> You should where possible use the command line switches > rather than "expect" because the prompts of the various > commands may change.
> You can generate requests via template configuration > files and there are various ways to supply passphrases.
While I agree 100% with the thrust of what Stephen is saying, the sad reality is that there are real problems with OpenSSL in this area.
For example, tell me how to specify a specific serial number on a C-language call like:
execle(SSLBPATH,SSLBPATH,"x509","-req","-sha1", "-extfile",SPKICONF, "-CA","./ssign.cert.pem", "-CAkey","./ssign.key.pem", "-CAserial",snumbuff, "-days","365", /* "-passin","fd:fileno(KDR)", */ "-passin","pass:aaaaa", 0,env);
Well, OK, I can do
int sn[2]; pipe(sn); sprintf(snumbuff,"%lx",serial); write(sn[1],snumbuff,strlen(snumbuff)); sprintf(snumbuff,"/dev/fd/%d",sn[0]);
(ignoring for the moment that it has to be an even number of hex bytes, the code is a *little* more complicated, see below)
but this is currently failing because the /dev/fd directory on this machine does not exist, and I have to get back to the systems people to find out if this is a bug or a feature...
Likewise with the passphrase, I earlier found a bug with specifying both "-passin fd:#" and "-passout fd:#" on the same OpenSSL call (was rsa to change pass phrase I think overlapping buffers or something :-) so when I take out the "aaaaa" above and make it
int pp[2]; pipe(pp); sprintf(passbuff,"/dev/fd/%d",pp[0]); /* arrange for passphrase to be written to pp[1] */
But this also relies on operating system support for /dev/fd/#.
(actual code considering length must be even:)
pipe(sn); sprintf(snumbuff,"0%lx",serial); pid = strlen(snumbuff); if (1 & pid) { write(sn[1],snumbuff+1,pid-1); } else { write(sn[1],snumbuff,pid); } sprintf(snumbuff,"/dev/fd/%d",sn[0]); close(sn[1]);
=====
The worst case I came up against required me to run a pipe of three different commands. There just seemed to be NO WAY to specify a passphrase for the CA command, so I ended up with an explicit call to OpenSSL rsa (second command in below pipe) just to get the private key decoded. Apologies if I missed something, but I did futz around for a good amount of time before doing it this way.
I don't recall why this code uses a temp file for the serial number instead of using another pipe. Maybe it didn't work at the time, or maybe I didn't think about it. This work was with 0.9.6c or so, and it is possible some of these points have been addressed in the evolution to 0.9.7
If there is a better way, score some points on me by telling me about it...
# ##### SPKCSIGN #####
# Call OpenSSL ca to sign a SPKAC or PKCS10
# Because of various limitations in the OpenSSL code, # this routine runs a pipe of three processes. # 1. Vault program writes a passphrase to stdout (bound to pipe PW/PR) # 2. An instance of OpenSSL rsa # * reads the passphrase from a -passin fd:<fileno(PR)> # * reads the encrypted private key from a -in file argument # * writes unencrypted private key to stdout (bound to pipe KW/KR). # 3. An instance of OpenSSL ca # * reads unencrypted private key from # a -privateKey /dev/fd/<fileno(KR)> # * reads the SPKAC from a -spkac /dev/fd<fileno(SR)> # * writes the signed certificate to stdout (bound to pipe CW/CR). # Standard error from all three is bound to pipe EW/ER. # # This routine writes the SPKAC data to SW and reads the signed # certificate from CR, and any errors from ER. # # SPKAC # +-------------------+ # SR | ^ SW # PASS KEY v CERT | # vault -----> OpenSSL rsa -----> OpenSSL ca -----> this routine # EW | PW PR | EW KW KR | EW CW CR ^ ER # v v v | # +--------------+-----------------+-------------------+
sub spkcsign { my ($vault,$vkey,$openssl,$tmpdir,$serial,$req,$certlife,$certmail) = @_; my $pid, $error, $cert; # Proc ID, error, result strs
# Make serial number as even-number-of-digits hex string and write file
my $hex = sprintf("%lX",$serial); # Convert serial to hex if ( length($hex) % 2 ) { $hex = '0'.$hex; # Requires even num digits! } my $snf = "$tmpdir/pca.serial.$$"; # Serial num file in config file open SERIAL,">$snf"; # Open write to file print SERIAL $hex; # Write serial number to file close SERIAL; # Close file
# Make empty initial database file
my $dbf = "$tmpdir/pca.dbf.$$"; # Database file open DBF,">$dbf"; # Write empty database file close DBF; # Close file
# Copy passphrase from the vault into P pipe.
pipe ER, EW; # Read and write for stderr pipe { $^F = 99; # FORCE CLOSE-ON-WRITE OFF!!! pipe PR, PW; # R & W for passphrase pipe } if ( !forkcode(sub{ # Run code in forked process close PR; # Close parent's pipe end close ER; # Close parent's pipe end open STDOUT,'>&PW'; # Bind standard out to pipe open STDERR,'>&EW'; # Bind standard err to pipe exec $vault,$vkey; # Send passphrase to PW die "Could not EXEC vault (spkcsign): $!"; # SHOULD NOT BE REACHED }) ) { htmlfail "Could not FORK vault (spkcsign): $!"; } close PW; # Close kid's pipe end
# Run OpenSSL rsa to decrypt the private key
{ $^F = 99; # FORCE CLOSE-ON-WRITE OFF!!! pipe KR, KW; # R & W for priv key pipe } if ( !forkcode(sub{ # Run code in forked process close KR; # Close parent's pipe end close ER; # Close parent's pipe end open STDOUT,'>&KW'; # Bind standard out to pipe open STDERR,'>&EW'; # Bind standard err to pipe exec $openssl.' rsa -passin fd:'.fileno(PR). ' -in ../certs/testca.key.pem'; die "Could not EXEC OpenSSL rsa (spkcsign): $!"; # NOT REACHED }) ) { htmlfail "Could not FORK OpenSSL rsa (SPKCSIGN): $1"; } close PR; # Close pass phrase pipe close KW; # Close kid's pipe end
# Run OpenSSL ca to sign the certificate
pipe CR, CW; # Read and write for cert pipe { $^F = 99; # FORCE CLOSE-ON-WRITE OFF!!! pipe SR, SW; # Read and write for SPKAC pipe } if ( !($pid=forkcode(sub{ # Run code in forked process $ENV{'CERTMAIL'} = $certmail; # Add altname to extension $ENV{'CERTSERN'} = $snf; # Set serial number file $ENV{'CADBF'} = $dbf; # Set database file close CR; # Close parent's pipe end close ER; # Close parent's pipe end close SW; # Close parent's pipe end open STDOUT,'>&CW'; # Bind standard out to pipe open STDERR,'>&EW'; # Bind standard err to pipe exec $openssl.' ca -config ../config/pconfig'. " -days $certlife". ' -batch -notext -keyfile /dev/fd/'.fileno(KR). ' -spkac /dev/fd/'.fileno(SR); die "Could not EXEC OpenSSL ca (spkcsign): $!"; # NOT REACHED })) ) { htmlfail "Could not FORK OpenSSL ca (spkcsign): $!" ; } close KR; # Close pipe from OpenSSL rsa close CW; # Close kid's pipe end close EW; # Close kid's pipe end close SR; # Close kid's pipe end print SW $req; # Send SPKAC data to pipe close SW; # Make EOF on pipe read ER,$error,4096; # Read any errors from kid read CR,$cert,4096; # Read any output from kid waitpid($pid,0); # Wait for kid to terminate if ($?) { htmlfail "OpenSSL ca (spkcsign):\n".$error; } close CR; # Close pipe from kid close ER; # Close pipe from kid unlink "$dbf.old", "$snf.old"; # Unlink old filenames unlink $dbf, $snf, "$tmpdir/$hex.pem"; # Unlink new filnames
return $cert; # Return certificate to caller }
-- Charles B (Ben) Cranston mailto: [EMAIL PROTECTED] http://www.wam.umd.edu/~zben
______________________________________________________________________ OpenSSL Project http://www.openssl.org User Support Mailing List [EMAIL PROTECTED] Automated List Manager [EMAIL PROTECTED]