sl@0: /* sl@0: * Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include "pkixcertchainao.h" sl@0: #include "pkixCons.h" sl@0: #include sl@0: #include sl@0: #include "x509constraintext.h" sl@0: sl@0: CPKIXCertChainAO* CPKIXCertChainAO::NewL(MCertStore& aCertStore, sl@0: CPKIXCertChainBase &aPKIXCertChain, sl@0: const RPointerArray& aRootCerts) sl@0: { sl@0: CPKIXCertChainAO* self = new(ELeave) CPKIXCertChainAO(aCertStore, aPKIXCertChain); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aRootCerts); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: CPKIXCertChainAO* CPKIXCertChainAO::NewL(MCertStore& aCertStore, sl@0: CPKIXCertChainBase &aPKIXCertChain, sl@0: const TUid aClient) sl@0: { sl@0: return new(ELeave) CPKIXCertChainAO(aCertStore, aPKIXCertChain, aClient); sl@0: } sl@0: sl@0: CPKIXCertChainAO::~CPKIXCertChainAO() sl@0: { sl@0: Cancel(); sl@0: sl@0: delete iRoots; sl@0: delete iBuilder; sl@0: delete iCertsFromStoreRoots; sl@0: } sl@0: sl@0: CPKIXCertChainAO::CPKIXCertChainAO(MCertStore& aCertStore, sl@0: CPKIXCertChainBase &aPKIXCertChain) sl@0: : CActive(EPriorityNormal), iCertStore(&aCertStore), iPKIXCertChain(aPKIXCertChain) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: CPKIXCertChainAO::CPKIXCertChainAO(MCertStore& aCertStore, sl@0: CPKIXCertChainBase &aPKIXCertChain, sl@0: const TUid aClient) sl@0: : CActive(EPriorityNormal), iCertStore(&aCertStore), sl@0: iPKIXCertChain(aPKIXCertChain), iClient(aClient) sl@0: { sl@0: CActiveScheduler::Add(this); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::ConstructL(const RPointerArray& aRootCerts) sl@0: { sl@0: CPKIXCertsFromClient* roots = CPKIXCertsFromClient::NewLC(aRootCerts); sl@0: iRoots = CPKIXChainBuilder::NewL(); sl@0: iRoots->AddSourceL(roots); sl@0: CleanupStack::Pop(roots); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::RunL() sl@0: { sl@0: User::LeaveIfError(iStatus.Int()); sl@0: sl@0: switch (iState) sl@0: { sl@0: case EAddRoots: sl@0: HandleEAddRootsL(); sl@0: break; sl@0: sl@0: case ERootsInitialized: sl@0: HandleERootsInitializedL(); sl@0: break; sl@0: sl@0: case EBuildChainStart: sl@0: HandleEBuildChainStartL(); sl@0: break; sl@0: sl@0: case EBuildChainAddCandidateEnd: sl@0: HandleEBuildChainAddCandidateEndL(); sl@0: break; sl@0: sl@0: case EBuildChainCertsFromStoreBegin: sl@0: HandleEBuildChainCertsFromStoreBeginL(); sl@0: break; sl@0: sl@0: case EBuildChainCertsFromStoreEnd: sl@0: HandleEBuildChainCertsFromStoreEndL(); sl@0: break; sl@0: sl@0: case EAddCandidateIntermediateCertsEnd: sl@0: HandleEAddCandidateIntermediateCertsEndL(); sl@0: break; sl@0: sl@0: case EValidateEnd: sl@0: HandleEValidateEndL(); sl@0: break; sl@0: sl@0: default: sl@0: User::Panic(_L("CPKIXCertChainAO"), 1); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: TInt CPKIXCertChainAO::RunError(TInt aError) sl@0: { sl@0: iPKIXCertChain.RemoveLastCerts(iNumberOfAddedCertificates); sl@0: iNumberOfAddedCertificates = 0; sl@0: sl@0: delete iRoots; sl@0: iRoots = 0; sl@0: sl@0: delete iBuilder; sl@0: iBuilder = 0; sl@0: delete iCertsFromStoreRoots; sl@0: iCertsFromStoreRoots = 0; sl@0: sl@0: iValidationResult->RemovePolicies(); sl@0: sl@0: User::RequestComplete(iOriginalRequestStatus, aError); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: * Creates a list of all the certificates retrieved from the store based on the filter passed. sl@0: */ sl@0: sl@0: void CPKIXCertChainAO::HandleEAddRootsL() sl@0: { sl@0: __ASSERT_DEBUG(!iCertsFromStoreRoots, User::Panic(_L("CPKICCertChainAO"), 1)); sl@0: iCertsFromStoreRoots = CPKIXCertsFromStore::NewL(*iCertStore, iClient); sl@0: iCertsFromStoreRoots->Initialize(iStatus); sl@0: iState = ERootsInitialized; sl@0: SetActive(); sl@0: } sl@0: sl@0: /** sl@0: * Adds the list of certificates retrieved from the store, iRoots (CPKIXChainBuilder) sl@0: * maintains a templatized list of all the certificates in MPKIXCertSource format. sl@0: */ sl@0: sl@0: void CPKIXCertChainAO::HandleERootsInitializedL() sl@0: { sl@0: iRoots->AddSourceL(iCertsFromStoreRoots); sl@0: // Ownership has been passed to iRoots sl@0: iCertsFromStoreRoots = 0; sl@0: iState = EBuildChainStart; sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::HandleEBuildChainStartL() sl@0: { sl@0: if ( false == iPKIXCertChain.ChainHasRoot()) sl@0: { sl@0: if (iPKIXCertChain.Chain().Count() == 0) sl@0: { sl@0: iState = EValidateEnd; sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: } sl@0: else sl@0: { sl@0: //1) look for an issuer that's a root sl@0: iRoots->AddIssuer(iNumberOfAddedCertificates, iAddIssuerResult, iPKIXCertChain.Chain(), iStatus); sl@0: iState = EBuildChainAddCandidateEnd; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // This is the correct state as at this point the chain of certificate has been build upto a sl@0: // root certificate. sl@0: iState = EValidateEnd; sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: } sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::HandleEBuildChainAddCandidateEndL() sl@0: { sl@0: if (iAddIssuerResult) sl@0: { sl@0: iPKIXCertChain.SetChainHasRoot(ETrue); sl@0: iState = EValidateEnd; sl@0: } sl@0: else sl@0: { sl@0: //2) look for a non-root issuer in intermediate certs sl@0: iBuilder = CPKIXChainBuilder::NewL(); sl@0: sl@0: CPKIXCertsFromClient* serverCerts = CPKIXCertsFromClient::NewLC(iPKIXCertChain.IntermediateCerts()); sl@0: iBuilder->AddSourceL(serverCerts); sl@0: CleanupStack::Pop(serverCerts); sl@0: sl@0: iState = EBuildChainCertsFromStoreBegin; sl@0: } sl@0: sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::HandleEBuildChainCertsFromStoreBeginL() sl@0: { sl@0: //3) look for a non-root issuer in the store sl@0: iCertsFromStoreRoots = CPKIXCertsFromStore::NewL(*iCertStore); sl@0: iCertsFromStoreRoots->Initialize(iStatus); sl@0: iState = EBuildChainCertsFromStoreEnd; sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::HandleEBuildChainCertsFromStoreEndL() sl@0: { sl@0: iBuilder->AddSourceL(iCertsFromStoreRoots); sl@0: iCertsFromStoreRoots = 0; sl@0: sl@0: iBuilder->AddIssuer(iNumberOfAddedCertificates, iAddIssuerResult, iPKIXCertChain.Chain(), iStatus); sl@0: iState = EAddCandidateIntermediateCertsEnd; sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::HandleEAddCandidateIntermediateCertsEndL() sl@0: { sl@0: if (iAddIssuerResult) sl@0: { sl@0: // cert is a pointer to something we don't own sl@0: CX509Certificate* cert = iPKIXCertChain.Chain().At(iPKIXCertChain.Chain().Count() - 1); sl@0: sl@0: /* If the issuer is not a self signed certificate then it cannot be trusted anchor for the chain sl@0: * validation process, this means that we restart the certification validation process. sl@0: */ sl@0: sl@0: if (!(cert->IsSelfSignedL())) sl@0: { sl@0: iState = EBuildChainStart; sl@0: } sl@0: else sl@0: { sl@0: iState = EValidateEnd; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iState = EValidateEnd; sl@0: } sl@0: sl@0: delete iBuilder; sl@0: iBuilder = 0; sl@0: sl@0: TRequestStatus* status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::HandleEValidateEndL() sl@0: { sl@0: InitParamsL(); sl@0: sl@0: __ASSERT_DEBUG(iValidationResult, User::Panic(_L("CPKICCertChainAO"), 1)); sl@0: DoValidateL(*iValidationResult, iValidationTime, iInitialPolicies); sl@0: sl@0: User::RequestComplete(iOriginalRequestStatus, KErrNone); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::DoCancel() sl@0: { sl@0: delete iRoots; sl@0: iRoots = 0; sl@0: sl@0: delete iBuilder; sl@0: iBuilder = 0; sl@0: sl@0: delete iCertsFromStoreRoots; sl@0: iCertsFromStoreRoots = 0; sl@0: sl@0: User::RequestComplete(iOriginalRequestStatus, KErrCancel); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::ValidateL(CPKIXValidationResultBase& aValidationResult, sl@0: const TTime& aValidationTime, sl@0: const CArrayPtr* aInitialPolicies, sl@0: TRequestStatus& aStatus) sl@0: { sl@0: aValidationResult.Reset(); sl@0: iValidationResult = &aValidationResult; sl@0: iValidationTime = aValidationTime; sl@0: iInitialPolicies = aInitialPolicies; sl@0: iOriginalRequestStatus = &aStatus; sl@0: iNumberOfAddedCertificates = 0; sl@0: sl@0: __ASSERT_ALWAYS(!IsActive(), User::Panic(_L("CPKICCertChainAO"), 1)); sl@0: sl@0: if (!iRoots) sl@0: { sl@0: // If iRoots is 0, it means that the caller gave a uid and that sl@0: // we must retrieve the trusted certificates from the different sl@0: // stores sl@0: iRoots = CPKIXChainBuilder::NewL(); sl@0: iState = EAddRoots; sl@0: } sl@0: else sl@0: { sl@0: // The caller gave a set of certificates it trusts, sl@0: // so we don't have to retrieve anything from the stores sl@0: iState = EBuildChainStart; sl@0: } sl@0: sl@0: aStatus = KRequestPending; sl@0: TRequestStatus *status = &iStatus; sl@0: User::RequestComplete(status, KErrNone); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::CancelValidate() sl@0: { sl@0: Cancel(); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::InitParamsL() sl@0: /* sl@0: this function initialises signing key parameters for the certificates sl@0: -only DSA needs these at present sl@0: -we get the signing key, from the spki of the issuer sl@0: -if it's dsa, we look for params here sl@0: -if we find them we initialise the cert with them sl@0: -otherwise, we look in the issuer's issuer sl@0: -if we don't find them there we give up. sl@0: */ sl@0: { sl@0: sl@0: // If the root is DSA signed, set its parameters sl@0: sl@0: TInt count = iPKIXCertChain.Chain().Count(); sl@0: sl@0: CX509Certificate* current = iPKIXCertChain.Chain().At(count-1); sl@0: TAlgorithmId signingAlgorithm = current->SigningAlgorithm().AsymmetricAlgorithm().Algorithm(); sl@0: sl@0: if (signingAlgorithm == EDSA) sl@0: { sl@0: sl@0: const CSubjectPublicKeyInfo& key = current->PublicKey(); sl@0: SetParamsL(*current, key.EncodedParams()); sl@0: sl@0: } sl@0: sl@0: // Also the rest of the chain sl@0: sl@0: for (TInt i = count - 2; i >= 0; i--) sl@0: { sl@0: sl@0: current = iPKIXCertChain.Chain().At(i); sl@0: TAlgorithmId signingAlgorithm = current->SigningAlgorithm().AsymmetricAlgorithm().Algorithm(); sl@0: sl@0: if (signingAlgorithm == EDSA) sl@0: { sl@0: sl@0: // Look down the chain for parameters sl@0: sl@0: for (TInt j = i+1; j < count; j++) sl@0: { sl@0: sl@0: CX509Certificate* issuer = iPKIXCertChain.Chain().At(j); sl@0: const CSubjectPublicKeyInfo& key = issuer->PublicKey(); sl@0: if (key.EncodedParams() != KNullDesC8 && key.AlgorithmId() == EDSA) sl@0: { sl@0: SetParamsL(*current, key.EncodedParams()); sl@0: break; sl@0: } sl@0: sl@0: } sl@0: sl@0: } sl@0: sl@0: } sl@0: } sl@0: sl@0: void CPKIXCertChainAO::SetParamsL(CX509Certificate& aCert, const TPtrC8& aEncodedParams) sl@0: { sl@0: TX509KeyFactory factory; sl@0: CDSAParameters* theDSAParams = factory.DSAParametersL(aEncodedParams); sl@0: CleanupStack::PushL(theDSAParams); sl@0: sl@0: CSigningKeyParameters* params = CSigningKeyParameters::NewLC(); sl@0: params->SetDSAParamsL(*theDSAParams); sl@0: sl@0: aCert.SetParametersL(*params); sl@0: sl@0: CleanupStack::PopAndDestroy(2, theDSAParams); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::DoValidateL(CPKIXValidationResultBase& aValidationResult, sl@0: const TTime& aValidationTime, sl@0: const CArrayPtr* aInitialPolicies) sl@0: { sl@0: if (!iPKIXCertChain.ChainHasRoot()) sl@0: { sl@0: aValidationResult.SetError(EChainHasNoRoot, 0); sl@0: } sl@0: else sl@0: { sl@0: CPKIXValidationState* state = CPKIXValidationState::NewLC(aValidationTime, iPKIXCertChain.Chain().Count(), aInitialPolicies); sl@0: TRAPD(err, ProcessCertsL(*state, aValidationResult)); sl@0: //a leave here means either: sl@0: // -a validation error, in which case we've set the error field in result, or sl@0: // -some other error (e.g. OOM) in which case error is still EChainHasNoRoot sl@0: if ((err != KErrNone) && ((aValidationResult.Error().iReason) == EChainHasNoRoot)) sl@0: //then we left with a non-validation-related error, so leave again... sl@0: { sl@0: User::Leave(err); sl@0: } sl@0: CleanupStack::PopAndDestroy(state); sl@0: } sl@0: } sl@0: sl@0: // ProcessCertsL: This function validates a complete certificate sl@0: // chain. If an error occurs in this function the function sl@0: // SetErrorAndLeaveL must be called. sl@0: // sl@0: // Note Do not use SetErrorAndLeaveL with EChainHasNoRoot (see TRAP code in sl@0: // CPKIXCertChainAO::DoValidateL ) sl@0: void CPKIXCertChainAO::ProcessCertsL(CPKIXValidationState& aState, sl@0: CPKIXValidationResultBase& aResult) const sl@0: { sl@0: TPKIXPolicyConstraint policy(aState, aResult); sl@0: TPKIXNameConstraint name(aState, aResult); sl@0: TPKIXBasicConstraint basic(aState, aResult); sl@0: TPKIXKeyUsageConstraint keyUsage(aState, aResult); sl@0: for (; aState.iPos >= 0; aState.iPos--) sl@0: { sl@0: aState.iMaxPathLength--; sl@0: if (aState.iMaxPathLength < aState.iPos) sl@0: { sl@0: aResult.SetErrorAndLeaveL(EPathTooLong, aState.iPos); sl@0: } sl@0: const CX509Certificate* current = iPKIXCertChain.Chain().At(aState.iPos); sl@0: CCertificateValidationWarnings* certWarnings = CCertificateValidationWarnings::NewLC(aState.iPos); sl@0: aResult.AppendCertificateValidationObjectL(*certWarnings); sl@0: CleanupStack::Pop(certWarnings); sl@0: CriticalExtsL(aState, *current); sl@0: CheckCriticalExtsL(aState, aResult); sl@0: CheckSignatureAndNameL(*current, aState, aResult); sl@0: //!!!!NO!!checks for revocation at this time!! sl@0: sl@0: if (!(current->ValidityPeriod().Valid(aState.iValidationTime))) sl@0: { sl@0: //validity period invalid, now check how to report this sl@0: if (iPKIXCertChain.ValidityPeriodCheckFatal()) sl@0: { sl@0: aResult.SetErrorAndLeaveL(EDateOutOfRange, aState.iPos); sl@0: } sl@0: else sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(EDateOutOfRange, aState.iPos)); sl@0: } sl@0: } sl@0: sl@0: policy.CheckCertPoliciesL(*current); sl@0: name.CheckNameConstraintsL(*current); sl@0: keyUsage.CheckKeyUsageL(*current); sl@0: if (aState.iPos < (iPKIXCertChain.Chain().Count() - 1)) sl@0: { sl@0: basic.CheckCertSubjectTypeL(*current); sl@0: } sl@0: basic.UpdatePathLengthConstraintsL(*current); sl@0: name.UpdateNameConstraintsL(*current); sl@0: policy.UpdatePolicyConstraintsL(*current); sl@0: aState.iCriticalExts->Reset(); sl@0: } sl@0: policy.FinishPolicyCheckL(); sl@0: //*copy* all policies from aState.iAuthorityConstrainedPolicies into aResult.iPolicies sl@0: TInt policyCount = aState.iAuthorityConstrainedPolicies->Count(); sl@0: for (TInt i = 0; i < policyCount; i ++) sl@0: { sl@0: CX509CertPolicyInfo* policyInfo = CX509CertPolicyInfo::NewLC(*(aState.iAuthorityConstrainedPolicies->At(i))); sl@0: aResult.AppendPolicyL(*policyInfo); sl@0: CleanupStack::Pop(policyInfo); sl@0: } sl@0: sl@0: aResult.SetError(EValidatedOK, 0); sl@0: } sl@0: sl@0: void CPKIXCertChainAO::CriticalExtsL(CPKIXValidationState& aState, sl@0: const CX509Certificate& aCert) const sl@0: { sl@0: const CArrayPtrFlat& exts = aCert.Extensions(); sl@0: TInt count = exts.Count(); sl@0: for (TInt i = 0; i < count; i++) sl@0: { sl@0: CX509CertExtension* ext = exts.At(i); sl@0: if (ext->Critical()) sl@0: { sl@0: aState.iCriticalExts->AppendL(ext); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CPKIXCertChainAO::CheckSignatureAndNameL(const CX509Certificate& aCert, CPKIXValidationState& aState, sl@0: CPKIXValidationResultBase& aResult) const sl@0: { sl@0: TInt issuerPos = aState.iPos + 1; sl@0: if (issuerPos == iPKIXCertChain.Chain().Count()) sl@0: //then it's the root sl@0: { sl@0: if (aCert.IssuerName().ExactMatchL(aCert.SubjectName())) sl@0: //then it claims to be self signed, sig must verify sl@0: { sl@0: if (!(aCert.VerifySignatureL(aCert.PublicKey().KeyData()))) sl@0: { sl@0: aResult.SetErrorAndLeaveL(ESignatureInvalid, aState.iPos); sl@0: } sl@0: } sl@0: else sl@0: //we generate a warning sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ERootCertNotSelfSigned, aState.iPos)); sl@0: } sl@0: } sl@0: else sl@0: //then it isn't the root: so names must chain & sigs must verify sl@0: { sl@0: const CX509Certificate* issuer = iPKIXCertChain.Chain().At(issuerPos); sl@0: if (!(aCert.IssuerName().ExactMatchL(issuer->SubjectName()))) sl@0: { sl@0: aResult.SetErrorAndLeaveL(ENamesDontChain, aState.iPos); sl@0: } sl@0: if (!(aCert.VerifySignatureL(issuer->PublicKey().KeyData()))) sl@0: { sl@0: aResult.SetErrorAndLeaveL(ESignatureInvalid, aState.iPos); sl@0: } sl@0: } sl@0: } sl@0: sl@0: void CPKIXCertChainAO::CheckCriticalExtsL(CPKIXValidationState& aState, CPKIXValidationResultBase& aResult) const sl@0: { sl@0: TBool foundUnrecognisedCritExt; sl@0: sl@0: // retrieve the supported list of critical extensions. If a critical extension is found whose OID matches an sl@0: // element in this set then certificate validation shall treat this as a warning instead of an error. sl@0: const RPointerArray& supportedCritExt = iPKIXCertChain.SupportedCriticalExtensions(); sl@0: sl@0: TInt count = aState.iCriticalExts->Count(); sl@0: TInt supportedCount = supportedCritExt.Count(); sl@0: for (TInt i = 0; i < count; i++) sl@0: { sl@0: foundUnrecognisedCritExt = ETrue; sl@0: const CX509CertExtension* ext = aState.iCriticalExts->At(i); sl@0: const TPtrC& extName = ext->Id(); sl@0: sl@0: for (TInt j = 0; j < supportedCount; ++j) sl@0: { sl@0: if (extName == *supportedCritExt[j]) sl@0: { sl@0: foundUnrecognisedCritExt = EFalse; sl@0: HBufC* oid = extName.AllocLC(); sl@0: aResult.AppendCriticalExtensionWarningL(*oid); sl@0: CleanupStack::Pop(oid); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: if (extName == KExtendedKeyUsage) sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ECriticalExtendedKeyUsage, aState.iPos)); sl@0: } sl@0: else if (extName == KPolicyMapping) sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ECriticalPolicyMapping, aState.iPos)); sl@0: } sl@0: else if (extName == KInhibitAnyPolicy) sl@0: { sl@0: //ignore this in the same way sl@0: } sl@0: else if (extName == KDeviceIdListConstraint) sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ECriticalDeviceId, aState.iPos)); sl@0: } sl@0: else if(extName == KSidListConstraint) sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ECriticalSid, aState.iPos)); sl@0: } sl@0: else if(extName == KVidListConstraint) sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ECriticalVid, aState.iPos)); sl@0: } sl@0: else if(extName == KCapabilitiesConstraint) sl@0: { sl@0: aResult.AppendWarningL(TValidationStatus(ECriticalCapabilities, aState.iPos)); sl@0: } sl@0: sl@0: if (foundUnrecognisedCritExt) sl@0: { sl@0: aResult.SetErrorAndLeaveL(EUnrecognizedCriticalExtension, aState.iPos); sl@0: } sl@0: sl@0: } sl@0: }