X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/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 index 21581d2f..00000000 --- a/Security/libsecurity_apple_x509_tp/lib/TPCrlInfo.cpp +++ /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 -#include -#include -#include -#include -#include /* for memcmp */ -#include - -/* - * 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; dexcritical) { - /* critical: is it in our list of understood extensions? */ - unsigned i; - for(i=0; iextnId, 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; dexnumberOfRevokedCertEntries; 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; dexcertificateSerialNumber)) { - /* - * 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; crlDexNumberOfCrls; 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 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; dexhasSameIssuer(subject)) { - return crl; - } - } - return NULL; -}