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