ocsp_vfy.c revision 296341
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 (mdlen < 0) 325 return -1; 326 if ((cid->issuerNameHash->length != mdlen) || 327 (cid->issuerKeyHash->length != mdlen)) 328 return 0; 329 iname = X509_get_subject_name(cert); 330 if (!X509_NAME_digest(iname, dgst, md, NULL)) 331 return -1; 332 if (memcmp(md, cid->issuerNameHash->data, mdlen)) 333 return 0; 334 X509_pubkey_digest(cert, dgst, md, NULL); 335 if (memcmp(md, cid->issuerKeyHash->data, mdlen)) 336 return 0; 337 338 return 1; 339 340 } else { 341 /* We have to match the whole lot */ 342 int i, ret; 343 OCSP_CERTID *tmpid; 344 for (i = 0; i < sk_OCSP_SINGLERESP_num(sresp); i++) { 345 tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId; 346 ret = ocsp_match_issuerid(cert, tmpid, NULL); 347 if (ret <= 0) 348 return ret; 349 } 350 return 1; 351 } 352 353} 354 355static int ocsp_check_delegated(X509 *x, int flags) 356{ 357 X509_check_purpose(x, -1, 0); 358 if ((x->ex_flags & EXFLAG_XKUSAGE) && (x->ex_xkusage & XKU_OCSP_SIGN)) 359 return 1; 360 OCSPerr(OCSP_F_OCSP_CHECK_DELEGATED, OCSP_R_MISSING_OCSPSIGNING_USAGE); 361 return 0; 362} 363 364/* 365 * Verify an OCSP request. This is fortunately much easier than OCSP response 366 * verify. Just find the signers certificate and verify it against a given 367 * trust value. 368 */ 369 370int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, 371 X509_STORE *store, unsigned long flags) 372{ 373 X509 *signer; 374 X509_NAME *nm; 375 GENERAL_NAME *gen; 376 int ret; 377 X509_STORE_CTX ctx; 378 if (!req->optionalSignature) { 379 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_REQUEST_NOT_SIGNED); 380 return 0; 381 } 382 gen = req->tbsRequest->requestorName; 383 if (!gen || gen->type != GEN_DIRNAME) { 384 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, 385 OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE); 386 return 0; 387 } 388 nm = gen->d.directoryName; 389 ret = ocsp_req_find_signer(&signer, req, nm, certs, store, flags); 390 if (ret <= 0) { 391 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, 392 OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND); 393 return 0; 394 } 395 if ((ret == 2) && (flags & OCSP_TRUSTOTHER)) 396 flags |= OCSP_NOVERIFY; 397 if (!(flags & OCSP_NOSIGS)) { 398 EVP_PKEY *skey; 399 skey = X509_get_pubkey(signer); 400 ret = OCSP_REQUEST_verify(req, skey); 401 EVP_PKEY_free(skey); 402 if (ret <= 0) { 403 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_SIGNATURE_FAILURE); 404 return 0; 405 } 406 } 407 if (!(flags & OCSP_NOVERIFY)) { 408 int init_res; 409 if (flags & OCSP_NOCHAIN) 410 init_res = X509_STORE_CTX_init(&ctx, store, signer, NULL); 411 else 412 init_res = X509_STORE_CTX_init(&ctx, store, signer, 413 req->optionalSignature->certs); 414 if (!init_res) { 415 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, ERR_R_X509_LIB); 416 return 0; 417 } 418 419 X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); 420 X509_STORE_CTX_set_trust(&ctx, X509_TRUST_OCSP_REQUEST); 421 ret = X509_verify_cert(&ctx); 422 X509_STORE_CTX_cleanup(&ctx); 423 if (ret <= 0) { 424 ret = X509_STORE_CTX_get_error(&ctx); 425 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, 426 OCSP_R_CERTIFICATE_VERIFY_ERROR); 427 ERR_add_error_data(2, "Verify error:", 428 X509_verify_cert_error_string(ret)); 429 return 0; 430 } 431 } 432 return 1; 433} 434 435static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, 436 X509_NAME *nm, STACK_OF(X509) *certs, 437 X509_STORE *st, unsigned long flags) 438{ 439 X509 *signer; 440 if (!(flags & OCSP_NOINTERN)) { 441 signer = X509_find_by_subject(req->optionalSignature->certs, nm); 442 if (signer) { 443 *psigner = signer; 444 return 1; 445 } 446 } 447 448 signer = X509_find_by_subject(certs, nm); 449 if (signer) { 450 *psigner = signer; 451 return 2; 452 } 453 return 0; 454} 455