|
1 /* |
|
2 * Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <x520ava.h> |
|
20 #include "X500dec.h" |
|
21 #include <asn1enc.h> |
|
22 #include <asn1dec.h> |
|
23 |
|
24 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(const CX520AttributeTypeAndValue& aPair) |
|
25 { |
|
26 CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aPair); |
|
27 CleanupStack::Pop();//self |
|
28 return self; |
|
29 } |
|
30 |
|
31 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(const CX520AttributeTypeAndValue& aPair) |
|
32 { |
|
33 CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; |
|
34 CleanupStack::PushL(self); |
|
35 self->ConstructL(aPair); |
|
36 return self; |
|
37 } |
|
38 |
|
39 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(const TDesC8& aBinaryData) |
|
40 { |
|
41 TInt pos = 0; |
|
42 return CX520AttributeTypeAndValue::NewL(aBinaryData, pos); |
|
43 } |
|
44 |
|
45 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(const TDesC8& aBinaryData) |
|
46 { |
|
47 TInt pos = 0; |
|
48 return CX520AttributeTypeAndValue::NewLC(aBinaryData, pos); |
|
49 } |
|
50 |
|
51 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(const TDesC8& aBinaryData, TInt& aPos) |
|
52 { |
|
53 CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aBinaryData, aPos); |
|
54 CleanupStack::Pop(); |
|
55 return self; |
|
56 } |
|
57 |
|
58 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(const TDesC8& aBinaryData, TInt& aPos) |
|
59 { |
|
60 CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; |
|
61 CleanupStack::PushL(self); |
|
62 self->ConstructL(aBinaryData, aPos); |
|
63 return self; |
|
64 } |
|
65 |
|
66 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(RReadStream& aStream) |
|
67 { |
|
68 CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aStream); |
|
69 CleanupStack::Pop();//self |
|
70 return self; |
|
71 } |
|
72 |
|
73 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC(RReadStream& aStream) |
|
74 { |
|
75 CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; |
|
76 CleanupStack::PushL(self); |
|
77 self->InternalizeL(aStream); |
|
78 return self; |
|
79 } |
|
80 |
|
81 /** Allocates and initializes a new attribute-value pair object from |
|
82 type and value. |
|
83 @param aType Type of the value (see TAttributeType enum). |
|
84 @param aValue String value of the attribute. |
|
85 @return Pointer to a newly allocated and initialized attribute-value pair. |
|
86 @see CX520AttributeTypeAndValue::NewLC */ |
|
87 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewL(TAttributeType aType, const TDesC8& aValue) |
|
88 { |
|
89 CX520AttributeTypeAndValue* self = CX520AttributeTypeAndValue::NewLC(aType, aValue); |
|
90 CleanupStack::Pop(); // self |
|
91 return self; |
|
92 } |
|
93 |
|
94 /** Allocates and initializes a new attribute-value pair object from |
|
95 type and value. Pushes the newly allocated object onto the |
|
96 cleanup stack. |
|
97 @param aType Type of the value (see TAttributeType enum). |
|
98 @param aValue String value of the attribute. |
|
99 @return Pointer to a newly allocated and initialized attribute-value pair. |
|
100 @see CX520AttributeTypeAndValue::NewL */ |
|
101 EXPORT_C CX520AttributeTypeAndValue* CX520AttributeTypeAndValue::NewLC( |
|
102 TAttributeType aType, |
|
103 const TDesC8& aValue) |
|
104 { |
|
105 CX520AttributeTypeAndValue* self = new(ELeave) CX520AttributeTypeAndValue; |
|
106 CleanupStack::PushL(self); |
|
107 self->ConstructL(aType, aValue); |
|
108 return self; |
|
109 } |
|
110 |
|
111 CX520AttributeTypeAndValue::CX520AttributeTypeAndValue() |
|
112 :iType(NULL), iValue(NULL) |
|
113 { |
|
114 } |
|
115 |
|
116 void CX520AttributeTypeAndValue::ConstructL(const CX520AttributeTypeAndValue& aPair) |
|
117 { |
|
118 iType = aPair.iType->AllocL(); |
|
119 iValue = aPair.iValue->AllocL(); |
|
120 } |
|
121 |
|
122 void CX520AttributeTypeAndValue::ConstructL(const TDesC8& aBinaryData, TInt& aPos) |
|
123 { |
|
124 TASN1DecGeneric dec(aBinaryData.Right(aBinaryData.Length() - aPos)); |
|
125 dec.InitL(); |
|
126 TInt end = aPos + dec.LengthDER(); |
|
127 aPos += dec.LengthDERHeader(); |
|
128 |
|
129 //first element must be the id |
|
130 TASN1DecObjectIdentifier encOID; |
|
131 iType = encOID.DecodeDERL(aBinaryData, aPos); |
|
132 //second is the data |
|
133 TASN1DecGeneric second(aBinaryData.Right(aBinaryData.Length() - aPos)); |
|
134 second.InitL(); |
|
135 |
|
136 iValue = second.Encoding().AllocL();; |
|
137 aPos += second.LengthDER(); |
|
138 |
|
139 if (aPos != end) |
|
140 { |
|
141 User::Leave(KErrArgument); |
|
142 } |
|
143 } |
|
144 |
|
145 void CX520AttributeTypeAndValue::ConstructL(TAttributeType aType, const TDesC8& aValue) |
|
146 { |
|
147 // iType is string representation of OID corresponding to the aType. |
|
148 TPtrC ptr; |
|
149 TInt maxlen = 64; // a reasonable default |
|
150 TTagType type = EASN1PrintableString; // the default for all except email, unstructured name and domain component |
|
151 switch(aType) |
|
152 { |
|
153 case ECommonName: |
|
154 ptr.Set(KX520CommonName); |
|
155 maxlen = KX520MaxCNLength; |
|
156 break; |
|
157 case ELocalityName: |
|
158 ptr.Set(KX520LocalityName); |
|
159 maxlen = KX520MaxLLength; |
|
160 break; |
|
161 case EStateOrProvinceName: |
|
162 ptr.Set(KX520StateOrProvinceName); |
|
163 maxlen = KX520MaxSOPLength; |
|
164 break; |
|
165 case EPostalCode: |
|
166 ptr.Set(KX520PostalCode); |
|
167 maxlen = KX520MaxPostalCodeLength; |
|
168 break; |
|
169 case EOrganizationName: |
|
170 ptr.Set(KX520OrganizationName); |
|
171 maxlen = KX520MaxOLength; |
|
172 break; |
|
173 case EOrganizationalUnitName: |
|
174 ptr.Set(KX520OrganizationalUnitName); |
|
175 maxlen = KX520MaxOULength; |
|
176 break; |
|
177 case ETitle: |
|
178 ptr.Set(KX520Title); |
|
179 maxlen = KX520MaxTLength; |
|
180 break; |
|
181 case EDNQualifier: |
|
182 ptr.Set(KX520DNQualifier); |
|
183 maxlen = 64; // no information was found on this one, so set to a safe minimum |
|
184 break; |
|
185 case ECountryName: |
|
186 ptr.Set(KX520CountryName); |
|
187 maxlen = KX520MaxCNLength; |
|
188 break; |
|
189 case EGivenName: |
|
190 ptr.Set(KX520GivenName); |
|
191 maxlen = KX520MaxGNLength; |
|
192 break; |
|
193 case ESurname: |
|
194 ptr.Set(KX520Surname); |
|
195 maxlen = KX520MaxSLength; |
|
196 break; |
|
197 case EInitials: |
|
198 ptr.Set(KX520Initials); |
|
199 maxlen = KX520MaxILength; |
|
200 break; |
|
201 case EGenerationQualifier: |
|
202 ptr.Set(KX520GenerationQualifier); |
|
203 maxlen = KX520MaxGQLength; |
|
204 break; |
|
205 case EPKCS9EmailAddress: |
|
206 ptr.Set(KPKCS9EmailAddress); |
|
207 maxlen = KPKCS9MaxEmailAddressLength; |
|
208 type = EASN1IA5String; |
|
209 break; |
|
210 case ESerialNumber: |
|
211 ptr.Set(KX520SerialNumber); |
|
212 maxlen = KX520MaxSNLength; |
|
213 break; |
|
214 case ERFC2247DomainComponent: |
|
215 ptr.Set(KRFC2247DomainComponent); |
|
216 maxlen = KRFC2247MaxDomainComponentLength; |
|
217 type = EASN1IA5String; |
|
218 break; |
|
219 case ERFC2256Street: |
|
220 ptr.Set(KRFC2256Street); |
|
221 maxlen = KRFC2256StreetLength; |
|
222 break; |
|
223 case EPKCS9UnstructuredName: |
|
224 { |
|
225 ptr.Set(KPKCS9UnstructuredName); |
|
226 maxlen = KPKCS9MaxUnstructuredNameLength; |
|
227 // Determine the encoded value. It could be a IA5String or a UTF8String |
|
228 TASN1DecGeneric decoderGeneric(aValue); |
|
229 decoderGeneric.InitL(); |
|
230 type = decoderGeneric.Tag(); |
|
231 break; |
|
232 } |
|
233 default: |
|
234 User::Leave(KErrArgument); |
|
235 } |
|
236 // Verify if the passed length is within limits |
|
237 if(aValue.Length() > maxlen) |
|
238 User::Leave(KErrArgument); |
|
239 |
|
240 // Allocate OID string for iType |
|
241 iType = ptr.AllocL(); |
|
242 |
|
243 // iValue must be stored in ASN.1-encoded form |
|
244 CASN1EncOctetString* enc = CASN1EncOctetString::NewLC(aValue); |
|
245 enc->SetTag(type, EUniversal); |
|
246 TUint len = enc->LengthDER(); |
|
247 HBufC8* buf = HBufC8::NewMaxLC(len); |
|
248 TUint pos = 0; |
|
249 TPtr8 bufptr(buf->Des()); |
|
250 enc->WriteDERL(bufptr, pos); |
|
251 iValue = bufptr.AllocL(); |
|
252 CleanupStack::PopAndDestroy(2); |
|
253 } |
|
254 |
|
255 EXPORT_C const TPtrC CX520AttributeTypeAndValue::Type() const |
|
256 { |
|
257 return iType->Des(); |
|
258 } |
|
259 |
|
260 EXPORT_C const TPtrC8 CX520AttributeTypeAndValue::EncodedValue() const |
|
261 { |
|
262 return iValue->Des(); |
|
263 } |
|
264 |
|
265 EXPORT_C HBufC* CX520AttributeTypeAndValue::ValueL() const |
|
266 { |
|
267 if (iType->Des() == KX520CountryName) |
|
268 { |
|
269 TASN1DecPrintableString encPString; |
|
270 TInt pos = 0; |
|
271 HBufC* res = encPString.DecodeDERL(iValue->Des(), pos); |
|
272 CleanupStack::PushL(res); |
|
273 if (res->Length() > KX520MaxCLength) |
|
274 { |
|
275 User::Leave(KErrArgument); |
|
276 } |
|
277 CleanupStack::Pop(); |
|
278 return res; |
|
279 } |
|
280 if (iType->Des() == KX520DNQualifier) |
|
281 { |
|
282 TInt pos = 0; |
|
283 TASN1DecPrintableString encPString; |
|
284 HBufC* res = encPString.DecodeDERL(iValue->Des(), pos); |
|
285 return res; |
|
286 } |
|
287 if (iType->Des() == KPKCS9EmailAddress) |
|
288 { |
|
289 TASN1DecIA5String encIA5String; |
|
290 TInt pos = 0; |
|
291 HBufC* res = encIA5String.DecodeDERL(iValue->Des(), pos); |
|
292 CleanupStack::PushL(res); |
|
293 if (res->Length() > KPKCS9MaxEmailAddressLength) |
|
294 { |
|
295 User::Leave(KErrArgument); |
|
296 } |
|
297 CleanupStack::Pop(); |
|
298 return res; |
|
299 } |
|
300 if (iType->Des() == KRFC2247DomainComponent) |
|
301 { |
|
302 TASN1DecIA5String encIA5String; |
|
303 TInt pos = 0; |
|
304 HBufC* res = encIA5String.DecodeDERL(iValue->Des(), pos); |
|
305 CleanupStack::PushL(res); |
|
306 if (res->Length() > KRFC2247MaxDomainComponentLength) |
|
307 { |
|
308 User::Leave(KErrArgument); |
|
309 } |
|
310 CleanupStack::Pop(); |
|
311 return res; |
|
312 } |
|
313 if (iType->Des() == KX520SerialNumber) |
|
314 { |
|
315 TASN1DecPrintableString encPString; |
|
316 TInt pos = 0; |
|
317 HBufC* res = encPString.DecodeDERL(iValue->Des(), pos); |
|
318 CleanupStack::PushL(res); |
|
319 if (res->Length() > KX520MaxSNLength) |
|
320 { |
|
321 User::Leave(KErrArgument); |
|
322 } |
|
323 CleanupStack::Pop(); |
|
324 return res; |
|
325 } |
|
326 TInt maxLength = 0; |
|
327 if (iType->Des() == KPKCS9UnstructuredName) |
|
328 { |
|
329 TASN1DecGeneric decoderGeneric(iValue->Des()); |
|
330 decoderGeneric.InitL(); |
|
331 // The encoded value should be a IA5String |
|
332 if (decoderGeneric.Tag() == EASN1IA5String) |
|
333 { |
|
334 TASN1DecIA5String encIA5String; |
|
335 TInt pos = 0; |
|
336 HBufC* res = encIA5String.DecodeDERL(iValue->Des(), pos); |
|
337 CleanupStack::PushL(res); |
|
338 if (res->Length() > KPKCS9MaxUnstructuredNameLength) |
|
339 { |
|
340 User::Leave(KErrArgument); |
|
341 } |
|
342 CleanupStack::Pop(); |
|
343 return res; |
|
344 } |
|
345 // But it could also be a UTF8String to support internationalization issues |
|
346 else |
|
347 { |
|
348 maxLength = KPKCS9MaxUnstructuredNameLength; |
|
349 } |
|
350 } |
|
351 if (iType->Des() == KX520OrganizationName) |
|
352 { |
|
353 maxLength = KX520MaxOLength; |
|
354 } |
|
355 if (iType->Des() == KX520OrganizationalUnitName) |
|
356 { |
|
357 maxLength = KX520MaxOULength; |
|
358 } |
|
359 if (iType->Des() == KX520LocalityName) |
|
360 { |
|
361 maxLength = KX520MaxLLength; |
|
362 } |
|
363 if (iType->Des() == KX520StateOrProvinceName) |
|
364 { |
|
365 maxLength = KX520MaxSOPLength; |
|
366 } |
|
367 if (iType->Des() == KX520Title) |
|
368 { |
|
369 maxLength = KX520MaxTLength; |
|
370 } |
|
371 if (iType->Des() == KX520CommonName) |
|
372 { |
|
373 maxLength = KX520MaxCNLength; |
|
374 } |
|
375 if (iType->Des() == KX520Surname) |
|
376 { |
|
377 maxLength = KX520MaxSLength; |
|
378 } |
|
379 if (iType->Des() == KX520GivenName) |
|
380 { |
|
381 maxLength = KX520MaxGNLength; |
|
382 } |
|
383 if (iType->Des() == KX520Initials) |
|
384 { |
|
385 maxLength = KX520MaxILength; |
|
386 } |
|
387 if (iType->Des() == KX520GenerationQualifier) |
|
388 { |
|
389 maxLength = KX520MaxGQLength; |
|
390 } |
|
391 if (iType->Des() == KX520PostalCode) |
|
392 { |
|
393 maxLength = KX520MaxPostalCodeLength; |
|
394 } |
|
395 if (iType->Des() == KRFC2256Street) |
|
396 { |
|
397 maxLength = KRFC2256StreetLength; |
|
398 } |
|
399 if (maxLength == 0) |
|
400 { |
|
401 User::Leave(KErrNotSupported); |
|
402 } |
|
403 |
|
404 TASN1DecX500DirectoryString encDString; |
|
405 TInt pos = 0; |
|
406 HBufC* res = encDString.DecodeDERL(iValue->Des(), pos, maxLength); |
|
407 return res; |
|
408 } |
|
409 |
|
410 TBool CX520AttributeTypeAndValue::IsCaseInSensitive(const TDesC8& aSource) const |
|
411 { |
|
412 TPtr attribute = iType->Des(); |
|
413 TBool caseInsensitiveAttr = (attribute == KPKCS9EmailAddress || attribute == KPKCS9UnstructuredName); |
|
414 TASN1DecGeneric gen(aSource); |
|
415 gen.InitL(); |
|
416 return ((gen.Tag() == EASN1PrintableString) || caseInsensitiveAttr); |
|
417 } |
|
418 |
|
419 EXPORT_C CASN1EncSequence* CX520AttributeTypeAndValue::EncodeASN1LC() const |
|
420 { |
|
421 CASN1EncSequence *seq = CASN1EncSequence::NewLC(); |
|
422 CASN1EncObjectIdentifier* oid = CASN1EncObjectIdentifier::NewLC(Type()); |
|
423 seq->AddAndPopChildL(oid); |
|
424 |
|
425 // The current ASN.1 base encoding class assumes that ASN.1 type, |
|
426 // length, and contents are stored and can be written to a buffer |
|
427 // separately. Therefore it is difficult, if not impossible, to |
|
428 // store raw ASN.1 encoding data in a tree of ASN.1 encoding |
|
429 // objects. That is why we are forced first to decode the raw value, |
|
430 // and then re-encode it so that we know what type and length it |
|
431 // has. |
|
432 TASN1DecGeneric decoderGeneric(EncodedValue()); |
|
433 decoderGeneric.InitL(); |
|
434 TASN1DecOctetString decoderOctetString; |
|
435 HBufC8* valBuf = decoderOctetString.DecodeDERL(decoderGeneric); |
|
436 CleanupStack::PushL(valBuf); |
|
437 CASN1EncOctetString* val = CASN1EncOctetString::NewLC(*valBuf); |
|
438 val->SetTag(decoderGeneric.Tag(), decoderGeneric.Class()); |
|
439 seq->AddAndPopChildL(val); |
|
440 CleanupStack::PopAndDestroy(valBuf); |
|
441 return seq; |
|
442 } |
|
443 |
|
444 EXPORT_C CASN1EncSequence* CX520AttributeTypeAndValue::EncodeASN1L() const |
|
445 { |
|
446 CASN1EncSequence *seq = EncodeASN1LC(); |
|
447 CleanupStack::Pop(seq); |
|
448 return seq; |
|
449 } |
|
450 |
|
451 EXPORT_C CX520AttributeTypeAndValue::~CX520AttributeTypeAndValue() |
|
452 { |
|
453 delete iType; |
|
454 delete iValue; |
|
455 } |
|
456 |
|
457 EXPORT_C TBool CX520AttributeTypeAndValue::ExactMatchL(const CX520AttributeTypeAndValue& aElement) const |
|
458 { |
|
459 TBool res = EFalse; |
|
460 if (*(iType) != *(aElement.iType)) |
|
461 { |
|
462 return res; |
|
463 } |
|
464 HBufC* lhs = this->ValueL(); |
|
465 CleanupStack::PushL(lhs); |
|
466 HBufC* rhs = aElement.ValueL(); |
|
467 |
|
468 TPtr plhs = lhs->Des(); |
|
469 TPtr prhs = rhs->Des(); |
|
470 plhs.TrimAll(); |
|
471 prhs.TrimAll(); |
|
472 |
|
473 // PDEF125098: Certificate name matching done in accordance to RFC3280 |
|
474 // RFC3280: Printable String and Email address(of value type 'IA5String') will |
|
475 // be compared case-insensitively. |
|
476 if (IsCaseInSensitive(iValue->Des())) |
|
477 { |
|
478 //case insensitive comparison for Printable String and IA5String (EmailAdress only). |
|
479 res = (plhs.CompareF(prhs) == 0); |
|
480 } |
|
481 else |
|
482 { |
|
483 // case-sensitive comparison for strings other than printable string |
|
484 // Exception: This may include IA5Stings other than 'EmailAddress' attiribute types. |
|
485 res = (plhs.Compare(prhs) == 0); |
|
486 } |
|
487 CleanupStack::PopAndDestroy(); |
|
488 delete rhs; |
|
489 return res; |
|
490 } |
|
491 |
|
492 void CX520AttributeTypeAndValue::ExternalizeL(RWriteStream& aStream) const |
|
493 { |
|
494 aStream.WriteInt32L(iType->Des().Length()); |
|
495 aStream << *iType; |
|
496 aStream.WriteInt32L(iValue->Des().Length()); |
|
497 aStream << *iValue; |
|
498 } |
|
499 |
|
500 void CX520AttributeTypeAndValue::InternalizeL(RReadStream& aStream) |
|
501 { |
|
502 TInt maxlen; |
|
503 maxlen = aStream.ReadInt32L(); |
|
504 iType = HBufC::NewL(aStream,maxlen); |
|
505 maxlen = aStream.ReadInt32L(); |
|
506 iValue = HBufC8::NewL(aStream,maxlen); |
|
507 } |