ocspResponse.cpp
1 /* 2 * Copyright (c) 2004,2011-2012,2014 Apple 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 * ocspResponse.cpp - OCSP Response class 26 */ 27 #include "ocspResponse.h" 28 #include "ocspdUtils.h" 29 #include <Security/cssmapple.h> 30 #include <Security/oidscrl.h> 31 #include <Security/oidsalg.h> 32 #include "ocspdDebug.h" 33 #include <CommonCrypto/CommonDigest.h> 34 #include <security_cdsa_utilities/cssmerrors.h> 35 #include <Security/SecAsn1Templates.h> 36 37 /* malloc & copy CSSM_DATA using std malloc */ 38 static void allocCopyData( 39 const CSSM_DATA &src, 40 CSSM_DATA &dst) 41 { 42 if(src.Length == 0) { 43 dst.Data = NULL; 44 dst.Length = 0; 45 return; 46 } 47 dst.Data = (uint8 *)malloc(src.Length); 48 memmove(dst.Data, src.Data, src.Length); 49 dst.Length = src.Length; 50 } 51 52 /* std free() of a CSSM_DATA */ 53 static void freeData( 54 CSSM_DATA &d) 55 { 56 if(d.Data) { 57 free(d.Data); 58 d.Data = NULL; 59 } 60 d.Length = 0; 61 } 62 63 #pragma mark ---- OCSPClientCertID ---- 64 65 /* 66 * Basic constructor given issuer's public key and name, and subject's 67 * serial number. 68 */ 69 OCSPClientCertID::OCSPClientCertID( 70 const CSSM_DATA &issuerName, 71 const CSSM_DATA &issuerPubKey, 72 const CSSM_DATA &subjectSerial) 73 { 74 mEncoded.Data = NULL; 75 mEncoded.Length = 0; 76 allocCopyData(issuerName, mIssuerName); 77 allocCopyData(issuerPubKey, mIssuerPubKey); 78 allocCopyData(subjectSerial, mSubjectSerial); 79 } 80 81 OCSPClientCertID::~OCSPClientCertID() 82 { 83 freeData(mIssuerName); 84 freeData(mIssuerPubKey); 85 freeData(mSubjectSerial); 86 freeData(mEncoded); 87 } 88 89 /* preencoded DER NULL */ 90 static uint8 nullParam[2] = {5, 0}; 91 92 /* 93 * DER encode in specified coder's memory. 94 */ 95 const CSSM_DATA *OCSPClientCertID::encode() 96 { 97 if(mEncoded.Data != NULL) { 98 return &mEncoded; 99 } 100 101 SecAsn1OCSPCertID certID; 102 uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH]; 103 uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH]; 104 105 /* algId refers to the hash we'll perform in issuer name and key */ 106 certID.algId.algorithm = CSSMOID_SHA1; 107 certID.algId.parameters.Data = nullParam; 108 certID.algId.parameters.Length = sizeof(nullParam); 109 110 /* SHA1(issuerName) */ 111 ocspdSha1(mIssuerName.Data, (CC_LONG)mIssuerName.Length, issuerNameHash); 112 113 /* SHA1(issuer public key bytes) */ 114 ocspdSha1(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, pubKeyHash); 115 116 /* build the CertID from those components */ 117 certID.issuerNameHash.Data = issuerNameHash; 118 certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH; 119 certID.issuerPubKeyHash.Data = pubKeyHash; 120 certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH; 121 certID.serialNumber = mSubjectSerial; 122 123 /* encode */ 124 SecAsn1CoderRef coder; 125 SecAsn1CoderCreate(&coder); 126 127 CSSM_DATA tmp = {0, NULL}; 128 SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp); 129 allocCopyData(tmp, mEncoded); 130 SecAsn1CoderRelease(coder); 131 return &mEncoded; 132 } 133 134 /* 135 * Does this object refer to the same cert as specified SecAsn1OCSPCertID? 136 * This is the main purpose of this class's existence; this function works 137 * even if specified SecAsn1OCSPCertID uses a different hash algorithm 138 * than we do, since we keep copies of our basic components. 139 * 140 * Returns true if compare successful. 141 */ 142 typedef void (*hashFcn)(const void *data, CC_LONG len, unsigned char *md); 143 144 bool OCSPClientCertID::compareToExist( 145 const SecAsn1OCSPCertID &exist) 146 { 147 /* easy part */ 148 if(!ocspdCompareCssmData(&mSubjectSerial, &exist.serialNumber)) { 149 return false; 150 } 151 152 hashFcn hf = NULL; 153 const CSSM_OID *alg = &exist.algId.algorithm; 154 uint8 digest[OCSPD_MAX_DIGEST_LEN]; 155 CSSM_DATA digestData = {0, digest}; 156 157 if(ocspdCompareCssmData(alg, &CSSMOID_SHA1)) { 158 hf = ocspdSha1; 159 digestData.Length = CC_SHA1_DIGEST_LENGTH; 160 } 161 else if(ocspdCompareCssmData(alg, &CSSMOID_MD5)) { 162 hf = ocspdMD5; 163 digestData.Length = CC_MD5_DIGEST_LENGTH; 164 } 165 else if(ocspdCompareCssmData(alg, &CSSMOID_MD4)) { 166 hf = ocspdMD4; 167 digestData.Length = CC_MD4_DIGEST_LENGTH; 168 } 169 /* an OID for SHA256? */ 170 else { 171 return false; 172 } 173 174 /* generate digests using exist's hash algorithm */ 175 hf(mIssuerName.Data, (CC_LONG)mIssuerName.Length, digest); 176 if(!ocspdCompareCssmData(&digestData, &exist.issuerNameHash)) { 177 return false; 178 } 179 hf(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, digest); 180 if(!ocspdCompareCssmData(&digestData, &exist.issuerPubKeyHash)) { 181 return false; 182 } 183 184 return true; 185 } 186 187 bool OCSPClientCertID::compareToExist( 188 const CSSM_DATA &exist) 189 { 190 SecAsn1CoderRef coder; 191 SecAsn1OCSPCertID certID; 192 bool brtn = false; 193 194 SecAsn1CoderCreate(&coder); 195 memset(&certID, 0, sizeof(certID)); 196 if(SecAsn1DecodeData(coder, &exist, kSecAsn1OCSPCertIDTemplate, &certID)) { 197 goto errOut; 198 } 199 brtn = compareToExist(certID); 200 errOut: 201 SecAsn1CoderRelease(coder); 202 return brtn; 203 } 204 205 #pragma mark ---- OCSPSingleResponse ---- 206 207 /* 208 * Constructor, called by OCSPResponse. 209 */ 210 OCSPSingleResponse::OCSPSingleResponse( 211 SecAsn1OCSPSingleResponse *resp) 212 : mCertStatus(CS_NotParsed), 213 mThisUpdate(NULL_TIME), 214 mNextUpdate(NULL_TIME), 215 mRevokedTime(NULL_TIME), 216 mCrlReason(CrlReason_NONE), 217 mExtensions(NULL) 218 { 219 assert(resp != NULL); 220 221 SecAsn1CoderCreate(&mCoder); 222 if((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) { 223 ocspdErrorLog("OCSPSingleResponse: bad certStatus\n"); 224 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 225 } 226 mCertStatus = (SecAsn1OCSPCertStatusTag)(resp->certStatus.Data[0] & SEC_ASN1_TAGNUM_MASK); 227 if(mCertStatus == CS_Revoked) { 228 /* decode further to get SecAsn1OCSPRevokedInfo */ 229 SecAsn1OCSPCertStatus certStatus; 230 memset(&certStatus, 0, sizeof(certStatus)); 231 if(SecAsn1DecodeData(mCoder, &resp->certStatus, 232 kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) { 233 ocspdErrorLog("OCSPSingleResponse: err decoding certStatus\n"); 234 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 235 } 236 SecAsn1OCSPRevokedInfo *revokedInfo = certStatus.revokedInfo; 237 if(revokedInfo != NULL) { 238 /* Treat this as optional even for CS_Revoked */ 239 mRevokedTime = genTimeToCFAbsTime(&revokedInfo->revocationTime); 240 const CSSM_DATA *revReason = revokedInfo->revocationReason; 241 if((revReason != NULL) && 242 (revReason->Data != NULL) && 243 (revReason->Length != 0)) { 244 mCrlReason = revReason->Data[0]; 245 } 246 } 247 } 248 mThisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); 249 if(resp->nextUpdate != NULL) { 250 mNextUpdate = genTimeToCFAbsTime(resp->nextUpdate); 251 } 252 mExtensions = new OCSPExtensions(resp->singleExtensions); 253 ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus, 254 (int)mCrlReason); 255 } 256 257 OCSPSingleResponse::~OCSPSingleResponse() 258 { 259 delete mExtensions; 260 SecAsn1CoderRelease(mCoder); 261 } 262 263 /*** Extensions-specific accessors ***/ 264 #if 0 /* unused ? */ 265 const CSSM_DATA *OCSPSingleResponse::*crlUrl() 266 { 267 /* TBD */ 268 return NULL; 269 } 270 #endif 271 272 const CSSM_DATA *OCSPSingleResponse::crlNum() 273 { 274 /* TBD */ 275 return NULL; 276 277 } 278 279 CFAbsoluteTime OCSPSingleResponse::crlTime() /* may be NULL_TIME */ 280 { 281 /* TBD */ 282 return NULL_TIME; 283 } 284 285 /* archive cutoff */ 286 CFAbsoluteTime OCSPSingleResponse::archiveCutoff() 287 { 288 /* TBD */ 289 return NULL_TIME; 290 } 291 292 #pragma mark ---- OCSPResponse ---- 293 294 OCSPResponse::OCSPResponse( 295 const CSSM_DATA &resp, 296 CFTimeInterval defaultTTL) // default time-to-live in seconds 297 : mLatestNextUpdate(NULL_TIME), 298 mExpireTime(NULL_TIME), 299 mExtensions(NULL) 300 { 301 SecAsn1CoderCreate(&mCoder); 302 memset(&mTopResp, 0, sizeof(mTopResp)); 303 memset(&mBasicResponse, 0, sizeof(mBasicResponse)); 304 memset(&mResponseData, 0, sizeof(mResponseData)); 305 memset(&mResponderId, 0, sizeof(mResponderId)); 306 mResponderIdTag = (SecAsn1OCSPResponderIDTag)0; // invalid 307 mEncResponderName.Data = NULL; 308 mEncResponderName.Length = 0; 309 310 if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) { 311 ocspdErrorLog("OCSPResponse: decode failure at top level\n"); 312 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 313 } 314 315 /* remainder is valid only on RS_Success */ 316 if((mTopResp.responseStatus.Data == NULL) || 317 (mTopResp.responseStatus.Length == 0)) { 318 ocspdErrorLog("OCSPResponse: no responseStatus\n"); 319 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 320 } 321 if(mTopResp.responseStatus.Data[0] != RS_Success) { 322 /* not a failure of our constructor; this object is now useful, but 323 * only for this one byte of status info */ 324 return; 325 } 326 if(mTopResp.responseBytes == NULL) { 327 /* I don't see how this can be legal on RS_Success */ 328 ocspdErrorLog("OCSPResponse: empty responseBytes\n"); 329 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 330 } 331 if(!ocspdCompareCssmData(&mTopResp.responseBytes->responseType, 332 &CSSMOID_PKIX_OCSP_BASIC)) { 333 ocspdErrorLog("OCSPResponse: unknown responseType\n"); 334 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 335 } 336 337 /* decode the SecAsn1OCSPBasicResponse */ 338 if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response, 339 kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) { 340 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n"); 341 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 342 } 343 344 /* signature and cert evaluation done externally */ 345 346 /* decode the SecAsn1OCSPResponseData */ 347 if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData, 348 kSecAsn1OCSPResponseDataTemplate, &mResponseData)) { 349 ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPResponseData\n"); 350 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 351 } 352 if(mResponseData.responderID.Data == NULL) { 353 ocspdErrorLog("OCSPResponse: bad responderID\n"); 354 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 355 } 356 357 /* choice processing for ResponderID */ 358 mResponderIdTag = (SecAsn1OCSPResponderIDTag) 359 (mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK); 360 const SecAsn1Template *templ; 361 switch(mResponderIdTag) { 362 case RIT_Name: 363 templ = kSecAsn1OCSPResponderIDAsNameTemplate; 364 break; 365 case RIT_Key: 366 templ = kSecAsn1OCSPResponderIDAsKeyTemplate; 367 break; 368 default: 369 ocspdErrorLog("OCSPResponse: bad responderID tag\n"); 370 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 371 } 372 if(SecAsn1DecodeData(mCoder, &mResponseData.responderID, templ, &mResponderId)) { 373 ocspdErrorLog("OCSPResponse: decode failure at responderID\n"); 374 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 375 } 376 377 /* check temporal validity */ 378 if(!calculateValidity(defaultTTL)) { 379 /* Whoops, abort */ 380 CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE); 381 } 382 383 /* 384 * Individual responses looked into when we're asked for a specific one 385 * via singleResponse() 386 */ 387 mExtensions = new OCSPExtensions(mResponseData.responseExtensions); 388 } 389 390 OCSPResponse::~OCSPResponse() 391 { 392 delete mExtensions; 393 SecAsn1CoderRelease(mCoder); 394 } 395 396 SecAsn1OCSPResponseStatus OCSPResponse::responseStatus() 397 { 398 assert(mTopResp.responseStatus.Data != NULL); /* else constructor should have failed */ 399 return (SecAsn1OCSPResponseStatus)(mTopResp.responseStatus.Data[0]); 400 } 401 402 const CSSM_DATA *OCSPResponse::nonce() /* NULL means not present */ 403 { 404 OCSPExtension *ext = mExtensions->findExtension(CSSMOID_PKIX_OCSP_NONCE); 405 if(ext == NULL) { 406 return NULL; 407 } 408 OCSPNonce *nonceExt = dynamic_cast<OCSPNonce *>(ext); 409 return &(nonceExt->nonce()); 410 } 411 412 CFAbsoluteTime OCSPResponse::producedAt() 413 { 414 return genTimeToCFAbsTime(&mResponseData.producedAt); 415 } 416 417 uint32 OCSPResponse::numSignerCerts() 418 { 419 return ocspdArraySize((const void **)mBasicResponse.certs); 420 } 421 422 const CSSM_DATA *OCSPResponse::signerCert(uint32 dex) 423 { 424 uint32 numCerts = numSignerCerts(); 425 if(dex >= numCerts) { 426 ocspdErrorLog("OCSPResponse::signerCert: numCerts overflow\n"); 427 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); 428 } 429 return mBasicResponse.certs[dex]; 430 } 431 432 /* 433 * Obtain a OCSPSingleResponse for a given "smart" CertID. 434 */ 435 OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertID) 436 { 437 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses); 438 for(unsigned dex=0; dex<numResponses; dex++) { 439 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex]; 440 SecAsn1OCSPCertID &certID = resp->certID; 441 if(matchCertID.compareToExist(certID)) { 442 try { 443 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp); 444 return singleResp; 445 } 446 catch(...) { 447 /* try to find another... */ 448 continue; 449 } 450 } 451 } 452 ocspdDebug("OCSPResponse::singleResponse: certID not found"); 453 return NULL; 454 } 455 456 /* 457 * If responderID is of form RIT_Name, return the encoded version of the 458 * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily, 459 * once, in mCoder space. 460 */ 461 const CSSM_DATA *OCSPResponse::encResponderName() 462 { 463 if(mResponderIdTag != RIT_Name) { 464 assert(0); 465 return NULL; 466 } 467 if(mEncResponderName.Data != NULL) { 468 return &mEncResponderName; 469 } 470 if(SecAsn1EncodeItem(mCoder, &mResponderId.byName, kSecAsn1AnyTemplate, 471 &mEncResponderName)) { 472 ocspdDebug("OCSPResponse::encResponderName: error encoding ResponderId!"); 473 return NULL; 474 } 475 return &mEncResponderName; 476 } 477 478 /* 479 * Obtain a OCSPSingleResponse for a given raw encoded CertID. 480 */ 481 OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID) 482 { 483 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses); 484 for(unsigned dex=0; dex<numResponses; dex++) { 485 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex]; 486 CSSM_DATA certID = {0, NULL}; 487 if(SecAsn1EncodeItem(mCoder, &resp->certID, kSecAsn1OCSPCertIDTemplate, 488 &certID)) { 489 ocspdDebug("OCSPResponse::singleResponse: error encoding certID!"); 490 return NULL; 491 } 492 if(!ocspdCompareCssmData(&matchCertID, &certID)) { 493 /* try to find another */ 494 continue; 495 } 496 try { 497 OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp); 498 return singleResp; 499 } 500 catch(...) { 501 /* try to find another... */ 502 continue; 503 } 504 } 505 ocspdDebug("OCSPResponse::singleResponse: certID not found"); 506 return NULL; 507 508 } 509 510 /* 511 * Calculate temporal validity; set mLatestNextUpdate and mExpireTime. Only 512 * called from constructor. Returns true if valid, else returns false. 513 */ 514 bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL) 515 { 516 mLatestNextUpdate = NULL_TIME; 517 CFAbsoluteTime now = CFAbsoluteTimeGetCurrent(); 518 519 unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses); 520 for(unsigned dex=0; dex<numResponses; dex++) { 521 SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex]; 522 523 /* 524 * First off, a thisUpdate later than 'now' invalidates the whole response. 525 */ 526 CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate); 527 if(thisUpdate > now) { 528 ocspdErrorLog("OCSPResponse::calculateValidity: thisUpdate not passed\n"); 529 return false; 530 } 531 532 /* 533 * Accumulate latest nextUpdate 534 */ 535 if(resp->nextUpdate != NULL) { 536 CFAbsoluteTime nextUpdate = genTimeToCFAbsTime(resp->nextUpdate); 537 if(nextUpdate > mLatestNextUpdate) { 538 mLatestNextUpdate = nextUpdate; 539 } 540 } 541 } 542 543 CFAbsoluteTime defaultExpire = now + defaultTTL; 544 if(mLatestNextUpdate == NULL_TIME) { 545 /* absolute expire time = current time plus default TTL */ 546 mExpireTime = defaultExpire; 547 } 548 else if(defaultExpire < mLatestNextUpdate) { 549 /* caller more stringent than response */ 550 mExpireTime = defaultExpire; 551 } 552 else { 553 /* response more stringent than caller */ 554 if(mLatestNextUpdate < now) { 555 ocspdErrorLog("OCSPResponse::calculateValidity: now > mLatestNextUpdate\n"); 556 return false; 557 } 558 mExpireTime = mLatestNextUpdate; 559 } 560 return true; 561 } 562