tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ocspsig.c (19840B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "plarena.h"
      6 
      7 #include "seccomon.h"
      8 #include "secitem.h"
      9 #include "secasn1.h"
     10 #include "secder.h"
     11 #include "cert.h"
     12 #include "secerr.h"
     13 #include "secoid.h"
     14 #include "sechash.h"
     15 #include "keyhi.h"
     16 #include "cryptohi.h"
     17 #include "ocsp.h"
     18 #include "ocspti.h"
     19 #include "ocspi.h"
     20 #include "pk11pub.h"
     21 
     22 extern const SEC_ASN1Template ocsp_ResponderIDByNameTemplate[];
     23 extern const SEC_ASN1Template ocsp_ResponderIDByKeyTemplate[];
     24 extern const SEC_ASN1Template ocsp_OCSPResponseTemplate[];
     25 
     26 ocspCertStatus *
     27 ocsp_CreateCertStatus(PLArenaPool *arena,
     28                      ocspCertStatusType status,
     29                      PRTime revocationTime)
     30 {
     31    ocspCertStatus *cs;
     32 
     33    if (!arena) {
     34        PORT_SetError(SEC_ERROR_INVALID_ARGS);
     35        return NULL;
     36    }
     37 
     38    switch (status) {
     39        case ocspCertStatus_good:
     40        case ocspCertStatus_unknown:
     41        case ocspCertStatus_revoked:
     42            break;
     43        default:
     44            PORT_SetError(SEC_ERROR_INVALID_ARGS);
     45            return NULL;
     46    }
     47 
     48    cs = PORT_ArenaZNew(arena, ocspCertStatus);
     49    if (!cs)
     50        return NULL;
     51    cs->certStatusType = status;
     52    switch (status) {
     53        case ocspCertStatus_good:
     54            cs->certStatusInfo.goodInfo = SECITEM_AllocItem(arena, NULL, 0);
     55            if (!cs->certStatusInfo.goodInfo)
     56                return NULL;
     57            break;
     58        case ocspCertStatus_unknown:
     59            cs->certStatusInfo.unknownInfo = SECITEM_AllocItem(arena, NULL, 0);
     60            if (!cs->certStatusInfo.unknownInfo)
     61                return NULL;
     62            break;
     63        case ocspCertStatus_revoked:
     64            cs->certStatusInfo.revokedInfo =
     65                PORT_ArenaZNew(arena, ocspRevokedInfo);
     66            if (!cs->certStatusInfo.revokedInfo)
     67                return NULL;
     68            cs->certStatusInfo.revokedInfo->revocationReason =
     69                SECITEM_AllocItem(arena, NULL, 0);
     70            if (!cs->certStatusInfo.revokedInfo->revocationReason)
     71                return NULL;
     72            if (DER_TimeToGeneralizedTimeArena(arena,
     73                                               &cs->certStatusInfo.revokedInfo->revocationTime,
     74                                               revocationTime) !=
     75                SECSuccess)
     76                return NULL;
     77            break;
     78        default:
     79            PORT_Assert(PR_FALSE);
     80    }
     81    return cs;
     82 }
     83 
     84 static const SEC_ASN1Template mySEC_EnumeratedTemplate[] = {
     85    { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
     86 };
     87 
     88 static const SEC_ASN1Template mySEC_PointerToEnumeratedTemplate[] = {
     89    { SEC_ASN1_POINTER, 0, mySEC_EnumeratedTemplate }
     90 };
     91 
     92 static const SEC_ASN1Template ocsp_EncodeRevokedInfoTemplate[] = {
     93    { SEC_ASN1_GENERALIZED_TIME,
     94      offsetof(ocspRevokedInfo, revocationTime) },
     95    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
     96          SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
     97      offsetof(ocspRevokedInfo, revocationReason),
     98      mySEC_PointerToEnumeratedTemplate },
     99    { 0 }
    100 };
    101 
    102 static const SEC_ASN1Template ocsp_PointerToEncodeRevokedInfoTemplate[] = {
    103    { SEC_ASN1_POINTER, 0,
    104      ocsp_EncodeRevokedInfoTemplate }
    105 };
    106 
    107 static const SEC_ASN1Template mySEC_NullTemplate[] = {
    108    { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) }
    109 };
    110 
    111 static const SEC_ASN1Template ocsp_CertStatusTemplate[] = {
    112    { SEC_ASN1_CHOICE, offsetof(ocspCertStatus, certStatusType),
    113      0, sizeof(ocspCertStatus) },
    114    { SEC_ASN1_CONTEXT_SPECIFIC | 0,
    115      0, mySEC_NullTemplate, ocspCertStatus_good },
    116    { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
    117          SEC_ASN1_CONTEXT_SPECIFIC | 1,
    118      offsetof(ocspCertStatus, certStatusInfo.revokedInfo),
    119      ocsp_PointerToEncodeRevokedInfoTemplate, ocspCertStatus_revoked },
    120    { SEC_ASN1_CONTEXT_SPECIFIC | 2,
    121      0, mySEC_NullTemplate, ocspCertStatus_unknown },
    122    { 0 }
    123 };
    124 
    125 static const SEC_ASN1Template mySECOID_AlgorithmIDTemplate[] = {
    126    { SEC_ASN1_SEQUENCE,
    127      0, NULL, sizeof(SECAlgorithmID) },
    128    { SEC_ASN1_OBJECT_ID,
    129      offsetof(SECAlgorithmID, algorithm) },
    130    { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
    131      offsetof(SECAlgorithmID, parameters) },
    132    { 0 }
    133 };
    134 
    135 static const SEC_ASN1Template mySEC_AnyTemplate[] = {
    136    { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
    137 };
    138 
    139 static const SEC_ASN1Template mySEC_SequenceOfAnyTemplate[] = {
    140    { SEC_ASN1_SEQUENCE_OF, 0, mySEC_AnyTemplate }
    141 };
    142 
    143 static const SEC_ASN1Template mySEC_PointerToSequenceOfAnyTemplate[] = {
    144    { SEC_ASN1_POINTER, 0, mySEC_SequenceOfAnyTemplate }
    145 };
    146 
    147 static const SEC_ASN1Template mySEC_IntegerTemplate[] = {
    148    { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
    149 };
    150 
    151 static const SEC_ASN1Template mySEC_PointerToIntegerTemplate[] = {
    152    { SEC_ASN1_POINTER, 0, mySEC_IntegerTemplate }
    153 };
    154 
    155 static const SEC_ASN1Template mySEC_GeneralizedTimeTemplate[] = {
    156    { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
    157 };
    158 
    159 static const SEC_ASN1Template mySEC_PointerToGeneralizedTimeTemplate[] = {
    160    { SEC_ASN1_POINTER, 0, mySEC_GeneralizedTimeTemplate }
    161 };
    162 
    163 static const SEC_ASN1Template ocsp_myCertIDTemplate[] = {
    164    { SEC_ASN1_SEQUENCE,
    165      0, NULL, sizeof(CERTOCSPCertID) },
    166    { SEC_ASN1_INLINE,
    167      offsetof(CERTOCSPCertID, hashAlgorithm),
    168      mySECOID_AlgorithmIDTemplate },
    169    { SEC_ASN1_OCTET_STRING,
    170      offsetof(CERTOCSPCertID, issuerNameHash) },
    171    { SEC_ASN1_OCTET_STRING,
    172      offsetof(CERTOCSPCertID, issuerKeyHash) },
    173    { SEC_ASN1_INTEGER,
    174      offsetof(CERTOCSPCertID, serialNumber) },
    175    { 0 }
    176 };
    177 
    178 static const SEC_ASN1Template myCERT_CertExtensionTemplate[] = {
    179    { SEC_ASN1_SEQUENCE,
    180      0, NULL, sizeof(CERTCertExtension) },
    181    { SEC_ASN1_OBJECT_ID,
    182      offsetof(CERTCertExtension, id) },
    183    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
    184      offsetof(CERTCertExtension, critical) },
    185    { SEC_ASN1_OCTET_STRING,
    186      offsetof(CERTCertExtension, value) },
    187    { 0 }
    188 };
    189 
    190 static const SEC_ASN1Template myCERT_SequenceOfCertExtensionTemplate[] = {
    191    { SEC_ASN1_SEQUENCE_OF, 0, myCERT_CertExtensionTemplate }
    192 };
    193 
    194 static const SEC_ASN1Template myCERT_PointerToSequenceOfCertExtensionTemplate[] = {
    195    { SEC_ASN1_POINTER, 0, myCERT_SequenceOfCertExtensionTemplate }
    196 };
    197 
    198 static const SEC_ASN1Template ocsp_mySingleResponseTemplate[] = {
    199    { SEC_ASN1_SEQUENCE,
    200      0, NULL, sizeof(CERTOCSPSingleResponse) },
    201    { SEC_ASN1_POINTER,
    202      offsetof(CERTOCSPSingleResponse, certID),
    203      ocsp_myCertIDTemplate },
    204    { SEC_ASN1_ANY,
    205      offsetof(CERTOCSPSingleResponse, derCertStatus) },
    206    { SEC_ASN1_GENERALIZED_TIME,
    207      offsetof(CERTOCSPSingleResponse, thisUpdate) },
    208    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
    209          SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
    210      offsetof(CERTOCSPSingleResponse, nextUpdate),
    211      mySEC_PointerToGeneralizedTimeTemplate },
    212    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
    213          SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
    214      offsetof(CERTOCSPSingleResponse, singleExtensions),
    215      myCERT_PointerToSequenceOfCertExtensionTemplate },
    216    { 0 }
    217 };
    218 
    219 static const SEC_ASN1Template ocsp_myResponseDataTemplate[] = {
    220    { SEC_ASN1_SEQUENCE,
    221      0, NULL, sizeof(ocspResponseData) },
    222    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | /* XXX DER_DEFAULT */
    223          SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
    224      offsetof(ocspResponseData, version),
    225      mySEC_PointerToIntegerTemplate },
    226    { SEC_ASN1_ANY,
    227      offsetof(ocspResponseData, derResponderID) },
    228    { SEC_ASN1_GENERALIZED_TIME,
    229      offsetof(ocspResponseData, producedAt) },
    230    { SEC_ASN1_SEQUENCE_OF,
    231      offsetof(ocspResponseData, responses),
    232      ocsp_mySingleResponseTemplate },
    233    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
    234          SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
    235      offsetof(ocspResponseData, responseExtensions),
    236      myCERT_PointerToSequenceOfCertExtensionTemplate },
    237    { 0 }
    238 };
    239 
    240 static const SEC_ASN1Template ocsp_EncodeBasicOCSPResponseTemplate[] = {
    241    { SEC_ASN1_SEQUENCE,
    242      0, NULL, sizeof(ocspBasicOCSPResponse) },
    243    { SEC_ASN1_POINTER,
    244      offsetof(ocspBasicOCSPResponse, tbsResponseData),
    245      ocsp_myResponseDataTemplate },
    246    { SEC_ASN1_INLINE,
    247      offsetof(ocspBasicOCSPResponse, responseSignature.signatureAlgorithm),
    248      mySECOID_AlgorithmIDTemplate },
    249    { SEC_ASN1_BIT_STRING,
    250      offsetof(ocspBasicOCSPResponse, responseSignature.signature) },
    251    { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT |
    252          SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0,
    253      offsetof(ocspBasicOCSPResponse, responseSignature.derCerts),
    254      mySEC_PointerToSequenceOfAnyTemplate },
    255    { 0 }
    256 };
    257 
    258 static CERTOCSPSingleResponse *
    259 ocsp_CreateSingleResponse(PLArenaPool *arena,
    260                          CERTOCSPCertID *id, ocspCertStatus *status,
    261                          PRTime thisUpdate, const PRTime *nextUpdate)
    262 {
    263    CERTOCSPSingleResponse *sr;
    264 
    265    if (!arena || !id || !status) {
    266        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    267        return NULL;
    268    }
    269 
    270    sr = PORT_ArenaZNew(arena, CERTOCSPSingleResponse);
    271    if (!sr)
    272        return NULL;
    273    sr->arena = arena;
    274    sr->certID = id;
    275    sr->certStatus = status;
    276    if (DER_TimeToGeneralizedTimeArena(arena, &sr->thisUpdate, thisUpdate) !=
    277        SECSuccess)
    278        return NULL;
    279    sr->nextUpdate = NULL;
    280    if (nextUpdate) {
    281        sr->nextUpdate = SECITEM_AllocItem(arena, NULL, 0);
    282        if (!sr->nextUpdate)
    283            return NULL;
    284        if (DER_TimeToGeneralizedTimeArena(arena, sr->nextUpdate, *nextUpdate) !=
    285            SECSuccess)
    286            return NULL;
    287    }
    288 
    289    sr->singleExtensions = PORT_ArenaNewArray(arena, CERTCertExtension *, 1);
    290    if (!sr->singleExtensions)
    291        return NULL;
    292 
    293    sr->singleExtensions[0] = NULL;
    294 
    295    if (!SEC_ASN1EncodeItem(arena, &sr->derCertStatus,
    296                            status, ocsp_CertStatusTemplate))
    297        return NULL;
    298 
    299    return sr;
    300 }
    301 
    302 CERTOCSPSingleResponse *
    303 CERT_CreateOCSPSingleResponseGood(PLArenaPool *arena,
    304                                  CERTOCSPCertID *id,
    305                                  PRTime thisUpdate,
    306                                  const PRTime *nextUpdate)
    307 {
    308    ocspCertStatus *cs;
    309    if (!arena) {
    310        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    311        return NULL;
    312    }
    313    cs = ocsp_CreateCertStatus(arena, ocspCertStatus_good, 0);
    314    if (!cs)
    315        return NULL;
    316    return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate);
    317 }
    318 
    319 CERTOCSPSingleResponse *
    320 CERT_CreateOCSPSingleResponseUnknown(PLArenaPool *arena,
    321                                     CERTOCSPCertID *id,
    322                                     PRTime thisUpdate,
    323                                     const PRTime *nextUpdate)
    324 {
    325    ocspCertStatus *cs;
    326    if (!arena) {
    327        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    328        return NULL;
    329    }
    330    cs = ocsp_CreateCertStatus(arena, ocspCertStatus_unknown, 0);
    331    if (!cs)
    332        return NULL;
    333    return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate);
    334 }
    335 
    336 CERTOCSPSingleResponse *
    337 CERT_CreateOCSPSingleResponseRevoked(
    338    PLArenaPool *arena,
    339    CERTOCSPCertID *id,
    340    PRTime thisUpdate,
    341    const PRTime *nextUpdate,
    342    PRTime revocationTime,
    343    const CERTCRLEntryReasonCode *revocationReason)
    344 {
    345    ocspCertStatus *cs;
    346    /* revocationReason is not yet supported, so it must be NULL. */
    347    if (!arena || revocationReason) {
    348        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    349        return NULL;
    350    }
    351    cs = ocsp_CreateCertStatus(arena, ocspCertStatus_revoked, revocationTime);
    352    if (!cs)
    353        return NULL;
    354    return ocsp_CreateSingleResponse(arena, id, cs, thisUpdate, nextUpdate);
    355 }
    356 
    357 /* responderCert == 0 means:
    358 * create a response with an invalid signature (for testing purposes) */
    359 SECItem *
    360 CERT_CreateEncodedOCSPSuccessResponse(
    361    PLArenaPool *arena,
    362    CERTCertificate *responderCert,
    363    CERTOCSPResponderIDType responderIDType,
    364    PRTime producedAt,
    365    CERTOCSPSingleResponse **responses,
    366    void *wincx)
    367 {
    368    PLArenaPool *tmpArena;
    369    ocspResponseData *rd = NULL;
    370    ocspResponderID *rid = NULL;
    371    const SEC_ASN1Template *responderIDTemplate = NULL;
    372    ocspBasicOCSPResponse *br = NULL;
    373    ocspResponseBytes *rb = NULL;
    374    CERTOCSPResponse *response = NULL;
    375 
    376    SECOidTag algID;
    377    SECOidData *od = NULL;
    378    SECKEYPrivateKey *privKey = NULL;
    379    SECItem *result = NULL;
    380 
    381    if (!arena || !responses) {
    382        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    383        return NULL;
    384    }
    385    if (responderIDType != ocspResponderID_byName &&
    386        responderIDType != ocspResponderID_byKey) {
    387        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    388        return NULL;
    389    }
    390 
    391    tmpArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    392    if (!tmpArena)
    393        return NULL;
    394 
    395    rd = PORT_ArenaZNew(tmpArena, ocspResponseData);
    396    if (!rd)
    397        goto done;
    398    rid = PORT_ArenaZNew(tmpArena, ocspResponderID);
    399    if (!rid)
    400        goto done;
    401    br = PORT_ArenaZNew(tmpArena, ocspBasicOCSPResponse);
    402    if (!br)
    403        goto done;
    404    rb = PORT_ArenaZNew(tmpArena, ocspResponseBytes);
    405    if (!rb)
    406        goto done;
    407    response = PORT_ArenaZNew(tmpArena, CERTOCSPResponse);
    408    if (!response)
    409        goto done;
    410 
    411    rd->version.data = NULL;
    412    rd->version.len = 0;
    413    rd->responseExtensions = NULL;
    414    rd->responses = responses;
    415    if (DER_TimeToGeneralizedTimeArena(tmpArena, &rd->producedAt, producedAt) !=
    416        SECSuccess)
    417        goto done;
    418 
    419    if (!responderCert) {
    420        /* use invalid signature for testing purposes */
    421        unsigned char dummyChar = 'd';
    422        SECItem dummy;
    423 
    424        dummy.len = 1;
    425        dummy.data = &dummyChar;
    426 
    427        /* it's easier to produdce a keyHash out of nowhere,
    428         * than to produce an encoded subject,
    429         * so for our dummy response we always use byKey
    430         */
    431 
    432        rid->responderIDType = ocspResponderID_byKey;
    433        if (!ocsp_DigestValue(tmpArena, SEC_OID_SHA1, &rid->responderIDValue.keyHash,
    434                              &dummy))
    435            goto done;
    436 
    437        if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid,
    438                                ocsp_ResponderIDByKeyTemplate))
    439            goto done;
    440 
    441        br->tbsResponseData = rd;
    442 
    443        if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData,
    444                                ocsp_myResponseDataTemplate))
    445            goto done;
    446 
    447        br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem *, 1);
    448        if (!br->responseSignature.derCerts)
    449            goto done;
    450        br->responseSignature.derCerts[0] = NULL;
    451 
    452        algID = SEC_GetSignatureAlgorithmOidTag(rsaKey, SEC_OID_SHA1);
    453        if (algID == SEC_OID_UNKNOWN)
    454            goto done;
    455 
    456        /* match the regular signature code, which doesn't use the arena */
    457        if (!SECITEM_AllocItem(NULL, &br->responseSignature.signature, 1))
    458            goto done;
    459        PORT_Memcpy(br->responseSignature.signature.data, &dummyChar, 1);
    460 
    461        /* convert len-in-bytes to len-in-bits */
    462        br->responseSignature.signature.len = br->responseSignature.signature.len << 3;
    463    } else {
    464        rid->responderIDType = responderIDType;
    465        if (responderIDType == ocspResponderID_byName) {
    466            responderIDTemplate = ocsp_ResponderIDByNameTemplate;
    467            if (CERT_CopyName(tmpArena, &rid->responderIDValue.name,
    468                              &responderCert->subject) != SECSuccess)
    469                goto done;
    470        } else {
    471            responderIDTemplate = ocsp_ResponderIDByKeyTemplate;
    472            if (!CERT_GetSubjectPublicKeyDigest(tmpArena, responderCert,
    473                                                SEC_OID_SHA1, &rid->responderIDValue.keyHash))
    474                goto done;
    475        }
    476 
    477        if (!SEC_ASN1EncodeItem(tmpArena, &rd->derResponderID, rid,
    478                                responderIDTemplate))
    479            goto done;
    480 
    481        br->tbsResponseData = rd;
    482 
    483        if (!SEC_ASN1EncodeItem(tmpArena, &br->tbsResponseDataDER, br->tbsResponseData,
    484                                ocsp_myResponseDataTemplate))
    485            goto done;
    486 
    487        br->responseSignature.derCerts = PORT_ArenaNewArray(tmpArena, SECItem *, 1);
    488        if (!br->responseSignature.derCerts)
    489            goto done;
    490        br->responseSignature.derCerts[0] = NULL;
    491 
    492        privKey = PK11_FindKeyByAnyCert(responderCert, wincx);
    493        if (!privKey)
    494            goto done;
    495 
    496        algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, SEC_OID_SHA1);
    497        if (algID == SEC_OID_UNKNOWN)
    498            goto done;
    499 
    500        if (SEC_SignData(&br->responseSignature.signature,
    501                         br->tbsResponseDataDER.data, br->tbsResponseDataDER.len,
    502                         privKey, algID) !=
    503            SECSuccess)
    504            goto done;
    505 
    506        /* convert len-in-bytes to len-in-bits */
    507        br->responseSignature.signature.len = br->responseSignature.signature.len << 3;
    508 
    509        /* br->responseSignature.signature wasn't allocated from arena,
    510         * we must free it when done. */
    511    }
    512 
    513    if (SECOID_SetAlgorithmID(tmpArena, &br->responseSignature.signatureAlgorithm, algID, 0) !=
    514        SECSuccess)
    515        goto done;
    516 
    517    if (!SEC_ASN1EncodeItem(tmpArena, &rb->response, br,
    518                            ocsp_EncodeBasicOCSPResponseTemplate))
    519        goto done;
    520 
    521    rb->responseTypeTag = SEC_OID_PKIX_OCSP_BASIC_RESPONSE;
    522 
    523    od = SECOID_FindOIDByTag(rb->responseTypeTag);
    524    if (!od)
    525        goto done;
    526 
    527    rb->responseType = od->oid;
    528    rb->decodedResponse.basic = br;
    529 
    530    response->arena = tmpArena;
    531    response->responseBytes = rb;
    532    response->statusValue = ocspResponse_successful;
    533 
    534    if (!SEC_ASN1EncodeInteger(tmpArena, &response->responseStatus,
    535                               response->statusValue))
    536        goto done;
    537 
    538    result = SEC_ASN1EncodeItem(arena, NULL, response, ocsp_OCSPResponseTemplate);
    539 
    540 done:
    541    if (privKey)
    542        SECKEY_DestroyPrivateKey(privKey);
    543    if (br && br->responseSignature.signature.data)
    544        SECITEM_FreeItem(&br->responseSignature.signature, PR_FALSE);
    545    PORT_FreeArena(tmpArena, PR_FALSE);
    546 
    547    return result;
    548 }
    549 
    550 static const SEC_ASN1Template ocsp_OCSPErrorResponseTemplate[] = {
    551    { SEC_ASN1_SEQUENCE,
    552      0, NULL, sizeof(CERTOCSPResponse) },
    553    { SEC_ASN1_ENUMERATED,
    554      offsetof(CERTOCSPResponse, responseStatus) },
    555    { 0, 0,
    556      mySEC_NullTemplate },
    557    { 0 }
    558 };
    559 
    560 SECItem *
    561 CERT_CreateEncodedOCSPErrorResponse(PLArenaPool *arena, int error)
    562 {
    563    CERTOCSPResponse response;
    564    SECItem *result = NULL;
    565 
    566    switch (error) {
    567        case SEC_ERROR_OCSP_MALFORMED_REQUEST:
    568            response.statusValue = ocspResponse_malformedRequest;
    569            break;
    570        case SEC_ERROR_OCSP_SERVER_ERROR:
    571            response.statusValue = ocspResponse_internalError;
    572            break;
    573        case SEC_ERROR_OCSP_TRY_SERVER_LATER:
    574            response.statusValue = ocspResponse_tryLater;
    575            break;
    576        case SEC_ERROR_OCSP_REQUEST_NEEDS_SIG:
    577            response.statusValue = ocspResponse_sigRequired;
    578            break;
    579        case SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST:
    580            response.statusValue = ocspResponse_unauthorized;
    581            break;
    582        default:
    583            PORT_SetError(SEC_ERROR_INVALID_ARGS);
    584            return NULL;
    585    }
    586 
    587    if (!SEC_ASN1EncodeInteger(NULL, &response.responseStatus,
    588                               response.statusValue))
    589        return NULL;
    590 
    591    result = SEC_ASN1EncodeItem(arena, NULL, &response,
    592                                ocsp_OCSPErrorResponseTemplate);
    593 
    594    SECITEM_FreeItem(&response.responseStatus, PR_FALSE);
    595 
    596    return result;
    597 }