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 sl@0: #include "X500dec.h" sl@0: #include sl@0: #include sl@0: sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(const CX520AttributeTypeAndValue& aPair) sl@0: { sl@0: CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aPair); sl@0: CleanupStack::Pop();//self sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(const CX520AttributeTypeAndValue& aPair) sl@0: { sl@0: CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aPair); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(const TDesC8& aBinaryData) sl@0: { sl@0: TInt pos = 0; sl@0: return CX520AttributeTypeAndValue::NewL(aBinaryData, pos); sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(const TDesC8& aBinaryData) sl@0: { sl@0: TInt pos = 0; sl@0: return CX520AttributeTypeAndValue::NewLC(aBinaryData, pos); sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(const TDesC8& aBinaryData, TInt& aPos) sl@0: { sl@0: CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aBinaryData, aPos); sl@0: CleanupStack::Pop(); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(const TDesC8& aBinaryData, TInt& aPos) sl@0: { sl@0: CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aBinaryData, aPos); sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(RReadStream& aStream) sl@0: { sl@0: CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aStream); sl@0: CleanupStack::Pop();//self sl@0: return self; sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(RReadStream& aStream) sl@0: { sl@0: CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; sl@0: CleanupStack::PushL(self); sl@0: self->InternalizeL(aStream); sl@0: return self; sl@0: } sl@0: sl@0: /** Allocates and initializes a new attribute-value pair object from sl@0: type and value. sl@0: @param aType Type of the value (see TAttributeType enum). sl@0: @param aValue String value of the attribute. sl@0: @return Pointer to a newly allocated and initialized attribute-value pair. sl@0: @see CX520AttributeTypeAndValue::NewLC */ sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(TAttributeType aType, const TDesC8& aValue) sl@0: { sl@0: CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aType, aValue); sl@0: CleanupStack::Pop(); // self sl@0: return self; sl@0: } sl@0: sl@0: /** Allocates and initializes a new attribute-value pair object from sl@0: type and value. Pushes the newly allocated object onto the sl@0: cleanup stack. sl@0: @param aType Type of the value (see TAttributeType enum). sl@0: @param aValue String value of the attribute. sl@0: @return Pointer to a newly allocated and initialized attribute-value pair. sl@0: @see CX520AttributeTypeAndValue::NewL */ sl@0: EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC( sl@0: TAttributeType aType, sl@0: const TDesC8& aValue) sl@0: { sl@0: CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(aType, aValue); sl@0: return self; sl@0: } sl@0: sl@0: CX520AttributeTypeAndValue::CX520AttributeTypeAndValue() sl@0: :iType(NULL), iValue(NULL) sl@0: { sl@0: } sl@0: sl@0: void CX520AttributeTypeAndValue::ConstructL(const CX520AttributeTypeAndValue& aPair) sl@0: { sl@0: iType = aPair.iType->AllocL(); sl@0: iValue = aPair.iValue->AllocL(); sl@0: } sl@0: sl@0: void CX520AttributeTypeAndValue::ConstructL(const TDesC8& aBinaryData, TInt& aPos) sl@0: { sl@0: TASN1DecGeneric dec(aBinaryData.Right(aBinaryData.Length() - aPos)); sl@0: dec.InitL(); sl@0: TInt end = aPos + dec.LengthDER(); sl@0: aPos += dec.LengthDERHeader(); sl@0: sl@0: //first element must be the id sl@0: TASN1DecObjectIdentifier encOID; sl@0: iType = encOID.DecodeDERL(aBinaryData, aPos); sl@0: //second is the data sl@0: TASN1DecGeneric second(aBinaryData.Right(aBinaryData.Length() - aPos)); sl@0: second.InitL(); sl@0: sl@0: iValue = second.Encoding().AllocL();; sl@0: aPos += second.LengthDER(); sl@0: sl@0: if (aPos != end) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: } sl@0: sl@0: void CX520AttributeTypeAndValue::ConstructL(TAttributeType aType, const TDesC8& aValue) sl@0: { sl@0: // iType is string representation of OID corresponding to the aType. sl@0: TPtrC ptr; sl@0: TInt maxlen = 64; // a reasonable default sl@0: TTagType type = EASN1PrintableString; // the default for all except email, unstructured name and domain component sl@0: switch(aType) sl@0: { sl@0: case ECommonName: sl@0: ptr.Set(KX520CommonName); sl@0: maxlen = KX520MaxCNLength; sl@0: break; sl@0: case ELocalityName: sl@0: ptr.Set(KX520LocalityName); sl@0: maxlen = KX520MaxLLength; sl@0: break; sl@0: case EStateOrProvinceName: sl@0: ptr.Set(KX520StateOrProvinceName); sl@0: maxlen = KX520MaxSOPLength; sl@0: break; sl@0: case EPostalCode: sl@0: ptr.Set(KX520PostalCode); sl@0: maxlen = KX520MaxPostalCodeLength; sl@0: break; sl@0: case EOrganizationName: sl@0: ptr.Set(KX520OrganizationName); sl@0: maxlen = KX520MaxOLength; sl@0: break; sl@0: case EOrganizationalUnitName: sl@0: ptr.Set(KX520OrganizationalUnitName); sl@0: maxlen = KX520MaxOULength; sl@0: break; sl@0: case ETitle: sl@0: ptr.Set(KX520Title); sl@0: maxlen = KX520MaxTLength; sl@0: break; sl@0: case EDNQualifier: sl@0: ptr.Set(KX520DNQualifier); sl@0: maxlen = 64; // no information was found on this one, so set to a safe minimum sl@0: break; sl@0: case ECountryName: sl@0: ptr.Set(KX520CountryName); sl@0: maxlen = KX520MaxCNLength; sl@0: break; sl@0: case EGivenName: sl@0: ptr.Set(KX520GivenName); sl@0: maxlen = KX520MaxGNLength; sl@0: break; sl@0: case ESurname: sl@0: ptr.Set(KX520Surname); sl@0: maxlen = KX520MaxSLength; sl@0: break; sl@0: case EInitials: sl@0: ptr.Set(KX520Initials); sl@0: maxlen = KX520MaxILength; sl@0: break; sl@0: case EGenerationQualifier: sl@0: ptr.Set(KX520GenerationQualifier); sl@0: maxlen = KX520MaxGQLength; sl@0: break; sl@0: case EPKCS9EmailAddress: sl@0: ptr.Set(KPKCS9EmailAddress); sl@0: maxlen = KPKCS9MaxEmailAddressLength; sl@0: type = EASN1IA5String; sl@0: break; sl@0: case ESerialNumber: sl@0: ptr.Set(KX520SerialNumber); sl@0: maxlen = KX520MaxSNLength; sl@0: break; sl@0: case ERFC2247DomainComponent: sl@0: ptr.Set(KRFC2247DomainComponent); sl@0: maxlen = KRFC2247MaxDomainComponentLength; sl@0: type = EASN1IA5String; sl@0: break; sl@0: case ERFC2256Street: sl@0: ptr.Set(KRFC2256Street); sl@0: maxlen = KRFC2256StreetLength; sl@0: break; sl@0: case EPKCS9UnstructuredName: sl@0: { sl@0: ptr.Set(KPKCS9UnstructuredName); sl@0: maxlen = KPKCS9MaxUnstructuredNameLength; sl@0: // Determine the encoded value. It could be a IA5String or a UTF8String sl@0: TASN1DecGeneric decoderGeneric(aValue); sl@0: decoderGeneric.InitL(); sl@0: type = decoderGeneric.Tag(); sl@0: break; sl@0: } sl@0: case EX520Description: sl@0: { sl@0: ptr.Set(KX520Description); sl@0: maxlen = KX520MaxDescriptionLength; sl@0: break; sl@0: } sl@0: default: sl@0: User::Leave(KErrArgument); sl@0: } sl@0: // Verify if the passed length is within limits sl@0: if(aValue.Length() > maxlen) sl@0: User::Leave(KErrArgument); sl@0: sl@0: // Allocate OID string for iType sl@0: iType = ptr.AllocL(); sl@0: sl@0: // iValue must be stored in ASN.1-encoded form sl@0: CASN1EncOctetString* enc = CASN1EncOctetString::NewLC(aValue); sl@0: enc->SetTag(type, EUniversal); sl@0: TUint len = enc->LengthDER(); sl@0: HBufC8* buf = HBufC8::NewMaxLC(len); sl@0: TUint pos = 0; sl@0: TPtr8 bufptr(buf->Des()); sl@0: enc->WriteDERL(bufptr, pos); sl@0: iValue = bufptr.AllocL(); sl@0: CleanupStack::PopAndDestroy(2); sl@0: } sl@0: sl@0: EXPORT_C const TPtrC CX520AttributeTypeAndValue::Type() const sl@0: { sl@0: return iType->Des(); sl@0: } sl@0: sl@0: EXPORT_C const TPtrC8 CX520AttributeTypeAndValue::EncodedValue() const sl@0: { sl@0: return iValue->Des(); sl@0: } sl@0: sl@0: EXPORT_C HBufC* CX520AttributeTypeAndValue::ValueL() const sl@0: { sl@0: if (iType->Des() == KX520CountryName) sl@0: { sl@0: TASN1DecPrintableString encPString; sl@0: TInt pos = 0; sl@0: HBufC* res = encPString.DecodeDERL(iValue->Des(), pos); sl@0: CleanupStack::PushL(res); sl@0: if (res->Length() > KX520MaxCLength) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CleanupStack::Pop(); sl@0: return res; sl@0: } sl@0: if (iType->Des() == KX520DNQualifier) sl@0: { sl@0: TInt pos = 0; sl@0: TASN1DecPrintableString encPString; sl@0: HBufC* res = encPString.DecodeDERL(iValue->Des(), pos); sl@0: return res; sl@0: } sl@0: if (iType->Des() == KPKCS9EmailAddress) sl@0: { sl@0: TASN1DecIA5String encIA5String; sl@0: TInt pos = 0; sl@0: HBufC* res = encIA5String.DecodeDERL(iValue->Des(), pos); sl@0: CleanupStack::PushL(res); sl@0: if (res->Length() > KPKCS9MaxEmailAddressLength) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CleanupStack::Pop(); sl@0: return res; sl@0: } sl@0: if (iType->Des() == KRFC2247DomainComponent) sl@0: { sl@0: TASN1DecIA5String encIA5String; sl@0: TInt pos = 0; sl@0: HBufC* res = encIA5String.DecodeDERL(iValue->Des(), pos); sl@0: CleanupStack::PushL(res); sl@0: if (res->Length() > KRFC2247MaxDomainComponentLength) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CleanupStack::Pop(); sl@0: return res; sl@0: } sl@0: if (iType->Des() == KX520SerialNumber) sl@0: { sl@0: TASN1DecPrintableString encPString; sl@0: TInt pos = 0; sl@0: HBufC* res = encPString.DecodeDERL(iValue->Des(), pos); sl@0: CleanupStack::PushL(res); sl@0: if (res->Length() > KX520MaxSNLength) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CleanupStack::Pop(); sl@0: return res; sl@0: } sl@0: TInt maxLength = 0; sl@0: if (iType->Des() == KPKCS9UnstructuredName) sl@0: { sl@0: TASN1DecGeneric decoderGeneric(iValue->Des()); sl@0: decoderGeneric.InitL(); sl@0: // The encoded value should be a IA5String sl@0: if (decoderGeneric.Tag() == EASN1IA5String) sl@0: { sl@0: TASN1DecIA5String encIA5String; sl@0: TInt pos = 0; sl@0: HBufC* res = encIA5String.DecodeDERL(iValue->Des(), pos); sl@0: CleanupStack::PushL(res); sl@0: if (res->Length() > KPKCS9MaxUnstructuredNameLength) sl@0: { sl@0: User::Leave(KErrArgument); sl@0: } sl@0: CleanupStack::Pop(); sl@0: return res; sl@0: } sl@0: // But it could also be a UTF8String to support internationalization issues sl@0: else sl@0: { sl@0: maxLength = KPKCS9MaxUnstructuredNameLength; sl@0: } sl@0: } sl@0: if (iType->Des() == KX520OrganizationName) sl@0: { sl@0: maxLength = KX520MaxOLength; sl@0: } sl@0: if (iType->Des() == KX520OrganizationalUnitName) sl@0: { sl@0: maxLength = KX520MaxOULength; sl@0: } sl@0: if (iType->Des() == KX520LocalityName) sl@0: { sl@0: maxLength = KX520MaxLLength; sl@0: } sl@0: if (iType->Des() == KX520StateOrProvinceName) sl@0: { sl@0: maxLength = KX520MaxSOPLength; sl@0: } sl@0: if (iType->Des() == KX520Title) sl@0: { sl@0: maxLength = KX520MaxTLength; sl@0: } sl@0: if (iType->Des() == KX520CommonName) sl@0: { sl@0: maxLength = KX520MaxCNLength; sl@0: } sl@0: if (iType->Des() == KX520Surname) sl@0: { sl@0: maxLength = KX520MaxSLength; sl@0: } sl@0: if (iType->Des() == KX520GivenName) sl@0: { sl@0: maxLength = KX520MaxGNLength; sl@0: } sl@0: if (iType->Des() == KX520Initials) sl@0: { sl@0: maxLength = KX520MaxILength; sl@0: } sl@0: if (iType->Des() == KX520GenerationQualifier) sl@0: { sl@0: maxLength = KX520MaxGQLength; sl@0: } sl@0: if (iType->Des() == KX520PostalCode) sl@0: { sl@0: maxLength = KX520MaxPostalCodeLength; sl@0: } sl@0: if (iType->Des() == KRFC2256Street) sl@0: { sl@0: maxLength = KRFC2256StreetLength; sl@0: } sl@0: if (iType->Des() == KX520Description) sl@0: { sl@0: maxLength = KX520MaxDescriptionLength; sl@0: } sl@0: if (maxLength == 0) sl@0: { sl@0: User::Leave(KErrNotSupported); sl@0: } sl@0: TASN1DecX500DirectoryString encDString; sl@0: TInt pos = 0; sl@0: HBufC* res = encDString.DecodeDERL(iValue->Des(), pos, maxLength); sl@0: return res; sl@0: } sl@0: sl@0: TBool CX520AttributeTypeAndValue::IsCaseInSensitiveL(const TDesC8& aSource) const sl@0: { sl@0: TPtr attribute = iType->Des(); sl@0: TBool caseInsensitiveAttr = (attribute == KPKCS9EmailAddress || attribute == KPKCS9UnstructuredName || attribute == KX520Description); sl@0: TASN1DecGeneric gen(aSource); sl@0: gen.InitL(); sl@0: return ((gen.Tag() == EASN1PrintableString) || caseInsensitiveAttr); sl@0: } sl@0: sl@0: sl@0: EXPORT_C CASN1EncSequence* CX520AttributeTypeAndValue::EncodeASN1LC() const sl@0: { sl@0: CASN1EncSequence *seq = CASN1EncSequence::NewLC(); sl@0: CASN1EncObjectIdentifier* oid = CASN1EncObjectIdentifier::NewLC(Type()); sl@0: seq->AddAndPopChildL(oid); sl@0: sl@0: // The current ASN.1 base encoding class assumes that ASN.1 type, sl@0: // length, and contents are stored and can be written to a buffer sl@0: // separately. Therefore it is difficult, if not impossible, to sl@0: // store raw ASN.1 encoding data in a tree of ASN.1 encoding sl@0: // objects. That is why we are forced first to decode the raw value, sl@0: // and then re-encode it so that we know what type and length it sl@0: // has. sl@0: TASN1DecGeneric decoderGeneric(EncodedValue()); sl@0: decoderGeneric.InitL(); sl@0: TASN1DecOctetString decoderOctetString; sl@0: HBufC8* valBuf = decoderOctetString.DecodeDERL(decoderGeneric); sl@0: CleanupStack::PushL(valBuf); sl@0: CASN1EncOctetString* val = CASN1EncOctetString::NewLC(*valBuf); sl@0: val->SetTag(decoderGeneric.Tag(), decoderGeneric.Class()); sl@0: seq->AddAndPopChildL(val); sl@0: CleanupStack::PopAndDestroy(valBuf); sl@0: return seq; sl@0: } sl@0: sl@0: EXPORT_C CASN1EncSequence* CX520AttributeTypeAndValue::EncodeASN1L() const sl@0: { sl@0: CASN1EncSequence *seq = EncodeASN1LC(); sl@0: CleanupStack::Pop(seq); sl@0: return seq; sl@0: } sl@0: sl@0: EXPORT_C CX520AttributeTypeAndValue::~CX520AttributeTypeAndValue() sl@0: { sl@0: delete iType; sl@0: delete iValue; sl@0: } sl@0: sl@0: EXPORT_C TBool CX520AttributeTypeAndValue::ExactMatchL(const CX520AttributeTypeAndValue& aElement) const sl@0: { sl@0: TBool res = EFalse; sl@0: if (*(iType) != *(aElement.iType)) sl@0: { sl@0: return res; sl@0: } sl@0: HBufC* lhs = this->ValueL(); sl@0: CleanupStack::PushL(lhs); sl@0: HBufC* rhs = aElement.ValueL(); sl@0: sl@0: TPtr plhs = lhs->Des(); sl@0: TPtr prhs = rhs->Des(); sl@0: plhs.TrimAll(); sl@0: prhs.TrimAll(); sl@0: sl@0: sl@0: // DEF124902: Certificate name matching done in accordance to RFC3280 sl@0: // RFC3280: Printable String and Email address(of value type 'IA5String') will sl@0: // be compared case-insensitively. sl@0: sl@0: if (IsCaseInSensitiveL(iValue->Des())) sl@0: { sl@0: //case insensitive comparison for Printable String and IA5String (EmailAdress only). sl@0: res = (plhs.CompareF(prhs) == 0); sl@0: } sl@0: else sl@0: { sl@0: // case-sensitive comparison for strings other than printable string sl@0: // Exception: This may include IA5Stings other than 'EmailAddress' attiribute types. sl@0: res = (plhs.Compare(prhs) == 0); sl@0: } sl@0: CleanupStack::PopAndDestroy(); sl@0: delete rhs; sl@0: return res; sl@0: } sl@0: sl@0: void CX520AttributeTypeAndValue::ExternalizeL(RWriteStream& aStream) const sl@0: { sl@0: aStream.WriteInt32L(iType->Des().Length()); sl@0: aStream << *iType; sl@0: aStream.WriteInt32L(iValue->Des().Length()); sl@0: aStream << *iValue; sl@0: } sl@0: sl@0: void CX520AttributeTypeAndValue::InternalizeL(RReadStream& aStream) sl@0: { sl@0: TInt maxlen; sl@0: maxlen = aStream.ReadInt32L(); sl@0: iType = HBufC::NewL(aStream,maxlen); sl@0: maxlen = aStream.ReadInt32L(); sl@0: iValue = HBufC8::NewL(aStream,maxlen); sl@0: }