Example #1
0
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;
}
/*
 * Find CRL for specified cert. Only returns a fully verified CRL. 
 * Cert-specific errors such as CSSMERR_APPLETP_CRL_NOT_FOUND will be added
 * to cert's return codes. 
 */
static CSSM_RETURN tpFindCrlForCert(
	TPCertInfo						&subject,
	TPCrlInfo						*&foundCrl,		// RETURNED
	TPVerifyContext					&vfyCtx)
{
	
	tpCrlDebug("tpFindCrlForCert top");
	TPCrlInfo *crl = NULL;
	foundCrl = NULL;
	CSSM_APPLE_TP_CRL_OPT_FLAGS crlOptFlags = 0;
	
	if(vfyCtx.crlOpts) {
		crlOptFlags = vfyCtx.crlOpts->CrlFlags;
	}
	
	/* Search inputCrls for a CRL for subject cert */
	if(vfyCtx.inputCrls != NULL) {
		crl = vfyCtx.inputCrls->findCrlForCert(subject);
		if(crl && (crl->verifyWithContextNow(vfyCtx, &subject) == CSSM_OK)) {
			foundCrl = crl;
			crl->mFromWhere = CFW_InGroup;
			tpCrlDebug("   ...CRL found in CrlGroup");
			return CSSM_OK;
		}
	}

	/* local process-wide cache */
	crl = tpGlobalCrlCache().search(subject, vfyCtx);
	if(crl) {
		tpCrlDebug("...tpFindCrlForCert found CRL in cache, calling verifyWithContext");
		if(crl->verifyWithContextNow(vfyCtx, &subject) == CSSM_OK) {
			foundCrl = crl;
			crl->mFromWhere = CFW_LocalCache;
			tpCrlDebug("   ...CRL found in local cache");
			return CSSM_OK;
		}
		else {
			tpGlobalCrlCache().release(*crl);
		}
	}
	
	/* 
	 * Try DL/DB.
	 * Note tpDbFindIssuerCrl() returns a verified CRL.
	 */
	crl = tpDbFindIssuerCrl(vfyCtx, *subject.issuerName(), subject);
	if(crl) {
		foundCrl = crl;
		crl->mFromWhere = CFW_DlDb;
		tpCrlDebug("   ...CRL found in DlDb");
		return CSSM_OK;
	}
	
	/* Last resort: try net if enabled */
	CSSM_RETURN crtn = CSSMERR_APPLETP_CRL_NOT_FOUND;
	crl = NULL;
	if(crlOptFlags & CSSM_TP_ACTION_FETCH_CRL_FROM_NET) {
		crtn = tpFetchCrlFromNet(subject, vfyCtx, crl);
	}
	
	if(crtn) {
		tpCrlDebug("   ...tpFindCrlForCert: CRL not found");
		if(subject.addStatusCode(crtn)) {
			return crtn;
		}
		else {
			return CSSM_OK;
		}
	}
	
	/* got one from net - add to global cache */
	assert(crl != NULL);
	tpGlobalCrlCache().add(*crl);
	crl->mFromWhere = CFW_Net;
	tpCrlDebug("   ...CRL found from net");
	
	foundCrl = crl;
	return CSSM_OK;
}
/*
 * 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;
}