]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_tp/lib/TPCrlInfo.cpp
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / libsecurity_apple_x509_tp / lib / TPCrlInfo.cpp
1 /*
2 * Copyright (c) 2002,2011-2012,2014-2015 Apple 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 */
23
24 #include "TPCrlInfo.h"
25 #include "tpdebugging.h"
26 #include "certGroupUtils.h"
27 #include "tpCrlVerify.h"
28 #include "tpPolicies.h"
29 #include "tpTime.h"
30 #include <Security/cssmapi.h>
31 #include <Security/x509defs.h>
32 #include <Security/oidscert.h>
33 #include <Security/oidscrl.h>
34 #include <security_cdsa_utilities/cssmerrors.h>
35 #include <string.h> /* for memcmp */
36 #include <Security/cssmapple.h>
37
38 /*
39 * Replacement for CSSM_CL_CrlGetFirstCachedFieldValue for use with
40 * TPCrlItemInfo's generic getFirstCachedField mechanism.
41 */
42 static CSSM_RETURN tpGetFirstCachedFieldValue (CSSM_CL_HANDLE CLHandle,
43 CSSM_HANDLE CrlHandle,
44 const CSSM_OID *CrlField,
45 CSSM_HANDLE_PTR ResultsHandle,
46 uint32 *NumberOfMatchedFields,
47 CSSM_DATA_PTR *Value)
48 {
49 return CSSM_CL_CrlGetFirstCachedFieldValue(CLHandle,
50 CrlHandle,
51 NULL, // const CSSM_DATA *CrlRecordIndex,
52 CrlField,
53 ResultsHandle,
54 NumberOfMatchedFields,
55 Value);
56 }
57
58 static const TPClItemCalls tpCrlClCalls =
59 {
60 tpGetFirstCachedFieldValue,
61 CSSM_CL_CrlAbortQuery,
62 CSSM_CL_CrlCache,
63 CSSM_CL_CrlAbortCache,
64 CSSM_CL_CrlVerify,
65 &CSSMOID_X509V1CRLThisUpdate,
66 &CSSMOID_X509V1CRLNextUpdate,
67 CSSMERR_TP_INVALID_CRL_POINTER,
68 CSSMERR_APPLETP_CRL_EXPIRED,
69 CSSMERR_APPLETP_CRL_NOT_VALID_YET
70 };
71
72
73 /*
74 * No default constructor - this is the only way.
75 * This caches the cert and fetches subjectName and issuerName
76 * to ensure the incoming certData is well-constructed.
77 */
78 TPCrlInfo::TPCrlInfo(
79 CSSM_CL_HANDLE clHand,
80 CSSM_CSP_HANDLE cspHand,
81 const CSSM_DATA *crlData,
82 TPItemCopy copyCrlData, // true: we copy, we free
83 // false - caller owns
84 const char *verifyTime) // = NULL
85
86 : TPClItemInfo(clHand, cspHand, tpCrlClCalls, crlData,
87 copyCrlData, verifyTime),
88 mRefCount(0),
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 Allocator::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(Allocator::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 TPVerifyContext &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_PARSED);
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 or via
245 * Trust Settings if so enabled.
246 * Intermediate certs can come from signerCerts or dBList.
247 */
248 CSSM_RETURN TPCrlInfo::verifyWithContext(
249 TPVerifyContext &tpVerifyContext,
250 TPCertInfo *forCert, // optional
251 bool doCrlVerify)
252 {
253 /*
254 * Step 1: this CRL must be current. Caller might have re-evaluated
255 * expired/notValidYet since our construction via calculateCurrent().
256 */
257 if(isExpired()) {
258 return CSSMERR_APPLETP_CRL_EXPIRED;
259 }
260 if(isNotValidYet()) {
261 return CSSMERR_APPLETP_CRL_NOT_VALID_YET;
262 }
263
264 /* subsequent verify state is cached */
265 switch(mVerifyState) {
266 case CVS_Good:
267 return CSSM_OK;
268 case CVS_Bad:
269 return mVerifyError;
270 case CVS_Unknown:
271 break;
272 default:
273 tpErrorLog("verifyWithContext: bad verifyState\n");
274 return CSSMERR_TP_INTERNAL_ERROR;
275 }
276
277 /*
278 * Step 2: parse & understand all critical CRL extensions.
279 */
280 CSSM_RETURN crtn;
281 bool isIndirectCrl;
282 crtn = parseExtensions(tpVerifyContext,
283 false,
284 0,
285 mX509Crl->tbsCertList.extensions,
286 forCert,
287 isIndirectCrl);
288 if(crtn) {
289 mVerifyState = CVS_Bad;
290 if(!forCert || forCert->addStatusCode(crtn)) {
291 return crtn;
292 }
293 /* else continue */
294 }
295 CSSM_X509_REVOKED_CERT_LIST_PTR revoked =
296 mX509Crl->tbsCertList.revokedCertificates;
297 if(revoked != NULL) {
298 for(uint32 dex=0; dex<revoked->numberOfRevokedCertEntries; dex++) {
299 bool dummyIsIndirect; // can't be set here
300 crtn = parseExtensions(tpVerifyContext,
301 true,
302 dex,
303 revoked->revokedCertEntry[dex].extensions,
304 forCert,
305 dummyIsIndirect);
306 if(crtn) {
307 if(!forCert || forCert->addStatusCode(crtn)) {
308 mVerifyState = CVS_Bad;
309 return crtn;
310 }
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 CSSM_BOOL verifiedViaTrustSetting;
321
322 TPCertGroup outCertGroup(tpVerifyContext.alloc,
323 TGO_Caller); // CRLs owned by inCertGroup
324
325 /* set up for disposal of TPCertInfos created by
326 * CertGroupConstructPriv */
327 TPCertGroup certsToBeFreed(tpVerifyContext.alloc, TGO_Group);
328
329 if(tpVerifyContext.signerCerts) {
330 /* start from scratch with this group */
331 tpVerifyContext.signerCerts->setAllUnused();
332 }
333 crtn = outCertGroup.buildCertGroup(
334 *this, // subject item
335 tpVerifyContext.signerCerts, // inCertGroup, optional
336 tpVerifyContext.dbList, // optional
337 tpVerifyContext.clHand,
338 tpVerifyContext.cspHand,
339 tpVerifyContext.verifyTime,
340 tpVerifyContext.numAnchorCerts,
341 tpVerifyContext.anchorCerts,
342 certsToBeFreed,
343 &tpVerifyContext.gatheredCerts,
344 CSSM_FALSE, // subjectIsInGroup
345 tpVerifyContext.actionFlags,
346 tpVerifyContext.policyOid,
347 tpVerifyContext.policyStr,
348 tpVerifyContext.policyStrLen,
349 kSecTrustSettingsKeyUseSignRevocation,
350 verifiedToRoot,
351 verifiedToAnchor,
352 verifiedViaTrustSetting);
353 /* subsequent errors to errOut: */
354
355 if(crtn) {
356 tpCrlDebug("TPCrlInfo::verifyWithContext buildCertGroup failure "
357 "index %u", index());
358 if(!forCert || forCert->addStatusCode(crtn)) {
359 goto errOut;
360 }
361 }
362 if (verifiedToRoot && (tpVerifyContext.actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS))
363 verifiedToAnchor = CSSM_TRUE;
364 if(!verifiedToAnchor && !verifiedViaTrustSetting) {
365 /* required */
366 if(verifiedToRoot) {
367 /* verified to root which is not an anchor */
368 tpCrlDebug("TPCrlInfo::verifyWithContext root, no anchor, "
369 "index %u", index());
370 crtn = CSSMERR_APPLETP_CRL_INVALID_ANCHOR_CERT;
371 }
372 else {
373 /* partial chain, no root, not verifiable by anchor */
374 tpCrlDebug("TPCrlInfo::verifyWithContext no root, no anchor, "
375 "index %u", index());
376 crtn = CSSMERR_APPLETP_CRL_NOT_TRUSTED;
377 }
378 if(!forCert || forCert->addStatusCode(crtn)) {
379 mVerifyState = CVS_Bad;
380 goto errOut;
381 }
382 }
383
384 /*
385 * Step 4: policy verification on the returned cert group
386 * We need to (temporarily) assert the "leaf cert is a CA" flag
387 * here.
388 */
389 outCertGroup.certAtIndex(0)->isLeaf(true);
390 crtn = tp_policyVerify(kCrlPolicy,
391 tpVerifyContext.alloc,
392 tpVerifyContext.clHand,
393 tpVerifyContext.cspHand,
394 &outCertGroup,
395 verifiedToRoot,
396 verifiedViaTrustSetting,
397 tpVerifyContext.actionFlags | CSSM_TP_ACTION_LEAF_IS_CA,
398 NULL, // sslOpts
399 NULL); // policyOpts, not currently used
400 if(crtn) {
401 tpCrlDebug(" ...verifyWithContext policy FAILURE CRL %u",
402 index());
403 if(!forCert || forCert->addStatusCode(CSSMERR_APPLETP_CRL_POLICY_FAIL)) {
404 mVerifyState = CVS_Bad;
405 goto errOut;
406 }
407 }
408
409 /*
410 * Step 5: recursively perform CRL verification on the certs
411 * gathered to verify this CRL.
412 * Only performed if this CRL is an indirect CRL or the caller
413 * explicitly told us to do this (i.e., caller is verifying a
414 * CRL, not a cert chain).
415 */
416 if(isIndirectCrl || doCrlVerify) {
417 tpCrlDebug("verifyWithContext recursing to "
418 "tpVerifyCertGroupWithCrls");
419 crtn = tpVerifyCertGroupWithCrls(tpVerifyContext,
420 outCertGroup);
421 if(crtn) {
422 tpCrlDebug(" ...verifyWithContext CRL reverify FAILURE CRL %u",
423 index());
424 if(!forCert || forCert->addStatusCode(crtn)) {
425 mVerifyState = CVS_Bad;
426 goto errOut;
427 }
428 }
429 }
430
431 tpCrlDebug(" ...verifyWithContext CRL %u SUCCESS", index());
432 mVerifyState = CVS_Good;
433 errOut:
434 /* we own these, we free the DB records */
435 certsToBeFreed.freeDbRecords();
436 return crtn;
437 }
438
439 /*
440 * Wrapper for verifyWithContext for use when evaluating a CRL
441 * "now" instead of at the time in TPVerifyContext.verifyTime.
442 * In this case, on entry, TPVerifyContext.verifyTime is the
443 * time at which a cert is being evaluated.
444 */
445 CSSM_RETURN TPCrlInfo::verifyWithContextNow(
446 TPVerifyContext &tpVerifyContext,
447 TPCertInfo *forCert, // optional
448 bool doCrlVerify)
449 {
450 CSSM_TIMESTRING ctxTime = tpVerifyContext.verifyTime;
451 CSSM_RETURN crtn = verifyWithContext(tpVerifyContext, forCert, doCrlVerify);
452 tpVerifyContext.verifyTime = ctxTime;
453 return crtn;
454 }
455
456 /*
457 * Do I have the same issuer as the specified subject cert? Returns
458 * true if so.
459 */
460 bool TPCrlInfo::hasSameIssuer(
461 const TPCertInfo &subject)
462 {
463 assert(subject.issuerName() != NULL);
464 if(tpCompareCssmData(issuerName(), subject.issuerName())) {
465 return true;
466 }
467 else {
468 return false;
469 }
470 }
471
472 /*
473 * Determine if specified cert has been revoked as of the
474 * provided time; a NULL timestring indicates "now".
475 *
476 * Assumes current CRL is verified good and that issuer names of
477 * the cert and CRL match.
478 *
479 * This duplicates similar logic in the CL, but to avoid re-parsing
480 * the subject cert (which we have parsed and cached), we just do it
481 * here.
482 *
483 * Possible errors are
484 * CSSMERR_TP_CERT_REVOKED
485 * CSSMERR_TP_CERT_SUSPENDED
486 * TBD
487 *
488 * Error status is added to subjectCert.
489 */
490 CSSM_RETURN TPCrlInfo::isCertRevoked(
491 TPCertInfo &subjectCert,
492 CSSM_TIMESTRING verifyTime)
493 {
494 assert(mVerifyState == CVS_Good);
495 CSSM_X509_TBS_CERTLIST_PTR tbs = &mX509Crl->tbsCertList;
496
497 /* trivial case - empty CRL */
498 if((tbs->revokedCertificates == NULL) ||
499 (tbs->revokedCertificates->numberOfRevokedCertEntries == 0)) {
500 tpCrlDebug(" isCertRevoked: empty CRL at index %u", index());
501 return CSSM_OK;
502 }
503
504 /* is subject cert's serial number in this CRL? */
505 CSSM_DATA_PTR subjSerial = NULL;
506 CSSM_RETURN crtn;
507 crtn = subjectCert.fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial);
508 if(crtn) {
509 /* should never happen */
510 tpErrorLog("TPCrlInfo:isCertRevoked: error fetching serial number\n");
511 if(subjectCert.addStatusCode(crtn)) {
512 return crtn;
513 }
514 else {
515 /* allowed error - can't proceed; punt with success */
516 return CSSM_OK;
517 }
518 }
519 /* subsequent errors to errOut: */
520
521 uint32 numEntries = tbs->revokedCertificates->numberOfRevokedCertEntries;
522 CSSM_X509_REVOKED_CERT_ENTRY_PTR entries =
523 tbs->revokedCertificates->revokedCertEntry;
524 crtn = CSSM_OK;
525 CFDateRef cfRevokedTime = NULL;
526 CFDateRef cfVerifyTime = NULL;
527
528 for(uint32 dex=0; dex<numEntries; dex++) {
529 CSSM_X509_REVOKED_CERT_ENTRY_PTR entry = &entries[dex];
530 if(tpCompareCssmData(subjSerial, &entry->certificateSerialNumber)) {
531 /*
532 * It's in there. Compare revocation time in the CRL to
533 * our caller-specified verifyTime.
534 */
535 CSSM_X509_TIME_PTR xTime = &entry->revocationDate;
536 int rtn;
537 rtn = timeStringToCfDate((char *)xTime->time.Data, (unsigned)xTime->time.Length,
538 &cfRevokedTime);
539 if(rtn) {
540 tpErrorLog("fetchNotBeforeAfter: malformed revocationDate\n");
541 }
542 else {
543 if(verifyTime != NULL) {
544 rtn = timeStringToCfDate((char *)verifyTime, (unsigned)strlen(verifyTime),
545 &cfVerifyTime);
546 }
547 else {
548 /* verify right now */
549 cfVerifyTime = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
550 }
551 if((rtn == 0) && cfVerifyTime != NULL) {
552 CFComparisonResult res = CFDateCompare(cfVerifyTime, cfRevokedTime, NULL);
553 if(res == kCFCompareLessThan) {
554 /* cfVerifyTime < cfRevokedTime; I guess this one's OK */
555 tpCrlDebug(" isCertRevoked: cert %u NOT YET REVOKED by CRL %u",
556 subjectCert.index(), index());
557 break;
558 }
559 }
560 }
561
562 /*
563 * REQUIRED TBD: parse the entry's extensions, specifically to
564 * get a reason. This will entail a bunch of new TP/cert specific
565 * CSSM_RETURNS.
566 * For now, just flag it revoked.
567 */
568 crtn = CSSMERR_TP_CERT_REVOKED;
569 subjectCert.crlReason(1);
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 }