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;

Reply via email to