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 28static 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 51void doIndent(int indent) 52{ 53 for(int dex=0; dex<indent; dex++) { 54 printf(" "); 55 } 56} 57 58static 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 69static 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 93static 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 109static 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 130static 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 */ 142static 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 } 320errOut: 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 337static 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 452static 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 473static void printCritical( 474 int indent, 475 OCSPExtension *ocspExt) 476{ 477 doIndent(indent); 478 printf("Critical : %s\n", ocspExt->critical() ? "true" : "false"); 479} 480 481static 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 550static 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 } 624errOut: 625 SecAsn1CoderRelease(coder); 626 return ortn; 627} 628 629static 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); 712errOut: 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 */ 722static 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 877static 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 971errOut: 972 SecAsn1CoderRelease(coder); 973 return ortn; 974} 975 976static 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 1063errOut: 1064 SecAsn1CoderRelease(coder); 1065 return ourRtn; 1066} 1067 1068typedef enum { 1069 op_genReq, 1070 op_parseReq, 1071 op_genReply, 1072 op_parseResp, 1073 op_post 1074} ocspOp; 1075 1076int 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} 1255