> 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 filnamesreturn $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]
