## OpenCA - Command
## Written by Michael Bell for the OpenCA project
## (c) Copyright 1998-2004 The OpenCA Project
##
##   File Name: approveCRR
##       Brief: store the revreq to the DB
##     Version: $Revision: 1.17.2.1 $
## Description: store the revreq to the DB for RA Operator approval
##  Parameters: head, text, signature

use strict;

sub cmdApproveCRR {

    our ($errval, $errno, $db, $query, $cryptoShell);

    ## Reserved variables
    my ( $text, $cert );

    ## To aprove a Request, we need it signed by the RA operator
    my $beginHeader = "-----BEGIN HEADER-----";
    my $endHeader = "-----END HEADER-----";
    my $beginSig = "-----BEGIN PKCS7-----";
    my $endSig = "-----END PKCS7-----";

    ## Get the parameters
    my $head        = $query->param('head');
    my $body        = $query->param('text');
    my $signature   = $query->param('signature');

    my $text = $head . $body ."\n";

    $signature =~ s/\n*$//;

    if ($signature !~ /^\s*$/) {
	$text .= $beginSig . "\n" . $signature . 
		    "\n" . $endSig . "\n";
    }

    ## Try to build the REQ object
    my $req = new OpenCA::REQ ( SHELL   => $cryptoShell,
                                GETTEXT => \&i18nGettext,
                                DATA    => $text );
    if( not $req ) {
	configError( gettext ("Error while creating the request."));
    }

    ## check for the old request and attach the signature of the user
    my $h = $db->getItem (DATATYPE => "CRR", KEY => $req->getSerial());
    $text .= $h->getParsed()->{SIGNATURE} if ($h);

    $req = new OpenCA::REQ ( SHELL   => $cryptoShell,
                             GETTEXT => \&i18nGettext,
                             DATA    => $text );

    if( not $req ) {
	configError( gettext ("Error while creating the request."));
    }

    my $signer = libGetSignatureObject( OBJECT=>$req );
    if ( not $signer ) {
	generalError ($errval, $errno);
    }
    libCheckSignature (OBJECT=>$req);
    my $sigStatus = $errval;
    
    ## check signaturestate - explaination:
    ## $errno gets only set by libCheckSignature in case of real error
    ## $errval gets always set, also in success by libCheckSignature!
    generalError ( $errval ) if $errno;
  
    ## get signer certificate
    my $tmpCert = libGetSignerCertificateDB( SIGNATURE=>$signer );
    if( not $tmpCert ) {
        generalError ($errval, $errno);
    }
    ## check validity of signer certificate
    if ($tmpCert->getStatus() =~ /revoked/ || $tmpCert->getStatus() =~ /suspended/
                                           || $tmpCert->getStatus() =~ /expired/ ) {
        generalError ( i18nGettext ("Cannot approve request! Invalid Operator-Certificate detected!").
                                    "<br>\n".$errval, $errno);
    }
											   
    ## download the certificate
    $cert = $db->getItem ( DATATYPE => "CERTIFICATE", KEY => $req->getParsed()->{REVOKE_CERTIFICATE_SERIAL} );
    if (not $cert)
    {
	##// it's not good to show the user the detailed problem
	print STDERR "SECURITY ALERT BY PKI: database failed during loading the certificate ".
                $req->getParsed()->{REVOKE_CERTIFICATE_SERIAL}."\n";
	configError( gettext ("Error while loading the affected certificate."));
    }

    if ( not $db->updateStatus ( OBJECT=>$req, DATATYPE=>"PENDING_CRR", NEWTYPE => "APPROVED_CRR" ) and
         not $db->updateStatus ( OBJECT=>$req, DATATYPE=>"SIGNED_CRR", NEWTYPE => "APPROVED_CRR" ) and
         not $db->updateStatus ( OBJECT=>$req, DATATYPE=>"NEW_CRR", NEWTYPE => "APPROVED_CRR" ))
    {
	if ( not $db->storeItem( OBJECT=>$req, DATATYPE=>"APPROVED_CRR", MODE => "INSERT" ))
        {
		print STDERR "SECURITY ALERT BY PKI: database failed during storing a correct CRR which follows\n".
			$text."\n";
		configError( gettext ("Error while storing the request."));
	}
    }

    if (not (
             $db->updateStatus ( OBJECT => $cert, DATATYPE=>"VALID_CERTIFICATE", NEWTYPE => "SUSPENDED_CERTIFICATE") or
             $db->updateStatus ( OBJECT => $cert, DATATYPE=>"EXPIRED_CERTIFICATE", NEWTYPE => "SUSPENDED_CERTIFICATE")
            ))
    {
	if ( not $db->getItem (DATATYPE=>"SUSPENDED_CERTIFICATE", KEY=>$cert->getSerial()) and
	     not $db->getItem (DATATYPE=>"REVOKED_CERTIFICATE",   KEY=>$cert->getSerial()) )
        {
		print STDERR "SECURITY ALERT BY PKI: database failed during storing a correct CRR which follows\n".
			$text."\n";
		configError( gettext ("Failed to change the certificate's state."));
	}
    }
    my $message = i18nGettext ("Your revocation request has been accepted and is now <B>waiting to be processed</B>.\n If you want to check out if the request has been correctly received, you can see the __BEGIN_LINK__ Approved Revocation Requests List __END_LINK__.\n Signature: __SIGSTATUS__",
                               "__BEGIN_LINK__", '<a href="?cmd=listCRR&dataType=APPROVED_CRR">',
                               "__END_LINK__", "</a>",
                               "__SIGSTATUS__", $sigStatus);

    return libSendReply (
                         "TIMESTAMP"   => 1,
                         "NAME"        => gettext ("Revocation Request Approved and Signed"),
                         "EXPLANATION" => $message
                        );
}

1;
