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