]> git.saurik.com Git - apple/security.git/blob - CertTool/cdsaUtils/printCert.cpp
Security-54.1.tar.gz
[apple/security.git] / CertTool / cdsaUtils / printCert.cpp
1 /*
2 * Parse a cert, dump contents.
3 */
4 #include "cdsaUtils.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <Security/oidscert.h>
8 #include <Security/x509defs.h>
9 #include <Security/oidsattr.h>
10 #include <Security/cssmapple.h>
11 #include <string.h>
12 #include "printCert.h"
13 #include "oidParser.h"
14 #include "timeStr.h"
15 #include <Security/certextensions.h>
16
17 static char *months[] = {
18 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
19 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
20 };
21
22 /*
23 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to a
24 * uint32.
25 */
26 static uint32 DER_ToInt(const CSSM_DATA *DER_Data)
27 {
28 uint32 rtn = 0;
29 uint32 i = 0;
30
31 while(i < DER_Data->Length) {
32 rtn |= DER_Data->Data[i];
33 if(++i == DER_Data->Length) {
34 break;
35 }
36 rtn <<= 8;
37 }
38 return rtn;
39 }
40
41 static void printTime(const CSSM_X509_TIME *cssmTime)
42 {
43 struct tm tm;
44
45 /* ignore cssmTime->timeType for now */
46 if(appTimeStringToTm((char *)cssmTime->time.Data, cssmTime->time.Length, &tm)) {
47 printf("***Bad time string format***\n");
48 return;
49 }
50 if(tm.tm_mon > 11) {
51 printf("***Bad time string format***\n");
52 return;
53 }
54 printf("%02d:%02d:%02d %s %d, %04d\n",
55 tm.tm_hour, tm.tm_min, tm.tm_sec,
56 months[tm.tm_mon], tm.tm_mday, tm.tm_year + 1900);
57
58 }
59
60 static void printDataAsHex(
61 const CSSM_DATA *d,
62 unsigned maxToPrint = 0) // optional, 0 means print it all
63 {
64 unsigned i;
65 bool more = false;
66 uint32 len = d->Length;
67 uint8 *cp = d->Data;
68
69 if((maxToPrint != 0) && (len > maxToPrint)) {
70 len = maxToPrint;
71 more = true;
72 }
73 for(i=0; i<len; i++) {
74 printf("%02X ", ((unsigned char *)cp)[i]);
75 }
76 if(more) {
77 printf("...\n");
78 }
79 else {
80 printf("\n");
81 }
82 }
83
84 /*
85 * Identify CSSM_BER_TAG with a C string.
86 */
87 static char *tagTypeString(
88 CSSM_BER_TAG tagType)
89 {
90 static char unknownType[80];
91
92 switch(tagType) {
93 case BER_TAG_UNKNOWN:
94 return "BER_TAG_UNKNOWN";
95 case BER_TAG_BOOLEAN:
96 return "BER_TAG_BOOLEAN";
97 case BER_TAG_INTEGER:
98 return "BER_TAG_INTEGER";
99 case BER_TAG_BIT_STRING:
100 return "BER_TAG_BIT_STRING";
101 case BER_TAG_OCTET_STRING:
102 return "BER_TAG_OCTET_STRING";
103 case BER_TAG_NULL:
104 return "BER_TAG_NULL";
105 case BER_TAG_OID:
106 return "BER_TAG_OID";
107 case BER_TAG_SEQUENCE:
108 return "BER_TAG_SEQUENCE";
109 case BER_TAG_SET:
110 return "BER_TAG_SET";
111 case BER_TAG_PRINTABLE_STRING:
112 return "BER_TAG_PRINTABLE_STRING";
113 case BER_TAG_T61_STRING:
114 return "BER_TAG_T61_STRING";
115 case BER_TAG_IA5_STRING:
116 return "BER_TAG_IA5_STRING";
117 case BER_TAG_UTC_TIME:
118 return "BER_TAG_UTC_TIME";
119 case BER_TAG_GENERALIZED_TIME:
120 return "BER_TAG_GENERALIZED_TIME";
121 default:
122 sprintf(unknownType, "Other type (0x%x)", tagType);
123 return unknownType;
124 }
125 }
126
127 /*
128 * Print an OID, assumed to be in BER encoded "Intel" format
129 * Length is inferred from oid->Length
130 * Tag is implied
131 */
132 static void printOid(OidParser &parser, const CSSM_DATA *oid)
133 {
134 char strBuf[OID_PARSER_STRING_SIZE];
135
136 if(oid == NULL) {
137 printf("NULL\n");
138 return;
139 }
140 if((oid->Length == 0) || (oid->Data == NULL)) {
141 printf("EMPTY\n");
142 return;
143 }
144 parser.oidParse(oid->Data, oid->Length, strBuf);
145 printf("%s\n", strBuf);
146 }
147
148 /*
149 * Used to print generic blobs which we don't really understand.
150 * The bytesToPrint argument is usually thing->Length; it's here because snacc
151 * peports lengths of bit strings in BITS. Caller knows this and
152 * modifies bytesToPrint accordingly. In any case, bytesToPrint is the
153 * max number of valid bytes in *thing->Data.
154 */
155 #define BLOB_LENGTH_PRINT 3
156
157 static void printBlobBytes(
158 char *blobType,
159 char *quanta, // e.g., "bytes', "bits"
160 uint32 bytesToPrint,
161 const CSSM_DATA *thing)
162 {
163 uint32 dex;
164 uint32 toPrint = bytesToPrint;
165
166 if(toPrint > BLOB_LENGTH_PRINT) {
167 toPrint = BLOB_LENGTH_PRINT;
168 }
169 printf("%s; Length %u %s; data = ",
170 blobType, (unsigned)thing->Length, quanta);
171 for(dex=0; dex<toPrint; dex++) {
172 printf("0x%x ", thing->Data[dex]);
173 if(dex == (toPrint - 1)) {
174 break;
175 }
176 }
177 if(dex < bytesToPrint) {
178 printf(" ...\n");
179 }
180 else {
181 printf("\n");
182 }
183 }
184
185 /*
186 * Print an IA5String or Printable string. Null terminator is not assumed.
187 * Trailing newline is printed.
188 */
189 static void printString(
190 const CSSM_DATA *str)
191 {
192 unsigned i;
193 char *cp = (char *)str->Data;
194 for(i=0; i<str->Length; i++) {
195 printf("%c", *cp++);
196 }
197 printf("\n");
198 }
199
200 static void printDerThing(
201 CSSM_BER_TAG tagType,
202 const CSSM_DATA *thing,
203 OidParser &parser)
204 {
205 switch(tagType) {
206 case BER_TAG_INTEGER:
207 printf("%u\n", (unsigned)DER_ToInt(thing));
208 return;
209 case BER_TAG_BOOLEAN:
210 if(thing->Length != 1) {
211 printf("***malformed BER_TAG_BOOLEAN: length %d data ",
212 (unsigned)thing->Length);
213 }
214 printf("%u\n", (unsigned)DER_ToInt(thing));
215 return;
216 case BER_TAG_PRINTABLE_STRING:
217 case BER_TAG_IA5_STRING:
218 case BER_TAG_T61_STRING: // mostly printable....
219 printString(thing);
220 return;
221 case BER_TAG_OCTET_STRING:
222 printBlobBytes("Byte string", "bytes", thing->Length, thing);
223 return;
224 case BER_TAG_BIT_STRING:
225 printBlobBytes("Bit string", "bits", (thing->Length + 7) / 8, thing);
226 return;
227 case BER_TAG_SEQUENCE:
228 printBlobBytes("Sequence", "bytes", thing->Length, thing);
229 return;
230 case BER_TAG_SET:
231 printBlobBytes("Set", "bytes", thing->Length, thing);
232 return;
233 case BER_TAG_OID:
234 printf("OID = ");
235 printOid(parser, thing);
236 break;
237 default:
238 printf("not displayed (tagType = %s; length %u)\n",
239 tagTypeString(tagType), (unsigned)thing->Length);
240 break;
241
242 }
243 }
244
245 static void printSigAlg(
246 CSSM_X509_ALGORITHM_IDENTIFIER *sigAlg,
247 OidParser &parser)
248 {
249 printOid(parser, &sigAlg->algorithm);
250 if(sigAlg->parameters.Data != NULL) {
251 printf(" alg params : ");
252 printDataAsHex(&sigAlg->parameters, 8);
253 }
254 }
255
256 /* compare two OIDs, return CSSM_TRUE if identical */
257 static CSSM_BOOL compareOids(
258 const CSSM_OID *oid1,
259 const CSSM_OID *oid2)
260 {
261 if((oid1 == NULL) || (oid2 == NULL)) {
262 return CSSM_FALSE;
263 }
264 if(oid1->Length != oid2->Length) {
265 return CSSM_FALSE;
266 }
267 if(memcmp(oid1->Data, oid2->Data, oid1->Length)) {
268 return CSSM_FALSE;
269 }
270 else {
271 return CSSM_TRUE;
272 }
273 }
274
275 static CSSM_RETURN printName(
276 const CSSM_X509_NAME_PTR x509Name,
277 OidParser &parser)
278 {
279 CSSM_X509_TYPE_VALUE_PAIR *ptvp;
280 CSSM_X509_RDN_PTR rdnp;
281 unsigned rdnDex;
282 unsigned pairDex;
283 char *fieldName;
284
285 for(rdnDex=0; rdnDex<x509Name->numberOfRDNs; rdnDex++) {
286 rdnp = &x509Name->RelativeDistinguishedName[rdnDex];
287 for(pairDex=0; pairDex<rdnp->numberOfPairs; pairDex++) {
288 ptvp = &rdnp->AttributeTypeAndValue[pairDex];
289 if(compareOids(&ptvp->type, &CSSMOID_CountryName)) {
290 fieldName = "Country ";
291 }
292 else if(compareOids(&ptvp->type, &CSSMOID_OrganizationName)) {
293 fieldName = "Org ";
294 }
295 else if(compareOids(&ptvp->type, &CSSMOID_LocalityName)) {
296 fieldName = "Locality ";
297 }
298 else if(compareOids(&ptvp->type, &CSSMOID_OrganizationalUnitName)) {
299 fieldName = "OrgUnit ";
300 }
301 else if(compareOids(&ptvp->type, &CSSMOID_CommonName)) {
302 fieldName = "Common Name ";
303 }
304 else if(compareOids(&ptvp->type, &CSSMOID_Surname)) {
305 fieldName = "Surname ";
306 }
307 else if(compareOids(&ptvp->type, &CSSMOID_Title)) {
308 fieldName = "Title ";
309 }
310 else if(compareOids(&ptvp->type, &CSSMOID_Surname)) {
311 fieldName = "Surname ";
312 }
313 else if(compareOids(&ptvp->type, &CSSMOID_StateProvinceName)) {
314 fieldName = "State ";
315 }
316 else if(compareOids(&ptvp->type, &CSSMOID_CollectiveStateProvinceName)) {
317 fieldName = "Coll. State ";
318 }
319 else if(compareOids(&ptvp->type, &CSSMOID_EmailAddress)) {
320 /* deprecated, used by Thawte */
321 fieldName = "Email addrs ";
322 }
323 else {
324 fieldName = "Other name ";
325 }
326 printf(" %s : ", fieldName);
327 printDerThing(ptvp->valueType, &ptvp->value, parser);
328 } /* for each type/value pair */
329 } /* for each RDN */
330
331 return CSSM_OK;
332 }
333
334 static void printKeyHeader(
335 const CSSM_KEYHEADER &hdr)
336 {
337 printf(" Algorithm : ");
338 switch(hdr.AlgorithmId) {
339 case CSSM_ALGID_RSA:
340 printf("RSA\n");
341 break;
342 case CSSM_ALGID_DSA:
343 printf("DSA\n");
344 break;
345 case CSSM_ALGID_FEE:
346 printf("FEE\n");
347 break;
348 default:
349 printf("Unknown(%d(d), 0x%x)\n", (unsigned)hdr.AlgorithmId,
350 (unsigned)hdr.AlgorithmId);
351 }
352 printf(" Key Size : %u bits\n", (unsigned)hdr.LogicalKeySizeInBits);
353 printf(" Key Use : ");
354 CSSM_KEYUSE usage = hdr.KeyUsage;
355 if(usage & CSSM_KEYUSE_ANY) {
356 printf("CSSM_KEYUSE_ANY ");
357 }
358 if(usage & CSSM_KEYUSE_ENCRYPT) {
359 printf("CSSM_KEYUSE_ENCRYPT ");
360 }
361 if(usage & CSSM_KEYUSE_DECRYPT) {
362 printf("CSSM_KEYUSE_DECRYPT ");
363 }
364 if(usage & CSSM_KEYUSE_SIGN) {
365 printf("CSSM_KEYUSE_SIGN ");
366 }
367 if(usage & CSSM_KEYUSE_VERIFY) {
368 printf("CSSM_KEYUSE_VERIFY ");
369 }
370 if(usage & CSSM_KEYUSE_SIGN_RECOVER) {
371 printf("CSSM_KEYUSE_SIGN_RECOVER ");
372 }
373 if(usage & CSSM_KEYUSE_VERIFY_RECOVER) {
374 printf("CSSM_KEYUSE_VERIFY_RECOVER ");
375 }
376 if(usage & CSSM_KEYUSE_WRAP) {
377 printf("CSSM_KEYUSE_WRAP ");
378 }
379 if(usage & CSSM_KEYUSE_UNWRAP) {
380 printf("CSSM_KEYUSE_UNWRAP ");
381 }
382 if(usage & CSSM_KEYUSE_DERIVE) {
383 printf("CSSM_KEYUSE_DERIVE ");
384 }
385 printf("\n");
386
387 }
388
389 /*
390 * Print contents of a CE_GeneralNames as best we can.
391 */
392 static void printGeneralNames(
393 CE_GeneralNames *generalNames,
394 OidParser &parser)
395 {
396 unsigned i;
397 CE_GeneralName *name;
398
399 for(i=0; i<generalNames->numNames; i++) {
400 name = &generalNames->generalName[i];
401 switch(name->nameType) {
402 case GNT_RFC822Name:
403 printf(" RFC822Name : ");
404 printString(&name->name);
405 break;
406 case GNT_DNSName:
407 printf(" DNSName : ");
408 printString(&name->name);
409 break;
410 case GNT_URI:
411 printf(" URI : ");
412 printString(&name->name);
413 break;
414 case GNT_IPAddress:
415 printf(" IP Address : ");
416 for(unsigned i=0; i<name->name.Length; i++) {
417 printf("%d", name->name.Data[i]);
418 if(i < (name->name.Length - 1)) {
419 printf(".");
420 }
421 }
422 printf("\n");
423 break;
424 case GNT_RegisteredID:
425 printf(" RegisteredID : ");
426 printOid(parser, &name->name);
427 break;
428 case GNT_X400Address:
429 /* ORAddress, a very complicated struct - punt */
430 printf(" X400Address : ");
431 printBlobBytes("Sequence", "bytes", name->name.Length, &name->name);
432 break;
433 case GNT_DirectoryName:
434 /* encoded Name (i.e. CSSM_X509_NAME) */
435 printf(" Dir Name : ");
436 printBlobBytes("Byte string", "bytes", name->name.Length, &name->name);
437 break;
438 case GNT_EdiPartyName:
439 /* sequence EDIPartyName */
440 printf(" EdiPartyName : ");
441 printBlobBytes("Sequence", "bytes", name->name.Length, &name->name);
442 break;
443 case GNT_OtherName:
444 printf(" OtherName : ");
445 printOid(parser, &name->name);
446 break;
447 }
448 }
449 }
450
451 static int printExtensionCommon(
452 const CSSM_DATA &value,
453 OidParser &parser,
454 bool expectParsed = true)
455 {
456 if(value.Length != sizeof(CSSM_X509_EXTENSION)) {
457 printf("***malformed CSSM_FIELD (1)\n");
458 return 1;
459 }
460 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
461 printf("Extension struct : "); printOid(parser, &cssmExt->extnId);
462 printf(" Critical : %s\n", cssmExt->critical ? "TRUE" : "FALSE");
463 switch(cssmExt->format) {
464 case CSSM_X509_DATAFORMAT_ENCODED:
465 if(expectParsed) {
466 printf("Bad CSSM_X509_EXTENSION; expected FORMAT_PARSED\n");
467 return 1;
468 }
469 if((cssmExt->BERvalue.Data == NULL) ||
470 (cssmExt->value.parsedValue != NULL)) {
471 printf("***Malformed CSSM_X509_EXTENSION (1)\n");
472 return 1;
473 }
474 break;
475 case CSSM_X509_DATAFORMAT_PARSED:
476 if(!expectParsed) {
477 printf("Bad CSSM_X509_EXTENSION; expected FORMAT_ENCODED\n");
478 return 1;
479 }
480 if((cssmExt->BERvalue.Data != NULL) ||
481 (cssmExt->value.parsedValue == NULL)) {
482 printf("***Malformed CSSM_X509_EXTENSION (2)\n");
483 return 1;
484 }
485 break;
486 default:
487 printf("***Unknown CSSM_X509_EXTENSION.format\n");
488 return 1;
489 }
490 return 0;
491 }
492
493 static void printKeyUsage(
494 const CSSM_DATA &value)
495 {
496 CE_KeyUsage usage;
497 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
498
499 usage = *((CE_KeyUsage *)cssmExt->value.parsedValue);
500 printf(" usage : ");
501 if(usage & CE_KU_DigitalSignature) {
502 printf("DigitalSignature ");
503 }
504 if(usage & CE_KU_NonRepudiation) {
505 printf("NonRepudiation ");
506 }
507 if(usage & CE_KU_KeyEncipherment) {
508 printf("KeyEncipherment ");
509 }
510 if(usage & CE_KU_DataEncipherment) {
511 printf("DataEncipherment ");
512 }
513 if(usage & CE_KU_KeyAgreement) {
514 printf("KeyAgreement ");
515 }
516 if(usage & CE_KU_KeyCertSign) {
517 printf("KeyCertSign ");
518 }
519 if(usage & CE_KU_CRLSign) {
520 printf("CRLSign ");
521 }
522 if(usage & CE_KU_EncipherOnly) {
523 printf("EncipherOnly ");
524 }
525 if(usage & CE_KU_DecipherOnly) {
526 printf("DecipherOnly ");
527 }
528 printf("\n");
529
530 }
531
532 static void printBasicConstraints(
533 const CSSM_DATA &value)
534 {
535 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
536 CE_BasicConstraints *bc = (CE_BasicConstraints *)cssmExt->value.parsedValue;
537 printf(" CA : %s\n", bc->cA ? "TRUE" : "FALSE");
538 if(bc->pathLenConstraintPresent) {
539 printf(" pathLenConstr : %u\n",
540 (unsigned)bc->pathLenConstraint);
541 }
542 }
543
544 static void printExtKeyUsage(
545 const CSSM_DATA &value,
546 OidParser &parser)
547 {
548 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
549 CE_ExtendedKeyUsage *eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue;
550 unsigned oidDex;
551 for(oidDex=0; oidDex<eku->numPurposes; oidDex++) {
552 printf(" purpose %2d : ", oidDex);
553 printOid(parser, &eku->purposes[oidDex]);
554 }
555 }
556
557 static void printAuthorityKeyId(
558 const CSSM_DATA &value,
559 OidParser &parser)
560 {
561 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
562 CE_AuthorityKeyID *akid = (CE_AuthorityKeyID *)cssmExt->value.parsedValue;
563 if(akid->keyIdentifierPresent) {
564 printf(" keyIdentifier : "); printDataAsHex(&akid->keyIdentifier, 8);
565 }
566 if(akid->generalNamesPresent) {
567 printGeneralNames(akid->generalNames, parser);
568 }
569 if(akid->serialNumberPresent) {
570 printf(" serialNumber : "); printDataAsHex(&akid->serialNumber, 8);
571 }
572 }
573
574 static void printSubjectAltName(
575 const CSSM_DATA &value,
576 OidParser &parser)
577 {
578 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
579 CE_GeneralNames *san = (CE_GeneralNames *)cssmExt->value.parsedValue;
580 printGeneralNames(san, parser);
581 }
582
583 static void printCertPolicies(
584 const CSSM_DATA &value,
585 OidParser &parser)
586 {
587 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
588 CE_CertPolicies *cdsaObj = (CE_CertPolicies *)cssmExt->value.parsedValue;
589 for(unsigned polDex=0; polDex<cdsaObj->numPolicies; polDex++) {
590 CE_PolicyInformation *cPolInfo = &cdsaObj->policies[polDex];
591 printf(" Policy %2d : ID ", polDex);
592 printOid(parser, &cPolInfo->certPolicyId);
593 for(unsigned qualDex=0; qualDex<cPolInfo->numPolicyQualifiers; qualDex++) {
594 CE_PolicyQualifierInfo *cQualInfo = &cPolInfo->policyQualifiers[qualDex];
595 printf(" Qual %2d : ID ", qualDex);
596 printOid(parser, &cQualInfo->policyQualifierId);
597 if(cuCompareCssmData(&cQualInfo->policyQualifierId,
598 &CSSMOID_QT_CPS)) {
599 printf(" CPS : ");
600 printString(&cQualInfo->qualifier);
601 }
602 else {
603 printf(" unparsed : ");
604 printDataAsHex(&cQualInfo->qualifier, 8);
605 }
606 }
607 }
608 }
609
610 static void printNetscapeCertType(
611 const CSSM_DATA &value)
612 {
613 CE_NetscapeCertType certType;
614 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)value.Data;
615
616 certType = *((CE_NetscapeCertType *)cssmExt->value.parsedValue);
617 printf(" certType : ");
618 if(certType & CE_NCT_SSL_Client) {
619 printf("SSL_Client ");
620 }
621 if(certType & CE_NCT_SSL_Server) {
622 printf("SSL_Server ");
623 }
624 if(certType & CE_NCT_SMIME) {
625 printf("S/MIME ");
626 }
627 if(certType & CE_NCT_ObjSign) {
628 printf("ObjectSign ");
629 }
630 if(certType & CE_NCT_Reserved) {
631 printf("Reserved ");
632 }
633 if(certType & CE_NCT_SSL_CA) {
634 printf("SSL_CA ");
635 }
636 if(certType & CE_NCT_SMIME_CA) {
637 printf("SMIME_CA ");
638 }
639 if(certType & CE_NCT_ObjSignCA) {
640 printf("ObjSignCA ");
641 }
642 printf("\n");
643 }
644
645 /* print one field */
646 void printCertField(
647 const CSSM_FIELD &field,
648 OidParser &parser,
649 CSSM_BOOL verbose)
650 {
651 const CSSM_DATA *thisData = &field.FieldValue;
652 const CSSM_OID *thisOid = &field.FieldOid;
653
654 if(cuCompareCssmData(thisOid, &CSSMOID_X509V1Version)) {
655 if(verbose) {
656 printf("Version : %u\n",
657 (unsigned)DER_ToInt(thisData));
658 }
659 }
660 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SerialNumber)) {
661 printf("Serial Number : "); printDataAsHex(thisData, 0);
662 }
663 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerNameCStruct)) {
664 printf("Issuer Name :\n");
665 CSSM_X509_NAME_PTR name = (CSSM_X509_NAME_PTR)thisData->Data;
666 if((name == NULL) || (thisData->Length != sizeof(CSSM_X509_NAME))) {
667 printf(" ***malformed CSSM_X509_NAME\n");
668 }
669 else {
670 printName(name, parser);
671 }
672 }
673 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectNameCStruct)) {
674 printf("Subject Name :\n");
675 CSSM_X509_NAME_PTR name = (CSSM_X509_NAME_PTR)thisData->Data;
676 if((name == NULL) || (thisData->Length != sizeof(CSSM_X509_NAME))) {
677 printf(" ***malformed CSSM_X509_NAME\n");
678 }
679 else {
680 printName(name, parser);
681 }
682 }
683 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1ValidityNotBefore)) {
684 CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)thisData->Data;
685 if((cssmTime == NULL) || (thisData->Length != sizeof(CSSM_X509_TIME))) {
686 printf(" ***malformed CSSM_X509_TIME\n");
687 }
688 else if(verbose) {
689 printf("Not Before : "); printString(&cssmTime->time);
690 printf(" : ");
691 printTime(cssmTime);
692 }
693 else {
694 printf("Not Before : ");
695 printTime(cssmTime);
696 }
697 }
698 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1ValidityNotAfter)) {
699 CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)thisData->Data;
700 if((cssmTime == NULL) || (thisData->Length != sizeof(CSSM_X509_TIME))) {
701 printf(" ***malformed CSSM_X509_TIME\n");
702 }
703 else if(verbose) {
704 printf("Not After : "); printString(&cssmTime->time);
705 printf(" : ");
706 printTime(cssmTime);
707 }
708 else {
709 printf("Not After : ");
710 printTime(cssmTime);
711 }
712 }
713 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SignatureAlgorithmTBS)) {
714 if(verbose) {
715 /* normally skip, it's the same as TBS sig alg */
716 printf("TBS Sig Algorithm : ");
717 CSSM_X509_ALGORITHM_IDENTIFIER *algId =
718 (CSSM_X509_ALGORITHM_IDENTIFIER *)thisData->Data;
719 if((algId == NULL) ||
720 (thisData->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) {
721 printf(" ***malformed CSSM_X509_ALGORITHM_IDENTIFIER\n");
722 }
723 else {
724 printSigAlg(algId, parser);
725 }
726 }
727 }
728 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SignatureAlgorithm)) {
729 printf("Cert Sig Algorithm : ");
730 CSSM_X509_ALGORITHM_IDENTIFIER *algId =
731 (CSSM_X509_ALGORITHM_IDENTIFIER *)thisData->Data;
732 if((algId == NULL) ||
733 (thisData->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER))) {
734 printf(" ***malformed CSSM_X509_ALGORITHM_IDENTIFIER\n");
735 }
736 else {
737 printSigAlg(algId, parser);
738 }
739 }
740 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1CertificateIssuerUniqueId)) {
741 if(verbose) {
742 printf("Issuer UniqueId : ");
743 printDerThing(BER_TAG_BIT_STRING, thisData, parser);
744 }
745 }
746 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1CertificateSubjectUniqueId)) {
747 if(verbose) {
748 printf("Subject UniqueId : ");
749 printDerThing(BER_TAG_BIT_STRING, thisData, parser);
750 }
751 }
752 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectPublicKeyCStruct)) {
753 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *pubKeyInfo =
754 (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)thisData->Data;
755 printf("Pub Key Algorithm : ");
756 if((pubKeyInfo == NULL) ||
757 (thisData->Length != sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO))) {
758 printf(" ***malformed CSSM_X509_SUBJECT_PUBLIC_KEY_INFO\n");
759 }
760 else {
761 printSigAlg(&pubKeyInfo->algorithm, parser);
762 printf("Pub key Bytes : Length %u bytes : ",
763 (unsigned)pubKeyInfo->subjectPublicKey.Length);
764 printDataAsHex(&pubKeyInfo->subjectPublicKey, 8);
765 }
766 }
767 else if(cuCompareCssmData(thisOid, &CSSMOID_CSSMKeyStruct)) {
768 CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)thisData->Data;
769 printf("CSSM Key :\n");
770 if((cssmKey == NULL) ||
771 (thisData->Length != sizeof(CSSM_KEY))) {
772 printf(" ***malformed CSSM_KEY\n");
773 }
774 else {
775 printKeyHeader(cssmKey->KeyHeader);
776 }
777 }
778 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1Signature)) {
779 printf("Signature : %u bytes : ",
780 (unsigned)thisData->Length);
781 printDataAsHex(thisData, 8);
782 }
783 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V3CertificateExtensionCStruct)) {
784 if(printExtensionCommon(*thisData, parser, false)) {
785 return;
786 }
787 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)thisData->Data;
788 printf(" Unparsed data : "); printDataAsHex(&cssmExt->BERvalue, 8);
789 }
790 else if(cuCompareCssmData(thisOid, &CSSMOID_KeyUsage)) {
791 if(printExtensionCommon(*thisData, parser)) {
792 return;
793 }
794 printKeyUsage(*thisData);
795 }
796 else if(cuCompareCssmData(thisOid, &CSSMOID_BasicConstraints)) {
797 if(printExtensionCommon(*thisData, parser)) {
798 return;
799 }
800 printBasicConstraints(*thisData);
801 }
802 else if(cuCompareCssmData(thisOid, &CSSMOID_ExtendedKeyUsage)) {
803 if(printExtensionCommon(*thisData, parser)) {
804 return;
805 }
806 printExtKeyUsage(*thisData, parser);
807 }
808 else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectKeyIdentifier)) {
809 if(printExtensionCommon(*thisData, parser)) {
810 return;
811 }
812 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)thisData->Data;
813 CSSM_DATA_PTR cdata = (CSSM_DATA_PTR)cssmExt->value.parsedValue;
814 if((cdata == NULL) || (cdata->Data == NULL)) {
815 printf("****Malformed extension (no parsedValue)\n");
816 }
817 else {
818 printf(" Subject KeyID : "); printDataAsHex(cdata, 8);
819 }
820 }
821 else if(cuCompareCssmData(thisOid, &CSSMOID_AuthorityKeyIdentifier)) {
822 if(printExtensionCommon(*thisData, parser)) {
823 return;
824 }
825 printAuthorityKeyId(*thisData, parser);
826 }
827 else if(cuCompareCssmData(thisOid, &CSSMOID_SubjectAltName)) {
828 if(printExtensionCommon(*thisData, parser)) {
829 return;
830 }
831 printSubjectAltName(*thisData, parser);
832 }
833 else if(cuCompareCssmData(thisOid, &CSSMOID_CertificatePolicies)) {
834 if(printExtensionCommon(*thisData, parser)) {
835 return;
836 }
837 printCertPolicies(*thisData, parser);
838 }
839 else if(cuCompareCssmData(thisOid, &CSSMOID_NetscapeCertType)) {
840 if(printExtensionCommon(*thisData, parser)) {
841 return;
842 }
843 printNetscapeCertType(*thisData);
844 }
845 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1IssuerName)) {
846 if(verbose) {
847 printf("Normalized Issuer : ");
848 printDataAsHex(thisData, 8);
849 }
850 }
851 else if(cuCompareCssmData(thisOid, &CSSMOID_X509V1SubjectName)) {
852 if(verbose) {
853 printf("Normalized Subject : ");
854 printDataAsHex(thisData, 8);
855 }
856 }
857 else {
858 printf("other field: : "); printOid(parser, thisOid);
859 }
860 }
861
862 /* connect to CSSM/CL lazily, once */
863 static CSSM_CL_HANDLE clHand = 0;
864
865 int printCert(
866 const unsigned char *certData,
867 unsigned certLen,
868 CSSM_BOOL verbose)
869 {
870 CSSM_FIELD_PTR fieldPtr; // mallocd by CL
871 uint32 i;
872 uint32 numFields;
873 OidParser parser;
874 CSSM_DATA cert;
875
876 if(clHand == 0) {
877 clHand = cuClStartup();
878 if(clHand == 0) {
879 printf("***Error connecting to CSSM cert module; aborting cert display\n");
880 return 0;
881 }
882 }
883 cert.Data = (uint8 *)certData;
884 cert.Length = certLen;
885
886 CSSM_RETURN crtn = CSSM_CL_CertGetAllFields(clHand,
887 &cert,
888 &numFields,
889 &fieldPtr);
890 if(crtn) {
891 cuPrintError("CSSM_CL_CertGetAllFields", crtn);
892 return crtn;
893 }
894
895 for(i=0; i<numFields; i++) {
896 printCertField(fieldPtr[i], parser, verbose);
897 }
898
899 crtn = CSSM_CL_FreeFields(clHand, numFields, &fieldPtr);
900 if(crtn) {
901 cuPrintError("CSSM_CL_FreeFields", crtn);
902 return crtn;
903 }
904 return 0;
905 }
906
907 void printCertShutdown()
908 {
909 if(clHand != 0) {
910 CSSM_ModuleDetach(clHand);
911 }
912 }