/*
 * Given a certificate, obtain the DER-encoded issuer and serial number. Result
 * is mallocd and must be freed by caller.
 */
static OSStatus pkinit_get_cert_issuer_sn(
    SecCertificateRef certRef,
    CSSM_DATA *issuerSerial)            /* mallocd and RETURNED */
{
    OSStatus ortn;
    CSSM_DATA certData;
    krb5_data INIT_KDATA(issuerSerialKrb);
    krb5_data certDataKrb;
    krb5_error_code krtn;

    assert(certRef != NULL);
    assert(issuerSerial != NULL);

    ortn = SecCertificateGetData(certRef, &certData);
    if(ortn) {
        pkiCssmErr("SecCertificateGetData", ortn);
        return ortn;
    }
    PKI_CSSM_TO_KRB_DATA(&certData, &certDataKrb);
    krtn = krb5int_pkinit_get_issuer_serial(&certDataKrb, &issuerSerialKrb);
    if(krtn) {
        return CSSMERR_CL_INVALID_DATA;
    }
    PKI_KRB_TO_CSSM_DATA(&issuerSerialKrb, issuerSerial);
    return noErr;
}
/*
 * 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;
}