]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_apple_x509_tp/lib/TPCrlInfo.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_apple_x509_tp / lib / TPCrlInfo.cpp
diff --git a/Security/libsecurity_apple_x509_tp/lib/TPCrlInfo.cpp b/Security/libsecurity_apple_x509_tp/lib/TPCrlInfo.cpp
deleted file mode 100644 (file)
index 21581d2..0000000
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * Copyright (c) 2002,2011-2012,2014 Apple Inc. All Rights Reserved.
- * 
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- * 
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-/*
- * TPCrlInfo.h - TP's private CRL and CRL group
- *
- */
-
-#include "TPCrlInfo.h"
-#include "tpdebugging.h"
-#include "certGroupUtils.h"
-#include "tpCrlVerify.h"
-#include "tpPolicies.h"
-#include "tpTime.h"
-#include <Security/cssmapi.h>
-#include <Security/x509defs.h>
-#include <Security/oidscert.h>
-#include <Security/oidscrl.h>
-#include <security_cdsa_utilities/cssmerrors.h>
-#include <string.h>                                            /* for memcmp */
-#include <Security/cssmapple.h>
-
-/*
- * Replacement for CSSM_CL_CrlGetFirstCachedFieldValue for use with 
- * TPCrlItemInfo's generic getFirstCachedField mechanism. 
- */
-static CSSM_RETURN tpGetFirstCachedFieldValue (CSSM_CL_HANDLE CLHandle,
-                                     CSSM_HANDLE CrlHandle,
-                                     const CSSM_OID *CrlField,
-                                     CSSM_HANDLE_PTR ResultsHandle,
-                                     uint32 *NumberOfMatchedFields,
-                                     CSSM_DATA_PTR *Value)
-{
-       return CSSM_CL_CrlGetFirstCachedFieldValue(CLHandle,
-               CrlHandle,
-        NULL,          // const CSSM_DATA *CrlRecordIndex,
-               CrlField,
-               ResultsHandle,
-               NumberOfMatchedFields,
-               Value);
-}
-
-static const TPClItemCalls tpCrlClCalls =
-{
-       tpGetFirstCachedFieldValue,
-       CSSM_CL_CrlAbortQuery,
-       CSSM_CL_CrlCache,
-       CSSM_CL_CrlAbortCache,
-       CSSM_CL_CrlVerify,
-       &CSSMOID_X509V1CRLThisUpdate,
-       &CSSMOID_X509V1CRLNextUpdate,
-       CSSMERR_TP_INVALID_CRL_POINTER,
-       CSSMERR_APPLETP_CRL_EXPIRED,
-       CSSMERR_APPLETP_CRL_NOT_VALID_YET
-};
-
-
-/* 
- * No default constructor - this is the only way.
- * This caches the cert and fetches subjectName and issuerName
- * to ensure the incoming certData is well-constructed.
- */
-TPCrlInfo::TPCrlInfo(
-       CSSM_CL_HANDLE          clHand,
-       CSSM_CSP_HANDLE         cspHand,
-       const CSSM_DATA         *crlData,
-       TPItemCopy                      copyCrlData,            // true: we copy, we free
-                                                                                       // false - caller owns
-       const char                      *verifyTime)            // = NULL
-       
-       : TPClItemInfo(clHand, cspHand, tpCrlClCalls, crlData, 
-                       copyCrlData, verifyTime),
-               mRefCount(0),
-               mFromWhere(CFW_Nowhere),
-               mX509Crl(NULL),
-               mCrlFieldToFree(NULL),
-               mVerifyState(CVS_Unknown),
-               mVerifyError(CSSMERR_TP_INTERNAL_ERROR)
-{
-       CSSM_RETURN     crtn;
-
-       mUri.Data = NULL;
-       mUri.Length = 0;
-       
-       /* fetch parsed CRL */
-       crtn = fetchField(&CSSMOID_X509V2CRLSignedCrlCStruct, &mCrlFieldToFree);
-       if(crtn) {
-               /* bad CRL */
-               releaseResources();
-               CssmError::throwMe(crtn);
-       }
-       if(mCrlFieldToFree->Length != sizeof(CSSM_X509_SIGNED_CRL)) {
-               tpErrorLog("fetchField(SignedCrlCStruct) length error\n");
-               releaseResources();
-               CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
-       }
-       mX509Crl = (CSSM_X509_SIGNED_CRL *)mCrlFieldToFree->Data;
-       /* any other other commonly used fields? */
-}
-       
-TPCrlInfo::~TPCrlInfo()
-{
-       releaseResources();
-}
-
-void TPCrlInfo::releaseResources()
-{
-       if(mCrlFieldToFree) {
-               freeField(&CSSMOID_X509V2CRLSignedCrlCStruct, mCrlFieldToFree);
-               mCrlFieldToFree = NULL;
-       }
-       if(mUri.Data) {
-               Allocator::standard().free(mUri.Data);
-               mUri.Data = NULL;
-               mUri.Length = 0;
-       }
-       TPClItemInfo::releaseResources();
-}
-
-void TPCrlInfo::uri(const CSSM_DATA &uri)
-{
-       tpCopyCssmData(Allocator::standard(), &uri, &mUri);
-}
-
-/*
- * List of extensions we understand and can accept as critical.
- */
-static const CSSM_OID *const TPGoodCrlExtens[] = 
-{
-       &CSSMOID_CrlNumber,
-       /* Note NOT CSSMOID_DeltaCrlIndicator! That's fatal */
-       &CSSMOID_CrlReason,
-       &CSSMOID_CertIssuer,
-       &CSSMOID_IssuingDistributionPoint,
-       &CSSMOID_HoldInstructionCode,
-       &CSSMOID_InvalidityDate,
-       &CSSMOID_AuthorityKeyIdentifier,
-       &CSSMOID_SubjectAltName,
-       &CSSMOID_IssuerAltName
-};
-
-#define NUM_KNOWN_EXTENS (sizeof(TPGoodCrlExtens) / sizeof(CSSM_OID_PTR))
-
-/*
- * Do our best to understand all the entries in a CSSM_X509_EXTENSIONS,
- * which may be per-CRL or per-entry.
- *
- * For now, we just ensure that for every critical extension,
- * we actually understand it and can deal it.
- */
-CSSM_RETURN TPCrlInfo::parseExtensions(
-       TPVerifyContext                         &vfyCtx,
-       bool                                            isPerEntry,
-       uint32                                          entryIndex,             // if isPerEntry
-       const CSSM_X509_EXTENSIONS      &extens,
-       TPCertInfo                                      *forCert,               // optional
-       bool                                            &isIndirectCrl) // RETURNED
-{
-       isIndirectCrl = false;
-       for(uint32 dex=0; dex<extens.numberOfExtensions; dex++) {
-               CSSM_X509_EXTENSION_PTR exten = &extens.extensions[dex];
-               if(exten->critical) {
-                       /* critical: is it in our list of understood extensions? */
-                       unsigned i;
-                       for(i=0; i<NUM_KNOWN_EXTENS; i++) {
-                               if(tpCompareOids(&exten->extnId, TPGoodCrlExtens[i])) {
-                                       /* we're cool with this one */
-                                       break;
-                               }
-                       }
-                       if(i == NUM_KNOWN_EXTENS) {
-                               tpCrlDebug("parseExtensions: Unknown Critical Extension\n");
-                               return CSSMERR_APPLETP_UNKNOWN_CRL_EXTEN;
-                       }
-               }
-               
-               /* Specific extension handling. */
-               if(tpCompareOids(&exten->extnId, 
-                               &CSSMOID_IssuingDistributionPoint)) {
-                       /*
-                        * If this assertion fails, we're out of sync with the CL
-                        */
-                       assert(exten->format == CSSM_X509_DATAFORMAT_PARSED);
-                       CE_IssuingDistributionPoint *idp = 
-                               (CE_IssuingDistributionPoint *)
-                                       exten->value.parsedValue;
-                                       
-                       /*
-                        * Snag indirectCrl flag for caller in any case
-                        */
-                       if(idp->indirectCrlPresent && idp->indirectCrl) {
-                               isIndirectCrl = true;
-                       }
-                       if(forCert != NULL) {
-                               /* If no target cert, i.e., we're just verifying a CRL,
-                                * skip the remaining IDP checks. */
-                               
-                               /* verify onlyCACerts/onlyUserCerts */
-                               bool isUserCert;
-                               if(forCert->isLeaf() &&
-                                       !(vfyCtx.actionFlags & CSSM_TP_ACTION_LEAF_IS_CA)) {
-                                               isUserCert = true;
-                               }
-                               else {
-                                       isUserCert = false;
-                               }
-                               if((idp->onlyUserCertsPresent) && (idp->onlyUserCerts)) {
-                                       if(!isUserCert) {
-                                               tpCrlDebug("parseExtensions: onlyUserCerts, "
-                                                       "!leaf\n");
-                                               return CSSMERR_APPLETP_IDP_FAIL;
-                                       }
-                               }
-                               if((idp->onlyCACertsPresent) && (idp->onlyCACerts)) {
-                                       if(isUserCert) {
-                                               tpCrlDebug("parseExtensions: onlyCACerts, leaf\n");
-                                               return CSSMERR_APPLETP_IDP_FAIL;
-                                       }
-                               }
-                       }       /* IDP */
-               }               /* have target cert */
-       }
-       
-       return CSSM_OK;
-}
-
-/* 
- * The heavyweight "perform full verification of this CRL" op.
- * Must verify to an anchor cert in tpVerifyContext or via
- * Trust Settings if so enabled. 
- * Intermediate certs can come from signerCerts or dBList. 
- */
-CSSM_RETURN TPCrlInfo::verifyWithContext(
-       TPVerifyContext                 &tpVerifyContext,
-       TPCertInfo                              *forCert,               // optional 
-       bool                                    doCrlVerify)    
-{
-       /*
-        * Step 1: this CRL must be current. Caller might have re-evaluated
-        * expired/notValidYet since our construction via calculateCurrent().
-        */
-       if(isExpired()) {
-               return CSSMERR_APPLETP_CRL_EXPIRED;
-       }
-       if(isNotValidYet()) {
-               return CSSMERR_APPLETP_CRL_NOT_VALID_YET;
-       }
-
-       /* subsequent verify state is cached */
-       switch(mVerifyState) {
-               case CVS_Good:
-                       return CSSM_OK;
-               case CVS_Bad:
-                       return mVerifyError;
-               case CVS_Unknown:
-                       break;
-               default:
-                       tpErrorLog("verifyWithContext: bad verifyState\n");
-                       return CSSMERR_TP_INTERNAL_ERROR;
-       }
-       
-       /*
-        * Step 2: parse & understand all critical CRL extensions. 
-        */
-       CSSM_RETURN crtn;
-       bool isIndirectCrl;
-       crtn = parseExtensions(tpVerifyContext,
-               false,
-               0,
-               mX509Crl->tbsCertList.extensions,
-               forCert,
-               isIndirectCrl);
-       if(crtn) {
-               mVerifyState = CVS_Bad;
-               if(!forCert || forCert->addStatusCode(crtn)) {
-                       return crtn;
-               }
-               /* else continue */
-       }
-       CSSM_X509_REVOKED_CERT_LIST_PTR revoked = 
-                       mX509Crl->tbsCertList.revokedCertificates;
-       if(revoked != NULL) {
-               for(uint32 dex=0; dex<revoked->numberOfRevokedCertEntries; dex++) {
-                       bool dummyIsIndirect;   // can't be set here 
-                       crtn = parseExtensions(tpVerifyContext,
-                               true,
-                               dex,
-                               revoked->revokedCertEntry[dex].extensions,
-                               forCert,
-                               dummyIsIndirect);
-                       if(crtn) {
-                               if(!forCert || forCert->addStatusCode(crtn)) {
-                                       mVerifyState = CVS_Bad;
-                                       return crtn;
-                               }
-                       }
-               }
-       }
-       
-       /*
-        * Step 3: obtain a fully verified cert chain which verifies this CRL.
-        */
-       CSSM_BOOL       verifiedToRoot;
-       CSSM_BOOL       verifiedToAnchor;
-       CSSM_BOOL       verifiedViaTrustSetting;
-       
-       TPCertGroup outCertGroup(tpVerifyContext.alloc, 
-               TGO_Caller);                    // CRLs owned by inCertGroup
-
-       /* set up for disposal of TPCertInfos created by 
-        * CertGroupConstructPriv */
-       TPCertGroup     certsToBeFreed(tpVerifyContext.alloc, TGO_Group);
-       
-       if(tpVerifyContext.signerCerts) {
-               /* start from scratch with this group */
-               tpVerifyContext.signerCerts->setAllUnused();
-       }
-       crtn = outCertGroup.buildCertGroup(
-                       *this,                                                  // subject item
-                       tpVerifyContext.signerCerts,    // inCertGroup, optional
-                       tpVerifyContext.dbList,                 // optional
-                       tpVerifyContext.clHand,
-                       tpVerifyContext.cspHand,
-                       tpVerifyContext.verifyTime,
-                       tpVerifyContext.numAnchorCerts,
-                       tpVerifyContext.anchorCerts,
-                       certsToBeFreed,
-                       &tpVerifyContext.gatheredCerts,
-                       CSSM_FALSE,                                             // subjectIsInGroup
-                       tpVerifyContext.actionFlags,
-                       tpVerifyContext.policyOid,
-                       tpVerifyContext.policyStr,
-                       tpVerifyContext.policyStrLen,
-                       kSecTrustSettingsKeyUseSignRevocation,
-                       verifiedToRoot, 
-                       verifiedToAnchor,
-                       verifiedViaTrustSetting);
-       /* subsequent errors to errOut: */
-
-       if(crtn) {
-               tpCrlDebug("TPCrlInfo::verifyWithContext buildCertGroup failure "
-                       "index %u",     index());
-               if(!forCert || forCert->addStatusCode(crtn)) {
-                       goto errOut;
-               }
-       }
-       if (verifiedToRoot && (tpVerifyContext.actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS))
-               verifiedToAnchor = CSSM_TRUE;
-       if(!verifiedToAnchor && !verifiedViaTrustSetting) {
-               /* required */
-               if(verifiedToRoot) {
-                       /* verified to root which is not an anchor */
-                       tpCrlDebug("TPCrlInfo::verifyWithContext root, no anchor, "
-                               "index %u",     index());
-                       crtn = CSSMERR_APPLETP_CRL_INVALID_ANCHOR_CERT;
-               }
-               else {
-                       /* partial chain, no root, not verifiable by anchor */
-                       tpCrlDebug("TPCrlInfo::verifyWithContext no root, no anchor, "
-                               "index %u",     index());
-                       crtn = CSSMERR_APPLETP_CRL_NOT_TRUSTED;
-               }
-               if(!forCert || forCert->addStatusCode(crtn)) {
-                       mVerifyState = CVS_Bad;
-                       goto errOut;
-               }
-       }
-       
-       /* 
-        * Step 4: policy verification on the returned cert group 
-        * We need to (temporarily) assert the "leaf cert is a CA" flag
-        * here. 
-        */
-       outCertGroup.certAtIndex(0)->isLeaf(true);
-       crtn = tp_policyVerify(kCrlPolicy,
-               tpVerifyContext.alloc,
-               tpVerifyContext.clHand,
-               tpVerifyContext.cspHand,
-               &outCertGroup,
-               verifiedToRoot,
-               verifiedViaTrustSetting,
-               tpVerifyContext.actionFlags | CSSM_TP_ACTION_LEAF_IS_CA,
-               NULL,                                                   // sslOpts
-               NULL);                                                  // policyOpts, not currently used 
-       if(crtn) {
-               tpCrlDebug("   ...verifyWithContext policy FAILURE CRL %u",
-                       index());
-               if(!forCert || forCert->addStatusCode(CSSMERR_APPLETP_CRL_POLICY_FAIL)) {
-                       mVerifyState = CVS_Bad;
-                       goto errOut;
-               }
-       }
-       
-       /*
-        * Step 5: recursively perform CRL verification on the certs 
-        * gathered to verify this CRL. 
-        * Only performed if this CRL is an indirect CRL or the caller
-        * explicitly told us to do this (i.e., caller is verifying a
-        * CRL, not a cert chain).
-        */
-       if(isIndirectCrl || doCrlVerify) {
-               tpCrlDebug("verifyWithContext recursing to "
-                       "tpVerifyCertGroupWithCrls");
-               crtn = tpVerifyCertGroupWithCrls(tpVerifyContext,
-                       outCertGroup);
-               if(crtn) {
-                       tpCrlDebug("   ...verifyWithContext CRL reverify FAILURE CRL %u",
-                               index());
-                       if(!forCert || forCert->addStatusCode(crtn)) {
-                               mVerifyState = CVS_Bad;
-                               goto errOut;
-                       }
-               }
-       }
-
-       tpCrlDebug("   ...verifyWithContext CRL %u SUCCESS", index());
-       mVerifyState = CVS_Good;
-errOut:
-       /* we own these, we free the DB records */
-       certsToBeFreed.freeDbRecords();
-       return crtn;
-}
-
-/*
- * Wrapper for verifyWithContext for use when evaluating a CRL
- * "now" instead of at the time in TPVerifyContext.verifyTime.
- * In this case, on entry, TPVerifyContext.verifyTime is the 
- * time at which a cert is being evaluated.
- */
-CSSM_RETURN TPCrlInfo::verifyWithContextNow(
-       TPVerifyContext         &tpVerifyContext,
-       TPCertInfo                      *forCert,                       // optional
-       bool                            doCrlVerify)
-{
-       CSSM_TIMESTRING ctxTime = tpVerifyContext.verifyTime;
-       CSSM_RETURN crtn = verifyWithContext(tpVerifyContext, forCert, doCrlVerify);
-       tpVerifyContext.verifyTime = ctxTime;
-       return crtn;
-}
-
-/*
- * Do I have the same issuer as the specified subject cert? Returns 
- * true if so.
- */
-bool TPCrlInfo::hasSameIssuer(
-       const TPCertInfo        &subject)
-{
-       assert(subject.issuerName() != NULL);
-       if(tpCompareCssmData(issuerName(), subject.issuerName())) {
-               return true;
-       }
-       else {
-               return false;
-       }
-}
-
-/*
- * Determine if specified cert has been revoked as of the
- * provided time; a NULL timestring indicates "now". 
- *
- * Assumes current CRL is verified good and that issuer names of 
- * the cert and CRL match.
- *
- * This duplicates similar logic in the CL, but to avoid re-parsing
- * the subject cert (which we have parsed and cached), we just do it 
- * here.
- *
- * Possible errors are 
- *     CSSMERR_TP_CERT_REVOKED
- *     CSSMERR_TP_CERT_SUSPENDED
- *  TBD
- *
- * Error status is added to subjectCert. 
- */
-CSSM_RETURN TPCrlInfo::isCertRevoked(
-       TPCertInfo &subjectCert,
-       CSSM_TIMESTRING verifyTime)
-{
-       assert(mVerifyState == CVS_Good);
-       CSSM_X509_TBS_CERTLIST_PTR tbs = &mX509Crl->tbsCertList;
-       
-       /* trivial case - empty CRL */
-       if((tbs->revokedCertificates == NULL) ||
-          (tbs->revokedCertificates->numberOfRevokedCertEntries == 0)) {
-          tpCrlDebug("   isCertRevoked: empty CRL at index %u", index());
-          return CSSM_OK;
-       }
-       
-       /* is subject cert's serial number in this CRL? */
-       CSSM_DATA_PTR subjSerial = NULL;
-       CSSM_RETURN crtn;
-       crtn = subjectCert.fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial);
-       if(crtn) {
-               /* should never happen */
-               tpErrorLog("TPCrlInfo:isCertRevoked: error fetching serial number\n");
-               if(subjectCert.addStatusCode(crtn)) {
-                       return crtn;
-               }
-               else {
-                       /* allowed error - can't proceed; punt with success */
-                       return CSSM_OK;
-               }
-       }
-       /* subsequent errors to errOut: */
-       
-       uint32 numEntries = tbs->revokedCertificates->numberOfRevokedCertEntries;
-       CSSM_X509_REVOKED_CERT_ENTRY_PTR entries = 
-               tbs->revokedCertificates->revokedCertEntry;
-       crtn = CSSM_OK;
-       CFDateRef cfRevokedTime = NULL;
-       CFDateRef cfVerifyTime = NULL;
-
-       for(uint32 dex=0; dex<numEntries; dex++) {
-               CSSM_X509_REVOKED_CERT_ENTRY_PTR entry = &entries[dex];
-               if(tpCompareCssmData(subjSerial, &entry->certificateSerialNumber)) {
-                       /* 
-                        * It's in there. Compare revocation time in the CRL to 
-                        * our caller-specified verifyTime.
-                        */
-                       CSSM_X509_TIME_PTR xTime = &entry->revocationDate;
-                       int rtn;
-                       rtn = timeStringToCfDate((char *)xTime->time.Data, (unsigned)xTime->time.Length,
-                               &cfRevokedTime);
-                       if(rtn) {
-                               tpErrorLog("fetchNotBeforeAfter: malformed revocationDate\n");
-                       }
-                       else {
-                               if(verifyTime != NULL) {
-                                       rtn = timeStringToCfDate((char *)verifyTime, (unsigned)strlen(verifyTime),
-                                                                                        &cfVerifyTime);
-                               }
-                               else {
-                                       /* verify right now */
-                                       cfVerifyTime = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
-                               }
-                               if((rtn == 0) && cfVerifyTime != NULL) {
-                                       CFComparisonResult res = CFDateCompare(cfVerifyTime, cfRevokedTime, NULL);
-                                       if(res == kCFCompareLessThan) {
-                                               /* cfVerifyTime < cfRevokedTime; I guess this one's OK */
-                                               tpCrlDebug("   isCertRevoked: cert %u NOT YET REVOKED by CRL %u", 
-                                                                  subjectCert.index(), index());
-                                               break;
-                                       }
-                               }
-                       }
-
-                       /*
-                        * REQUIRED TBD: parse the entry's extensions, specifically to 
-                        * get a reason. This will entail a bunch of new TP/cert specific
-                        * CSSM_RETURNS.
-                        * For now, just flag it revoked. 
-                        */
-                       crtn = CSSMERR_TP_CERT_REVOKED;
-                       tpCrlDebug("   isCertRevoked: cert %u REVOKED by CRL %u", 
-                               subjectCert.index(), index());
-                       break;
-               }
-       }
-       
-       subjectCert.freeField(&CSSMOID_X509V1SerialNumber, subjSerial);
-       if(crtn && !subjectCert.addStatusCode(crtn)) {
-               return CSSM_OK;
-       }
-       if(cfRevokedTime) {
-               CFRelease(cfRevokedTime);
-       }
-       if(cfVerifyTime) {
-               CFRelease(cfVerifyTime);
-       }
-       return crtn;
-}
-
-/***
- *** TPCrlGroup class
- ***/
-/* build empty group */
-TPCrlGroup::TPCrlGroup(
-       Allocator                       &alloc,
-       TPGroupOwner            whoOwns) :
-               mAlloc(alloc),
-               mCrlInfo(NULL),
-               mNumCrls(0),
-               mSizeofCrlInfo(0),
-               mWhoOwns(whoOwns)
-{
-       /* nothing for now */
-}
-       
-/*
- * Construct from unordered, untrusted CSSM_CRLGROUP. Resulting
- * TPCrlInfos are more or less in the same order as the incoming
- * CRLs, though incoming CRLs are discarded if they don't parse.
- * No verification of any sort is performed. 
- */
-TPCrlGroup::TPCrlGroup(
-       const CSSM_CRLGROUP     *cssmCrlGroup,                  // optional
-       CSSM_CL_HANDLE                  clHand,
-       CSSM_CSP_HANDLE                 cspHand,
-       Allocator                               &alloc,
-       const char                              *verifyTime,                    // may be NULL
-       TPGroupOwner                    whoOwns) :
-               mAlloc(alloc),
-               mCrlInfo(NULL),
-               mNumCrls(0),
-               mSizeofCrlInfo(0),
-               mWhoOwns(whoOwns)
-{
-       /* verify input args */
-       if((cssmCrlGroup == NULL) || (cssmCrlGroup->NumberOfCrls == 0)) {
-               return;
-       }
-       if(cspHand == CSSM_INVALID_HANDLE) {
-               CssmError::throwMe(CSSMERR_TP_INVALID_CSP_HANDLE);
-       }
-       if(clHand == CSSM_INVALID_HANDLE)       {
-               CssmError::throwMe(CSSMERR_TP_INVALID_CL_HANDLE);
-       }
-       if(cssmCrlGroup->CrlGroupType != CSSM_CRLGROUP_DATA) {
-               CssmError::throwMe(CSSMERR_TP_INVALID_CERTGROUP);
-       }
-       switch(cssmCrlGroup->CrlType) {
-               case CSSM_CRL_TYPE_X_509v1:
-               case CSSM_CRL_TYPE_X_509v2:
-                       break;
-               default:
-                       CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT);
-       }
-       switch(cssmCrlGroup->CrlEncoding) {
-               case CSSM_CRL_ENCODING_BER:
-               case CSSM_CRL_ENCODING_DER:
-                       break;
-               default:
-                       CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT);
-       }
-       
-       /* 
-        * Add remaining input certs to mCrlInfo.
-        */
-       TPCrlInfo *crlInfo = NULL;
-       for(unsigned crlDex=0; crlDex<cssmCrlGroup->NumberOfCrls; crlDex++) {
-               try {
-                       crlInfo = new TPCrlInfo(clHand,
-                               cspHand,
-                               &cssmCrlGroup->GroupCrlList.CrlList[crlDex],
-                               TIC_NoCopy,                     // don't copy data 
-                               verifyTime);
-               }
-               catch (...) {
-                       /* just ignore this CRL */
-                       continue;
-               }
-               crlInfo->index(crlDex);
-               appendCrl(*crlInfo);
-       }
-}
-
-/*
- * Deletes all TPCrlInfo's if appropriate.
- */
-TPCrlGroup::~TPCrlGroup()
-{
-       if(mWhoOwns == TGO_Group) {
-               unsigned i;
-               for(i=0; i<mNumCrls; i++) {
-                       delete mCrlInfo[i];
-               }
-       }
-       mAlloc.free(mCrlInfo);
-}
-
-/* add/remove/access TPTCrlInfo's. */
-/*
- * NOTE: I am aware that most folks would just use an array<> here, but
- * gdb is so lame that it doesn't even let one examine the contents
- * of an array<> (or just about anything else in the STL). I prefer
- * debuggability over saving a few lines of trivial code.
- */
-void TPCrlGroup::appendCrl(
-       TPCrlInfo                       &crlInfo)
-{
-       if(mNumCrls == mSizeofCrlInfo) {
-               if(mSizeofCrlInfo == 0) {
-                       /* appending to empty array */
-                       mSizeofCrlInfo = 1;
-               }
-               else {
-                       mSizeofCrlInfo *= 2;
-               }
-               mCrlInfo = (TPCrlInfo **)mAlloc.realloc(mCrlInfo, 
-                       mSizeofCrlInfo * sizeof(TPCrlInfo *));
-       }
-       mCrlInfo[mNumCrls++] = &crlInfo;
-}
-
-TPCrlInfo *TPCrlGroup::crlAtIndex(
-       unsigned                        index)
-{
-       if(index > (mNumCrls - 1)) {
-               CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
-       }
-       return mCrlInfo[index];
-}
-
-TPCrlInfo &TPCrlGroup::removeCrlAtIndex(
-       unsigned                        index)                          // doesn't delete the cert, just 
-                                                                                       // removes it from our list
-{
-       if(index > (mNumCrls - 1)) {
-               CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
-       }
-       TPCrlInfo &rtn = *mCrlInfo[index];
-       
-       /* removed requested element and compact remaining array */
-       unsigned i;
-       for(i=index; i<(mNumCrls - 1); i++) {
-               mCrlInfo[i] = mCrlInfo[i+1];
-       }
-       mNumCrls--;
-       return rtn;
-}
-
-void TPCrlGroup::removeCrl(
-       TPCrlInfo                       &crlInfo)
-{
-       for(unsigned dex=0; dex<mNumCrls; dex++) {
-               if(mCrlInfo[dex] == &crlInfo) {
-                       removeCrlAtIndex(dex);
-                       return;
-               }
-       }
-       tpErrorLog("TPCrlGroup::removeCrl: CRL NOT FOUND\n");
-       assert(0);
-}
-
-TPCrlInfo *TPCrlGroup::firstCrl()
-{
-       if(mNumCrls == 0) {
-               /* the caller really should not do this... */
-               CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
-       }
-       else {
-               return mCrlInfo[0];
-       }
-}
-
-TPCrlInfo *TPCrlGroup::lastCrl()
-{
-       if(mNumCrls == 0) {
-               /* the caller really should not do this... */
-               CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
-       }
-       else {
-               return mCrlInfo[mNumCrls - 1];
-       }
-}
-
-       /* 
-        * Find a CRL whose issuer matches specified subject cert.
-        * Returned CRL has not necessarily been verified.
-        */
-TPCrlInfo *TPCrlGroup::findCrlForCert(
-               TPCertInfo                      &subject)
-{
-       for(unsigned dex=0; dex<mNumCrls; dex++) {
-               TPCrlInfo *crl = mCrlInfo[dex];
-               if(crl->hasSameIssuer(subject)) {
-                       return crl;
-               }
-       }
-       return NULL;
-}