]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/ocspTool/ocspTool.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / SecurityTests / clxutils / ocspTool / ocspTool.cpp
1 /*
2 * ocspTool - simple OCSP request/response generator and parser
3 */
4 #include <Security/Security.h>
5 #include <Security/SecAsn1Coder.h>
6 #include <Security/ocspTemplates.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/types.h>
12 #include <security_cdsa_utils/cuFileIo.h>
13 #include <security_cdsa_utils/cuCdsaUtils.h>
14 #include <security_cdsa_utils/cuOidParser.h>
15 #include <security_cdsa_utils/cuPrintCert.h>
16 #include <clAppUtils/CertParser.h>
17 #include <clAppUtils/timeStr.h>
18 #include <clAppUtils/identPicker.h>
19 #include <CommonCrypto/CommonDigest.h>
20 #include <security_ocspd/ocspExtensions.h>
21 #include <security_ocspd/ocspdUtils.h>
22 #include <utilLib/common.h>
23 #include "ocspUtils.h"
24 #include "ocspRequest.h"
25 #include "ocspNetwork.h"
26 #include "findOcspUrl.h"
27
28 static void usage(char **argv)
29 {
30 printf("Usage: %s cmd [option...]\n", argv[0]);
31 printf("cmds:\n");
32 printf(" g generate request\n");
33 printf(" G parse request\n");
34 printf(" r generate reply\n");
35 printf(" R parse reply\n");
36 printf(" p generate OCSP request, post, get reply (use -p and/or -o)\n");
37 printf("Options\n");
38 printf(" -c cert_file -- for generating request\n");
39 printf(" -C issuer_cert_file -- for generating request\n");
40 printf(" -i in_file -- for parsing\n");
41 printf(" -o out_file -- for generating\n");
42 printf(" -s status -- cert status: g(ood)|r(evoked)|u(nknown)\n");
43 printf(" -r crlReason -- integer 0..8\n");
44 printf(" -k keychain -- keychain containing signing cert\n");
45 printf(" -p -- parse reply from post op\n");
46 printf(" -u responderURI -- OCSP responder here, not from cert's AIA extension\n");
47 printf(" -v -- verbose; e.g., print certs\n");
48 exit(1);
49 }
50
51 void doIndent(int indent)
52 {
53 for(int dex=0; dex<indent; dex++) {
54 printf(" ");
55 }
56 }
57
58 static void printString(
59 const CSSM_DATA *str)
60 {
61 unsigned i;
62 char *cp = (char *)str->Data;
63 for(i=0; i<str->Length; i++) {
64 printf("%c", *cp++);
65 }
66 printf("\n");
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;
75 uint32 len = d->Length;
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 static void printTaggedItem(
94 const NSS_TaggedItem &ti)
95 {
96 switch(ti.tag) {
97 case BER_TAG_PRINTABLE_STRING:
98 case BER_TAG_T61_STRING:
99 case BER_TAG_IA5_STRING:
100 case BER_TAG_UTC_TIME:
101 case BER_TAG_GENERALIZED_TIME:
102 printString(&ti.item);
103 break;
104 default:
105 printDataAsHex(&ti.item, 0);
106 }
107 }
108
109 static void printName(
110 const NSS_Name &name,
111 int indent)
112 {
113 OidParser parser;
114
115 unsigned numRdns = ocspdArraySize((const void **)name.rdns);
116 for(unsigned rdnDex=0; rdnDex<numRdns; rdnDex++) {
117 NSS_RDN *rdn = name.rdns[rdnDex];
118 unsigned numATVs = ocspdArraySize((const void **)rdn->atvs);
119 for(unsigned atvDex=0; atvDex<numATVs; atvDex++) {
120 NSS_ATV *atv = rdn->atvs[atvDex];
121 char buf[OID_PARSER_STRING_SIZE];
122 parser.oidParse(atv->type.Data, atv->type.Length, buf);
123 doIndent(indent);
124 printf("%s : ", buf);
125 printTaggedItem(atv->value);
126 }
127 }
128 }
129
130 static uint8 nullParam[2] = {5, 0};
131
132 /*
133 * Given the following, create a ResponseData (to be signed by caller).
134 *
135 * cert status (CS_{Good,Revoked,Unknown})
136 * cert being verified
137 * issuer cert
138 * this update time
139 * next update time (optional)
140 * nonce (optional)
141 */
142 static int genTbsResp(
143 SecAsn1CoderRef coder, // result in this coder's address space
144 CSSM_CL_HANDLE clHand,
145 SecAsn1OCSPCertStatusTag status,
146 CE_CrlReason reason, // for CS_Revoked
147 const CSSM_DATA &subjectCert,
148 const CSSM_DATA &issuerCert,
149 unsigned thisUpdate, // required, seconds from now
150 unsigned nextUpdate, // optional, seconds from now, 0 ==> skip
151 const CSSM_DATA *nonce, // optional
152 CSSM_DATA &encodedTbs) // allocated in coder space and RETURNED
153 {
154 char *nextUpdStr = NULL;
155 CSSM_DATA nextUpdateData;
156 char *thisUpdStr = NULL;
157 CSSM_DATA *thisUpdateData;
158 SecAsn1OCSPResponseData responseData;
159 OCSPNonce *nonceExt = NULL;
160 char *producedAt = NULL;
161 SecAsn1OCSPSingleResponse singleResp;
162 SecAsn1OCSPSingleResponse *respArray[2] = {&singleResp, NULL};
163 SecAsn1OCSPResponderID responderID;
164 NSS_CertExtension *extenArray[2] = {NULL, NULL};
165
166 /* SingleResponse */
167 memset(&singleResp, 0, sizeof(singleResp));
168
169 /* SingleResponse.CertID */
170 SecAsn1OCSPCertID &certId = singleResp.certID;
171 CertParser parser(clHand);
172 CertParser issuerParser(clHand);
173 CSSM_RETURN crtn = parser.initWithData(subjectCert);
174 if(crtn) {
175 cssmPerror("CertParser.initWithData for subject cert", crtn);
176 return -1;
177 }
178 crtn = issuerParser.initWithData(issuerCert);
179 if(crtn) {
180 cssmPerror("CertParser.initWithData for issuer", crtn);
181 return -1;
182 }
183
184 /* algId refers to the hash we'll perform in issuer name and key */
185 certId.algId.algorithm = CSSMOID_SHA1;
186 certId.algId.parameters.Data = nullParam;
187 certId.algId.parameters.Length = sizeof(nullParam);
188
189 /* SHA1(issuerName) */
190 CSSM_DATA issuerName = {0, NULL};
191 issuerName.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1IssuerNameStd,
192 issuerName.Length);
193 if(issuerName.Data == NULL) {
194 printf("***Error fetching issuer name. Aborting.\n");
195 return 1;
196 }
197 uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH];
198 ocspdSha1(issuerName.Data, issuerName.Length, issuerNameHash);
199
200 /* SHA1(issuer public key) */
201 CSSM_KEY_PTR pubKey = NULL;
202 CSSM_SIZE pubKeyLen = sizeof(CSSM_KEY);
203 pubKey = (CSSM_KEY_PTR)issuerParser.fieldForOid(CSSMOID_CSSMKeyStruct, pubKeyLen);
204 if(pubKey == NULL) {
205 printf("***Error fetching public key from issuer cert. Aborting.\n");
206 return 1;
207 }
208 uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH];
209 ocspdSha1(pubKey->KeyData.Data, pubKey->KeyData.Length, pubKeyHash);
210
211 /* serial number */
212 CSSM_DATA serialNum = {0, NULL};
213 serialNum.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1SerialNumber,
214 serialNum.Length);
215 if(serialNum.Data == NULL) {
216 printf("***Error fetching serial number. Aborting.\n");
217 return 1;
218 }
219
220 /* build the CertID from those components */
221 certId.issuerNameHash.Data = issuerNameHash;
222 certId.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
223 certId.issuerPubKeyHash.Data = pubKeyHash;
224 certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
225 certId.serialNumber = serialNum;
226
227 /* SingleResponse.CertStatus - to be encoded on its own */
228 SecAsn1OCSPCertStatus certStatus;
229 memset(&certStatus, 0, sizeof(certStatus));
230 SecAsn1OCSPRevokedInfo revokedInfo;
231 char *revokedAt = NULL;
232 CSSM_DATA reasonData;
233 OSStatus ortn;
234
235 if(status == CS_Revoked) {
236 /* cook up SecAsn1OCSPRevokedInfo */
237 certStatus.revokedInfo = &revokedInfo;
238 revokedAt = appTimeAtNowPlus(-3600, TIME_GEN);
239 revokedInfo.revocationTime.Data = (uint8 *)revokedAt;
240 revokedInfo.revocationTime.Length = strlen(revokedAt);
241 uint8 theReason = reason;
242 reasonData.Data = &theReason;
243 reasonData.Length = 1;
244 revokedInfo.revocationReason = &reasonData;
245 ortn = SecAsn1EncodeItem(coder, &certStatus,
246 kSecAsn1OCSPCertStatusRevokedTemplate,
247 &singleResp.certStatus);
248 }
249 else {
250 ortn = SecAsn1EncodeItem(coder, &certStatus,
251 kSecAsn1OCSPCertStatusGoodTemplate,
252 &singleResp.certStatus);
253 }
254 if(ortn) {
255 printf("***Error encoding certStatus\n");
256 goto errOut;
257 }
258
259 /* SingleResponse.thisUpdate */
260 thisUpdStr = appTimeAtNowPlus(thisUpdate, TIME_GEN);
261 thisUpdateData = &singleResp.thisUpdate;
262 thisUpdateData->Data = (uint8 *)thisUpdStr;
263 thisUpdateData->Length = strlen(thisUpdStr);
264
265 /* SingleResponse.nextUpdate, optional */
266 if(nextUpdate) {
267 nextUpdStr = appTimeAtNowPlus(nextUpdate, TIME_GEN);
268 nextUpdateData.Data = (uint8 *)nextUpdStr;
269 nextUpdateData.Length = strlen(nextUpdStr);
270 singleResp.nextUpdate = &nextUpdateData;
271 }
272
273 /* Single Extensions - none for now */
274
275 /* Now up to ResponseData */
276 memset(&responseData, 0, sizeof(responseData));
277
278 /* skip version */
279
280 /*
281 * ResponseData.responderID: KeyHash (of signer); we already got this for CertID.
282 * WE have to encode this one separately and drop it in as an ASN_ANY.
283 */
284 responderID.byKey = certId.issuerPubKeyHash;
285 ortn = SecAsn1EncodeItem(coder, &responderID,
286 kSecAsn1OCSPResponderIDAsKeyTemplate,
287 &responseData.responderID);
288 if(ortn) {
289 printf("***Error encoding responderID\n");
290 goto errOut;
291 }
292
293 /* ResponseData.producedAt = now */
294 producedAt = appTimeAtNowPlus(0, TIME_GEN);
295 responseData.producedAt.Data = (uint8 *)producedAt;
296 responseData.producedAt.Length = strlen(producedAt);
297
298 /* ResponseData.responses - one of 'em */
299 responseData.responses = respArray;
300
301 /* ResponseData.responseExtensions - optionally one, nonce */
302 if(nonce) {
303 nonceExt = new OCSPNonce(coder, false, *nonce);
304 extenArray[0] = nonceExt->nssExt();
305 responseData.responseExtensions = extenArray;
306 }
307 else {
308 responseData.responseExtensions = NULL;
309 }
310
311 /* encode it */
312 encodedTbs.Data = NULL;
313 encodedTbs.Length = 0;
314 ortn = SecAsn1EncodeItem(coder, &responseData,
315 kSecAsn1OCSPResponseDataTemplate,
316 &encodedTbs);
317 if(ortn) {
318 printf("***Error encoding SecAsn1OCSPResponseData\n");
319 }
320 errOut:
321 /* free resources */
322 if(revokedAt) {
323 CSSM_FREE(revokedAt);
324 }
325 if(thisUpdStr) {
326 CSSM_FREE(thisUpdStr);
327 }
328 if(nextUpdStr) {
329 CSSM_FREE(nextUpdStr);
330 }
331 if(nonceExt) {
332 delete nonceExt;
333 }
334 return ortn;
335 }
336
337 static int genOcspReq(
338 CSSM_CL_HANDLE clHand,
339 const unsigned char *certFile,
340 unsigned certFileLen,
341 const unsigned char *issuerCertFile,
342 unsigned issuerCertFileLen,
343 unsigned char **outFile, // RETURNED
344 unsigned *outFileLen) // RETURNED
345 {
346 CertParser parser(clHand);
347 CertParser issuerParser(clHand);
348 CSSM_DATA certData = {certFileLen, (uint8 *)certFile};
349 CSSM_RETURN crtn;
350 crtn = parser.initWithData(certData);
351 if(crtn) {
352 cssmPerror("CertParser.initWithData for subject cert", crtn);
353 return -1;
354 }
355 certData.Data = (uint8 *)issuerCertFile;
356 certData.Length = issuerCertFileLen;
357 crtn = issuerParser.initWithData(certData);
358 if(crtn) {
359 cssmPerror("CertParser.initWithData for issuer", crtn);
360 return -1;
361 }
362
363 /*
364 * One single request, no extensions
365 */
366 SecAsn1OCSPRequest singleReq;
367 memset(&singleReq, 0, sizeof(singleReq));
368 SecAsn1OCSPCertID &certId = singleReq.reqCert;
369
370 /* algId refers to the hash we'll perform in issuer name and key */
371 certId.algId.algorithm = CSSMOID_SHA1;
372 certId.algId.parameters.Data = nullParam;
373 certId.algId.parameters.Length = sizeof(nullParam);
374
375 /* SHA1(issuerName) */
376 CSSM_DATA issuerName = {0, NULL};
377 issuerName.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1IssuerNameStd,
378 issuerName.Length);
379 if(issuerName.Data == NULL) {
380 printf("***Error fetching issuer name. Aborting.\n");
381 return 1;
382 }
383 uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH];
384 ocspdSha1(issuerName.Data, issuerName.Length, issuerNameHash);
385
386 /* SHA1(issuer public key) */
387 CSSM_KEY_PTR pubKey = NULL;
388 CSSM_SIZE pubKeyLen = sizeof(CSSM_KEY);
389 pubKey = (CSSM_KEY_PTR)issuerParser.fieldForOid(CSSMOID_CSSMKeyStruct, pubKeyLen);
390 if(pubKey == NULL) {
391 printf("***Error fetching public key from issuer cert. Aborting.\n");
392 return 1;
393 }
394 uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH];
395 ocspdSha1(pubKey->KeyData.Data, pubKey->KeyData.Length, pubKeyHash);
396
397 /* serial number */
398 CSSM_DATA serialNum = {0, NULL};
399 serialNum.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1SerialNumber,
400 serialNum.Length);
401 if(serialNum.Data == NULL) {
402 printf("***Error fetching serial number. Aborting.\n");
403 return 1;
404 }
405
406 /* build the CertID from those components */
407 certId.issuerNameHash.Data = issuerNameHash;
408 certId.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
409 certId.issuerPubKeyHash.Data = pubKeyHash;
410 certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
411 certId.serialNumber = serialNum;
412
413 /*
414 * Build top level request with one entry in requestList, no signature,
415 * one extension (a nonce)
416 */
417 SecAsn1OCSPSignedRequest signedReq;
418 SecAsn1OCSPRequest *reqArray[2] = { &singleReq, NULL };
419 SecAsn1OCSPTbsRequest &tbs = signedReq.tbsRequest;
420 memset(&signedReq, 0, sizeof(signedReq));
421 uint8 version = 0;
422 CSSM_DATA vers = {1, &version};
423 tbs.version = &vers;
424 tbs.requestList = reqArray;
425
426 /* one extension - the nonce */
427 SecAsn1CoderRef coder;
428 SecAsn1CoderCreate(&coder);
429 uint8 nonceBytes[8] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
430 CSSM_DATA nonceData = {8, nonceBytes};
431 OCSPNonce *nonce = new OCSPNonce(coder, false, nonceData);
432 NSS_CertExtension *extenArray[2] = {nonce->nssExt(), NULL};
433 tbs.requestExtensions = extenArray;
434
435 /* Encode */
436 OSStatus ortn;
437 CSSM_DATA encoded = {0, NULL};
438 ortn = SecAsn1EncodeItem(coder, &signedReq, kSecAsn1OCSPSignedRequestTemplate,
439 &encoded);
440 if(ortn) {
441 printf("***Error encoding SecAsn1OCSPSignedRequest\n");
442 }
443 else {
444 *outFile = (unsigned char *)malloc(encoded.Length);
445 *outFileLen = encoded.Length;
446 memmove(*outFile, encoded.Data, encoded.Length);
447 }
448 SecAsn1CoderRelease(coder);
449 return (int)ortn;
450 }
451
452 static void dumpCertID(
453 SecAsn1OCSPCertID *certID,
454 int indent)
455 {
456 doIndent(indent);
457 printf("algId : ");
458 printDataAsHex(&certID->algId.algorithm);
459
460 doIndent(indent);
461 printf("issuerNameHash : ");
462 printDataAsHex(&certID->issuerNameHash);
463
464 doIndent(indent);
465 printf("issuerPubKeyHash : ");
466 printDataAsHex(&certID->issuerPubKeyHash);
467
468 doIndent(indent);
469 printf("serialNumber : ");
470 printDataAsHex(&certID->serialNumber);
471 }
472
473 static void printCritical(
474 int indent,
475 OCSPExtension *ocspExt)
476 {
477 doIndent(indent);
478 printf("Critical : %s\n", ocspExt->critical() ? "true" : "false");
479 }
480
481 static void printOcspExt(
482 SecAsn1CoderRef coder,
483 NSS_CertExtension *nssExt,
484 int indent)
485 {
486 OCSPExtension *ocspExt = NULL;
487 try {
488 ocspExt = OCSPExtension::createFromNSS(coder, *nssExt);
489 }
490 catch(...) {
491 doIndent(indent);
492 printf("***Error thrown parsing extension\n");
493 return;
494 }
495 switch(ocspExt->tag()) {
496 case OET_Unknown:
497 doIndent(indent);
498 printf("Extension type: Unknown\n");
499 printCritical(indent, ocspExt);
500 return;
501 case OET_Nonce:
502 {
503 doIndent(indent);
504 printf("Extension type : Nonce\n");
505 printCritical(indent, ocspExt);
506 doIndent(indent);
507 OCSPNonce *nonce = dynamic_cast<OCSPNonce *>(ocspExt);
508 if(nonce == NULL) {
509 printf("***dynamic_cast failure in OCSPNonce!\n");
510 return;
511 }
512 printf("nonce value : ");
513 printDataAsHex(&nonce->nonce());
514 break;
515 }
516 case OET_CrlReference:
517 doIndent(indent);
518 printf("Extension type : CrlReference");
519 printCritical(indent, ocspExt);
520 /* TBD */
521 return;
522 case OET_AcceptResponse:
523 doIndent(indent);
524 printf("Extension type : AcceptResponse");
525 printCritical(indent, ocspExt);
526 /* TBD */
527 return;
528 case OET_ArchiveCutoff:
529 doIndent(indent);
530 printf("Extension type : ArchiveCutoff");
531 printCritical(indent, ocspExt);
532 /* TBD */
533 return;
534 case OET_ServiceLocator:
535 doIndent(indent);
536 printf("Extension type : ServiceLocator");
537 printCritical(indent, ocspExt);
538 /* TBD */
539 return;
540 default:
541 /* this code is out of sync with ocspExtensions.{h,cpp} */
542 doIndent(indent);
543 printf("Extension type : unrecognized - code sync error");
544 printCritical(indent, ocspExt);
545 return;
546
547 }
548 }
549
550 static int parseOcspReq(
551 CSSM_CL_HANDLE clHand,
552 unsigned char *inFile,
553 unsigned inFileLen,
554 bool verbose)
555 {
556 SecAsn1CoderRef coder;
557 SecAsn1OCSPSignedRequest signedReq;
558 SecAsn1OCSPTbsRequest &tbs = signedReq.tbsRequest;
559 OSStatus ortn;
560 int indent;
561 unsigned numExts;
562 unsigned numReqs;
563
564 SecAsn1CoderCreate(&coder);
565 memset(&signedReq, 0, sizeof(signedReq));
566
567 ortn = SecAsn1Decode(coder, inFile, inFileLen, kSecAsn1OCSPSignedRequestTemplate,
568 &signedReq);
569 if(ortn) {
570 printf("***Error decoding SecAsn1OCSPSignedRequest\n");
571 goto errOut;
572 }
573 printf("SecAsn1OCSPSignedRequest:\n");
574
575 printf("SecAsn1OCSPTbsRequest:\n");
576 indent = 2;
577 if(tbs.version) {
578 doIndent(indent);
579 printf("Version : ");
580 printDataAsHex(tbs.version);
581 }
582 if(tbs.requestorName) {
583 doIndent(indent);
584 printf("NSS_GeneralName found; print it later maybe\n");
585 }
586 numReqs = ocspdArraySize((const void **)tbs.requestList);
587 for(unsigned dex=0; dex<numReqs; dex++) {
588 SecAsn1OCSPRequest *req = tbs.requestList[dex];
589 doIndent(indent);
590 printf("Request List Entry %u\n", dex);
591 indent += 2;
592 doIndent(indent);
593 printf("CertID:\n");
594 indent += 2;
595 SecAsn1OCSPCertID *certID = &req->reqCert;
596 dumpCertID(certID, indent);
597 indent -= 2;
598 numExts = ocspdArraySize((const void **)req->extensions);
599 for(unsigned extDex=0; extDex<numExts; extDex++) {
600 doIndent(indent);
601 printf("singleExtension[%u]\n", extDex);
602 printOcspExt(coder, req->extensions[dex], indent + 2);
603 }
604 indent -= 2;
605 }
606
607 numExts = ocspdArraySize((const void **)tbs.requestExtensions);
608 for(unsigned extDex=0; extDex<numExts; extDex++) {
609 doIndent(indent);
610 printf("requestExtension[%u]\n", extDex);
611 printOcspExt(coder, tbs.requestExtensions[extDex], indent + 2);
612 }
613
614 indent -= 2;
615
616 if(signedReq.signature) {
617 printf("SecAsn1OCSPSignature:\n");
618 indent += 2;
619 doIndent(indent);
620 printf("==unparsed for now ==\n");
621 /* ... */
622 indent -= 2;
623 }
624 errOut:
625 SecAsn1CoderRelease(coder);
626 return ortn;
627 }
628
629 static int genOcspResp(
630 CSSM_CL_HANDLE clHand,
631 SecAsn1OCSPCertStatusTag status,
632 CE_CrlReason reason, // for CS_Revoked
633 const unsigned char *subjectCert,
634 unsigned subjectCertLen,
635 const unsigned char *issuerCert,
636 unsigned issuerCertLen,
637 SecIdentityRef signer,
638 unsigned char **outData,
639 unsigned *outDataLen)
640 {
641 SecAsn1CoderRef coder;
642 SecAsn1CoderCreate(&coder);
643
644 CSSM_DATA subjectCertData = {subjectCertLen, (uint8 *)subjectCert};
645 CSSM_DATA issuerCertData = {issuerCertLen, (uint8 *)issuerCert};
646 uint8 nonceBytes[8] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
647 CSSM_DATA nonceData = {8, nonceBytes};
648 CSSM_DATA tbs;
649 CSSM_DATA encoded = {0, NULL};
650 SecAsn1OCSPResponse topResponse;
651 SecAsn1OCSPResponseBytes responseBytes;
652 uint8 responseStatusByte;
653 CSSM_DATA resp = {0, NULL};
654 CSSM_DATA sig = {0, NULL};
655
656 int irtn = genTbsResp(coder, clHand, status, reason,
657 subjectCertData, issuerCertData,
658 0, // thisUpdate
659 2600 * 24, // next update
660 &nonceData,
661 tbs);
662 if(irtn) {
663 printf("***Error encoding tbsResp\n");
664 return irtn;
665 }
666
667 /*
668 * That's the TBSResponseData. Sign it.
669 */
670 OSStatus ortn;
671 SecAsn1OCSPBasicResponse basicResp;
672 memset(&basicResp, 0, sizeof(basicResp));
673 ortn = ocspSign(signer, tbs, CSSM_ALGID_SHA1WithRSA, sig);
674 if(ortn) {
675 printf("***Error signing basicResponse.\n");
676 goto errOut;
677 }
678 basicResp.algId.algorithm = CSSMOID_SHA1WithRSA;
679 basicResp.algId.parameters.Data = nullParam;
680 basicResp.algId.parameters.Length = sizeof(nullParam);
681 basicResp.tbsResponseData = tbs;
682 basicResp.sig = sig;
683 /* ASN1 encoder needs to know length in bits */
684 basicResp.sig.Length *= 8;
685 /* no certs for now */
686 /* encode SecAsn1OCSPBasicResponse */
687
688 ortn = SecAsn1EncodeItem(coder, &basicResp, kSecAsn1OCSPBasicResponseTemplate,
689 &encoded);
690 if(ortn) {
691 printf("***Error encoding SecAsn1OCSPBasicResponse\n");
692 }
693
694 /* put that into a SecAsn1OCSPResponse */
695 responseBytes.responseType = CSSMOID_PKIX_OCSP_BASIC;
696 responseBytes.response = encoded;
697 responseStatusByte = RS_Success;
698 topResponse.responseStatus.Data = &responseStatusByte;
699 topResponse.responseStatus.Length = 1;
700 topResponse.responseBytes = &responseBytes;
701 ortn = SecAsn1EncodeItem(coder, &topResponse, kSecAsn1OCSPResponseTemplate,
702 &resp);
703 if(ortn) {
704 printf("***Error encoding SecAsn1OCSPBasicResponse\n");
705 goto errOut;
706 }
707
708 /* TA DA */
709 *outData = (unsigned char *)malloc(resp.Length);
710 *outDataLen = resp.Length;
711 memmove(*outData, resp.Data, resp.Length);
712 errOut:
713 SecAsn1CoderRelease(coder);
714 if(sig.Data) {
715 APP_FREE(sig.Data);
716 }
717 return ortn;
718 }
719
720 /* decode and parse tbsResponseData, sitting in SecAsn1OCSPBasicResponse as an
721 * ASN_ANY */
722 static int parseResponseData(
723 SecAsn1CoderRef coder,
724 int indent,
725 const CSSM_DATA &tbsResponseData)
726 {
727 SecAsn1OCSPResponseData respData;
728 SecAsn1OCSPResponderID responderID;
729 uint8 tag;
730 const SecAsn1Template *templ;
731 unsigned numExts;
732
733 memset(&respData, 0, sizeof(respData));
734 OSStatus ortn = SecAsn1DecodeData(coder, &tbsResponseData,
735 kSecAsn1OCSPResponseDataTemplate, &respData);
736 if(ortn) {
737 printf("***Error decoding ResponseData\n");
738 return 1;
739 }
740 if(respData.version && respData.version->Data) {
741 doIndent(indent);
742 printf("version: %u\n", respData.version->Data[0]);
743 }
744 doIndent(indent);
745 printf("ResponderID:\n");
746 indent += 2;
747 memset(&responderID, 0, sizeof(responderID));
748 if(respData.responderID.Data == NULL) {
749 doIndent(indent);
750 printf("***Malformed(empty)***\n");
751 return 1;
752 }
753
754 /* lame-o choice processing */
755 tag = respData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK;
756 switch(tag) {
757 case RIT_Name:
758 templ = kSecAsn1OCSPResponderIDAsNameTemplate;
759 break;
760 case RIT_Key:
761 templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
762 break;
763 default:
764 doIndent(indent);
765 printf("**Unknown tag for ResponderID (%u)\n", tag);
766 return 1;
767 }
768 ortn = SecAsn1DecodeData(coder, &respData.responderID, templ, &responderID);
769 if(ortn) {
770 doIndent(indent);
771 printf("***Error decoding ResponderID\n");
772 return 1;
773 }
774 doIndent(indent);
775 switch(tag) {
776 case RIT_Name:
777 printf("byName:\n");
778 printName((NSS_Name &)responderID.byName, indent + 2);
779 break;
780 case RIT_Key:
781 printf("byKey : ");
782 printDataAsHex(&responderID.byKey);
783 break;
784 }
785 indent -= 2; // end of ResponderID
786
787 doIndent(indent);
788 printf("producedAt: ");
789 printString(&respData.producedAt);
790 unsigned numResps = ocspdArraySize((const void **)respData.responses);
791 doIndent(indent);
792 printf("Num responses: %u\n", numResps);
793 for(unsigned dex=0; dex<numResps; dex++) {
794 SecAsn1OCSPSingleResponse *resp = respData.responses[dex];
795 doIndent(indent);
796 printf("Response %u:\n", dex);
797 indent += 2;
798 doIndent(indent);
799 printf("CertID:\n");
800 dumpCertID(&resp->certID, indent + 2);
801
802 doIndent(indent);
803 printf("certStatus: ");
804 /* lame-o choice processing */
805 tag = resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK;
806 switch(tag) {
807 case CS_Good:
808 printf("Good\n");
809 break;
810 case CS_Unknown:
811 printf("Unknown\n");
812 break;
813 default:
814 printf("**MALFORMED cert status tag (%u)\n", tag);
815 break;
816 case CS_Revoked:
817 {
818 printf("Revoked\n");
819 doIndent(indent);
820 SecAsn1OCSPCertStatus certStatus;
821 memset(&certStatus, 0, sizeof(certStatus));
822 ortn = SecAsn1DecodeData(coder, &resp->certStatus,
823 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus);
824 if(ortn) {
825 doIndent(indent);
826 printf("***error parsing RevokedInfo\n");
827 break;
828 }
829 if(certStatus.revokedInfo == NULL) {
830 doIndent(indent);
831 printf("***GAK! Malformed (empty) revokedInfo\n");break;
832 }
833 printf("RevokedIndfo:\n");
834 indent += 2;
835 doIndent(indent);
836 printf("revocationTime: ");
837 printString(&certStatus.revokedInfo->revocationTime);
838 if(certStatus.revokedInfo->revocationReason) {
839 doIndent(indent);
840 printf("reason: %u\n",
841 certStatus.revokedInfo->revocationReason->Data[0]);
842 }
843 indent -= 2; // end of RevokedInfo
844 break;
845 }
846 } /* switch cert status tag */
847
848 doIndent(indent);
849 printf("thisUpdate: ");
850 printString(&resp->thisUpdate);
851
852 if(resp->nextUpdate) {
853 doIndent(indent);
854 printf("nextUpdate: ");
855 printString(resp->nextUpdate);
856 }
857
858 numExts = ocspdArraySize((const void **)resp->singleExtensions);
859 for(unsigned extDex=0; extDex<numExts; extDex++) {
860 doIndent(indent);
861 printf("singleExtensions[%u]\n", extDex);
862 printOcspExt(coder, resp->singleExtensions[extDex], indent + 2);
863 }
864
865 indent -= 2; // end of resp[dex]
866 }
867
868 numExts = ocspdArraySize((const void **)respData.responseExtensions);
869 for(unsigned extDex=0; extDex<numExts; extDex++) {
870 doIndent(indent);
871 printf("responseExtensions[%u]\n", extDex);
872 printOcspExt(coder, respData.responseExtensions[extDex], indent + 2);
873 }
874 return 0;
875 }
876
877 static int parseOcspResp(
878 CSSM_CL_HANDLE clHand,
879 unsigned char *inFile,
880 unsigned inFileLen,
881 bool verbose)
882 {
883 SecAsn1OCSPResponse topResp;
884 SecAsn1CoderRef coder;
885 OSStatus ortn;
886 int indent = 0;
887 const char *str;
888 SecAsn1OCSPBasicResponse basicResp;
889 unsigned numCerts = 0;
890
891 SecAsn1CoderCreate(&coder);
892 memset(&topResp, 0, sizeof(topResp));
893 ortn = SecAsn1Decode(coder, inFile, inFileLen, kSecAsn1OCSPResponseTemplate,
894 &topResp);
895 if(ortn) {
896 printf("***Error decoding SecAsn1OCSPResponse\n");
897 goto errOut;
898 }
899 printf("OCSPResponse:\n");
900 indent += 2;
901 doIndent(indent);
902 printf("responseStatus: ");
903 if(topResp.responseStatus.Length == 0) {
904 printf("**MALFORMED**\n");
905 }
906 else {
907 switch(topResp.responseStatus.Data[0]) {
908 case RS_Success: str = "RS_Success"; break;
909 case RS_MalformedRequest: str = "RS_MalformedRequest"; break;
910 case RS_InternalError: str = "RS_InternalError"; break;
911 case RS_TryLater: str = "RS_TryLater"; break;
912 case RS_Unused: str = "RS_Unused"; break;
913 case RS_SigRequired: str = "RS_SigRequired"; break;
914 case RS_Unauthorized: str = "RS_Unauthorized"; break;
915 default: str = "MALFORMED (unknown enum)\n"; break;
916 }
917 printf("%s (%u(d))\n", str, topResp.responseStatus.Data[0]);
918 }
919 doIndent(indent);
920 printf("ResponseBytes: ");
921 if(topResp.responseBytes == NULL) {
922 printf("empty\n");
923 goto errOut;
924 }
925 printf("\n");
926 indent += 2;
927 doIndent(indent);
928 printf("responseType: ");
929 if(appCompareCssmData(&topResp.responseBytes->responseType,
930 &CSSMOID_PKIX_OCSP_BASIC)) {
931 str = "ocsp-basic";
932 }
933 else {
934 str = "Unknown type\n";
935 }
936 printf("%s\n", str);
937
938 /* decode the BasicOCSPResponse */
939 memset(&basicResp, 0, sizeof(basicResp));
940 ortn = SecAsn1DecodeData(coder, &topResp.responseBytes->response,
941 kSecAsn1OCSPBasicResponseTemplate, &basicResp);
942 if(ortn) {
943 printf("***Error decoding BasicOCSPResponse\n");
944 goto errOut;
945 }
946
947 doIndent(indent);
948 printf("BasicOCSPResponse:\n");
949 indent += 2;
950 doIndent(indent);
951 printf("ResponseData:\n");
952 parseResponseData(coder, indent + 2, basicResp.tbsResponseData);
953 doIndent(indent);
954 printf("sig: ");
955 printDataAsHex(&basicResp.sig, 8);
956 numCerts = ocspdArraySize((const void **)basicResp.certs);
957 doIndent(indent);
958 printf("Num Certs: %u\n", numCerts);
959
960 if(verbose) {
961 for(unsigned dex=0; dex<numCerts; dex++) {
962 printf("+++++++++++++++++++++++++ Cert %u +++++++++++++++++++++++++\n", dex);
963 printCert(basicResp.certs[dex]->Data, basicResp.certs[dex]->Length,
964 CSSM_FALSE);
965 printf("+++++++++++++++++++++++ End Cert %u +++++++++++++++++++++++\n", dex);
966 }
967 }
968 indent -= 2; // end of BasicOCSPResponse
969 indent -= 2; // end of ResponseBytes
970 indent -= 2; // end of OCSPResponse
971 errOut:
972 SecAsn1CoderRelease(coder);
973 return ortn;
974 }
975
976 static int postOcspReq(
977 CSSM_CL_HANDLE clHand,
978 const unsigned char *certFile,
979 unsigned certFileLen,
980 const unsigned char *issuerCertFile,
981 unsigned issuerCertFileLen,
982 const char *responderURI,
983 bool doParse,
984 bool verbose,
985 unsigned char **outFile, // RETURNED
986 unsigned *outFileLen) // RETURNED
987 {
988 auto_ptr<CertParser> subject;
989 auto_ptr<CertParser> issuer;
990 CSSM_DATA uriData = {0, NULL};
991 CSSM_DATA *url = NULL;
992
993 try {
994 CSSM_DATA cdata = {certFileLen, (uint8 *)certFile};
995 subject.reset(new CertParser(clHand, cdata));
996 }
997 catch(...) {
998 printf("***Error parsing subject cert. Aborting.\n");
999 return -1;
1000 }
1001 try {
1002 CSSM_DATA cdata = {issuerCertFileLen, (uint8 *)issuerCertFile};
1003 issuer.reset(new CertParser(clHand, cdata));
1004 }
1005 catch(...) {
1006 printf("***Error parsing issuer cert. Aborting.\n");
1007 return -1;
1008 }
1009
1010 SecAsn1CoderRef coder;
1011 SecAsn1CoderCreate(&coder);
1012 /* subsequent errors to errOut: */
1013 int ourRtn = 0;
1014 const CSSM_DATA *derReq = NULL;
1015 auto_ptr<OCSPRequest> ocspReq;
1016
1017 if(responderURI != NULL) {
1018 uriData.Data = (uint8 *)responderURI;
1019 uriData.Length = strlen(responderURI);
1020 url = &uriData;
1021 }
1022 else {
1023 /* get OCSP URL from subject cert */
1024 url = ocspUrlFromCert(*subject, coder);
1025 if(url == NULL) {
1026 printf("Sorry, no can do.\n");
1027 ourRtn = -1;
1028 goto errOut;
1029 }
1030 }
1031
1032 /* create DER-encoded OCSP request for subject */
1033 try {
1034 ocspReq.reset(new OCSPRequest(*subject, *issuer, false));
1035 derReq = ocspReq->encode();
1036 }
1037 catch(...) {
1038 printf("***Error creating OCSP request. Aborting.\n");
1039 ourRtn = -1;
1040 goto errOut;
1041 }
1042
1043 /* do it */
1044 CSSM_DATA ocspResp;
1045 CSSM_RETURN crtn;
1046 crtn = ocspdHttpPost(coder, *url, *derReq, ocspResp);
1047 if(crtn) {
1048 printf("***Error fetching OCSP response***\n");
1049 cssmPerror("ocspdHttpPost", crtn);
1050 ourRtn = -1;
1051 goto errOut;
1052 }
1053 *outFile = ocspResp.Data;
1054 *outFileLen = ocspResp.Length;
1055 if(doParse) {
1056 parseOcspResp(clHand, ocspResp.Data, ocspResp.Length, verbose);
1057 }
1058 /* copy out */
1059 *outFile = (unsigned char *)malloc(ocspResp.Length);
1060 *outFileLen = ocspResp.Length;
1061 memmove(*outFile, ocspResp.Data, ocspResp.Length);
1062
1063 errOut:
1064 SecAsn1CoderRelease(coder);
1065 return ourRtn;
1066 }
1067
1068 typedef enum {
1069 op_genReq,
1070 op_parseReq,
1071 op_genReply,
1072 op_parseResp,
1073 op_post
1074 } ocspOp;
1075
1076 int main(int argc, char **argv)
1077 {
1078 if(argc < 2) {
1079 usage(argv);
1080 }
1081 ocspOp op;
1082 switch(argv[1][0]) {
1083 case 'g': op = op_genReq; break;
1084 case 'G': op = op_parseReq; break;
1085 case 'r': op = op_genReply; break;
1086 case 'R': op = op_parseResp; break;
1087 case 'p': op = op_post; break;
1088 default: usage(argv);
1089 }
1090
1091 /* user defined vars */
1092 char *inFile = NULL;
1093 char *outFile = NULL;
1094 char *inCertName = NULL;
1095 char *issuerCertName = NULL;
1096 SecAsn1OCSPCertStatusTag certStatus = CS_Good;
1097 CE_CrlReason crlReason = CE_CR_Unspecified;
1098 char *kcName = NULL;
1099 bool verbose = false;
1100 bool doParse = false;
1101 const char *responderURI = NULL;
1102
1103 extern int optind;
1104 optind = 2;
1105 extern char *optarg;
1106 int arg;
1107 while ((arg = getopt(argc, argv, "c:C:i:o:s:r:k:phvu:")) != -1) {
1108 switch (arg) {
1109 case 'c':
1110 inCertName = optarg;
1111 break;
1112 case 'C':
1113 issuerCertName = optarg;
1114 break;
1115 case 'i':
1116 inFile = optarg;
1117 break;
1118 case 'o':
1119 outFile = optarg;
1120 break;
1121 case 's':
1122 switch(optarg[0]) {
1123 case 'g':
1124 certStatus = CS_Good;
1125 break;
1126 case 'r':
1127 certStatus = CS_Revoked;
1128 break;
1129 case 'u':
1130 certStatus = CS_Unknown;
1131 break;
1132 default:
1133 printf("***Unrecognized certStatus***\n");
1134 usage(argv);
1135 }
1136 break;
1137 case 'r':
1138 crlReason = atoi(optarg);
1139 break;
1140 case 'k':
1141 kcName = optarg;
1142 break;
1143 case 'v':
1144 verbose = 1;
1145 break;
1146 case 'p':
1147 doParse = true;
1148 break;
1149 case 'u':
1150 responderURI = optarg;
1151 break;
1152 default:
1153 case '?':
1154 usage(argv);
1155 }
1156 }
1157 if(optind != argc) {
1158 /* this happens if you give getopt() an arg which doesn't start with '-' */
1159 usage(argv);
1160 }
1161
1162 unsigned char *certData = NULL;
1163 unsigned certDataLen = 0;
1164 unsigned char *issuerCertData = NULL;
1165 unsigned issuerCertDataLen = 0;
1166 unsigned char *inData = NULL;
1167 unsigned inDataLen = 0;
1168 unsigned char *outData = NULL;
1169 unsigned outDataLen = 0;
1170 SecKeychainRef kcRef = NULL;
1171 OSStatus ortn;
1172
1173 if(inCertName) {
1174 if(readFile(inCertName, &certData, &certDataLen)) {
1175 printf("***Error reading cert file %s. Aborting.\n", inCertName);
1176 exit(1);
1177 }
1178 }
1179 if(issuerCertName) {
1180 if(readFile(issuerCertName, &issuerCertData, &issuerCertDataLen)) {
1181 printf("***Error reading cert file %s. Aborting.\n", issuerCertName);
1182 exit(1);
1183 }
1184 }
1185 if(inFile) {
1186 if(readFile(inFile, &inData, &inDataLen)) {
1187 printf("***Error reading input file %s. Aborting.\n", inFile);
1188 exit(1);
1189 }
1190 }
1191 if(kcName) {
1192 ortn = SecKeychainOpen(kcName, &kcRef);
1193 if(ortn) {
1194 cssmPerror("SecKeychainOpen", ortn);
1195 return ortn;
1196 }
1197 }
1198 CSSM_CL_HANDLE clHand = cuClStartup();
1199
1200 switch(op) {
1201 case op_genReq:
1202 ortn = genOcspReq(clHand, certData, certDataLen,
1203 issuerCertData, issuerCertDataLen,
1204 &outData, &outDataLen);
1205 break;
1206 case op_parseReq:
1207 ortn = parseOcspReq(clHand, inData, inDataLen, verbose);
1208 break;
1209 case op_genReply:
1210 {
1211 SecIdentityRef idRef = NULL;
1212 ortn = sslSimpleIdentPicker(kcRef, &idRef);
1213 if(ortn) {
1214 printf("***Error choosing identity. Aborting.\n");
1215 exit(1);
1216 }
1217 ortn = genOcspResp(clHand, certStatus, crlReason,
1218 certData, certDataLen, issuerCertData, issuerCertDataLen,
1219 idRef, &outData, &outDataLen);
1220 CFRelease(idRef);
1221 break;
1222 }
1223 case op_parseResp:
1224 ortn = parseOcspResp(clHand, inData, inDataLen, verbose);
1225 break;
1226 case op_post:
1227 ortn = postOcspReq(clHand, certData, certDataLen,
1228 issuerCertData, issuerCertDataLen, responderURI,
1229 doParse, verbose,
1230 &outData, &outDataLen);
1231 break;
1232 default:
1233 printf("Op %s is not yet implemented.\n", argv[1]);
1234 exit(1);
1235 }
1236
1237 if(ortn == 0) {
1238 if(outData != NULL) {
1239 if(outFile== NULL) {
1240 printf("...generated %u bytes but no place to write it.\n", outDataLen);
1241 }
1242 else {
1243 ortn = writeFile(outFile, outData, outDataLen);
1244 if(ortn) {
1245 printf("***Error writing output to %s.\n", outFile);
1246 }
1247 else {
1248 printf("...wrote %u bytes to %s\n", outDataLen, outFile);
1249 }
1250 }
1251 }
1252 }
1253 return ortn;
1254 }