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