Example #1
0
/* 
 * Obtain a OCSPSingleResponse for a given raw encoded CertID. 
 */
OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID)
{
	unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
	for(unsigned dex=0; dex<numResponses; dex++) {
		SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
		CSSM_DATA certID = {0, NULL};
		if(SecAsn1EncodeItem(mCoder, &resp->certID, kSecAsn1OCSPCertIDTemplate,
				&certID)) {
			ocspdDebug("OCSPResponse::singleResponse: error encoding certID!");
			return NULL;
		}
		if(!ocspdCompareCssmData(&matchCertID, &certID)) {
			/* try to find another */
			continue;
		}
		try {
			OCSPSingleResponse *singleResp = new OCSPSingleResponse(resp);
			return singleResp;
		}
		catch(...) {
			/* try to find another... */
			continue;
		}
	}
	ocspdDebug("OCSPResponse::singleResponse: certID not found");
	return NULL;

}
/*
 * Given DER-encoded issuer and serial number, create an encoded
 * IssuerAndSerialNumber.
 */
krb5_error_code krb5int_pkinit_issuer_serial_encode(
    const krb5_data *issuer,		    /* DER encoded */
    const krb5_data *serial_num,
    krb5_data       *issuer_and_serial)     /* content mallocd and RETURNED */
{
    KRB5_IssuerAndSerial issuerSerial;
    SecAsn1CoderRef coder;
    CSSM_DATA ber = {0, NULL};
    OSStatus ortn;

    if(SecAsn1CoderCreate(&coder)) {
	return ENOMEM;
    }
    PKI_KRB_TO_CSSM_DATA(issuer, &issuerSerial.derIssuer);
    PKI_KRB_TO_CSSM_DATA(serial_num, &issuerSerial.serialNumber);
    ortn = SecAsn1EncodeItem(coder, &issuerSerial, KRB5_IssuerAndSerialTemplate, &ber);
    if(ortn) {
	ortn = ENOMEM;
	goto errOut;
    }
    ortn = pkiCssmDataToKrb5Data(&ber, issuer_and_serial);
errOut:
    SecAsn1CoderRelease(coder);
    return ortn;
}
int derDecodeInit(
	TestParams *testParams)
{
	/*
	 * DER encode a sequence of two integers
	 */
	twoInts ti;
	ti.int1.Data = int1;
	ti.int1.Length = sizeof(int1);
	ti.int2.Data = int2;
	ti.int2.Length = sizeof(int2);
	
	/* encode --> tempDer */
	SecAsn1CoderRef coder;
	SecAsn1CoderCreate(&coder);
	
	CSSM_DATA tmpDer = {0, NULL};
	if(SecAsn1EncodeItem(coder, &ti, twoIntsTemp, &tmpDer)) {
		printf("***derDecodeInit: Error on encodeItem()\n");
		return -1;
	}
	
	/* copy to goodDer and badDer */
	appCopyCssmData(&tmpDer, &goodDer);
	appCopyCssmData(&tmpDer, &badDer);
	
	/* increment the length of the outer sequence to force error */
	badDer.Data[1]++;
	SecAsn1CoderRelease(coder);
	return 0;
}
Example #4
0
/*
 * If responderID is of form RIT_Name, return the encoded version of the 
 * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily,
 * once, in mCoder space.
 */
const CSSM_DATA *OCSPResponse::encResponderName()
{
	if(mResponderIdTag != RIT_Name) {
		assert(0);
		return NULL;
	}
	if(mEncResponderName.Data != NULL) {
		return &mEncResponderName;
	}
	if(SecAsn1EncodeItem(mCoder, &mResponderId.byName, kSecAsn1NameTemplate, 
			&mEncResponderName)) {
		ocspdDebug("OCSPResponse::encResponderName: error encoding ResponderId!");
		return NULL;
	}
	return &mEncResponderName;
}
Example #5
0
/*
 * Given a kerberos service tiocket in GSS form (i.e., an AP_REQ),
 * cook up a DER-encoded SPNEGO blob. Result is malloc'd; caller
 * must free.
 */
int spnegoCreateInit(
					 const unsigned char *gssBlob,
					 unsigned gssBlobLen,
					 unsigned char **spnegoBlob,			// mallocd and RETURNED
					 unsigned *spnegoBlobLen)			// RETURNED
{
	SpnegoNegTokenInitGss negInit;
	SecAsn1CoderRef coder;

	if(SecAsn1CoderCreate(&coder)) {
		/* memory failure */
		return -1;
	}
	memset(&negInit, 0, sizeof(negInit));
	negInit.oid = CSSMOID_SPNEGO;
	negInit.token.mechTypeList = (CSSM_OID **)nssNullArray(coder, 2);
	negInit.token.mechTypeList[0] = (CSSM_OID *)&CSSMOID_KERB_V5_LEGACY;
	negInit.token.mechTypeList[1] = (CSSM_OID *)&CSSMOID_KERB_V5;
	/* no contextFlags for now, though we might need 'em */
	CSSM_DATA gssData;
	if(gssBlob) {
		gssData.Data = (uint8 *)gssBlob;
		gssData.Length = gssBlobLen;
		negInit.token.mechToken = &gssData;
	}

	CSSM_DATA res = {0, NULL};
	OSStatus ortn = SecAsn1EncodeItem(coder, &negInit,
									  SpnegoNegTokenInitGssTemplate, &res);
	if(ortn) {
		SecAsn1CoderRelease(coder);
		return -1;
	}
	*spnegoBlob = (unsigned char *)malloc(res.Length);
	memmove(*spnegoBlob, res.Data, res.Length);
	*spnegoBlobLen = res.Length;

	/* this frees all memory allocated during SecAsn1EncodeItem() */
	SecAsn1CoderRelease(coder);
	return 0;
}
/*
 * Encode a ReplyKeyPack. The result is used as the Content of a SignedData.
 */
krb5_error_code krb5int_pkinit_reply_key_pack_encode(
    const krb5_keyblock *key_block,
    const krb5_checksum *checksum,
    krb5_data		*reply_key_pack)      /* mallocd and RETURNED */
{
    KRB5_ReplyKeyPack repKeyPack;
    SecAsn1CoderRef coder;
    krb5_error_code ourRtn = 0;
    CSSM_DATA der = {0, NULL};
    OSStatus ortn;
    KRB5_EncryptionKey *encryptKey = &repKeyPack.encryptionKey;
    KRB5_Checksum *cksum = &repKeyPack.asChecksum;

    if(SecAsn1CoderCreate(&coder)) {
	return ENOMEM;
    }
    memset(&repKeyPack, 0, sizeof(repKeyPack));

    if((ourRtn = pkiIntToData(key_block->enctype, &encryptKey->keyType, coder))) {
	goto errOut;
    }
    encryptKey->keyValue.Length = key_block->length,
    encryptKey->keyValue.Data = (uint8 *)key_block->contents;

    if((ourRtn = pkiIntToData(checksum->checksum_type, &cksum->checksumType, coder))) {
	goto errOut;
    }
    cksum->checksum.Data = (uint8 *)checksum->contents;
    cksum->checksum.Length = checksum->length;

    ortn = SecAsn1EncodeItem(coder, &repKeyPack, KRB5_ReplyKeyPackTemplate, &der);
    if(ortn) {
	ourRtn = ENOMEM;
	goto errOut;
    }
    ourRtn = pkiCssmDataToKrb5Data(&der, reply_key_pack);
errOut:
    SecAsn1CoderRelease(coder);
    return ourRtn;
}
/*
 * DER encode in specified coder's memory.
 */
const CSSM_DATA *OCSPClientCertID::encode()
{
	if(mEncoded.Data != NULL) {
		return &mEncoded;
	}

	SecAsn1OCSPCertID	certID;
	uint8				issuerNameHash[CC_SHA1_DIGEST_LENGTH];
	uint8				pubKeyHash[CC_SHA1_DIGEST_LENGTH];

	/* algId refers to the hash we'll perform in issuer name and key */
	certID.algId.algorithm = CSSMOID_SHA1;
	certID.algId.parameters.Data = nullParam;
	certID.algId.parameters.Length = sizeof(nullParam);

	/* SHA1(issuerName) */
	ocspdSha1(mIssuerName.Data, (CC_LONG)mIssuerName.Length, issuerNameHash);

	/* SHA1(issuer public key bytes) */
	ocspdSha1(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, pubKeyHash);

	/* build the CertID from those components */
	certID.issuerNameHash.Data = issuerNameHash;
	certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
	certID.issuerPubKeyHash.Data = pubKeyHash;
	certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
	certID.serialNumber = mSubjectSerial;

	/* encode */
	SecAsn1CoderRef coder;
	SecAsn1CoderCreate(&coder);

	CSSM_DATA tmp = {0, NULL};
	SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp);
	allocCopyData(tmp, mEncoded);
	SecAsn1CoderRelease(coder);
	return &mEncoded;
}
/*
 * Encode a KRB5_PA_PK_AS_REP.
 */
krb5_error_code krb5int_pkinit_pa_pk_as_rep_encode(
    const krb5_data *dh_signed_data,
    const krb5_data *enc_key_pack,
    krb5_data       *pa_pk_as_rep)      /* mallocd and RETURNED */
{
    KRB5_PA_PK_AS_REP asRep;
    SecAsn1CoderRef coder;
    krb5_error_code ourRtn = 0;
    CSSM_DATA	    der = {0, NULL};
    OSStatus	    ortn;
    CSSM_DATA	    dhSignedData;
    CSSM_DATA	    encKeyPack;

    if(SecAsn1CoderCreate(&coder)) {
	return ENOMEM;
    }
    memset(&asRep, 0, sizeof(asRep));
    if(dh_signed_data) {
	PKI_KRB_TO_CSSM_DATA(dh_signed_data, &dhSignedData);
	asRep.dhSignedData = &dhSignedData;
    }
    if(enc_key_pack) {
	PKI_KRB_TO_CSSM_DATA(enc_key_pack, &encKeyPack);
	asRep.encKeyPack = &encKeyPack;
    }

    ortn = SecAsn1EncodeItem(coder, &asRep, KRB5_PA_PK_AS_REPTemplate, &der);
    if(ortn) {
	ourRtn = ENOMEM;
	goto errOut;
    }
    ourRtn = pkiCssmDataToKrb5Data(&der, pa_pk_as_rep);

errOut:
    SecAsn1CoderRelease(coder);
    return ourRtn;
}
/*
 * 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;
}
static int genOcspResp(
	CSSM_CL_HANDLE clHand, 
	SecAsn1OCSPCertStatusTag status,
	CE_CrlReason reason,			// for CS_Revoked
	const unsigned char *subjectCert,
	unsigned subjectCertLen,
	const unsigned char *issuerCert,
	unsigned issuerCertLen,
	SecIdentityRef signer,
	unsigned char **outData,
	unsigned *outDataLen)
{
	SecAsn1CoderRef coder;
	SecAsn1CoderCreate(&coder);

	CSSM_DATA subjectCertData = {subjectCertLen, (uint8 *)subjectCert};
	CSSM_DATA issuerCertData = {issuerCertLen, (uint8 *)issuerCert};
	uint8 nonceBytes[8] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
	CSSM_DATA nonceData = {8, nonceBytes};
	CSSM_DATA tbs;
	CSSM_DATA encoded = {0, NULL};
	SecAsn1OCSPResponse topResponse;
	SecAsn1OCSPResponseBytes responseBytes;
	uint8 responseStatusByte;
	CSSM_DATA resp = {0, NULL};
	CSSM_DATA sig = {0, NULL};
	
	int irtn = genTbsResp(coder, clHand, status, reason, 
		subjectCertData, issuerCertData,
		0,			// thisUpdate
		2600 * 24,	// next update
		&nonceData,
		tbs);
	if(irtn) {
		printf("***Error encoding tbsResp\n");
		return irtn;
	}
	
	/* 
	 * That's the TBSResponseData. Sign it.
	 */
	OSStatus ortn;
	SecAsn1OCSPBasicResponse basicResp;
	memset(&basicResp, 0, sizeof(basicResp));
	ortn = ocspSign(signer, tbs, CSSM_ALGID_SHA1WithRSA, sig);
	if(ortn) {
		printf("***Error signing basicResponse.\n");
		goto errOut;
	}
	basicResp.algId.algorithm = CSSMOID_SHA1WithRSA;
	basicResp.algId.parameters.Data = nullParam;
	basicResp.algId.parameters.Length = sizeof(nullParam);
	basicResp.tbsResponseData = tbs;
	basicResp.sig = sig;
	/* ASN1 encoder needs to know length in bits */
	basicResp.sig.Length *= 8;
	/* no certs for now */
	/* encode SecAsn1OCSPBasicResponse */
	
	ortn = SecAsn1EncodeItem(coder, &basicResp, kSecAsn1OCSPBasicResponseTemplate,
		&encoded);
	if(ortn) {
		printf("***Error encoding SecAsn1OCSPBasicResponse\n");
	}
	
	/* put that into a SecAsn1OCSPResponse */
	responseBytes.responseType = CSSMOID_PKIX_OCSP_BASIC;
	responseBytes.response = encoded;
	responseStatusByte = RS_Success;
	topResponse.responseStatus.Data = &responseStatusByte;
	topResponse.responseStatus.Length = 1;
	topResponse.responseBytes = &responseBytes;
	ortn = SecAsn1EncodeItem(coder, &topResponse, kSecAsn1OCSPResponseTemplate,
		&resp);
	if(ortn) {
		printf("***Error encoding SecAsn1OCSPBasicResponse\n");
		goto errOut;
	}

	/* TA DA */
	*outData = (unsigned char *)malloc(resp.Length);
	*outDataLen = resp.Length;
	memmove(*outData, resp.Data, resp.Length);
errOut:
	SecAsn1CoderRelease(coder);
	if(sig.Data) {
		APP_FREE(sig.Data);
	}
	return ortn;
}
static int genOcspReq(
	CSSM_CL_HANDLE clHand,
	const unsigned char *certFile, 
	unsigned certFileLen, 
	const unsigned char *issuerCertFile, 
	unsigned issuerCertFileLen, 
	unsigned char **outFile,		// RETURNED 
	unsigned *outFileLen)			// RETURNED
{
	CertParser parser(clHand);
	CertParser issuerParser(clHand);
	CSSM_DATA certData = {certFileLen, (uint8 *)certFile};
	CSSM_RETURN crtn;
	crtn = parser.initWithData(certData);
	if(crtn) {
		cssmPerror("CertParser.initWithData for subject cert", crtn);
		return -1;
	}
	certData.Data = (uint8 *)issuerCertFile;
	certData.Length = issuerCertFileLen;
	crtn = issuerParser.initWithData(certData);
	if(crtn) {
		cssmPerror("CertParser.initWithData for issuer", crtn);
		return -1;
	}
	
	/* 
	 * One single request, no extensions
	 */
	SecAsn1OCSPRequest singleReq;
	memset(&singleReq, 0, sizeof(singleReq));
	SecAsn1OCSPCertID &certId = singleReq.reqCert;

	/* algId refers to the hash we'll perform in issuer name and key */
	certId.algId.algorithm = CSSMOID_SHA1;
	certId.algId.parameters.Data = nullParam;
	certId.algId.parameters.Length = sizeof(nullParam);
	
	/* SHA1(issuerName) */
	CSSM_DATA issuerName = {0, NULL};
	issuerName.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1IssuerNameStd, 
		issuerName.Length);
	if(issuerName.Data == NULL) {
		printf("***Error fetching issuer name. Aborting.\n");
		return 1;
	}
	uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH];
	ocspdSha1(issuerName.Data, issuerName.Length, issuerNameHash);
	
	/* SHA1(issuer public key) */
	CSSM_KEY_PTR pubKey = NULL;
	CSSM_SIZE pubKeyLen = sizeof(CSSM_KEY);
	pubKey = (CSSM_KEY_PTR)issuerParser.fieldForOid(CSSMOID_CSSMKeyStruct, pubKeyLen);
	if(pubKey == NULL) {
		printf("***Error fetching public key from issuer cert. Aborting.\n");
		return 1;
	}
	uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH];
	ocspdSha1(pubKey->KeyData.Data, pubKey->KeyData.Length, pubKeyHash);

	/* serial number */
	CSSM_DATA serialNum = {0, NULL};
	serialNum.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1SerialNumber, 
		serialNum.Length);
	if(serialNum.Data == NULL) {
		printf("***Error fetching serial number. Aborting.\n");
		return 1;
	}

	/* build the CertID from those components */
	certId.issuerNameHash.Data = issuerNameHash;
	certId.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
	certId.issuerPubKeyHash.Data = pubKeyHash;
	certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;	
	certId.serialNumber = serialNum;

	/* 
	 * Build top level request with one entry in requestList, no signature,
	 * one extension (a nonce)
	 */
	SecAsn1OCSPSignedRequest signedReq;
	SecAsn1OCSPRequest *reqArray[2] = { &singleReq, NULL };
	SecAsn1OCSPTbsRequest &tbs = signedReq.tbsRequest;
	memset(&signedReq, 0, sizeof(signedReq));
	uint8 version = 0;
	CSSM_DATA vers = {1, &version};
	tbs.version = &vers;
	tbs.requestList = reqArray;

	/* one extension - the nonce */
	SecAsn1CoderRef coder;
	SecAsn1CoderCreate(&coder);
	uint8 nonceBytes[8] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0};
	CSSM_DATA nonceData = {8, nonceBytes};
	OCSPNonce *nonce = new OCSPNonce(coder, false, nonceData);
	NSS_CertExtension *extenArray[2] = {nonce->nssExt(), NULL};
	tbs.requestExtensions = extenArray;
	
	/* Encode */
	OSStatus ortn;
	CSSM_DATA encoded = {0, NULL};
	ortn = SecAsn1EncodeItem(coder, &signedReq, kSecAsn1OCSPSignedRequestTemplate,
		&encoded);
	if(ortn) {
		printf("***Error encoding SecAsn1OCSPSignedRequest\n");
	}
	else {
		*outFile = (unsigned char *)malloc(encoded.Length);
		*outFileLen = encoded.Length;
		memmove(*outFile, encoded.Data, encoded.Length);
	}
	SecAsn1CoderRelease(coder);
	return (int)ortn;
}
/*
 * Given the following, create a ResponseData (to be signed by caller).
 *
 *		cert status (CS_{Good,Revoked,Unknown})
 *		cert being verified
 *		issuer cert
 *		this update time
 *		next update time (optional)
 *		nonce (optional)
 */
static int genTbsResp(
	SecAsn1CoderRef coder,			// result in this coder's address space
	CSSM_CL_HANDLE clHand, 
	SecAsn1OCSPCertStatusTag status,
	CE_CrlReason reason,			// for CS_Revoked
	const CSSM_DATA	&subjectCert,
	const CSSM_DATA &issuerCert,
	unsigned thisUpdate,			// required, seconds from now
	unsigned nextUpdate,			// optional, seconds from now, 0 ==> skip
	const CSSM_DATA *nonce,			// optional
	CSSM_DATA &encodedTbs)			// allocated in coder space and RETURNED
{
	char *nextUpdStr = NULL;
	CSSM_DATA nextUpdateData;
	char *thisUpdStr = NULL;
	CSSM_DATA *thisUpdateData;
	SecAsn1OCSPResponseData responseData;
	OCSPNonce *nonceExt = NULL;
	char *producedAt = NULL;
	SecAsn1OCSPSingleResponse singleResp;
	SecAsn1OCSPSingleResponse *respArray[2] = {&singleResp, NULL};
	SecAsn1OCSPResponderID responderID;
	NSS_CertExtension *extenArray[2] = {NULL, NULL};
	
	/* SingleResponse */
	memset(&singleResp, 0, sizeof(singleResp));
	
	/* SingleResponse.CertID */
	SecAsn1OCSPCertID &certId = singleResp.certID;
	CertParser parser(clHand);
	CertParser issuerParser(clHand);
	CSSM_RETURN crtn = parser.initWithData(subjectCert);
	if(crtn) {
		cssmPerror("CertParser.initWithData for subject cert", crtn);
		return -1;
	}
	crtn = issuerParser.initWithData(issuerCert);
	if(crtn) {
		cssmPerror("CertParser.initWithData for issuer", crtn);
		return -1;
	}

	/* algId refers to the hash we'll perform in issuer name and key */
	certId.algId.algorithm = CSSMOID_SHA1;
	certId.algId.parameters.Data = nullParam;
	certId.algId.parameters.Length = sizeof(nullParam);
	
	/* SHA1(issuerName) */
	CSSM_DATA issuerName = {0, NULL};
	issuerName.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1IssuerNameStd, 
		issuerName.Length);
	if(issuerName.Data == NULL) {
		printf("***Error fetching issuer name. Aborting.\n");
		return 1;
	}
	uint8 issuerNameHash[CC_SHA1_DIGEST_LENGTH];
	ocspdSha1(issuerName.Data, issuerName.Length, issuerNameHash);
	
	/* SHA1(issuer public key) */
	CSSM_KEY_PTR pubKey = NULL;
	CSSM_SIZE pubKeyLen = sizeof(CSSM_KEY);
	pubKey = (CSSM_KEY_PTR)issuerParser.fieldForOid(CSSMOID_CSSMKeyStruct, pubKeyLen);
	if(pubKey == NULL) {
		printf("***Error fetching public key from issuer cert. Aborting.\n");
		return 1;
	}
	uint8 pubKeyHash[CC_SHA1_DIGEST_LENGTH];
	ocspdSha1(pubKey->KeyData.Data, pubKey->KeyData.Length, pubKeyHash);

	/* serial number */
	CSSM_DATA serialNum = {0, NULL};
	serialNum.Data = (uint8 *)parser.fieldForOid(CSSMOID_X509V1SerialNumber, 
		serialNum.Length);
	if(serialNum.Data == NULL) {
		printf("***Error fetching serial number. Aborting.\n");
		return 1;
	}

	/* build the CertID from those components */
	certId.issuerNameHash.Data = issuerNameHash;
	certId.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
	certId.issuerPubKeyHash.Data = pubKeyHash;
	certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;	
	certId.serialNumber = serialNum;

	/* SingleResponse.CertStatus - to be encoded on its own */
	SecAsn1OCSPCertStatus certStatus;
	memset(&certStatus, 0, sizeof(certStatus));
	SecAsn1OCSPRevokedInfo revokedInfo;
	char *revokedAt = NULL;
	CSSM_DATA reasonData;
	OSStatus ortn;
	
	if(status == CS_Revoked) { 
		/* cook up SecAsn1OCSPRevokedInfo */
		certStatus.revokedInfo = &revokedInfo;
		revokedAt = appTimeAtNowPlus(-3600, TIME_GEN);
		revokedInfo.revocationTime.Data = (uint8 *)revokedAt; 
		revokedInfo.revocationTime.Length = strlen(revokedAt);
		uint8 theReason = reason;
		reasonData.Data = &theReason;
		reasonData.Length = 1;
		revokedInfo.revocationReason = &reasonData;
		ortn = SecAsn1EncodeItem(coder, &certStatus, 
			kSecAsn1OCSPCertStatusRevokedTemplate, 
			&singleResp.certStatus);
	}
	else {
		ortn = SecAsn1EncodeItem(coder, &certStatus, 
			kSecAsn1OCSPCertStatusGoodTemplate,
			&singleResp.certStatus);
	}
	if(ortn) {
		printf("***Error encoding certStatus\n"); 
		goto errOut;
	}
	
	/* SingleResponse.thisUpdate */
	thisUpdStr = appTimeAtNowPlus(thisUpdate, TIME_GEN);
	thisUpdateData = &singleResp.thisUpdate;
	thisUpdateData->Data = (uint8 *)thisUpdStr;
	thisUpdateData->Length = strlen(thisUpdStr);
	
	/* SingleResponse.nextUpdate, optional */
	if(nextUpdate) {
		nextUpdStr = appTimeAtNowPlus(nextUpdate, TIME_GEN); 
		nextUpdateData.Data = (uint8 *)nextUpdStr;
		nextUpdateData.Length = strlen(nextUpdStr);
		singleResp.nextUpdate = &nextUpdateData;
	}
	
	/* Single Extensions - none for now */
	 
	/* Now up to ResponseData */
	memset(&responseData, 0, sizeof(responseData));
	
	/* skip version */
	
	/* 
	 * ResponseData.responderID: KeyHash (of signer); we already got this for CertID.
	 * WE have to encode this one separately and drop it in as an ASN_ANY. 
	 */
	responderID.byKey = certId.issuerPubKeyHash;
	ortn = SecAsn1EncodeItem(coder, &responderID, 
		kSecAsn1OCSPResponderIDAsKeyTemplate,
		&responseData.responderID);
	if(ortn) {
		printf("***Error encoding responderID\n");
		goto errOut;
	}
	
	/* ResponseData.producedAt = now */
	producedAt = appTimeAtNowPlus(0, TIME_GEN);
	responseData.producedAt.Data = (uint8 *)producedAt;
	responseData.producedAt.Length = strlen(producedAt);
		
	/* ResponseData.responses - one of 'em */
	responseData.responses = respArray;
	
	/* ResponseData.responseExtensions - optionally one, nonce */
	if(nonce) {
		nonceExt = new OCSPNonce(coder, false, *nonce);
		extenArray[0] = nonceExt->nssExt();
		responseData.responseExtensions = extenArray;
	}
	else {
		responseData.responseExtensions = NULL;
	}
	
	/* encode it */
	encodedTbs.Data = NULL;
	encodedTbs.Length = 0;
	ortn = SecAsn1EncodeItem(coder, &responseData, 
		kSecAsn1OCSPResponseDataTemplate,
		&encodedTbs);
	if(ortn) {
		printf("***Error encoding SecAsn1OCSPResponseData\n");
	}
errOut:
	/* free resources */
	if(revokedAt) {
		CSSM_FREE(revokedAt);
	}
	if(thisUpdStr) {
		CSSM_FREE(thisUpdStr);
	}
	if(nextUpdStr) {
		CSSM_FREE(nextUpdStr);
	}
	if(nonceExt) {
		delete nonceExt;
	}
	return ortn;
}
	certId->issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
	certId->issuerNameHash.Data = (uint8_t *)CFDataGetBytePtr(issuerNameDigest);
	certId->issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
	certId->issuerPubKeyHash.Data = (uint8_t *)CFDataGetBytePtr(issuerPubKeyDigest);
	certId->serialNumber.Length = CFDataGetLength(serial);
	certId->serialNumber.Data = (uint8_t *)CFDataGetBytePtr(serial);

	/* Build top level request with one entry in requestList, no signature,
       and no optional extensions. */
	tbs->version = &vers;
	tbs->requestList = reqArray;

	/* Encode the request. */
    require_noerr(SecAsn1CoderCreate(&coder), errOut);
    SecAsn1Item encoded;
	require_noerr(SecAsn1EncodeItem(coder, &signedReq,
        kSecAsn1OCSPSignedRequestTemplate, &encoded), errOut);
    der = CFDataCreate(kCFAllocatorDefault, encoded.Data,
        encoded.Length);

errOut:
    if (coder)
        SecAsn1CoderRelease(coder);
    CFReleaseSafe(issuerNameDigest);
    CFReleaseSafe(serial);
    CFReleaseSafe(issuerPubKeyDigest);

    return der;
}

SecOCSPRequestRef SecOCSPRequestCreate(SecCertificateRef certificate,
    SecCertificateRef issuer) {