/* * Returns true if we are to allow/trust the specified * cert as a PKINIT-only anchor. */ static bool tpCheckPkinitServerCert( TPCertGroup &certGroup) { /* * Basic requirement: exactly one cert, self-signed. * The numCerts == 1 requirement might change... */ unsigned numCerts = certGroup.numCerts(); if(numCerts != 1) { tpDebug("tpCheckPkinitServerCert: too many certs"); return false; } /* end of chain... */ TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1); if(!theCert->isSelfSigned()) { tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed"); return false; } const CSSM_DATA *subjectName = theCert->subjectName(); /* * Open the magic keychain. * We're going up and over the Sec layer here, not generally * kosher, but this is a temp hack. */ OSStatus ortn; SecKeychainRef kcRef = NULL; string fullPathName; const char *homeDir = getenv("HOME"); if (homeDir == NULL) { // If $HOME is unset get the current user's home directory // from the passwd file. uid_t uid = geteuid(); if (!uid) uid = getuid(); struct passwd *pw = getpwuid(uid); if (!pw) { return false; } homeDir = pw->pw_dir; } fullPathName = homeDir; fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain"; ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef); if(ortn) { tpDebug("tpCheckPkinitServerCert: keychain not found (1)"); return false; } /* subsequent errors to errOut: */ bool ourRtn = false; SecKeychainStatus kcStatus; CSSM_DATA_PTR subjSerial = NULL; CSSM_RETURN crtn; SecKeychainSearchRef srchRef = NULL; SecKeychainAttributeList attrList; SecKeychainAttribute attrs[2]; SecKeychainItemRef foundItem = NULL; ortn = SecKeychainGetStatus(kcRef, &kcStatus); if(ortn) { tpDebug("tpCheckPkinitServerCert: keychain not found (2)"); goto errOut; } /* * We already have this cert's normalized name; get its * serial number. */ crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial); if(crtn) { /* should never happen */ tpDebug("tpCheckPkinitServerCert: error fetching serial number"); goto errOut; } attrs[0].tag = kSecSubjectItemAttr; attrs[0].length = subjectName->Length; attrs[0].data = subjectName->Data; attrs[1].tag = kSecSerialNumberItemAttr; attrs[1].length = subjSerial->Length; attrs[1].data = subjSerial->Data; attrList.count = 2; attrList.attr = attrs; ortn = SecKeychainSearchCreateFromAttributes(kcRef, kSecCertificateItemClass, &attrList, &srchRef); if(ortn) { tpDebug("tpCheckPkinitServerCert: search failure"); goto errOut; } for(;;) { ortn = SecKeychainSearchCopyNext(srchRef, &foundItem); if(ortn) { tpDebug("tpCheckPkinitServerCert: end search"); break; } /* found a matching cert; do byte-for-byte compare */ CSSM_DATA certData; ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData); if(ortn) { tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure"); continue; } if(tpCompareCssmData(&certData, theCert->itemData())){ tpDebug("tpCheckPkinitServerCert: FOUND CERT"); ourRtn = true; break; } tpDebug("tpCheckPkinitServerCert: skipping matching cert"); CFRelease(foundItem); foundItem = NULL; } errOut: CFRELEASE(kcRef); CFRELEASE(srchRef); CFRELEASE(foundItem); if(subjSerial != NULL) { theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial); } return ourRtn; }
void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand, CSSM_CSP_HANDLE cspHand, const CSSM_CERTGROUP &CertGroupToBeVerified, const CSSM_TP_VERIFY_CONTEXT *VerifyContext, CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult) { CSSM_BOOL verifiedToRoot = CSSM_FALSE; CSSM_BOOL verifiedToAnchor = CSSM_FALSE; CSSM_BOOL verifiedViaTrustSetting = CSSM_FALSE; CSSM_RETURN constructReturn = CSSM_OK; CSSM_RETURN policyReturn = CSSM_OK; const CSSM_TP_CALLERAUTH_CONTEXT *cred; /* declare volatile as compiler workaround to avoid caching in CR4 */ const CSSM_APPLE_TP_ACTION_DATA * volatile actionData = NULL; CSSM_TIMESTRING cssmTimeStr; CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0; CSSM_TP_STOP_ON tpStopOn = 0; /* keep track of whether we did policy checking; if not, we do defaults */ bool didCertPolicy = false; bool didRevokePolicy = false; /* user trust parameters */ CSSM_OID utNullPolicy = {0, NULL}; const CSSM_OID *utPolicyOid = NULL; const char *utPolicyStr = NULL; uint32 utPolicyStrLen = 0; SecTrustSettingsKeyUsage utKeyUse = 0; bool utTrustSettingEnabled = false; if(VerifyContextResult) { memset(VerifyContextResult, 0, sizeof(*VerifyContextResult)); } /* verify input args, skipping the ones checked by CertGroupConstruct */ if((VerifyContext == NULL) || (VerifyContext->Cred == NULL)) { /* the spec says that this is optional but we require it */ CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); } cred = VerifyContext->Cred; /* Optional ActionData affecting all policies */ actionData = (CSSM_APPLE_TP_ACTION_DATA * volatile)VerifyContext->ActionData.Data; if(actionData != NULL) { switch(actionData->Version) { case CSSM_APPLE_TP_ACTION_VERSION: if(VerifyContext->ActionData.Length != sizeof(CSSM_APPLE_TP_ACTION_DATA)) { CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA); } break; /* handle backwards versions here if we ever go beyond version 0 */ default: CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA); } actionFlags = actionData->ActionFlags; if(actionFlags & CSSM_TP_ACTION_TRUST_SETTINGS) { utTrustSettingEnabled = true; } } /* optional, may be NULL */ cssmTimeStr = cred->VerifyTime; tpStopOn = cred->VerificationAbortOn; switch(tpStopOn) { /* the only two we support */ case CSSM_TP_STOP_ON_NONE: case CSSM_TP_STOP_ON_FIRST_FAIL: break; /* default maps to stop on first fail */ case CSSM_TP_STOP_ON_POLICY: tpStopOn = CSSM_TP_STOP_ON_FIRST_FAIL; break; default: CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY); } /* now the args we can't deal with */ if(cred->CallerCredentials != NULL) { CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER); } /* ...any others? */ /* set up for optional user trust evaluation */ if(utTrustSettingEnabled) { const CSSM_TP_POLICYINFO *pinfo = &cred->Policy; TPPolicy utPolicy = kTPx509Basic; /* default policy OID in case caller hasn't specified one */ utPolicyOid = &utNullPolicy; if(pinfo->NumberOfPolicyIds == 0) { tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies (1)"); /* keep going, I guess - no policy-specific info - use kTPx509Basic */ } else { CSSM_FIELD_PTR utPolicyField = &pinfo->PolicyIds[0]; utPolicyOid = &utPolicyField->FieldOid; bool foundPolicy = checkPolicyOid(*utPolicyOid, utPolicy); if(!foundPolicy) { tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies"); /* keep going, I guess - no policy-specific info - use kTPx509Basic */ } else { /* get policy-specific info */ tp_policyTrustSettingParams(utPolicy, &utPolicyField->FieldValue, &utPolicyStr, &utPolicyStrLen, &utKeyUse); } } } /* get verified (possibly partial) outCertGroup - error is fatal */ /* BUT: we still return partial evidence if asked to...from now on. */ TPCertGroup outCertGroup(*this, TGO_Caller); // certs are owned by inCertGroup TPCertGroup inCertGroup(CertGroupToBeVerified, clHand, cspHand, *this, cssmTimeStr, // optional 'this' time true, // firstCertMustBeValid TGO_Group); /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */ TPCertGroup gatheredCerts(*this, TGO_Group); try { CertGroupConstructPriv( clHand, cspHand, inCertGroup, cred->DBList, cssmTimeStr, cred->NumberOfAnchorCerts, cred->AnchorCerts, actionFlags, utPolicyOid, utPolicyStr, utPolicyStrLen, utKeyUse, gatheredCerts, verifiedToRoot, verifiedToAnchor, verifiedViaTrustSetting, outCertGroup); } catch(const CssmError &cerr) { constructReturn = cerr.error; /* abort if no certs found */ if(outCertGroup.numCerts() == 0) { CssmError::throwMe(constructReturn); } /* else press on, collecting as much info as we can */ } /* others are way fatal */ assert(outCertGroup.numCerts() >= 1); /* Infer interim status from return values */ switch(constructReturn) { /* these values do not get overridden */ case CSSMERR_TP_CERTIFICATE_CANT_OPERATE: case CSSMERR_TP_INVALID_CERT_AUTHORITY: case CSSMERR_APPLETP_TRUST_SETTING_DENY: case errSecInvalidTrustSettings: break; default: /* infer status from these values... */ if(verifiedToAnchor || verifiedViaTrustSetting) { /* full success; anchor doesn't have to be root */ constructReturn = CSSM_OK; } else if(verifiedToRoot) { if(actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS) { constructReturn = CSSM_OK; } else { /* verified to root which is not an anchor */ constructReturn = CSSMERR_TP_INVALID_ANCHOR_CERT; } } else { /* partial chain, no root, not verifiable by anchor */ constructReturn = CSSMERR_TP_NOT_TRUSTED; } /* * Those errors can be allowed, cert-chain-wide, per individual * certs' allowedErrors */ if((constructReturn != CSSM_OK) && outCertGroup.isAllowedError(constructReturn)) { constructReturn = CSSM_OK; } break; } /* * Parameters passed to tp_policyVerify() and which vary per policy * in the loop below */ TPPolicy tpPolicy; const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts; CSSM_RETURN thisPolicyRtn = CSSM_OK; // returned from tp_policyVerify() /* common CRL verify parameters */ TPCrlGroup *crlGroup = NULL; try { crlGroup = new TPCrlGroup(&VerifyContext->Crls, clHand, cspHand, *this, // alloc NULL, // cssmTimeStr - we want CRLs that are valid 'now' TGO_Group); } catch(const CssmError &cerr) { CSSM_RETURN cr = cerr.error; /* I don't see a straightforward way to report this error, * other than adding it to the leaf cert's status... */ outCertGroup.certAtIndex(0)->addStatusCode(cr); tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n"); } /* others are way fatal */ TPVerifyContext revokeVfyContext(*this, clHand, cspHand, cssmTimeStr, cred->NumberOfAnchorCerts, cred->AnchorCerts, &inCertGroup, crlGroup, /* * This may consist of certs gathered from the net (which is the purpose * of this argument) and from DLDBs (a side-effect optimization). */ gatheredCerts, cred->DBList, kRevokeNone, // policy actionFlags, NULL, // CRL options NULL, // OCSP options utPolicyOid, utPolicyStr, utPolicyStrLen, utKeyUse); /* true if we're to execute tp_policyVerify at end of loop */ bool doPolicyVerify; /* true if we're to execute a revocation policy at end of loop */ bool doRevocationPolicy; /* grind thru each policy */ for(uint32 polDex=0; polDex<cred->Policy.NumberOfPolicyIds; polDex++) { if(cred->Policy.PolicyIds == NULL) { policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; break; } CSSM_FIELD_PTR policyId = &cred->Policy.PolicyIds[polDex]; const CSSM_DATA *fieldVal = &policyId->FieldValue; const CSSM_OID *oid = &policyId->FieldOid; thisPolicyRtn = CSSM_OK; doPolicyVerify = false; doRevocationPolicy = false; sslOpts = NULL; /* first the basic cert policies */ doPolicyVerify = checkPolicyOid(*oid, tpPolicy); if(doPolicyVerify) { /* some basic checks... */ bool policyAbort = false; switch(tpPolicy) { case kTPx509Basic: case kTPiSign: case kTP_PKINIT_Client: case kTP_PKINIT_Server: if(fieldVal->Data != NULL) { policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; policyAbort = true; break; } break; default: break; } if(policyAbort) { break; } #if TP_PKINIT_SERVER_HACK if(tpPolicy == kTP_PKINIT_Server) { /* possible override of "root not in anchors" */ if(constructReturn == CSSMERR_TP_INVALID_ANCHOR_CERT) { if(tpCheckPkinitServerCert(outCertGroup)) { constructReturn = CSSM_OK; } } } #endif /* TP_PKINIT_SERVER_HACK */ } /* * Now revocation policies. Note some fields in revokeVfyContext can * accumulate across multiple policy calls, e.g., signerCerts. */ else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_CRL)) { /* CRL-specific options */ const CSSM_APPLE_TP_CRL_OPTIONS *crlOpts; crlOpts = (CSSM_APPLE_TP_CRL_OPTIONS *)fieldVal->Data; thisPolicyRtn = CSSM_OK; if(crlOpts != NULL) { switch(crlOpts->Version) { case CSSM_APPLE_TP_CRL_OPTS_VERSION: if(fieldVal->Length != sizeof(CSSM_APPLE_TP_CRL_OPTIONS)) { thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; break; } break; /* handle backwards compatibility here if necessary */ default: thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; break; } if(thisPolicyRtn != CSSM_OK) { policyReturn = thisPolicyRtn; break; } } revokeVfyContext.policy = kRevokeCrlBasic; revokeVfyContext.crlOpts = crlOpts; doRevocationPolicy = true; } else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_OCSP)) { /* OCSP-specific options */ const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts; ocspOpts = (CSSM_APPLE_TP_OCSP_OPTIONS *)fieldVal->Data; thisPolicyRtn = CSSM_OK; if(ocspOpts != NULL) { switch(ocspOpts->Version) { case CSSM_APPLE_TP_OCSP_OPTS_VERSION: if(fieldVal->Length != sizeof(CSSM_APPLE_TP_OCSP_OPTIONS)) { thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; break; } break; /* handle backwards compatibility here if necessary */ default: thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; break; } if(thisPolicyRtn != CSSM_OK) { policyReturn = thisPolicyRtn; break; } } revokeVfyContext.policy = kRevokeOcsp; revokeVfyContext.ocspOpts = ocspOpts; doRevocationPolicy = true; } /* etc. - add more policies here */ else { /* unknown TP policy OID */ policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; break; } /* common cert policy call */ if(doPolicyVerify) { assert(!doRevocationPolicy); // one at a time thisPolicyRtn = tp_policyVerify(tpPolicy, *this, clHand, cspHand, &outCertGroup, verifiedToRoot, verifiedViaTrustSetting, actionFlags, fieldVal, cred->Policy.PolicyControl); // not currently used didCertPolicy = true; } /* common revocation policy call */ if(doRevocationPolicy) { assert(!doPolicyVerify); // one at a time thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, outCertGroup); didRevokePolicy = true; } /* See if possible error is allowed, cert-chain-wide. */ if((thisPolicyRtn != CSSM_OK) && outCertGroup.isAllowedError(thisPolicyRtn)) { thisPolicyRtn = CSSM_OK; } if(thisPolicyRtn) { /* Now remember the error if it's the first policy * error we've seen. */ if(policyReturn == CSSM_OK) { policyReturn = thisPolicyRtn; } /* Keep going? */ if(tpStopOn == CSSM_TP_STOP_ON_FIRST_FAIL) { /* Nope; we're done with policy evaluation */ break; } } } /* for each policy */ /* * Upon completion of the above loop, perform default policy ops if * appropriate. */ if((policyReturn == CSSM_OK) || (tpStopOn == CSSM_TP_STOP_ON_NONE)) { if(!didCertPolicy) { policyReturn = tp_policyVerify(kTPDefault, *this, clHand, cspHand, &outCertGroup, verifiedToRoot, verifiedViaTrustSetting, actionFlags, NULL, // policyFieldData cred->Policy.PolicyControl); // not currently used /* See if error is allowed, cert-chain-wide. */ if((policyReturn != CSSM_OK) && outCertGroup.isAllowedError(policyReturn)) { policyReturn = CSSM_OK; } } if( !didRevokePolicy && // no revoke policy yet ( (policyReturn == CSSM_OK || // default cert policy OK (tpStopOn == CSSM_TP_STOP_ON_NONE)) // keep going anyway ) ) { revokeVfyContext.policy = TP_CRL_POLICY_DEFAULT; CSSM_RETURN thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, outCertGroup); if((thisPolicyRtn != CSSM_OK) && outCertGroup.isAllowedError(thisPolicyRtn)) { thisPolicyRtn = CSSM_OK; } if((thisPolicyRtn != CSSM_OK) && (policyReturn == CSSM_OK)) { policyReturn = thisPolicyRtn; } } } /* default policy opts */ delete crlGroup; /* return evidence - i.e., constructed chain - if asked to */ if(VerifyContextResult != NULL) { /* * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO */ VerifyContextResult->NumberOfEvidences = 3; VerifyContextResult->Evidence = (CSSM_EVIDENCE_PTR)calloc(3, sizeof(CSSM_EVIDENCE)); CSSM_TP_APPLE_EVIDENCE_HEADER *hdr = (CSSM_TP_APPLE_EVIDENCE_HEADER *)malloc( sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER)); hdr->Version = CSSM_TP_APPLE_EVIDENCE_VERSION; CSSM_EVIDENCE_PTR ev = &VerifyContextResult->Evidence[0]; ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_HEADER; ev->Evidence = hdr; ev = &VerifyContextResult->Evidence[1]; ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERTGROUP; ev->Evidence = outCertGroup.buildCssmCertGroup(); ev = &VerifyContextResult->Evidence[2]; ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERT_INFO; ev->Evidence = outCertGroup.buildCssmEvidenceInfo(); } else { /* caller responsible for freeing these if they are for evidence.... */ outCertGroup.freeDbRecords(); } CSSM_RETURN outErr = outCertGroup.getReturnCode(constructReturn, policyReturn, actionFlags); if(outErr) { CssmError::throwMe(outErr); } }
/* * Fetch a CRL or a cert via a GeneralNames. * Shared by cert and CRL code to avoid duplicating GeneralNames traversal * code, despite the awkward interface for this function. */ static CSSM_RETURN tpFetchViaGeneralNames( const CE_GeneralNames *names, TPCertInfo &forCert, const CSSM_DATA *issuer, // optional, and only for CRLs TPVerifyContext *verifyContext, // only for CRLs CSSM_CL_HANDLE clHand, // only for certs CSSM_CSP_HANDLE cspHand, // only for certs const char *verifyTime, // optional /* exactly one must be non-NULL, that one is returned */ TPCertInfo **certInfo, TPCrlInfo **crlInfo) { assert(certInfo || crlInfo); assert(!certInfo || !crlInfo); CSSM_RETURN crtn; for(unsigned nameDex=0; nameDex<names->numNames; nameDex++) { CE_GeneralName *name = &names->generalName[nameDex]; switch(name->nameType) { case GNT_URI: if(name->name.Length < 5) { continue; } if(strncmp((char *)name->name.Data, "ldap:", 5) && strncmp((char *)name->name.Data, "http:", 5) && strncmp((char *)name->name.Data, "https:", 6)) { /* eventually handle other schemes here */ continue; } if(certInfo) { tpDebug(" fetching cert via net"); crtn = tpIssuerCertViaNet(name->name, clHand, cspHand, verifyTime, forCert, *certInfo); } else { tpDebug(" fetching CRL via net"); assert(verifyContext != NULL); crtn = tpCrlViaNet(name->name, issuer, *verifyContext, forCert, *crlInfo); } switch(crtn) { case CSSM_OK: case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE: // caller handles return crtn; default: break; } /* not found/no good; try again */ break; default: tpCrlDebug(" tpFetchCrlFromNet: unknown" "nameType (%u)", (unsigned)name->nameType); break; } /* switch nameType */ } /* for each name */ if(certInfo) { return CSSMERR_TP_CERTGROUP_INCOMPLETE; } else { return CSSMERR_APPLETP_CRL_NOT_FOUND; } }
static CSSM_RETURN tpCrlViaNet( const CSSM_DATA &url, const CSSM_DATA *issuer, // optional, only if cert and CRL have same issuer TPVerifyContext &vfyCtx, TPCertInfo &forCert, // for verifyWithContext TPCrlInfo *&rtnCrl) { TPCrlInfo *crl = NULL; CSSM_DATA crlData; CSSM_RETURN crtn; Allocator &alloc = Allocator::standard(); char cssmTime[CSSM_TIME_STRLEN+1]; rtnCrl = NULL; /* verifyTime: we want a CRL that's valid right now. */ { StLock<Mutex> _(tpTimeLock()); timeAtNowPlus(0, TIME_CSSM, cssmTime); } crtn = tpFetchViaNet(url, issuer, LT_Crl, cssmTime, alloc, crlData); if(crtn) { return crtn; } try { crl = new TPCrlInfo(vfyCtx.clHand, vfyCtx.cspHand, &crlData, TIC_CopyData, NULL); // verifyTime = Now } catch(...) { alloc.free(crlData.Data); /* * There is a slight possibility of recovering from this error. In case * the CRL came from disk cache, flush the cache and try to get the CRL * from the net. */ tpDebug(" bad CRL; flushing from cache and retrying"); ocspdCRLFlush(url); crtn = tpFetchViaNet(url, issuer, LT_Crl, cssmTime, alloc, crlData); if(crtn == CSSM_OK) { try { crl = new TPCrlInfo(vfyCtx.clHand, vfyCtx.cspHand, &crlData, TIC_CopyData, NULL); tpDebug(" RECOVERY: good CRL obtained from net"); } catch(...) { alloc.free(crlData.Data); tpDebug(" bad CRL; recovery FAILED (1)"); return CSSMERR_APPLETP_CRL_NOT_FOUND; } } else { /* it was in cache but we can't find it on the net */ tpDebug(" bad CRL; recovery FAILED (2)"); return CSSMERR_APPLETP_CRL_NOT_FOUND; } } alloc.free(crlData.Data); /* * Full CRL verify. * The verify time in the TPVerifyContext is the time at which various * entities (CRL and its own cert chain) are to be verified; that's * NULL for "right now". The current vfyCtx.verifyTime is the time at * which the cert's revocation status to be determined; this call to * verifyWithContextNow() doesn't do that. */ crtn = crl->verifyWithContextNow(vfyCtx, &forCert); if(crtn == CSSM_OK) { crl->uri(url); } else { delete crl; crl = NULL; } rtnCrl = crl; return crtn; }
/* * Search a list of DBs for a CRL from the specified issuer and (optional) * TPVerifyContext.verifyTime. * Just a boolean return - we found it, or not. If we did, we return a * TPCrlInfo which has been verified with the specified TPVerifyContext. */ TPCrlInfo *tpDbFindIssuerCrl( TPVerifyContext &vfyCtx, const CSSM_DATA &issuer, TPCertInfo &forCert) { StLock<Mutex> _(SecTrustKeychainsGetMutex()); uint32 dbDex; CSSM_HANDLE resultHand; CSSM_DATA crl; CSSM_DL_DB_HANDLE dlDb; CSSM_DB_UNIQUE_RECORD_PTR record; TPCrlInfo *issuerCrl = NULL; CSSM_DL_DB_LIST_PTR dbList = vfyCtx.dbList; CSSM_RETURN crtn; if(dbList == NULL) { return NULL; } for(dbDex=0; dbDex<dbList->NumHandles; dbDex++) { dlDb = dbList->DLDBHandle[dbDex]; crl.Data = NULL; crl.Length = 0; record = tpCrlLookup(dlDb, &issuer, vfyCtx.verifyTime, &resultHand, &crl); /* remember we have to: * -- abort this query regardless, and * -- free the CSSM_DATA crl regardless, and * -- free the unique record if we don't use it * (by placing it in issuerCert)... */ if(record != NULL) { /* Found one */ assert(crl.Data != NULL); issuerCrl = new TPCrlInfo(vfyCtx.clHand, vfyCtx.cspHand, &crl, TIC_CopyData, vfyCtx.verifyTime); /* we're done with raw CRL data */ /* FIXME this assumes that vfyCtx.alloc is the same as the * allocator associated with DlDB...OK? */ tpFreeCssmData(vfyCtx.alloc, &crl, CSSM_FALSE); crl.Data = NULL; crl.Length = 0; /* and we're done with the record */ CSSM_DL_FreeUniqueRecord(dlDb, record); /* Does it verify with specified context? */ crtn = issuerCrl->verifyWithContextNow(vfyCtx, &forCert); if(crtn) { delete issuerCrl; issuerCrl = NULL; /* * Verify fail. Continue searching this DB. Break on * finding the holy grail or no more records found. */ for(;;) { crl.Data = NULL; crl.Length = 0; crtn = CSSM_DL_DataGetNext(dlDb, resultHand, NULL, // no attrs &crl, &record); if(crtn) { /* no more, done with this DB */ assert(crl.Data == NULL); break; } assert(crl.Data != NULL); /* found one - is it any good? */ issuerCrl = new TPCrlInfo(vfyCtx.clHand, vfyCtx.cspHand, &crl, TIC_CopyData, vfyCtx.verifyTime); /* we're done with raw CRL data */ /* FIXME this assumes that vfyCtx.alloc is the same as the * allocator associated with DlDB...OK? */ tpFreeCssmData(vfyCtx.alloc, &crl, CSSM_FALSE); crl.Data = NULL; crl.Length = 0; CSSM_DL_FreeUniqueRecord(dlDb, record); crtn = issuerCrl->verifyWithContextNow(vfyCtx, &forCert); if(crtn == CSSM_OK) { /* yes! */ break; } delete issuerCrl; issuerCrl = NULL; } /* searching subsequent records */ } /* verify fail */ /* else success! */ if(issuerCrl != NULL) { /* successful return */ CSSM_DL_DataAbortQuery(dlDb, resultHand); tpDebug("tpDbFindIssuerCrl: found CRL record %p", record); return issuerCrl; } } /* tpCrlLookup, i.e., CSSM_DL_DataGetFirst, succeeded */ else { assert(crl.Data == NULL); } /* in any case, abort the query for this db */ CSSM_DL_DataAbortQuery(dlDb, resultHand); } /* main loop searching dbList */ /* issuer not found */ return NULL; }