--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/securitymanager/securitymanager.cpp Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,1212 @@
+/*
+* Copyright (c) 1997-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 <f32file.h>
+
+#include "securitymanager.h"
+#include "swi/sishash.h"
+#include "swi/sisdataprovider.h"
+#include "swi/sissignaturealgorithm.h"
+#include "swi/sissignaturecertificatechain.h"
+#include "swi/siscertificatechain.h"
+#include "swi/sisinfo.h"
+#include "swi/sissupportedoptions.h"
+#include "swi/sissupportedlanguages.h"
+#include "swi/sisprerequisites.h"
+#include "swi/sislogo.h"
+#include "swi/sisproperties.h"
+#include "swi/sisinstallblock.h"
+#include "swi/sistruststatus.h"
+#include "hashcontainer.h"
+#include "certchainconstraints.h"
+#include "devinfosupportclient.h"
+
+#include "log.h"
+
+// PKIX dependencies
+#include <pkixcertchain.h>
+#include <x509keys.h>
+#include <ocsp.h>
+#include <securitydefsconst.h>
+
+#include <ccertattributefilter.h>
+#include <ct/mcttoken.h>
+//#include <mctcertstore.h>
+#include "cfstokentypeclient.h"
+
+// Crypto dependencies
+#include <hash.h>
+#include <swicertstore.h>
+
+// SecMan includes
+#include "chainvalidator.h"
+#include "certificateretriever.h"
+#include "signatureverifier.h"
+#include "securitypolicy.h"
+#include "revocationhandler.h"
+
+const TInt KFileBufferSize = 1024; // 1k buffer used to read the data to be hashed
+_LIT(KSecurityManagerName, "_Security_Manager_");
+
+
+using namespace Swi;
+
+//
+// Life Cycle methods
+//
+
+EXPORT_C CSecurityManager* CSecurityManager::NewL()
+ {
+ CSecurityManager* self = CSecurityManager::NewLC();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+EXPORT_C CSecurityManager* CSecurityManager::NewLC()
+ {
+ CSecurityManager* self = new(ELeave) CSecurityManager();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ return self;
+ }
+
+EXPORT_C CSecurityPolicy& CSecurityManager::SecurityPolicy() const
+ {
+ return *iSecPolicy;
+ }
+
+CSecurityManager::CSecurityManager() : CActive(EPriorityNormal)
+ {
+ CActiveScheduler::Add(this);
+ }
+
+CSecurityManager::~CSecurityManager()
+ {
+ Deque();
+
+ if (iCurrentPkixChain)
+ {
+ delete iCurrentPkixChain;
+ }
+
+ if (iCertStore)
+ {
+ iCertStore->Release();
+ }
+
+ if (iCertificateRetriever)
+ {
+ delete iCertificateRetriever;
+ }
+
+ if (iChainValidator)
+ {
+ delete iChainValidator;
+ }
+
+ if (iRevocationHandler)
+ {
+ delete iRevocationHandler;
+ }
+
+ iValidPkixChains.ResetAndDestroy();
+ iUntrustedRoots.ResetAndDestroy();
+ iDeviceIDs.ResetAndDestroy();
+ TInt count = iTrustedRoots.Count();
+ // Release certificates from the list
+ for (TInt i = 0; i < count; ++i)
+ {
+ iTrustedRoots[0]->Release();
+ iTrustedRoots.Remove(0);
+ }
+ iTrustedRoots.Close();
+ iCertMetaInfo.Reset();
+ iFs.Close();
+ }
+
+
+void CSecurityManager::ConstructL()
+ {
+ User::LeaveIfError(iFs.Connect());
+ iSecPolicy = CSecurityPolicy::GetSecurityPolicyL();
+ iCertStore=CSWICertStore::NewL(iFs);
+ }
+
+
+//
+// Active Objects methods
+//
+
+void CSecurityManager::RunL()
+ {
+ DEBUG_PRINTF3(_L8("Security Manager - RunL(). State: %d, Status: %d."),
+ iState, iStatus.Int());
+
+ if (iStatus.Int() != KErrNone)
+ {
+ User::Leave(iStatus.Int()); // Hop into RunError()
+ }
+
+ switch (iState)
+ {
+ case ERetrievedTrustedRoots:
+ {
+ iCertMetaInfo.Reset();
+ TInt trustedCertCount = iTrustedRoots.Count();
+ for (TInt i = 0; i < trustedCertCount; ++i)
+ {
+ CCTCertInfo& certInfo=*iTrustedRoots[i];
+ DEBUG_CODE_SECTION(
+ DEBUG_PRINTF2(_L("Security Manager - SWI certstore contains trust anchor certificate '%S'"),
+ &(certInfo.Label()));
+ );
+ TCertMetaInfo metaInfo = iCertStore->CertMetaInfoL(certInfo);
+ iCertMetaInfo.AppendL(metaInfo);
+ if (metaInfo.iIsMandatory)
+ {
+ iMandatoryCertDNCount++;
+ DEBUG_CODE_SECTION(
+ DEBUG_PRINTF2(_L("Security Manager - SWI certstore contains mandatory certificate '%S'"),
+ &(certInfo.Label()));
+ );
+ }
+ if (metaInfo.iIsSystemUpgrade)
+ {
+ DEBUG_CODE_SECTION(
+ DEBUG_PRINTF2(_L("Security Manager - SWI certstore contains system upgrade certificate '%S'"),
+ &(certInfo.Label()));
+ );
+ }
+ }
+ // After we get here, we have retrieved mandatory certificates
+ // We may have an unsigned sis file in which case we do not want to verify the block
+ // since there isn't one, so bail here with the correct error
+ if (iChains.Count() == 0)
+ {
+ if (iMandatoryCertDNCount == 0)
+ {
+ *iResult = ESignatureNotPresent; // No mandatory certs, so just say unsigned
+ }
+ else
+ {
+ *iResult = EMandatorySignatureMissing; // more important error code overrides
+ }
+
+ User::RequestComplete(iClientStatus, KErrNone);
+ break;
+ }
+
+
+ VerifyBlockL(iCurrentChain);
+ }
+ break;
+
+ case EValidatingChain :
+ {
+ CPKIXValidationResultBase* result = (*iValidationResultsOut)[iCurrentChain];
+ ::TValidationStatus resultStatus = result->Error();
+
+ DEBUG_PRINTF3(_L8("Security Manager - Certificate validation result was %d. (If applicable, error on certificate %d.)"),
+ resultStatus.iReason, resultStatus.iCert);
+
+ iCurrentChain++; // Next chain to validate
+
+ if (resultStatus.iReason != EValidatedOK)
+ {
+ // we can discard the invalid cert chain
+ delete iCurrentPkixChain;
+ iCurrentPkixChain = NULL;
+
+ // ooops
+ if (iChains.Count() > iCurrentChain) // This is the ValidateANY policy
+ {
+ VerifyBlockL(iCurrentChain);
+ break;
+ }
+ }
+ else
+ {
+ iHasValidated = ETrue; // At least one chain has been validated! Hurrah!
+
+ // check if a chain has validated that is not self signed
+ if (*iResult != ESignatureSelfSigned)
+ {
+ iHasValidatedTrusted = ETrue;
+ }
+
+ // From here on the chain has been validated successfully
+
+ iTotalCapabilitiesOut->Union(iCurrentCapabilities); // Update the total capabilities
+
+ // Reduce the count from the list of mandatory certs
+ UpdateListOfMissingRequiredCertsL(iCurrentPkixChain->Cert(iCurrentPkixChain->Count()-1));
+
+ // Updage the System Upgrade status of the Certificate
+ UpdateSystemUpgradeCertStatusL(iCurrentPkixChain->Cert(iCurrentPkixChain->Count()-1));
+
+ User::LeaveIfError(iValidPkixChains.Append(iCurrentPkixChain));
+ // this chain will be used for OCSP checking if required, so record it.
+ iController->AddChainIndex(iCurrentChain-1);
+
+ iCurrentPkixChain = NULL;
+ }
+
+ if (iCurrentChain == iChains.Count())
+ {
+ if (iMandatoryCertDNCount == 0)
+ {
+ // Mandatory certs prerequisites met
+
+ if (iHasValidated)
+ {
+ //Build the certificate chain constraints
+ CCertChainConstraints* certChainConstraints(0);
+ TRAPD(err, certChainConstraints=CCertChainConstraints::NewL(iValidPkixChains));
+ if (err)
+ {
+ *iResult = ECertificateValidationError;
+ User::RequestComplete(iClientStatus, KErrNone);
+ return;
+ }
+
+ *iResult = iHasValidatedTrusted ? EValidationSucceeded : ESignatureSelfSigned;
+
+ //Pass the certificate chain constraints ownership to controller
+ Sis::CController* controller=const_cast<Sis::CController*>(iController);
+ controller->SetCertChainConstraints(certChainConstraints);
+
+ //Set the dev cert found flag if dev cert first time found
+ if (iDevCertWarningState==ENoDevCerts &&
+ (certChainConstraints->SIDsAreConstrained()
+ ||certChainConstraints->VIDsAreConstrained()
+ ||certChainConstraints->DeviceIDsAreConstrained()
+ ||certChainConstraints->CapabilitiesAreConstrained()))
+ {
+ DEBUG_PRINTF(_L("Security Manager - At least one certificate chain contains a devcert."));
+ iDevCertWarningState=EFoundDevCerts;
+ }
+
+ //Check if the device id is contrained and the device Id has been retrieved
+ if (certChainConstraints->DeviceIDsAreConstrained() && iDeviceIDs.Count()==0)
+ {
+ //Retrieve and Save the device ID list then complete
+ RDeviceInfo deviceInfo;
+ User::LeaveIfError(deviceInfo.Connect());
+ CleanupClosePushL(deviceInfo);
+ const RPointerArray<HBufC>& tempbuf=deviceInfo.DeviceIdsL();
+ for (TInt i=0;i<tempbuf.Count();i++)
+ {
+ HBufC* element=tempbuf[i]->AllocLC();
+ iDeviceIDs.AppendL(element);
+ CleanupStack::Pop(element);
+ }
+ CleanupStack::PopAndDestroy(&deviceInfo);
+ }
+ iState = EChecksDone;
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+ return;
+ }
+ }
+
+ if (iMandatoryCertDNCount != 0)
+ {
+ *iResult = EMandatorySignatureMissing; // We did not meet mandatory cert requirements!
+ }
+ else
+ {
+ if (!iHasValidated)
+ {
+ *iResult = ECertificateValidationError; // No chain ever validated
+ }
+ }
+
+ User::RequestComplete(iClientStatus, KErrNone);
+ }
+ else
+ {
+ VerifyBlockL(iCurrentChain);
+ return;
+ }
+ }
+ break;
+
+ case ERevalidatingChain:
+ {
+ TInt chainIndex = (*iChainListIndices)[iCurrentChain];
+
+ CPKIXValidationResultBase* result = (*iValidationResultsOut)[iCurrentChain];
+ ::TValidationStatus resultStatus = result->Error();
+
+ DEBUG_PRINTF3(_L8("Security Manager - Certificate validation result was %d. (If applicable, error on certificate %d.)"),
+ resultStatus.iReason, resultStatus.iCert);
+
+ iCurrentChain++; // Next chain to validate
+
+ if (resultStatus.iReason != EValidatedOK)
+ {
+ // We can discard the invalid chain.
+ delete iCurrentPkixChain;
+ iCurrentPkixChain = NULL;
+
+ // ooops
+ if (iChains.Count() > chainIndex)
+ { // This is the ValidateANY policy
+ VerifyBlockL(chainIndex);
+ break;
+ }
+ }
+ else
+ {
+ iHasValidated = ETrue; // At least one chain has been validated! Hurrah!
+
+ // check if a chain has validated that is not self signed
+ if (*iResult != ESignatureSelfSigned)
+ {
+ iHasValidatedTrusted = ETrue;
+ }
+
+ // From here on the chain has been validated successfully
+
+ iTotalCapabilitiesOut->Union(iCurrentCapabilities); // Update the total capabilities
+
+ // Reduce the count from the list of mandatory certs
+ UpdateListOfMissingRequiredCertsL(iCurrentPkixChain->Cert(iCurrentPkixChain->Count()-1));
+
+ // Updage the System Upgrade status of the Certificate
+ UpdateSystemUpgradeCertStatusL(iCurrentPkixChain->Cert(iCurrentPkixChain->Count()-1));
+
+ iValidPkixChains.AppendL(iCurrentPkixChain);
+
+ iCurrentPkixChain = NULL;
+ }
+
+ if (chainIndex == iChains.Count())
+ {
+ if (iHasValidated)
+ {
+ //Build the certificate chain constraints
+ CCertChainConstraints* certChainConstraints(0);
+ TRAPD(err, certChainConstraints=CCertChainConstraints::NewL(iValidPkixChains));
+ if (err)
+ {
+ *iResult = ECertificateValidationError;
+ User::RequestComplete(iClientStatus, KErrNone);
+ return;
+ }
+ else
+ {
+ *iResult = iHasValidatedTrusted ? EValidationSucceeded : ESignatureSelfSigned;
+ }
+
+ //Pass the certificate chain constraints ownership to controller
+ Sis::CController* controller=const_cast<Sis::CController*>(iController);
+ controller->SetCertChainConstraints(certChainConstraints);
+
+ //Check if the device id is contrained and the device Id has been retrieved
+ if (certChainConstraints->DeviceIDsAreConstrained() && iDeviceIDs.Count()==0)
+ {
+ //Retrieve and Save the device ID list then complete
+ RDeviceInfo deviceInfo;
+ User::LeaveIfError(deviceInfo.Connect());
+ CleanupClosePushL(deviceInfo);
+ const RPointerArray<HBufC>& tempbuf=deviceInfo.DeviceIdsL();
+ for (TInt i=0;i<tempbuf.Count();i++)
+ {
+ HBufC* element=tempbuf[i]->AllocLC();
+ iDeviceIDs.AppendL(element);
+ CleanupStack::Pop(element);
+ }
+ CleanupStack::PopAndDestroy(&deviceInfo);
+ }
+ iState = EChecksDone;
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+ return;
+ }
+
+ else
+ {
+ *iResult = ECertificateValidationError; // No chain ever validated
+ }
+
+ User::RequestComplete(iClientStatus, KErrNone);
+ }
+ else
+ {
+ VerifyBlockL(chainIndex);
+ return;
+ }
+ }
+ break;
+
+ case EOCSPCheck:
+ {
+ iState = EChecksDone;
+ ProcessOcspOutcomesL();
+
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete(status, KErrNone);
+ SetActive();
+ }
+ break;
+
+ case EChecksDone:
+ {
+ // If the validation is done by certs passed by third party(API user)
+ // instead of cert-store then even on successful validation
+ // the result of validation is ESignatureSelfSigned.
+ // But if iUntrustedRoots count is not zero then the result is
+ // really ESignatureSelfSigned.
+ if (NULL != iRootCerts && iHasValidated)
+ {
+ *iResult = EValidationSucceeded;
+ }
+ // Complete the client and be happy
+ User::RequestComplete(iClientStatus, KErrNone);
+ }
+ break;
+
+ default:
+ {
+ User::Panic(KSecurityManagerName, 1);
+ }
+ }
+ }
+
+
+void CSecurityManager::ProcessOcspOutcomesL()
+ {
+
+ // Identify the worst outcome overall, and the worst in each chain.
+ // The OCSP outcomes are in the same order as the valid chains and
+ // certificates within them, with the number of outcomes per chain
+ // one fewer than the number of certs in the chain.
+
+
+ TInt numOutcomes=iRevocationHandler->TransactionCount();
+ TInt currentChain = 0;
+ TInt chainErrorLevel = 0;
+
+ // Since the number of outcomes is 1 fewer than the number of certs in the
+ // PkixChain, the index for the last outcome of the first chain will be
+ // 2 lower than the number of certs in the chain.
+ TInt chainLastOutcomeIndex = iValidPkixChains[0]->Count() - 2;
+ TInt chainWorstOutcome = 0;
+
+ // This variable is used to record the most serious error condition.
+ TInt errorLevel = 0;
+
+ DEBUG_PRINTF2(_L8("Security Manager - OCSP check complete. %d OCSP outcomes."), numOutcomes);
+
+ for (TInt i=0; i<numOutcomes; i++)
+ {
+ const TOCSPOutcome& outcome=iRevocationHandler->Outcome(i);
+
+ DEBUG_PRINTF4(_L8("Security Manager - OCSP outcome %d; Status: %d, Result: %d."),
+ i, outcome.iStatus, outcome.iResult);
+
+ if (outcome.iResult == OCSP::ERevoked)
+ {
+ // If any certificate is revoked then installation must be aborted
+ // but we still want to identify the worst case for each chain for
+ // the purposes of the error dialog.
+
+ *iRevocationMessage = ECertificateStatusIsRevoked;
+ errorLevel = 6;
+ chainWorstOutcome = i;
+
+ // Skip the rest of the outcomes for this chain.
+ i = chainLastOutcomeIndex;
+ }
+ else if (outcome.iResult != OCSP::EGood)
+ {
+ switch (outcome.iStatus)
+ {
+ // permanent errors, no user interaction is required
+ case OCSP::ENoServerSpecified:
+ case OCSP::EClientInternalError:
+ case OCSP::EMalformedRequest:
+ case OCSP::EUnknownResponseType:
+ case OCSP::EClientUnauthorised:
+ case OCSP::EUnknownCriticalExtension:
+ case OCSP::EMissingCertificates:
+ case OCSP::ESignatureRequired:
+ case OCSP::EThisUpdateTooLate:
+ case OCSP::EThisUpdateTooEarly:
+ case OCSP::ENextUpdateTooEarly:
+ case OCSP::ECertificateNotValidAtValidationTime:
+ case OCSP::ENonceMismatch:
+ if (errorLevel < 5)
+ {
+ errorLevel = 5;
+ *iRevocationMessage = EInvalidCertificateStatusInformation;
+ }
+ if (chainErrorLevel < 5)
+ {
+ chainErrorLevel = 5;
+ chainWorstOutcome = i;
+ }
+ break;
+ case OCSP::EResponseSignatureValidationFailure:
+ if (errorLevel < 4)
+ {
+ errorLevel = 4;
+ *iRevocationMessage = EResponseSignatureValidationFailure;
+ }
+ if (chainErrorLevel < 4)
+ {
+ chainErrorLevel = 4;
+ chainWorstOutcome = i;
+ }
+ break;
+ // permanent errors, ask the user
+ case OCSP::EValid:
+ if (errorLevel < 3)
+ {
+ errorLevel = 3;
+ *iRevocationMessage = ECertificateStatusIsUnknown;
+ }
+ if (chainErrorLevel < 3)
+ {
+ chainErrorLevel = 3;
+ chainWorstOutcome = i;
+ }
+ break;
+ // transient errors - user can retry
+ case OCSP::EInvalidURI:
+ if (errorLevel < 2)
+ {
+ errorLevel = 2;
+ *iRevocationMessage = EInvalidRevocationServerUrl;
+ }
+ if (chainErrorLevel < 2)
+ {
+ chainErrorLevel = 2;
+ chainWorstOutcome = i;
+ }
+ break;
+ case OCSP::ETryLater:
+ case OCSP::ETransportError:
+ case OCSP::EServerInternalError:
+ case OCSP::EMissingNonce:
+ if (errorLevel < 1)
+ {
+ errorLevel = 1;
+ *iRevocationMessage = EUnableToObtainCertificateStatus;
+ }
+ if (chainErrorLevel < 1)
+ {
+ chainErrorLevel = 1;
+ chainWorstOutcome = i;
+ }
+
+ break;
+ default:
+ // All possible OCSP responses should be checked
+ __ASSERT_ALWAYS(EFalse, User::Leave(KErrArgument));
+ break;
+ }
+ }
+
+ // If this is the end of the chain, store the worst outcome for the
+ // chain in the output outcome array.
+ if (i == chainLastOutcomeIndex)
+ {
+ TOCSPOutcome* chainOutcome=new(ELeave) TOCSPOutcome(iRevocationHandler->Outcome(chainWorstOutcome));
+ CleanupStack::PushL(chainOutcome);
+ iOcspOutcomeOut->AppendL(chainOutcome);
+ CleanupStack::Pop(chainOutcome);
+
+ // If there are more chains to consider, get set to identify the
+ // worst outcome in the next chain.
+ if (++currentChain < iValidPkixChains.Count())
+ {
+ chainErrorLevel = 0;
+ chainWorstOutcome = i + 1;
+ chainLastOutcomeIndex += iValidPkixChains[currentChain]->Count() - 1;
+ }
+ }
+
+ }
+ }
+
+void CSecurityManager::DoCancel()
+ {
+ DEBUG_PRINTF2(_L8("Security Manager - Cancelling in state %d."), iState);
+
+ switch (iState)
+ {
+ case ERetrievedTrustedRoots:
+ {
+ iCertificateRetriever->Cancel();
+ }
+ break;
+
+ case EValidatingChain:
+ case ERevalidatingChain:
+ {
+ iChainValidator->Cancel();
+ }
+ break;
+
+ case EOCSPCheck:
+ {
+ iRevocationHandler->Cancel();
+ }
+ break;
+
+ case EChecksDone:
+ default:
+ {
+ // Do nothing
+ }
+ }
+ if(iClientStatus)
+ {
+ User::RequestComplete(iClientStatus,KErrCancel);
+ }
+ }
+
+TInt CSecurityManager::RunError(TInt aError)
+ {
+ DEBUG_PRINTF2(_L8("Security Manager - RunError(). Error code %d."), aError);
+
+ User::RequestComplete(iClientStatus, aError);
+ return KErrNone;
+ }
+
+
+//
+// Business methods
+//
+
+EXPORT_C void CSecurityManager::PerformOcspL(const TDesC8& aOcspUri,
+ TUint32& aIap,
+ TRevocationDialogMessage* aRevocationMessageOut,
+ RPointerArray<TOCSPOutcome>& aOcspOutcomeOut,
+ RPointerArray<CX509Certificate>& aCertOut,
+ TRequestStatus& aStatus)
+ {
+ Cancel();
+
+ DEBUG_PRINTF2(_L8("Security Manager - Performing OCSP with revocation server at %S."),
+ &aOcspUri);
+
+ // Reset and re-populate certificate list to contain only end certificates
+ // from valid chains, so that the end cert list can be correlated with the
+ // list of outcomes.
+ aCertOut.ResetAndDestroy();
+ TInt numChains = iValidPkixChains.Count();
+ for (TInt index = 0; index < numChains; index++)
+ {
+ CX509Certificate* certOut = CX509Certificate::NewLC(iValidPkixChains[index]->Cert(0));
+ aCertOut.AppendL(certOut);
+ CleanupStack::Pop(certOut);
+ }
+
+ DEBUG_PRINTF2(_L8("Security Manager - Validating %d certificate chains for this controller."), numChains);
+
+ iClientStatus = &aStatus;
+ *iClientStatus = KRequestPending;
+
+ iOcspOutcomeOut = &aOcspOutcomeOut;
+ iRevocationMessage = aRevocationMessageOut;
+
+ // Make sure to delete earlier object
+ if (iRevocationHandler)
+ {
+ delete iRevocationHandler;
+ iRevocationHandler = NULL;
+ }
+ iRevocationHandler = CRevocationHandler::NewL(*iCertStore);
+ iRevocationHandler->SetDefaultURIL(aOcspUri);
+ iState = EOCSPCheck;
+
+ iRevocationHandler->SendRequestL(iValidPkixChains, aIap, iStatus);
+
+ SetActive();
+ }
+
+EXPORT_C void CSecurityManager::VerifyControllerL(
+ TDesC8& aRawController,
+ const Sis::CController& aController,
+ TSignatureValidationResult* aResultOut,
+ RPointerArray<CPKIXValidationResultBase>& aPkixResultsOut,
+ RPointerArray<CX509Certificate>& aCertsOut,
+ TCapabilitySet* aCapabilitySetOut,
+ TBool& aAllowUnsigned,
+ TBool& aIsEmbeddedController,
+ TRequestStatus& aStatus,
+ TBool aCheckDateAndTime)
+ {
+ DEBUG_PRINTF(_L8("Security Manager - Validating Controller"));
+
+ iResult = aResultOut;
+ iChains = aController.SignatureCertificateChains();
+ iController = &aController;
+ iEndCertificatesOut = &aCertsOut;
+ iValidationResultsOut = &aPkixResultsOut;
+ iTotalCapabilitiesOut = aCapabilitySetOut;
+ iIsEmbeddedController = aIsEmbeddedController;
+ iCheckDateAndTime = aCheckDateAndTime;
+
+ // Initialy assume that the chain is not validated
+ iHasValidated = EFalse;
+ iHasValidatedTrusted = EFalse;
+
+ *iResult = ESignatureNotPresent;
+ aAllowUnsigned=iSecPolicy->AllowUnsigned();
+
+
+ iClientStatus = &aStatus; // Store caller's request status
+ *iClientStatus = KRequestPending;
+
+ if (iChains.Count() == 0)
+ {
+ User::RequestComplete(iClientStatus, KErrNone);
+ return;
+ }
+
+ iRawController.Set(aRawController);
+ iCurrentChain = 0;
+
+ // First retrieve all CA certificates
+
+ delete iCertificateRetriever;
+ iCertificateRetriever = NULL;
+ iCertificateRetriever = CCertificateRetriever::NewL(*iCertStore);
+
+ delete iChainValidator;
+ iChainValidator = NULL;
+ iChainValidator = CChainValidator::NewL(*iCertStore, *iSecPolicy);
+
+ iState = ERetrievedTrustedRoots;
+ SetActive();
+
+ // No need to fetch certificates from the certstore if the root certs
+ // are already provided by the caller. or
+ // The root Certificates already fetched from certstore in case of embedded packages
+
+ if(NULL == iRootCerts && iTrustedRoots.Count() == 0)
+ {
+ iCertificateRetriever->RetrieveCACertificates(
+ iTrustedRoots, iStatus);
+ }
+ else
+ {
+ TRequestStatus* tempStatus = &iStatus;
+ User::RequestComplete(tempStatus, KErrNone);
+ }
+ }
+
+EXPORT_C void CSecurityManager::ReverifyControllerL(
+ TDesC8& aRawController,
+ const Sis::CController& aController,
+ const RArray<TInt>& aChainListIndices,
+ TSignatureValidationResult* aResultOut,
+ RPointerArray<CPKIXValidationResultBase>& aPkixResultsOut,
+ RPointerArray<CX509Certificate>& aCertsOut,
+ TCapabilitySet* aCapabilitySetOut,
+ TBool& aAllowUnsigned,
+ TRequestStatus& aStatus)
+ {
+ DEBUG_PRINTF(_L8("Security Manager - Re-Verifying Controller"));
+
+ iResult = aResultOut;
+ iChains = aController.SignatureCertificateChains();
+ iController = &aController;
+ iChainListIndices = &aChainListIndices;
+ iEndCertificatesOut = &aCertsOut;
+ iValidationResultsOut = &aPkixResultsOut;
+ iTotalCapabilitiesOut = aCapabilitySetOut;
+ iIsEmbeddedController = ETrue;
+
+
+ *iResult = ESignatureNotPresent;
+ aAllowUnsigned = iSecPolicy->AllowUnsigned();
+
+ iClientStatus = &aStatus; // Store caller's request status
+ *iClientStatus = KRequestPending;
+
+ if (iChains.Count() == 0)
+ {
+ // This is an unsigned SISX file
+ User::RequestComplete(iClientStatus, KErrNone);
+ return;
+ }
+
+ iRawController.Set(aRawController);
+ iCurrentChain = 0;
+
+ delete iCertificateRetriever;
+ iCertificateRetriever = NULL;
+ iCertificateRetriever = CCertificateRetriever::NewL(*iCertStore);
+
+ delete iChainValidator;
+ iChainValidator = NULL;
+ iChainValidator = CChainValidator::NewL(*iCertStore, *iSecPolicy);
+
+ // We may have an unsigned sis file in which case we do not want to verify the block
+ // since there isn't one, so bail here with the correct error
+ if (iChains.Count() == 0)
+ {
+ User::RequestComplete(iClientStatus, KErrNone);
+ }
+ else
+ {
+ TInt currentChain = (*iChainListIndices)[iCurrentChain];
+ VerifyBlockL(currentChain);
+ }
+ }
+
+TInt CSecurityManager::SignedSize(TInt iChainsToAdd) const
+ {
+ TInt64 size = 0;
+
+ const Sis::CInfo& info = iController->Info();
+ size += info.Length() + info.HeaderSize() + info.PaddingSize();
+
+ const Sis::CSupportedOptions& options = iController->SupportedOptions();
+ size += options.Length() + options.HeaderSize() + options.PaddingSize();
+
+ const Sis::CSupportedLanguages& languages = iController->SupportedLanguages();
+ size += languages.Length() + languages.HeaderSize() + languages.PaddingSize();
+
+ const Sis::CPrerequisites& prerequisites = iController->Prerequisites();
+ size += prerequisites.Length() + prerequisites.HeaderSize() + prerequisites.PaddingSize();
+
+ const Sis::CProperties& props = iController->Properties();
+ size += props.Length() + props.HeaderSize() + props.PaddingSize();
+
+ const Sis::CLogo* logo = iController->Logo();
+ if (logo != NULL)
+ {
+ size += logo->Length() + logo->HeaderSize() + logo->PaddingSize();
+ }
+
+ const Sis::CInstallBlock& installblock = iController->InstallBlock();
+ size += installblock.Length() + installblock.HeaderSize() + installblock.PaddingSize();
+
+ for (TInt k = 0; k < iChainsToAdd; k++)
+ {
+ size += iChains[k]->Length() + iChains[k]->HeaderSize() + iChains[k]->PaddingSize();
+ }
+
+ return I64INT(size);
+ }
+
+void CSecurityManager::VerifyBlockL(TInt aChainIndex)
+ {
+ DEBUG_PRINTF2(_L8("Security Manager - Validating certificate chain %d."), aChainIndex);
+
+ Sis::CSignatureCertificateChain& chain = *iChains[aChainIndex];
+
+ // First verify the signature
+ const RPointerArray<Sis::CSignature> signatures = chain.Signatures();
+
+ // Determine the size of the controller data which was signed
+ TInt size = SignedSize(aChainIndex);
+
+ const Sis::CCertificateChain& certChain = chain.CertificateChain();
+ const TPtrC8 data = certChain.Data();
+
+ TInt pos = 0;
+ TInt end = data.Length();
+ iUntrustedRoots.ResetAndDestroy();
+
+ // Find all the self-signed certificates in the chain as possible root candidates
+
+ while (pos < end)
+ {
+ CX509Certificate* decoded = CX509Certificate::NewLC(data, pos);
+ if (decoded->IsSelfSignedL())
+ {
+ // If the root isn't in the trusted list, append it to the untrusted roots
+ TBool found = EFalse;
+ if(NULL == iRootCerts)
+ {
+ for (TInt i = 0; i < iTrustedRoots.Count(); i++)
+ {
+ CCTCertInfo* root = iTrustedRoots[i];
+ if (root->SubjectKeyId() == decoded->KeyIdentifierL())
+ {
+ found = ETrue;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (TInt i = iRootCerts->Count() - 1; i >= 0; --i)
+ {
+ CX509Certificate* root = (*iRootCerts)[i];
+ if (root->KeyIdentifierL() == decoded->KeyIdentifierL())
+ {
+ found = ETrue;
+ break;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ iUntrustedRoots.AppendL(decoded);
+ CleanupStack::Pop(decoded);
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy(decoded);
+ }
+ }
+ else
+ {
+ CleanupStack::PopAndDestroy(decoded);
+ }
+ }
+
+ DEBUG_PRINTF2(_L8("Security Manager - Found %d non-trusted candidate root certificates"), iUntrustedRoots.Count());
+
+ // If we have self signed roots, don't look in the certstore for a further root
+
+ TBool hasUntrustedRoot = (iUntrustedRoots.Count() > 0);
+
+ if (NULL != iRootCerts)
+ {
+ DEBUG_PRINTF(_L8("Security Manager - Validating chain using user provided roots"));
+ iCurrentPkixChain = CPKIXCertChainBase::NewL(*iCertStore, data, *iRootCerts);
+ hasUntrustedRoot = ETrue; // These root certs are considered untrusted.
+ }
+ else if(hasUntrustedRoot)
+ {
+ DEBUG_PRINTF(_L8("Security Manager - Validating chain using untrusted roots"));
+ iCurrentPkixChain = CPKIXCertChainBase::NewL(*iCertStore, data, iUntrustedRoots);
+ }
+ else
+ {
+ DEBUG_PRINTF(_L8("Security Manager - Validating chain using trusted roots from store"));
+ iCurrentPkixChain = CPKIXCertChainBase::NewL(*iCertStore, data, KSwiApplicabilityUid);
+ }
+
+
+ DEBUG_PRINTF2(_L8("Security Manager - Certificate chain contains %d certificates."), iCurrentPkixChain->Count());
+
+ const CX509Certificate& clientCert = iCurrentPkixChain->Cert(0); // This is the ee certificate
+ CX509Certificate* endCertOut = CX509Certificate::NewLC(clientCert);
+ iEndCertificatesOut->AppendL(endCertOut);
+ CleanupStack::Pop(endCertOut);
+
+ DEBUG_CODE_SECTION(HBufC* issuer = clientCert.IssuerL(); DEBUG_PRINTF2(_L("Security Manager - End Entity Certificate Issuer: '%S'."), issuer); delete issuer;);
+ DEBUG_CODE_SECTION(HBufC* subject = clientCert.SubjectL(); DEBUG_PRINTF2(_L("Security Manager - End Entity Certificate Subject: '%S'."), subject); delete subject;);
+
+ const CSubjectPublicKeyInfo& publicKey= clientCert.PublicKey();
+
+ DEBUG_PRINTF2(_L8("Security Manager - SIS file signed %d times with this certificate."), signatures.Count());
+
+ CSignatureVerifier* verifier = CSignatureVerifier::NewLC();
+ TBool result = EFalse;
+ for (TInt k = 0; k < signatures.Count(); k++)
+ {
+ const TDesC& algorithmOID = signatures[k]->Algorithm().AlgorithmIdentifier().Data();
+ TRAP_IGNORE(result = verifier->VerifySignatureL(algorithmOID, publicKey, iRawController.Mid((iIsEmbeddedController ? 4 : iController->HeaderSize()), size), signatures[k]->Data()));
+ if (result)
+ {
+ // We have a verify any policy on signatures (inside a given SISSignatureCertificateChain)
+ // Cf. SGL.GT0188.251 Section 4.3
+ break;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(verifier);
+
+ if (!result) // Signature not verified: something is WRONG. Abort.
+ {
+ DEBUG_PRINTF(_L8("Security Manager - No signature validated."));
+
+ *iResult = ESignatureCouldNotBeValidated;
+ User::RequestComplete(iClientStatus, KErrNone);
+ return;
+ }
+
+ // The signature is good, validate the certificate chain
+
+ CPKIXValidationResultBase* validationResult = CPKIXValidationResultBase::NewLC();
+ iValidationResultsOut->Append(validationResult);
+ CleanupStack::Pop(validationResult);
+
+ iState = EValidatingChain;
+ iCurrentPkixChain->SetValidityPeriodCheckFatal(iCheckDateAndTime);
+ iChainValidator->ValidateChainL(*iCurrentPkixChain, *iResult, *validationResult,
+ iCurrentCapabilities, hasUntrustedRoot, iStatus);
+ SetActive();
+ }
+
+EXPORT_C HBufC8* CSecurityManager::CalculateHashLC(MSisDataProvider& aDataProvider, CMessageDigest::THashId aAlgorithm)
+ {
+ CMessageDigest* digest = CMessageDigestFactory::NewDigestLC(aAlgorithm);
+
+ HBufC8* aBuffer = HBufC8::NewMaxLC(KFileBufferSize);
+ TPtr8 aBufferPtr(aBuffer->Des());
+
+ User::LeaveIfError(aDataProvider.Read(aBufferPtr));
+
+ while (aBuffer->Length() != 0)
+ {
+ digest->Update(*aBuffer);
+ User::LeaveIfError(aDataProvider.Read(aBufferPtr));
+ }
+ TPtrC8 hash = digest->Final();
+ HBufC8* hashBuffer = hash.AllocL();
+ CleanupStack::PopAndDestroy(2, digest); // aBuffer, digest
+
+ CleanupStack::PushL(hashBuffer);
+ return hashBuffer;
+ }
+
+EXPORT_C TBool CSecurityManager::VerifyFileHashL(MSisDataProvider& aDataProvider, const CHashContainer& aDigest)
+ {
+ HBufC8* hashBuffer = CalculateHashLC(aDataProvider, aDigest.Algorithm());
+
+ TBool result = EFalse;
+
+ TPtrC8 hash = hashBuffer->Des();
+ if (hash.Compare(aDigest.Data()) == 0)
+ {
+ result = ETrue;
+ }
+
+ CleanupStack::PopAndDestroy(hashBuffer);
+ return result;
+ }
+
+void CSecurityManager::UpdateListOfMissingRequiredCertsL(const CCertificate& aCertificate)
+ {
+ // Find aCertificate in iTrustedRoots and marked as nonmandatory for temporary!
+ TInt count = iTrustedRoots.Count();
+ for (TInt k = 0; k < count; k++)
+ {
+ CCTCertInfo* certInfo = iTrustedRoots[k];
+ if (iCertMetaInfo[k].iIsMandatory && !certInfo->SubjectKeyId().Compare(aCertificate.KeyIdentifierL()))
+ {
+ DEBUG_PRINTF2(_L("Security Manager - Mandatory certificate '%S' satisfied."), &(certInfo->Label()));
+ // set the Mandatory is false so that next time this certificate won't be compared
+ iCertMetaInfo[k].iIsMandatory = 0;
+ iMandatoryCertDNCount--;
+ break;
+ }
+ }
+ }
+
+void CSecurityManager::UpdateSystemUpgradeCertStatusL(const CCertificate& aCertificate)
+ {
+ // Find aCertificate in iTrustedRoots and update the system upgrade trust status
+ TInt count = iTrustedRoots.Count();
+ for (TInt k = 0; k < count; k++)
+ {
+ CCTCertInfo* certInfo = iTrustedRoots[k];
+ if (iCertMetaInfo[k].iIsSystemUpgrade && certInfo->SubjectKeyId() == aCertificate.KeyIdentifierL())
+ {
+ DEBUG_PRINTF2(_L("Security Manager - System upgrade certificate '%S' satisfied."), &(certInfo->Label()));
+ // create a modifyable reference to the current controller
+ Sis::CController& controller = const_cast <Sis::CController&>(*iController);
+ // set the SuCert validation status
+ controller.SetSignedBySuCert(ETrue);
+ break;
+ }
+ }
+
+ }
+
+EXPORT_C void CSecurityManager::GetCertificatesFromControllerL(
+ const Sis::CController& aController,
+ RPointerArray<CX509Certificate>& aCerts)
+ {
+ // Go through all SIS chains and extract end certificates from them.
+ const RPointerArray<Sis::CSignatureCertificateChain>& chains=
+ aController.SignatureCertificateChains();
+ for (TInt i=0; i<chains.Count(); i++)
+ {
+ Sis::CSignatureCertificateChain& sigCertChain=*chains[i];
+ const Sis::CCertificateChain& certChain=
+ sigCertChain.CertificateChain();
+ // Construct PKIX cert chain from raw data in the controller.
+ CPKIXCertChainBase* pkixChain=CPKIXCertChainBase::NewLC(*iCertStore,
+ certChain.Data(), KSwiApplicabilityUid);
+
+ // Extract end entity certificate and store it in the member array.
+ const CX509Certificate& endCert=pkixChain->Cert(0);
+ CX509Certificate* endCertCopy=CX509Certificate::NewLC(endCert);
+ User::LeaveIfError(aCerts.Append(endCertCopy));
+ CleanupStack::Pop(endCertCopy);
+
+ // Cleanup.
+ CleanupStack::PopAndDestroy(pkixChain);
+ }
+ }
+
+EXPORT_C void CSecurityManager::FillCertInfoArrayL(
+ const RPointerArray<CX509Certificate>& aCertificates,
+ RPointerArray<CCertificateInfo>& aCertInfos)
+ {
+ for (TInt i=0; i<aCertificates.Count(); i++)
+ {
+ CCertificateInfo* certInfo=CCertificateInfo::NewLC(*aCertificates[i]);
+ aCertInfos.AppendL(certInfo);
+ CleanupStack::Pop(certInfo);
+ }
+ }
+
+EXPORT_C const RPointerArray<HBufC>& CSecurityManager::DeviceIDsInfo() const
+ {
+ return iDeviceIDs;
+ }
+
+EXPORT_C void CSecurityManager::ResetValidCertChains()
+ {
+ iValidPkixChains.ResetAndDestroy();
+ }
+
+EXPORT_C void CSecurityManager::SetDevCertWarningState(TInt aDevCertWarningState)
+ {
+ iDevCertWarningState=static_cast<TDevCertWarningState>(aDevCertWarningState);
+ }
+
+EXPORT_C TInt CSecurityManager::GetDevCertWarningState()
+ {
+ return iDevCertWarningState;
+ }
+
+
+EXPORT_C void CSecurityManager::SetRootCerts(RPointerArray<CX509Certificate>* aX509CertArray)
+ {
+ iRootCerts = aX509CertArray;
+ }
+
+
+
+
+
+