|
1 /* |
|
2 * Copyright (c) 2002 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 "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: Extracts relevant certificate information to be shown to user. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 #include "X509CertNameParser.h" |
|
21 #include <x509cert.h> //X509Certificate |
|
22 #include <x500dn.h> // CX500DistinguishedName |
|
23 #include <pkixcertchain.h> // OIDS for the extensions |
|
24 #include <escapeutils.h> // for escape decoding |
|
25 |
|
26 // CONSTANTS |
|
27 _LIT (KX509CertParserSpace, " "); |
|
28 |
|
29 // Max length of array in case of PrimaryAndSecondaryNameL. |
|
30 const TInt KX509CNPPrimAndSecondNameLengh( 3 ); |
|
31 |
|
32 // ============================ MEMBER FUNCTIONS =============================== |
|
33 |
|
34 // ----------------------------------------------------------------------------- |
|
35 // X509CertNameParser::PrimaryAndSecondaryNameL |
|
36 // |
|
37 // ----------------------------------------------------------------------------- |
|
38 EXPORT_C TInt X509CertNameParser::PrimaryAndSecondaryNameL( |
|
39 const CX509Certificate& aCertificate, |
|
40 HBufC*& aPrimaryName, |
|
41 HBufC*& aSecondaryName, |
|
42 const TDesC& aLabel) |
|
43 { |
|
44 // Get subjectname |
|
45 const CX500DistinguishedName& dName = aCertificate.SubjectName(); |
|
46 // Get subject alternative name |
|
47 const CX509CertExtension* extension = |
|
48 aCertificate.Extension( KSubjectAltName ); |
|
49 |
|
50 CDesCArrayFlat* nameArray = new( ELeave ) CDesCArrayFlat(3); |
|
51 CleanupStack::PushL( nameArray ); |
|
52 // Append label to array |
|
53 nameArray->AppendL( aLabel ); |
|
54 |
|
55 // Get PrimaryName and SecondaryName to nameArray if they exists. |
|
56 GetNamePartsL( dName, extension, *nameArray, EX509CNPPrimAndSecond ); |
|
57 |
|
58 // Make sure that these are NULL |
|
59 aPrimaryName = NULL; |
|
60 aSecondaryName = NULL; |
|
61 |
|
62 switch ( nameArray->MdcaCount() ) |
|
63 { |
|
64 case 1: //Neither PrimaryName nor SecondaryName found |
|
65 { |
|
66 aPrimaryName = HBufC::NewLC( KNullDesC.iTypeLength ); |
|
67 *aPrimaryName = KNullDesC; |
|
68 aSecondaryName = HBufC::NewLC( KNullDesC.iTypeLength ); |
|
69 *aSecondaryName = KNullDesC; |
|
70 break; |
|
71 } |
|
72 case 2: // Only PrimaryName found |
|
73 { |
|
74 aPrimaryName = HBufC::NewLC(( *nameArray)[1].Length() ); |
|
75 *aPrimaryName = ( *nameArray )[1]; |
|
76 aSecondaryName = HBufC::NewLC( KNullDesC.iTypeLength ); |
|
77 *aSecondaryName = KNullDesC; |
|
78 break; |
|
79 } |
|
80 case 3: // Both found |
|
81 { |
|
82 aPrimaryName = HBufC::NewLC(( *nameArray)[1].Length() ); |
|
83 *aPrimaryName = ( *nameArray )[1]; |
|
84 aSecondaryName = HBufC::NewLC( ( *nameArray )[2].Length() ); |
|
85 *aSecondaryName = ( *nameArray )[2]; |
|
86 break; |
|
87 } |
|
88 default: // Something went wrong. |
|
89 { |
|
90 aPrimaryName = HBufC::NewLC( KNullDesC.iTypeLength ); |
|
91 *aPrimaryName = KNullDesC; |
|
92 aSecondaryName = HBufC::NewLC( KNullDesC.iTypeLength ); |
|
93 *aSecondaryName = KNullDesC; |
|
94 break; |
|
95 } |
|
96 } |
|
97 |
|
98 if ( aSecondaryName ) |
|
99 { |
|
100 CleanupStack::Pop( aSecondaryName ); // aSecondaryName |
|
101 } |
|
102 if ( aPrimaryName ) |
|
103 { |
|
104 CleanupStack::Pop( aPrimaryName ); // aPrimaryName |
|
105 } |
|
106 CleanupStack::PopAndDestroy( nameArray ); // nameArray |
|
107 return KErrNone; |
|
108 } |
|
109 |
|
110 // ----------------------------------------------------------------------------- |
|
111 // X509CertNameParser::SubjectFullNameL |
|
112 // |
|
113 // ----------------------------------------------------------------------------- |
|
114 |
|
115 EXPORT_C TInt X509CertNameParser::SubjectFullNameL( |
|
116 const CX509Certificate& aCertificate, |
|
117 HBufC*& aSubjectName, |
|
118 const TDesC& aLabel ) |
|
119 { |
|
120 // Get subjectname |
|
121 const CX500DistinguishedName& dName = aCertificate.SubjectName(); |
|
122 // Get subject alternative name |
|
123 const CX509CertExtension* extension = |
|
124 aCertificate.Extension( KSubjectAltName ); |
|
125 |
|
126 return GetFullNameL( dName, extension, aSubjectName, aLabel ); |
|
127 } |
|
128 |
|
129 // ----------------------------------------------------------------------------- |
|
130 // X509CertNameParser::IssuerFullNameL |
|
131 // |
|
132 // ----------------------------------------------------------------------------- |
|
133 |
|
134 EXPORT_C TInt X509CertNameParser::IssuerFullNameL( |
|
135 const CX509Certificate& aCertificate, |
|
136 HBufC*& aIssuerName ) |
|
137 { |
|
138 // Get issuerName |
|
139 const CX500DistinguishedName& dName = aCertificate.IssuerName(); |
|
140 // Get issuer alternative name |
|
141 const CX509CertExtension* extension = |
|
142 aCertificate.Extension( KIssuerAltName ); |
|
143 |
|
144 return GetFullNameL( dName, extension, aIssuerName ); |
|
145 } |
|
146 |
|
147 // ----------------------------------------------------------------------------- |
|
148 // X509CertNameParser::GetFullNameL |
|
149 // |
|
150 // ----------------------------------------------------------------------------- |
|
151 TInt X509CertNameParser::GetFullNameL( |
|
152 const CX500DistinguishedName& aDN, |
|
153 const CX509CertExtension* aExtension, |
|
154 HBufC*& aName, |
|
155 const TDesC& aLabel ) |
|
156 { |
|
157 CDesCArrayFlat* nameArray = new( ELeave ) CDesCArrayFlat(3); |
|
158 CleanupStack::PushL( nameArray ); |
|
159 // Add label to array. It is used for comparing. |
|
160 nameArray->AppendL( aLabel ); |
|
161 |
|
162 // Collect name parts to array |
|
163 GetNamePartsL( aDN, aExtension, *nameArray, EX509CNPFullName); |
|
164 |
|
165 // Count length of the aName. |
|
166 TInt length = 0; |
|
167 TInt i = 1; // Pass label |
|
168 for ( ; i < nameArray->MdcaCount(); i++ ) |
|
169 { |
|
170 length += (*nameArray)[i].Length(); |
|
171 length += KX509CNPComma.iTypeLength; |
|
172 } |
|
173 |
|
174 // Add elements of the array to aName. |
|
175 // First element is label, so it is passed. |
|
176 aName = HBufC::NewLC( length ); |
|
177 for ( i = 1; i < nameArray->MdcaCount(); i++ ) |
|
178 { |
|
179 if ( i != 1 ) |
|
180 { |
|
181 aName->Des().Append( KX509CNPComma ); |
|
182 } |
|
183 aName->Des().Append( (*nameArray)[i] ); |
|
184 } |
|
185 |
|
186 CleanupStack::Pop( aName ); |
|
187 CleanupStack::PopAndDestroy( nameArray ); |
|
188 |
|
189 return KErrNone; |
|
190 } |
|
191 |
|
192 // ----------------------------------------------------------------------------- |
|
193 // X509CertNameParser::GetNamePartsL |
|
194 // |
|
195 // ----------------------------------------------------------------------------- |
|
196 |
|
197 TInt X509CertNameParser::GetNamePartsL( |
|
198 const CX500DistinguishedName& aDN, |
|
199 const CX509CertExtension* aExtension, |
|
200 CDesCArray& aNameArray, |
|
201 TX509CNPNameType aNameType) |
|
202 { |
|
203 const CX509AltNameExt* altNameExt = NULL; |
|
204 |
|
205 if (aExtension) |
|
206 { |
|
207 altNameExt = CX509AltNameExt::NewLC( aExtension->Data() ); |
|
208 } |
|
209 |
|
210 TBool notFound = ETrue; |
|
211 |
|
212 // In case of PrimaryAndSecondaryName loop goes through name elements |
|
213 // until two of them is found. |
|
214 // In case of FullNames loop goes through all supported name element and |
|
215 // adds founded names to array. |
|
216 for( TInt round = 1; notFound; round++ ) |
|
217 { |
|
218 switch( round ) |
|
219 { |
|
220 case EDNCommonName: |
|
221 { |
|
222 GetDNPartL( aDN, KX520CommonName, aNameArray ); |
|
223 break; |
|
224 } |
|
225 case ECritAltRFC822Name: |
|
226 { |
|
227 if (aExtension && aExtension->Critical()) |
|
228 { |
|
229 GetAltNamePartL( *altNameExt, EX509RFC822Name, aNameArray ); |
|
230 } |
|
231 break; |
|
232 } |
|
233 case EDNOrganizationName: |
|
234 { |
|
235 GetDNPartL( aDN, KX520OrganizationName, aNameArray); |
|
236 break; |
|
237 } |
|
238 case EDNOrganizationalUnitName: |
|
239 { |
|
240 if ( aNameType == EX509CNPPrimAndSecond ) |
|
241 { |
|
242 GetDNPartL( aDN, KX520OrganizationalUnitName, aNameArray); |
|
243 } |
|
244 else |
|
245 { |
|
246 GetDNPartAllL( aDN, KX520OrganizationalUnitName, aNameArray); |
|
247 } |
|
248 break; |
|
249 } |
|
250 case ECritAltURI: |
|
251 { |
|
252 if (aExtension && aExtension->Critical()) |
|
253 { |
|
254 GetAltNamePartL( *altNameExt, EX509URI, aNameArray ); |
|
255 } |
|
256 break; |
|
257 } |
|
258 case ECritAltDNSName: |
|
259 { |
|
260 if (aExtension && aExtension->Critical()) |
|
261 { |
|
262 GetAltNamePartL( *altNameExt, EX509DNSName, aNameArray); |
|
263 } |
|
264 break; |
|
265 } |
|
266 case ECritAltDirectoryName: |
|
267 { |
|
268 if (aExtension && aExtension->Critical()) |
|
269 { |
|
270 GetAltNamePartL( *altNameExt, EX509DirectoryName, |
|
271 aNameArray ); |
|
272 } |
|
273 break; |
|
274 } |
|
275 case ECritAltIPAddress: |
|
276 { |
|
277 if (aExtension && aExtension->Critical()) |
|
278 { |
|
279 GetAltNamePartL( *altNameExt, EX509IPAddress, |
|
280 aNameArray ); |
|
281 } |
|
282 break; |
|
283 } |
|
284 case EAltRFC822Name: |
|
285 { |
|
286 if (aExtension) |
|
287 { |
|
288 GetAltNamePartL( *altNameExt, EX509RFC822Name, |
|
289 aNameArray ); |
|
290 } |
|
291 break; |
|
292 } |
|
293 case EAltURI: |
|
294 { |
|
295 if ( aExtension ) |
|
296 { |
|
297 GetAltNamePartL( *altNameExt, EX509URI, aNameArray ); |
|
298 } |
|
299 break; |
|
300 } |
|
301 case EAltDNSName: |
|
302 { |
|
303 if ( aExtension ) |
|
304 { |
|
305 GetAltNamePartL( *altNameExt, EX509DNSName, aNameArray ); |
|
306 } |
|
307 break; |
|
308 } |
|
309 case EDNCountryName: |
|
310 { |
|
311 GetDNPartL( aDN, KX520CountryName, aNameArray ); |
|
312 break; |
|
313 } |
|
314 case EDNStateOrProvinceName: |
|
315 { |
|
316 GetDNPartL( aDN, KX520StateOrProvinceName, aNameArray ); |
|
317 break; |
|
318 } |
|
319 case EDNLocalityName: |
|
320 { |
|
321 GetDNPartL( aDN, KX520LocalityName, aNameArray ); |
|
322 break; |
|
323 } |
|
324 case EAltDirectoryName: |
|
325 { |
|
326 if ( aExtension ) |
|
327 { |
|
328 GetAltNamePartL( *altNameExt, EX509DirectoryName, |
|
329 aNameArray ); |
|
330 } |
|
331 break; |
|
332 } |
|
333 case EAltIPAddress: |
|
334 { |
|
335 if ( aExtension ) |
|
336 { |
|
337 GetAltNamePartL( *altNameExt, EX509IPAddress, |
|
338 aNameArray ); |
|
339 } |
|
340 break; |
|
341 } |
|
342 default: |
|
343 { |
|
344 // All the names are gone through. |
|
345 notFound = EFalse; |
|
346 break; |
|
347 } |
|
348 } // switch |
|
349 |
|
350 if ( notFound ) |
|
351 { |
|
352 // If caller is PrimaryAndSecondaryNameL and PrimaryName and |
|
353 // SecondaryName have found then end loop. |
|
354 if ( aNameType == EX509CNPPrimAndSecond && |
|
355 ( aNameArray.MdcaCount() >= KX509CNPPrimAndSecondNameLengh ) ) |
|
356 { |
|
357 notFound = EFalse; |
|
358 } // if |
|
359 } // if |
|
360 } // for |
|
361 |
|
362 if ( aExtension ) |
|
363 { |
|
364 CleanupStack::PopAndDestroy(); // altNameExt |
|
365 } |
|
366 return KErrNone; |
|
367 } |
|
368 |
|
369 // ----------------------------------------------------------------------------- |
|
370 // X509CertNameParser::GetDNPartAllL |
|
371 // |
|
372 // ----------------------------------------------------------------------------- |
|
373 |
|
374 void X509CertNameParser::GetDNPartAllL( |
|
375 const CX500DistinguishedName& aDN, |
|
376 const TDesC& aSubPartOID, |
|
377 CDesCArray& aNameArray ) |
|
378 { |
|
379 HBufC* buf = NULL; |
|
380 // Count of the name parts of the DN |
|
381 TInt count = aDN.Count(); |
|
382 |
|
383 // This goes through all the nameparts of the DN and appends all the |
|
384 // parts, that OID is aSubPartOID, to the array. |
|
385 for ( TInt i = 0; i < count; i++ ) |
|
386 { |
|
387 const CX520AttributeTypeAndValue& ava = aDN.Element( i ); |
|
388 if ( ava.Type() == aSubPartOID ) |
|
389 { |
|
390 TRAPD( error, buf = ava.ValueL() ); |
|
391 HandleErrorL( error ); |
|
392 |
|
393 if ( buf ) |
|
394 { |
|
395 CleanupStack::PushL( buf ); |
|
396 CompareAndAddNameL( *buf, aNameArray ); |
|
397 CleanupStack::PopAndDestroy( buf ); // buf |
|
398 buf = NULL; |
|
399 } // if |
|
400 } // if |
|
401 } // for |
|
402 } |
|
403 |
|
404 // ----------------------------------------------------------------------------- |
|
405 // X509CertNameParser::GetDNPartL |
|
406 // |
|
407 // ----------------------------------------------------------------------------- |
|
408 |
|
409 void X509CertNameParser::GetDNPartL( |
|
410 const CX500DistinguishedName& aDN, |
|
411 const TDesC& aSubPartOID, |
|
412 CDesCArray& aNameArray ) |
|
413 { |
|
414 HBufC* buf = NULL; |
|
415 // Extract one DN part |
|
416 TRAPD( error, buf = aDN.ExtractFieldL( aSubPartOID ) ); |
|
417 HandleErrorL( error ); |
|
418 |
|
419 // Add to array |
|
420 if ( buf ) |
|
421 { |
|
422 CleanupStack::PushL( buf ); |
|
423 CompareAndAddNameL( *buf, aNameArray ); |
|
424 CleanupStack::PopAndDestroy( buf ); // buf |
|
425 } |
|
426 } |
|
427 |
|
428 // ----------------------------------------------------------------------------- |
|
429 // X509CertNameParser::GetAltNamePartL |
|
430 // |
|
431 // ----------------------------------------------------------------------------- |
|
432 |
|
433 void X509CertNameParser::GetAltNamePartL( |
|
434 const CX509AltNameExt& aAltName, |
|
435 const TGNType& aSubPartType, |
|
436 CDesCArray& aNameArray ) |
|
437 { |
|
438 // Get all parts of the alternative name to the array |
|
439 const CArrayPtrFlat<CX509GeneralName>& subParts = aAltName.AltName(); |
|
440 TInt count = subParts.Count(); |
|
441 CX509DomainName* domainName = NULL; |
|
442 TInt error = KErrNone; |
|
443 |
|
444 // This goes through all the nameparts of the DN and appends all the |
|
445 // parts, that OID is aSubPartOID, to the array. |
|
446 for (TInt i = 0; count > i; i++) |
|
447 { |
|
448 if ( subParts[i]->Tag() == aSubPartType ) |
|
449 { |
|
450 TPtrC8 data = subParts[i]->Data(); |
|
451 switch ( aSubPartType ) |
|
452 { |
|
453 case EX509RFC822Name: |
|
454 { |
|
455 TRAP( error, domainName = CX509RFC822Name::NewL( data ) ); |
|
456 CleanupStack::PushL( domainName ); |
|
457 AddAltNameToArrayL( error, domainName, aNameArray ); |
|
458 CleanupStack::PopAndDestroy( domainName ); |
|
459 break; |
|
460 } |
|
461 case EX509DNSName: |
|
462 case EX509DirectoryName: |
|
463 { |
|
464 TRAP( error, domainName = CX509DNSName::NewL( data ) ); |
|
465 CleanupStack::PushL( domainName ); |
|
466 AddAltNameToArrayL( error, domainName, aNameArray ); |
|
467 CleanupStack::PopAndDestroy( domainName ); |
|
468 break; |
|
469 } |
|
470 case EX509URI: |
|
471 { |
|
472 CX509IPBasedURI* uri = NULL; |
|
473 HBufC* decodedUri = NULL; |
|
474 TRAP( error, uri = CX509IPBasedURI::NewL( data ) ); |
|
475 |
|
476 if ( error == KErrNone ) |
|
477 { |
|
478 CleanupStack::PushL( uri ); |
|
479 TRAP( error, decodedUri = EscapeUtils:: |
|
480 EscapeDecodeL( uri->Name() ) ); |
|
481 CleanupStack::PopAndDestroy(); //uri |
|
482 } |
|
483 |
|
484 HandleErrorL( error ); |
|
485 if ( error == KErrNone ) |
|
486 { |
|
487 CleanupStack::PushL( decodedUri ); |
|
488 CompareAndAddNameL( *decodedUri, aNameArray ); |
|
489 CleanupStack::PopAndDestroy(); // decodedUri |
|
490 } |
|
491 break; |
|
492 } |
|
493 case EX509IPAddress: |
|
494 { |
|
495 // Not supported |
|
496 break; |
|
497 } |
|
498 default: |
|
499 { |
|
500 break; |
|
501 } |
|
502 } // switch |
|
503 } // if |
|
504 } // for |
|
505 } |
|
506 |
|
507 // ----------------------------------------------------------------------------- |
|
508 // X509CertNameParser::AddAltNameToArrayL |
|
509 // |
|
510 // ----------------------------------------------------------------------------- |
|
511 |
|
512 TInt X509CertNameParser::AddAltNameToArrayL( |
|
513 TInt aError, |
|
514 CX509DomainName* aDomainName, |
|
515 CDesCArray& aNameArray ) |
|
516 { |
|
517 TInt error = HandleErrorL( aError ); |
|
518 |
|
519 if ( error == KErrNone ) |
|
520 { |
|
521 const TPtrC name = aDomainName->Name(); |
|
522 CompareAndAddNameL( name, aNameArray ); |
|
523 } |
|
524 |
|
525 return error; |
|
526 } |
|
527 |
|
528 // ----------------------------------------------------------------------------- |
|
529 // X509CertNameParser::AddToBufLD |
|
530 // |
|
531 // ----------------------------------------------------------------------------- |
|
532 |
|
533 void X509CertNameParser::AddToBufLD( const TDesC& aName, HBufC*& aBuf ) |
|
534 { |
|
535 if (!aBuf) |
|
536 { |
|
537 aBuf = HBufC::NewL( aName.Length() ); |
|
538 aBuf->Des().Append( aName ); |
|
539 } |
|
540 else |
|
541 { |
|
542 HBufC* helpBuf = HBufC::NewL( aName.Length() + aBuf->Length() + 1); |
|
543 helpBuf->Des().Append( *aBuf ); |
|
544 helpBuf->Des().Append( KX509CertParserSpace ); |
|
545 helpBuf->Des().Append( aName ); |
|
546 CleanupStack::PopAndDestroy( aBuf ); // aBuf |
|
547 aBuf = helpBuf; |
|
548 } |
|
549 } |
|
550 |
|
551 // ----------------------------------------------------------------------------- |
|
552 // X509CertNameParser::CompareAndAddNameL |
|
553 // |
|
554 // ----------------------------------------------------------------------------- |
|
555 |
|
556 void X509CertNameParser::CompareAndAddNameL( const TDesC& aProposal, |
|
557 CDesCArray& aNameArray ) |
|
558 { |
|
559 TInt pos = 0; // This is needed only for calling Find(). |
|
560 // Append to array, if aProposal don't already exist in the array. |
|
561 if ( aNameArray.Find( aProposal, pos, ECmpNormal ) ) |
|
562 { |
|
563 aNameArray.AppendL( aProposal ); |
|
564 } |
|
565 } |
|
566 |
|
567 |
|
568 |
|
569 // ----------------------------------------------------------------------------- |
|
570 // X509CertNameParser::HandleErrorL |
|
571 // |
|
572 // ----------------------------------------------------------------------------- |
|
573 |
|
574 TInt X509CertNameParser::HandleErrorL( TInt aError ) |
|
575 { |
|
576 if ( !( aError == KErrNone || aError == KErrArgument || aError == KErrNotSupported ) ) |
|
577 { |
|
578 User::Leave( aError ); |
|
579 } |
|
580 return aError; |
|
581 } |
|
582 |
|
583 // End of File |