OCSPExtensions::OCSPExtensions(
	NSS_CertExtension **nssExts)
		: mCoder(NULL), mNumExtensions(0), mExtensions(NULL)
{
	SecAsn1CoderCreate(&mCoder);
	mNumExtensions = ocspdArraySize((const void **)nssExts);
	if(mNumExtensions == 0) {
		return;
	}
	
	mExtensions = (OCSPExtension **)SecAsn1Malloc(mCoder, 
		(mNumExtensions * sizeof(OCSPExtension *)));
	for(unsigned dex=0; dex<mNumExtensions; dex++) {
		try {
			mExtensions[dex] = 
				OCSPExtension::createFromNSS(mCoder, *nssExts[dex]);
			if(mExtensions[dex] == NULL) {
				ocspdErrorLog("OCSPExtensions: extension failure (NULL) dex %u\n", dex);
				CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
			}
			if(mExtensions[dex]->unrecognizedCritical()) {
				ocspdErrorLog("OCSPExtensions: unrecognized critical extension\n");
				CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
			}
		}
		catch (...) {
			ocspdErrorLog("OCSPExtensions: extension failure dex %u\n", dex);
			CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
		}
	}
}
/* 
 * Constructor during encode, called from subclass-specific constructorÊ(which
 * always has all of the subclass-specific arguments).
 */ 
OCSPExtension::OCSPExtension(
	SecAsn1CoderRef			coder,			// passed to subclass constructor
	const CSSM_OID			&extnId,		// subclass knows this 
	OCSPExtensionTag		tag,			// subclass knows this
	bool					critical)		// passed to subclass constructor
		: mNssExt(NULL),					// we'll cook this up
		  mCoder(coder),
		  mCritical(critical),
		  mTag(tag),
		  mUnrecognizedCritical(false)		// this is a tautology
{
	mNssExt = (NSS_CertExtension *)SecAsn1Malloc(coder, sizeof(NSS_CertExtension));
	memset(mNssExt, 0, sizeof(NSS_CertExtension));
	SecAsn1AllocCopyItem(coder, &extnId, &mNssExt->extnId);
	/* alloc one byte for critical flag */
	SecAsn1AllocItem(coder, &mNssExt->critical, 1);
	mNssExt->critical.Data[0] = critical ? 0xff : 0;
}
/*
 * Top-level encode for PA-PK-AS-REQ.
 */
krb5_error_code krb5int_pkinit_pa_pk_as_req_encode(
    const krb5_data *signed_auth_pack,      /* DER encoded ContentInfo */
    const krb5_data *trusted_CAs,	    /* optional: trustedCertifiers. Contents are
					     * DER-encoded issuer/serialNumbers. */
    krb5_ui_4	    num_trusted_CAs,
    const krb5_data *kdc_cert,		    /* optional kdcPkId, DER encoded issuer/serial */
    krb5_data	    *pa_pk_as_req)	    /* mallocd and RETURNED */
{
    KRB5_PA_PK_AS_REQ req;
    SecAsn1CoderRef coder;
    CSSM_DATA ber = {0, NULL};
    OSStatus ortn;
    unsigned dex;

    assert(signed_auth_pack != NULL);
    assert(pa_pk_as_req != NULL);

    if(SecAsn1CoderCreate(&coder)) {
	return ENOMEM;
    }

    /* krb5_data ==> CSSM format */

    memset(&req, 0, sizeof(req));
    PKI_KRB_TO_CSSM_DATA(signed_auth_pack, &req.signedAuthPack);
    if(num_trusted_CAs) {
	/*
	 * Set up a NULL-terminated array of KRB5_ExternalPrincipalIdentifier
	 * pointers. We malloc the actual KRB5_ExternalPrincipalIdentifiers as
	 * a contiguous array; it's in temp SecAsn1CoderRef memory. The referents
	 * are just dropped in from the caller's krb5_datas.
	 */
	KRB5_ExternalPrincipalIdentifier *cas =
	    (KRB5_ExternalPrincipalIdentifier *)SecAsn1Malloc(coder,
		num_trusted_CAs * sizeof(KRB5_ExternalPrincipalIdentifier));
	req.trusted_CAs =
	    (KRB5_ExternalPrincipalIdentifier **)
		pkiNssNullArray(num_trusted_CAs, coder);
	for(dex=0; dex<num_trusted_CAs; dex++) {
	    req.trusted_CAs[dex] = &cas[dex];
	    memset(&cas[dex], 0, sizeof(KRB5_ExternalPrincipalIdentifier));
	    PKI_KRB_TO_CSSM_DATA(&trusted_CAs[dex],
		&cas[dex].issuerAndSerialNumber);
	}
    }
    if(kdc_cert) {
	PKI_KRB_TO_CSSM_DATA(kdc_cert, &req.kdcPkId);
    }

    /* encode */
    ortn = SecAsn1EncodeItem(coder, &req, KRB5_PA_PK_AS_REQTemplate, &ber);
    if(ortn) {
	ortn = ENOMEM;
	goto errOut;
    }
    ortn = pkiCssmDataToKrb5Data(&ber, pa_pk_as_req);

errOut:
    SecAsn1CoderRelease(coder);
    return ortn;
}
/*
 * Encode AuthPack, public key version (no Diffie-Hellman components).
 */
krb5_error_code krb5int_pkinit_auth_pack_encode(
    krb5_timestamp		kctime,
    krb5_int32			cusec,		    /* microseconds */
    krb5_ui_4			nonce,
    const krb5_checksum		*pa_checksum,
    const krb5int_algorithm_id	*cms_types,	    /* optional */
    krb5_ui_4			num_cms_types,
    krb5_data			*auth_pack) /* mallocd and RETURNED */
{
    KRB5_AuthPack localAuthPack;
    SecAsn1CoderRef coder;
    CSSM_DATA *cksum = &localAuthPack.pkAuth.paChecksum;
    krb5_error_code ourRtn = 0;
    CSSM_DATA ber = {0, NULL};
    OSStatus ortn;
    char *timeStr = NULL;

    if(SecAsn1CoderCreate(&coder)) {
	return ENOMEM;
    }
    memset(&localAuthPack, 0, sizeof(localAuthPack));
    if(pkiKrbTimestampToStr(kctime, &timeStr)) {
	ourRtn = -1;
	goto errOut;
    }
    localAuthPack.pkAuth.kctime.Data = (uint8 *)timeStr;
    localAuthPack.pkAuth.kctime.Length = strlen(timeStr);
    if(pkiIntToData(cusec, &localAuthPack.pkAuth.cusec, coder)) {
	ourRtn = ENOMEM;
	goto errOut;
    }
    if(pkiIntToData(nonce, &localAuthPack.pkAuth.nonce, coder)) {
	ourRtn = ENOMEM;
	goto errOut;
    }
    cksum->Data = (uint8 *)pa_checksum->contents;
    cksum->Length = pa_checksum->length;

    if((cms_types != NULL) && (num_cms_types != 0)) {
	unsigned dex;
	CSSM_X509_ALGORITHM_IDENTIFIER **algIds;

	/* build a NULL_terminated array of CSSM_X509_ALGORITHM_IDENTIFIERs */
	localAuthPack.supportedCMSTypes = (CSSM_X509_ALGORITHM_IDENTIFIER **)
	    SecAsn1Malloc(coder,
		(num_cms_types + 1) * sizeof(CSSM_X509_ALGORITHM_IDENTIFIER *));
	algIds = localAuthPack.supportedCMSTypes;
	for(dex=0; dex<num_cms_types; dex++) {
	    algIds[dex] = (CSSM_X509_ALGORITHM_IDENTIFIER *)
		SecAsn1Malloc(coder, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
	    pkiKrb5DataToCssm(&cms_types[dex].algorithm,
		&algIds[dex]->algorithm, coder);
	    if(cms_types[dex].parameters.data != NULL) {
		pkiKrb5DataToCssm(&cms_types[dex].parameters,
		    &algIds[dex]->parameters, coder);
	    }
	    else {
		algIds[dex]->parameters.Data = NULL;
		algIds[dex]->parameters.Length = 0;
	    }
	}
	algIds[num_cms_types] = NULL;
    }
    ortn = SecAsn1EncodeItem(coder, &localAuthPack, KRB5_AuthPackTemplate, &ber);
    if(ortn) {
	ourRtn = ENOMEM;
	goto errOut;
    }

    if(pkiCssmDataToKrb5Data(&ber, auth_pack)) {
	ourRtn = ENOMEM;
    }
    else {
	auth_pack->magic = KV5M_AUTHENTICATOR;
	ourRtn = 0;
    }
errOut:
    SecAsn1CoderRelease(coder);
    return ourRtn;
}