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