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