1/* $OpenBSD: ocsp_cl.c,v 1.25 2024/03/24 11:30:12 beck Exp $ */ 2/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL 3 * project. */ 4 5/* History: 6 This file was transfered to Richard Levitte from CertCo by Kathy 7 Weinhold in mid-spring 2000 to be included in OpenSSL or released 8 as a patch kit. */ 9 10/* ==================================================================== 11 * Copyright (c) 1998-2000 The OpenSSL Project. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. All advertising materials mentioning features or use of this 26 * software must display the following acknowledgment: 27 * "This product includes software developed by the OpenSSL Project 28 * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" 29 * 30 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 31 * endorse or promote products derived from this software without 32 * prior written permission. For written permission, please contact 33 * openssl-core@openssl.org. 34 * 35 * 5. Products derived from this software may not be called "OpenSSL" 36 * nor may "OpenSSL" appear in their names without prior written 37 * permission of the OpenSSL Project. 38 * 39 * 6. Redistributions of any form whatsoever must retain the following 40 * acknowledgment: 41 * "This product includes software developed by the OpenSSL Project 42 * for use in the OpenSSL Toolkit (http://www.openssl.org/)" 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 45 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 47 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 48 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 51 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 53 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 54 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 55 * OF THE POSSIBILITY OF SUCH DAMAGE. 56 * ==================================================================== 57 * 58 * This product includes cryptographic software written by Eric Young 59 * (eay@cryptsoft.com). This product includes software written by Tim 60 * Hudson (tjh@cryptsoft.com). 61 * 62 */ 63 64#include <stdio.h> 65#include <time.h> 66 67#include <openssl/err.h> 68#include <openssl/ocsp.h> 69#include <openssl/objects.h> 70#include <openssl/pem.h> 71#include <openssl/posix_time.h> 72#include <openssl/x509.h> 73#include <openssl/x509v3.h> 74 75#include "asn1_local.h" 76#include "ocsp_local.h" 77 78/* Utility functions related to sending OCSP requests and extracting 79 * relevant information from the response. 80 */ 81 82/* Add an OCSP_CERTID to an OCSP request. Return new OCSP_ONEREQ 83 * pointer: useful if we want to add extensions. 84 */ 85OCSP_ONEREQ * 86OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid) 87{ 88 OCSP_ONEREQ *one; 89 90 if ((one = OCSP_ONEREQ_new()) == NULL) 91 goto err; 92 if (req != NULL) { 93 if (!sk_OCSP_ONEREQ_push(req->tbsRequest->requestList, one)) 94 goto err; 95 } 96 OCSP_CERTID_free(one->reqCert); 97 one->reqCert = cid; 98 return one; 99 100 err: 101 OCSP_ONEREQ_free(one); 102 return NULL; 103} 104LCRYPTO_ALIAS(OCSP_request_add0_id); 105 106/* Set requestorName from an X509_NAME structure */ 107int 108OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm) 109{ 110 GENERAL_NAME *gen; 111 112 gen = GENERAL_NAME_new(); 113 if (gen == NULL) 114 return 0; 115 if (!X509_NAME_set(&gen->d.directoryName, nm)) { 116 GENERAL_NAME_free(gen); 117 return 0; 118 } 119 gen->type = GEN_DIRNAME; 120 if (req->tbsRequest->requestorName) 121 GENERAL_NAME_free(req->tbsRequest->requestorName); 122 req->tbsRequest->requestorName = gen; 123 return 1; 124} 125LCRYPTO_ALIAS(OCSP_request_set1_name); 126 127/* Add a certificate to an OCSP request */ 128int 129OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert) 130{ 131 OCSP_SIGNATURE *sig; 132 133 if (!req->optionalSignature) 134 req->optionalSignature = OCSP_SIGNATURE_new(); 135 sig = req->optionalSignature; 136 if (!sig) 137 return 0; 138 if (!cert) 139 return 1; 140 if (!sig->certs && !(sig->certs = sk_X509_new_null())) 141 return 0; 142 143 if (!sk_X509_push(sig->certs, cert)) 144 return 0; 145 X509_up_ref(cert); 146 return 1; 147} 148LCRYPTO_ALIAS(OCSP_request_add1_cert); 149 150/* Sign an OCSP request set the requestorName to the subject 151 * name of an optional signers certificate and include one 152 * or more optional certificates in the request. Behaves 153 * like PKCS7_sign(). 154 */ 155int 156OCSP_request_sign(OCSP_REQUEST *req, X509 *signer, EVP_PKEY *key, 157 const EVP_MD *dgst, STACK_OF(X509) *certs, unsigned long flags) 158{ 159 int i; 160 OCSP_SIGNATURE *sig; 161 X509 *x; 162 163 if (!OCSP_request_set1_name(req, X509_get_subject_name(signer))) 164 goto err; 165 166 if (!(req->optionalSignature = sig = OCSP_SIGNATURE_new())) 167 goto err; 168 if (key) { 169 if (!X509_check_private_key(signer, key)) { 170 OCSPerror(OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); 171 goto err; 172 } 173 if (!OCSP_REQUEST_sign(req, key, dgst)) 174 goto err; 175 } 176 177 if (!(flags & OCSP_NOCERTS)) { 178 if (!OCSP_request_add1_cert(req, signer)) 179 goto err; 180 for (i = 0; i < sk_X509_num(certs); i++) { 181 x = sk_X509_value(certs, i); 182 if (!OCSP_request_add1_cert(req, x)) 183 goto err; 184 } 185 } 186 187 return 1; 188 189err: 190 OCSP_SIGNATURE_free(req->optionalSignature); 191 req->optionalSignature = NULL; 192 return 0; 193} 194LCRYPTO_ALIAS(OCSP_request_sign); 195 196/* Get response status */ 197int 198OCSP_response_status(OCSP_RESPONSE *resp) 199{ 200 return ASN1_ENUMERATED_get(resp->responseStatus); 201} 202LCRYPTO_ALIAS(OCSP_response_status); 203 204/* Extract basic response from OCSP_RESPONSE or NULL if 205 * no basic response present. 206 */ 207OCSP_BASICRESP * 208OCSP_response_get1_basic(OCSP_RESPONSE *resp) 209{ 210 OCSP_RESPBYTES *rb; 211 212 rb = resp->responseBytes; 213 if (!rb) { 214 OCSPerror(OCSP_R_NO_RESPONSE_DATA); 215 return NULL; 216 } 217 if (OBJ_obj2nid(rb->responseType) != NID_id_pkix_OCSP_basic) { 218 OCSPerror(OCSP_R_NOT_BASIC_RESPONSE); 219 return NULL; 220 } 221 222 return ASN1_item_unpack(rb->response, &OCSP_BASICRESP_it); 223} 224LCRYPTO_ALIAS(OCSP_response_get1_basic); 225 226/* Return number of OCSP_SINGLERESP responses present in 227 * a basic response. 228 */ 229int 230OCSP_resp_count(OCSP_BASICRESP *bs) 231{ 232 if (!bs) 233 return -1; 234 return sk_OCSP_SINGLERESP_num(bs->tbsResponseData->responses); 235} 236LCRYPTO_ALIAS(OCSP_resp_count); 237 238/* Extract an OCSP_SINGLERESP response with a given index */ 239OCSP_SINGLERESP * 240OCSP_resp_get0(OCSP_BASICRESP *bs, int idx) 241{ 242 if (!bs) 243 return NULL; 244 return sk_OCSP_SINGLERESP_value(bs->tbsResponseData->responses, idx); 245} 246LCRYPTO_ALIAS(OCSP_resp_get0); 247 248const ASN1_GENERALIZEDTIME * 249OCSP_resp_get0_produced_at(const OCSP_BASICRESP *bs) 250{ 251 return bs->tbsResponseData->producedAt; 252} 253LCRYPTO_ALIAS(OCSP_resp_get0_produced_at); 254 255const STACK_OF(X509) * 256OCSP_resp_get0_certs(const OCSP_BASICRESP *bs) 257{ 258 return bs->certs; 259} 260LCRYPTO_ALIAS(OCSP_resp_get0_certs); 261 262int 263OCSP_resp_get0_id(const OCSP_BASICRESP *bs, const ASN1_OCTET_STRING **pid, 264 const X509_NAME **pname) 265{ 266 const OCSP_RESPID *rid = bs->tbsResponseData->responderId; 267 268 if (rid->type == V_OCSP_RESPID_NAME) { 269 *pname = rid->value.byName; 270 *pid = NULL; 271 } else if (rid->type == V_OCSP_RESPID_KEY) { 272 *pid = rid->value.byKey; 273 *pname = NULL; 274 } else { 275 return 0; 276 } 277 278 return 1; 279} 280LCRYPTO_ALIAS(OCSP_resp_get0_id); 281 282const ASN1_OCTET_STRING * 283OCSP_resp_get0_signature(const OCSP_BASICRESP *bs) 284{ 285 return bs->signature; 286} 287LCRYPTO_ALIAS(OCSP_resp_get0_signature); 288 289const X509_ALGOR * 290OCSP_resp_get0_tbs_sigalg(const OCSP_BASICRESP *bs) 291{ 292 return bs->signatureAlgorithm; 293} 294LCRYPTO_ALIAS(OCSP_resp_get0_tbs_sigalg); 295 296const OCSP_RESPDATA * 297OCSP_resp_get0_respdata(const OCSP_BASICRESP *bs) 298{ 299 return bs->tbsResponseData; 300} 301LCRYPTO_ALIAS(OCSP_resp_get0_respdata); 302 303/* Look single response matching a given certificate ID */ 304int 305OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last) 306{ 307 int i; 308 STACK_OF(OCSP_SINGLERESP) *sresp; 309 OCSP_SINGLERESP *single; 310 311 if (!bs) 312 return -1; 313 if (last < 0) 314 last = 0; 315 else 316 last++; 317 sresp = bs->tbsResponseData->responses; 318 for (i = last; i < sk_OCSP_SINGLERESP_num(sresp); i++) { 319 single = sk_OCSP_SINGLERESP_value(sresp, i); 320 if (!OCSP_id_cmp(id, single->certId)) 321 return i; 322 } 323 return -1; 324} 325LCRYPTO_ALIAS(OCSP_resp_find); 326 327/* Extract status information from an OCSP_SINGLERESP structure. 328 * Note: the revtime and reason values are only set if the 329 * certificate status is revoked. Returns numerical value of 330 * status. 331 */ 332int 333OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason, 334 ASN1_GENERALIZEDTIME **revtime, ASN1_GENERALIZEDTIME **thisupd, 335 ASN1_GENERALIZEDTIME **nextupd) 336{ 337 int ret; 338 OCSP_CERTSTATUS *cst; 339 340 if (!single) 341 return -1; 342 cst = single->certStatus; 343 ret = cst->type; 344 if (ret == V_OCSP_CERTSTATUS_REVOKED) { 345 OCSP_REVOKEDINFO *rev = cst->value.revoked; 346 347 if (revtime) 348 *revtime = rev->revocationTime; 349 if (reason) { 350 if (rev->revocationReason) 351 *reason = ASN1_ENUMERATED_get( 352 rev->revocationReason); 353 else 354 *reason = -1; 355 } 356 } 357 if (thisupd) 358 *thisupd = single->thisUpdate; 359 if (nextupd) 360 *nextupd = single->nextUpdate; 361 return ret; 362} 363LCRYPTO_ALIAS(OCSP_single_get0_status); 364 365/* This function combines the previous ones: look up a certificate ID and 366 * if found extract status information. Return 0 is successful. 367 */ 368int 369OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status, 370 int *reason, ASN1_GENERALIZEDTIME **revtime, ASN1_GENERALIZEDTIME **thisupd, 371 ASN1_GENERALIZEDTIME **nextupd) 372{ 373 int i; 374 OCSP_SINGLERESP *single; 375 376 i = OCSP_resp_find(bs, id, -1); 377 /* Maybe check for multiple responses and give an error? */ 378 if (i < 0) 379 return 0; 380 single = OCSP_resp_get0(bs, i); 381 i = OCSP_single_get0_status(single, reason, revtime, thisupd, nextupd); 382 if (status) 383 *status = i; 384 return 1; 385} 386LCRYPTO_ALIAS(OCSP_resp_find_status); 387 388/* Check validity of thisUpdate and nextUpdate fields. It is possible that the request will 389 * take a few seconds to process and/or the time wont be totally accurate. Therefore to avoid 390 * rejecting otherwise valid time we allow the times to be within 'nsec' of the current time. 391 * Also to avoid accepting very old responses without a nextUpdate field an optional maxage 392 * parameter specifies the maximum age the thisUpdate field can be. 393 */ 394int 395OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd, 396 ASN1_GENERALIZEDTIME *nextupd, long nsec, long maxsec) 397{ 398 int64_t posix_next, posix_this, posix_now; 399 struct tm tm_this, tm_next; 400 401 /* Negative values of nsec make no sense */ 402 if (nsec < 0) 403 return 0; 404 405 posix_now = time(NULL); 406 407 /* 408 * Times must explicitly be a GENERALIZEDTIME as per section 409 * 4.2.2.1 of RFC 6960 - It is invalid to accept other times 410 * (such as UTCTIME permitted/required by RFC 5280 for certificates) 411 */ 412 /* Check that thisUpdate is valid. */ 413 if (ASN1_time_parse(thisupd->data, thisupd->length, &tm_this, 414 V_ASN1_GENERALIZEDTIME) != V_ASN1_GENERALIZEDTIME) { 415 OCSPerror(OCSP_R_ERROR_IN_THISUPDATE_FIELD); 416 return 0; 417 } 418 if (!OPENSSL_tm_to_posix(&tm_this, &posix_this)) 419 return 0; 420 /* thisUpdate must not be more than nsec in the future. */ 421 if (posix_this - nsec > posix_now) { 422 OCSPerror(OCSP_R_STATUS_NOT_YET_VALID); 423 return 0; 424 } 425 /* thisUpdate must not be more than maxsec seconds in the past. */ 426 if (maxsec >= 0 && posix_this < posix_now - maxsec) { 427 OCSPerror(OCSP_R_STATUS_TOO_OLD); 428 return 0; 429 } 430 431 /* RFC 6960 section 4.2.2.1 allows for servers to not set nextUpdate */ 432 if (nextupd == NULL) 433 return 1; 434 435 /* Check that nextUpdate is valid. */ 436 if (ASN1_time_parse(nextupd->data, nextupd->length, &tm_next, 437 V_ASN1_GENERALIZEDTIME) != V_ASN1_GENERALIZEDTIME) { 438 OCSPerror(OCSP_R_ERROR_IN_NEXTUPDATE_FIELD); 439 return 0; 440 } 441 if (!OPENSSL_tm_to_posix(&tm_next, &posix_next)) 442 return 0; 443 /* Don't allow nextUpdate to precede thisUpdate. */ 444 if (posix_next < posix_this) { 445 OCSPerror(OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE); 446 return 0; 447 } 448 /* nextUpdate must not be more than nsec seconds in the past. */ 449 if (posix_next + nsec < posix_now) { 450 OCSPerror(OCSP_R_STATUS_EXPIRED); 451 return 0; 452 } 453 454 return 1; 455} 456LCRYPTO_ALIAS(OCSP_check_validity); 457 458const OCSP_CERTID * 459OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *single) 460{ 461 return single->certId; 462} 463LCRYPTO_ALIAS(OCSP_SINGLERESP_get0_id); 464