]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * The contents of this file constitute Original Code as defined in and are | |
5 | * subject to the Apple Public Source License Version 1.2 (the 'License'). | |
6 | * You may not use this file except in compliance with the License. Please obtain | |
7 | * a copy of the License at http://www.apple.com/publicsource and read it before | |
8 | * using this file. | |
9 | * | |
10 | * This Original Code and all software distributed under the License are | |
11 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS | |
12 | * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT | |
13 | * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
14 | * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the | |
15 | * specific language governing rights and limitations under the License. | |
16 | */ | |
17 | ||
18 | /* | |
19 | * cuPrintCert.cpp - Parse a cert or CRL, dump contents. | |
20 | */ | |
21 | #include "cuCdsaUtils.h" | |
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | #include <Security/oidscert.h> | |
25 | #include <Security/oidscrl.h> | |
26 | #include <Security/x509defs.h> | |
27 | #include <Security/oidsattr.h> | |
28 | #include <Security/oidsalg.h> | |
29 | #include <Security/cssmapple.h> | |
30 | #include <string.h> | |
31 | #include "cuPrintCert.h" | |
32 | #include "cuOidParser.h" | |
33 | #include "cuTimeStr.h" | |
34 | #include <Security/certextensions.h> | |
35 | #include <Security/SecAsn1Coder.h> | |
36 | #include <Security/keyTemplates.h> | |
37 | ||
38 | static const char *months[] = { | |
39 | "Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
40 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" | |
41 | }; | |
42 | ||
43 | static void printTimeStr(const CSSM_DATA *cssmTime) | |
44 | { | |
45 | struct tm tm; | |
46 | ||
47 | /* ignore cssmTime->timeType for now */ | |
427c49bc | 48 | if(cuTimeStringToTm((char *)cssmTime->Data, (unsigned int)cssmTime->Length, &tm)) { |
b1ab9ed8 A |
49 | printf("***Bad time string format***\n"); |
50 | return; | |
51 | } | |
52 | if(tm.tm_mon > 11) { | |
53 | printf("***Bad time string format***\n"); | |
54 | return; | |
55 | } | |
56 | printf("%02d:%02d:%02d %s %d, %04d\n", | |
57 | tm.tm_hour, tm.tm_min, tm.tm_sec, | |
58 | months[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900); | |
59 | ||
60 | } | |
61 | ||
62 | ||
63 | static void printTime(const CSSM_X509_TIME *cssmTime) | |
64 | { | |
65 | /* ignore cssmTime->timeType for now */ | |
66 | printTimeStr(&cssmTime->time); | |
67 | } | |
68 | ||
69 | static void printDataAsHex( | |
70 | const CSSM_DATA *d, | |
71 | unsigned maxToPrint = 0) // optional, 0 means print it all | |
72 | { | |
73 | unsigned i; | |
74 | bool more = false; | |
427c49bc | 75 | uint32 len = (uint32)d->Length; |
b1ab9ed8 A |
76 | uint8 *cp = d->Data; |
77 | ||
78 | if((maxToPrint != 0) && (len > maxToPrint)) { | |
79 | len = maxToPrint; | |
80 | more = true; | |
81 | } | |
82 | for(i=0; i<len; i++) { | |
83 | printf("%02X ", ((unsigned char *)cp)[i]); | |
84 | } | |
85 | if(more) { | |
86 | printf("...\n"); | |
87 | } | |
88 | else { | |
89 | printf("\n"); | |
90 | } | |
91 | } | |
92 | ||
93 | /* | |
94 | * Identify CSSM_BER_TAG with a C string. | |
95 | */ | |
96 | static const char *tagTypeString( | |
97 | CSSM_BER_TAG tagType) | |
98 | { | |
99 | static char unknownType[80]; | |
100 | ||
101 | switch(tagType) { | |
102 | case BER_TAG_UNKNOWN: | |
103 | return "BER_TAG_UNKNOWN"; | |
104 | case BER_TAG_BOOLEAN: | |
105 | return "BER_TAG_BOOLEAN"; | |
106 | case BER_TAG_INTEGER: | |
107 | return "BER_TAG_INTEGER"; | |
108 | case BER_TAG_BIT_STRING: | |
109 | return "BER_TAG_BIT_STRING"; | |
110 | case BER_TAG_OCTET_STRING: | |
111 | return "BER_TAG_OCTET_STRING"; | |
112 | case BER_TAG_NULL: | |
113 | return "BER_TAG_NULL"; | |
114 | case BER_TAG_OID: | |
115 | return "BER_TAG_OID"; | |
116 | case BER_TAG_SEQUENCE: | |
117 | return "BER_TAG_SEQUENCE"; | |
118 | case BER_TAG_SET: | |
119 | return "BER_TAG_SET"; | |
120 | case BER_TAG_PRINTABLE_STRING: | |
121 | return "BER_TAG_PRINTABLE_STRING"; | |
122 | case BER_TAG_T61_STRING: | |
123 | return "BER_TAG_T61_STRING"; | |
124 | case BER_TAG_IA5_STRING: | |
125 | return "BER_TAG_IA5_STRING"; | |
126 | case BER_TAG_UTC_TIME: | |
127 | return "BER_TAG_UTC_TIME"; | |
128 | case BER_TAG_GENERALIZED_TIME: | |
129 | return "BER_TAG_GENERALIZED_TIME"; | |
130 | default: | |
131 | sprintf(unknownType, "Other type (0x%x)", tagType); | |
132 | return unknownType; | |
133 | } | |
134 | } | |
135 | ||
136 | /* | |
137 | * Print an OID, assumed to be in BER encoded "Intel" format | |
138 | * Length is inferred from oid->Length | |
139 | * Tag is implied | |
140 | */ | |
141 | static void printOid(OidParser &parser, const CSSM_DATA *oid) | |
142 | { | |
143 | char strBuf[OID_PARSER_STRING_SIZE]; | |
144 | ||
145 | if(oid == NULL) { | |
146 | printf("NULL\n"); | |
147 | return; | |
148 | } | |
149 | if((oid->Length == 0) || (oid->Data == NULL)) { | |
150 | printf("EMPTY\n"); | |
151 | return; | |
152 | } | |
427c49bc | 153 | parser.oidParse(oid->Data, (unsigned int)oid->Length, strBuf); |
b1ab9ed8 A |
154 | printf("%s\n", strBuf); |
155 | } | |
156 | ||
157 | /* | |
158 | * Used to print generic blobs which we don't really understand. | |
159 | * The bytesToPrint argument is usually thing->Length; it's here because snacc | |
160 | * peports lengths of bit strings in BITS. Caller knows this and | |
161 | * modifies bytesToPrint accordingly. In any case, bytesToPrint is the | |
162 | * max number of valid bytes in *thing->Data. | |
163 | */ | |
164 | #define BLOB_LENGTH_PRINT 3 | |
165 | ||
166 | static void printBlobBytes( | |
167 | const char *blobType, | |
168 | const char *quanta, // e.g., "bytes', "bits" | |
169 | uint32 bytesToPrint, | |
170 | const CSSM_DATA *thing) | |
171 | { | |
172 | uint32 dex; | |
173 | uint32 toPrint = bytesToPrint; | |
174 | ||
175 | if(toPrint > BLOB_LENGTH_PRINT) { | |
176 | toPrint = BLOB_LENGTH_PRINT; | |
177 | } | |
178 | printf("%s; Length %u %s; data = ", | |
179 | blobType, (unsigned)thing->Length, quanta); | |
180 | for(dex=0; dex<toPrint; dex++) { | |
181 | printf("0x%x ", thing->Data[dex]); | |
182 | if(dex == (toPrint - 1)) { | |
183 | break; | |
184 | } | |
185 | } | |
186 | if(dex < bytesToPrint) { | |
187 | printf(" ...\n"); | |
188 | } | |
189 | else { | |
190 | printf("\n"); | |
191 | } | |
192 | } | |
193 | ||
194 | /* | |
195 | * Print an IA5String or Printable string. Null terminator is not assumed. | |
196 | * Trailing newline is printed. | |
197 | */ | |
198 | static void printString( | |
199 | const CSSM_DATA *str) | |
200 | { | |
201 | unsigned i; | |
202 | char *cp = (char *)str->Data; | |
203 | for(i=0; i<str->Length; i++) { | |
204 | printf("%c", *cp++); | |
205 | } | |
206 | printf("\n"); | |
207 | } | |
208 | ||
209 | static void printDerThing( | |
210 | CSSM_BER_TAG tagType, | |
211 | const CSSM_DATA *thing, | |
212 | OidParser &parser) | |
213 | { | |
214 | switch(tagType) { | |
215 | case BER_TAG_INTEGER: | |
216 | printf("%d\n", cuDER_ToInt(thing)); | |
217 | return; | |
218 | case BER_TAG_BOOLEAN: | |
219 | if(thing->Length != 1) { | |
220 | printf("***malformed BER_TAG_BOOLEAN: length %u data ", | |
221 | (unsigned)thing->Length); | |
222 | } | |
223 | printf("%u\n", cuDER_ToInt(thing)); | |
224 | return; | |
225 | case BER_TAG_PRINTABLE_STRING: | |
226 | case BER_TAG_IA5_STRING: | |
227 | case BER_TAG_T61_STRING: | |
228 | case BER_TAG_PKIX_UTF8_STRING: // mostly printable.... | |
229 | printString(thing); | |
230 | return; | |
231 | case BER_TAG_OCTET_STRING: | |
427c49bc | 232 | printBlobBytes("Byte string", "bytes", (uint32)thing->Length, thing); |
b1ab9ed8 A |
233 | return; |
234 | case BER_TAG_BIT_STRING: | |
427c49bc | 235 | printBlobBytes("Bit string", "bits", (uint32)(thing->Length + 7) / 8, thing); |
b1ab9ed8 A |
236 | return; |
237 | case BER_TAG_SEQUENCE: | |
427c49bc | 238 | printBlobBytes("Sequence", "bytes", (uint32)thing->Length, thing); |
b1ab9ed8 A |
239 | return; |
240 | case BER_TAG_SET: | |
427c49bc | 241 | printBlobBytes("Set", "bytes", (uint32)thing->Length, thing); |
b1ab9ed8 A |
242 | return; |
243 | case BER_TAG_OID: | |
244 | printf("OID = "); | |
245 | printOid(parser, thing); | |
246 | break; | |
247 | default: | |
248 | printf("not displayed (tagType = %s; length %u)\n", | |
249 | tagTypeString(tagType), (unsigned)thing->Length); | |
250 | break; | |
251 | ||
252 | } | |
253 | } | |
254 | ||
255 | /* compare two OIDs, return CSSM_TRUE if identical */ | |
256 | static CSSM_BOOL compareOids( | |
257 | const CSSM_OID *oid1, | |
258 | const CSSM_OID *oid2) | |
259 | { | |
260 | if((oid1 == NULL) || (oid2 == NULL)) { | |
261 | return CSSM_FALSE; | |
262 | } | |
263 | if(oid1->Length != oid2->Length) { | |
264 | return CSSM_FALSE; | |
265 | } | |
266 | if(memcmp(oid1->Data, oid2->Data, oid1->Length)) { | |
267 | return CSSM_FALSE; | |
268 | } | |
269 | else { | |
270 | return CSSM_TRUE; | |
271 | } | |
272 | } | |
273 | ||
274 | /* | |
275 | * Following a CSSMOID_ECDSA_WithSpecified algorithm is another encoded | |
276 | * CSSM_X509_ALGORITHM_IDENTIFIER containing the digest algorithm OID. | |
277 | * Decode and print the OID. | |
278 | */ | |
279 | static void printECDSA_SigAlgParams( | |
280 | const CSSM_DATA *params, | |
281 | OidParser &parser) | |
282 | { | |
283 | SecAsn1CoderRef coder = NULL; | |
284 | if(SecAsn1CoderCreate(&coder)) { | |
285 | printf("***Error in SecAsn1CoderCreate()\n"); | |
286 | return; | |
287 | } | |
288 | CSSM_X509_ALGORITHM_IDENTIFIER algParams; | |
289 | memset(&algParams, 0, sizeof(algParams)); | |
290 | if(SecAsn1DecodeData(coder, params, kSecAsn1AlgorithmIDTemplate, | |
291 | &algParams)) { | |
292 | printf("***Error decoding CSSM_X509_ALGORITHM_IDENTIFIER\n"); | |
293 | goto errOut; | |
294 | } | |
295 | printOid(parser, &algParams.algorithm); | |
296 | errOut: | |
297 | SecAsn1CoderRelease(coder); | |
298 | } | |
299 | ||
300 | static void printSigAlg( | |
301 | const CSSM_X509_ALGORITHM_IDENTIFIER *sigAlg, | |
302 | OidParser &parser) | |
303 | { | |
304 | printOid(parser, &sigAlg->algorithm); | |
305 | if(sigAlg->parameters.Data != NULL) { | |
306 | printf(" alg params : "); | |
307 | if(compareOids(&sigAlg->algorithm, &CSSMOID_ecPublicKey) && | |
308 | (sigAlg->parameters.Data[0] == BER_TAG_OID) && | |
309 | (sigAlg->parameters.Length > 2)) { | |
310 | /* | |
311 | * An OID accompanying an ECDSA public key. The OID is an ECDSA curve. | |
312 | * Do a quickie DER-decode of the OID - it's here in encoded form | |
313 | * because this field is an ASN_ANY - and print the resulting OID. | |
314 | */ | |
315 | CSSM_OID curveOid = {sigAlg->parameters.Length-2, sigAlg->parameters.Data+2}; | |
316 | printOid(parser, &curveOid); | |
317 | } | |
318 | else if(compareOids(&sigAlg->algorithm, &CSSMOID_ECDSA_WithSpecified)) { | |
319 | /* | |
320 | * The accompanying params specify the digest algorithm. | |
321 | */ | |
322 | printECDSA_SigAlgParams(&sigAlg->parameters, parser); | |
323 | } | |
324 | else { | |
325 | /* All others - ASN_ANY - punt */ | |
326 | printDataAsHex(&sigAlg->parameters, 8); | |
327 | } | |
328 | } | |
329 | } | |
330 | ||
331 | static void printRdn( | |
332 | const CSSM_X509_RDN *rdnp, | |
333 | OidParser &parser) | |
334 | { | |
335 | CSSM_X509_TYPE_VALUE_PAIR *ptvp; | |
336 | unsigned pairDex; | |
337 | const char *fieldName; | |
338 | ||
339 | for(pairDex=0; pairDex<rdnp->numberOfPairs; pairDex++) { | |
340 | ptvp = &rdnp->AttributeTypeAndValue[pairDex]; | |
341 | if(compareOids(&ptvp->type, &CSSMOID_CountryName)) { | |
342 | fieldName = "Country "; | |
343 | } | |
344 | else if(compareOids(&ptvp->type, &CSSMOID_OrganizationName)) { | |
345 | fieldName = "Org "; | |
346 | } | |
347 | else if(compareOids(&ptvp->type, &CSSMOID_LocalityName)) { | |
348 | fieldName = "Locality "; | |
349 | } | |
350 | else if(compareOids(&ptvp->type, &CSSMOID_OrganizationalUnitName)) { | |
351 | fieldName = "OrgUnit "; | |
352 | } | |
353 | else if(compareOids(&ptvp->type, &CSSMOID_CommonName)) { | |
354 | fieldName = "Common Name "; | |
355 | } | |
356 | else if(compareOids(&ptvp->type, &CSSMOID_Surname)) { | |
357 | fieldName = "Surname "; | |
358 | } | |
359 | else if(compareOids(&ptvp->type, &CSSMOID_Title)) { | |
360 | fieldName = "Title "; | |
361 | } | |
362 | else if(compareOids(&ptvp->type, &CSSMOID_Surname)) { | |
363 | fieldName = "Surname "; | |
364 | } | |
365 | else if(compareOids(&ptvp->type, &CSSMOID_StateProvinceName)) { | |
366 | fieldName = "State "; | |
367 | } | |
368 | else if(compareOids(&ptvp->type, &CSSMOID_CollectiveStateProvinceName)) { | |
369 | fieldName = "Coll. State "; | |
370 | } | |
371 | else if(compareOids(&ptvp->type, &CSSMOID_EmailAddress)) { | |
372 | /* deprecated, used by Thawte */ | |
373 | fieldName = "Email addrs "; | |
374 | } | |
375 | else if(compareOids(&ptvp->type, &CSSMOID_Description)) { | |
376 | fieldName = "Description "; | |
377 | } | |
378 | else { | |
379 | fieldName = "Other name "; | |
380 | } | |
381 | printf(" %s : ", fieldName); | |
382 | printDerThing(ptvp->valueType, &ptvp->value, parser); | |
383 | } /* for each type/value pair */ | |
384 | } | |
385 | ||
386 | static CSSM_RETURN printName( | |
387 | const CSSM_X509_NAME *x509Name, | |
388 | OidParser &parser) | |
389 | { | |
390 | CSSM_X509_RDN_PTR rdnp; | |
391 | unsigned rdnDex; | |
392 | ||
393 | for(rdnDex=0; rdnDex<x509Name->numberOfRDNs; rdnDex++) { | |
394 | rdnp = &x509Name->RelativeDistinguishedName[rdnDex]; | |
395 | printRdn(rdnp, parser); | |
396 | } | |
397 | ||
398 | return CSSM_OK; | |
399 | } | |
400 | ||
401 | static void printKeyHeader( | |
402 | const CSSM_KEYHEADER &hdr) | |
403 | { | |
404 | printf(" Algorithm : "); | |
405 | switch(hdr.AlgorithmId) { | |
406 | case CSSM_ALGID_RSA: | |
407 | printf("RSA\n"); | |
408 | break; | |
409 | case CSSM_ALGID_DSA: | |
410 | printf("DSA\n"); | |
411 | break; | |
412 | case CSSM_ALGID_FEE: | |
413 | printf("FEE\n"); | |
414 | break; | |
415 | case CSSM_ALGID_DH: | |
416 | printf("Diffie-Hellman\n"); | |
417 | break; | |
418 | case CSSM_ALGID_ECDSA: | |
419 | printf("ECDSA\n"); | |
420 | break; | |
421 | default: | |
422 | printf("Unknown(%u(d), 0x%x)\n", (unsigned)hdr.AlgorithmId, | |
423 | (unsigned)hdr.AlgorithmId); | |
424 | } | |
425 | printf(" Key Size : %u bits\n", (unsigned)hdr.LogicalKeySizeInBits); | |
426 | printf(" Key Use : "); | |
427 | CSSM_KEYUSE usage = hdr.KeyUsage; | |
428 | if(usage & CSSM_KEYUSE_ANY) { | |
429 | printf("CSSM_KEYUSE_ANY "); | |
430 | } | |
431 | if(usage & CSSM_KEYUSE_ENCRYPT) { | |
432 | printf("CSSM_KEYUSE_ENCRYPT "); | |
433 | } | |
434 | if(usage & CSSM_KEYUSE_DECRYPT) { | |
435 | printf("CSSM_KEYUSE_DECRYPT "); | |
436 | } | |
437 | if(usage & CSSM_KEYUSE_SIGN) { | |
438 | printf("CSSM_KEYUSE_SIGN "); | |
439 | } | |
440 | if(usage & CSSM_KEYUSE_VERIFY) { | |
441 | printf("CSSM_KEYUSE_VERIFY "); | |
442 | } | |
443 | if(usage & CSSM_KEYUSE_SIGN_RECOVER) { | |
444 | printf("CSSM_KEYUSE_SIGN_RECOVER "); | |
445 | } | |
446 | if(usage & CSSM_KEYUSE_VERIFY_RECOVER) { | |
447 | printf("CSSM_KEYUSE_VERIFY_RECOVER "); | |
448 | } | |
449 | if(usage & CSSM_KEYUSE_WRAP) { | |
450 | printf("CSSM_KEYUSE_WRAP "); | |
451 | } | |
452 | if(usage & CSSM_KEYUSE_UNWRAP) { | |
453 | printf("CSSM_KEYUSE_UNWRAP "); | |
454 | } | |
455 | if(usage & CSSM_KEYUSE_DERIVE) { | |
456 | printf("CSSM_KEYUSE_DERIVE "); | |
457 | } | |
458 | printf("\n"); | |
459 | ||
460 | } | |
461 | ||
462 | /* | |
463 | * Print contents of a CE_GeneralName as best we can. | |
464 | */ | |
465 | static void printGeneralName( | |
466 | const CE_GeneralName *name, | |
467 | OidParser &parser) | |
468 | { | |
469 | switch(name->nameType) { | |
470 | case GNT_RFC822Name: | |
471 | printf(" RFC822Name : "); | |
472 | printString(&name->name); | |
473 | break; | |
474 | case GNT_DNSName: | |
475 | printf(" DNSName : "); | |
476 | printString(&name->name); | |
477 | break; | |
478 | case GNT_URI: | |
479 | printf(" URI : "); | |
480 | printString(&name->name); | |
481 | break; | |
482 | case GNT_IPAddress: | |
483 | printf(" IP Address : "); | |
484 | for(unsigned i=0; i<name->name.Length; i++) { | |
485 | printf("%d", name->name.Data[i]); | |
486 | if(i < (name->name.Length - 1)) { | |
487 | printf("."); | |
488 | } | |
489 | } | |
490 | printf("\n"); | |
491 | break; | |
492 | case GNT_RegisteredID: | |
493 | printf(" RegisteredID : "); | |
494 | printOid(parser, &name->name); | |
495 | break; | |
496 | case GNT_X400Address: | |
497 | /* ORAddress, a very complicated struct - punt */ | |
498 | printf(" X400Address : "); | |
427c49bc | 499 | printBlobBytes("Sequence", "bytes", (uint32)name->name.Length, &name->name); |
b1ab9ed8 A |
500 | break; |
501 | case GNT_DirectoryName: | |
502 | if(!name->berEncoded) { | |
503 | /* CL parsed it for us into an CSSM_X509_NAME */ | |
504 | if(name->name.Length != sizeof(CSSM_X509_NAME)) { | |
505 | printf("***MALFORMED GNT_DirectoryName\n"); | |
506 | break; | |
507 | } | |
508 | const CSSM_X509_NAME *x509Name = | |
509 | (const CSSM_X509_NAME *)name->name.Data; | |
510 | printf(" Dir Name :\n"); | |
511 | printName(x509Name, parser); | |
512 | } | |
513 | else { | |
514 | /* encoded Name (i.e. CSSM_X509_NAME) */ | |
515 | printf(" Dir Name : "); | |
516 | printBlobBytes("Byte string", "bytes", | |
427c49bc | 517 | (uint32)name->name.Length, &name->name); |
b1ab9ed8 A |
518 | } |
519 | break; | |
520 | case GNT_EdiPartyName: | |
521 | /* sequence EDIPartyName */ | |
522 | printf(" EdiPartyName : "); | |
427c49bc | 523 | printBlobBytes("Sequence", "bytes", (uint32)name->name.Length, &name->name); |
b1ab9ed8 A |
524 | break; |
525 | case GNT_OtherName: | |
526 | { | |
527 | printf(" OtherName :\n"); | |
528 | if(name->name.Length != sizeof(CE_OtherName)) { | |
529 | printf("***Malformed CE_OtherName\n"); | |
530 | break; | |
531 | } | |
532 | CE_OtherName *other = (CE_OtherName *)name->name.Data; | |
533 | printf(" typeID : "); | |
534 | printOid(parser, &other->typeId); | |
535 | printf(" value : "); | |
536 | printDataAsHex(&other->value, 0); | |
537 | break; | |
538 | } | |
539 | } | |
540 | } | |
541 | ||
542 | ||
543 | /* | |
544 | * Print contents of a CE_GeneralNames as best we can. | |
545 | */ | |
546 | static void printGeneralNames( | |
547 | const CE_GeneralNames *generalNames, | |
548 | OidParser &parser) | |
549 | { | |
550 | unsigned i; | |
551 | CE_GeneralName *name; | |
552 | ||
553 | for(i=0; i<generalNames->numNames; i++) { | |
554 | name = &generalNames->generalName[i]; | |
555 | printGeneralName(name, parser); | |
556 | } | |
557 | } | |
558 | ||
559 | static int printCdsaExtensionCommon( | |
560 | const CSSM_X509_EXTENSION *cssmExt, | |
561 | OidParser &parser, | |
562 | bool expectParsed, | |
563 | CSSM_BOOL verbose, | |
564 | bool extraIndent = false) | |
565 | { | |
566 | if(extraIndent) { | |
567 | printf(" Extension : "); printOid(parser, &cssmExt->extnId); | |
568 | printf(" Critical : %s\n", cssmExt->critical ? "TRUE" : "FALSE"); | |
569 | } | |
570 | else { | |
571 | printf("Extension struct : "); printOid(parser, &cssmExt->extnId); | |
572 | printf(" Critical : %s\n", cssmExt->critical ? "TRUE" : "FALSE"); | |
573 | } | |
574 | ||
575 | /* currently (since Radar 3593624), these are both always valid */ | |
576 | #if 0 | |
577 | /* this prevents printing pre-encoded extensions in clxutils/extenTest */ | |
578 | if((cssmExt->BERvalue.Data == NULL) || | |
579 | (cssmExt->value.parsedValue == NULL)) { /* actually, one of three variants */ | |
580 | printf("***Malformed CSSM_X509_EXTENSION (1)\n"); | |
581 | return 1; | |
582 | } | |
583 | #endif | |
584 | switch(cssmExt->format) { | |
585 | case CSSM_X509_DATAFORMAT_ENCODED: | |
586 | if(expectParsed) { | |
587 | printf("Bad CSSM_X509_EXTENSION; expected FORMAT_PARSED\n"); | |
588 | return 1; | |
589 | } | |
590 | break; | |
591 | case CSSM_X509_DATAFORMAT_PARSED: | |
592 | if(!expectParsed) { | |
593 | printf("Bad CSSM_X509_EXTENSION; expected FORMAT_ENCODED\n"); | |
594 | return 1; | |
595 | } | |
596 | break; | |
597 | case CSSM_X509_DATAFORMAT_PAIR: | |
598 | /* unsupported */ | |
599 | printf("Bad CSSM_X509_EXTENSION format:FORMAT_PAIR\n"); | |
600 | return 1; | |
601 | default: | |
602 | printf("***Unknown CSSM_X509_EXTENSION.format\n"); | |
603 | return 1; | |
604 | } | |
605 | return 0; | |
606 | } | |
607 | ||
608 | static int printExtensionCommon( | |
609 | const CSSM_DATA &value, | |
610 | OidParser &parser, | |
611 | CSSM_BOOL verbose, | |
612 | bool expectParsed = true) | |
613 | { | |
614 | if(value.Length != sizeof(CSSM_X509_EXTENSION)) { | |
615 | printf("***malformed CSSM_FIELD (1)\n"); | |
616 | return 1; | |
617 | } | |
618 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
619 | return printCdsaExtensionCommon(cssmExt, parser, expectParsed, verbose); | |
620 | } | |
621 | ||
622 | ||
623 | static void printKeyUsage( | |
624 | const CSSM_DATA &value) | |
625 | { | |
626 | CE_KeyUsage usage; | |
627 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
628 | ||
629 | usage = *((CE_KeyUsage *)cssmExt->value.parsedValue); | |
630 | printf(" usage : "); | |
631 | if(usage & CE_KU_DigitalSignature) { | |
632 | printf("DigitalSignature "); | |
633 | } | |
634 | if(usage & CE_KU_NonRepudiation) { | |
635 | printf("NonRepudiation "); | |
636 | } | |
637 | if(usage & CE_KU_KeyEncipherment) { | |
638 | printf("KeyEncipherment "); | |
639 | } | |
640 | if(usage & CE_KU_DataEncipherment) { | |
641 | printf("DataEncipherment "); | |
642 | } | |
643 | if(usage & CE_KU_KeyAgreement) { | |
644 | printf("KeyAgreement "); | |
645 | } | |
646 | if(usage & CE_KU_KeyCertSign) { | |
647 | printf("KeyCertSign "); | |
648 | } | |
649 | if(usage & CE_KU_CRLSign) { | |
650 | printf("CRLSign "); | |
651 | } | |
652 | if(usage & CE_KU_EncipherOnly) { | |
653 | printf("EncipherOnly "); | |
654 | } | |
655 | if(usage & CE_KU_DecipherOnly) { | |
656 | printf("DecipherOnly "); | |
657 | } | |
658 | printf("\n"); | |
659 | ||
660 | } | |
661 | ||
662 | static void printBasicConstraints( | |
663 | const CSSM_DATA &value) | |
664 | { | |
665 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
666 | CE_BasicConstraints *bc = (CE_BasicConstraints *)cssmExt->value.parsedValue; | |
667 | printf(" CA : %s\n", bc->cA ? "TRUE" : "FALSE"); | |
668 | if(bc->pathLenConstraintPresent) { | |
669 | printf(" pathLenConstr : %u\n", (unsigned)bc->pathLenConstraint); | |
670 | } | |
671 | } | |
672 | ||
673 | static void printExtKeyUsage( | |
674 | const CSSM_DATA &value, | |
675 | OidParser &parser) | |
676 | { | |
677 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
678 | CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue; | |
679 | unsigned oidDex; | |
680 | for(oidDex=0; oidDex<eku->numPurposes; oidDex++) { | |
681 | printf(" purpose %2d : ", oidDex); | |
682 | printOid(parser, &eku->purposes[oidDex]); | |
683 | } | |
684 | } | |
685 | ||
686 | static void printCssmAuthorityKeyId( | |
687 | const CE_AuthorityKeyID *akid, | |
688 | OidParser &parser) | |
689 | { | |
690 | if(akid->keyIdentifierPresent) { | |
691 | printf(" Auth KeyID : "); | |
692 | printDataAsHex(&akid->keyIdentifier, | |
693 | 8); | |
694 | } | |
695 | if(akid->generalNamesPresent) { | |
696 | printGeneralNames(akid->generalNames, parser); | |
697 | } | |
698 | if(akid->serialNumberPresent) { | |
699 | printf(" serialNumber : "); | |
700 | printDataAsHex(&akid->serialNumber, 8); | |
701 | } | |
702 | } | |
703 | ||
704 | static void printAuthorityKeyId( | |
705 | const CSSM_DATA &value, | |
706 | OidParser &parser) | |
707 | { | |
708 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
709 | CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)cssmExt->value.parsedValue; | |
710 | printCssmAuthorityKeyId(akid, parser); | |
711 | } | |
712 | ||
713 | static void printSubjectIssuerAltName( | |
714 | const CSSM_DATA &value, | |
715 | OidParser &parser) | |
716 | { | |
717 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
718 | CE_GeneralNames *san = (CE_GeneralNames *)cssmExt->value.parsedValue; | |
719 | printGeneralNames(san, parser); | |
720 | } | |
721 | ||
722 | static void printDistPointName( | |
723 | const CE_DistributionPointName *dpn, | |
724 | OidParser &parser) | |
725 | { | |
726 | switch(dpn->nameType) { | |
727 | case CE_CDNT_FullName: | |
728 | printGeneralNames(dpn->dpn.fullName, parser); | |
729 | break; | |
730 | case CE_CDNT_NameRelativeToCrlIssuer: | |
731 | printRdn(dpn->dpn.rdn, parser); | |
732 | break; | |
733 | default: | |
734 | printf("***BOGUS CE_DistributionPointName.nameType\n"); | |
735 | break; | |
736 | } | |
737 | } | |
738 | ||
739 | static void printDistPoint( | |
740 | const CE_CRLDistributionPoint *dp, | |
741 | OidParser &parser) | |
742 | { | |
743 | if(dp->distPointName) { | |
744 | printf(" Dist pt Name :\n"); | |
745 | printDistPointName(dp->distPointName, parser); | |
746 | } | |
747 | printf(" reasonsPresent : %s\n", dp->reasonsPresent ? "TRUE" : "FALSE"); | |
748 | if(dp->reasonsPresent) { | |
749 | /* FIXME - parse */ | |
750 | printf(" reasons : 0x%X\n", dp->reasons); | |
751 | } | |
752 | if(dp->crlIssuer) { | |
753 | printf(" CRLIssuer :\n"); | |
754 | printGeneralNames(dp->crlIssuer, parser); | |
755 | } | |
756 | } | |
757 | ||
758 | static void printDistributionPoints( | |
759 | const CSSM_DATA &value, | |
760 | OidParser &parser) | |
761 | { | |
762 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
763 | CE_CRLDistPointsSyntax *dps = (CE_CRLDistPointsSyntax *)cssmExt->value.parsedValue; | |
764 | ||
765 | for(unsigned dex=0; dex<dps->numDistPoints; dex++) { | |
766 | printf(" Dist pt %d :\n", dex); | |
767 | printDistPoint(&dps->distPoints[dex], parser); | |
768 | } | |
769 | } | |
770 | ||
771 | static void printValueOrNotPresent( | |
772 | CSSM_BOOL present, | |
773 | CSSM_BOOL value) | |
774 | { | |
775 | if(!present) { | |
776 | printf("<Not Present>\n"); | |
777 | } | |
778 | else if(value) { | |
779 | printf("TRUE\n"); | |
780 | } | |
781 | else { | |
782 | printf("FALSE"); | |
783 | } | |
784 | } | |
785 | ||
786 | static void printIssuingDistributionPoint( | |
787 | const CE_IssuingDistributionPoint *idp, | |
788 | OidParser &parser) | |
789 | { | |
790 | if(idp->distPointName) { | |
791 | printf(" Dist pt :\n"); | |
792 | printDistPointName(idp->distPointName, parser); | |
793 | } | |
794 | printf(" Only user certs : "); | |
795 | printValueOrNotPresent(idp->onlyUserCertsPresent, idp->onlyUserCerts); | |
796 | printf(" Only CA certs : "); | |
797 | printValueOrNotPresent(idp->onlyCACertsPresent, idp->onlyCACerts); | |
798 | printf(" Only some reason: "); | |
799 | printValueOrNotPresent(idp->onlySomeReasonsPresent, idp->onlySomeReasons); | |
800 | printf(" Indirectl CRL : "); | |
801 | printValueOrNotPresent(idp->indirectCrlPresent, idp->indirectCrl); | |
802 | } | |
803 | ||
804 | static void printCertPolicies( | |
805 | const CSSM_DATA &value, | |
806 | OidParser &parser) | |
807 | { | |
808 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
809 | CE_CertPolicies *cdsaObj = (CE_CertPolicies *)cssmExt->value.parsedValue; | |
810 | for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) { | |
811 | CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex]; | |
812 | printf(" Policy %2d : ID ", polDex); | |
813 | printOid(parser, &cPolInfo->certPolicyId); | |
814 | for(unsigned qualDex=0; qualDex<cPolInfo->numPolicyQualifiers; qualDex++) { | |
815 | CE_PolicyQualifierInfo *cQualInfo = &cPolInfo->policyQualifiers[qualDex]; | |
816 | printf(" Qual %2d : ID ", qualDex); | |
817 | printOid(parser, &cQualInfo->policyQualifierId); | |
818 | if(cuCompareCssmData(&cQualInfo->policyQualifierId, | |
819 | &CSSMOID_QT_CPS)) { | |
820 | printf(" CPS : "); | |
821 | printString(&cQualInfo->qualifier); | |
822 | } | |
823 | else { | |
824 | printf(" unparsed : "); | |
825 | printDataAsHex(&cQualInfo->qualifier, 8); | |
826 | } | |
827 | } | |
828 | } | |
829 | } | |
830 | ||
831 | static void printNetscapeCertType( | |
832 | const CSSM_DATA &value) | |
833 | { | |
834 | CE_NetscapeCertType certType; | |
835 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
836 | ||
837 | certType = *((CE_NetscapeCertType *)cssmExt->value.parsedValue); | |
838 | printf(" certType : "); | |
839 | if(certType & CE_NCT_SSL_Client) { | |
840 | printf("SSL_Client "); | |
841 | } | |
842 | if(certType & CE_NCT_SSL_Server) { | |
843 | printf("SSL_Server "); | |
844 | } | |
845 | if(certType & CE_NCT_SMIME) { | |
846 | printf("S/MIME "); | |
847 | } | |
848 | if(certType & CE_NCT_ObjSign) { | |
849 | printf("ObjectSign "); | |
850 | } | |
851 | if(certType & CE_NCT_Reserved) { | |
852 | printf("Reserved "); | |
853 | } | |
854 | if(certType & CE_NCT_SSL_CA) { | |
855 | printf("SSL_CA "); | |
856 | } | |
857 | if(certType & CE_NCT_SMIME_CA) { | |
858 | printf("SMIME_CA "); | |
859 | } | |
860 | if(certType & CE_NCT_ObjSignCA) { | |
861 | printf("ObjSignCA "); | |
862 | } | |
863 | printf("\n"); | |
864 | } | |
865 | ||
866 | static void printAuthorityInfoAccess( | |
867 | const CSSM_DATA &value, | |
868 | OidParser &parser) | |
869 | { | |
870 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
871 | CE_AuthorityInfoAccess *info = (CE_AuthorityInfoAccess *)cssmExt->value.parsedValue; | |
872 | ||
873 | printf(" numDescriptions : %lu\n", (unsigned long)info->numAccessDescriptions); | |
874 | for(unsigned dex=0; dex<info->numAccessDescriptions; dex++) { | |
875 | printf(" description %u : \n", dex); | |
876 | printf(" accessMethod : "); | |
877 | CE_AccessDescription *descr = &info->accessDescriptions[dex]; | |
878 | printOid(parser, &descr->accessMethod); | |
879 | printGeneralName(&descr->accessLocation, parser); | |
880 | } | |
881 | } | |
882 | ||
883 | static void printQualCertStatements( | |
884 | const CSSM_DATA &value, | |
885 | OidParser &parser) | |
886 | { | |
887 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data; | |
888 | CE_QC_Statements *qcss = (CE_QC_Statements *)cssmExt->value.parsedValue; | |
889 | ||
890 | printf(" numQCStatements : %lu\n", (unsigned long)qcss->numQCStatements); | |
891 | for(unsigned dex=0; dex<qcss->numQCStatements; dex++) { | |
892 | CE_QC_Statement *qcs = &qcss->qcStatements[dex]; | |
893 | ||
894 | printf(" statement %u : \n", dex); | |
895 | printf(" statementId : "); | |
896 | printOid(parser, &qcs->statementId); | |
897 | if(qcs->semanticsInfo) { | |
898 | printf(" semanticsInfo :\n"); | |
899 | CE_SemanticsInformation *si = qcs->semanticsInfo; | |
900 | if(si->semanticsIdentifier) { | |
901 | printf(" semanticsId : "); | |
902 | printOid(parser, si->semanticsIdentifier); | |
903 | } | |
904 | if(si->nameRegistrationAuthorities) { | |
905 | printf(" nameRegAuth :\n"); | |
906 | printGeneralNames(si->nameRegistrationAuthorities, parser); | |
907 | } | |
908 | } | |
909 | if(qcs->otherInfo) { | |
910 | printf(" otherInfo : "); printDataAsHex(qcs->otherInfo, 8); | |
911 | } | |
912 | } | |
913 | } | |
914 | ||
915 | /* print one field */ | |
916 | void printCertField( | |
917 | const CSSM_FIELD &field, | |
918 | OidParser &parser, | |
919 | CSSM_BOOL verbose) | |
920 | { | |
921 | const CSSM_DATA *thisData = &field.FieldValue; | |
922 | const CSSM_OID *thisOid = &field.FieldOid; | |
923 | ||
924 | if(cuCompareCssmData(thisOid, &CSSMOID_X509V1Version)) { | |
925 | if(verbose) { | |
926 | printf("Version : %u\n", cuDER_ToInt(thisData)); | |
927 | } | |
928 | } | |
929 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SerialNumber)) { | |
930 | printf("Serial Number : "); printDataAsHex(thisData, 0); | |
931 | } | |
932 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerNameCStruct)) { | |
933 | printf("Issuer Name :\n"); | |
934 | CSSM_X509_NAME_PTR name = (CSSM_X509_NAME_PTR)thisData->Data; | |
935 | if((name == NULL) || (thisData->Length != sizeof(CSSM_X509_NAME))) { | |
936 | printf(" ***malformed CSSM_X509_NAME\n"); | |
937 | } | |
938 | else { | |
939 | printName(name, parser); | |
940 | } | |
941 | } | |
942 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectNameCStruct)) { | |
943 | printf("Subject Name :\n"); | |
944 | CSSM_X509_NAME_PTR name = (CSSM_X509_NAME_PTR)thisData->Data; | |
945 | if((name == NULL) || (thisData->Length != sizeof(CSSM_X509_NAME))) { | |
946 | printf(" ***malformed CSSM_X509_NAME\n"); | |
947 | } | |
948 | else { | |
949 | printName(name, parser); | |
950 | } | |
951 | } | |
952 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1ValidityNotBefore)) { | |
953 | CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)thisData->Data; | |
954 | if((cssmTime == NULL) || (thisData->Length != sizeof(CSSM_X509_TIME))) { | |
955 | printf(" ***malformed CSSM_X509_TIME\n"); | |
956 | } | |
957 | else if(verbose) { | |
958 | printf("Not Before : "); printString(&cssmTime->time); | |
959 | printf(" : "); | |
960 | printTime(cssmTime); | |
961 | } | |
962 | else { | |
963 | printf("Not Before : "); | |
964 | printTime(cssmTime); | |
965 | } | |
966 | } | |
967 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1ValidityNotAfter)) { | |
968 | CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)thisData->Data; | |
969 | if((cssmTime == NULL) || (thisData->Length != sizeof(CSSM_X509_TIME))) { | |
970 | printf(" ***malformed CSSM_X509_TIME\n"); | |
971 | } | |
972 | else if(verbose) { | |
973 | printf("Not After : "); printString(&cssmTime->time); | |
974 | printf(" : "); | |
975 | printTime(cssmTime); | |
976 | } | |
977 | else { | |
978 | printf("Not After : "); | |
979 | printTime(cssmTime); | |
980 | } | |
981 | } | |
982 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SignatureAlgorithmTBS)) { | |
983 | if(verbose) { | |
984 | /* normally skip, it's the same as TBS sig alg */ | |
985 | printf("TBS Sig Algorithm : "); | |
986 | CSSM_X509_ALGORITHM_IDENTIFIER *algId = | |
987 | (CSSM_X509_ALGORITHM_IDENTIFIER *)thisData->Data; | |
988 | if((algId == NULL) || | |
989 | (thisData->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) { | |
990 | printf(" ***malformed CSSM_X509_ALGORITHM_IDENTIFIER\n"); | |
991 | } | |
992 | else { | |
993 | printSigAlg(algId, parser); | |
994 | } | |
995 | } | |
996 | } | |
997 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SignatureAlgorithm)) { | |
998 | printf("Cert Sig Algorithm : "); | |
999 | CSSM_X509_ALGORITHM_IDENTIFIER *algId = | |
1000 | (CSSM_X509_ALGORITHM_IDENTIFIER *)thisData->Data; | |
1001 | if((algId == NULL) || | |
1002 | (thisData->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) { | |
1003 | printf(" ***malformed CSSM_X509_ALGORITHM_IDENTIFIER\n"); | |
1004 | } | |
1005 | else { | |
1006 | printSigAlg(algId, parser); | |
1007 | } | |
1008 | } | |
1009 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1CertificateIssuerUniqueId)) { | |
1010 | if(verbose) { | |
1011 | printf("Issuer UniqueId : "); | |
1012 | printDerThing(BER_TAG_BIT_STRING, thisData, parser); | |
1013 | } | |
1014 | } | |
1015 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1CertificateSubjectUniqueId)) { | |
1016 | if(verbose) { | |
1017 | printf("Subject UniqueId : "); | |
1018 | printDerThing(BER_TAG_BIT_STRING, thisData, parser); | |
1019 | } | |
1020 | } | |
1021 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectPublicKeyCStruct)) { | |
1022 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *pubKeyInfo = | |
1023 | (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)thisData->Data; | |
1024 | printf("Pub Key Algorithm : "); | |
1025 | if((pubKeyInfo == NULL) || | |
1026 | (thisData->Length != sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO))) { | |
1027 | printf(" ***malformed CSSM_X509_SUBJECT_PUBLIC_KEY_INFO\n"); | |
1028 | } | |
1029 | else { | |
1030 | printSigAlg(&pubKeyInfo->algorithm, parser); | |
1031 | printf("Pub key Bytes : Length %u bytes : ", | |
1032 | (unsigned)pubKeyInfo->subjectPublicKey.Length); | |
1033 | printDataAsHex(&pubKeyInfo->subjectPublicKey, 8); | |
1034 | } | |
1035 | } | |
1036 | else if(cuCompareCssmData(thisOid, &CSSMOID_CSSMKeyStruct)) { | |
1037 | CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)thisData->Data; | |
1038 | printf("CSSM Key :\n"); | |
1039 | if((cssmKey == NULL) || | |
1040 | (thisData->Length != sizeof(CSSM_KEY))) { | |
1041 | printf(" ***malformed CSSM_KEY\n"); | |
1042 | } | |
1043 | else { | |
1044 | printKeyHeader(cssmKey->KeyHeader); | |
1045 | if(verbose) { | |
1046 | printf(" Key Blob : "); | |
1047 | printDataAsHex(&cssmKey->KeyData, 8); | |
1048 | } | |
1049 | } | |
1050 | } | |
1051 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1Signature)) { | |
1052 | printf("Signature : %u bytes : ", (unsigned)thisData->Length); | |
1053 | printDataAsHex(thisData, 8); | |
1054 | } | |
1055 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V3CertificateExtensionCStruct)) { | |
1056 | if(printExtensionCommon(*thisData, parser, verbose, false)) { | |
1057 | return; | |
1058 | } | |
1059 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)thisData->Data; | |
1060 | printf(" Unparsed data : "); printDataAsHex(&cssmExt->BERvalue, 8); | |
1061 | } | |
1062 | else if(cuCompareCssmData(thisOid, &CSSMOID_KeyUsage)) { | |
1063 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1064 | return; | |
1065 | } | |
1066 | printKeyUsage(*thisData); | |
1067 | } | |
1068 | else if(cuCompareCssmData(thisOid, &CSSMOID_BasicConstraints)) { | |
1069 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1070 | return; | |
1071 | } | |
1072 | printBasicConstraints(*thisData); | |
1073 | } | |
1074 | else if(cuCompareCssmData(thisOid, &CSSMOID_ExtendedKeyUsage)) { | |
1075 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1076 | return; | |
1077 | } | |
1078 | printExtKeyUsage(*thisData, parser); | |
1079 | } | |
1080 | else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectKeyIdentifier)) { | |
1081 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1082 | return; | |
1083 | } | |
1084 | CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)thisData->Data; | |
1085 | CSSM_DATA_PTR cdata = (CSSM_DATA_PTR)cssmExt->value.parsedValue; | |
1086 | if((cdata == NULL) || (cdata->Data == NULL)) { | |
1087 | printf("****Malformed extension (no parsedValue)\n"); | |
1088 | } | |
1089 | else { | |
1090 | printf(" Subject KeyID : "); printDataAsHex(cdata, 8); | |
1091 | } | |
1092 | } | |
1093 | else if(cuCompareCssmData(thisOid, &CSSMOID_AuthorityKeyIdentifier)) { | |
1094 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1095 | return; | |
1096 | } | |
1097 | printAuthorityKeyId(*thisData, parser); | |
1098 | } | |
1099 | else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectAltName)) { | |
1100 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1101 | return; | |
1102 | } | |
1103 | printSubjectIssuerAltName(*thisData, parser); | |
1104 | } | |
1105 | else if(cuCompareCssmData(thisOid, &CSSMOID_IssuerAltName)) { | |
1106 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1107 | return; | |
1108 | } | |
1109 | printSubjectIssuerAltName(*thisData, parser); | |
1110 | } | |
1111 | else if(cuCompareCssmData(thisOid, &CSSMOID_CertificatePolicies)) { | |
1112 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1113 | return; | |
1114 | } | |
1115 | printCertPolicies(*thisData, parser); | |
1116 | } | |
1117 | else if(cuCompareCssmData(thisOid, &CSSMOID_NetscapeCertType)) { | |
1118 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1119 | return; | |
1120 | } | |
1121 | printNetscapeCertType(*thisData); | |
1122 | } | |
1123 | else if(cuCompareCssmData(thisOid, &CSSMOID_CrlDistributionPoints)) { | |
1124 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1125 | return; | |
1126 | } | |
1127 | printDistributionPoints(*thisData, parser); | |
1128 | } | |
1129 | else if(cuCompareCssmData(thisOid, &CSSMOID_AuthorityInfoAccess)) { | |
1130 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1131 | return; | |
1132 | } | |
1133 | printAuthorityInfoAccess(*thisData, parser); | |
1134 | } | |
1135 | else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectInfoAccess)) { | |
1136 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1137 | return; | |
1138 | } | |
1139 | printAuthorityInfoAccess(*thisData, parser); | |
1140 | } | |
1141 | else if(cuCompareCssmData(thisOid, &CSSMOID_QC_Statements)) { | |
1142 | if(printExtensionCommon(*thisData, parser, verbose)) { | |
1143 | return; | |
1144 | } | |
1145 | printQualCertStatements(*thisData, parser); | |
1146 | } | |
1147 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerName)) { | |
1148 | if(verbose) { | |
1149 | printf("Normalized Issuer : "); | |
1150 | printDataAsHex(thisData, 8); | |
1151 | } | |
1152 | } | |
1153 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectName)) { | |
1154 | if(verbose) { | |
1155 | printf("Normalized Subject : "); | |
1156 | printDataAsHex(thisData, 8); | |
1157 | } | |
1158 | } | |
1159 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerNameStd)) { | |
1160 | if(verbose) { | |
1161 | printf("DER-encoded issuer : "); | |
1162 | printDataAsHex(thisData, 8); | |
1163 | } | |
1164 | } | |
1165 | else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectNameStd)) { | |
1166 | if(verbose) { | |
1167 | printf("DER-encoded subject: "); | |
1168 | printDataAsHex(thisData, 8); | |
1169 | } | |
1170 | } | |
1171 | else { | |
1172 | printf("Other field: : "); printOid(parser, thisOid); | |
1173 | } | |
1174 | } | |
1175 | ||
427c49bc | 1176 | static |
b1ab9ed8 A |
1177 | void printCrlExten( |
1178 | const CSSM_X509_EXTENSION *exten, | |
1179 | CSSM_BOOL verbose, | |
1180 | OidParser &parser) | |
1181 | { | |
1182 | const CSSM_OID *oid = &exten->extnId; | |
1183 | const void *thisData = exten->value.parsedValue; | |
1184 | ||
1185 | if(exten->format == CSSM_X509_DATAFORMAT_ENCODED) { | |
1186 | if(printCdsaExtensionCommon(exten, parser, false, verbose)) { | |
1187 | return; | |
1188 | } | |
1189 | printf(" Unparsed data : "); printDataAsHex(&exten->BERvalue, 8); | |
1190 | } | |
1191 | else if(exten->format != CSSM_X509_DATAFORMAT_PARSED) { | |
1192 | printf("***Badly formatted CSSM_X509_EXTENSION\n"); | |
1193 | return; | |
1194 | } | |
1195 | else if(cuCompareCssmData(oid, &CSSMOID_AuthorityKeyIdentifier)) { | |
1196 | if(printCdsaExtensionCommon(exten, parser, true, verbose)) { | |
1197 | return; | |
1198 | } | |
1199 | printCssmAuthorityKeyId((CE_AuthorityKeyID *)thisData, parser); | |
1200 | } | |
1201 | else if(cuCompareCssmData(oid, &CSSMOID_IssuerAltName)) { | |
1202 | if(printCdsaExtensionCommon(exten, parser, true, verbose)) { | |
1203 | return; | |
1204 | } | |
1205 | printGeneralNames((CE_GeneralNames *)thisData, parser); | |
1206 | } | |
1207 | else if(cuCompareCssmData(oid, &CSSMOID_CrlNumber)) { | |
1208 | if(printCdsaExtensionCommon(exten, parser, true, verbose)) { | |
1209 | return; | |
1210 | } | |
1211 | printf(" CRL Number : %u\n", *((unsigned *)thisData)); | |
1212 | } | |
1213 | else if(cuCompareCssmData(oid, &CSSMOID_DeltaCrlIndicator)) { | |
1214 | if(printCdsaExtensionCommon(exten, parser, true, verbose)) { | |
1215 | return; | |
1216 | } | |
1217 | printf(" Delta CRL Base : %u\n", *((unsigned *)thisData)); | |
1218 | } | |
1219 | else if(cuCompareCssmData(oid, &CSSMOID_IssuingDistributionPoint)) { | |
1220 | if(printCdsaExtensionCommon(exten, parser, true, verbose)) { | |
1221 | return; | |
1222 | } | |
1223 | printIssuingDistributionPoint((CE_IssuingDistributionPoint *)thisData, | |
1224 | parser); | |
1225 | } | |
1226 | else { | |
1227 | /* should never happen - we're out of sync with the CL */ | |
1228 | printf("UNKNOWN EXTENSION : "); printOid(parser, oid); | |
1229 | } | |
1230 | } | |
1231 | ||
427c49bc A |
1232 | |
1233 | static | |
b1ab9ed8 A |
1234 | void printCrlEntryExten( |
1235 | const CSSM_X509_EXTENSION *exten, | |
1236 | CSSM_BOOL verbose, | |
1237 | OidParser &parser) | |
1238 | { | |
1239 | const CSSM_OID *oid = &exten->extnId; | |
1240 | const void *thisData = exten->value.parsedValue; | |
1241 | ||
1242 | if(exten->format == CSSM_X509_DATAFORMAT_ENCODED) { | |
1243 | if(printCdsaExtensionCommon(exten, parser, false, verbose, true)) { | |
1244 | return; | |
1245 | } | |
1246 | printf(" Unparsed data: "); printDataAsHex(&exten->BERvalue, 8); | |
1247 | } | |
1248 | else if(exten->format != CSSM_X509_DATAFORMAT_PARSED) { | |
1249 | printf("***Badly formatted CSSM_X509_EXTENSION\n"); | |
1250 | return; | |
1251 | } | |
1252 | else if(cuCompareCssmData(oid, &CSSMOID_CrlReason)) { | |
1253 | if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) { | |
1254 | return; | |
1255 | } | |
1256 | CE_CrlReason *cr = (CE_CrlReason *)thisData; | |
1257 | const char *reason = "UNKNOWN"; | |
1258 | switch(*cr) { | |
1259 | case CE_CR_Unspecified: | |
1260 | reason = "CE_CR_Unspecified"; break; | |
1261 | case CE_CR_KeyCompromise: | |
1262 | reason = "CE_CR_KeyCompromise"; break; | |
1263 | case CE_CR_CACompromise: | |
1264 | reason = "CE_CR_CACompromise"; break; | |
1265 | case CE_CR_AffiliationChanged: | |
1266 | reason = "CE_CR_AffiliationChanged"; break; | |
1267 | case CE_CR_Superseded: | |
1268 | reason = "CE_CR_Superseded"; break; | |
1269 | case CE_CR_CessationOfOperation: | |
1270 | reason = "CE_CR_CessationOfOperation"; break; | |
1271 | case CE_CR_CertificateHold: | |
1272 | reason = "CE_CR_CertificateHold"; break; | |
1273 | case CE_CR_RemoveFromCRL: | |
1274 | reason = "CE_CR_RemoveFromCRL"; break; | |
1275 | default: | |
1276 | break; | |
1277 | } | |
1278 | printf(" CRL Reason : %s\n", reason); | |
1279 | } | |
1280 | else if(cuCompareCssmData(oid, &CSSMOID_HoldInstructionCode)) { | |
1281 | if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) { | |
1282 | return; | |
1283 | } | |
1284 | printf(" Hold Instr : "); | |
1285 | printOid(parser, (CSSM_OID_PTR)thisData); | |
1286 | } | |
1287 | else if(cuCompareCssmData(oid, &CSSMOID_InvalidityDate)) { | |
1288 | if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) { | |
1289 | return; | |
1290 | } | |
1291 | printf(" Invalid Date : "); | |
1292 | printTimeStr((CSSM_DATA_PTR)thisData); | |
1293 | } | |
1294 | else if(cuCompareCssmData(oid, &CSSMOID_CertIssuer)) { | |
1295 | if(printCdsaExtensionCommon(exten, parser, true, verbose, true)) { | |
1296 | return; | |
1297 | } | |
1298 | printGeneralNames((CE_GeneralNames *)thisData, parser); | |
1299 | } | |
1300 | else { | |
1301 | /* should never happen - we're out of sync with the CL */ | |
1302 | printf("UNKNOWN EXTENSION : "); printOid(parser, oid); | |
1303 | } | |
1304 | } | |
1305 | ||
427c49bc | 1306 | static |
b1ab9ed8 A |
1307 | void printCrlFields( |
1308 | const CSSM_X509_SIGNED_CRL *signedCrl, | |
1309 | CSSM_BOOL verbose, | |
1310 | OidParser &parser) | |
1311 | { | |
1312 | unsigned i; | |
1313 | const CSSM_X509_TBS_CERTLIST *tbsCrl = &signedCrl->tbsCertList; | |
1314 | ||
1315 | if(tbsCrl->version.Data) { | |
1316 | printf("Version : %d\n", cuDER_ToInt(&tbsCrl->version)); | |
1317 | } | |
1318 | ||
1319 | printf("TBS Sig Algorithm : "); | |
1320 | const CSSM_X509_ALGORITHM_IDENTIFIER *algId = &tbsCrl->signature; | |
1321 | printSigAlg(algId, parser); | |
1322 | ||
1323 | printf("Issuer Name :\n"); | |
1324 | printName(&tbsCrl->issuer, parser); | |
1325 | ||
1326 | printf("This Update : "); | |
1327 | printTime(&tbsCrl->thisUpdate); | |
1328 | printf("Next Update : "); | |
1329 | if(tbsCrl->nextUpdate.time.Data) { | |
1330 | printTime(&tbsCrl->nextUpdate); | |
1331 | } | |
1332 | else { | |
1333 | printf("<not present>\n"); | |
1334 | } | |
1335 | ||
1336 | CSSM_X509_REVOKED_CERT_LIST_PTR certList = tbsCrl->revokedCertificates; | |
1337 | if(certList) { | |
1338 | if(verbose) { | |
1339 | printf("Num Revoked Certs : %d\n", | |
1340 | (int)certList->numberOfRevokedCertEntries); | |
1341 | for(i=0; i<certList->numberOfRevokedCertEntries; i++) { | |
1342 | CSSM_X509_REVOKED_CERT_ENTRY_PTR entry; | |
1343 | entry = &certList->revokedCertEntry[i]; | |
1344 | printf("Revoked Cert %d :\n", (int)i); | |
1345 | printf(" Serial number : "); | |
1346 | printDataAsHex(&entry->certificateSerialNumber, 0); | |
1347 | printf(" Revocation time : "); | |
1348 | printTime(&entry->revocationDate); | |
1349 | const CSSM_X509_EXTENSIONS *cssmExtens = &entry->extensions; | |
1350 | uint32 numExtens = cssmExtens->numberOfExtensions; | |
1351 | if(numExtens == 0) { | |
1352 | continue; | |
1353 | } | |
1354 | printf(" Num Extensions : %u\n", (unsigned)numExtens); | |
1355 | for(unsigned dex=0; dex<numExtens; dex++) { | |
1356 | printCrlEntryExten(&cssmExtens->extensions[dex], verbose, | |
1357 | parser); | |
1358 | } | |
1359 | } | |
1360 | } | |
1361 | else { | |
1362 | printf("Num Revoked Certs : %d (use verbose option to see)\n", | |
1363 | (int)certList->numberOfRevokedCertEntries); | |
1364 | } | |
1365 | } | |
1366 | ||
1367 | const CSSM_X509_EXTENSIONS *crlExtens = &tbsCrl->extensions; | |
1368 | if(crlExtens->numberOfExtensions) { | |
1369 | printf("Num CRL Extensions : %d\n", | |
1370 | (int)crlExtens->numberOfExtensions); | |
1371 | for(i=0; i<crlExtens->numberOfExtensions; i++) { | |
1372 | printCrlExten(&crlExtens->extensions[i], verbose, parser); | |
1373 | } | |
1374 | } | |
1375 | ||
1376 | const CSSM_X509_SIGNATURE *sig = &signedCrl->signature; | |
1377 | if(sig->encrypted.Data) { | |
1378 | printf("Signature : %u bytes : ", (unsigned)sig->encrypted.Length); | |
1379 | printDataAsHex(&sig->encrypted, 8); | |
1380 | } | |
1381 | } | |
1382 | ||
1383 | ||
1384 | /* connect to CSSM/CL lazily, once */ | |
1385 | static CSSM_CL_HANDLE clHand = 0; | |
1386 | ||
1387 | int printCert( | |
1388 | const unsigned char *certData, | |
1389 | unsigned certLen, | |
1390 | CSSM_BOOL verbose) | |
1391 | { | |
1392 | CSSM_FIELD_PTR fieldPtr; // mallocd by CL | |
1393 | uint32 i; | |
1394 | uint32 numFields; | |
1395 | OidParser parser; | |
1396 | CSSM_DATA cert; | |
1397 | ||
1398 | if(clHand == 0) { | |
1399 | clHand = cuClStartup(); | |
1400 | if(clHand == 0) { | |
1401 | printf("***Error connecting to CSSM cert module; aborting cert " | |
1402 | "display\n"); | |
1403 | return 0; | |
1404 | } | |
1405 | } | |
1406 | cert.Data = (uint8 *)certData; | |
1407 | cert.Length = certLen; | |
1408 | ||
1409 | CSSM_RETURN crtn = CSSM_CL_CertGetAllFields(clHand, | |
1410 | &cert, | |
1411 | &numFields, | |
1412 | &fieldPtr); | |
1413 | if(crtn) { | |
1414 | cuPrintError("CSSM_CL_CertGetAllFields", crtn); | |
1415 | return crtn; | |
1416 | } | |
1417 | ||
1418 | for(i=0; i<numFields; i++) { | |
1419 | printCertField(fieldPtr[i], parser, verbose); | |
1420 | } | |
1421 | ||
1422 | crtn = CSSM_CL_FreeFields(clHand, numFields, &fieldPtr); | |
1423 | if(crtn) { | |
1424 | cuPrintError("CSSM_CL_FreeFields", crtn); | |
1425 | return crtn; | |
1426 | } | |
1427 | return 0; | |
1428 | } | |
1429 | ||
1430 | /* parse CRL */ | |
1431 | /* This one's easier, we just get one field - the whole parsed CRL */ | |
1432 | int printCrl( | |
1433 | const unsigned char *crlData, | |
1434 | unsigned crlLen, | |
1435 | CSSM_BOOL verbose) | |
1436 | { | |
1437 | CSSM_DATA_PTR value; // mallocd by CL | |
1438 | uint32 numFields; | |
1439 | OidParser parser; | |
1440 | CSSM_DATA crl; | |
1441 | CSSM_HANDLE result; | |
1442 | ||
1443 | if(clHand == 0) { | |
1444 | clHand = cuClStartup(); | |
1445 | if(clHand == 0) { | |
1446 | printf("***Error connecting to CSSM cert module; aborting CRL" | |
1447 | "display\n"); | |
1448 | return 0; | |
1449 | } | |
1450 | } | |
1451 | crl.Data = (uint8 *)crlData; | |
1452 | crl.Length = crlLen; | |
1453 | ||
1454 | CSSM_RETURN crtn = CSSM_CL_CrlGetFirstFieldValue(clHand, | |
1455 | &crl, | |
1456 | &CSSMOID_X509V2CRLSignedCrlCStruct, | |
1457 | &result, | |
1458 | &numFields, | |
1459 | &value); | |
1460 | if(crtn) { | |
1461 | cuPrintError("CSSM_CL_CrlGetFirstFieldValue", crtn); | |
1462 | return crtn; | |
1463 | } | |
1464 | if(numFields != 1) { | |
1465 | printf("***CSSM_CL_CrlGetFirstFieldValue: numFields error\n"); | |
1466 | printf(" expected 1, got %d\n", (int)numFields); | |
1467 | return 1; | |
1468 | } | |
1469 | crtn = CSSM_CL_CrlAbortQuery(clHand, result); | |
1470 | if(crtn) { | |
1471 | cuPrintError("CSSM_CL_CertAbortQuery", crtn); | |
1472 | return crtn; | |
1473 | } | |
1474 | ||
1475 | if(value == NULL) { | |
1476 | printf("***CSSM_CL_CrlGetFirstFieldValue: value error (1)\n"); | |
1477 | return 1; | |
1478 | } | |
1479 | if((value->Data == NULL) || | |
1480 | (value->Length != sizeof(CSSM_X509_SIGNED_CRL))) { | |
1481 | printf("***CSSM_CL_CrlGetFirstFieldValue: value error (2)\n"); | |
1482 | return 1; | |
1483 | } | |
1484 | const CSSM_X509_SIGNED_CRL *signedCrl = | |
1485 | (const CSSM_X509_SIGNED_CRL *)value->Data; | |
1486 | printCrlFields(signedCrl, verbose, parser); | |
1487 | ||
1488 | crtn = CSSM_CL_FreeFieldValue(clHand, | |
1489 | &CSSMOID_X509V2CRLSignedCrlCStruct, | |
1490 | value); | |
1491 | if(crtn) { | |
1492 | cuPrintError("CSSM_CL_FreeFieldValue", crtn); | |
1493 | return crtn; | |
1494 | } | |
1495 | return 0; | |
1496 | } | |
1497 | ||
1498 | ||
1499 | void printCertShutdown() | |
1500 | { | |
1501 | if(clHand != 0) { | |
1502 | CSSM_ModuleDetach(clHand); | |
1503 | } | |
1504 | } |