diff -r 000000000000 -r 2c201484c85f cryptoservices/certificateandkeymgmt/pkixcertbase/pkixcons.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cryptoservices/certificateandkeymgmt/pkixcertbase/pkixcons.cpp Wed Jul 08 11:25:26 2009 +0100 @@ -0,0 +1,630 @@ +/* +* Copyright (c) 1998-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: +* +*/ + + +#include "pkixCons.h" + +//PKIX constraint +//only function is remove +TPKIXConstraint::TPKIXConstraint( CPKIXValidationState& aState, + CPKIXValidationResultBase& aResult) + :iState(aState), iResult(aResult) + { + } + +void TPKIXConstraint::Remove(CArrayPtrFlat& aCriticalExtensions, const TDesC& aOID) + { + TInt count = aCriticalExtensions.Count(); + for (TInt i = 0; i < count; i++) + { + CX509CertExtension* ext = aCriticalExtensions.At(i); + if (ext->Id() == aOID) + { + aCriticalExtensions.Delete(i); + break; + } + } + } + +//policy constraint +//public functions +TPKIXPolicyConstraint::TPKIXPolicyConstraint( CPKIXValidationState& aState, + CPKIXValidationResultBase& aResult) + :TPKIXConstraint(aState, aResult) + { + } + +void TPKIXPolicyConstraint::CleanupPolicyInfoArray(TAny* aPolicies) + { + CArrayPtrFlat* array = REINTERPRET_CAST(CArrayPtrFlat*, aPolicies); + array->ResetAndDestroy(); + delete array; + } + +void TPKIXPolicyConstraint::CheckCertPoliciesL(const CX509Certificate& aCert) + { + const CX509CertExtension* ext = aCert.Extension(KCertPolicies); + CX509CertPoliciesExt* policyExt = NULL; + if (ext) + { + policyExt = CX509CertPoliciesExt::NewLC(ext->Data()); + } + if (iState.iPos > iState.iPolicyRequired) + { + if (!(policyExt)) + { + iResult.SetErrorAndLeaveL(ERequiredPolicyNotFound, iState.iPos); + } + const CArrayPtrFlat& policies = policyExt->Policies(); + if ((iState.iUserPolicies->Count() == 0) || (PolicyIsPresentL(policies, *iState.iUserPolicies))) + { + } + else + { + iResult.SetErrorAndLeaveL(ERequiredPolicyNotFound, iState.iPos); + } + } + if (!policyExt) + { + if (!iState.iAnyAuthorityPolicy) + { + iState.iAuthorityConstrainedPolicies->ResetAndDestroy();//AP becomes NULL + } + } + else + { + IntersectCertPoliciesL(*policyExt); + if (ext->Critical()) + { + TInt count = iState.iAuthorityConstrainedPolicies->Count(); + for (TInt i = 0; i < count; i++) + { + const CX509CertPolicyInfo* policy = iState.iAuthorityConstrainedPolicies->At(i); + if (policy->Qualifiers().Count() > 0) + { + iResult.AppendWarningL(TValidationStatus(ECriticalCertPoliciesWithQualifiers, i)); + break; + } + } + Remove(*(iState.iCriticalExts), KCertPolicies); + } + CleanupStack::PopAndDestroy();//policyExt + } + } + +void TPKIXPolicyConstraint::IntersectCertPoliciesL(const CX509CertPoliciesExt& aPolicyExt) + { + //1 intersect AP and CP, assign result to newAP + CArrayPtrFlat* newAP; + TInt certPolicyCount = aPolicyExt.Policies().Count(); + if (iState.iAnyAuthorityPolicy) + { + newAP = new(ELeave) CArrayPtrFlat (1); + TCleanupItem cleanupPolicies(CleanupPolicyInfoArray, newAP); + CleanupStack::PushL(cleanupPolicies); + for (TInt i = 0; i < certPolicyCount; i++) + { + CX509CertPolicyInfo* info = CX509CertPolicyInfo::NewLC(*(aPolicyExt.Policies().At(i))); + newAP->AppendL(info); + CleanupStack::Pop(); + } + iState.iAnyAuthorityPolicy = EFalse; + } + else + { + newAP = IntersectionLC(aPolicyExt.Policies(), *(iState.iAuthorityConstrainedPolicies)); + } + + TInt mappedCount = iState.iMappedPolicies->Count(); + for (TInt i = 0; i < mappedCount; i++) + { + CX509PolicyMapping* mapping = iState.iMappedPolicies->At(i); + TInt apCount = iState.iAuthorityConstrainedPolicies->Count(); + //2 for each mapping in MP, if issuer is in AP and subject is in CP, add subject to newAP + for (TInt j = 0; j < apCount; j++) + { + CX509CertPolicyInfo* aCP = iState.iAuthorityConstrainedPolicies->At(j); + if (aCP->Id() == mapping->IssuerPolicy()) + { + for (TInt k = 0; k < certPolicyCount; k++) + { + CX509CertPolicyInfo* cp = aPolicyExt.Policies().At(k); + if (mapping->SubjectPolicy() == cp->Id()) + { + CX509CertPolicyInfo* newPolicy = CX509CertPolicyInfo::NewLC(*cp); + newAP->AppendL(newPolicy); + CleanupStack::Pop(); + } + } + } + } + } + //new acceptable policies = intersection + iState.iAuthorityConstrainedPolicies->ResetAndDestroy(); + delete iState.iAuthorityConstrainedPolicies; + iState.iAuthorityConstrainedPolicies = newAP; + CleanupStack::Pop();//newAP + } + +void TPKIXPolicyConstraint::UpdatePolicyConstraintsL(const CX509Certificate& aCert) + { + //get mapping ext + const CX509CertExtension* ext = aCert.Extension(KPolicyMapping); + if ((iState.iPos <= iState.iPolicyMapping) && (ext)) + { + CX509PolicyMappingExt* policyMappingExt = CX509PolicyMappingExt::NewLC(ext->Data()); + const CArrayPtrFlat& mappings = policyMappingExt->Mappings(); + //for each policy mapping + TInt countM = mappings.Count(); + for (TInt i = 0; i < countM; i++) + { + CX509PolicyMapping* mapping = mappings.At(i); + CX509PolicyMapping* newMapping = CX509PolicyMapping::NewLC(*mapping); + iState.iMappedPolicies->AppendL(newMapping); + CleanupStack::Pop(); + TInt uCount = iState.iUserPolicies->Count(); + for (TInt j = 0; j < uCount; j++) + { + HBufC* userPolicy = iState.iUserPolicies->At(j); + if (newMapping->IssuerPolicy() == *userPolicy) + { + HBufC* newUP = newMapping->SubjectPolicy().AllocL(); + CleanupStack::PushL(newUP); + iState.iUserPolicies->AppendL(newUP); + CleanupStack::Pop(); + break; + } + } + } + CleanupStack::PopAndDestroy();//mapping ext + } + iState.iPolicyMapping --; + iState.iPolicyRequired --; + //get constraints + ext = aCert.Extension(KPolicyConstraints); + if ( ext ) + { + CX509PolicyConstraintsExt* policyConstraintsExt = CX509PolicyConstraintsExt::NewLC(ext->Data()); + UpdateConstraint(policyConstraintsExt->InhibitPolicyMapping(), iState.iPolicyMapping); + UpdateConstraint(policyConstraintsExt->ExplicitPolicyRequired(), iState.iPolicyRequired); + CleanupStack::PopAndDestroy();//constraint ext + //remove it from the 'critical list' + if (ext->Critical()) + { + Remove(*(iState.iCriticalExts), KPolicyConstraints); + } + } + } + +//private functions +TBool TPKIXPolicyConstraint::PolicyIsPresentL( const CArrayPtrFlat& aPolicies, + const CArrayPtr& aAcceptablePolicies) + { + TInt certCount = aPolicies.Count(); + TInt chainCount = aAcceptablePolicies.Count(); + for (TInt i = 0; i < certCount; i++) + { + CX509CertPolicyInfo* certPolicy = aPolicies.At(i); + for (TInt j = 0; j < chainCount; j++) + { + HBufC* chainPolicy = aAcceptablePolicies.At(j); + if (certPolicy->Id() == chainPolicy->Des()) + { + return ETrue; + } + } + } + return EFalse; + } + +void TPKIXPolicyConstraint::UpdateConstraint(const TX509PolicyConstraint& aConstraint, TInt& aCountdown) + { + if (aConstraint.iRequired) + { + if (aConstraint.iCountdown < aCountdown) + aCountdown = aConstraint.iCountdown; + } + } + +void TPKIXPolicyConstraint::FinishPolicyCheckL() + { + if (iState.iUserConstrainedPolicies) + { + TBool passed = EFalse; + if (!(iState.iAnyAuthorityPolicy)) + {//policy from user policies must be in authority policy set + if ((PolicyIsPresentL(*(iState.iAuthorityConstrainedPolicies), *(iState.iUserPolicies)))) + { + passed = ETrue; + } + } + if (!passed) + { + iResult.SetErrorAndLeaveL(ERequiredPolicyNotFound, iState.iPos); + } + } + } + +CArrayPtrFlat* TPKIXPolicyConstraint::IntersectionLC( + const CArrayPtrFlat& aFirst, + const CArrayPtrFlat& aSecond) + //constructs an array of certificate policy objects, + //populating it with policies that occur in both of the array parameters + { + CArrayPtrFlat* inter = new(ELeave) CArrayPtrFlat (1); + TCleanupItem cleanupPolicies(CleanupPolicyInfoArray, inter); + CleanupStack::PushL(cleanupPolicies); + TInt count1 = aFirst.Count(); + TInt count2 = aSecond.Count(); + for (TInt i = 0; i < count1; i++) + { + CX509CertPolicyInfo* policy1 = aFirst.At(i); + for (TInt j = 0; j < count2; j++) + { + CX509CertPolicyInfo* policy2 = aSecond.At(j); + if (policy1->Id() == policy2->Id()) + { + CX509CertPolicyInfo* info = CX509CertPolicyInfo::NewLC(*policy1); + inter->AppendL(info); + CleanupStack::Pop(); + } + } + } + return inter; + } + +//name constraint +//public functions +TPKIXNameConstraint::TPKIXNameConstraint( CPKIXValidationState& aState, + CPKIXValidationResultBase& aResult) + :TPKIXConstraint(aState, aResult) + { + } + +void TPKIXNameConstraint::CheckNameConstraintsL(const CX509Certificate& aCert) + { + //*do the subject name + if (NameIsPresentL(aCert.SubjectName(), *(iState.iExcludedDNSubtrees))) + { + iResult.SetErrorAndLeaveL(ENameIsExcluded, iState.iPos); + } + TInt pCount = iState.iPermittedDNSubtrees->Count(); + if ((pCount > 0) && (!(NameIsPresentL(aCert.SubjectName(), *(iState.iPermittedDNSubtrees))))) + { + iResult.SetErrorAndLeaveL(ENameNotPermitted, iState.iPos); + } + //*do the alt name + const CX509CertExtension* ext = aCert.Extension(KSubjectAltName); + if (ext) + { + CX509AltNameExt* altNameExt = CX509AltNameExt::NewLC(ext->Data()); + const CArrayPtrFlat& altName = altNameExt->AltName(); + TInt count = altName.Count(); + for (TInt i = 0; i < count; i++) + { + const CX509GeneralName* gN = altName.At(i); + switch (gN->Tag()) + { + case EX509DirectoryName://X500DN + { + const CX500DistinguishedName* dN = CX500DistinguishedName::NewLC(gN->Data()); + if (NameIsPresentL(*dN, *(iState.iExcludedDNSubtrees))) + { + iResult.SetErrorAndLeaveL(ENameIsExcluded, iState.iPos); + } + if ((pCount > 0) && (!(NameIsPresentL(*dN, *(iState.iPermittedDNSubtrees))))) + { + iResult.SetErrorAndLeaveL(ENameNotPermitted, iState.iPos); + } + CleanupStack::PopAndDestroy(); + } + break; + case EX509RFC822Name://IA5String + { + const CX509RFC822Name* name = CX509RFC822Name::NewLC(gN->Data()); + if (NameIsPresent(*name, *(iState.iExcludedRFC822Subtrees))) + { + iResult.SetErrorAndLeaveL(ENameIsExcluded, iState.iPos); + } + if ((iState.iPermittedRFC822Subtrees->Count() > 0) && (!(NameIsPresent(*name, *(iState.iPermittedRFC822Subtrees))))) + { + iResult.SetErrorAndLeaveL(ENameNotPermitted, iState.iPos); + } + CleanupStack::PopAndDestroy(); + } + break; + case EX509URI://IA5String + { + const CX509IPBasedURI* name = CX509IPBasedURI::NewLC(gN->Data()); + const CX509DNSName& domain = name->Host(); + if (NameIsPresent(domain, *(iState.iExcludedDNSNameSubtrees))) + { + iResult.SetErrorAndLeaveL(ENameIsExcluded, iState.iPos); + } + if ((iState.iPermittedDNSNameSubtrees->Count() > 0) && (!(NameIsPresent(domain, *(iState.iPermittedDNSNameSubtrees))))) + { + iResult.SetErrorAndLeaveL(ENameNotPermitted, iState.iPos); + } + CleanupStack::PopAndDestroy(); + } + break; + case EX509DNSName://IA5String + { + const CX509DNSName* name = CX509DNSName::NewLC(gN->Data()); + if (NameIsPresent(*name, *(iState.iExcludedDNSNameSubtrees))) + { + iResult.SetErrorAndLeaveL(ENameIsExcluded, iState.iPos); + } + if ((iState.iPermittedDNSNameSubtrees->Count() > 0) && (!(NameIsPresent(*name, *(iState.iPermittedDNSNameSubtrees))))) + { + iResult.SetErrorAndLeaveL(ENameNotPermitted, iState.iPos); + } + CleanupStack::PopAndDestroy(); + } + break; + case EX509IPAddress://octet string + { + const CX509IPAddress* name = CX509IPAddress::NewLC(gN->Data()); + if (NameIsPresent(*name, *(iState.iExcludedIPAddressSubtrees))) + { + iResult.SetErrorAndLeaveL(ENameIsExcluded, iState.iPos); + } + if ((iState.iPermittedIPAddressSubtrees->Count() > 0) && (!(NameIsPresent(*name, *(iState.iPermittedIPAddressSubtrees))))) + { + iResult.SetErrorAndLeaveL(ENameNotPermitted, iState.iPos); + } + CleanupStack::PopAndDestroy(); + } + break; + } + }//end of for loop + //we've handled this now, so can remove it from the critical list + Remove(*(iState.iCriticalExts), KSubjectAltName); + CleanupStack::PopAndDestroy();//altNameExt + }//end of if(ext) + } + +void TPKIXNameConstraint::UpdateNameConstraintsL(const CX509Certificate& aCert) + { + const CX509CertExtension* ext = aCert.Extension(KNameConstraints); + if (ext) + { + CX509NameConstraintsExt* nameCons = CX509NameConstraintsExt::NewLC(ext->Data()); + const CArrayPtrFlat& excSubtrees = nameCons->ExcludedSubtrees(); + TInt count = excSubtrees.Count(); + for (TInt i = 0; i < count; i++) + { + const CX509GeneralSubtree* subtree = excSubtrees.At(i); + const CX509GeneralName& gN = subtree->Name(); + switch (gN.Tag()) + { + case EX509DirectoryName://X500DN + { + CX500DistinguishedName* name = CX500DistinguishedName::NewLC(gN.Data()); + iState.iExcludedDNSubtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + case EX509RFC822Name://IA5String + { + CX509RFC822Name* name = CX509RFC822Name::NewLC(gN.Data()); + iState.iExcludedRFC822Subtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + case EX509URI://IA5String + { + CX509IPBasedURI* name = CX509IPBasedURI::NewLC(gN.Data()); + CX509DNSName* domain = CX509DNSName::NewLC(name->Host()); + iState.iExcludedDNSNameSubtrees->AppendL(domain); + CleanupStack::Pop(); + CleanupStack::PopAndDestroy(); + } + break; + case EX509DNSName://IA5String + { + CX509DNSName* name = CX509DNSName::NewLC(gN.Data()); + iState.iExcludedDNSNameSubtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + case EX509IPAddress://octet string + { + CX509IPSubnetMask* name = CX509IPSubnetMask::NewLC(gN.Data()); + iState.iExcludedIPAddressSubtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + default: + { + User::Leave(KErrNotSupported); + } + break; + } + }//end of for loop + const CArrayPtrFlat& perSubtrees = nameCons->PermittedSubtrees(); + count = perSubtrees.Count(); + for (TInt j = 0; j < count; j++) + { + const CX509GeneralSubtree* subtree = perSubtrees.At(j); + const CX509GeneralName& gN = subtree->Name(); + switch (gN.Tag()) + { + case EX509DirectoryName://X500DN + { + CX500DistinguishedName* name = CX500DistinguishedName::NewLC(gN.Data()); + iState.iPermittedDNSubtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + case EX509RFC822Name://IA5String + { + CX509RFC822Name* name = CX509RFC822Name::NewLC(gN.Data()); + iState.iPermittedRFC822Subtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + case EX509URI://IA5String + { + CX509IPBasedURI* name = CX509IPBasedURI::NewLC(gN.Data()); + CX509DNSName* domain = CX509DNSName::NewLC(name->Host()); + iState.iPermittedDNSNameSubtrees->AppendL(domain); + CleanupStack::Pop(); + CleanupStack::PopAndDestroy(); + } + break; + case EX509DNSName://IA5String + { + CX509DNSName* name = CX509DNSName::NewLC(gN.Data()); + iState.iPermittedDNSNameSubtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + case EX509IPAddress://octet string + { + CX509IPSubnetMask* name = CX509IPSubnetMask::NewLC(gN.Data()); + iState.iPermittedIPAddressSubtrees->AppendL(name); + CleanupStack::Pop(); + } + break; + default: + { + User::Leave(KErrNotSupported); + } + break; + } + }//end of for loop + CleanupStack::PopAndDestroy();//nameConsExt + //we've handled this now, so can remove it from the critical list + Remove(*(iState.iCriticalExts), KNameConstraints); + }//end of if(ext) + } + + +//private functions +TBool TPKIXNameConstraint::NameIsPresentL( const CX500DistinguishedName& aSubject, + const CArrayPtrFlat& aSubtrees) + { + TInt count = aSubtrees.Count(); + for (TInt i = 0; i < count; i++) + { + const CX500DistinguishedName* excluded = aSubtrees.At(i); + if (aSubject.IsWithinSubtreeL(*excluded)) + { + return ETrue; + } + } + return EFalse; + } + +TBool TPKIXNameConstraint::NameIsPresent( const CX509DomainName& aSubject, + const CArrayPtrFlat& aSubtrees) + { + TInt count = aSubtrees.Count(); + for (TInt i = 0; i < count; i++) + { + const CX509DomainName* excluded = aSubtrees.At(i); + if (aSubject.IsWithinSubtree(*excluded)) + { + return ETrue; + } + } + return EFalse; + } + +TBool TPKIXNameConstraint::NameIsPresent( const CX509IPAddress& aSubject, + const CArrayPtrFlat& aSubtrees) + { + TInt count = aSubtrees.Count(); + for (TInt i = 0; i < count; i++) + { + const CX509IPSubnetMask* excluded = aSubtrees.At(i); + if (aSubject.IsWithinSubtree(*excluded)) + { + return ETrue; + } + } + return EFalse; + } + +//basic constraint +TPKIXBasicConstraint::TPKIXBasicConstraint( CPKIXValidationState& aState, + CPKIXValidationResultBase& aResult) + :TPKIXConstraint(aState, aResult) + { + } + +void TPKIXBasicConstraint::CheckCertSubjectTypeL(const CX509Certificate& aCert) + { + TBool markedAsCA = EFalse; + TBool actsAsCA = iState.iPos > 0; + const CX509CertExtension* ext = aCert.Extension(KBasicConstraints); + if (ext) + { + CX509BasicConstraintsExt* basic = CX509BasicConstraintsExt::NewLC(ext->Data()); + markedAsCA = basic->IsCA(); + CleanupStack::PopAndDestroy(); + } + if (actsAsCA && (!markedAsCA)) + { + iResult.SetErrorAndLeaveL(ENotCACert, iState.iPos); + } + } + +void TPKIXBasicConstraint::UpdatePathLengthConstraintsL(const CX509Certificate& aCert) + { + const CX509CertExtension* ext = aCert.Extension(KBasicConstraints); + if (ext) + { + CX509BasicConstraintsExt* basic = CX509BasicConstraintsExt::NewLC(ext->Data()); + TInt pathLength = basic->MaxChainLength(); + if (pathLength < 0) + { + iResult.SetErrorAndLeaveL(ENegativePathLengthSpecified, iState.iPos); + } + if (iState.iPos > pathLength) + { + iState.iMaxPathLength = pathLength + 1; + } + Remove(*(iState.iCriticalExts), KBasicConstraints); + CleanupStack::PopAndDestroy();//basic + } + } + +//key usage constraint +TPKIXKeyUsageConstraint::TPKIXKeyUsageConstraint( CPKIXValidationState& aState, + CPKIXValidationResultBase& aResult) + :TPKIXConstraint(aState, aResult) + { + } + +void TPKIXKeyUsageConstraint::CheckKeyUsageL(const CX509Certificate& aCert) + { + //if key usage is critical and this is a CA cert, the keyCertSign bit must be set + const CX509CertExtension* ext = aCert.Extension(KKeyUsage); + if (ext) + { + CX509KeyUsageExt* keyUsage = CX509KeyUsageExt::NewLC(ext->Data()); + if ( (iState.iPos > 0) && (!(keyUsage->IsSet(EX509KeyCertSign)))) + { + iResult.SetErrorAndLeaveL(EBadKeyUsage, iState.iPos); + } + CleanupStack::PopAndDestroy(); + //we've processed this critical ext, so remove it + Remove(*(iState.iCriticalExts), KKeyUsage); + } + }