There are several people already doing this, including myself and the Papyrus people at Georgia Tech. What I do is just to supply the non-secret information in a configuration file, and add the secret information via Unix pipes.
There is some variance depending on if you're using the "openssl ca" or if you are using a lower level API like "openssl req" or "openssl x509". Here is an example configuration file for lower-level calling:
# OpenSSL configuration file for signing Internet Server Certificates
extensions = extend
[req] # openssl req params prompt = no distinguished_name = dn-param
[dn-param] # DN fields C = US ST = Maryland O = University of Maryland OU = College Park Campus CN = $ENV::CERTHOST 1.DC = umd 2.DC = edu emailAddress = $ENV::CERTMAIL
[extend] # openssl extensions subjectAltName = email:$ENV::CERTMAIL # no double quotes here! issuerAltName = "DNS:umd.edu","email:[EMAIL PROTECTED]" subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always basicConstraints = critical,CA:false keyUsage = critical,Key Encipherment extendedKeyUsage = serverAuth, clientAuth nsCertType = SSL Server nsComment = "See http://cert.umd.edu/server for details." certificatePolicies = ia5org,@policy
[policy] # certificate policy extension data policyIdentifier = 1.3.6.1.4.1.4305.1.2.1 CPS = "http://cert.umd.edu/certpolicy"
# sconfig
This configuration file is entirely static; the varying parts are supplied by environment variable substitution (see the $ENV stores in the example code below). It is passed to "openssl req" to create a request and also to "openssl x509" to sign the request. Here is some example Perl code.
# ##### CSRQMAKE #####
# Generate a Certificate Signing Request (CSR)
# csrqmake(vault,vkey,openssl,hostname,email)
# If the requestor did not supply a CSR # this routine generates a private key and a CSR.
sub csrqmake { my ($vault,$vkey,$openssl,$certhost,$certmail) = @_;
my $pid, $error, $csr, $pkey; # PID, error, result
$ENV{'CERTHOST'} = $certhost; # Add server to config $ENV{'CERTMAIL'} = $certmail; # Add email to config
{ $^F = 99; # FORCE CLOSE-ON-WRITE OFF!!! pipe KCR,KCW; # Kid Code Read/Write pipe KPR,KPW; # Kid Private Key Read/Write }
# Copy passphrase from the vault into the KC pipe.
if ( !forkcode(sub{ # Run this in forked process close KCR; # Close parent's pipe end open STDOUT,'>&KCW'; # Bind std out to the KC pipe exec $vault,$vkey; # Send passphrase to KCW die "Could not EXEC vault (csrqmake): $!"; # NOT REACHED }) ) { htmlfail "Could not FORK (csrqmake): $!"; } close KCW; # Close kid's pipe end
# Run OpenSSL req to generate the private key and CSR
pipe KOR,KOW; # Kid (std) Output Read/Write pipe KER,KEW; # Kid (err) Output Read/Write if ( !($pid=forkcode(sub{ # Run in forked process close KER; # Close parent's pipe end close KOR; # Close parent's pipe end open STDOUT,'>&KOW'; # Bind pipe to standard out open STDERR,'>&KEW'; # Bind pipe to standard err exec $openssl.' req -config ../config/sconfig'. ' -newkey rsa:2048 -keyout /dev/fd/'.fileno(KPW). ' -passout fd:'.fileno(KCR); die "Could not EXEC OpenSSL (csrqmake): $!"; # NOT REACHED })) ) { htmlfail "Could not FORK (csrqmake): $!"; } close KCR; # Close pipe from vault close KPW; # Close kid's pipe end close KOW; # Close kid's pipe end close KEW; # Close kid's pipe end read KER,$error,4096; # Read any errors from kid read KOR,$csr,4096; # Read any output from kid read KPR,$pkey,4096; # Read private key from kid waitpid($pid,0); # Wait for kid to terminate if ($?) { # If error in kid htmlfail "OpenSSL req failed (gencsr):\n".$error; } close KOR; # Close pipe from kid close KER; # Close pipe from kid close KPR; # Close pipe from kid
return ($csr,$pkey); # Return CSR and private key }
# ##### CERTSIGN #####
# Generate a signed certificate
# certsign(vault,vkey,openssl,serialno,signreq,lifetime,email);
sub certsign { my ($vault,$vkey,$openssl,$serial,$csr,$certlife,$certmail) = @_;
my $pid, $error, $cert; # PID, error, result
$ENV{'CERTMAIL'} = $certmail; # Add altname to extension $ENV{'CERTHOST'} = 'placeholder'; # Kluge
{ $^F = 99; # FORCE CLOSE-ON-WRITE OFF!!! pipe KDR,KDW; # Kid Decode passphr R/W pipe KSR,KSW; # Kid Serial number R/W }
my $hex = sprintf("%lx",$serial); # Convert serial to hex if ( length($hex)%2 ) { $hex = '0'.$hex; # Even num digits required! } print KSW $hex; # Write serial number to pipe close KSW; # Make EOF
# Copy passphrase from the vault into the KD pipe.
if ( !forkcode(sub{ # Run in forked process close KDR; # Close parent's end of pipe open STDOUT,'>&KDW'; # Bind std out to the KD pipe exec $vault,$vkey; # Send passphrase to KDW die "Could not EXEC vault (certsign): $!"; # NOT REACHED }) ) { htmlfail "Could not FORK (certsign): $!"; } close KDW; # Close kid's pipe end
# Run OpenSSL x509 to sign the certificate
pipe KIR,KIW; # Kid (std) Input Read/Write pipe KOR,KOW; # Kid (std) Output Read/Write pipe KER,KEW; # Kid Error (output) R/W if ( !($pid=forkcode(sub{ # Run in forked process close KIW; # Close parent's end of pipe close KOR; # Close parent's end of pipe close KER; # Close parent's end of pipe open STDIN, '<&KIR'; # Bind pipe to standard in open STDOUT,'>&KOW'; # Bind pipe to standard out open STDERR,'>&KEW'; # Bind pipe to standard err exec $openssl.' x509 -req -sha1 -extfile ../config/sconfig'. ' -CA ../certs/ssign.cert.pem'. ' -CAkey /usr/local/nobackup/umcpca/ssign.key.pem'. ' -CAserial /dev/fd/'.fileno(KSR). ' -days '.$certlife. ' -passin fd:'.fileno(KDR); die "Could not EXEC OpenSSL (certsign): $!"; # NOT REACHED })) ) { htmlfail "Could not FORK (certsign): $!" ; } close KDR; # Close pipe from vault close KIR; # Close kid's pipe end close KOW; # Close kid's pipe end close KEW; # Close kid's pipe end print KIW $csr; # Send input to kid close KIW; # Cause an end of file read KER,$error,4096; # Read any errors from kid read KOR,$cert,4096; # Read any output from kid waitpid($pid,0); # Wait for kid to terminate if ($?) { htmlfail "OpenSSL x509 failed (certsign):\n".$error; } close KOR; # Close pipe from kid close KER; # Close pipe from kid
return $cert; # Return cert to caller }
# Run a new forked process (passed as an anonymous subroutine)
# $pid = forkcode(sub{code});
# Returns zero if the fork failed # If return is nonzero then # The code passed is running in the child process # The return value is the process ID of the child
sub forkcode { my $pid; # Process ID my $childcode = @_[0]; # Code to run as child while ( !defined($pid=fork) ) { # Retry until fork succeeds if ($! !~ /No more process/) { # Under some conditions retry return 0; # Return failure } sleep 5; # Delay between retries } if ($pid) { # If fork succeed and parent return $pid; # Return PID to parent } &$childcode; # Child runs passed code exit; # Child does NOT return }
These examples are for SSL Server certificates. I have some minor skeletal code for identity and privacy certificates, which uses "openssl ca" instead. I have posted that code on this list before. Contact me via direct email if you want a copy.
BTW I've started to work on this code several times, and each time a SSL Server CA emergency has forced me to back-burner it, so I'm not picking the work up again until after August when our old root expires. When the sturm und drang from that dies down I will look at the identity and privacy CA stuff again.
[EMAIL PROTECTED] wrote:
Hi,
I want to create a request automatically with an webapplication. So the persons enter the details into a form an I write a temporary config-file to create request. But how does the content of the config-file look, that it contains the details (cn, o, ou,...) and how does the command look, what I have to execute?
Hope anybody can help me..
Thanx a lot for help!!!!
Carsten
-- 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]