Jack Disu schrieb:
>
> I am used newCSR which you attached , now it takes subjectAlt
> Name as a email ID but still it not isssue the
> certificate give the error
>
> Error 6783
> General Error. Error while storing req to archived requests! The
> database returns errorcode 10007 (ENTRY_NOT_EXIST)..
This was my mistake because I use different codebases. I forgot to
commit and attach crypto-utils.lib. The code only try to move the
request from the pending and approved requests to the archived request
but the code ignores requests with the status renew.
> also request not edit at RA.
> One more thing I am using mysql database.
I use mysql too.
> Also write a mail is not solved, I browse CVS
> but can't conclued.
This change is a little bit more complex. I removed the directory
src/common/lib/mails completely and changed the Makefile in
src/common/lib/. After this I added the removed directory mails in
/src/web-interfaces/ra/i18n/english/ and changed the Makefile of
/src/web-interfaces/ra/i18n/english/.
So you should use the new RC.
Warning: in some minutes I change the RC4 because there was a build-bug.
Michael
--
-------------------------------------------------------------------
Michael Bell Email (private): [EMAIL PROTECTED]
Rechenzentrum - Datacenter Email: [EMAIL PROTECTED]
Humboldt-University of Berlin Tel.: +49 (0)30-2093 2482
Unter den Linden 6 Fax: +49 (0)30-2093 2959
10099 Berlin
Germany http://www.openca.org
## Certification Authority (HTML Interface)
## (c) 1999 by Massimiliano Pala and OpenCA Group
## All Rights Reserved
##
## Program currently tested with Perl5 Linux, Solaris and Apache.
##
## DISC CLAIMER: THIS SOFTWARE IS GIVEN AS IS WITHOUT ANY WARRANTIES
## ABOUT ANY DAMAGE DERIVED BY THE USE ( CORRECT OR NOT ) OF THIS
## SOFTWARE. THE AUTHOR IS THEREFORE NOT RESPONSABLE IN ANY WAY OF
## DAMAGES RELATED IN ANY WAY TO THIS OR SUPPORTED SOFTWARE AS WELL.
##
## Thank you for using this software, and remember that Open Projects
## are the future of mankind. Do not sleep, partecipate to world wide
## efforts to make life easier for all!
## only for testing the library
#use strict;
#my $errno;
#my $errval;
#my $cryptoShell;
#my $tools;
#my $db;
##
## following you can find the defined errorcodes of this library
## please take in mind that this is THE crypto-library of OpenCA
##
## functions and their domains
## ===========================
##
## general error 6000-6099
## libCheckSignature 6101-6199
## libGetSignatureObject 6201-6299
## libGetSignerCertificateDB 6301-6399
## export_openssl_db 6401-6499
## updateOCSPdata 6501-6599
## master alert 6600-6699
## libIssueCertificate 6701-6799
## libRevokeCertificate 6801-6899
##
## functions and their errorcodes
## ==============================
##
## libCheckSignature
## -----------------
## 6101 Parameters error, needed at least item or object
## 6102 The PKCS#7-object signals an error. The signature is not valid.
## 6103 Signer's certificate is corrupt!
## 6104 Signer's Certificate and DB's Certificate do not match.
##
## libGetSignatureObject
## ---------------------
## 6201 Cannot determine signature from non-existent object!
## 6202 The body of the request is empty!
## 6203 The request is not signed!
## 6204 Cannot store the body of the request in the file ...
## 6205 Cannot store the signature of the request in the file ...
## 6206 Cannot build PKCS#7-object from extracted signature!
##
## libGetSignerCertificateDB
## -------------------------
## 6301 Cannot determine signer because there is no signature present!
## 6302 Cannot create X509-object from the certificate of the signer!
## 6303 Cannot find the certificate with the matching serial in the database!
##
## export_openssl_db
## -----------------
## 6401 Cannot open databasefile of OpenSSL for writing.
## 6402 Cannot open file with the next serial of OpenSSL for writing.
##
## updateOCSPdata
## --------------
## 6501 No database was submitted.
## 6502 Cannot link to new index.txt for OCSP daemon.
## 6503 Cannot remove temp-file.
##
## libIssueCertificate
## -------------------
## 6701 Needed key to access database!
## 6702 Needed passwd!
## 6703 SERVICE_MAIL_ACCOUNT not defined in configfile
## 6711 Cannot Access Request!
## 6711 Another cert with the same key detected
## 6721 Cannot write to tempfile
## 6731 Cannot get a DN from the request!
## 6735 A Valid Certificate with same DN exists!
## 6741 Cannot create backup for OpenSSL's indexfile!
## 6742 Cannot create backup for OpenSSL's serialfile!
## 6751 openssl->issueCert failed
## 6755 objectcreation from new cert failed
## 6757 Error while storing the request's serial in cert-object
## 6761 Error while signing Role
## 6762 Error while storing role in cert-object
## 6763 Error while storing role-signature in cert-object
## 6771 The parameter of the PIN are unknown!
## 6779 Cannot create PIN!
## 6772 Cannot hash PIN!
## 6773 PIN-mail cannot be created!
## 6774 Cannot encrypt PIN-mail!
## 6775 Cannot store the PIN-mail in the directory for the mails!
## 6776 Error while signing PIN
## 6777 Error while storing role in cert-object
## 6778 Error while storing role-signature in cert-object
## 6781 Error while storing cert in database
## 6783 Error while storing req to archived requests!
##
## libRevokeCertificate
## --------------------
## 6801 Needed key to access database!
## 6802 Needed passwd!
## 6811 Cannot Access CRR in the database!
## 6821 The certificate is always revoked so please delete the CRR!
## 6831 Certificate was not found in the database!
## 6841 Error while revoking Certificate!
## 6851 Error changing status from certificate
## 6861 Error changing status from crr to Revoked dB
# sub signData {
# my $keys = { @_ };
# my $ret;
#
# return $ret;
# }
# sub cryptData {
# my $keys = { @_ };
# my $ret;
#
# return $ret;
# }
# sub envelope {
#
# return;
# }
sub libCheckSignature {
my $keys = { @_ };
my $item = $keys->{OBJECT};
my $sig = $keys->{SIGNATURE};
my ( $sigCert );
if( (not $item) and (not $sig) ) {
$errno = 6101;
$errval = "Parameters error, needed at least item or object";
return undef;
}
## Get the signature Object if not already given
if( $item ) {
$sig = libGetSignatureObject( OBJECT=>$item );
if( not $sig ) {
## take errorcode and errorvalue from the called function
return undef;
}
}
if( $sig->errno() != 0 ) {
$errno = 6102;
$errval = "The PKCS#7-object signals an error. ".
"The signature is not valid.<br>\n".
"PKCS#7-Error ".$sig->errno().": ".$sig->errval();
return undef;
} else {
$errval = "Signature Correctly Verified";
}
## Get signer certificate (or it should be - serial oriented)
## form the local dB
my $tmpCert = libGetSignerCertificateDB( SIGNATURE=> $sig );
if( not $tmpCert ) {
## take the errorcode and errorvalue from the called function
return undef;
}
## Get signer certificate from the pkcs7 structure
$sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
DATA => $sig->getSigner()->{CERTIFICATE});
if( not $sigCert ) {
$errno = 6103;
$errval = "Signer's certificate is corrupt!\n".
"OpenCA::X509 returns errorcode ".
$OpenCA::X509::errno." (".$OpenCA::X509::errval.").";
return undef;
}
if( $tmpCert->getSerial() ne $sigCert->getSerial() ) {
$errno = 6104;
$errval = "Signer's Certificate and DB's Certificate do not" .
" match";
return undef;
}
return 1;
}
sub libGetSignatureObject {
my $keys = { @_ };
my $item = $keys->{OBJECT};
my $tempDir = getRequired('tempDir');
my $chainDir = getRequired('ChainDir');
my ( $sig, $parsed );
if (not $item) {
$errno = 6201;
$errval = "Cannot determine signature from non-existent object!";
return undef;
}
## Get Parsed Object
$parsed = $item->getParsed();
if (not $parsed->{BODY} and not $parsed->{RAWHEADER}) {
$errno = 6202;
$errval = "The body of the request is empty!";
return undef;
}
if (not $parsed->{SIGNATURE}) {
$errno = 6203;
$errval = "The request is not signed!";
return undef;
}
my $message = $parsed->{RAWHEADER}."\n".$parsed->{BODY};
## Save signature and check it
if (not $tools->saveFile( FILENAME=>"${tempDir}/${$}.req",
DATA=>$message )) {
$errno = 6204;
$errval = "Cannot store the body of the request in the file
${tempDir}/${$}.req.";
unlink( "${tempDir}/${$}.req" );
return undef;
}
if (not $tools->saveFile( FILENAME=>"${tempDir}/${$}.sig",
DATA=>$parsed->{SIGNATURE} )) {
$errno = 6205;
$errval = "Cannot store the signature of the request in the file
${tempDir}/${$}.sig.";
unlink( "${tempDir}/${$}.sig" );
unlink( "${tempDir}/${$}.req" );
return undef;
}
## Build a new PKCS7 object
$sig = new OpenCA::PKCS7( SHELL=>$cryptoShell,
INFILE=>"${tempDir}/${$}.sig",
DATAFILE=>"${tempDir}/${$}.req",
CA_DIR=>"${chainDir}" );
unlink( "${tempDir}/${$}.sig" );
unlink( "${tempDir}/${$}.req" );
if (not $sig) {
$errno = 6206;
$errval = "Cannot build PKCS#7-object from extracted signature!\n".
"OpenCA::PKCS7 returns errorcode ".
$OpenCA::PKCS7::errno." (".$OpenCA::PKCS7::errval.").";
return undef;
}
return $sig;
}
sub libGetSignerCertificateDB {
my $keys = { @_ };
my $sig = $keys->{SIGNATURE};
if (not $sig) {
$errno = 6301;
$errval = "Cannot determine signer because there is no signature
present!";
return undef;
}
my $sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
DATA => $sig->getSigner()->{CERTIFICATE});
if (not $sigCert) {
$errno = 6302;
$errval = "Cannot create X509-object from the certificate of the
signer!".
"OpenCA::X509 returns errorcode ".
$OpenCA::X509::errno." (".$OpenCA::X509::errval.").";
return undef;
}
my $db_cert = $db->getItem( DATATYPE => 'CERTIFICATE',
KEY => $sigCert->getSerial() );
if( not $db_cert ) {
$errno = 6303;
$errval = "Cannot find the certificate with the matching serial in the
database!";
return undef;
} else {
return $db_cert;
}
}
################################################
## recover index.txt and serial from database ##
################################################
## begin of recovery code ##
################################################
sub export_openssl_db {
my $keys = { @_ };
## $keys->{DB};
## $keys->{SERIAL};
## $keys->{OCSP};
## if defined and (Y|ON) then SUSPENDED will be interpreted like REVOKED
my @index;
my $max = 0;
my @list;
## all entries are hashes with the following format
## STATUS V,E,R
## DATE_1
## DATE_2
## SERIAL
## DN
print addLogSection ("Loading the Objects ...");
## get all valid_ca_certificates
@list = $db->searchItems ( DATATYPE => "VALID_CA_CERTIFICATE" );
foreach my $value (@list) {
my %hash;
$hash {STATUS} = "V";
$hash {DATE_1} = $cryptoShell->getOpenSSLDate ($value->getParsed ()->{NOTBEFORE});
$hash {DATE_2} = "";
if ($value->getSerial() < 16) {
$hash {SERIAL} = "0";
} else {
$hash {SERIAL} = "";
}
$hash {SERIAL} .= sprintf ("%lX", $value->getSerial());
$hash {DN} = $value->getParsed ()->{DN};
print addPreLogLine ("VALID_CA_CERTIFICATE: ".$hash{SERIAL});
$index [$value->getSerial()] = \%hash;
$max = $value->getSerial() if ($value->getSerial() > $max);
}
## get all expired_ca_certificates
@list = $db->searchItems ( DATATYPE => "EXPIRED_CA_CERTIFICATE" );
foreach my $value (@list) {
my %hash;
$hash {STATUS} = "E";
$hash {DATE_1} = $cryptoShell->getOpenSSLDate ($value->getParsed ()->{NOTBEFORE});
$hash {DATE_2} = "";
if ($value->getSerial() < 16) {
$hash {SERIAL} = "0";
} else {
$hash {SERIAL} = "";
}
$hash {SERIAL} .= sprintf ("%lX", $value->getSerial());
$hash {DN} = $value->getParsed ()->{DN};
print addPreLogLine ("EXPIRED_CA_CERTIFICATE: ".$hash{SERIAL});
$index [$value->getSerial()] = \%hash;
$max = $value->getSerial() if ($value->getSerial() > $max);
}
## get all valid_certificates
@list = $db->searchItems ( DATATYPE => "VALID_CERTIFICATE" );
foreach my $value (@list) {
my %hash;
$hash {STATUS} = "V";
$hash {DATE_1} = $cryptoShell->getOpenSSLDate ($value->getParsed ()->{NOTBEFORE});
$hash {DATE_2} = "";
if ($value->getSerial() < 16) {
$hash {SERIAL} = "0";
} else {
$hash {SERIAL} = "";
}
$hash {SERIAL} .= sprintf ("%lX", $value->getSerial());
$hash {DN} = $value->getParsed ()->{DN};
print addPreLogLine ("VALID_CERTIFICATE: ".$hash{SERIAL});
$index [$value->getSerial()] = \%hash;
$max = $value->getSerial() if ($value->getSerial() > $max);
}
## get all expired_certificates
@list = $db->searchItems ( DATATYPE => "EXPIRED_CERTIFICATE" );
foreach my $value (@list) {
my %hash;
$hash {STATUS} = "E";
$hash {DATE_1} = $cryptoShell->getOpenSSLDate ($value->getParsed ()->{NOTBEFORE});
$hash {DATE_2} = "";
if ($value->getSerial() < 16) {
$hash {SERIAL} = "0";
} else {
$hash {SERIAL} = "";
}
$hash {SERIAL} .= sprintf ("%lX", $value->getSerial());
$hash {DN} = $value->getParsed ()->{DN};
print addPreLogLine ("EXPIRED_CERTIFICATE: ".$hash{SERIAL});
$index [$value->getSerial()] = \%hash;
$max = $value->getSerial() if ($value->getSerial() > $max);
}
## get all suspended_certificates
@list = $db->searchItems ( DATATYPE => "SUSPENDED_CERTIFICATE" );
foreach my $value (@list) {
my %hash;
if (defined $keys->{OCSP} and ($keys->{OCSP} =~ /Y|ON/i)) {
$hash {STATUS} = "R";
} else {
$hash {STATUS} = "V";
}
$hash {DATE_1} = $cryptoShell->getOpenSSLDate ($value->getParsed ()->{NOTBEFORE});
$hash {DATE_2} = "";
if ($value->getSerial() < 16) {
$hash {SERIAL} = "0";
} else {
$hash {SERIAL} = "";
}
$hash {SERIAL} .= sprintf ("%lX", $value->getSerial());
$hash {DN} = $value->getParsed ()->{DN};
print addPreLogLine ("SUSPENDED_CERTIFICATE: ".$hash{SERIAL});
$index [$value->getSerial()] = \%hash;
$max = $value->getSerial() if ($value->getSerial() > $max);
}
## get all revoked_certificates
@list = $db->searchItems ( DATATYPE => "REVOKED_CERTIFICATE" );
foreach my $value (@list) {
my %hash;
$hash {STATUS} = "R";
$hash {DATE_1} = $cryptoShell->getOpenSSLDate ($value->getParsed ()->{NOTBEFORE});
if ($value->getSerial() < 16) {
$hash {SERIAL} = "0";
} else {
$hash {SERIAL} = "";
}
$hash {SERIAL} .= sprintf ("%lX", $value->getSerial());
$hash {DN} = $value->getParsed ()->{DN};
my @result = $db->searchItems ( DATATYPE => "ARCHIVED_CRR",
REVOKED_CERTIFICATE_DN => $hash {DN} );
$hash {DATE_2} = "991231235959Z";
my $h = 99991231235959;
foreach my $value (@result) {
if ($h > $cryptoShell->getNumericDate ($value->getParsed ()->{SUBMIT_DATE})) {
$h = $cryptoShell->getNumericDate ($value->getParsed ()->{SUBMIT_DATE});
$hash {DATE_2} = $cryptoShell->getOpenSSLDate ($value->getParsed
()->{SUBMIT_DATE});
}
}
print addPreLogLine ("REVOKED_CERTIFICATE: ".$hash{SERIAL});
$index [$value->getSerial()] = \%hash;
$max = $value->getSerial() if ($value->getSerial() > $max);
}
print closeLogSection ();
## write index database of openssl
if (defined $keys->{OCSP} and ($keys->{OCSP} =~ /Y|ON/i)) {
print addLogSection ("Writing index.txt for the OCSP daemon (".$keys->{DB}.")
...");
} else {
print addLogSection ("Writing index.txt (".$keys->{DB}.") ...");
}
if (not open( FD, ">$keys->{DB}" )) {
$errno = 6401;
$errval = "Cannot open databasefile ".$keys->{DB}." of OpenSSL for writing.";
return undef;
}
my $i;
foreach $i (@index) {
$i->{DN} =~ s/, */\//g;
$i->{DN} = "/".$i->{DN};
print FD $i->{STATUS}."\t".
$i->{DATE_1}."\t".
$i->{DATE_2}."\t".
$i->{SERIAL}."\tunknown\t".
$i->{DN}."\n";
print addPreLogLine ( $i->{STATUS}." ".
$i->{DATE_1}." ".
$i->{DATE_2}." ".
$i->{SERIAL}." unknown ".
$i->{DN} );
}
close(FD);
print closeLogSection ();
if (not (defined $keys->{OCSP} and ($keys->{OCSP} =~ /Y|ON/i))) {
## write serial
print addLogSection ("Writing serial (".$keys->{SERIAL}.") ...");
if (not open( FD, ">$keys->{SERIAL}" )) {
$errno = 6402;
$errval = "Cannot open file ".$keys->{DB}." with the next serial of OpenSSL
for writing.";
return undef;
}
$max++;
print FD "0" if ($max < 16);
print FD sprintf ("%lX", $max);
close(FD);
print addLogLine ($max);
print closeLogSection ();
}
return 1;
}
################################################
## recover index.txt and serial from database ##
################################################
## end of recovery code ##
################################################
############################################
## sync the update of the index.txt which ##
## is needed by the OCSP daemon ##
############################################
## BEGIN of OCSP realted stuff ##
############################################
sub updateOCSPdata {
my $keys = { @_ };
## $keys->{DB};
## check the data
if (not defined $keys->{DB}) {
$errval = "No database was submitted.";
$errno = 6501;
return undef;
}
## build and write the index.txt
if (not export_openssl_db (
DB => getRequired ('TempDir')."/ocsp_".$$,
OCSP => "YES")) {
## use errno and errval of called function
return undef;
}
## create new link
my $command = "rm ".$keys->{DB}.
";ln ".getRequired ('TempDir')."/ocsp_".$$." ".$keys->{DB};
my $ret = `$command`;
if ( $? ) {
$errval = "Cannot link to new index.txt for OCSP daemon.";
$errno = 6502;
return undef;
}
## remove temp-file
if (not $tools->deleteFiles (DIR => getRequired ('TempDir'), FILTER =>
"ocsp_".$$)) {
$errval = "Cannot remove temp-file.";
$errno = 6503;
return undef;
}
return 1;
}
############################################
## END of OCSP related stuff ##
############################################
############################################
## begin of certificate creation ##
############################################
sub libIssueCertificate {
my $keys = { @_ };
## To aprove a Request, we need the file containing the
## user data and the SPKAC. In a second time we must be
## able to manage encrypted files with CA key.
my ( $inForm, $reqType, $reqFile, @certList );
my $tmpdir = getRequired ('TempDir');
## Get Configuration needed parameters ...
my $newCertsDir = getRequired('NewCertsDir');
my $SSLIndex = getRequired('SSLIndex');
my $SSLSerial = getRequired('SSLSerial');
my $cacert = getRequired('CACertificate');
my $cakey = getRequired('CAKey');
## PIN-parameter
my $use_req_pin = getRequired ('USE_REQUEST_PIN');
my $secure_pin_length = getRequired ('SECURE_PIN_LENGTH');
my $secure_pin_random = getRequired ('SECURE_PIN_RANDOM');
my $mail_dir = getRequired ('CRIN_MAIL_DIR');
my $account = getRequired ('SERVICE_MAIL_ACCOUNT');
my $automatic_subject_alt_name = getRequired ('AUTOMATIC_SUBJECT_ALT_NAME');
my $default_subject_alt_name = getRequired ('DEFAULT_SUBJECT_ALT_NAME');
## Get the parameters
my $key = $keys->{KEY};
my $dataType = $keys->{DATATYPE};
my $passwd = $keys->{PASSWD};
my $role;
if ( not $key ) {
$errno = 6701;
$errval = "Needed key to access database!";
return undef;
}
if ( not $passwd ) {
$errno = 6702;
$errval = "Needed passwd!";
return undef;
}
if ( not $account ) {
$errno = 6703;
$errval = "You must specify at minimum a mail account for the CA
(SERVICE_MAIL_ACCOUNT)!";
return undef;
}
## Get Request
my $req = $db->getItem ( DATATYPE => $dataType, KEY => $key );
if( not $req ) {
$errno = 6711;
$errval = "Cannot Access $key Request!\n".
"Database returns errorcode ".
$db->errno()." (".$db->errval.").";
return undef;
}
## get the role
$role = $req->getParsed()->{HEADER}->{ROLE};
my $extfile = $role;
$extfile =~ s/ /_/g;
$extfile .= ".ext";
if( $extfile ) {
$extfile = getRequired ( 'EXT_DIR')."/${extfile}";
}
my $opensslfile = $role;
$opensslfile =~ s/ /_/g;
$opensslfile .= ".conf";
if( $opensslfile ) {
$opensslfile = getRequired ( 'OpenSSL_DIR' )."/${opensslfile}";
}
if (not $req->getParsed()->{HEADER}->{RENEW}) {
## Check if there are certificates with the same keys
my @certList = $db->searchItems( DATATYPE=> "CERTIFICATE",
PUBKEY => $req->getParsed()->{PUBKEY});
my $errorString = "A Certificate with the same public key exists!
<br>\n".
"This is a keycompromise of the certificates with the
serial:\n".
"<ul>\n";
foreach my $h (@certList) {
$errorString .= "<li>".$h->getSerial()."</li>\n";
}
$errorString .= "Please revoke the certificates and delete the
request.\n";
if($#certList > -1) {
$errno = 6711;
$errval = $errorString;
return undef;
}
}
if ( $req->getParsed()->{TYPE} =~ /IE/ ) {
$reqType = "MSIE";
$inForm = PEM;
} elsif ( $req->getParsed()->{TYPE} =~ /SPKAC|MOZILLA|NETSCAPE/ ) {
$inForm = SPKAC;
} else {
$inForm = PEM;
};
## Get the serial Number the certificate will have
my ( $ser ) =
( $query->getFile("$SSLSerial") =~ /([0-9a-f]+)/i );
## Let's save the request body to a temp file
if (not $tools->saveFile( FILENAME=>"$tmpdir/${ser}.req",
DATA=>$req->getParsed()->{BODY}."\n" )) {
$errno = 6721;
$errval = "Cannot write to $tmpdir/${ser}.req";
return undef;
}
## set configFile from OpenSSL/
# it's senseless to do this because all blanks were replaced
# by underscores some lines above
# $extfile =~ s/ /\\ /g;
# $opensslfile =~ s/ /\\ /g;
$cryptoShell->setParams( CONFIG=> $opensslfile);
# prepare the DN
my $cert_subject = "";
my $attribute_name;
# perhaps the request's serial must be stored in the dn
my $use_request_serial = getRequired ('SET_REQUEST_SERIAL_IN_DN');
my $request_serial_name = "";
if ($use_request_serial =~ /^(Y|YES|ON)$/i) {
$cert_subject .= getRequired ('REQUEST_SERIAL_NAME')."=".$ser.",";
}
# perhaps the cert's serial must be stored in the dn
my $use_cert_serial = getRequired ('SET_CERTIFICATE_SERIAL_IN_DN');
my $cert_serial_name = "";
if ($use_cert_serial =~ /^(Y|YES|ON)$/i) {
$cert_subject = getRequired ('CERTIFICATE_SERIAL_NAME')."=".$ser.",";
}
if ($req->getParsed()->{HEADER}->{SUBJECT}) {
$cert_subject .= $req->getParsed()->{HEADER}->{SUBJECT};
} elsif (defined $req->getParsed()->{DN} and $req->getParsed()->{DN}) {
$cert_subject .= $req->getParsed()->{DN};
} else {
$errno = 6731;
$errval = "Cannot get a DN from the request!";
return undef;
}
## filter email if necessary
if ( getRequired ('DN_WITHOUT_EMAIL') =~ /Y|YES|ON/i ) {
$cert_subject =~ s/^\s*EMAIL\s*=[^,]*,\s*//i;
$cert_subject =~ s/^\s*EMAILADDRESS\s*=[^,]*,\s*//i;
$cert_subject =~ s/,\s*EMAIL\s*=[^,]*//i;
$cert_subject =~ s/,\s*EMAILADDRESS\s*=[^,]*//i;
} else {
$cert_subject =~ s/^\s*EMAILADDRESS\s*=/emailAddress=/i;
$cert_subject =~ s/^\s*EMAIL\s*=/emailAddress=/i;
$cert_subject =~ s/,\s*EMAILADDRESS\s*=/,emailAddress=/i;
$cert_subject =~ s/,\s*EMAIL\s*=/,emailAddress=/i;
}
print "issueCertificate: \$cert_subject: ".$cert_subject."<br>\n" if ($DEBUG);
## Check if there are certificates with the same DN
@certList = $db->searchItems( DATATYPE=>"VALID_CERTIFICATE",
DN=>$cert_subject );
if($#certList > -1) {
$errno = 6735;
$errval = "A Valid Certificate with same DN exists!";
return undef;
}
# set the subjectAlternativeName
# * we don't use email:copy to be able to support PKIX-recommendations
# and S/MIME v3
# * Email should not be in the DN so email:copy is senseless
# * preserveDN is not recommended by openssl develeopers
if ( $req->getParsed()->{HEADER}->{SUBJECT_ALT_NAME} ) {
$ENV{'subjectAltName'} =
$req->getParsed()->{HEADER}->{SUBJECT_ALT_NAME};
} elsif ( $automatic_subject_alt_name =~ /(Y|YES|ON)/i ) {
## perhaps we support DNS and IP in the future too
if ( ($default_subject_alt_name =~ /Email/i) and
$req->getParsed()->{DN_HASH}->{EMAILADDRESS}
) {
$ENV{'subjectAltName'} =
"email:".$req->getParsed()->{DN_HASH}->{EMAILADDRESS}[0];
} else {
$ENV{'subjectAltName'} = "";
}
} else {
$ENV{'subjectAltName'} = "";
}
## creating backup-files for openssl
if ( not $tools->copyFiles (SRC => getRequired ('sslindex'),
DEST => $tmpdir."/openssl_backup_".$$."_index.txt")) {
$errno = 6741;
$errval = "Cannot create backup for OpenSSL's indexfile!";
return undef;
}
if (not $tools->copyFiles (SRC => getRequired ('sslserial'),
DEST => $tmpdir."/openssl_backup_".$$."_serial")) {
$errno = 6742;
$errval = "Cannot create backup for OpenSSL's serialfile!";
return undef;
}
## Issue the Certificate
if ( not $cryptoShell->issueCert(
REQFILE => "$tmpdir/${ser}.req",
SUBJECT => $cert_subject,
INFORM => $inForm,
EXTFILE => $extfile,
PRESERVE_DN => Y,
CAKEY => $cakey,
CACERT => $cacert,
PASSWD => "$passwd" ) ) {
libIssueCertificateRestoreOpensslState ();
$errno = 6751;
$errval = "Error while issuing Certificate to ".
$req->getParsed()->{DN_HASH}->{CN}[0] . "<BR><BR>".
"(file name: $tmpdir/${ser}.req).<br><br>\n".
"OpenCA::OpenSSL returns errocode ".$OpenCA::OpenSSL::errno."
(".$OpenCA::OpenSSL::errval.").";
return undef;
}
## Unlinking Temporary File
unlink( "$tmpdir/${ser}.req" );
## add a possible keypair to the cert
my $certdata = $tools->getFile ("${newCertsDir}/${ser}.pem");
$certdata .= $req->getParsed()->{KEY};
$tools->saveFile (FILENAME => "${newCertsDir}/${ser}.pem", DATA => $certdata);
## Put the certificate in the certificate DB
my $cert = new OpenCA::X509 ( SHELL=>$cryptoShell,
INFILE=>"${newCertsDir}/${ser}.pem" );
if (not $cert) {
libIssueCertificateRestoreOpensslState ();
$errno = 6755;
$errval = "Error while opening ${newCertsDir}/${ser}.pem.\n".
"OpenCA::X509 returns errorcode ".
$OpenCA::X509::errno." (".$OpenCA::X509::errval.").";
return undef;
}
###########################################
## add the requests serial to the header ##
###########################################
if ( not $cert->setHeaderAttribute (CSR_SERIAL => $req->getSerial())) {
libIssueCertificateRestoreOpensslState ();
$errno = 6757;
$errval = "Error while storing the request's serial in cert-object";
return undef;
}
#########################
## role initialization ##
#########################
## sign the role
if ( not $cryptoShell->sign(
DATA => $ser."\n".$role,
OUT_FILE => $tmpdir."/".$ser.".sig",
KEY_FILE => $cakey,
CERT_FILE => $cacert,
PASSWD => "$passwd" ) ) {
libIssueCertificateRestoreOpensslState ();
$errno = 6761;
$errval = "Error while signing Role of ".
$req->getParsed()->{DN_HASH}->{CN}[0] . "<BR><BR>".
"(file name: $tmpdir/${ser}.sig ).<br>\n".
"OpenCA::OpenSSL returns errorcode ".
$OpenCA::OpenSSL::errno." (".$OpenCA::OpenSSL::errval.").";
return undef;
}
## including the signaturer into the certificate
## adding the signature to the pemCert
## not nice because the objectrientation is ignored
if ( not $cert->setHeaderAttribute (ROLE => $role)) {
libIssueCertificateRestoreOpensslState ();
$errno = 6762;
$errval = "Error while storing role in cert-object";
return undef;
}
if ( not $cert->setHeaderAttribute (ROLE_SIGNATURE => $tools->getFile
($tmpdir."/".$ser.".sig"))) {
libIssueCertificateRestoreOpensslState ();
$errno = 6763;
$errval = "Error while storing role-signature in cert-object";
return undef;
}
unlink ($tmpdir."/".$ser.".sig");
########################
## PIN initialization ##
########################
my $msg;
my $hashed_pin;
## which PIN should be used ?
if ($use_req_pin and ($use_req_pin =~ /^YES$/i)) {
## use request's PIN
## load prepared mail
$msg = $tools->getFile (getRequired ('REQUEST_PIN_MAIL'));
} else {
## generate new PIN
my $pin;
## get PIN
if (getRequired ('SECURE_PIN_LENGTH')) {
if (getRequired ('SECURE_PIN_RANDOM')) {
$pin = $cryptoShell->getPIN (
PIN_LENGTH => getRequired
('SECURE_PIN_LENGTH'),
RANDOM_LENGTH => getRequired
('SECURE_PIN_RANDOM')
);
} else {
$pin = $cryptoShell->getPIN (
PIN_LENGTH => getRequired
('SECURE_PIN_LENGTH')
);
}
} elsif (getRequired ('SECURE_PIN_RANDOM')) {
$pin = $cryptoShell->getPIN (
RANDOM_LENGTH => getRequired
('SECURE_PIN_RANDOM')
);
} else {
libIssueCertificateRestoreOpensslState ();
$errno = 6771;
$errval = "The parameter of the PIN are unknown!";
return undef;
}
if (not $pin) {
libIssueCertificateRestoreOpensslState ();
$errno = 6779;
$errval = "Cannot create PIN!\n".
"OpenCA::OpenSSL returns errorcode ".
$OpenCA::OpenSSL::errno."
(".$OpenCA::OpenSSL::errval.").";
return undef;
}
## load prepared mail
$msg = $tools->getFile (getRequired ('SECURE_PIN_MAIL'));
## replace the PIN in the mail
$msg = $query->subVar( $msg, '$PIN', $pin );
## hash the PIN
$hashed_pin = $cryptoShell->getDigest (
DATA => $pin,
ALGORITHM => "sha1");
if (not $hashed_pin) {
libIssueCertificateRestoreOpensslState ();
$errno = 6772;
$errval = "Cannot hash PIN!".
"OpenCA::OpenSSL returns errorcode ".
$OpenCA::OpenSSL::errno."
(".$OpenCA::OpenSSL::errval.").";
return undef;
}
}
## replace the standad variables in the mail
## actully there are no such variables
## later there should be mail, dn, serial and cn used
## check msg
if (not $msg) {
libIssueCertificateRestoreOpensslState ();
$errno = 6773;
$errval = "PIN-mail cannot be created!";
return undef;
}
## sign and encrypt
## sign deactivated because of a mismatch with the CA's-extensions
my $enc_msg;
if ( defined $cert->getParsed()->{EMAILADDRESS} and
$cert->getParsed()->{EMAILADDRESS} ) {
$enc_msg = $cryptoShell->getSMIME (
ENCRYPT => 1,
SIGN => 0,
ENCRYPT_CERT => "${newCertsDir}/${ser}.pem",
SIGN_CERT => $cacert,
SIGN_KEY => $cakey,
SIGN_PASSWD => "$passwd",
MESSAGE => $msg,
TO => $cert->getParsed()->{EMAILADDRESS},
FROM => $account,
SUBJECT => "OpenCA Certificate and PIN
information");
} else {
## send to the admin itself and print a warning
$enc_msg = $cryptoShell->getSMIME (
ENCRYPT => 1,
SIGN => 0,
ENCRYPT_CERT => "${newCertsDir}/${ser}.pem",
SIGN_CERT => $cacert,
SIGN_KEY => $cakey,
SIGN_PASSWD => "$passwd",
MESSAGE => $msg,
TO => $account,
FROM => $account,
SUBJECT => "OpenCA Certificate and PIN
information for certificate ${ser}");
}
if (not $enc_msg) {
libIssueCertificateRestoreOpensslState ();
$errno = 6774;
$errval = "Cannot encrypt PIN-mail! Aborting!\n".
"OpenCA::OpenSSL returns errorcode ".
$OpenCA::OpenSSL::errno." (".$OpenCA::OpenSSL::errval.").";
return undef;
}
## store the mail in the maildirectory
my $mail_ser = $cert->getSerial();
$mail_ser =~ s/^0*//;
if (not $tools->saveFile (
FILENAME => $mail_dir."/".$mail_ser.".msg",
DATA => $enc_msg)) {
libIssueCertificateRestoreOpensslState ();
$errno = 6775;
$errval = "Cannot store the PIN-mail in the directory for the mails!";
return undef;
}
## sign the PIN
if ( not $cryptoShell->sign(
DATA => $hashed_pin,
OUT_FILE => $tmpdir."/".$ser.".sig",
KEY_FILE => $cakey,
CERT_FILE => $cacert,
PASSWD => "$passwd" ) ) {
libIssueCertificateRestoreOpensslState ();
$errno = 6776;
$errval = "Error while signing PIN of ".
$req->getParsed()->{DN_HASH}->{CN}[0] . "<BR><BR>".
"(file name: $tmpdir/${ser}.sig )\n<br>".
"OpenCA::OpenSSL returns errorcode ".
$OpenCA::OpenSSL::errno." (".$OpenCA::OpenSSL::errval.").";
return undef;
}
## including the signaturer into the certificate
## adding the signature to the pemCert
## not nice because the objectorientation is ignored
## store the PIN in the header
if ( not $cert->setHeaderAttribute (PIN => $hashed_pin)) {
libIssueCertificateRestoreOpensslState ();
$errno = 6777;
$errval = "Error while storing role in cert-object.\n".
"OpenCA::X509 returns errorcode ".
$OpenCA::X509::errno." (".$OpenCA::X509::errval.").";
return undef;
}
if ( not $cert->setHeaderAttribute (PIN_SIGNATURE => $tools->getFile
($tmpdir."/".$ser.".sig"))) {
libIssueCertificateRestoreOpensslState ();
$errno = 6778;
$errval = "Error while storing role-signature in cert-object.\n".
"OpenCA::X509 returns errorcode ".
$OpenCA::X509::errno." (".$OpenCA::X509::errval.").";
return undef;
}
unlink ($tmpdir."/".$ser.".sig");
###############
## DB change ##
###############
if ( not $db->storeItem( DATATYPE=>VALID_CERTIFICATE, OBJECT=>$cert,
MODE=>"INSERT" )) {
$errno = 6781;
$errval = "Error while storing ${ser}.pem cert in dB!\n".
"The database returns errorcode ".
$db->errno()." (".$db->errval().").";
return undef;
}
## destroying backupfiles from openssl
$tools->deleteFiles (DIR => $tmpdir, FILTER => "openssl_backup_".$$."_*");
## Put the Request in the archived requests DBM. This is built
## as $serial=>$req where the serial is the certificate's
## serial number and the req is the request file
if( not $db->updateStatus( OBJECT=>$req,
DATATYPE=>"APPROVED_REQUEST",
NEWTYPE=>"ARCHIVED_REQUEST" ) and
not $db->updateStatus( OBJECT=>$req,
DATATYPE=>"PENDING_REQUEST",
NEWTYPE=>"ARCHIVED_REQUEST" ) and
not $db->updateStatus( OBJECT=>$req,
DATATYPE=>"RENEW_REQUEST",
NEWTYPE=>"ARCHIVED_REQUEST" )
) {
$errno = 6783;
$errval = "Error while storing req to archived requests!\n".
"The database returns errorcode ".
$db->errno()." (".$db->errval().").";
return undef;
}
return $cert;
}
sub libIssueCertificateRestoreOpensslState {
$tools->moveFiles (DEST => getRequired ('sslindex'),
SRC => $tmpdir."/openssl_backup_".$$."_index.txt");
$tools->moveFiles (DEST => getRequired ('sslserial'),
SRC => $tmpdir."/openssl_backup_".$$."_serial");
}
############################################
## end of certificate creation ##
############################################
############################################
## begin of certificate revocation ##
############################################
sub libRevokeCertificate {
my $keys = { @_ };
## Get Configuration needed parameters ...
my $tmpdir = getRequired('TempDir');
## Get the parameters
my $key = $keys->{KEY};
my $passwd = $keys->{PASSWD};
## the first CRR is 1
if (not $key) {
$errno = 6801;
$errval = "Needed key to access database!";
return undef;
}
if ( not $passwd ) {
$errno = 6802;
$errval = "Needed passwd!";
return undef;
}
my $crr = $db->getItem (DATATYPE => "CRR",
KEY => $key );
if( not $crr ) {
$errno = 6811;
$errval = "Cannot Access CRR $key in the database!\n".
"Database returns errorcode ".
$db->errno()." (".$db->errval.").";
return undef;
}
my $serial = $crr->getParsed()->{REVOKE_CERTIFICATE_SERIAL};
## try to get the state of the certificate
my $v_cert = $db->getItem( DATATYPE=>"VALID_CERTIFICATE", KEY=>$serial );
my $s_cert = $db->getItem( DATATYPE=>"SUSPENDED_CERTIFICATE", KEY=>$serial );
my $r_cert = $db->getItem( DATATYPE=>"REVOKED_CERTIFICATE", KEY=>$serial );
my $e_cert = $db->getItem( DATATYPE=>"EXPIRED_CERTIFICATE", KEY=>$serial );
my $cert;
my $cert_dataType;
if ($v_cert) {
$cert_dataType = "VALID_CERTIFICATE";
$cert = $v_cert;
}
if ($e_cert) {
$cert_dataType = "EXPIRED_CERTIFICATE";
if ($cert) {
## inconsistency detected
print STDERR "PKI: detected an inconsistency in the
certificate-database!";
print STDERR "PKI: didn't fix the inconsistency (not
necessary).";
}
$cert = $e_cert;
}
if ($s_cert) {
$cert_dataType = "SUSPENDED_CERTIFICATE";
if ($cert) {
## inconsistency detected
print STDERR "PKI: detected an inconsistency in the
certificate-database!";
print STDERR "PKI: try to remove certificate $serial from the
valid certificates ...";
if ($db->deleteItem (DATATYPE=>"VALID_CERTIFICATE",
KEY=>$serial )) {
print STDERR "PKI: fixed inconsistency.";
} else {
print STDERR "PKI: failed to fix the inconsistency.";
}
}
$cert = $s_cert;
}
if ($r_cert) {
$errno = 6821;
$errval = "The certificate is always revoked so please delete the
CRR!\n".
return undef;
}
if( not $cert ) {
$errno = 6831;
$errval = "Certificate $serial was not found in the database!\n".
"Database returns errorcode ".
$db->errno()." (".$db->errval.").";
return undef;
}
my $fileName = "$tmpdir/${$}_${serial}_cert.pem";
$tools->saveFile( FILENAME=>$fileName, DATA=>$cert->getPEM() );
## Revoke Certificate
if( not $cryptoShell->revoke( INFILE=>"$fileName", PASSWD=>$passwd)) {
unlink( $fileName );
$errno = 6841;
$errval = "Error while revoking Certificate!\n".
"OpenCA::OpenSSL returns errorcode ".
$OpenCA::OpenSSL::errno." (".$OpenCA::OpenSSL::errval.").";
return undef;
}
if( not $db->updateStatus( OBJECT=>$cert,
DATATYPE=>$cert_dataType,
NEWTYPE=>"REVOKED_CERTIFICATE" )) {
$errno = 6851;
$errval = "Error changing status from certificate $serial (you should
recover OpenSSL's index.txt)\n".
"Database returns errorcode ".
$db->errno()." (".$db->errval().").";
return undef;
}
if( not $db->updateStatus( OBJECT=>$crr,
DATATYPE=>"APPROVED_CRR",
NEWTYPE=>"ARCHIVED_CRR" )) {
## perhaps a directly revoked certificate without approval?
if ( not $db->updateStatus( OBJECT => $crr,
DATATYPE => "PENDING_CRR",
NEWTYPE => "ARCHIVED_CRR")) {
generalError("Error changing status from crr $key to Revoked
dB (you should recover OpenSSL's index.txt)");
$errno = 6861;
$errval = "Error changing status from crr $key to Revoked dB ".
"(you should recover OpenSSL's index.txt)\n".
"Database returns errorcode ".
$db->errno()." (".$db->errval().").";
return undef;
}
}
return $cert;
}
############################################
## end of certificate revocation ##
############################################
1;