diff -r 000000000000 -r ba25891c3a9e installationservices/swi/source/securitymanager/securitymanager.cpp --- /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 + +#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 +#include +#include +#include + +#include +#include +//#include +#include "cfstokentypeclient.h" + +// Crypto dependencies +#include +#include + +// 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(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& tempbuf=deviceInfo.DeviceIdsL(); + for (TInt i=0;iAllocLC(); + 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(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& tempbuf=deviceInfo.DeviceIdsL(); + for (TInt i=0;iAllocLC(); + 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; iOutcome(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& aOcspOutcomeOut, + RPointerArray& 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& aPkixResultsOut, + RPointerArray& 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& aChainListIndices, + TSignatureValidationResult* aResultOut, + RPointerArray& aPkixResultsOut, + RPointerArray& 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 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 (*iController); + // set the SuCert validation status + controller.SetSignedBySuCert(ETrue); + break; + } + } + + } + +EXPORT_C void CSecurityManager::GetCertificatesFromControllerL( + const Sis::CController& aController, + RPointerArray& aCerts) + { + // Go through all SIS chains and extract end certificates from them. + const RPointerArray& chains= + aController.SignatureCertificateChains(); + for (TInt i=0; iCert(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& aCertificates, + RPointerArray& aCertInfos) + { + for (TInt i=0; i& CSecurityManager::DeviceIDsInfo() const + { + return iDeviceIDs; + } + +EXPORT_C void CSecurityManager::ResetValidCertChains() + { + iValidPkixChains.ResetAndDestroy(); + } + +EXPORT_C void CSecurityManager::SetDevCertWarningState(TInt aDevCertWarningState) + { + iDevCertWarningState=static_cast(aDevCertWarningState); + } + +EXPORT_C TInt CSecurityManager::GetDevCertWarningState() + { + return iDevCertWarningState; + } + + +EXPORT_C void CSecurityManager::SetRootCerts(RPointerArray* aX509CertArray) + { + iRootCerts = aX509CertArray; + } + + + + + +