]> git.saurik.com Git - apple/security.git/blob - libsecurity_apple_x509_tp/lib/TPCrlInfo.cpp
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_apple_x509_tp / lib / 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 "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 */
43 static 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
59 static 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 */
79 TPCrlInfo::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
117 TPCrlInfo::~TPCrlInfo()
118 {
119 releaseResources();
120 }
121
122 void 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
136 void 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 */
144 static 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 */
167 CSSM_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 */
249 CSSM_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;
434 errOut:
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 */
446 CSSM_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 */
461 bool 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 */
491 CSSM_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 */
594 TPCrlGroup::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 */
612 TPCrlGroup::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 */
677 TPCrlGroup::~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 */
695 void 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
712 TPCrlInfo *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
721 TPCrlInfo &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
739 void 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
752 TPCrlInfo *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
763 TPCrlInfo *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 */
778 TPCrlInfo *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 }