2  * Copyright (c) 2002,2011-2012,2014-2015 Apple Inc. All Rights Reserved. 
   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 
  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. 
  20  * TPCrlInfo.h - TP's private CRL and CRL group 
  24 #include "TPCrlInfo.h" 
  25 #include "tpdebugging.h" 
  26 #include "certGroupUtils.h" 
  27 #include "tpCrlVerify.h" 
  28 #include "tpPolicies.h" 
  30 #include <Security/cssmapi.h> 
  31 #include <Security/x509defs.h> 
  32 #include <Security/oidscert.h> 
  33 #include <Security/oidscrl.h> 
  34 #include <security_cdsa_utilities/cssmerrors.h> 
  35 #include <string.h>                                             /* for memcmp */ 
  36 #include <Security/cssmapple.h> 
  39  * Replacement for CSSM_CL_CrlGetFirstCachedFieldValue for use with 
  40  * TPCrlItemInfo's generic getFirstCachedField mechanism. 
  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
, 
  49         return CSSM_CL_CrlGetFirstCachedFieldValue(CLHandle
, 
  51         NULL
,           // const CSSM_DATA *CrlRecordIndex, 
  54                 NumberOfMatchedFields
, 
  58 static const TPClItemCalls tpCrlClCalls 
= 
  60         tpGetFirstCachedFieldValue
, 
  61         CSSM_CL_CrlAbortQuery
, 
  63         CSSM_CL_CrlAbortCache
, 
  65         &CSSMOID_X509V1CRLThisUpdate
, 
  66         &CSSMOID_X509V1CRLNextUpdate
, 
  67         CSSMERR_TP_INVALID_CRL_POINTER
, 
  68         CSSMERR_APPLETP_CRL_EXPIRED
, 
  69         CSSMERR_APPLETP_CRL_NOT_VALID_YET
 
  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. 
  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 
  86         : TPClItemInfo(clHand
, cspHand
, tpCrlClCalls
, crlData
, 
  87                         copyCrlData
, verifyTime
), 
  89                 mFromWhere(CFW_Nowhere
), 
  91                 mCrlFieldToFree(NULL
), 
  92                 mVerifyState(CVS_Unknown
), 
  93                 mVerifyError(CSSMERR_TP_INTERNAL_ERROR
) 
 100         /* fetch parsed CRL */ 
 101         crtn 
= fetchField(&CSSMOID_X509V2CRLSignedCrlCStruct
, &mCrlFieldToFree
); 
 105                 CssmError::throwMe(crtn
); 
 107         if(mCrlFieldToFree
->Length 
!= sizeof(CSSM_X509_SIGNED_CRL
)) { 
 108                 tpErrorLog("fetchField(SignedCrlCStruct) length error\n"); 
 110                 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
); 
 112         mX509Crl 
= (CSSM_X509_SIGNED_CRL 
*)mCrlFieldToFree
->Data
; 
 113         /* any other other commonly used fields? */ 
 116 TPCrlInfo::~TPCrlInfo() 
 121 void TPCrlInfo::releaseResources() 
 123         if(mCrlFieldToFree
) { 
 124                 freeField(&CSSMOID_X509V2CRLSignedCrlCStruct
, mCrlFieldToFree
); 
 125                 mCrlFieldToFree 
= NULL
; 
 128                 Allocator::standard().free(mUri
.Data
); 
 132         TPClItemInfo::releaseResources(); 
 135 void TPCrlInfo::uri(const CSSM_DATA 
&uri
) 
 137         tpCopyCssmData(Allocator::standard(), &uri
, &mUri
); 
 141  * List of extensions we understand and can accept as critical. 
 143 static const CSSM_OID 
*const TPGoodCrlExtens
[] = 
 146         /* Note NOT CSSMOID_DeltaCrlIndicator! That's fatal */ 
 149         &CSSMOID_IssuingDistributionPoint
, 
 150         &CSSMOID_HoldInstructionCode
, 
 151         &CSSMOID_InvalidityDate
, 
 152         &CSSMOID_AuthorityKeyIdentifier
, 
 153         &CSSMOID_SubjectAltName
, 
 154         &CSSMOID_IssuerAltName
 
 157 #define NUM_KNOWN_EXTENS (sizeof(TPGoodCrlExtens) / sizeof(CSSM_OID_PTR)) 
 160  * Do our best to understand all the entries in a CSSM_X509_EXTENSIONS, 
 161  * which may be per-CRL or per-entry. 
 163  * For now, we just ensure that for every critical extension, 
 164  * we actually understand it and can deal it. 
 166 CSSM_RETURN 
TPCrlInfo::parseExtensions( 
 167         TPVerifyContext                         
&vfyCtx
, 
 169         uint32                                          entryIndex
,             // if isPerEntry 
 170         const CSSM_X509_EXTENSIONS      
&extens
, 
 171         TPCertInfo                                      
*forCert
,               // optional 
 172         bool                                            &isIndirectCrl
) // RETURNED 
 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? */ 
 180                         for(i
=0; i
<NUM_KNOWN_EXTENS
; i
++) { 
 181                                 if(tpCompareOids(&exten
->extnId
, TPGoodCrlExtens
[i
])) { 
 182                                         /* we're cool with this one */ 
 186                         if(i 
== NUM_KNOWN_EXTENS
) { 
 187                                 tpCrlDebug("parseExtensions: Unknown Critical Extension\n"); 
 188                                 return CSSMERR_APPLETP_UNKNOWN_CRL_EXTEN
; 
 192                 /* Specific extension handling. */ 
 193                 if(tpCompareOids(&exten
->extnId
, 
 194                                 &CSSMOID_IssuingDistributionPoint
)) { 
 196                          * If this assertion fails, we're out of sync with the CL 
 198                         assert(exten
->format 
== CSSM_X509_DATAFORMAT_PARSED
); 
 199                         CE_IssuingDistributionPoint 
*idp 
= 
 200                                 (CE_IssuingDistributionPoint 
*) 
 201                                         exten
->value
.parsedValue
; 
 204                          * Snag indirectCrl flag for caller in any case 
 206                         if(idp
->indirectCrlPresent 
&& idp
->indirectCrl
) { 
 207                                 isIndirectCrl 
= true; 
 209                         if(forCert 
!= NULL
) { 
 210                                 /* If no target cert, i.e., we're just verifying a CRL, 
 211                                  * skip the remaining IDP checks. */ 
 213                                 /* verify onlyCACerts/onlyUserCerts */ 
 215                                 if(forCert
->isLeaf() && 
 216                                         !(vfyCtx
.actionFlags 
& CSSM_TP_ACTION_LEAF_IS_CA
)) { 
 222                                 if((idp
->onlyUserCertsPresent
) && (idp
->onlyUserCerts
)) { 
 224                                                 tpCrlDebug("parseExtensions: onlyUserCerts, " 
 226                                                 return CSSMERR_APPLETP_IDP_FAIL
; 
 229                                 if((idp
->onlyCACertsPresent
) && (idp
->onlyCACerts
)) { 
 231                                                 tpCrlDebug("parseExtensions: onlyCACerts, leaf\n"); 
 232                                                 return CSSMERR_APPLETP_IDP_FAIL
; 
 236                 /* Verify DistributionPointName matches cRLDistributionPoints 
 239                 if(idp
->distPointName
) { 
 240                     CSSM_DATA_PTR certDistPoints
; 
 241                     CSSM_RETURN crtn 
= forCert
->fetchField(&CSSMOID_CrlDistributionPoints
, &certDistPoints
); 
 245                         case CSSMERR_CL_NO_FIELD_VALUES
: 
 250                     if (certDistPoints
->Length 
!= sizeof(CSSM_X509_EXTENSION
)) { 
 251                         forCert
->freeField(&CSSMOID_CrlDistributionPoints
, certDistPoints
); 
 252                         return CSSMERR_TP_UNKNOWN_FORMAT
; 
 254                     CSSM_X509_EXTENSION 
*cssmExt 
= (CSSM_X509_EXTENSION 
*)certDistPoints
->Data
; 
 255                     if (cssmExt 
== NULL
) { 
 256                         forCert
->freeField(&CSSMOID_CrlDistributionPoints
, certDistPoints
); 
 257                         return CSSMERR_TP_UNKNOWN_FORMAT
; 
 259                     CE_CRLDistPointsSyntax 
*dps 
= (CE_CRLDistPointsSyntax 
*)cssmExt
->value
.parsedValue
; 
 261                         forCert
->freeField(&CSSMOID_CrlDistributionPoints
, certDistPoints
); 
 262                         return CSSMERR_TP_UNKNOWN_FORMAT
; 
 264                     if (!dps
->numDistPoints
) { 
 265                         /* no distribution points in the cert extension */ 
 266                         forCert
->freeField(&CSSMOID_CrlDistributionPoints
, certDistPoints
); 
 270                     /* Loop over the cRLDistributionPoints in the cert. */ 
 271                     CSSM_BOOL sameType 
= CSSM_FALSE
; 
 272                     CSSM_BOOL found 
= CSSM_FALSE
; 
 273                     for (unsigned dex
=0; dex
<dps
->numDistPoints
; dex
++) { 
 274                         CE_CRLDistributionPoint 
*dp 
= &dps
->distPoints
[dex
]; 
 275                         if (dp
->distPointName 
== NULL
) { 
 278                         if (idp
->distPointName
->nameType 
!= dp
->distPointName
->nameType
) { 
 279                             /* Not the same name type; move on. */ 
 282                         sameType 
= CSSM_TRUE
; 
 283                         switch (dp
->distPointName
->nameType
) { 
 284                             case CE_CDNT_NameRelativeToCrlIssuer
: { 
 286                                     /* RDN code below is not tested, so we won't use it. 
 287                                      * Defaulting to prior behavior of accepting without testing. 
 290                                     tpErrorLog("parseExtensions: " 
 291                                                "CE_CDNT_NameRelativeToCrlIssuer not implemented\n"); 
 295                                 /* relativeName is a RDN sequence */ 
 296                                 CSSM_X509_RDN_PTR idpName 
= idp
->distPointName
->dpn
.rdn
; 
 297                                 CSSM_X509_RDN_PTR certName 
= dp
->distPointName
->dpn
.rdn
; 
 298                                 if (idpName 
== NULL 
|| certName 
== NULL 
|| idpName
->numberOfPairs 
!= certName
->numberOfPairs
) { 
 299                                     /* They don't have the same number of attribute/value pairs; move on. */ 
 303                                 for (nDex
=0; nDex
<idpName
->numberOfPairs
; nDex
++) { 
 304                                     CSSM_X509_TYPE_VALUE_PAIR_PTR iPair 
= idpName
->AttributeTypeAndValue
; 
 305                                     CSSM_X509_TYPE_VALUE_PAIR_PTR cPair 
= certName
->AttributeTypeAndValue
; 
 306                                     if (!tpCompareCssmData(&iPair
->type
, &cPair
->type
) || 
 307                                         !tpCompareCssmData(&iPair
->value
, &cPair
->value
)) { 
 311                                 if (nDex
==idpName
->numberOfPairs
) { 
 312                                     /* All the pairs matched. */ 
 317                             case CE_CDNT_FullName
: { 
 318                                 /* fullName is a GeneralNames sequence */ 
 319                                 CE_GeneralNames 
*idpNames 
= idp
->distPointName
->dpn
.fullName
; 
 320                                 CE_GeneralNames 
*certNames 
= dp
->distPointName
->dpn
.fullName
; 
 321                                 if (idpNames 
== NULL 
|| certNames 
== NULL 
|| idpNames
->numNames 
!= certNames
->numNames
) { 
 322                                     /* They don't have the same number of names; move on. */ 
 326                                 for (nDex
=0; nDex
<idpNames
->numNames
; nDex
++) { 
 327                                     CE_GeneralName 
*idpName 
= &idpNames
->generalName
[nDex
]; 
 328                                     CE_GeneralName 
*certName 
= &certNames
->generalName
[nDex
]; 
 329                                     if ((idpName
->nameType 
!= certName
->nameType
) || 
 330                                         (!tpCompareCssmData(&idpName
->name
, &certName
->name
))) { 
 334                                 if (nDex
==idpNames
->numNames
) { 
 335                                     /* All the names matched. */ 
 341                                 forCert
->freeField(&CSSMOID_CrlDistributionPoints
, certDistPoints
); 
 342                                 return CSSMERR_TP_UNKNOWN_FORMAT
; 
 346                             break; /* out of loop over crlDistribtionPoints in cert. */ 
 349                     forCert
->freeField(&CSSMOID_CrlDistributionPoints
, certDistPoints
); 
 350                     if(sameType 
&& !found
) { 
 351                         return CSSMERR_APPLETP_IDP_FAIL
; 
 353                 } /* distPointName check */ 
 355                 }               /* have target cert */ 
 362  * The heavyweight "perform full verification of this CRL" op. 
 363  * Must verify to an anchor cert in tpVerifyContext or via 
 364  * Trust Settings if so enabled. 
 365  * Intermediate certs can come from signerCerts or dBList. 
 367 CSSM_RETURN 
TPCrlInfo::verifyWithContext( 
 368         TPVerifyContext                 
&tpVerifyContext
, 
 369         TPCertInfo                              
*forCert
,               // optional 
 373          * Step 1: this CRL must be current. Caller might have re-evaluated 
 374          * expired/notValidYet since our construction via calculateCurrent(). 
 377                 return CSSMERR_APPLETP_CRL_EXPIRED
; 
 379         if(isNotValidYet()) { 
 380                 return CSSMERR_APPLETP_CRL_NOT_VALID_YET
; 
 383         /* subsequent verify state is cached */ 
 384         switch(mVerifyState
) { 
 392                         tpErrorLog("verifyWithContext: bad verifyState\n"); 
 393                         return CSSMERR_TP_INTERNAL_ERROR
; 
 397          * Step 2: parse & understand all critical CRL extensions. 
 401         crtn 
= parseExtensions(tpVerifyContext
, 
 404                 mX509Crl
->tbsCertList
.extensions
, 
 408                 mVerifyState 
= CVS_Bad
; 
 409                 if(!forCert 
|| forCert
->addStatusCode(crtn
)) { 
 414         CSSM_X509_REVOKED_CERT_LIST_PTR revoked 
= 
 415                         mX509Crl
->tbsCertList
.revokedCertificates
; 
 416         if(revoked 
!= NULL
) { 
 417                 for(uint32 dex
=0; dex
<revoked
->numberOfRevokedCertEntries
; dex
++) { 
 418                         bool dummyIsIndirect
;   // can't be set here 
 419                         crtn 
= parseExtensions(tpVerifyContext
, 
 422                                 revoked
->revokedCertEntry
[dex
].extensions
, 
 426                                 if(!forCert 
|| forCert
->addStatusCode(crtn
)) { 
 427                                         mVerifyState 
= CVS_Bad
; 
 435          * Step 3: obtain a fully verified cert chain which verifies this CRL. 
 437         CSSM_BOOL       verifiedToRoot
; 
 438         CSSM_BOOL       verifiedToAnchor
; 
 439         CSSM_BOOL       verifiedViaTrustSetting
; 
 441         TPCertGroup 
outCertGroup(tpVerifyContext
.alloc
, 
 442                 TGO_Caller
);                    // CRLs owned by inCertGroup 
 444         /* set up for disposal of TPCertInfos created by 
 445          * CertGroupConstructPriv */ 
 446         TPCertGroup     
certsToBeFreed(tpVerifyContext
.alloc
, TGO_Group
); 
 448         if(tpVerifyContext
.signerCerts
) { 
 449                 /* start from scratch with this group */ 
 450                 tpVerifyContext
.signerCerts
->setAllUnused(); 
 452         crtn 
= outCertGroup
.buildCertGroup( 
 453                         *this,                                                  // subject item 
 454                         tpVerifyContext
.signerCerts
,    // inCertGroup, optional 
 455                         tpVerifyContext
.dbList
,                 // optional 
 456                         tpVerifyContext
.clHand
, 
 457                         tpVerifyContext
.cspHand
, 
 458                         tpVerifyContext
.verifyTime
, 
 459                         tpVerifyContext
.numAnchorCerts
, 
 460                         tpVerifyContext
.anchorCerts
, 
 462                         &tpVerifyContext
.gatheredCerts
, 
 463                         CSSM_FALSE
,                                             // subjectIsInGroup 
 464                         tpVerifyContext
.actionFlags
, 
 465                         tpVerifyContext
.policyOid
, 
 466                         tpVerifyContext
.policyStr
, 
 467                         tpVerifyContext
.policyStrLen
, 
 468                         kSecTrustSettingsKeyUseSignRevocation
, 
 471                         verifiedViaTrustSetting
); 
 472         /* subsequent errors to errOut: */ 
 475                 tpCrlDebug("TPCrlInfo::verifyWithContext buildCertGroup failure " 
 476                         "index %u",     index()); 
 477                 if(!forCert 
|| forCert
->addStatusCode(crtn
)) { 
 481         if (verifiedToRoot 
&& (tpVerifyContext
.actionFlags 
& CSSM_TP_ACTION_IMPLICIT_ANCHORS
)) 
 482                 verifiedToAnchor 
= CSSM_TRUE
; 
 483         if(!verifiedToAnchor 
&& !verifiedViaTrustSetting
) { 
 486                         /* verified to root which is not an anchor */ 
 487                         tpCrlDebug("TPCrlInfo::verifyWithContext root, no anchor, " 
 488                                 "index %u",     index()); 
 489                         crtn 
= CSSMERR_APPLETP_CRL_INVALID_ANCHOR_CERT
; 
 492                         /* partial chain, no root, not verifiable by anchor */ 
 493                         tpCrlDebug("TPCrlInfo::verifyWithContext no root, no anchor, " 
 494                                 "index %u",     index()); 
 495                         crtn 
= CSSMERR_APPLETP_CRL_NOT_TRUSTED
; 
 497                 if(!forCert 
|| forCert
->addStatusCode(crtn
)) { 
 498                         mVerifyState 
= CVS_Bad
; 
 504          * Step 4: policy verification on the returned cert group 
 505          * We need to (temporarily) assert the "leaf cert is a CA" flag 
 508         outCertGroup
.certAtIndex(0)->isLeaf(true); 
 509         crtn 
= tp_policyVerify(kCrlPolicy
, 
 510                 tpVerifyContext
.alloc
, 
 511                 tpVerifyContext
.clHand
, 
 512                 tpVerifyContext
.cspHand
, 
 515                 verifiedViaTrustSetting
, 
 516                 tpVerifyContext
.actionFlags 
| CSSM_TP_ACTION_LEAF_IS_CA
, 
 518                 NULL
);                                                  // policyOpts, not currently used 
 520                 tpCrlDebug("   ...verifyWithContext policy FAILURE CRL %u", 
 522                 if(!forCert 
|| forCert
->addStatusCode(CSSMERR_APPLETP_CRL_POLICY_FAIL
)) { 
 523                         mVerifyState 
= CVS_Bad
; 
 529          * Step 5: recursively perform CRL verification on the certs 
 530          * gathered to verify this CRL. 
 531          * Only performed if this CRL is an indirect CRL or the caller 
 532          * explicitly told us to do this (i.e., caller is verifying a 
 533          * CRL, not a cert chain). 
 535         if(isIndirectCrl 
|| doCrlVerify
) { 
 536                 tpCrlDebug("verifyWithContext recursing to " 
 537                         "tpVerifyCertGroupWithCrls"); 
 538                 crtn 
= tpVerifyCertGroupWithCrls(tpVerifyContext
, 
 541                         tpCrlDebug("   ...verifyWithContext CRL reverify FAILURE CRL %u", 
 543                         if(!forCert 
|| forCert
->addStatusCode(crtn
)) { 
 544                                 mVerifyState 
= CVS_Bad
; 
 550         tpCrlDebug("   ...verifyWithContext CRL %u SUCCESS", index()); 
 551         mVerifyState 
= CVS_Good
; 
 553         /* we own these, we free the DB records */ 
 554         certsToBeFreed
.freeDbRecords(); 
 559  * Wrapper for verifyWithContext for use when evaluating a CRL 
 560  * "now" instead of at the time in TPVerifyContext.verifyTime. 
 561  * In this case, on entry, TPVerifyContext.verifyTime is the 
 562  * time at which a cert is being evaluated. 
 564 CSSM_RETURN 
TPCrlInfo::verifyWithContextNow( 
 565         TPVerifyContext         
&tpVerifyContext
, 
 566         TPCertInfo                      
*forCert
,                       // optional 
 569         CSSM_TIMESTRING ctxTime 
= tpVerifyContext
.verifyTime
; 
 570         CSSM_RETURN crtn 
= verifyWithContext(tpVerifyContext
, forCert
, doCrlVerify
); 
 571         tpVerifyContext
.verifyTime 
= ctxTime
; 
 576  * Do I have the same issuer as the specified subject cert? Returns 
 579 bool TPCrlInfo::hasSameIssuer( 
 580         const TPCertInfo        
&subject
) 
 582         assert(subject
.issuerName() != NULL
); 
 583         if(tpCompareCssmData(issuerName(), subject
.issuerName())) { 
 592  * Determine if specified cert has been revoked as of the 
 593  * provided time; a NULL timestring indicates "now". 
 595  * Assumes current CRL is verified good and that issuer names of 
 596  * the cert and CRL match. 
 598  * This duplicates similar logic in the CL, but to avoid re-parsing 
 599  * the subject cert (which we have parsed and cached), we just do it 
 602  * Possible errors are 
 603  *      CSSMERR_TP_CERT_REVOKED 
 604  *      CSSMERR_TP_CERT_SUSPENDED 
 607  * Error status is added to subjectCert. 
 609 CSSM_RETURN 
TPCrlInfo::isCertRevoked( 
 610         TPCertInfo 
&subjectCert
, 
 611         CSSM_TIMESTRING verifyTime
) 
 613         assert(mVerifyState 
== CVS_Good
); 
 614         CSSM_X509_TBS_CERTLIST_PTR tbs 
= &mX509Crl
->tbsCertList
; 
 616         /* trivial case - empty CRL */ 
 617         if((tbs
->revokedCertificates 
== NULL
) || 
 618            (tbs
->revokedCertificates
->numberOfRevokedCertEntries 
== 0)) { 
 619            tpCrlDebug("   isCertRevoked: empty CRL at index %u", index()); 
 623         /* is subject cert's serial number in this CRL? */ 
 624         CSSM_DATA_PTR subjSerial 
= NULL
; 
 626         crtn 
= subjectCert
.fetchField(&CSSMOID_X509V1SerialNumber
, &subjSerial
); 
 628                 /* should never happen */ 
 629                 tpErrorLog("TPCrlInfo:isCertRevoked: error fetching serial number\n"); 
 630                 if(subjectCert
.addStatusCode(crtn
)) { 
 634                         /* allowed error - can't proceed; punt with success */ 
 638         /* subsequent errors to errOut: */ 
 640         uint32 numEntries 
= tbs
->revokedCertificates
->numberOfRevokedCertEntries
; 
 641         CSSM_X509_REVOKED_CERT_ENTRY_PTR entries 
= 
 642                 tbs
->revokedCertificates
->revokedCertEntry
; 
 644         CFDateRef cfRevokedTime 
= NULL
; 
 645         CFDateRef cfVerifyTime 
= NULL
; 
 647         for(uint32 dex
=0; dex
<numEntries
; dex
++) { 
 648                 CSSM_X509_REVOKED_CERT_ENTRY_PTR entry 
= &entries
[dex
]; 
 649                 if(tpCompareCssmData(subjSerial
, &entry
->certificateSerialNumber
)) { 
 651                          * It's in there. Compare revocation time in the CRL to 
 652                          * our caller-specified verifyTime. 
 654                         CSSM_X509_TIME_PTR xTime 
= &entry
->revocationDate
; 
 656                         rtn 
= timeStringToCfDate((char *)xTime
->time
.Data
, (unsigned)xTime
->time
.Length
, 
 659                                 tpErrorLog("fetchNotBeforeAfter: malformed revocationDate\n"); 
 662                                 if(verifyTime 
!= NULL
) { 
 663                                         rtn 
= timeStringToCfDate((char *)verifyTime
, (unsigned)strlen(verifyTime
), 
 667                                         /* verify right now */ 
 668                                         cfVerifyTime 
= CFDateCreate(NULL
, CFAbsoluteTimeGetCurrent()); 
 670                                 if((rtn 
== 0) && cfVerifyTime 
!= NULL
) { 
 671                                         CFComparisonResult res 
= CFDateCompare(cfVerifyTime
, cfRevokedTime
, NULL
); 
 672                                         if(res 
== kCFCompareLessThan
) { 
 673                                                 /* cfVerifyTime < cfRevokedTime; I guess this one's OK */ 
 674                                                 tpCrlDebug("   isCertRevoked: cert %u NOT YET REVOKED by CRL %u", 
 675                                                                    subjectCert
.index(), index()); 
 682                          * REQUIRED TBD: parse the entry's extensions, specifically to 
 683                          * get a reason. This will entail a bunch of new TP/cert specific 
 685                          * For now, just flag it revoked. 
 687                         crtn 
= CSSMERR_TP_CERT_REVOKED
; 
 688                         subjectCert
.crlReason(1); 
 689                         tpCrlDebug("   isCertRevoked: cert %u REVOKED by CRL %u", 
 690                                 subjectCert
.index(), index()); 
 695         subjectCert
.freeField(&CSSMOID_X509V1SerialNumber
, subjSerial
); 
 696         if(crtn 
&& !subjectCert
.addStatusCode(crtn
)) { 
 700                 CFRelease(cfRevokedTime
); 
 703                 CFRelease(cfVerifyTime
); 
 712 /* build empty group */ 
 713 TPCrlGroup::TPCrlGroup( 
 715         TPGroupOwner            whoOwns
) : 
 722         /* nothing for now */ 
 726  * Construct from unordered, untrusted CSSM_CRLGROUP. Resulting 
 727  * TPCrlInfos are more or less in the same order as the incoming 
 728  * CRLs, though incoming CRLs are discarded if they don't parse. 
 729  * No verification of any sort is performed. 
 731 TPCrlGroup::TPCrlGroup( 
 732         const CSSM_CRLGROUP     
*cssmCrlGroup
,                  // optional 
 733         CSSM_CL_HANDLE                  clHand
, 
 734         CSSM_CSP_HANDLE                 cspHand
, 
 736         const char                              *verifyTime
,                    // may be NULL 
 737         TPGroupOwner                    whoOwns
) : 
 744         /* verify input args */ 
 745         if((cssmCrlGroup 
== NULL
) || (cssmCrlGroup
->NumberOfCrls 
== 0)) { 
 748         if(cspHand 
== CSSM_INVALID_HANDLE
) { 
 749                 CssmError::throwMe(CSSMERR_TP_INVALID_CSP_HANDLE
); 
 751         if(clHand 
== CSSM_INVALID_HANDLE
)       { 
 752                 CssmError::throwMe(CSSMERR_TP_INVALID_CL_HANDLE
); 
 754         if(cssmCrlGroup
->CrlGroupType 
!= CSSM_CRLGROUP_DATA
) { 
 755                 CssmError::throwMe(CSSMERR_TP_INVALID_CERTGROUP
); 
 757         switch(cssmCrlGroup
->CrlType
) { 
 758                 case CSSM_CRL_TYPE_X_509v1
: 
 759                 case CSSM_CRL_TYPE_X_509v2
: 
 762                         CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT
); 
 764         switch(cssmCrlGroup
->CrlEncoding
) { 
 765                 case CSSM_CRL_ENCODING_BER
: 
 766                 case CSSM_CRL_ENCODING_DER
: 
 769                         CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT
); 
 773          * Add remaining input certs to mCrlInfo. 
 775         TPCrlInfo 
*crlInfo 
= NULL
; 
 776         for(unsigned crlDex
=0; crlDex
<cssmCrlGroup
->NumberOfCrls
; crlDex
++) { 
 778                         crlInfo 
= new TPCrlInfo(clHand
, 
 780                                 &cssmCrlGroup
->GroupCrlList
.CrlList
[crlDex
], 
 781                                 TIC_NoCopy
,                     // don't copy data 
 785                         /* just ignore this CRL */ 
 788                 crlInfo
->index(crlDex
); 
 794  * Deletes all TPCrlInfo's if appropriate. 
 796 TPCrlGroup::~TPCrlGroup() 
 798         if(mWhoOwns 
== TGO_Group
) { 
 800                 for(i
=0; i
<mNumCrls
; i
++) { 
 804         mAlloc
.free(mCrlInfo
); 
 807 /* add/remove/access TPTCrlInfo's. */ 
 809  * NOTE: I am aware that most folks would just use an array<> here, but 
 810  * gdb is so lame that it doesn't even let one examine the contents 
 811  * of an array<> (or just about anything else in the STL). I prefer 
 812  * debuggability over saving a few lines of trivial code. 
 814 void TPCrlGroup::appendCrl( 
 817         if(mNumCrls 
== mSizeofCrlInfo
) { 
 818                 if(mSizeofCrlInfo 
== 0) { 
 819                         /* appending to empty array */ 
 825                 mCrlInfo 
= (TPCrlInfo 
**)mAlloc
.realloc(mCrlInfo
, 
 826                         mSizeofCrlInfo 
* sizeof(TPCrlInfo 
*)); 
 828         mCrlInfo
[mNumCrls
++] = &crlInfo
; 
 831 TPCrlInfo 
*TPCrlGroup::crlAtIndex( 
 834         if(index 
> (mNumCrls 
- 1)) { 
 835                 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
); 
 837         return mCrlInfo
[index
]; 
 840 TPCrlInfo 
&TPCrlGroup::removeCrlAtIndex( 
 841         unsigned                        index
)                          // doesn't delete the cert, just 
 842                                                                                         // removes it from our list 
 844         if(index 
> (mNumCrls 
- 1)) { 
 845                 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
); 
 847         TPCrlInfo 
&rtn 
= *mCrlInfo
[index
]; 
 849         /* removed requested element and compact remaining array */ 
 851         for(i
=index
; i
<(mNumCrls 
- 1); i
++) { 
 852                 mCrlInfo
[i
] = mCrlInfo
[i
+1]; 
 858 void TPCrlGroup::removeCrl( 
 861         for(unsigned dex
=0; dex
<mNumCrls
; dex
++) { 
 862                 if(mCrlInfo
[dex
] == &crlInfo
) { 
 863                         removeCrlAtIndex(dex
); 
 867         tpErrorLog("TPCrlGroup::removeCrl: CRL NOT FOUND\n"); 
 871 TPCrlInfo 
*TPCrlGroup::firstCrl() 
 874                 /* the caller really should not do this... */ 
 875                 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
); 
 882 TPCrlInfo 
*TPCrlGroup::lastCrl() 
 885                 /* the caller really should not do this... */ 
 886                 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR
); 
 889                 return mCrlInfo
[mNumCrls 
- 1]; 
 894          * Find a CRL whose issuer matches specified subject cert. 
 895          * Returned CRL has not necessarily been verified. 
 897 TPCrlInfo 
*TPCrlGroup::findCrlForCert( 
 900         for(unsigned dex
=0; dex
<mNumCrls
; dex
++) { 
 901                 TPCrlInfo 
*crl 
= mCrlInfo
[dex
]; 
 902                 if(crl
->hasSameIssuer(subject
)) {