diff -r 000000000000 -r 2c201484c85f cryptoservices/certificateandkeymgmt/x509/x509gn.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cryptoservices/certificateandkeymgmt/x509/x509gn.cpp Wed Jul 08 11:25:26 2009 +0100 @@ -0,0 +1,712 @@ +/* +* 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 +#include "asn1dec.h" + +/* + * __SECURITY_PLATSEC_ARCH__: Changes for platform security + * + * If this macro is defined, the represenation of TPtrC arrays is changed from + * using CPtrCArray to RArray. This is because CPtrCArray is supplied by + * bafl.dll, which is not trusted for TCB. x509 needs to be trusted for TCB so + * it can be used by software install, hence this dependency was removed. + * + * This changes is implmented as a series of macros for the basic operations, + * to minimise the amount of conditional compilation. + */ + + +#define REP_INIT_L /* do nothing */ +#define REP_FINAL iRep.Close() +#define REP_APPEND_L(X) User::LeaveIfError(iRep.Append(X)) +#define REP_COUNT iRep.Count() +#define REP_AT(X) iRep[X] +#define REP_VAL iRep +#define REP_VAL_TYPE RArray + + +_LIT(KX509RFC822HostDomainSeparator,"@"); +_LIT(KX509SubdomainSeparator,"."); +_LIT(KX509URISchemeSpecificStart, "//"); +_LIT(KX509URIUserPasswordEnd, "@"); +_LIT(KX509URIPortStart, ":"); +_LIT(KX509URIurlPathStart, "/"); + +const TInt KX509URISchemeSpecificStartLength = 2; +const TInt KX509URIUserPasswordEndLength = 1; +const TInt KX509MaxDNSNameLabelLength = 63; + +//superclass: common functionality for DNS names & RFC 822 email addresses +EXPORT_C CX509DomainName::~CX509DomainName() + { + REP_FINAL; + delete iName; + } + +CX509DomainName::CX509DomainName() + { + } + +EXPORT_C TPtrC CX509DomainName::Name() const + { + return *iName; + } + +EXPORT_C TBool CX509DomainName::IsWithinSubtree(const CX509DomainName& aName) const + { + TInt myCount = REP_COUNT; + TInt otherCount = aName.REP_COUNT; + if (otherCount > myCount) + { + return EFalse; + } + for (TInt i = otherCount-1; i >= 0; i--) + { + myCount--; + if ( KErrNotFound == REP_AT(myCount).MatchF(aName.REP_AT(i)) ) + { + return EFalse; + } + } + return ETrue; + } + +TBool CX509DomainName::AddDomainL(TInt& aPos) + { + TInt end = iName->Length(); + FOREVER + { + if (!(AddSubdomainL(aPos))) + { + return EFalse; + } + if (aPos == end) + { + break; + } + AddSubdomainSeparatorL(aPos); + } + return ETrue; + } + +TBool CX509DomainName::AddSubdomainL(TInt& aPos) + { + TBool res = EFalse; + TInt end = iName->Length(); + if (aPos >= end) + { + return res; + } + TPtrC whatsLeft(&(iName->operator[] (aPos)), end - aPos); + TInt subdomainEnd = whatsLeft.FindF(KX509SubdomainSeparator); + if (subdomainEnd == 0) + { + return res; + } + if (subdomainEnd == KErrNotFound) + { + subdomainEnd = end - aPos; + } + TPtrC subdomain(&whatsLeft[0], subdomainEnd); + if (IsValidString(subdomain)) + { + REP_APPEND_L(subdomain); + res = ETrue; + } + aPos = aPos + subdomainEnd; + return res; + } + +TBool CX509DomainName::AddSubdomainSeparatorL(TInt& aPos) + { + TBool res = EFalse; + TInt end = iName->Length(); + if (end <= aPos) + { + return res; + } + TPtrC whatsLeft(&(iName->operator[] (aPos)), end - aPos); + TInt separatorEnd = whatsLeft.FindF(KX509SubdomainSeparator); + if (separatorEnd == 0) + { + TPtrC separator(&whatsLeft[0], 1); + REP_APPEND_L(separator); + aPos++; + res = ETrue; + } + return res; + } + +TBool CX509DomainName::IsValidString(const TDesC& aStr) const + { + TInt pos=0; + TInt end=aStr.Length()-1; + if (end < 0) + { + return ETrue; + } + while (pos= 97) && (aChar <= 122)) || + ((aChar >= 65) && (aChar <= 90)) ); + } + +TBool CX509DomainName::IsAlphaOrNum(const TChar& aChar) const + { + return ((IsAlpha(aChar)) || + ((aChar >= 48) && (aChar <= 57)) || (aChar == 42)); + } + +TBool CX509DomainName::IsValidChar(const TChar& aChar) const + { + //default implementation: must be letter, number or hyphen + return ((IsAlphaOrNum(aChar)) || + (aChar == 45) || (aChar == 42)); + } + +//RFC 822 email address +//subtree +EXPORT_C CX509RFC822NameSubtree* CX509RFC822NameSubtree::NewL(const TDesC8& aBinaryData) + { + CX509RFC822NameSubtree* self = CX509RFC822NameSubtree::NewLC(aBinaryData); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509RFC822NameSubtree* CX509RFC822NameSubtree::NewLC(const TDesC8& aBinaryData) + { + CX509RFC822NameSubtree* self = new(ELeave) CX509RFC822NameSubtree; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +void CX509RFC822NameSubtree::ConstructL(const TDesC8& aBinaryData) + { + TInt pos = 0; + TASN1DecIA5String encStr; + iName = encStr.DecodeDERL(aBinaryData, pos); + REP_INIT_L; + //now, parse your data + pos = 0; + AddLocalHostL(pos); + AddSubdomainSeparatorL(pos); + if (!(AddDomainL(pos))) + { + User::Leave(KErrArgument); + } + } + +TBool CX509RFC822NameSubtree::AddLocalHostL(TInt& aPos) + { + TInt localHostLength = iName->FindF(KX509RFC822HostDomainSeparator); + if ((localHostLength != KErrNotFound) && (localHostLength > 0)) + { + TPtrC localHost(&(iName->operator[] (aPos)), localHostLength); + //the local host name is not checked here as it caused defect PDEF108960 + //and for compatability with IE and Firefox. + REP_APPEND_L(localHost); + aPos = aPos + localHostLength; + aPos++; //skip the @ symbol + return ETrue; + } + return EFalse; //local host not found + } + + +EXPORT_C const REP_VAL_TYPE& CX509RFC822NameSubtree::Rep() const + { + return REP_VAL; + } + +TBool CX509RFC822NameSubtree::IsValidChar(const TChar& aChar) const + { + //we permit "." here, 'cos it's allowed in local host names + //and must have been stripped out by domain parsing code, + //since it's the separator char + return ( (aChar == 33) || + ((aChar >= 35) && (aChar <= 40)) || + (aChar == 42) || + (aChar == 43) || + ((aChar >= 45) && (aChar <= 57)) || + (aChar == 61) || + (aChar == 63) || + ((aChar >= 65) && (aChar <= 90)) || + ((aChar >= 94) && (aChar <= 126)) ); + } + +//full rfc 822 name: exactly as subtree, but requires local host and full domain name +EXPORT_C CX509RFC822Name* CX509RFC822Name::NewL(const TDesC8& aBinaryData) + { + CX509RFC822Name* self = CX509RFC822Name::NewLC(aBinaryData); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509RFC822Name* CX509RFC822Name::NewLC(const TDesC8& aBinaryData) + { + CX509RFC822Name* self = new(ELeave) CX509RFC822Name; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +void CX509RFC822Name::ConstructL(const TDesC8& aBinaryData) + { + TInt pos = 0; + TASN1DecIA5String encStr; + iName = encStr.DecodeDERL(aBinaryData, pos); + REP_INIT_L; + //now, parse your data + pos = 0; + if (! ((AddLocalHostL(pos)) && (AddDomainL(pos))) ) + { + User::Leave(KErrArgument); + } + } + +//DNS Name subtree +EXPORT_C CX509DNSNameSubtree* CX509DNSNameSubtree::NewL(const TDesC8& aBinaryData) + { + CX509DNSNameSubtree* self = CX509DNSNameSubtree::NewLC(aBinaryData); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509DNSNameSubtree* CX509DNSNameSubtree::NewLC(const TDesC8& aBinaryData) + { + CX509DNSNameSubtree* self = new(ELeave) CX509DNSNameSubtree; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +void CX509DNSNameSubtree::ConstructL(const TDesC8& aBinaryData) + { + TInt pos = 0; + TASN1DecIA5String encStr; + iName = encStr.DecodeDERL(aBinaryData, pos); + REP_INIT_L; + pos = 0; + AddSubdomainSeparatorL(pos);//a subtree may start with a period + if (!(AddDomainL(pos))) + { + User::Leave(KErrArgument); + } + } + +EXPORT_C const REP_VAL_TYPE& CX509DNSNameSubtree::Rep() const + { + return REP_VAL; + } + +TBool CX509DNSNameSubtree::IsValidString(const TDesC& aStr) const + { + //must be <= 63 chars long + //must start with letter, end with letter or number + TInt len = aStr.Length(); + return ( (len <= KX509MaxDNSNameLabelLength) && + (IsAlphaOrNum(aStr[0])) && + (IsAlphaOrNum(aStr[len-1])) && + (CX509DomainName::IsValidString(aStr)) ); + } + +//dns name: exactly as subtree but requires full domain name +EXPORT_C CX509DNSName* CX509DNSName::NewL(const TDesC8& aBinaryData) + { + CX509DNSName* self = CX509DNSName::NewLC(aBinaryData); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509DNSName* CX509DNSName::NewLC(const TDesC8& aBinaryData) + { + CX509DNSName* self = new(ELeave) CX509DNSName; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +EXPORT_C CX509DNSName* CX509DNSName::NewL(const CX509DNSName& aName) + { + CX509DNSName* self = CX509DNSName::NewLC(aName); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509DNSName* CX509DNSName::NewLC(const CX509DNSName& aName) + { + CX509DNSName* self = new(ELeave) CX509DNSName; + CleanupStack::PushL(self); + self->ConstructL(aName); + return self; + } + + +EXPORT_C CX509DNSName* CX509DNSName::NewL(const TDesC& aNameString) + { + CX509DNSName* self = CX509DNSName::NewLC(aNameString); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509DNSName* CX509DNSName::NewLC(const TDesC& aNameString) + { + CX509DNSName* self = new(ELeave) CX509DNSName; + CleanupStack::PushL(self); + self->ConstructL(aNameString); + return self; + } + +void CX509DNSName::ConstructL(const TDesC& aNameString) + { + TInt pos = 0; + REP_INIT_L; + iName = aNameString.AllocL(); + AddSubdomainSeparatorL(pos);//a subtree may start with a period + if (!(AddDomainL(pos))) + { + User::Leave(KErrArgument); + } + } + +void CX509DNSName::ConstructL(const TDesC8& aBinaryData) + { + TInt pos = 0; + TASN1DecIA5String encStr; + iName = encStr.DecodeDERL(aBinaryData, pos); + ParseNameL(); + } + +void CX509DNSName::ConstructL(const CX509DNSName& aName) + { + iName = aName.iName->AllocL(); + ParseNameL(); + } + +void CX509DNSName::ParseNameL() + { + REP_INIT_L; + TInt pos = 0; + if (!AddDomainL(pos)) + { + User::Leave(KErrArgument); + } + } + +//URI: must be of 'ip-based' form (rfc 1738 section 3.1) +//_and_ contain a domain name (not an IP address) +EXPORT_C CX509IPBasedURI* CX509IPBasedURI::NewL(const TDesC8& aBinaryData) + { + CX509IPBasedURI* self = CX509IPBasedURI::NewLC(aBinaryData); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509IPBasedURI* CX509IPBasedURI::NewLC(const TDesC8& aBinaryData) + { + CX509IPBasedURI* self = new(ELeave) CX509IPBasedURI; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +void CX509IPBasedURI::ConstructL(const TDesC8& aBinaryData) + { + TInt pos = 0; + TASN1DecIA5String encStr; + iName = encStr.DecodeDERL(aBinaryData, pos); + iHost = CX509DNSName::NewL(ExtractHostNameL()); + } + +EXPORT_C CX509IPBasedURI::~CX509IPBasedURI() + { + delete iName; + delete iHost; + } + +CX509IPBasedURI::CX509IPBasedURI() + :iHost(NULL), iName(NULL) + { + } + +EXPORT_C const CX509DNSName& CX509IPBasedURI::Host() const + { + return *iHost; + } + +EXPORT_C TPtrC CX509IPBasedURI::Name() const + { + return iName->Des(); + } + +TPtrC CX509IPBasedURI::ExtractHostNameL() const + { + TInt hostStart; + TInt hostEnd; + TInt len = iName->Length(); + TInt schemeSpecificStart = (iName->FindF(KX509URISchemeSpecificStart) + KX509URISchemeSpecificStartLength); + TInt userPasswordEnd = (iName->FindF(KX509URIUserPasswordEnd)) + KX509URIUserPasswordEndLength; + hostStart = ((userPasswordEnd == 0)? schemeSpecificStart : userPasswordEnd); + if (hostStart == KErrNotFound) + { + User::Leave(KErrArgument); + } + TPtrC whatsLeft(&(iName->operator[](hostStart)), len - hostStart); + TInt newlen = whatsLeft.Length(); + TInt portStart = whatsLeft.FindF(KX509URIPortStart); + TInt urlPathStart = whatsLeft.FindF(KX509URIurlPathStart); + if (portStart == KErrNotFound) + { + if (urlPathStart == KErrNotFound) + { + hostEnd = newlen; + } + else + { + hostEnd = urlPathStart; + } + } + else + { + if (urlPathStart == KErrNotFound) + { + hostEnd = portStart; + } + else //both are there, choose the first one + { + hostEnd = ((urlPathStart > portStart)? portStart: urlPathStart); + } + } + TPtrC host(&(iName->operator[](hostStart)), hostEnd); + return host; + } + +//IP Address +//subnet mask +EXPORT_C CX509IPSubnetMask* CX509IPSubnetMask::NewL(const TDesC8& aBinaryData) + { + CX509IPSubnetMask* self = CX509IPSubnetMask::NewLC(aBinaryData); + CleanupStack::Pop();//self; + return self; + } + +EXPORT_C CX509IPSubnetMask* CX509IPSubnetMask::NewLC(const TDesC8& aBinaryData) + { + CX509IPSubnetMask* self = new(ELeave) CX509IPSubnetMask; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +void CX509IPSubnetMask::ConstructL(const TDesC8& aBinaryData) + { + //!!!need to correct this when we have octet strings going!!! + TASN1DecGeneric encAddr(aBinaryData); + encAddr.InitL(); + iName = encAddr.GetContentDER().AllocL();// = CASN1OctetString::DecodeDERL(aBinaryData, pos); + TInt len = iName->Length(); + if (!((len == 8) || (len == 32))) + { + User::Leave(KErrArgument); + } + } + +EXPORT_C CX509IPSubnetMask::~CX509IPSubnetMask() + { + delete iName; + } + +EXPORT_C TPtrC8 CX509IPSubnetMask::BaseAddress() const + { + TInt half = iName->Length()/2; + TPtrC8 ptr(&(iName->operator [] (0)), half); + return ptr; + } + +EXPORT_C TPtrC8 CX509IPSubnetMask::Mask() const + { + TInt half = iName->Length()/2; + TPtrC8 ptr(&(iName->operator [] (half)), half); + return ptr; + } + +CX509IPSubnetMask::CX509IPSubnetMask() + :iName(NULL) + { + } + +//ip address +EXPORT_C CX509IPAddress* CX509IPAddress::NewL(const TDesC8& aBinaryData) + { + CX509IPAddress* self = CX509IPAddress::NewLC(aBinaryData); + CleanupStack::Pop();//self + return self; + } + +EXPORT_C CX509IPAddress* CX509IPAddress::NewLC(const TDesC8& aBinaryData) + { + CX509IPAddress* self = new(ELeave) CX509IPAddress; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData); + return self; + } + +void CX509IPAddress::ConstructL(const TDesC8& aBinaryData) + { + TASN1DecGeneric encAddr(aBinaryData); + encAddr.InitL(); + iName = encAddr.GetContentDER().AllocL(); + TInt len = iName->Length(); + if (!(len == 4 || len == 16)) + { + User::Leave(KErrArgument); + } + } + +EXPORT_C CX509IPAddress::~CX509IPAddress() + { + delete iName; + } + +EXPORT_C TBool CX509IPAddress::IsWithinSubtree(const CX509IPSubnetMask& aName) const + { + TInt addrLen = iName->Length(); + if (((aName.iName->Length())/2) != addrLen) + { + return EFalse; + } + for (TInt i = 0; i < addrLen; i++) + { + //stop stupid compiler warning + TUint8 masked = (TUint8) ((iName->operator [] (i)) & (aName.iName->operator [] (i + addrLen))); + if (masked != (aName.iName->operator [] (i))) + { + return EFalse; + } + } + return ETrue; + } + +EXPORT_C TPtrC8 CX509IPAddress::Address() const + { + return iName->Des(); + } + +CX509IPAddress::CX509IPAddress() + :iName(NULL) + { + } + +//*******************X.509 General Name**********************// +EXPORT_C CX509GeneralName* CX509GeneralName::NewL(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509GeneralName::NewL(aBinaryData, pos); + } + +EXPORT_C CX509GeneralName* CX509GeneralName::NewLC(const TDesC8& aBinaryData) + { + TInt pos = 0; + return CX509GeneralName::NewLC(aBinaryData, pos); + } + +EXPORT_C CX509GeneralName* CX509GeneralName::NewL(const TDesC8& aBinaryData, TInt& aPos) + { + CX509GeneralName* self = CX509GeneralName::NewLC(aBinaryData, aPos); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509GeneralName* CX509GeneralName::NewLC(const TDesC8& aBinaryData, TInt& aPos) + { + CX509GeneralName* self = new(ELeave) CX509GeneralName; + CleanupStack::PushL(self); + self->ConstructL(aBinaryData, aPos); + return self; + } + +EXPORT_C CX509GeneralName* CX509GeneralName::NewL(const CX509GeneralName& aName) + { + CX509GeneralName* self = CX509GeneralName::NewLC(aName); + CleanupStack::Pop(); + return self; + } + +EXPORT_C CX509GeneralName* CX509GeneralName::NewLC(const CX509GeneralName& aName) + { + CX509GeneralName* self = new(ELeave) CX509GeneralName(aName.iTag); + CleanupStack::PushL(self); + self->ConstructL(aName.iData->Des()); + return self; + } + +void CX509GeneralName::ConstructL(const TDesC8& aBinaryData, TInt& aPos) + { + TASN1DecGeneric gen(aBinaryData.Right(aBinaryData.Length() - aPos)); + gen.InitL(); + aPos += gen.LengthDER();//add on header info + if (gen.Class() != EContextSpecific) + { + User::Leave(KErrArgument); + } + iData = gen.Tag() == 4 ? gen.GetContentDER().AllocL(): gen.Encoding().AllocL(); + iTag = gen.Tag(); + } + +void CX509GeneralName::ConstructL(const TDesC8& aData) + { + iData = aData.AllocL(); + } + +CX509GeneralName::CX509GeneralName(TGNType aType) + :iTag(aType) + { + } + +CX509GeneralName::CX509GeneralName() + { + } + +EXPORT_C TGNType CX509GeneralName::Tag() const + { + return iTag; + } + +EXPORT_C TPtrC8 CX509GeneralName::Data() const + { + return iData->Des(); + } + +EXPORT_C TBool CX509GeneralName::ExactMatch(const CX509GeneralName& /*aName*/) const + { + return EFalse; + } + +EXPORT_C CX509GeneralName::~CX509GeneralName() + { + delete iData; + }