Coverage Report

Created: 2026-10-28 07:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/openssl/crypto/ocsp/ocsp_cl.c
Line
Count
Source
1
/*
2
 * Copyright 2001-2026 The OpenSSL Project Authors. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License 2.0 (the "License").  You may not use
5
 * this file except in compliance with the License.  You can obtain a copy
6
 * in the file LICENSE in the source distribution or at
7
 * https://www.openssl.org/source/license.html
8
 */
9
10
#include <stdio.h>
11
#include <time.h>
12
#include "internal/cryptlib.h"
13
#include <openssl/asn1.h>
14
#include <openssl/objects.h>
15
#include <openssl/x509.h>
16
#include <openssl/pem.h>
17
#include <openssl/x509v3.h>
18
#include <openssl/ocsp.h>
19
#include <openssl/posix_time.h>
20
#include "ocsp_local.h"
21
22
/*
23
 * Utility functions related to sending OCSP requests and extracting relevant
24
 * information from the response.
25
 */
26
27
/*
28
 * Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ pointer:
29
 * useful if we want to add extensions.
30
 */
31
OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid)
32
0
{
33
0
    OCSP_ONEREQ *one = NULL;
34
35
0
    if ((one = OCSP_ONEREQ_new()) == NULL)
36
0
        return NULL;
37
0
    OCSP_CERTID_free(one->reqCert);
38
0
    one->reqCert = cid;
39
0
    if (req && !sk_OCSP_ONEREQ_push(req->tbsRequest.requestList, one)) {
40
0
        one->reqCert = NULL; /* do not free on error */
41
0
        OCSP_ONEREQ_free(one);
42
0
        return NULL;
43
0
    }
44
0
    return one;
45
0
}
46
47
/* Set requestorName from an X509_NAME structure */
48
int OCSP_request_set1_name(OCSP_REQUEST *req, const X509_NAME *nm)
49
0
{
50
0
    return GENERAL_NAME_set1_X509_NAME(&req->tbsRequest.requestorName, nm);
51
0
}
52
53
/* Add a certificate to an OCSP request */
54
int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert)
55
0
{
56
0
    if (req->optionalSignature == NULL
57
0
        && (req->optionalSignature = OCSP_SIGNATURE_new()) == NULL)
58
0
        return 0;
59
0
    if (cert == NULL)
60
0
        return 1;
61
0
    return ossl_x509_add_cert_new(&req->optionalSignature->certs, cert,
62
0
        X509_ADD_FLAG_UP_REF);
63
0
}
64
65
/*
66
 * Sign an OCSP request set the requestorName to the subject name of an
67
 * optional signers certificate and include one or more optional certificates
68
 * in the request. Behaves like PKCS7_sign().
69
 */
70
int OCSP_request_sign(OCSP_REQUEST *req,
71
    X509 *signer,
72
    EVP_PKEY *key,
73
    const EVP_MD *dgst,
74
    const STACK_OF(X509) *certs, unsigned long flags)
75
0
{
76
0
    OSSL_LIB_CTX *libctx;
77
0
    const char *propq;
78
79
0
    if (!OCSP_request_set1_name(req, X509_get_subject_name(signer)))
80
0
        goto err;
81
82
0
    if ((req->optionalSignature = OCSP_SIGNATURE_new()) == NULL)
83
0
        goto err;
84
0
    if (key != NULL) {
85
0
        if (!X509_check_private_key(signer, key)) {
86
0
            ERR_raise(ERR_LIB_OCSP,
87
0
                OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE);
88
0
            goto err;
89
0
        }
90
0
        ossl_x509_get0_libctx(signer, &libctx, &propq);
91
0
        if (!OCSP_REQUEST_sign(req, key, dgst, libctx, propq))
92
0
            goto err;
93
0
    }
94
95
0
    if ((flags & OCSP_NOCERTS) == 0) {
96
0
        if (!OCSP_request_add1_cert(req, signer)
97
0
            || !X509_add_certs(req->optionalSignature->certs, certs,
98
0
                X509_ADD_FLAG_UP_REF))
99
0
            goto err;
100
0
    }
101
102
0
    return 1;
103
0
err:
104
0
    OCSP_SIGNATURE_free(req->optionalSignature);
105
0
    req->optionalSignature = NULL;
106
0
    return 0;
107
0
}
108
109
/* Get response status */
110
int OCSP_response_status(OCSP_RESPONSE *resp)
111
0
{
112
0
    return ASN1_ENUMERATED_get(resp->responseStatus);
113
0
}
114
115
/*
116
 * Extract basic response from OCSP_RESPONSE or NULL if no basic response
117
 * present.
118
 */
119
OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp)
120
0
{
121
0
    OCSP_RESPBYTES *rb = resp->responseBytes;
122
123
0
    if (rb == NULL) {
124
0
        ERR_raise(ERR_LIB_OCSP, OCSP_R_NO_RESPONSE_DATA);
125
0
        return NULL;
126
0
    }
127
0
    if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) {
128
0
        ERR_raise(ERR_LIB_OCSP, OCSP_R_NOT_BASIC_RESPONSE);
129
0
        return NULL;
130
0
    }
131
132
0
    return ASN1_item_unpack(rb->response, ASN1_ITEM_rptr(OCSP_BASICRESP));
133
0
}
134
135
const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *bs)
136
0
{
137
0
    return bs->signature;
138
0
}
139
140
const X509_ALGOR *OCSP_resp_get0_tbs_sigalg(const OCSP_BASICRESP *bs)
141
0
{
142
0
    return &bs->signatureAlgorithm;
143
0
}
144
145
const OCSP_RESPDATA *OCSP_resp_get0_respdata(const OCSP_BASICRESP *bs)
146
0
{
147
0
    return &bs->tbsResponseData;
148
0
}
149
150
/* Return number of OCSP_SINGLERESP responses present in a basic response */
151
152
int OCSP_resp_count(OCSP_BASICRESP *bs)
153
0
{
154
0
    if (bs == NULL)
155
0
        return -1;
156
0
    return sk_OCSP_SINGLERESP_num(bs->tbsResponseData.responses);
157
0
}
158
159
/* Extract an OCSP_SINGLERESP response with a given index */
160
OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx)
161
0
{
162
0
    if (bs == NULL)
163
0
        return NULL;
164
0
    return sk_OCSP_SINGLERESP_value(bs->tbsResponseData.responses, idx);
165
0
}
166
167
const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at(const OCSP_BASICRESP *bs)
168
0
{
169
0
    return bs->tbsResponseData.producedAt;
170
0
}
171
172
const STACK_OF(X509) *OCSP_resp_get0_certs(const OCSP_BASICRESP *bs)
173
0
{
174
0
    return bs->certs;
175
0
}
176
177
int OCSP_resp_get0_id(const OCSP_BASICRESP *bs,
178
    const ASN1_OCTET_STRING **pid,
179
    const X509_NAME **pname)
180
0
{
181
0
    const OCSP_RESPID *rid = &bs->tbsResponseData.responderId;
182
183
0
    if (rid->type == V_OCSP_RESPID_NAME) {
184
0
        *pname = rid->value.byName;
185
0
        *pid = NULL;
186
0
    } else if (rid->type == V_OCSP_RESPID_KEY) {
187
0
        *pid = rid->value.byKey;
188
0
        *pname = NULL;
189
0
    } else {
190
0
        return 0;
191
0
    }
192
0
    return 1;
193
0
}
194
195
int OCSP_resp_get1_id(const OCSP_BASICRESP *bs,
196
    ASN1_OCTET_STRING **pid,
197
    X509_NAME **pname)
198
0
{
199
0
    const OCSP_RESPID *rid = &bs->tbsResponseData.responderId;
200
201
0
    if (rid->type == V_OCSP_RESPID_NAME) {
202
0
        *pname = X509_NAME_dup(rid->value.byName);
203
0
        *pid = NULL;
204
0
    } else if (rid->type == V_OCSP_RESPID_KEY) {
205
0
        *pid = ASN1_OCTET_STRING_dup(rid->value.byKey);
206
0
        *pname = NULL;
207
0
    } else {
208
0
        return 0;
209
0
    }
210
0
    if (*pname == NULL && *pid == NULL)
211
0
        return 0;
212
0
    return 1;
213
0
}
214
215
/* Look single response matching a given certificate ID */
216
int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last)
217
0
{
218
0
    int i;
219
0
    STACK_OF(OCSP_SINGLERESP) *sresp;
220
0
    OCSP_SINGLERESP *single;
221
222
0
    if (bs == NULL)
223
0
        return -1;
224
0
    if (last < 0)
225
0
        last = 0;
226
0
    else
227
0
        last++;
228
0
    sresp = bs->tbsResponseData.responses;
229
0
    for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++) {
230
0
        single = sk_OCSP_SINGLERESP_value(sresp, i);
231
0
        if (!OCSP_id_cmp(id, single->certId))
232
0
            return i;
233
0
    }
234
0
    return -1;
235
0
}
236
237
/*
238
 * Extract status information from an OCSP_SINGLERESP structure. Note: the
239
 * revtime and reason values are only set if the certificate status is
240
 * revoked. Returns numerical value of status.
241
 */
242
int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
243
    ASN1_GENERALIZEDTIME **revtime,
244
    ASN1_GENERALIZEDTIME **thisupd,
245
    ASN1_GENERALIZEDTIME **nextupd)
246
0
{
247
0
    int ret;
248
0
    OCSP_CERTSTATUS *cst;
249
250
0
    if (single == NULL)
251
0
        return -1;
252
0
    cst = single->certStatus;
253
0
    ret = cst->type;
254
0
    if (ret == V_OCSP_CERTSTATUS_REVOKED) {
255
0
        OCSP_REVOKEDINFO *rev = cst->value.revoked;
256
257
0
        if (revtime)
258
0
            *revtime = rev->revocationTime;
259
0
        if (reason) {
260
0
            if (rev->revocationReason)
261
0
                *reason = ASN1_ENUMERATED_get(rev->revocationReason);
262
0
            else
263
0
                *reason = -1;
264
0
        }
265
0
    }
266
0
    if (thisupd != NULL)
267
0
        *thisupd = single->thisUpdate;
268
0
    if (nextupd != NULL)
269
0
        *nextupd = single->nextUpdate;
270
0
    return ret;
271
0
}
272
273
/*
274
 * This function combines the previous ones: look up a certificate ID and if
275
 * found extract status information. Return 0 is successful.
276
 */
277
int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
278
    int *reason,
279
    ASN1_GENERALIZEDTIME **revtime,
280
    ASN1_GENERALIZEDTIME **thisupd,
281
    ASN1_GENERALIZEDTIME **nextupd)
282
0
{
283
0
    int i = OCSP_resp_find(bs, id, -1);
284
0
    OCSP_SINGLERESP *single;
285
286
    /* Maybe check for multiple responses and give an error? */
287
0
    if (i < 0)
288
0
        return 0;
289
0
    single = OCSP_resp_get0(bs, i);
290
0
    i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd);
291
0
    if (status != NULL)
292
0
        *status = i;
293
0
    return 1;
294
0
}
295
296
static int gentime_to_posix(ASN1_GENERALIZEDTIME *time, int64_t *out_time)
297
0
{
298
0
    struct tm ctm;
299
300
0
    if (!ASN1_GENERALIZEDTIME_check(time))
301
0
        return 0;
302
0
    if (!ASN1_TIME_to_tm(time, &ctm))
303
0
        return 0;
304
0
    if (!OPENSSL_tm_to_posix(&ctm, out_time))
305
0
        return 0;
306
307
0
    return 1;
308
0
}
309
310
/*
311
 * Check validity of thisUpdate and nextUpdate fields. It is possible that
312
 * the request will take a few seconds to process and/or the time won't be
313
 * totally accurate. Therefore to avoid rejecting otherwise valid time we
314
 * allow the times to be within 'nsec' of the current time. Also to avoid
315
 * accepting very old responses without a nextUpdate field an optional maxage
316
 * parameter specifies the maximum age the thisUpdate field can be.
317
 */
318
int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd,
319
    ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec)
320
0
{
321
0
    int64_t t_now, this_time, next_time;
322
0
    int ret = 0;
323
324
0
    if (nsec < 0)
325
0
        nsec = 0;
326
327
0
    t_now = (int64_t)time(NULL);
328
    /* Check thisUpdate is valid */
329
0
    if (!gentime_to_posix(thisupd, &this_time)) {
330
0
        ERR_raise(ERR_LIB_OCSP, OCSP_R_ERROR_IN_THISUPDATE_FIELD);
331
0
        goto err;
332
0
    }
333
    /* Check if thisUpdate is more than nsec in the future */
334
0
    if (this_time > t_now + nsec) {
335
0
        ERR_raise(ERR_LIB_OCSP, OCSP_R_STATUS_NOT_YET_VALID);
336
0
        goto err;
337
0
    }
338
    /*
339
     * If maxsec specified check thisUpdate is not more than maxsec in
340
     * the past
341
     */
342
0
    if (maxsec >= 0 && this_time < t_now - maxsec) {
343
0
        ERR_raise(ERR_LIB_OCSP, OCSP_R_STATUS_TOO_OLD);
344
0
        goto err;
345
0
    }
346
0
    if (nextupd != NULL) {
347
        /* Check nextUpdate is valid */
348
0
        if (!gentime_to_posix(nextupd, &next_time)) {
349
0
            ERR_raise(ERR_LIB_OCSP, OCSP_R_ERROR_IN_NEXTUPDATE_FIELD);
350
0
            goto err;
351
0
        }
352
        /* Check nextUpdate is not more than nsec in the past */
353
0
        if (next_time < t_now - nsec) {
354
0
            ERR_raise(ERR_LIB_OCSP, OCSP_R_STATUS_EXPIRED);
355
0
            goto err;
356
0
        }
357
        /* Also don't allow nextUpdate to precede thisUpdate */
358
0
        if (next_time < this_time) {
359
0
            ERR_raise(ERR_LIB_OCSP, OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE);
360
0
            goto err;
361
0
        }
362
0
    }
363
364
0
    ret = 1;
365
366
0
err:
367
0
    return ret;
368
0
}
369
370
const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *single)
371
0
{
372
0
    return single->certId;
373
0
}