2 * ocspTool - simple OCSP request/response generator and parser
4 #include <Security/Security.h>
5 #include <Security/SecAsn1Coder.h>
6 #include <Security/ocspTemplates.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"
28 static void usage(char **argv
)
30 printf("Usage: %s cmd [option...]\n", argv
[0]);
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");
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");
51 void doIndent(int indent
)
53 for(int dex
=0; dex
<indent
; dex
++) {
58 static void printString(
62 char *cp
= (char *)str
->Data
;
63 for(i
=0; i
<str
->Length
; i
++) {
69 static void printDataAsHex(
71 unsigned maxToPrint
= 0) // optional, 0 means print it all
75 uint32 len
= d
->Length
;
78 if((maxToPrint
!= 0) && (len
> maxToPrint
)) {
82 for(i
=0; i
<len
; i
++) {
83 printf("%02X ", ((unsigned char *)cp
)[i
]);
93 static void printTaggedItem(
94 const NSS_TaggedItem
&ti
)
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
);
105 printDataAsHex(&ti
.item
, 0);
109 static void printName(
110 const NSS_Name
&name
,
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
);
124 printf("%s : ", buf
);
125 printTaggedItem(atv
->value
);
130 static uint8 nullParam
[2] = {5, 0};
133 * Given the following, create a ResponseData (to be signed by caller).
135 * cert status (CS_{Good,Revoked,Unknown})
136 * cert being verified
139 * next update time (optional)
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
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
};
167 memset(&singleResp
, 0, sizeof(singleResp
));
169 /* SingleResponse.CertID */
170 SecAsn1OCSPCertID
&certId
= singleResp
.certID
;
171 CertParser
parser(clHand
);
172 CertParser
issuerParser(clHand
);
173 CSSM_RETURN crtn
= parser
.initWithData(subjectCert
);
175 cssmPerror("CertParser.initWithData for subject cert", crtn
);
178 crtn
= issuerParser
.initWithData(issuerCert
);
180 cssmPerror("CertParser.initWithData for issuer", crtn
);
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
);
189 /* SHA1(issuerName) */
190 CSSM_DATA issuerName
= {0, NULL
};
191 issuerName
.Data
= (uint8
*)parser
.fieldForOid(CSSMOID_X509V1IssuerNameStd
,
193 if(issuerName
.Data
== NULL
) {
194 printf("***Error fetching issuer name. Aborting.\n");
197 uint8 issuerNameHash
[CC_SHA1_DIGEST_LENGTH
];
198 ocspdSha1(issuerName
.Data
, issuerName
.Length
, issuerNameHash
);
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
);
205 printf("***Error fetching public key from issuer cert. Aborting.\n");
208 uint8 pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
209 ocspdSha1(pubKey
->KeyData
.Data
, pubKey
->KeyData
.Length
, pubKeyHash
);
212 CSSM_DATA serialNum
= {0, NULL
};
213 serialNum
.Data
= (uint8
*)parser
.fieldForOid(CSSMOID_X509V1SerialNumber
,
215 if(serialNum
.Data
== NULL
) {
216 printf("***Error fetching serial number. Aborting.\n");
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
;
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
;
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
);
250 ortn
= SecAsn1EncodeItem(coder
, &certStatus
,
251 kSecAsn1OCSPCertStatusGoodTemplate
,
252 &singleResp
.certStatus
);
255 printf("***Error encoding certStatus\n");
259 /* SingleResponse.thisUpdate */
260 thisUpdStr
= appTimeAtNowPlus(thisUpdate
, TIME_GEN
);
261 thisUpdateData
= &singleResp
.thisUpdate
;
262 thisUpdateData
->Data
= (uint8
*)thisUpdStr
;
263 thisUpdateData
->Length
= strlen(thisUpdStr
);
265 /* SingleResponse.nextUpdate, optional */
267 nextUpdStr
= appTimeAtNowPlus(nextUpdate
, TIME_GEN
);
268 nextUpdateData
.Data
= (uint8
*)nextUpdStr
;
269 nextUpdateData
.Length
= strlen(nextUpdStr
);
270 singleResp
.nextUpdate
= &nextUpdateData
;
273 /* Single Extensions - none for now */
275 /* Now up to ResponseData */
276 memset(&responseData
, 0, sizeof(responseData
));
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.
284 responderID
.byKey
= certId
.issuerPubKeyHash
;
285 ortn
= SecAsn1EncodeItem(coder
, &responderID
,
286 kSecAsn1OCSPResponderIDAsKeyTemplate
,
287 &responseData
.responderID
);
289 printf("***Error encoding responderID\n");
293 /* ResponseData.producedAt = now */
294 producedAt
= appTimeAtNowPlus(0, TIME_GEN
);
295 responseData
.producedAt
.Data
= (uint8
*)producedAt
;
296 responseData
.producedAt
.Length
= strlen(producedAt
);
298 /* ResponseData.responses - one of 'em */
299 responseData
.responses
= respArray
;
301 /* ResponseData.responseExtensions - optionally one, nonce */
303 nonceExt
= new OCSPNonce(coder
, false, *nonce
);
304 extenArray
[0] = nonceExt
->nssExt();
305 responseData
.responseExtensions
= extenArray
;
308 responseData
.responseExtensions
= NULL
;
312 encodedTbs
.Data
= NULL
;
313 encodedTbs
.Length
= 0;
314 ortn
= SecAsn1EncodeItem(coder
, &responseData
,
315 kSecAsn1OCSPResponseDataTemplate
,
318 printf("***Error encoding SecAsn1OCSPResponseData\n");
323 CSSM_FREE(revokedAt
);
326 CSSM_FREE(thisUpdStr
);
329 CSSM_FREE(nextUpdStr
);
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
346 CertParser
parser(clHand
);
347 CertParser
issuerParser(clHand
);
348 CSSM_DATA certData
= {certFileLen
, (uint8
*)certFile
};
350 crtn
= parser
.initWithData(certData
);
352 cssmPerror("CertParser.initWithData for subject cert", crtn
);
355 certData
.Data
= (uint8
*)issuerCertFile
;
356 certData
.Length
= issuerCertFileLen
;
357 crtn
= issuerParser
.initWithData(certData
);
359 cssmPerror("CertParser.initWithData for issuer", crtn
);
364 * One single request, no extensions
366 SecAsn1OCSPRequest singleReq
;
367 memset(&singleReq
, 0, sizeof(singleReq
));
368 SecAsn1OCSPCertID
&certId
= singleReq
.reqCert
;
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
);
375 /* SHA1(issuerName) */
376 CSSM_DATA issuerName
= {0, NULL
};
377 issuerName
.Data
= (uint8
*)parser
.fieldForOid(CSSMOID_X509V1IssuerNameStd
,
379 if(issuerName
.Data
== NULL
) {
380 printf("***Error fetching issuer name. Aborting.\n");
383 uint8 issuerNameHash
[CC_SHA1_DIGEST_LENGTH
];
384 ocspdSha1(issuerName
.Data
, issuerName
.Length
, issuerNameHash
);
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
);
391 printf("***Error fetching public key from issuer cert. Aborting.\n");
394 uint8 pubKeyHash
[CC_SHA1_DIGEST_LENGTH
];
395 ocspdSha1(pubKey
->KeyData
.Data
, pubKey
->KeyData
.Length
, pubKeyHash
);
398 CSSM_DATA serialNum
= {0, NULL
};
399 serialNum
.Data
= (uint8
*)parser
.fieldForOid(CSSMOID_X509V1SerialNumber
,
401 if(serialNum
.Data
== NULL
) {
402 printf("***Error fetching serial number. Aborting.\n");
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
;
414 * Build top level request with one entry in requestList, no signature,
415 * one extension (a nonce)
417 SecAsn1OCSPSignedRequest signedReq
;
418 SecAsn1OCSPRequest
*reqArray
[2] = { &singleReq
, NULL
};
419 SecAsn1OCSPTbsRequest
&tbs
= signedReq
.tbsRequest
;
420 memset(&signedReq
, 0, sizeof(signedReq
));
422 CSSM_DATA vers
= {1, &version
};
424 tbs
.requestList
= reqArray
;
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
;
437 CSSM_DATA encoded
= {0, NULL
};
438 ortn
= SecAsn1EncodeItem(coder
, &signedReq
, kSecAsn1OCSPSignedRequestTemplate
,
441 printf("***Error encoding SecAsn1OCSPSignedRequest\n");
444 *outFile
= (unsigned char *)malloc(encoded
.Length
);
445 *outFileLen
= encoded
.Length
;
446 memmove(*outFile
, encoded
.Data
, encoded
.Length
);
448 SecAsn1CoderRelease(coder
);
452 static void dumpCertID(
453 SecAsn1OCSPCertID
*certID
,
458 printDataAsHex(&certID
->algId
.algorithm
);
461 printf("issuerNameHash : ");
462 printDataAsHex(&certID
->issuerNameHash
);
465 printf("issuerPubKeyHash : ");
466 printDataAsHex(&certID
->issuerPubKeyHash
);
469 printf("serialNumber : ");
470 printDataAsHex(&certID
->serialNumber
);
473 static void printCritical(
475 OCSPExtension
*ocspExt
)
478 printf("Critical : %s\n", ocspExt
->critical() ? "true" : "false");
481 static void printOcspExt(
482 SecAsn1CoderRef coder
,
483 NSS_CertExtension
*nssExt
,
486 OCSPExtension
*ocspExt
= NULL
;
488 ocspExt
= OCSPExtension::createFromNSS(coder
, *nssExt
);
492 printf("***Error thrown parsing extension\n");
495 switch(ocspExt
->tag()) {
498 printf("Extension type: Unknown\n");
499 printCritical(indent
, ocspExt
);
504 printf("Extension type : Nonce\n");
505 printCritical(indent
, ocspExt
);
507 OCSPNonce
*nonce
= dynamic_cast<OCSPNonce
*>(ocspExt
);
509 printf("***dynamic_cast failure in OCSPNonce!\n");
512 printf("nonce value : ");
513 printDataAsHex(&nonce
->nonce());
516 case OET_CrlReference
:
518 printf("Extension type : CrlReference");
519 printCritical(indent
, ocspExt
);
522 case OET_AcceptResponse
:
524 printf("Extension type : AcceptResponse");
525 printCritical(indent
, ocspExt
);
528 case OET_ArchiveCutoff
:
530 printf("Extension type : ArchiveCutoff");
531 printCritical(indent
, ocspExt
);
534 case OET_ServiceLocator
:
536 printf("Extension type : ServiceLocator");
537 printCritical(indent
, ocspExt
);
541 /* this code is out of sync with ocspExtensions.{h,cpp} */
543 printf("Extension type : unrecognized - code sync error");
544 printCritical(indent
, ocspExt
);
550 static int parseOcspReq(
551 CSSM_CL_HANDLE clHand
,
552 unsigned char *inFile
,
556 SecAsn1CoderRef coder
;
557 SecAsn1OCSPSignedRequest signedReq
;
558 SecAsn1OCSPTbsRequest
&tbs
= signedReq
.tbsRequest
;
564 SecAsn1CoderCreate(&coder
);
565 memset(&signedReq
, 0, sizeof(signedReq
));
567 ortn
= SecAsn1Decode(coder
, inFile
, inFileLen
, kSecAsn1OCSPSignedRequestTemplate
,
570 printf("***Error decoding SecAsn1OCSPSignedRequest\n");
573 printf("SecAsn1OCSPSignedRequest:\n");
575 printf("SecAsn1OCSPTbsRequest:\n");
579 printf("Version : ");
580 printDataAsHex(tbs
.version
);
582 if(tbs
.requestorName
) {
584 printf("NSS_GeneralName found; print it later maybe\n");
586 numReqs
= ocspdArraySize((const void **)tbs
.requestList
);
587 for(unsigned dex
=0; dex
<numReqs
; dex
++) {
588 SecAsn1OCSPRequest
*req
= tbs
.requestList
[dex
];
590 printf("Request List Entry %u\n", dex
);
595 SecAsn1OCSPCertID
*certID
= &req
->reqCert
;
596 dumpCertID(certID
, indent
);
598 numExts
= ocspdArraySize((const void **)req
->extensions
);
599 for(unsigned extDex
=0; extDex
<numExts
; extDex
++) {
601 printf("singleExtension[%u]\n", extDex
);
602 printOcspExt(coder
, req
->extensions
[dex
], indent
+ 2);
607 numExts
= ocspdArraySize((const void **)tbs
.requestExtensions
);
608 for(unsigned extDex
=0; extDex
<numExts
; extDex
++) {
610 printf("requestExtension[%u]\n", extDex
);
611 printOcspExt(coder
, tbs
.requestExtensions
[extDex
], indent
+ 2);
616 if(signedReq
.signature
) {
617 printf("SecAsn1OCSPSignature:\n");
620 printf("==unparsed for now ==\n");
625 SecAsn1CoderRelease(coder
);
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
)
641 SecAsn1CoderRef coder
;
642 SecAsn1CoderCreate(&coder
);
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
};
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
};
656 int irtn
= genTbsResp(coder
, clHand
, status
, reason
,
657 subjectCertData
, issuerCertData
,
659 2600 * 24, // next update
663 printf("***Error encoding tbsResp\n");
668 * That's the TBSResponseData. Sign it.
671 SecAsn1OCSPBasicResponse basicResp
;
672 memset(&basicResp
, 0, sizeof(basicResp
));
673 ortn
= ocspSign(signer
, tbs
, CSSM_ALGID_SHA1WithRSA
, sig
);
675 printf("***Error signing basicResponse.\n");
678 basicResp
.algId
.algorithm
= CSSMOID_SHA1WithRSA
;
679 basicResp
.algId
.parameters
.Data
= nullParam
;
680 basicResp
.algId
.parameters
.Length
= sizeof(nullParam
);
681 basicResp
.tbsResponseData
= tbs
;
683 /* ASN1 encoder needs to know length in bits */
684 basicResp
.sig
.Length
*= 8;
685 /* no certs for now */
686 /* encode SecAsn1OCSPBasicResponse */
688 ortn
= SecAsn1EncodeItem(coder
, &basicResp
, kSecAsn1OCSPBasicResponseTemplate
,
691 printf("***Error encoding SecAsn1OCSPBasicResponse\n");
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
,
704 printf("***Error encoding SecAsn1OCSPBasicResponse\n");
709 *outData
= (unsigned char *)malloc(resp
.Length
);
710 *outDataLen
= resp
.Length
;
711 memmove(*outData
, resp
.Data
, resp
.Length
);
713 SecAsn1CoderRelease(coder
);
720 /* decode and parse tbsResponseData, sitting in SecAsn1OCSPBasicResponse as an
722 static int parseResponseData(
723 SecAsn1CoderRef coder
,
725 const CSSM_DATA
&tbsResponseData
)
727 SecAsn1OCSPResponseData respData
;
728 SecAsn1OCSPResponderID responderID
;
730 const SecAsn1Template
*templ
;
733 memset(&respData
, 0, sizeof(respData
));
734 OSStatus ortn
= SecAsn1DecodeData(coder
, &tbsResponseData
,
735 kSecAsn1OCSPResponseDataTemplate
, &respData
);
737 printf("***Error decoding ResponseData\n");
740 if(respData
.version
&& respData
.version
->Data
) {
742 printf("version: %u\n", respData
.version
->Data
[0]);
745 printf("ResponderID:\n");
747 memset(&responderID
, 0, sizeof(responderID
));
748 if(respData
.responderID
.Data
== NULL
) {
750 printf("***Malformed(empty)***\n");
754 /* lame-o choice processing */
755 tag
= respData
.responderID
.Data
[0] & SEC_ASN1_TAGNUM_MASK
;
758 templ
= kSecAsn1OCSPResponderIDAsNameTemplate
;
761 templ
= kSecAsn1OCSPResponderIDAsKeyTemplate
;
765 printf("**Unknown tag for ResponderID (%u)\n", tag
);
768 ortn
= SecAsn1DecodeData(coder
, &respData
.responderID
, templ
, &responderID
);
771 printf("***Error decoding ResponderID\n");
778 printName((NSS_Name
&)responderID
.byName
, indent
+ 2);
782 printDataAsHex(&responderID
.byKey
);
785 indent
-= 2; // end of ResponderID
788 printf("producedAt: ");
789 printString(&respData
.producedAt
);
790 unsigned numResps
= ocspdArraySize((const void **)respData
.responses
);
792 printf("Num responses: %u\n", numResps
);
793 for(unsigned dex
=0; dex
<numResps
; dex
++) {
794 SecAsn1OCSPSingleResponse
*resp
= respData
.responses
[dex
];
796 printf("Response %u:\n", dex
);
800 dumpCertID(&resp
->certID
, indent
+ 2);
803 printf("certStatus: ");
804 /* lame-o choice processing */
805 tag
= resp
->certStatus
.Data
[0] & SEC_ASN1_TAGNUM_MASK
;
814 printf("**MALFORMED cert status tag (%u)\n", tag
);
820 SecAsn1OCSPCertStatus certStatus
;
821 memset(&certStatus
, 0, sizeof(certStatus
));
822 ortn
= SecAsn1DecodeData(coder
, &resp
->certStatus
,
823 kSecAsn1OCSPCertStatusRevokedTemplate
, &certStatus
);
826 printf("***error parsing RevokedInfo\n");
829 if(certStatus
.revokedInfo
== NULL
) {
831 printf("***GAK! Malformed (empty) revokedInfo\n");break;
833 printf("RevokedIndfo:\n");
836 printf("revocationTime: ");
837 printString(&certStatus
.revokedInfo
->revocationTime
);
838 if(certStatus
.revokedInfo
->revocationReason
) {
840 printf("reason: %u\n",
841 certStatus
.revokedInfo
->revocationReason
->Data
[0]);
843 indent
-= 2; // end of RevokedInfo
846 } /* switch cert status tag */
849 printf("thisUpdate: ");
850 printString(&resp
->thisUpdate
);
852 if(resp
->nextUpdate
) {
854 printf("nextUpdate: ");
855 printString(resp
->nextUpdate
);
858 numExts
= ocspdArraySize((const void **)resp
->singleExtensions
);
859 for(unsigned extDex
=0; extDex
<numExts
; extDex
++) {
861 printf("singleExtensions[%u]\n", extDex
);
862 printOcspExt(coder
, resp
->singleExtensions
[extDex
], indent
+ 2);
865 indent
-= 2; // end of resp[dex]
868 numExts
= ocspdArraySize((const void **)respData
.responseExtensions
);
869 for(unsigned extDex
=0; extDex
<numExts
; extDex
++) {
871 printf("responseExtensions[%u]\n", extDex
);
872 printOcspExt(coder
, respData
.responseExtensions
[extDex
], indent
+ 2);
877 static int parseOcspResp(
878 CSSM_CL_HANDLE clHand
,
879 unsigned char *inFile
,
883 SecAsn1OCSPResponse topResp
;
884 SecAsn1CoderRef coder
;
888 SecAsn1OCSPBasicResponse basicResp
;
889 unsigned numCerts
= 0;
891 SecAsn1CoderCreate(&coder
);
892 memset(&topResp
, 0, sizeof(topResp
));
893 ortn
= SecAsn1Decode(coder
, inFile
, inFileLen
, kSecAsn1OCSPResponseTemplate
,
896 printf("***Error decoding SecAsn1OCSPResponse\n");
899 printf("OCSPResponse:\n");
902 printf("responseStatus: ");
903 if(topResp
.responseStatus
.Length
== 0) {
904 printf("**MALFORMED**\n");
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;
917 printf("%s (%u(d))\n", str
, topResp
.responseStatus
.Data
[0]);
920 printf("ResponseBytes: ");
921 if(topResp
.responseBytes
== NULL
) {
928 printf("responseType: ");
929 if(appCompareCssmData(&topResp
.responseBytes
->responseType
,
930 &CSSMOID_PKIX_OCSP_BASIC
)) {
934 str
= "Unknown type\n";
938 /* decode the BasicOCSPResponse */
939 memset(&basicResp
, 0, sizeof(basicResp
));
940 ortn
= SecAsn1DecodeData(coder
, &topResp
.responseBytes
->response
,
941 kSecAsn1OCSPBasicResponseTemplate
, &basicResp
);
943 printf("***Error decoding BasicOCSPResponse\n");
948 printf("BasicOCSPResponse:\n");
951 printf("ResponseData:\n");
952 parseResponseData(coder
, indent
+ 2, basicResp
.tbsResponseData
);
955 printDataAsHex(&basicResp
.sig
, 8);
956 numCerts
= ocspdArraySize((const void **)basicResp
.certs
);
958 printf("Num Certs: %u\n", numCerts
);
961 for(unsigned dex
=0; dex
<numCerts
; dex
++) {
962 printf("+++++++++++++++++++++++++ Cert %u +++++++++++++++++++++++++\n", dex
);
963 printCert(basicResp
.certs
[dex
]->Data
, basicResp
.certs
[dex
]->Length
,
965 printf("+++++++++++++++++++++++ End Cert %u +++++++++++++++++++++++\n", dex
);
968 indent
-= 2; // end of BasicOCSPResponse
969 indent
-= 2; // end of ResponseBytes
970 indent
-= 2; // end of OCSPResponse
972 SecAsn1CoderRelease(coder
);
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
,
985 unsigned char **outFile
, // RETURNED
986 unsigned *outFileLen
) // RETURNED
988 auto_ptr
<CertParser
> subject
;
989 auto_ptr
<CertParser
> issuer
;
990 CSSM_DATA uriData
= {0, NULL
};
991 CSSM_DATA
*url
= NULL
;
994 CSSM_DATA cdata
= {certFileLen
, (uint8
*)certFile
};
995 subject
.reset(new CertParser(clHand
, cdata
));
998 printf("***Error parsing subject cert. Aborting.\n");
1002 CSSM_DATA cdata
= {issuerCertFileLen
, (uint8
*)issuerCertFile
};
1003 issuer
.reset(new CertParser(clHand
, cdata
));
1006 printf("***Error parsing issuer cert. Aborting.\n");
1010 SecAsn1CoderRef coder
;
1011 SecAsn1CoderCreate(&coder
);
1012 /* subsequent errors to errOut: */
1014 const CSSM_DATA
*derReq
= NULL
;
1015 auto_ptr
<OCSPRequest
> ocspReq
;
1017 if(responderURI
!= NULL
) {
1018 uriData
.Data
= (uint8
*)responderURI
;
1019 uriData
.Length
= strlen(responderURI
);
1023 /* get OCSP URL from subject cert */
1024 url
= ocspUrlFromCert(*subject
, coder
);
1026 printf("Sorry, no can do.\n");
1032 /* create DER-encoded OCSP request for subject */
1034 ocspReq
.reset(new OCSPRequest(*subject
, *issuer
, false));
1035 derReq
= ocspReq
->encode();
1038 printf("***Error creating OCSP request. Aborting.\n");
1046 crtn
= ocspdHttpPost(coder
, *url
, *derReq
, ocspResp
);
1048 printf("***Error fetching OCSP response***\n");
1049 cssmPerror("ocspdHttpPost", crtn
);
1053 *outFile
= ocspResp
.Data
;
1054 *outFileLen
= ocspResp
.Length
;
1056 parseOcspResp(clHand
, ocspResp
.Data
, ocspResp
.Length
, verbose
);
1059 *outFile
= (unsigned char *)malloc(ocspResp
.Length
);
1060 *outFileLen
= ocspResp
.Length
;
1061 memmove(*outFile
, ocspResp
.Data
, ocspResp
.Length
);
1064 SecAsn1CoderRelease(coder
);
1076 int main(int argc
, char **argv
)
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
);
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
;
1105 extern char *optarg
;
1107 while ((arg
= getopt(argc
, argv
, "c:C:i:o:s:r:k:phvu:")) != -1) {
1110 inCertName
= optarg
;
1113 issuerCertName
= optarg
;
1124 certStatus
= CS_Good
;
1127 certStatus
= CS_Revoked
;
1130 certStatus
= CS_Unknown
;
1133 printf("***Unrecognized certStatus***\n");
1138 crlReason
= atoi(optarg
);
1150 responderURI
= optarg
;
1157 if(optind
!= argc
) {
1158 /* this happens if you give getopt() an arg which doesn't start with '-' */
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
;
1174 if(readFile(inCertName
, &certData
, &certDataLen
)) {
1175 printf("***Error reading cert file %s. Aborting.\n", inCertName
);
1179 if(issuerCertName
) {
1180 if(readFile(issuerCertName
, &issuerCertData
, &issuerCertDataLen
)) {
1181 printf("***Error reading cert file %s. Aborting.\n", issuerCertName
);
1186 if(readFile(inFile
, &inData
, &inDataLen
)) {
1187 printf("***Error reading input file %s. Aborting.\n", inFile
);
1192 ortn
= SecKeychainOpen(kcName
, &kcRef
);
1194 cssmPerror("SecKeychainOpen", ortn
);
1198 CSSM_CL_HANDLE clHand
= cuClStartup();
1202 ortn
= genOcspReq(clHand
, certData
, certDataLen
,
1203 issuerCertData
, issuerCertDataLen
,
1204 &outData
, &outDataLen
);
1207 ortn
= parseOcspReq(clHand
, inData
, inDataLen
, verbose
);
1211 SecIdentityRef idRef
= NULL
;
1212 ortn
= sslSimpleIdentPicker(kcRef
, &idRef
);
1214 printf("***Error choosing identity. Aborting.\n");
1217 ortn
= genOcspResp(clHand
, certStatus
, crlReason
,
1218 certData
, certDataLen
, issuerCertData
, issuerCertDataLen
,
1219 idRef
, &outData
, &outDataLen
);
1224 ortn
= parseOcspResp(clHand
, inData
, inDataLen
, verbose
);
1227 ortn
= postOcspReq(clHand
, certData
, certDataLen
,
1228 issuerCertData
, issuerCertDataLen
, responderURI
,
1230 &outData
, &outDataLen
);
1233 printf("Op %s is not yet implemented.\n", argv
[1]);
1238 if(outData
!= NULL
) {
1239 if(outFile
== NULL
) {
1240 printf("...generated %u bytes but no place to write it.\n", outDataLen
);
1243 ortn
= writeFile(outFile
, outData
, outDataLen
);
1245 printf("***Error writing output to %s.\n", outFile
);
1248 printf("...wrote %u bytes to %s\n", outDataLen
, outFile
);