Пример #1
0
/*
 * 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;
}
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;
}