static int checkOneField(
	CSSM_CL_HANDLE		clHand,
	CSSM_HANDLE 		cacheHand1,
	CSSM_HANDLE 		cacheHand2,
	const CSSM_OID		*fieldOid)
{
	CSSM_DATA_PTR	fieldData1 = NULL;
	CSSM_DATA_PTR	fieldData2 = NULL;
	CSSM_RETURN		crtn;
	CSSM_HANDLE 	resultHand1 = 0;
	CSSM_HANDLE 	resultHand2 = 0;
	uint32 			numFields = 0;
	int				rtn;
	
	crtn = CSSM_CL_CertGetFirstCachedFieldValue(
		clHand,
		cacheHand1,
	    fieldOid,
	    &resultHand1,
	    &numFields,
		&fieldData1);
	if(crtn) {
		return crtn;
	}
	if(numFields != 1) {
		printf("Fiedl not present; try another cert\n");
		return 1;
	}
	crtn = CSSM_CL_CertGetFirstCachedFieldValue(
		clHand,
		cacheHand2,
	    fieldOid,
	    &resultHand2,
	    &numFields,
		&fieldData2);
	if(crtn) {
		return crtn;
	}
	rtn = compareFields(fieldOid, fieldData1, fieldData2);
  	CSSM_CL_CertAbortQuery(clHand, resultHand1);
  	CSSM_CL_CertAbortQuery(clHand, resultHand2);
	CSSM_CL_FreeFieldValue(clHand, fieldOid, fieldData1);
	CSSM_CL_FreeFieldValue(clHand, fieldOid, fieldData2);
	return rtn;
}
static void printOneCertName(
    CSSM_CL_HANDLE clHand,
    CSSM_HANDLE cacheHand,
    const char *title,
    const CSSM_OID *oid)
{
    CSSM_HANDLE resultHand = 0;
    CSSM_DATA_PTR field = NULL;
    uint32 numFields;
    CSSM_RETURN crtn;
    
    crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand,
	oid, &resultHand, &numFields, &field);
    if(crtn) {
	printf("***Error parsing cert\n");
	cssmPerror("CSSM_CL_CertGetFirstCachedFieldValue", crtn);
	return;
    }
    printName(title, field->Data, field->Length);
    CSSM_CL_FreeFieldValue(clHand, oid, field);
}
/*
 * Obtain atrbitrary field from cached cert. This class takes care of freeing
 * the field in its destructor. 
 *
 * Returns NULL if field not found (not exception). 
 *
 * Caller optionally specifies field length to check - specifying zero means
 * "don't care, don't check". Actual field length always returned in fieldLength. 
 */
const void *CertParser::fieldForOid(
	const CSSM_OID		&oid,
	CSSM_SIZE			&fieldLength)		// IN/OUT
{
	CSSM_RETURN crtn;
	
	uint32 NumberOfFields = 0;
	CSSM_HANDLE resultHand = 0;
	CSSM_DATA_PTR fieldData = NULL;

	assert(mClHand != 0);
	assert(mCacheHand != 0);
	crtn = CSSM_CL_CertGetFirstCachedFieldValue(
		mClHand,
		mCacheHand,
	    &oid,
	    &resultHand,
	    &NumberOfFields,
		&fieldData);
	if(crtn) {
		/* not an error; just means that the cert doesn't have this field */
		return NULL;
	}
	assert(NumberOfFields == 1);
  	CSSM_CL_CertAbortQuery(mClHand, resultHand);
	
	if(fieldLength) {
		if(fieldLength != fieldData->Length) {
			/* FIXME what's a good way to log in this situation? */
			printf("***CertParser::fieldForOid: field length mismatch\n");
			return NULL;
		}
	}
	/* Store the OID and the field for autorelease */
	CP_FetchedField *cpField = new CP_FetchedField(oid, fieldData, mClHand);
	mFetchedFields.push_back(cpField);
	fieldLength = fieldData->Length;
	return fieldData->Data;
}
/*
 * Given a DER encoded certificate, obtain the associated IssuerAndSerialNumber.
 */
krb5_error_code krb5int_pkinit_get_issuer_serial(
    const krb5_data *cert,
    krb5_data       *issuer_and_serial)
{
    CSSM_HANDLE cacheHand = 0;
    CSSM_RETURN crtn = CSSM_OK;
    CSSM_DATA certData = { cert->length, (uint8 *)cert->data };
    CSSM_HANDLE resultHand = 0;
    CSSM_DATA_PTR derIssuer = NULL;
    CSSM_DATA_PTR serial;
    krb5_data krb_serial;
    krb5_data krb_issuer;
    uint32 numFields;
    krb5_error_code ourRtn = 0;

    CSSM_CL_HANDLE clHand = pkiClStartup();
    if(clHand == 0) {
	return CSSMERR_CSSM_ADDIN_LOAD_FAILED;
    }
    /* subsequent errors to errOut: */

    crtn = CSSM_CL_CertCache(clHand, &certData, &cacheHand);
    if(crtn) {
	pkiCssmErr("CSSM_CL_CertCache", crtn);
	ourRtn = ASN1_PARSE_ERROR;
	goto errOut;
    }

    /* obtain the two fields; issuer is DER encoded */
    crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand,
	&CSSMOID_X509V1IssuerNameStd, &resultHand, &numFields, &derIssuer);
    if(crtn) {
	pkiCssmErr("CSSM_CL_CertGetFirstCachedFieldValue(issuer)", crtn);
	ourRtn = ASN1_PARSE_ERROR;
	goto errOut;
    }
    crtn = CSSM_CL_CertGetFirstCachedFieldValue(clHand, cacheHand,
	&CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &serial);
    if(crtn) {
	pkiCssmErr("CSSM_CL_CertGetFirstCachedFieldValue(serial)", crtn);
	ourRtn = ASN1_PARSE_ERROR;
	goto errOut;
    }
    PKI_CSSM_TO_KRB_DATA(derIssuer, &krb_issuer);
    PKI_CSSM_TO_KRB_DATA(serial, &krb_serial);
    ourRtn = krb5int_pkinit_issuer_serial_encode(&krb_issuer, &krb_serial, issuer_and_serial);

errOut:
    if(derIssuer) {
	CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1IssuerNameStd, derIssuer);
    }
    if(serial) {
	CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, serial);
    }
    if(cacheHand) {
	CSSM_CL_CertAbortCache(clHand, cacheHand);
    }
    if(clHand) {
	pkiClDetachUnload(clHand);
    }
    return ourRtn;
}