1/* 2 * Copyright (c) 2002 Apple Computer, Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 * TPCrlInfo.h - TP's private CRL and CRL group 21 * 22 * Written 9/30/2002 by Doug Mitchell. 23 */ 24 25#include "TPCrlInfo.h" 26#include "tpdebugging.h" 27#include "certGroupUtils.h" 28#include "tpCrlVerify.h" 29#include "tpPolicies.h" 30#include "tpTime.h" 31#include <Security/cssmapi.h> 32#include <Security/x509defs.h> 33#include <Security/oidscert.h> 34#include <Security/oidscrl.h> 35#include <security_cdsa_utilities/cssmerrors.h> 36#include <string.h> /* for memcmp */ 37#include <Security/cssmapple.h> 38 39/* 40 * Replacement for CSSM_CL_CrlGetFirstCachedFieldValue for use with 41 * TPCrlItemInfo's generic getFirstCachedField mechanism. 42 */ 43static CSSM_RETURN tpGetFirstCachedFieldValue (CSSM_CL_HANDLE CLHandle, 44 CSSM_HANDLE CrlHandle, 45 const CSSM_OID *CrlField, 46 CSSM_HANDLE_PTR ResultsHandle, 47 uint32 *NumberOfMatchedFields, 48 CSSM_DATA_PTR *Value) 49{ 50 return CSSM_CL_CrlGetFirstCachedFieldValue(CLHandle, 51 CrlHandle, 52 NULL, // const CSSM_DATA *CrlRecordIndex, 53 CrlField, 54 ResultsHandle, 55 NumberOfMatchedFields, 56 Value); 57} 58 59static const TPClItemCalls tpCrlClCalls = 60{ 61 tpGetFirstCachedFieldValue, 62 CSSM_CL_CrlAbortQuery, 63 CSSM_CL_CrlCache, 64 CSSM_CL_CrlAbortCache, 65 CSSM_CL_CrlVerify, 66 &CSSMOID_X509V1CRLThisUpdate, 67 &CSSMOID_X509V1CRLNextUpdate, 68 CSSMERR_TP_INVALID_CRL_POINTER, 69 CSSMERR_APPLETP_CRL_EXPIRED, 70 CSSMERR_APPLETP_CRL_NOT_VALID_YET 71}; 72 73 74/* 75 * No default constructor - this is the only way. 76 * This caches the cert and fetches subjectName and issuerName 77 * to ensure the incoming certData is well-constructed. 78 */ 79TPCrlInfo::TPCrlInfo( 80 CSSM_CL_HANDLE clHand, 81 CSSM_CSP_HANDLE cspHand, 82 const CSSM_DATA *crlData, 83 TPItemCopy copyCrlData, // true: we copy, we free 84 // false - caller owns 85 const char *verifyTime) // = NULL 86 87 : TPClItemInfo(clHand, cspHand, tpCrlClCalls, crlData, 88 copyCrlData, verifyTime), 89 mRefCount(0), 90 mFromWhere(CFW_Nowhere), 91 mX509Crl(NULL), 92 mCrlFieldToFree(NULL), 93 mVerifyState(CVS_Unknown), 94 mVerifyError(CSSMERR_TP_INTERNAL_ERROR) 95{ 96 CSSM_RETURN crtn; 97 98 mUri.Data = NULL; 99 mUri.Length = 0; 100 101 /* fetch parsed CRL */ 102 crtn = fetchField(&CSSMOID_X509V2CRLSignedCrlCStruct, &mCrlFieldToFree); 103 if(crtn) { 104 /* bad CRL */ 105 releaseResources(); 106 CssmError::throwMe(crtn); 107 } 108 if(mCrlFieldToFree->Length != sizeof(CSSM_X509_SIGNED_CRL)) { 109 tpErrorLog("fetchField(SignedCrlCStruct) length error\n"); 110 releaseResources(); 111 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); 112 } 113 mX509Crl = (CSSM_X509_SIGNED_CRL *)mCrlFieldToFree->Data; 114 /* any other other commonly used fields? */ 115} 116 117TPCrlInfo::~TPCrlInfo() 118{ 119 releaseResources(); 120} 121 122void TPCrlInfo::releaseResources() 123{ 124 if(mCrlFieldToFree) { 125 freeField(&CSSMOID_X509V2CRLSignedCrlCStruct, mCrlFieldToFree); 126 mCrlFieldToFree = NULL; 127 } 128 if(mUri.Data) { 129 Allocator::standard().free(mUri.Data); 130 mUri.Data = NULL; 131 mUri.Length = 0; 132 } 133 TPClItemInfo::releaseResources(); 134} 135 136void TPCrlInfo::uri(const CSSM_DATA &uri) 137{ 138 tpCopyCssmData(Allocator::standard(), &uri, &mUri); 139} 140 141/* 142 * List of extensions we understand and can accept as critical. 143 */ 144static const CSSM_OID *const TPGoodCrlExtens[] = 145{ 146 &CSSMOID_CrlNumber, 147 /* Note NOT CSSMOID_DeltaCrlIndicator! That's fatal */ 148 &CSSMOID_CrlReason, 149 &CSSMOID_CertIssuer, 150 &CSSMOID_IssuingDistributionPoint, 151 &CSSMOID_HoldInstructionCode, 152 &CSSMOID_InvalidityDate, 153 &CSSMOID_AuthorityKeyIdentifier, 154 &CSSMOID_SubjectAltName, 155 &CSSMOID_IssuerAltName 156}; 157 158#define NUM_KNOWN_EXTENS (sizeof(TPGoodCrlExtens) / sizeof(CSSM_OID_PTR)) 159 160/* 161 * Do our best to understand all the entries in a CSSM_X509_EXTENSIONS, 162 * which may be per-CRL or per-entry. 163 * 164 * For now, we just ensure that for every critical extension, 165 * we actually understand it and can deal it. 166 */ 167CSSM_RETURN TPCrlInfo::parseExtensions( 168 TPVerifyContext &vfyCtx, 169 bool isPerEntry, 170 uint32 entryIndex, // if isPerEntry 171 const CSSM_X509_EXTENSIONS &extens, 172 TPCertInfo *forCert, // optional 173 bool &isIndirectCrl) // RETURNED 174{ 175 isIndirectCrl = false; 176 for(uint32 dex=0; dex<extens.numberOfExtensions; dex++) { 177 CSSM_X509_EXTENSION_PTR exten = &extens.extensions[dex]; 178 if(exten->critical) { 179 /* critical: is it in our list of understood extensions? */ 180 unsigned i; 181 for(i=0; i<NUM_KNOWN_EXTENS; i++) { 182 if(tpCompareOids(&exten->extnId, TPGoodCrlExtens[i])) { 183 /* we're cool with this one */ 184 break; 185 } 186 } 187 if(i == NUM_KNOWN_EXTENS) { 188 tpCrlDebug("parseExtensions: Unknown Critical Extension\n"); 189 return CSSMERR_APPLETP_UNKNOWN_CRL_EXTEN; 190 } 191 } 192 193 /* Specific extension handling. */ 194 if(tpCompareOids(&exten->extnId, 195 &CSSMOID_IssuingDistributionPoint)) { 196 /* 197 * If this assertion fails, we're out of sync with the CL 198 */ 199 assert(exten->format == CSSM_X509_DATAFORMAT_PARSED); 200 CE_IssuingDistributionPoint *idp = 201 (CE_IssuingDistributionPoint *) 202 exten->value.parsedValue; 203 204 /* 205 * Snag indirectCrl flag for caller in any case 206 */ 207 if(idp->indirectCrlPresent && idp->indirectCrl) { 208 isIndirectCrl = true; 209 } 210 if(forCert != NULL) { 211 /* If no target cert, i.e., we're just verifying a CRL, 212 * skip the remaining IDP checks. */ 213 214 /* verify onlyCACerts/onlyUserCerts */ 215 bool isUserCert; 216 if(forCert->isLeaf() && 217 !(vfyCtx.actionFlags & CSSM_TP_ACTION_LEAF_IS_CA)) { 218 isUserCert = true; 219 } 220 else { 221 isUserCert = false; 222 } 223 if((idp->onlyUserCertsPresent) && (idp->onlyUserCerts)) { 224 if(!isUserCert) { 225 tpCrlDebug("parseExtensions: onlyUserCerts, " 226 "!leaf\n"); 227 return CSSMERR_APPLETP_IDP_FAIL; 228 } 229 } 230 if((idp->onlyCACertsPresent) && (idp->onlyCACerts)) { 231 if(isUserCert) { 232 tpCrlDebug("parseExtensions: onlyCACerts, leaf\n"); 233 return CSSMERR_APPLETP_IDP_FAIL; 234 } 235 } 236 } /* IDP */ 237 } /* have target cert */ 238 } 239 240 return CSSM_OK; 241} 242 243/* 244 * The heavyweight "perform full verification of this CRL" op. 245 * Must verify to an anchor cert in tpVerifyContext or via 246 * Trust Settings if so enabled. 247 * Intermediate certs can come from signerCerts or dBList. 248 */ 249CSSM_RETURN TPCrlInfo::verifyWithContext( 250 TPVerifyContext &tpVerifyContext, 251 TPCertInfo *forCert, // optional 252 bool doCrlVerify) 253{ 254 /* 255 * Step 1: this CRL must be current. Caller might have re-evaluated 256 * expired/notValidYet since our construction via calculateCurrent(). 257 */ 258 if(isExpired()) { 259 return CSSMERR_APPLETP_CRL_EXPIRED; 260 } 261 if(isNotValidYet()) { 262 return CSSMERR_APPLETP_CRL_NOT_VALID_YET; 263 } 264 265 /* subsequent verify state is cached */ 266 switch(mVerifyState) { 267 case CVS_Good: 268 return CSSM_OK; 269 case CVS_Bad: 270 return mVerifyError; 271 case CVS_Unknown: 272 break; 273 default: 274 tpErrorLog("verifyWithContext: bad verifyState\n"); 275 return CSSMERR_TP_INTERNAL_ERROR; 276 } 277 278 /* 279 * Step 2: parse & understand all critical CRL extensions. 280 */ 281 CSSM_RETURN crtn; 282 bool isIndirectCrl; 283 crtn = parseExtensions(tpVerifyContext, 284 false, 285 0, 286 mX509Crl->tbsCertList.extensions, 287 forCert, 288 isIndirectCrl); 289 if(crtn) { 290 mVerifyState = CVS_Bad; 291 if(!forCert || forCert->addStatusCode(crtn)) { 292 return crtn; 293 } 294 /* else continue */ 295 } 296 CSSM_X509_REVOKED_CERT_LIST_PTR revoked = 297 mX509Crl->tbsCertList.revokedCertificates; 298 if(revoked != NULL) { 299 for(uint32 dex=0; dex<revoked->numberOfRevokedCertEntries; dex++) { 300 bool dummyIsIndirect; // can't be set here 301 crtn = parseExtensions(tpVerifyContext, 302 true, 303 dex, 304 revoked->revokedCertEntry[dex].extensions, 305 forCert, 306 dummyIsIndirect); 307 if(crtn) { 308 if(!forCert || forCert->addStatusCode(crtn)) { 309 mVerifyState = CVS_Bad; 310 return crtn; 311 } 312 } 313 } 314 } 315 316 /* 317 * Step 3: obtain a fully verified cert chain which verifies this CRL. 318 */ 319 CSSM_BOOL verifiedToRoot; 320 CSSM_BOOL verifiedToAnchor; 321 CSSM_BOOL verifiedViaTrustSetting; 322 323 TPCertGroup outCertGroup(tpVerifyContext.alloc, 324 TGO_Caller); // CRLs owned by inCertGroup 325 326 /* set up for disposal of TPCertInfos created by 327 * CertGroupConstructPriv */ 328 TPCertGroup certsToBeFreed(tpVerifyContext.alloc, TGO_Group); 329 330 if(tpVerifyContext.signerCerts) { 331 /* start from scratch with this group */ 332 tpVerifyContext.signerCerts->setAllUnused(); 333 } 334 crtn = outCertGroup.buildCertGroup( 335 *this, // subject item 336 tpVerifyContext.signerCerts, // inCertGroup, optional 337 tpVerifyContext.dbList, // optional 338 tpVerifyContext.clHand, 339 tpVerifyContext.cspHand, 340 tpVerifyContext.verifyTime, 341 tpVerifyContext.numAnchorCerts, 342 tpVerifyContext.anchorCerts, 343 certsToBeFreed, 344 &tpVerifyContext.gatheredCerts, 345 CSSM_FALSE, // subjectIsInGroup 346 tpVerifyContext.actionFlags, 347 tpVerifyContext.policyOid, 348 tpVerifyContext.policyStr, 349 tpVerifyContext.policyStrLen, 350 kSecTrustSettingsKeyUseSignRevocation, 351 verifiedToRoot, 352 verifiedToAnchor, 353 verifiedViaTrustSetting); 354 /* subsequent errors to errOut: */ 355 356 if(crtn) { 357 tpCrlDebug("TPCrlInfo::verifyWithContext buildCertGroup failure " 358 "index %u", index()); 359 if(!forCert || forCert->addStatusCode(crtn)) { 360 goto errOut; 361 } 362 } 363 if (verifiedToRoot && (tpVerifyContext.actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS)) 364 verifiedToAnchor = CSSM_TRUE; 365 if(!verifiedToAnchor && !verifiedViaTrustSetting) { 366 /* required */ 367 if(verifiedToRoot) { 368 /* verified to root which is not an anchor */ 369 tpCrlDebug("TPCrlInfo::verifyWithContext root, no anchor, " 370 "index %u", index()); 371 crtn = CSSMERR_APPLETP_CRL_INVALID_ANCHOR_CERT; 372 } 373 else { 374 /* partial chain, no root, not verifiable by anchor */ 375 tpCrlDebug("TPCrlInfo::verifyWithContext no root, no anchor, " 376 "index %u", index()); 377 crtn = CSSMERR_APPLETP_CRL_NOT_TRUSTED; 378 } 379 if(!forCert || forCert->addStatusCode(crtn)) { 380 mVerifyState = CVS_Bad; 381 goto errOut; 382 } 383 } 384 385 /* 386 * Step 4: policy verification on the returned cert group 387 * We need to (temporarily) assert the "leaf cert is a CA" flag 388 * here. 389 */ 390 outCertGroup.certAtIndex(0)->isLeaf(true); 391 crtn = tp_policyVerify(kCrlPolicy, 392 tpVerifyContext.alloc, 393 tpVerifyContext.clHand, 394 tpVerifyContext.cspHand, 395 &outCertGroup, 396 verifiedToRoot, 397 verifiedViaTrustSetting, 398 tpVerifyContext.actionFlags | CSSM_TP_ACTION_LEAF_IS_CA, 399 NULL, // sslOpts 400 NULL); // policyOpts, not currently used 401 if(crtn) { 402 tpCrlDebug(" ...verifyWithContext policy FAILURE CRL %u", 403 index()); 404 if(!forCert || forCert->addStatusCode(CSSMERR_APPLETP_CRL_POLICY_FAIL)) { 405 mVerifyState = CVS_Bad; 406 goto errOut; 407 } 408 } 409 410 /* 411 * Step 5: recursively perform CRL verification on the certs 412 * gathered to verify this CRL. 413 * Only performed if this CRL is an indirect CRL or the caller 414 * explicitly told us to do this (i.e., caller is verifying a 415 * CRL, not a cert chain). 416 */ 417 if(isIndirectCrl || doCrlVerify) { 418 tpCrlDebug("verifyWithContext recursing to " 419 "tpVerifyCertGroupWithCrls"); 420 crtn = tpVerifyCertGroupWithCrls(tpVerifyContext, 421 outCertGroup); 422 if(crtn) { 423 tpCrlDebug(" ...verifyWithContext CRL reverify FAILURE CRL %u", 424 index()); 425 if(!forCert || forCert->addStatusCode(crtn)) { 426 mVerifyState = CVS_Bad; 427 goto errOut; 428 } 429 } 430 } 431 432 tpCrlDebug(" ...verifyWithContext CRL %u SUCCESS", index()); 433 mVerifyState = CVS_Good; 434errOut: 435 /* we own these, we free the DB records */ 436 certsToBeFreed.freeDbRecords(); 437 return crtn; 438} 439 440/* 441 * Wrapper for verifyWithContext for use when evaluating a CRL 442 * "now" instead of at the time in TPVerifyContext.verifyTime. 443 * In this case, on entry, TPVerifyContext.verifyTime is the 444 * time at which a cert is being evaluated. 445 */ 446CSSM_RETURN TPCrlInfo::verifyWithContextNow( 447 TPVerifyContext &tpVerifyContext, 448 TPCertInfo *forCert, // optional 449 bool doCrlVerify) 450{ 451 CSSM_TIMESTRING ctxTime = tpVerifyContext.verifyTime; 452 CSSM_RETURN crtn = verifyWithContext(tpVerifyContext, forCert, doCrlVerify); 453 tpVerifyContext.verifyTime = ctxTime; 454 return crtn; 455} 456 457/* 458 * Do I have the same issuer as the specified subject cert? Returns 459 * true if so. 460 */ 461bool TPCrlInfo::hasSameIssuer( 462 const TPCertInfo &subject) 463{ 464 assert(subject.issuerName() != NULL); 465 if(tpCompareCssmData(issuerName(), subject.issuerName())) { 466 return true; 467 } 468 else { 469 return false; 470 } 471} 472 473/* 474 * Determine if specified cert has been revoked as of the 475 * provided time; a NULL timestring indicates "now". 476 * 477 * Assumes current CRL is verified good and that issuer names of 478 * the cert and CRL match. 479 * 480 * This duplicates similar logic in the CL, but to avoid re-parsing 481 * the subject cert (which we have parsed and cached), we just do it 482 * here. 483 * 484 * Possible errors are 485 * CSSMERR_TP_CERT_REVOKED 486 * CSSMERR_TP_CERT_SUSPENDED 487 * TBD 488 * 489 * Error status is added to subjectCert. 490 */ 491CSSM_RETURN TPCrlInfo::isCertRevoked( 492 TPCertInfo &subjectCert, 493 CSSM_TIMESTRING verifyTime) 494{ 495 assert(mVerifyState == CVS_Good); 496 CSSM_X509_TBS_CERTLIST_PTR tbs = &mX509Crl->tbsCertList; 497 498 /* trivial case - empty CRL */ 499 if((tbs->revokedCertificates == NULL) || 500 (tbs->revokedCertificates->numberOfRevokedCertEntries == 0)) { 501 tpCrlDebug(" isCertRevoked: empty CRL at index %u", index()); 502 return CSSM_OK; 503 } 504 505 /* is subject cert's serial number in this CRL? */ 506 CSSM_DATA_PTR subjSerial = NULL; 507 CSSM_RETURN crtn; 508 crtn = subjectCert.fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial); 509 if(crtn) { 510 /* should never happen */ 511 tpErrorLog("TPCrlInfo:isCertRevoked: error fetching serial number\n"); 512 if(subjectCert.addStatusCode(crtn)) { 513 return crtn; 514 } 515 else { 516 /* allowed error - can't proceed; punt with success */ 517 return CSSM_OK; 518 } 519 } 520 /* subsequent errors to errOut: */ 521 522 uint32 numEntries = tbs->revokedCertificates->numberOfRevokedCertEntries; 523 CSSM_X509_REVOKED_CERT_ENTRY_PTR entries = 524 tbs->revokedCertificates->revokedCertEntry; 525 crtn = CSSM_OK; 526 CFDateRef cfRevokedTime = NULL; 527 CFDateRef cfVerifyTime = NULL; 528 529 for(uint32 dex=0; dex<numEntries; dex++) { 530 CSSM_X509_REVOKED_CERT_ENTRY_PTR entry = &entries[dex]; 531 if(tpCompareCssmData(subjSerial, &entry->certificateSerialNumber)) { 532 /* 533 * It's in there. Compare revocation time in the CRL to 534 * our caller-specified verifyTime. 535 */ 536 CSSM_X509_TIME_PTR xTime = &entry->revocationDate; 537 int rtn; 538 rtn = timeStringToCfDate((char *)xTime->time.Data, (unsigned)xTime->time.Length, 539 &cfRevokedTime); 540 if(rtn) { 541 tpErrorLog("fetchNotBeforeAfter: malformed revocationDate\n"); 542 } 543 else { 544 if(verifyTime != NULL) { 545 rtn = timeStringToCfDate((char *)verifyTime, (unsigned)strlen(verifyTime), 546 &cfVerifyTime); 547 } 548 else { 549 /* verify right now */ 550 cfVerifyTime = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); 551 } 552 if((rtn == 0) && cfVerifyTime != NULL) { 553 CFComparisonResult res = CFDateCompare(cfVerifyTime, cfRevokedTime, NULL); 554 if(res == kCFCompareLessThan) { 555 /* cfVerifyTime < cfRevokedTime; I guess this one's OK */ 556 tpCrlDebug(" isCertRevoked: cert %u NOT YET REVOKED by CRL %u", 557 subjectCert.index(), index()); 558 break; 559 } 560 } 561 } 562 563 /* 564 * REQUIRED TBD: parse the entry's extensions, specifically to 565 * get a reason. This will entail a bunch of new TP/cert specific 566 * CSSM_RETURNS. 567 * For now, just flag it revoked. 568 */ 569 crtn = CSSMERR_TP_CERT_REVOKED; 570 tpCrlDebug(" isCertRevoked: cert %u REVOKED by CRL %u", 571 subjectCert.index(), index()); 572 break; 573 } 574 } 575 576 subjectCert.freeField(&CSSMOID_X509V1SerialNumber, subjSerial); 577 if(crtn && !subjectCert.addStatusCode(crtn)) { 578 return CSSM_OK; 579 } 580 if(cfRevokedTime) { 581 CFRelease(cfRevokedTime); 582 } 583 if(cfVerifyTime) { 584 CFRelease(cfVerifyTime); 585 } 586 return crtn; 587} 588 589/*** 590 *** TPCrlGroup class 591 ***/ 592 593/* build empty group */ 594TPCrlGroup::TPCrlGroup( 595 Allocator &alloc, 596 TPGroupOwner whoOwns) : 597 mAlloc(alloc), 598 mCrlInfo(NULL), 599 mNumCrls(0), 600 mSizeofCrlInfo(0), 601 mWhoOwns(whoOwns) 602{ 603 /* nothing for now */ 604} 605 606/* 607 * Construct from unordered, untrusted CSSM_CRLGROUP. Resulting 608 * TPCrlInfos are more or less in the same order as the incoming 609 * CRLs, though incoming CRLs are discarded if they don't parse. 610 * No verification of any sort is performed. 611 */ 612TPCrlGroup::TPCrlGroup( 613 const CSSM_CRLGROUP *cssmCrlGroup, // optional 614 CSSM_CL_HANDLE clHand, 615 CSSM_CSP_HANDLE cspHand, 616 Allocator &alloc, 617 const char *verifyTime, // may be NULL 618 TPGroupOwner whoOwns) : 619 mAlloc(alloc), 620 mCrlInfo(NULL), 621 mNumCrls(0), 622 mSizeofCrlInfo(0), 623 mWhoOwns(whoOwns) 624{ 625 /* verify input args */ 626 if((cssmCrlGroup == NULL) || (cssmCrlGroup->NumberOfCrls == 0)) { 627 return; 628 } 629 if(cspHand == CSSM_INVALID_HANDLE) { 630 CssmError::throwMe(CSSMERR_TP_INVALID_CSP_HANDLE); 631 } 632 if(clHand == CSSM_INVALID_HANDLE) { 633 CssmError::throwMe(CSSMERR_TP_INVALID_CL_HANDLE); 634 } 635 if(cssmCrlGroup->CrlGroupType != CSSM_CRLGROUP_DATA) { 636 CssmError::throwMe(CSSMERR_TP_INVALID_CERTGROUP); 637 } 638 switch(cssmCrlGroup->CrlType) { 639 case CSSM_CRL_TYPE_X_509v1: 640 case CSSM_CRL_TYPE_X_509v2: 641 break; 642 default: 643 CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT); 644 } 645 switch(cssmCrlGroup->CrlEncoding) { 646 case CSSM_CRL_ENCODING_BER: 647 case CSSM_CRL_ENCODING_DER: 648 break; 649 default: 650 CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT); 651 } 652 653 /* 654 * Add remaining input certs to mCrlInfo. 655 */ 656 TPCrlInfo *crlInfo = NULL; 657 for(unsigned crlDex=0; crlDex<cssmCrlGroup->NumberOfCrls; crlDex++) { 658 try { 659 crlInfo = new TPCrlInfo(clHand, 660 cspHand, 661 &cssmCrlGroup->GroupCrlList.CrlList[crlDex], 662 TIC_NoCopy, // don't copy data 663 verifyTime); 664 } 665 catch (...) { 666 /* just ignore this CRL */ 667 continue; 668 } 669 crlInfo->index(crlDex); 670 appendCrl(*crlInfo); 671 } 672} 673 674/* 675 * Deletes all TPCrlInfo's if appropriate. 676 */ 677TPCrlGroup::~TPCrlGroup() 678{ 679 if(mWhoOwns == TGO_Group) { 680 unsigned i; 681 for(i=0; i<mNumCrls; i++) { 682 delete mCrlInfo[i]; 683 } 684 } 685 mAlloc.free(mCrlInfo); 686} 687 688/* add/remove/access TPTCrlInfo's. */ 689/* 690 * NOTE: I am aware that most folks would just use an array<> here, but 691 * gdb is so lame that it doesn't even let one examine the contents 692 * of an array<> (or just about anything else in the STL). I prefer 693 * debuggability over saving a few lines of trivial code. 694 */ 695void TPCrlGroup::appendCrl( 696 TPCrlInfo &crlInfo) 697{ 698 if(mNumCrls == mSizeofCrlInfo) { 699 if(mSizeofCrlInfo == 0) { 700 /* appending to empty array */ 701 mSizeofCrlInfo = 1; 702 } 703 else { 704 mSizeofCrlInfo *= 2; 705 } 706 mCrlInfo = (TPCrlInfo **)mAlloc.realloc(mCrlInfo, 707 mSizeofCrlInfo * sizeof(TPCrlInfo *)); 708 } 709 mCrlInfo[mNumCrls++] = &crlInfo; 710} 711 712TPCrlInfo *TPCrlGroup::crlAtIndex( 713 unsigned index) 714{ 715 if(index > (mNumCrls - 1)) { 716 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); 717 } 718 return mCrlInfo[index]; 719} 720 721TPCrlInfo &TPCrlGroup::removeCrlAtIndex( 722 unsigned index) // doesn't delete the cert, just 723 // removes it from our list 724{ 725 if(index > (mNumCrls - 1)) { 726 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); 727 } 728 TPCrlInfo &rtn = *mCrlInfo[index]; 729 730 /* removed requested element and compact remaining array */ 731 unsigned i; 732 for(i=index; i<(mNumCrls - 1); i++) { 733 mCrlInfo[i] = mCrlInfo[i+1]; 734 } 735 mNumCrls--; 736 return rtn; 737} 738 739void TPCrlGroup::removeCrl( 740 TPCrlInfo &crlInfo) 741{ 742 for(unsigned dex=0; dex<mNumCrls; dex++) { 743 if(mCrlInfo[dex] == &crlInfo) { 744 removeCrlAtIndex(dex); 745 return; 746 } 747 } 748 tpErrorLog("TPCrlGroup::removeCrl: CRL NOT FOUND\n"); 749 assert(0); 750} 751 752TPCrlInfo *TPCrlGroup::firstCrl() 753{ 754 if(mNumCrls == 0) { 755 /* the caller really should not do this... */ 756 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); 757 } 758 else { 759 return mCrlInfo[0]; 760 } 761} 762 763TPCrlInfo *TPCrlGroup::lastCrl() 764{ 765 if(mNumCrls == 0) { 766 /* the caller really should not do this... */ 767 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR); 768 } 769 else { 770 return mCrlInfo[mNumCrls - 1]; 771 } 772} 773 774 /* 775 * Find a CRL whose issuer matches specified subject cert. 776 * Returned CRL has not necessarily been verified. 777 */ 778TPCrlInfo *TPCrlGroup::findCrlForCert( 779 TPCertInfo &subject) 780{ 781 for(unsigned dex=0; dex<mNumCrls; dex++) { 782 TPCrlInfo *crl = mCrlInfo[dex]; 783 if(crl->hasSameIssuer(subject)) { 784 return crl; 785 } 786 } 787 return NULL; 788} 789