ocsp_vfy.c revision 1.23
1/* $OpenBSD: ocsp_vfy.c,v 1.23 2023/07/08 10:44:00 beck Exp $ */ 2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL 3 * project 2000. 4 */ 5/* ==================================================================== 6 * Copyright (c) 2000-2004 The OpenSSL Project. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in 17 * the documentation and/or other materials provided with the 18 * distribution. 19 * 20 * 3. All advertising materials mentioning features or use of this 21 * software must display the following acknowledgment: 22 * "This product includes software developed by the OpenSSL Project 23 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" 24 * 25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to 26 * endorse or promote products derived from this software without 27 * prior written permission. For written permission, please contact 28 * licensing@OpenSSL.org. 29 * 30 * 5. Products derived from this software may not be called "OpenSSL" 31 * nor may "OpenSSL" appear in their names without prior written 32 * permission of the OpenSSL Project. 33 * 34 * 6. Redistributions of any form whatsoever must retain the following 35 * acknowledgment: 36 * "This product includes software developed by the OpenSSL Project 37 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" 38 * 39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY 40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR 43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 50 * OF THE POSSIBILITY OF SUCH DAMAGE. 51 * ==================================================================== 52 * 53 * This product includes cryptographic software written by Eric Young 54 * (eay@cryptsoft.com). This product includes software written by Tim 55 * Hudson (tjh@cryptsoft.com). 56 * 57 */ 58 59#include <openssl/ocsp.h> 60#include <openssl/err.h> 61#include <string.h> 62 63#include "ocsp_local.h" 64#include "x509_local.h" 65 66static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, 67 STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags); 68static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id); 69static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, 70 unsigned long flags); 71static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret); 72static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid, 73 STACK_OF(OCSP_SINGLERESP) *sresp); 74static int ocsp_check_delegated(X509 *x, int flags); 75static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, 76 X509_NAME *nm, STACK_OF(X509) *certs, X509_STORE *st, 77 unsigned long flags); 78 79/* Verify a basic response message */ 80int 81OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, X509_STORE *st, 82 unsigned long flags) 83{ 84 X509 *signer, *x; 85 STACK_OF(X509) *chain = NULL; 86 STACK_OF(X509) *untrusted = NULL; 87 X509_STORE_CTX ctx; 88 int i, ret = 0; 89 90 ret = ocsp_find_signer(&signer, bs, certs, st, flags); 91 if (!ret) { 92 OCSPerror(OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND); 93 goto end; 94 } 95 if ((ret == 2) && (flags & OCSP_TRUSTOTHER)) 96 flags |= OCSP_NOVERIFY; 97 if (!(flags & OCSP_NOSIGS)) { 98 EVP_PKEY *skey; 99 100 skey = X509_get0_pubkey(signer); 101 if (skey) { 102 ret = OCSP_BASICRESP_verify(bs, skey, 0); 103 } 104 if (!skey || ret <= 0) { 105 OCSPerror(OCSP_R_SIGNATURE_FAILURE); 106 goto end; 107 } 108 } 109 if (!(flags & OCSP_NOVERIFY)) { 110 int init_res; 111 112 if (flags & OCSP_NOCHAIN) { 113 untrusted = NULL; 114 } else if (bs->certs && certs) { 115 untrusted = sk_X509_dup(bs->certs); 116 for (i = 0; i < sk_X509_num(certs); i++) { 117 if (!sk_X509_push(untrusted, 118 sk_X509_value(certs, i))) { 119 OCSPerror(ERR_R_MALLOC_FAILURE); 120 goto end; 121 } 122 } 123 } else if (certs != NULL) { 124 untrusted = certs; 125 } else { 126 untrusted = bs->certs; 127 } 128 init_res = X509_STORE_CTX_init(&ctx, st, signer, untrusted); 129 if (!init_res) { 130 ret = -1; 131 OCSPerror(ERR_R_X509_LIB); 132 goto end; 133 } 134 135 if (X509_STORE_CTX_set_purpose(&ctx, 136 X509_PURPOSE_OCSP_HELPER) == 0) { 137 X509_STORE_CTX_cleanup(&ctx); 138 ret = -1; 139 goto end; 140 } 141 ret = X509_verify_cert(&ctx); 142 chain = X509_STORE_CTX_get1_chain(&ctx); 143 X509_STORE_CTX_cleanup(&ctx); 144 if (ret <= 0) { 145 i = X509_STORE_CTX_get_error(&ctx); 146 OCSPerror(OCSP_R_CERTIFICATE_VERIFY_ERROR); 147 ERR_asprintf_error_data("Verify error:%s", 148 X509_verify_cert_error_string(i)); 149 goto end; 150 } 151 if (flags & OCSP_NOCHECKS) { 152 ret = 1; 153 goto end; 154 } 155 /* At this point we have a valid certificate chain 156 * need to verify it against the OCSP issuer criteria. 157 */ 158 ret = ocsp_check_issuer(bs, chain, flags); 159 160 /* If fatal error or valid match then finish */ 161 if (ret != 0) 162 goto end; 163 164 /* Easy case: explicitly trusted. Get root CA and 165 * check for explicit trust 166 */ 167 if (flags & OCSP_NOEXPLICIT) 168 goto end; 169 170 x = sk_X509_value(chain, sk_X509_num(chain) - 1); 171 if (X509_check_trust(x, NID_OCSP_sign, 0) != 172 X509_TRUST_TRUSTED) { 173 OCSPerror(OCSP_R_ROOT_CA_NOT_TRUSTED); 174 goto end; 175 } 176 ret = 1; 177 } 178 179end: 180 if (chain) 181 sk_X509_pop_free(chain, X509_free); 182 if (bs->certs && certs) 183 sk_X509_free(untrusted); 184 return ret; 185} 186LCRYPTO_ALIAS(OCSP_basic_verify); 187 188int 189OCSP_resp_get0_signer(OCSP_BASICRESP *bs, X509 **signer, 190 STACK_OF(X509) *extra_certs) 191{ 192 return ocsp_find_signer(signer, bs, extra_certs, NULL, 0) > 0; 193} 194LCRYPTO_ALIAS(OCSP_resp_get0_signer); 195 196static int 197ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, STACK_OF(X509) *certs, 198 X509_STORE *st, unsigned long flags) 199{ 200 X509 *signer; 201 OCSP_RESPID *rid = bs->tbsResponseData->responderId; 202 203 if ((signer = ocsp_find_signer_sk(certs, rid))) { 204 *psigner = signer; 205 return 2; 206 } 207 if (!(flags & OCSP_NOINTERN) && 208 (signer = ocsp_find_signer_sk(bs->certs, rid))) { 209 *psigner = signer; 210 return 1; 211 } 212 /* Maybe lookup from store if by subject name */ 213 214 *psigner = NULL; 215 return 0; 216} 217 218static X509 * 219ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id) 220{ 221 int i; 222 unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash; 223 X509 *x; 224 225 /* Easy if lookup by name */ 226 if (id->type == V_OCSP_RESPID_NAME) 227 return X509_find_by_subject(certs, id->value.byName); 228 229 /* Lookup by key hash */ 230 231 /* If key hash isn't SHA1 length then forget it */ 232 if (id->value.byKey->length != SHA_DIGEST_LENGTH) 233 return NULL; 234 keyhash = id->value.byKey->data; 235 /* Calculate hash of each key and compare */ 236 for (i = 0; i < sk_X509_num(certs); i++) { 237 x = sk_X509_value(certs, i); 238 X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL); 239 if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH)) 240 return x; 241 } 242 return NULL; 243} 244 245static int 246ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, 247 unsigned long flags) 248{ 249 STACK_OF(OCSP_SINGLERESP) *sresp; 250 X509 *signer, *sca; 251 OCSP_CERTID *caid = NULL; 252 int i; 253 254 sresp = bs->tbsResponseData->responses; 255 256 if (sk_X509_num(chain) <= 0) { 257 OCSPerror(OCSP_R_NO_CERTIFICATES_IN_CHAIN); 258 return -1; 259 } 260 261 /* See if the issuer IDs match. */ 262 i = ocsp_check_ids(sresp, &caid); 263 264 /* If ID mismatch or other error then return */ 265 if (i <= 0) 266 return i; 267 268 signer = sk_X509_value(chain, 0); 269 /* Check to see if OCSP responder CA matches request CA */ 270 if (sk_X509_num(chain) > 1) { 271 sca = sk_X509_value(chain, 1); 272 i = ocsp_match_issuerid(sca, caid, sresp); 273 if (i < 0) 274 return i; 275 if (i) { 276 /* We have a match, if extensions OK then success */ 277 if (ocsp_check_delegated(signer, flags)) 278 return 1; 279 return 0; 280 } 281 } 282 283 /* Otherwise check if OCSP request signed directly by request CA */ 284 return ocsp_match_issuerid(signer, caid, sresp); 285} 286 287/* Check the issuer certificate IDs for equality. If there is a mismatch with the same 288 * algorithm then there's no point trying to match any certificates against the issuer. 289 * If the issuer IDs all match then we just need to check equality against one of them. 290 */ 291static int 292ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret) 293{ 294 OCSP_CERTID *tmpid, *cid; 295 int i, idcount; 296 297 idcount = sk_OCSP_SINGLERESP_num(sresp); 298 if (idcount <= 0) { 299 OCSPerror(OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA); 300 return -1; 301 } 302 303 cid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId; 304 305 *ret = NULL; 306 307 for (i = 1; i < idcount; i++) { 308 tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId; 309 /* Check to see if IDs match */ 310 if (OCSP_id_issuer_cmp(cid, tmpid)) { 311 return 0; 312 } 313 } 314 315 /* All IDs match: only need to check one ID */ 316 *ret = cid; 317 return 1; 318} 319 320static int 321ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid, 322 STACK_OF(OCSP_SINGLERESP) *sresp) 323{ 324 /* If only one ID to match then do it */ 325 if (cid) { 326 const EVP_MD *dgst; 327 X509_NAME *iname; 328 int mdlen; 329 unsigned char md[EVP_MAX_MD_SIZE]; 330 331 if (!(dgst = 332 EVP_get_digestbyobj(cid->hashAlgorithm->algorithm))) { 333 OCSPerror(OCSP_R_UNKNOWN_MESSAGE_DIGEST); 334 return -1; 335 } 336 337 mdlen = EVP_MD_size(dgst); 338 if (mdlen < 0) 339 return -1; 340 if (cid->issuerNameHash->length != mdlen || 341 cid->issuerKeyHash->length != mdlen) 342 return 0; 343 iname = X509_get_subject_name(cert); 344 if (!X509_NAME_digest(iname, dgst, md, NULL)) 345 return -1; 346 if (memcmp(md, cid->issuerNameHash->data, mdlen)) 347 return 0; 348 X509_pubkey_digest(cert, dgst, md, NULL); 349 if (memcmp(md, cid->issuerKeyHash->data, mdlen)) 350 return 0; 351 352 return 1; 353 } else { 354 /* We have to match the whole lot */ 355 int i, ret; 356 OCSP_CERTID *tmpid; 357 358 for (i = 0; i < sk_OCSP_SINGLERESP_num(sresp); i++) { 359 tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId; 360 ret = ocsp_match_issuerid(cert, tmpid, NULL); 361 if (ret <= 0) 362 return ret; 363 } 364 return 1; 365 } 366} 367 368static int 369ocsp_check_delegated(X509 *x, int flags) 370{ 371 X509_check_purpose(x, -1, 0); 372 if ((x->ex_flags & EXFLAG_XKUSAGE) && (x->ex_xkusage & XKU_OCSP_SIGN)) 373 return 1; 374 OCSPerror(OCSP_R_MISSING_OCSPSIGNING_USAGE); 375 return 0; 376} 377 378/* Verify an OCSP request. This is fortunately much easier than OCSP 379 * response verify. Just find the signers certificate and verify it 380 * against a given trust value. 381 */ 382int 383OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, X509_STORE *store, 384 unsigned long flags) 385{ 386 X509 *signer; 387 X509_NAME *nm; 388 GENERAL_NAME *gen; 389 int ret; 390 X509_STORE_CTX ctx; 391 392 if (!req->optionalSignature) { 393 OCSPerror(OCSP_R_REQUEST_NOT_SIGNED); 394 return 0; 395 } 396 gen = req->tbsRequest->requestorName; 397 if (!gen || gen->type != GEN_DIRNAME) { 398 OCSPerror(OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE); 399 return 0; 400 } 401 nm = gen->d.directoryName; 402 ret = ocsp_req_find_signer(&signer, req, nm, certs, store, flags); 403 if (ret <= 0) { 404 OCSPerror(OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND); 405 return 0; 406 } 407 if ((ret == 2) && (flags & OCSP_TRUSTOTHER)) 408 flags |= OCSP_NOVERIFY; 409 if (!(flags & OCSP_NOSIGS)) { 410 EVP_PKEY *skey; 411 412 if ((skey = X509_get0_pubkey(signer)) == NULL) 413 return 0; 414 ret = OCSP_REQUEST_verify(req, skey); 415 if (ret <= 0) { 416 OCSPerror(OCSP_R_SIGNATURE_FAILURE); 417 return 0; 418 } 419 } 420 if (!(flags & OCSP_NOVERIFY)) { 421 int init_res; 422 423 if (flags & OCSP_NOCHAIN) 424 init_res = X509_STORE_CTX_init(&ctx, store, signer, 425 NULL); 426 else 427 init_res = X509_STORE_CTX_init(&ctx, store, signer, 428 req->optionalSignature->certs); 429 if (!init_res) { 430 OCSPerror(ERR_R_X509_LIB); 431 return 0; 432 } 433 434 if (X509_STORE_CTX_set_purpose(&ctx, 435 X509_PURPOSE_OCSP_HELPER) == 0 || 436 X509_STORE_CTX_set_trust(&ctx, 437 X509_TRUST_OCSP_REQUEST) == 0) { 438 X509_STORE_CTX_cleanup(&ctx); 439 return 0; 440 } 441 ret = X509_verify_cert(&ctx); 442 X509_STORE_CTX_cleanup(&ctx); 443 if (ret <= 0) { 444 ret = X509_STORE_CTX_get_error(&ctx); 445 OCSPerror(OCSP_R_CERTIFICATE_VERIFY_ERROR); 446 ERR_asprintf_error_data("Verify error:%s", 447 X509_verify_cert_error_string(ret)); 448 return 0; 449 } 450 } 451 return 1; 452} 453LCRYPTO_ALIAS(OCSP_request_verify); 454 455static int 456ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, X509_NAME *nm, 457 STACK_OF(X509) *certs, X509_STORE *st, unsigned long flags) 458{ 459 X509 *signer; 460 461 if (!(flags & OCSP_NOINTERN)) { 462 signer = X509_find_by_subject(req->optionalSignature->certs, nm); 463 if (signer) { 464 *psigner = signer; 465 return 1; 466 } 467 } 468 469 signer = X509_find_by_subject(certs, nm); 470 if (signer) { 471 *psigner = signer; 472 return 2; 473 } 474 return 0; 475} 476