1/* 2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * tpOcspCertVfy.cpp - OCSP cert verification routines 26 */ 27 28#include "tpOcspCertVfy.h" 29#include "tpdebugging.h" 30#include "certGroupUtils.h" 31#include <Security/oidscert.h> 32#include <CommonCrypto/CommonDigest.h> 33#include <security_ocspd/ocspdUtils.h> 34 35/* 36 * Is signerCert authorized to sign OCSP responses by issuerCert? IssuerCert is 37 * assumed to be (i.e., must, but we don't check that here) the signer of the 38 * cert being verified, which is not in the loop for this op. Just a bool returned; 39 * it's autoritized or it's not. 40 */ 41static bool tpIsAuthorizedOcspSigner( 42 TPCertInfo &issuerCert, // issuer of cert being verified 43 TPCertInfo &signerCert) // potential signer of OCSP response 44{ 45 CSSM_DATA_PTR fieldValue = NULL; // mallocd by CL 46 CSSM_RETURN crtn; 47 bool ourRtn = false; 48 CE_ExtendedKeyUsage *eku = NULL; 49 bool foundEku = false; 50 51 /* 52 * First see if issuerCert issued signerCert (No signature vfy yet, just 53 * subject/issuer check). 54 */ 55 if(!issuerCert.isIssuerOf(signerCert)) { 56 return false; 57 } 58 59 /* Fetch ExtendedKeyUse field from signerCert */ 60 crtn = signerCert.fetchField(&CSSMOID_ExtendedKeyUsage, &fieldValue); 61 if(crtn) { 62 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU"); 63 return false; 64 } 65 CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data; 66 if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) { 67 tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format"); 68 goto errOut; 69 } 70 eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue; 71 72 /* Look for OID_KP_OCSPSigning */ 73 for(unsigned dex=0; dex<eku->numPurposes; dex++) { 74 if(tpCompareCssmData(&eku->purposes[dex], &CSSMOID_OCSPSigning)) { 75 foundEku = true; 76 break; 77 } 78 } 79 if(!foundEku) { 80 tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no OCSP " 81 "signing EKU"); 82 goto errOut; 83 } 84 85 /* 86 * OK, signerCert is authorized by *someone* to sign OCSP requests, and 87 * it claims to be issued by issuer. Sig verify to be sure. 88 * FIXME this is not handling partial public keys, which would be a colossal 89 * mess to handle in this module...so we don't. 90 */ 91 crtn = signerCert.verifyWithIssuer(&issuerCert, NULL); 92 if(crtn == CSSM_OK) { 93 tpOcspDebug("tpIsAuthorizedOcspSigner: FOUND authorized signer"); 94 ourRtn = true; 95 } 96 else { 97 /* This is a highly irregular situation... */ 98 tpOcspDebug("tpIsAuthorizedOcspSigner: signer sig verify FAIL"); 99 } 100errOut: 101 if(fieldValue != NULL) { 102 signerCert.freeField(&CSSMOID_ExtendedKeyUsage, fieldValue); 103 } 104 return ourRtn; 105} 106 107/* 108 * Check ResponderID linkage between an OCSPResponse and a cert we believe to 109 * be the issuer of both that response and the cert being verified. Returns 110 * true if OK. 111 */ 112static 113bool tpOcspResponderIDCheck( 114 OCSPResponse &ocspResp, 115 TPCertInfo &signer) 116{ 117 bool shouldBeSigner = false; 118 if(ocspResp.responderIDTag() == RIT_Name) { 119 /* 120 * Name inside response must == signer's SubjectName. 121 * Note we can't use signer.subjectName(); that's normalized. 122 */ 123 124 const CSSM_DATA *respIdName = ocspResp.encResponderName(); 125 CSSM_DATA *subjectName = NULL; 126 CSSM_RETURN crtn = signer.fetchField(&CSSMOID_X509V1SubjectNameStd, 127 &subjectName); 128 if(crtn) { 129 /* bad cert */ 130 tpOcspDebug("tpOcspResponderIDCheck: error on fetchField(subjectName"); 131 return false; 132 } 133 if(tpCompareCssmData(respIdName, subjectName)) { 134 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byName"); 135 shouldBeSigner = true; 136 } 137 else { 138 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byName"); 139 } 140 signer.freeField(&CSSMOID_X509V1SubjectNameStd, subjectName); 141 } 142 else { 143 /* ResponderID.byKey must == SHA1(signer's public key) */ 144 const CSSM_KEY *pubKey = signer.pubKey(); 145 assert(pubKey != NULL); 146 uint8 digest[CC_SHA1_DIGEST_LENGTH]; 147 CSSM_DATA keyHash = {CC_SHA1_DIGEST_LENGTH, digest}; 148 ocspdSha1(pubKey->KeyData.Data, (CC_LONG)pubKey->KeyData.Length, digest); 149 const CSSM_DATA *respKeyHash = &ocspResp.responderID().byKey; 150 if(tpCompareCssmData(&keyHash, respKeyHash)) { 151 tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byKey"); 152 shouldBeSigner = true; 153 } 154 else { 155 tpOcspDebug("tpOcspResponderIDCheck: BAD ResponderID.byKey"); 156 } 157 } 158 return shouldBeSigner; 159} 160 161/* 162 * Verify the signature of an OCSP response. Caller is responsible for all other 163 * verification of the response, this is just the crypto. 164 * Returns true on success. 165 */ 166static bool tpOcspResponseSigVerify( 167 TPVerifyContext &vfyCtx, 168 OCSPResponse &ocspResp, // parsed response 169 TPCertInfo &signer) 170{ 171 /* get signature algorithm in CSSM form from the response */ 172 const SecAsn1OCSPBasicResponse &basicResp = ocspResp.basicResponse(); 173 const CSSM_OID *algOid = &basicResp.algId.algorithm; 174 CSSM_ALGORITHMS sigAlg; 175 176 if(!cssmOidToAlg(algOid, &sigAlg)) { 177 tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm"); 178 } 179 180 /* signer's public key from the cert */ 181 const CSSM_KEY *pubKey = signer.pubKey(); 182 183 /* signature: on decode, length is in BITS */ 184 CSSM_DATA sig = basicResp.sig; 185 sig.Length /= 8; 186 187 CSSM_RETURN crtn; 188 CSSM_CC_HANDLE sigHand; 189 bool ourRtn = false; 190 crtn = CSSM_CSP_CreateSignatureContext(vfyCtx.cspHand, sigAlg, NULL, 191 pubKey, &sigHand); 192 if(crtn) { 193 #ifndef NDEBUG 194 cssmPerror("tpOcspResponseSigVerify, CSSM_CSP_CreateSignatureContext", crtn); 195 #endif 196 return false; 197 } 198 crtn = CSSM_VerifyData(sigHand, &basicResp.tbsResponseData, 1, 199 CSSM_ALGID_NONE, &sig); 200 if(crtn) { 201 #ifndef NDEBUG 202 cssmPerror("tpOcspResponseSigVerify, CSSM_VerifyData", crtn); 203 #endif 204 } 205 else { 206 ourRtn = true; 207 } 208 CSSM_DeleteContext(sigHand); 209 return ourRtn; 210} 211 212/* possible return from tpIsOcspIssuer() */ 213typedef enum { 214 OIS_No, // not the issuer 215 OIS_Good, // is the issuer and signature matches 216 OIS_BadSig, // appears to be issuer, but signature doesn't match 217} OcspIssuerStatus; 218 219/* type of rawCert passed to tpIsOcspIssuer */ 220typedef enum { 221 OCT_Local, // LocalResponder - no checking other than signature 222 OCT_Issuer, // it's the issuer of the cert being verified 223 OCT_Provided, // came with response, provenance unknown 224} OcspCertType; 225 226/* 227 * Did specified cert issue the OCSP response? 228 * 229 * This implements the algorithm described in RFC2560, section 4.2.2.2, 230 * "Authorized Responders". It sees if the cert could be the issuer of the 231 * OCSP response per that algorithm; then if it could, it performs signature 232 * verification. 233 */ 234static OcspIssuerStatus tpIsOcspIssuer( 235 TPVerifyContext &vfyCtx, 236 OCSPResponse &ocspResp, // parsed response 237 /* on input specify at least one of the following two */ 238 const CSSM_DATA *signerData, 239 TPCertInfo *signer, 240 OcspCertType certType, // where rawCert came from 241 TPCertInfo *issuer, // OPTIONAL, if known 242 TPCertInfo **signerRtn) // optionally RETURNED if at all possible 243{ 244 assert((signerData != NULL) || (signer != NULL)); 245 246 /* get signer as TPCertInfo if caller hasn't provided */ 247 TPCertInfo *tmpSigner = NULL; 248 if(signer == NULL) { 249 try { 250 tmpSigner = new TPCertInfo(vfyCtx.clHand, vfyCtx.cspHand, signerData, 251 TIC_CopyData, vfyCtx.verifyTime); 252 } 253 catch(...) { 254 tpOcspDebug("tpIsOcspIssuer: bad cert"); 255 return OIS_No; 256 } 257 signer = tmpSigner; 258 } 259 if(signer == NULL) { 260 return OIS_No; 261 } 262 if(signerRtn != NULL) { 263 *signerRtn = signer; 264 } 265 266 /* 267 * Qualification of "this can be the signer" depends on where the 268 * signer came from. 269 */ 270 bool shouldBeSigner = false; 271 OcspIssuerStatus ourRtn = OIS_No; 272 273 switch(certType) { 274 case OCT_Local: // caller trusts this and thinks it's the signer 275 shouldBeSigner = true; 276 break; 277 case OCT_Issuer: // last resort, the actual issuer 278 /* check ResponderID linkage */ 279 shouldBeSigner = tpOcspResponderIDCheck(ocspResp, *signer); 280 break; 281 case OCT_Provided: 282 { 283 /* 284 * This cert came with the response. 285 */ 286 if(issuer == NULL) { 287 /* 288 * careful, might not know the issuer...how would this path ever 289 * work then? I don't think it needs to because you can NOT 290 * do OCSP on a cert without its issuer in hand. 291 */ 292 break; 293 } 294 295 /* check EKU linkage */ 296 shouldBeSigner = tpIsAuthorizedOcspSigner(*issuer, *signer); 297 break; 298 } 299 } 300 if(!shouldBeSigner) { 301 goto errOut; 302 } 303 304 /* verify the signature */ 305 if(tpOcspResponseSigVerify(vfyCtx, ocspResp, *signer)) { 306 ourRtn = OIS_Good; 307 } 308 309errOut: 310 if((signerRtn == NULL) && (tmpSigner != NULL)) { 311 delete tmpSigner; 312 } 313 return ourRtn; 314 315} 316 317OcspRespStatus tpVerifyOcspResp( 318 TPVerifyContext &vfyCtx, 319 SecNssCoder &coder, 320 TPCertInfo *issuer, // issuer of the related cert, may be issuer of 321 // reply, may not be known 322 OCSPResponse &ocspResp, 323 CSSM_RETURN &cssmErr) // possible per-cert error 324{ 325 OcspRespStatus ourRtn = ORS_Unknown; 326 CSSM_RETURN crtn; 327 328 tpOcspDebug("tpVerifyOcspResp top"); 329 330 switch(ocspResp.responseStatus()) { 331 case RS_Success: 332 crtn = CSSM_OK; 333 break; 334 case RS_MalformedRequest: 335 crtn = CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ; 336 break; 337 case RS_InternalError: 338 crtn = CSSMERR_APPLETP_OCSP_RESP_INTERNAL_ERR; 339 break; 340 case RS_TryLater: 341 crtn = CSSMERR_APPLETP_OCSP_RESP_TRY_LATER; 342 break; 343 case RS_SigRequired: 344 crtn = CSSMERR_APPLETP_OCSP_RESP_SIG_REQUIRED; 345 break; 346 case RS_Unauthorized: 347 crtn = CSSMERR_APPLETP_OCSP_RESP_UNAUTHORIZED; 348 break; 349 default: 350 crtn = CSSMERR_APPLETP_OCSP_BAD_RESPONSE; 351 break; 352 } 353 if(crtn) { 354 tpOcspDebug("tpVerifyOcspResp aborting due to response status %d", 355 (int)(ocspResp.responseStatus())); 356 cssmErr = crtn; 357 return ORS_Unknown; 358 } 359 cssmErr = CSSM_OK; 360 361 /* one of our main jobs is to locate the signer of the response, here */ 362 TPCertInfo *signerInfo = NULL; 363 TPCertInfo *signerInfoTBD = NULL; // if non NULL at end, we delete 364 /* we'll be verifying into this cert group */ 365 TPCertGroup ocspCerts(vfyCtx.alloc, TGO_Caller); 366 CSSM_BOOL verifiedToRoot; 367 CSSM_BOOL verifiedToAnchor; 368 CSSM_BOOL verifiedViaTrustSetting; 369 370 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts; 371 OcspIssuerStatus issuerStat; 372 373 /* 374 * Set true if we ever find an apparent issuer which does not correctly 375 * pass signature verify. If true and we never success, that's a XXX error. 376 */ 377 bool foundBadIssuer = false; 378 bool foundLocalResponder = false; 379 uint32 numSignerCerts = ocspResp.numSignerCerts(); 380 381 /* 382 * This cert group, allocated by AppleTPSession::CertGroupVerify(), 383 * serves two functions here: 384 * 385 * -- it accumulates certs we get from the net (as parts of OCSP responses) 386 * for user in verifying OCSPResponse-related certs. 387 * TPCertGroup::buildCertGroup() uses this group as one of the many 388 * sources of certs when building a cert chain. 389 * 390 * -- it provides a container into which to stash TPCertInfos which 391 * persist at least as long as the TPVerifyContext; it's of type TGO_Group, 392 * so all of the certs added to it get freed when the group does. 393 */ 394 assert(vfyCtx.signerCerts != NULL); 395 396 TPCertGroup &gatheredCerts = vfyCtx.gatheredCerts; 397 398 /* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */ 399 TPCertGroup certsToBeFreed(vfyCtx.alloc, TGO_Group); 400 401 /* 402 * First job is to find the cert which signed this response. 403 * Give priority to caller's LocalResponderCert. 404 */ 405 if((ocspOpts != NULL) && (ocspOpts->LocalResponderCert != NULL)) { 406 TPCertInfo *responderInfo = NULL; 407 issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp, 408 ocspOpts->LocalResponderCert, NULL, 409 OCT_Local, issuer, &responderInfo); 410 switch(issuerStat) { 411 case OIS_BadSig: 412 foundBadIssuer = true; 413 /* drop thru */ 414 case OIS_No: 415 if(responderInfo != NULL) { 416 /* can't use it - should this be an immediate error? */ 417 delete responderInfo; 418 } 419 break; 420 case OIS_Good: 421 assert(responderInfo != NULL); 422 signerInfo = signerInfoTBD = responderInfo; 423 foundLocalResponder = true; 424 tpOcspDebug("tpVerifyOcspResp: signer := LocalResponderCert"); 425 break; 426 } 427 } 428 429 if((signerInfo == NULL) && (numSignerCerts != 0)) { 430 /* 431 * App did not specify a local responder (or provided a bad one) 432 * and the response came with some certs. Try those. 433 */ 434 TPCertInfo *respCert = NULL; 435 for(unsigned dex=0; dex<numSignerCerts; dex++) { 436 const CSSM_DATA *certData = ocspResp.signerCert(dex); 437 if(signerInfo == NULL) { 438 /* stop trying this after we succeed... */ 439 issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp, 440 certData, NULL, 441 OCT_Provided, issuer, &respCert); 442 switch(issuerStat) { 443 case OIS_No: 444 break; 445 case OIS_Good: 446 assert(respCert != NULL); 447 signerInfo = signerInfoTBD = respCert; 448 tpOcspDebug("tpVerifyOcspResp: signer := signerCert[%u]", dex); 449 break; 450 case OIS_BadSig: 451 foundBadIssuer = true; 452 break; 453 } 454 } 455 else { 456 /* 457 * At least add this cert to certGroup for verification. 458 * OcspCert will own the TPCertInfo. 459 */ 460 try { 461 respCert = new TPCertInfo(vfyCtx.clHand, vfyCtx.cspHand, certData, 462 TIC_CopyData, vfyCtx.verifyTime); 463 } 464 catch(...) { 465 tpOcspDebug("tpVerifyOcspResp: BAD signerCert[%u]", dex); 466 } 467 } 468 /* if we got a TPCertInfo, and it's not the signer, add it to certGroup */ 469 if((respCert != NULL) && (respCert != signerInfo)) { 470 gatheredCerts.appendCert(respCert); 471 } 472 } 473 } 474 475 if((signerInfo == NULL) && (issuer != NULL)) { 476 /* 477 * Haven't found it yet, try the actual issuer 478 */ 479 issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp, 480 NULL, issuer, 481 OCT_Issuer, issuer, NULL); 482 switch(issuerStat) { 483 case OIS_BadSig: 484 ourRtn = ORS_Unknown; 485 cssmErr = CSSMERR_APPLETP_OCSP_SIG_ERROR; 486 goto errOut; 487 case OIS_No: 488 break; 489 case OIS_Good: 490 signerInfo = issuer; 491 tpOcspDebug("tpVerifyOcspResp: signer := issuer"); 492 break; 493 } 494 } 495 496 if(signerInfo == NULL) { 497 if((issuer != NULL) && !issuer->isStatusFatal(CSSMERR_APPLETP_OCSP_NO_SIGNER)) { 498 /* user wants to proceed without verifying! */ 499 tpOcspDebug("tpVerifyOcspResp: no signer found, user allows!"); 500 ourRtn = ORS_Good; 501 } 502 else { 503 tpOcspDebug("tpVerifyOcspResp: no signer found"); 504 ourRtn = ORS_Unknown; 505 /* caller adds to per-cert status */ 506 cssmErr = CSSMERR_APPLETP_OCSP_NO_SIGNER; 507 } 508 goto errOut; 509 } 510 511 if(signerInfo != NULL && !foundLocalResponder) { 512 /* 513 * tpIsOcspIssuer has verified that signerInfo is the signer of the 514 * OCSP response, and that it is either the issuer of the cert being 515 * checked or is a valid authorized responder for that issuer based on 516 * key id linkage and EKU. There is no stipulation in RFC2560 to also 517 * build the chain back to a trusted anchor; however, we'll continue to 518 * enforce this for the local responder case. (10742723) 519 */ 520 tpOcspDebug("tpVerifyOcspResp SUCCESS"); 521 ourRtn = ORS_Good; 522 goto errOut; 523 } 524 525 /* 526 * Last remaining task is to verify the signer, and all the certs back to 527 * an anchor 528 */ 529 530 /* start from scratch with both of these groups */ 531 gatheredCerts.setAllUnused(); 532 vfyCtx.signerCerts->setAllUnused(); 533 crtn = ocspCerts.buildCertGroup( 534 *signerInfo, // subject item 535 vfyCtx.signerCerts, // inCertGroup the original group-to-be-verified 536 vfyCtx.dbList, // optional 537 vfyCtx.clHand, 538 vfyCtx.cspHand, 539 vfyCtx.verifyTime, 540 vfyCtx.numAnchorCerts, 541 vfyCtx.anchorCerts, 542 certsToBeFreed, // local to-be-freed right now 543 &gatheredCerts, // accumulate gathered certs here 544 CSSM_FALSE, // subjectIsInGroup 545 vfyCtx.actionFlags, 546 vfyCtx.policyOid, 547 vfyCtx.policyStr, 548 vfyCtx.policyStrLen, 549 kSecTrustSettingsKeyUseSignRevocation, 550 verifiedToRoot, 551 verifiedToAnchor, 552 verifiedViaTrustSetting); 553 if(crtn) { 554 tpOcspDebug("tpVerifyOcspResp buildCertGroup failure"); 555 cssmErr = crtn; 556 ourRtn = ORS_Unknown; 557 goto errOut; 558 } 559 560 if(!verifiedToAnchor && !verifiedViaTrustSetting) { 561 /* required */ 562 ourRtn = ORS_Unknown; 563 if(verifiedToRoot) { 564 /* verified to root which is not an anchor */ 565 tpOcspDebug("tpVerifyOcspResp root, no anchor"); 566 cssmErr = CSSMERR_APPLETP_OCSP_INVALID_ANCHOR_CERT; 567 } 568 else { 569 /* partial chain, no root, not verifiable by anchor */ 570 tpOcspDebug("tpVerifyOcspResp no root, no anchor"); 571 cssmErr = CSSMERR_APPLETP_OCSP_NOT_TRUSTED; 572 } 573 if((issuer != NULL) && !issuer->isStatusFatal(cssmErr)) { 574 tpOcspDebug("...ignoring last error per trust setting"); 575 ourRtn = ORS_Good; 576 } 577 else { 578 ourRtn = ORS_Unknown; 579 } 580 } 581 else { 582 tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified"); 583 ourRtn = ORS_Good; 584 } 585 586 /* FIXME policy verify? */ 587 588errOut: 589 delete signerInfoTBD; 590 /* any other cleanup? */ 591 return ourRtn; 592} 593