/*
* Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
/**
@file
@released
@internalTechnology
*/
#include "log.h"
#include "securitymanager.h"
#include "sistruststatus.h"
#include "sisrevocationmanager.h"
#include "sisregistryserversession.h"
#include "sisinfo.h"
#include "sisuid.h"
#include "swi/msisuihandlers.h"
_LIT(KMyModuleName, "_SISREVOCATION_MANAGER_");
using namespace Swi;
//
// Life Cycle methods
//
EXPORT_C CSisRevocationManager* CSisRevocationManager::NewL(CSisRegistrySession& aSession)
{
CSisRevocationManager* self = CSisRevocationManager::NewLC(aSession);
CleanupStack::Pop(self);
return self;
}
EXPORT_C CSisRevocationManager* CSisRevocationManager::NewLC(CSisRegistrySession& aSession)
{
CSisRevocationManager* self = new(ELeave) CSisRevocationManager(aSession);
CleanupStack::PushL(self);
return self;
}
CSisRevocationManager::CSisRevocationManager(CSisRegistrySession& aSession) :
CActive(EPriorityNormal),
iSession(&aSession)
{
CActiveScheduler::Add(this);
}
CSisRevocationManager::~CSisRevocationManager()
{
// Remove active object from active scheduler
Deque();
Cleanup();
}
//
// Active Objects methods
//
void CSisRevocationManager::RunL()
{
DEBUG_PRINTF2(_L8("Sis Registry Server - CSisrevocationManager::RunL (State: %d.)"), iState);
if (iStatus.Int() != KErrNone)
{
User::Leave(iStatus.Int()); // Hop into RunError()
}
switch (iState)
{
case EVerifyChains:
VerifcationRequestL();
break;
case ERevocationCheck:
{
switch (iSignatureValidationResult)
{
case EValidationSucceeded:
PerformOcspRequestL();
break;
default:
iState = ERevocationComplete;
// Self complete
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
SetActive();
break;
}
}
break;
case ERevocationComplete:
{
SetTrustStatusL();
// Complete the client
iMessage.Complete(KErrNone);
Cleanup();
}
break;
default:
{
User::Panic(KMyModuleName, 1);
}
}
}
void CSisRevocationManager::DoCancel()
{
DEBUG_PRINTF(_L8("Sis Registry Server - Cancelling Revocation Manager"));
if (iSecurityManager)
{
iSecurityManager->Cancel();
}
if (iState != EIdle)
{
iMessage.Complete(KErrCancel);
iState = EIdle;
}
}
TInt CSisRevocationManager::RunError(TInt aError)
{
DEBUG_PRINTF2(_L8("Sis Registry Server - Revocation Manager Failed with error code %d."), aError);
iMessage.Complete(aError);
Cleanup();
return KErrNone;
}
//
// Business methods
//
EXPORT_C void CSisRevocationManager::RevocationStatusRequestL(
HBufC8* aRawController,
const Sis::CController* aController,
TSisTrustStatus& aTrustStatus,
const RArray<TInt>& aCertChainIndices,
const TDesC8& aOcspUri,
const RMessage2& aMessage)
{
__ASSERT_ALWAYS(!IsActive(), User::Panic(KMyModuleName, KErrInUse));
ASSERT(EIdle == iState);
iStatus = KRequestPending;
iRawController = aRawController;
iController = aController;
iChains = aController->SignatureCertificateChains();
iSecurityManager = CSecurityManager::NewL();
// Store caller's request status
iMessage = aMessage;
iState = EVerifyChains;
iTrustStatus = aTrustStatus;
iOcspUri = aOcspUri.AllocL();
// Make a copy of the cert chain indicies array
TInt count = aCertChainIndices.Count();
for (TInt index = 0; index < count; ++index)
{
iCertChainIndices.AppendL(aCertChainIndices[index]);
}
// Self complete
TRequestStatus* status = &iStatus;
User::RequestComplete(status, KErrNone);
SetActive();
}
void CSisRevocationManager::VerifcationRequestL()
{
ASSERT(EVerifyChains == iState);
// Get current controller data.
TPtrC8 data(iRawController->Mid(iController->DataOffset()));
iSecurityManager->ReverifyControllerL(data,
*iController,
iCertChainIndices,
&iSignatureValidationResult,
iValidationResultsOut,
iEndCertificates,
&iCapabilitySet,
iAllowUnsigned,
iStatus);
iState = ERevocationCheck;
SetActive();
}
void CSisRevocationManager::PerformOcspRequestL()
{
iIap = 0;
iSecurityManager->PerformOcspL(iOcspUri->Des(),
iIap,
&iOcspMsg,
iOcspOutcomeOut,
iEndCertificates,
iStatus);
iState = ERevocationComplete;
SetActive();
}
void CSisRevocationManager::SetTrustStatusL()
{
TBool validated = EFalse;
TValidationStatus validationStatus = EUnknown;
switch (iSignatureValidationResult)
{
case EValidationSucceeded:
validated = ETrue;
validationStatus = EValidatedToAnchor;
break;
case ESignatureSelfSigned:
validated = ETrue;
validationStatus = EValidated;
break;
case ESignatureNotPresent:
validationStatus = EUnsigned;
break;
case ECertificateValidationError:
case ENoCertificate:
case ENoCodeSigningExtension:
case ENoSupportedPolicyExtension:
case ESignatureCouldNotBeValidated:
case EMandatorySignatureMissing:
validationStatus = EInvalid;
break;
default:
// BC break, unknown validation code, abort
User::Leave(KErrNotSupported);
break;
}
TRevocationStatus revocationStatus = EUnknown2;
if (validated)
{
for (TInt index = 0; index < iOcspOutcomeOut.Count(); index++)
{
if (iOcspOutcomeOut[index]->iResult == OCSP::EUnknown)
{
switch (iOcspOutcomeOut[index]->iStatus)
{
case OCSP::ETransportError:
case OCSP::EInvalidURI:
case OCSP::EServerInternalError:
case OCSP::ETryLater:
case OCSP::EMissingCertificates:
case OCSP::EResponseSignatureValidationFailure:
// Possibly transient error, may retry.
revocationStatus = EOcspTransient;
break;
case OCSP::EClientInternalError:
case OCSP::ENoServerSpecified:
case OCSP::EMalformedResponse:
case OCSP::EUnknownResponseType:
case OCSP::EUnknownCriticalExtension:
case OCSP::ESignatureRequired:
case OCSP::EClientUnauthorised:
case OCSP::EThisUpdateTooLate:
case OCSP::EThisUpdateTooEarly:
case OCSP::ENextUpdateTooEarly:
case OCSP::ECertificateNotValidAtValidationTime:
case OCSP::ENonceMismatch:
case OCSP::EMissingNonce:
case OCSP::EMalformedRequest:
// This is a permanent error, unable to retry.
revocationStatus = EOcspUnknown;
break;
case OCSP::EValid:
revocationStatus = EOcspUnknown;
break;
// not a valid status for this state
default:
// Unknown value, must be a BC break!
User::Leave(KErrNotSupported);
break;
}
break;
}
else if (iOcspOutcomeOut[index]->iResult == OCSP::ERevoked)
{
revocationStatus = EOcspRevoked;
break;
}
else
{
// OCSP of chain is good
revocationStatus = EOcspGood;
}
}
}
else // not validated
{
revocationStatus = EOcspNotPerformed;
}
// set trust status
TTime time;
time.UniversalTime();
iTrustStatus.SetLastCheckDate(time);
iTrustStatus.SetValidationStatus(validationStatus);
iTrustStatus.SetRevocationStatus(revocationStatus);
if (validated
&& (revocationStatus == EOcspGood
|| revocationStatus == EOcspUnknown
|| revocationStatus == EOcspRevoked ))
{
iTrustStatus.SetResultDate(iTrustStatus.LastCheckDate());
}
iSession->UpdateTrustStatusL(iController->Info().Uid().Uid(),
iTrustStatus);
}
void CSisRevocationManager::Cleanup()
{
iState = EIdle;
delete iController;
iController = 0;
delete iRawController;
iRawController = 0;
iEndCertificates.ResetAndDestroy();
iOcspOutcomeOut.ResetAndDestroy();
iValidationResultsOut.ResetAndDestroy();
iCertChainIndices.Close();
delete iOcspUri;
iOcspUri = 0;
delete iSecurityManager;
iSecurityManager = 0;
}