]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
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 | } |