/* * 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; }