andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: #include "plarena.h" andre@0: andre@0: #include "seccomon.h" andre@0: #include "secitem.h" andre@0: #include "secasn1.h" andre@0: #include "secder.h" andre@0: #include "cert.h" andre@0: #include "secerr.h" andre@0: #include "secoid.h" andre@0: #include "sechash.h" andre@0: #include "keyhi.h" andre@0: #include "cryptohi.h" andre@0: #include "ocsp.h" andre@0: #include "ocspti.h" andre@0: #include "ocspi.h" andre@0: #include "pk11pub.h" andre@0: andre@0: andre@0: extern const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[]; andre@0: extern const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[]; andre@0: extern const SEC_ASN1Template ocsp_OCSPResponseTemplate[]; andre@0: andre@0: ocspCertStatus* andre@0: ocsp_CreateCertStatus(PLArenaPool *arena, andre@0: ocspCertStatusType status, andre@0: PRTime revocationTime) andre@0: { andre@0: ocspCertStatus *cs; andre@0: andre@0: if (!arena) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: switch (status) { andre@0: case ocspCertStatus_good: andre@0: case ocspCertStatus_unknown: andre@0: case ocspCertStatus_revoked: andre@0: break; andre@0: default: andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: cs = PORT_ArenaZNew(arena, ocspCertStatus); andre@0: if (!cs) andre@0: return NULL; andre@0: cs->certStatusType = status; andre@0: switch (status) { andre@0: case ocspCertStatus_good: andre@0: cs->certStatusInfo.goodInfo = SECITEM_AllocItem(arena, NULL, 0); andre@0: if (!cs->certStatusInfo.goodInfo) andre@0: return NULL; andre@0: break; andre@0: case ocspCertStatus_unknown: andre@0: cs->certStatusInfo.unknownInfo = SECITEM_AllocItem(arena, NULL, 0); andre@0: if (!cs->certStatusInfo.unknownInfo) andre@0: return NULL; andre@0: break; andre@0: case ocspCertStatus_revoked: andre@0: cs->certStatusInfo.revokedInfo = andre@0: PORT_ArenaZNew(arena, ocspRevokedInfo); andre@0: if (!cs->certStatusInfo.revokedInfo) andre@0: return NULL; andre@0: cs->certStatusInfo.revokedInfo->revocationReason = andre@0: SECITEM_AllocItem(arena, NULL, 0); andre@0: if (!cs->certStatusInfo.revokedInfo->revocationReason) andre@0: return NULL; andre@0: if (DER_TimeToGeneralizedTimeArena(arena, andre@0: &cs->certStatusInfo.revokedInfo->revocationTime, andre@0: revocationTime) != SECSuccess) andre@0: return NULL; andre@0: break; andre@0: default: andre@0: PORT_Assert(PR_FALSE); andre@0: } andre@0: return cs; andre@0: } andre@0: andre@0: static const SEC_ASN1Template mySEC_EnumeratedTemplate[] = { andre@0: { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_PointerToEnumeratedTemplate[] = { andre@0: { SEC_ASN1_POINTER, 0, mySEC_EnumeratedTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template ocsp_EncodeRevokedInfoTemplate[] = { andre@0: { SEC_ASN1_GENERALIZED_TIME, andre@0: offsetof(ocspRevokedInfo, revocationTime) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC| 0, andre@0: offsetof(ocspRevokedInfo, revocationReason), andre@0: mySEC_PointerToEnumeratedTemplate }, andre@0: { 0 } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template ocsp_PointerToEncodeRevokedInfoTemplate[] = { andre@0: { SEC_ASN1_POINTER, 0, andre@0: ocsp_EncodeRevokedInfoTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_NullTemplate[] = { andre@0: { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template ocsp_CertStatusTemplate[] = { andre@0: { SEC_ASN1_CHOICE, offsetof(ocspCertStatus, certStatusType), andre@0: 0, sizeof(ocspCertStatus) }, andre@0: { SEC_ASN1_CONTEXT_SPECIFIC | 0, andre@0: 0, mySEC_NullTemplate, ocspCertStatus_good }, andre@0: { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | andre@0: SEC_ASN1_CONTEXT_SPECIFIC | 1, andre@0: offsetof(ocspCertStatus, certStatusInfo.revokedInfo), andre@0: ocsp_PointerToEncodeRevokedInfoTemplate, ocspCertStatus_revoked }, andre@0: { SEC_ASN1_CONTEXT_SPECIFIC | 2, andre@0: 0, mySEC_NullTemplate, ocspCertStatus_unknown }, andre@0: { 0 } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySECOID_AlgorithmIDTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(SECAlgorithmID) }, andre@0: { SEC_ASN1_OBJECT_ID, andre@0: offsetof(SECAlgorithmID,algorithm), }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, andre@0: offsetof(SECAlgorithmID,parameters), }, andre@0: { 0, } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_AnyTemplate[] = { andre@0: { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_SequenceOfAnyTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE_OF, 0, mySEC_AnyTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_PointerToSequenceOfAnyTemplate[] = { andre@0: { SEC_ASN1_POINTER, 0, mySEC_SequenceOfAnyTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_IntegerTemplate[] = { andre@0: { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_PointerToIntegerTemplate[] = { andre@0: { SEC_ASN1_POINTER, 0, mySEC_IntegerTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_GeneralizedTimeTemplate[] = { andre@0: { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)} andre@0: }; andre@0: andre@0: static const SEC_ASN1Template mySEC_PointerToGeneralizedTimeTemplate[] = { andre@0: { SEC_ASN1_POINTER, 0, mySEC_GeneralizedTimeTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template ocsp_myCertIDTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTOCSPCertID) }, andre@0: { SEC_ASN1_INLINE, andre@0: offsetof(CERTOCSPCertID, hashAlgorithm), andre@0: mySECOID_AlgorithmIDTemplate }, andre@0: { SEC_ASN1_OCTET_STRING, andre@0: offsetof(CERTOCSPCertID, issuerNameHash) }, andre@0: { SEC_ASN1_OCTET_STRING, andre@0: offsetof(CERTOCSPCertID, issuerKeyHash) }, andre@0: { SEC_ASN1_INTEGER, andre@0: offsetof(CERTOCSPCertID, serialNumber) }, andre@0: { 0 } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template myCERT_CertExtensionTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTCertExtension) }, andre@0: { SEC_ASN1_OBJECT_ID, andre@0: offsetof(CERTCertExtension,id) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */ andre@0: offsetof(CERTCertExtension,critical) }, andre@0: { SEC_ASN1_OCTET_STRING, andre@0: offsetof(CERTCertExtension,value) }, andre@0: { 0, } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template myCERT_SequenceOfCertExtensionTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE_OF, 0, myCERT_CertExtensionTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template myCERT_PointerToSequenceOfCertExtensionTemplate[] = { andre@0: { SEC_ASN1_POINTER, 0, myCERT_SequenceOfCertExtensionTemplate } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template ocsp_mySingleResponseTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTOCSPSingleResponse) }, andre@0: { SEC_ASN1_POINTER, andre@0: offsetof(CERTOCSPSingleResponse, certID), andre@0: ocsp_myCertIDTemplate }, andre@0: { SEC_ASN1_ANY, andre@0: offsetof(CERTOCSPSingleResponse, derCertStatus) }, andre@0: { SEC_ASN1_GENERALIZED_TIME, andre@0: offsetof(CERTOCSPSingleResponse, thisUpdate) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, andre@0: offsetof(CERTOCSPSingleResponse, nextUpdate), andre@0: mySEC_PointerToGeneralizedTimeTemplate }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, andre@0: offsetof(CERTOCSPSingleResponse, singleExtensions), andre@0: myCERT_PointerToSequenceOfCertExtensionTemplate }, andre@0: { 0 } andre@0: }; andre@0: andre@0: static const SEC_ASN1Template ocsp_myResponseDataTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(ocspResponseData) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */ andre@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, andre@0: offsetof(ocspResponseData, version), andre@0: mySEC_PointerToIntegerTemplate }, andre@0: { SEC_ASN1_ANY, andre@0: offsetof(ocspResponseData, derResponderID) }, andre@0: { SEC_ASN1_GENERALIZED_TIME, andre@0: offsetof(ocspResponseData, producedAt) }, andre@0: { SEC_ASN1_SEQUENCE_OF, andre@0: offsetof(ocspResponseData, responses), andre@0: ocsp_mySingleResponseTemplate }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, andre@0: offsetof(ocspResponseData, responseExtensions), andre@0: myCERT_PointerToSequenceOfCertExtensionTemplate }, andre@0: { 0 } andre@0: }; andre@0: andre@0: andre@0: static const SEC_ASN1Template ocsp_EncodeBasicOCSPResponseTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(ocspBasicOCSPResponse) }, andre@0: { SEC_ASN1_POINTER, andre@0: offsetof(ocspBasicOCSPResponse, tbsResponseData), andre@0: ocsp_myResponseDataTemplate }, andre@0: { SEC_ASN1_INLINE, andre@0: offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm), andre@0: mySECOID_AlgorithmIDTemplate }, andre@0: { SEC_ASN1_BIT_STRING, andre@0: offsetof(ocspBasicOCSPResponse, responseSignature.signature) }, andre@0: { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | andre@0: SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, andre@0: offsetof(ocspBasicOCSPResponse, responseSignature.derCerts), andre@0: mySEC_PointerToSequenceOfAnyTemplate }, andre@0: { 0 } andre@0: }; andre@0: andre@0: static CERTOCSPSingleResponse* andre@0: ocsp_CreateSingleResponse(PLArenaPool *arena, andre@0: CERTOCSPCertID *id, ocspCertStatus *status, andre@0: PRTime thisUpdate, const PRTime *nextUpdate) andre@0: { andre@0: CERTOCSPSingleResponse *sr; andre@0: andre@0: if (!arena || !id || !status) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: sr = PORT_ArenaZNew(arena, CERTOCSPSingleResponse); andre@0: if (!sr) andre@0: return NULL; andre@0: sr->arena = arena; andre@0: sr->certID = id; andre@0: sr->certStatus = status; andre@0: if (DER_TimeToGeneralizedTimeArena(arena, &sr->thisUpdate, thisUpdate) andre@0: != SECSuccess) andre@0: return NULL; andre@0: sr->nextUpdate = NULL; andre@0: if (nextUpdate) { andre@0: sr->nextUpdate = SECITEM_AllocItem(arena, NULL, 0); andre@0: if (!sr->nextUpdate) andre@0: return NULL; andre@0: if (DER_TimeToGeneralizedTimeArena(arena, sr->nextUpdate, *nextUpdate) andre@0: != SECSuccess) andre@0: return NULL; andre@0: } andre@0: andre@0: sr->singleExtensions = PORT_ArenaNewArray(arena, CERTCertExtension*, 1); andre@0: if (!sr->singleExtensions) andre@0: return NULL; andre@0: andre@0: sr->singleExtensions[0] = NULL; andre@0: andre@0: if (!SEC_ASN1EncodeItem(arena, &sr->derCertStatus, andre@0: status, ocsp_CertStatusTemplate)) andre@0: return NULL; andre@0: andre@0: return sr; andre@0: } andre@0: andre@0: CERTOCSPSingleResponse* andre@0: CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena, andre@0: CERTOCSPCertID *id, andre@0: PRTime thisUpdate, andre@0: const PRTime *nextUpdate) andre@0: { andre@0: ocspCertStatus * cs; andre@0: if (!arena) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: cs = ocsp_CreateCertStatus(arena, ocspCertStatus_good, 0); andre@0: if (!cs) andre@0: return NULL; andre@0: return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); andre@0: } andre@0: andre@0: CERTOCSPSingleResponse* andre@0: CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena, andre@0: CERTOCSPCertID *id, andre@0: PRTime thisUpdate, andre@0: const PRTime *nextUpdate) andre@0: { andre@0: ocspCertStatus * cs; andre@0: if (!arena) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: cs = ocsp_CreateCertStatus(arena, ocspCertStatus_unknown, 0); andre@0: if (!cs) andre@0: return NULL; andre@0: return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); andre@0: } andre@0: andre@0: CERTOCSPSingleResponse* andre@0: CERT_CreateOCSPSingleResponseRevoked( andre@0: PLArenaPool *arena, andre@0: CERTOCSPCertID *id, andre@0: PRTime thisUpdate, andre@0: const PRTime *nextUpdate, andre@0: PRTime revocationTime, andre@0: const CERTCRLEntryReasonCode* revocationReason) andre@0: { andre@0: ocspCertStatus * cs; andre@0: /* revocationReason is not yet supported, so it must be NULL. */ andre@0: if (!arena || revocationReason) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: cs = ocsp_CreateCertStatus(arena, ocspCertStatus_revoked, revocationTime); andre@0: if (!cs) andre@0: return NULL; andre@0: return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate); andre@0: } andre@0: andre@0: /* responderCert == 0 means: andre@0: * create a response with an invalid signature (for testing purposes) */ andre@0: SECItem* andre@0: CERT_CreateEncodedOCSPSuccessResponse( andre@0: PLArenaPool *arena, andre@0: CERTCertificate *responderCert, andre@0: CERTOCSPResponderIDType responderIDType, andre@0: PRTime producedAt, andre@0: CERTOCSPSingleResponse **responses, andre@0: void *wincx) andre@0: { andre@0: PLArenaPool *tmpArena; andre@0: ocspResponseData *rd = NULL; andre@0: ocspResponderID *rid = NULL; andre@0: const SEC_ASN1Template *responderIDTemplate = NULL; andre@0: ocspBasicOCSPResponse *br = NULL; andre@0: ocspResponseBytes *rb = NULL; andre@0: CERTOCSPResponse *response = NULL; andre@0: andre@0: SECOidTag algID; andre@0: SECOidData *od = NULL; andre@0: SECKEYPrivateKey *privKey = NULL; andre@0: SECItem *result = NULL; andre@0: andre@0: if (!arena || !responses) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: if (responderIDType != ocspResponderID_byName && andre@0: responderIDType != ocspResponderID_byKey) { andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); andre@0: if (!tmpArena) andre@0: return NULL; andre@0: andre@0: rd = PORT_ArenaZNew(tmpArena, ocspResponseData); andre@0: if (!rd) andre@0: goto done; andre@0: rid = PORT_ArenaZNew(tmpArena, ocspResponderID); andre@0: if (!rid) andre@0: goto done; andre@0: br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse); andre@0: if (!br) andre@0: goto done; andre@0: rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes); andre@0: if (!rb) andre@0: goto done; andre@0: response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse); andre@0: if (!response) andre@0: goto done; andre@0: andre@0: rd->version.data=NULL; andre@0: rd->version.len=0; andre@0: rd->responseExtensions = NULL; andre@0: rd->responses = responses; andre@0: if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) andre@0: != SECSuccess) andre@0: goto done; andre@0: andre@0: if (!responderCert) { andre@0: /* use invalid signature for testing purposes */ andre@0: unsigned char dummyChar = 'd'; andre@0: SECItem dummy; andre@0: andre@0: dummy.len = 1; andre@0: dummy.data = &dummyChar; andre@0: andre@0: /* it's easier to produdce a keyHash out of nowhere, andre@0: * than to produce an encoded subject, andre@0: * so for our dummy response we always use byKey andre@0: */ andre@0: andre@0: rid->responderIDType = ocspResponderID_byKey; andre@0: if (!ocsp_DigestValue(tmpArena, SEC_OID_SHA1, &rid->responderIDValue.keyHash, andre@0: &dummy)) andre@0: goto done; andre@0: andre@0: if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, andre@0: ocsp_ResponderIDByKeyTemplate)) andre@0: goto done; andre@0: andre@0: br->tbsResponseData = rd; andre@0: andre@0: if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, andre@0: ocsp_myResponseDataTemplate)) andre@0: goto done; andre@0: andre@0: br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); andre@0: if (!br->responseSignature.derCerts) andre@0: goto done; andre@0: br->responseSignature.derCerts[0] = NULL; andre@0: andre@0: algID = SEC_GetSignatureAlgorithmOidTag(rsaKey, SEC_OID_SHA1); andre@0: if (algID == SEC_OID_UNKNOWN) andre@0: goto done; andre@0: andre@0: /* match the regular signature code, which doesn't use the arena */ andre@0: if (!SECITEM_AllocItem(NULL, &br->responseSignature.signature, 1)) andre@0: goto done; andre@0: PORT_Memcpy(br->responseSignature.signature.data, &dummyChar, 1); andre@0: andre@0: /* convert len-in-bytes to len-in-bits */ andre@0: br->responseSignature.signature.len = br->responseSignature.signature.len << 3; andre@0: } andre@0: else { andre@0: rid->responderIDType = responderIDType; andre@0: if (responderIDType == ocspResponderID_byName) { andre@0: responderIDTemplate = ocsp_ResponderIDByNameTemplate; andre@0: if (CERT_CopyName(tmpArena, &rid->responderIDValue.name, andre@0: &responderCert->subject) != SECSuccess) andre@0: goto done; andre@0: } andre@0: else { andre@0: responderIDTemplate = ocsp_ResponderIDByKeyTemplate; andre@0: if (!CERT_GetSubjectPublicKeyDigest(tmpArena, responderCert, andre@0: SEC_OID_SHA1, &rid->responderIDValue.keyHash)) andre@0: goto done; andre@0: } andre@0: andre@0: if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid, andre@0: responderIDTemplate)) andre@0: goto done; andre@0: andre@0: br->tbsResponseData = rd; andre@0: andre@0: if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData, andre@0: ocsp_myResponseDataTemplate)) andre@0: goto done; andre@0: andre@0: br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem*, 1); andre@0: if (!br->responseSignature.derCerts) andre@0: goto done; andre@0: br->responseSignature.derCerts[0] = NULL; andre@0: andre@0: privKey = PK11_FindKeyByAnyCert(responderCert, wincx); andre@0: if (!privKey) andre@0: goto done; andre@0: andre@0: algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1); andre@0: if (algID == SEC_OID_UNKNOWN) andre@0: goto done; andre@0: andre@0: if (SEC_SignData(&br->responseSignature.signature, andre@0: br->tbsResponseDataDER.data, br->tbsResponseDataDER.len, andre@0: privKey, algID) andre@0: != SECSuccess) andre@0: goto done; andre@0: andre@0: /* convert len-in-bytes to len-in-bits */ andre@0: br->responseSignature.signature.len = br->responseSignature.signature.len << 3; andre@0: andre@0: /* br->responseSignature.signature wasn't allocated from arena, andre@0: * we must free it when done. */ andre@0: } andre@0: andre@0: if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorithm, algID, 0) andre@0: != SECSuccess) andre@0: goto done; andre@0: andre@0: if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br, andre@0: ocsp_EncodeBasicOCSPResponseTemplate)) andre@0: goto done; andre@0: andre@0: rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE; andre@0: andre@0: od = SECOID_FindOIDByTag(rb->responseTypeTag); andre@0: if (!od) andre@0: goto done; andre@0: andre@0: rb->responseType = od->oid; andre@0: rb->decodedResponse.basic = br; andre@0: andre@0: response->arena = tmpArena; andre@0: response->responseBytes = rb; andre@0: response->statusValue = ocspResponse_successful; andre@0: andre@0: if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus, andre@0: response->statusValue)) andre@0: goto done; andre@0: andre@0: result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate); andre@0: andre@0: done: andre@0: if (privKey) andre@0: SECKEY_DestroyPrivateKey(privKey); andre@0: if (br->responseSignature.signature.data) andre@0: SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE); andre@0: PORT_FreeArena(tmpArena, PR_FALSE); andre@0: andre@0: return result; andre@0: } andre@0: andre@0: static const SEC_ASN1Template ocsp_OCSPErrorResponseTemplate[] = { andre@0: { SEC_ASN1_SEQUENCE, andre@0: 0, NULL, sizeof(CERTOCSPResponse) }, andre@0: { SEC_ASN1_ENUMERATED, andre@0: offsetof(CERTOCSPResponse, responseStatus) }, andre@0: { 0, 0, andre@0: mySEC_NullTemplate }, andre@0: { 0 } andre@0: }; andre@0: andre@0: SECItem* andre@0: CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error) andre@0: { andre@0: CERTOCSPResponse response; andre@0: SECItem *result = NULL; andre@0: andre@0: switch (error) { andre@0: case SEC_ERROR_OCSP_MALFORMED_REQUEST: andre@0: response.statusValue = ocspResponse_malformedRequest; andre@0: break; andre@0: case SEC_ERROR_OCSP_SERVER_ERROR: andre@0: response.statusValue = ocspResponse_internalError; andre@0: break; andre@0: case SEC_ERROR_OCSP_TRY_SERVER_LATER: andre@0: response.statusValue = ocspResponse_tryLater; andre@0: break; andre@0: case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG: andre@0: response.statusValue = ocspResponse_sigRequired; andre@0: break; andre@0: case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST: andre@0: response.statusValue = ocspResponse_unauthorized; andre@0: break; andre@0: default: andre@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); andre@0: return NULL; andre@0: } andre@0: andre@0: if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus, andre@0: response.statusValue)) andre@0: return NULL; andre@0: andre@0: result = SEC_ASN1EncodeItem(arena, NULL, &response, andre@0: ocsp_OCSPErrorResponseTemplate); andre@0: andre@0: SECITEM_FreeItem(&response.responseStatus, PR_FALSE); andre@0: andre@0: return result; andre@0: }