/*
 * Get current CRL status for a certificate and its issuers.
 *
 * Possible results:
 *
 * CSSM_OK (we have a valid CRL; certificate is not revoked)
 * CSSMERR_TP_CERT_REVOKED (we have a valid CRL; certificate is revoked)
 * CSSMERR_APPLETP_NETWORK_FAILURE (CRL not available, download in progress)
 * CSSMERR_APPLETP_CRL_NOT_FOUND (CRL not available, and not being fetched)
 * CSSMERR_TP_INTERNAL_ERROR (unexpected error)
 *
 * Note that ocspdCRLStatus does NOT wait for the CRL to be downloaded before
 * returning, nor does it initiate a CRL download.
 */
static
CSSM_RETURN tpGetCrlStatusForCert(
	TPCertInfo						&subject,
	const CSSM_DATA					&issuers)
{
	CSSM_DATA *serialNumber=NULL;
	CSSM_RETURN crtn = subject.fetchField(&CSSMOID_X509V1SerialNumber, &serialNumber);
	if(crtn || !serialNumber) {
		return CSSMERR_TP_INTERNAL_ERROR;
	}
	crtn = ocspdCRLStatus(*serialNumber, issuers, subject.issuerName(), NULL);
	subject.freeField(&CSSMOID_X509V1SerialNumber, serialNumber);
	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;
}
예제 #3
0
/*
 * Fetch CRL(s) from specified cert if the cert has a cRlDistributionPoint
 * extension.
 *
 * Return values:
 *   CSSM_OK - found and returned fully verified CRL 
 *   CSSMERR_APPLETP_CRL_NOT_FOUND - no CRL in cRlDistributionPoint
 *   Anything else - gross error, typically from last LDAP/HTTP attempt
 *
 * FIXME - this whole mechanism sort of falls apart if verifyContext.verifyTime
 * is non-NULL. How are we supposed to get the CRL which was valid at 
 * a specified time in the past?
 */
CSSM_RETURN tpFetchCrlFromNet(
	TPCertInfo 			&cert,
	TPVerifyContext		&vfyCtx,
	TPCrlInfo			*&crl)			// RETURNED
{
	/* does the cert have a cRlDistributionPoint? */
	CSSM_DATA_PTR fieldValue;			// mallocd by CL
	
	CSSM_RETURN crtn = cert.fetchField(&CSSMOID_CrlDistributionPoints,
		&fieldValue);
	switch(crtn) {
		case CSSM_OK:
			break;
		case CSSMERR_CL_NO_FIELD_VALUES:
			/* field not present */
			return CSSMERR_APPLETP_CRL_NOT_FOUND;
		default:
			/* gross error */
			return crtn;
	}
	if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) {
		tpErrorLog("tpFetchCrlFromNet: malformed CSSM_FIELD");
		return CSSMERR_TP_UNKNOWN_FORMAT;
	}
	CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
	CE_CRLDistPointsSyntax *dps = 
		(CE_CRLDistPointsSyntax *)cssmExt->value.parsedValue;
	TPCrlInfo *rtnCrl = NULL;

	/* default return if we don't find anything */
	crtn = CSSMERR_APPLETP_CRL_NOT_FOUND;
	for(unsigned dex=0; dex<dps->numDistPoints; dex++) {
		CE_CRLDistributionPoint *dp = &dps->distPoints[dex];
		if(dp->distPointName == NULL) {
			continue;
		}
		/*
		 * FIXME if this uses an indirect CRL, we need to follow the 
		 * crlIssuer field... TBD.
		 */
		switch(dp->distPointName->nameType) {
			case CE_CDNT_NameRelativeToCrlIssuer:
				/* not yet */
				tpErrorLog("tpFetchCrlFromNet: "
					"CE_CDNT_NameRelativeToCrlIssuer not implemented\n");
				break;
				
			case CE_CDNT_FullName:
			{
				/*
				 * Since we don't support indirect CRLs (yet), we always pass
				 * the cert-to-be-verified's issuer as the CRL issuer for 
				 * cache lookup.
				 */
				CE_GeneralNames *names = dp->distPointName->dpn.fullName;
				crtn = tpFetchViaGeneralNames(names,
					cert,
					cert.issuerName(),
					&vfyCtx,
					0,			// clHand, use the one in vfyCtx
					0,			// cspHand, ditto
					vfyCtx.verifyTime,	
					NULL,		
					&rtnCrl);
				break;
			}	/* CE_CDNT_FullName */
			
			default:
				/* not yet */
				tpErrorLog("tpFetchCrlFromNet: "
					"unknown distPointName->nameType (%u)\n",
						(unsigned)dp->distPointName->nameType);
				break;
		}	/* switch distPointName->nameType */
		if(crtn == CSSM_OK) {
			/* i.e., tpFetchViaGeneralNames SUCCEEDED */
			break;
		}
	}	/* for each distPoints */

	cert.freeField(&CSSMOID_CrlDistributionPoints,	fieldValue);
	if(crtn == CSSM_OK) {
		assert(rtnCrl != NULL);
		crl = rtnCrl;
	}
	return crtn;
}