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 if (certs != NULL) { 122 untrusted = certs; 123 } else { 124 untrusted = bs->certs; 125 } 126 init_res = X509_STORE_CTX_init(&ctx, st, signer, untrusted); 127 if (!init_res) { 128 ret = -1; 129 OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, ERR_R_X509_LIB); 130 goto end; 131 } 132 133 X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); 134 ret = X509_verify_cert(&ctx); 135 chain = X509_STORE_CTX_get1_chain(&ctx); 136 X509_STORE_CTX_cleanup(&ctx); 137 if (ret <= 0) { 138 i = X509_STORE_CTX_get_error(&ctx); 139 OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, 140 OCSP_R_CERTIFICATE_VERIFY_ERROR); 141 ERR_add_error_data(2, "Verify error:", 142 X509_verify_cert_error_string(i)); 143 goto end; 144 } 145 if (flags & OCSP_NOCHECKS) { 146 ret = 1; 147 goto end; 148 } 149 /* 150 * At this point we have a valid certificate chain need to verify it 151 * against the OCSP issuer criteria. 152 */ 153 ret = ocsp_check_issuer(bs, chain, flags); 154 155 /* If fatal error or valid match then finish */ 156 if (ret != 0) 157 goto end; 158 159 /* 160 * Easy case: explicitly trusted. Get root CA and check for explicit 161 * trust 162 */ 163 if (flags & OCSP_NOEXPLICIT) 164 goto end; 165 166 x = sk_X509_value(chain, sk_X509_num(chain) - 1); 167 if (X509_check_trust(x, NID_OCSP_sign, 0) != X509_TRUST_TRUSTED) { 168 OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_ROOT_CA_NOT_TRUSTED); 169 goto end; 170 } 171 ret = 1; 172 } 173 174 end: 175 if (chain) 176 sk_X509_pop_free(chain, X509_free); 177 if (bs->certs && certs) 178 sk_X509_free(untrusted); 179 return ret; 180} 181 182static int ocsp_find_signer(X509 **psigner, OCSP_BASICRESP *bs, 183 STACK_OF(X509) *certs, X509_STORE *st, 184 unsigned long flags) 185{ 186 X509 *signer; 187 OCSP_RESPID *rid = bs->tbsResponseData->responderId; 188 if ((signer = ocsp_find_signer_sk(certs, rid))) { 189 *psigner = signer; 190 return 2; 191 } 192 if (!(flags & OCSP_NOINTERN) && 193 (signer = ocsp_find_signer_sk(bs->certs, rid))) { 194 *psigner = signer; 195 return 1; 196 } 197 /* Maybe lookup from store if by subject name */ 198 199 *psigner = NULL; 200 return 0; 201} 202 203static X509 *ocsp_find_signer_sk(STACK_OF(X509) *certs, OCSP_RESPID *id) 204{ 205 int i; 206 unsigned char tmphash[SHA_DIGEST_LENGTH], *keyhash; 207 X509 *x; 208 209 /* Easy if lookup by name */ 210 if (id->type == V_OCSP_RESPID_NAME) 211 return X509_find_by_subject(certs, id->value.byName); 212 213 /* Lookup by key hash */ 214 215 /* If key hash isn't SHA1 length then forget it */ 216 if (id->value.byKey->length != SHA_DIGEST_LENGTH) 217 return NULL; 218 keyhash = id->value.byKey->data; 219 /* Calculate hash of each key and compare */ 220 for (i = 0; i < sk_X509_num(certs); i++) { 221 x = sk_X509_value(certs, i); 222 X509_pubkey_digest(x, EVP_sha1(), tmphash, NULL); 223 if (!memcmp(keyhash, tmphash, SHA_DIGEST_LENGTH)) 224 return x; 225 } 226 return NULL; 227} 228 229static int ocsp_check_issuer(OCSP_BASICRESP *bs, STACK_OF(X509) *chain, 230 unsigned long flags) 231{ 232 STACK_OF(OCSP_SINGLERESP) *sresp; 233 X509 *signer, *sca; 234 OCSP_CERTID *caid = NULL; 235 int i; 236 sresp = bs->tbsResponseData->responses; 237 238 if (sk_X509_num(chain) <= 0) { 239 OCSPerr(OCSP_F_OCSP_CHECK_ISSUER, OCSP_R_NO_CERTIFICATES_IN_CHAIN); 240 return -1; 241 } 242 243 /* See if the issuer IDs match. */ 244 i = ocsp_check_ids(sresp, &caid); 245 246 /* If ID mismatch or other error then return */ 247 if (i <= 0) 248 return i; 249 250 signer = sk_X509_value(chain, 0); 251 /* Check to see if OCSP responder CA matches request CA */ 252 if (sk_X509_num(chain) > 1) { 253 sca = sk_X509_value(chain, 1); 254 i = ocsp_match_issuerid(sca, caid, sresp); 255 if (i < 0) 256 return i; 257 if (i) { 258 /* We have a match, if extensions OK then success */ 259 if (ocsp_check_delegated(signer, flags)) 260 return 1; 261 return 0; 262 } 263 } 264 265 /* Otherwise check if OCSP request signed directly by request CA */ 266 return ocsp_match_issuerid(signer, caid, sresp); 267} 268 269/* 270 * Check the issuer certificate IDs for equality. If there is a mismatch with 271 * the same algorithm then there's no point trying to match any certificates 272 * against the issuer. If the issuer IDs all match then we just need to check 273 * equality against one of them. 274 */ 275 276static int ocsp_check_ids(STACK_OF(OCSP_SINGLERESP) *sresp, OCSP_CERTID **ret) 277{ 278 OCSP_CERTID *tmpid, *cid; 279 int i, idcount; 280 281 idcount = sk_OCSP_SINGLERESP_num(sresp); 282 if (idcount <= 0) { 283 OCSPerr(OCSP_F_OCSP_CHECK_IDS, 284 OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA); 285 return -1; 286 } 287 288 cid = sk_OCSP_SINGLERESP_value(sresp, 0)->certId; 289 290 *ret = NULL; 291 292 for (i = 1; i < idcount; i++) { 293 tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId; 294 /* Check to see if IDs match */ 295 if (OCSP_id_issuer_cmp(cid, tmpid)) { 296 /* If algoritm mismatch let caller deal with it */ 297 if (OBJ_cmp(tmpid->hashAlgorithm->algorithm, 298 cid->hashAlgorithm->algorithm)) 299 return 2; 300 /* Else mismatch */ 301 return 0; 302 } 303 } 304 305 /* All IDs match: only need to check one ID */ 306 *ret = cid; 307 return 1; 308} 309 310static int ocsp_match_issuerid(X509 *cert, OCSP_CERTID *cid, 311 STACK_OF(OCSP_SINGLERESP) *sresp) 312{ 313 /* If only one ID to match then do it */ 314 if (cid) { 315 const EVP_MD *dgst; 316 X509_NAME *iname; 317 int mdlen; 318 unsigned char md[EVP_MAX_MD_SIZE]; 319 if (!(dgst = EVP_get_digestbyobj(cid->hashAlgorithm->algorithm))) { 320 OCSPerr(OCSP_F_OCSP_MATCH_ISSUERID, 321 OCSP_R_UNKNOWN_MESSAGE_DIGEST); 322 return -1; 323 } 324 325 mdlen = EVP_MD_size(dgst); 326 if (mdlen < 0) 327 return -1; 328 if ((cid->issuerNameHash->length != mdlen) || 329 (cid->issuerKeyHash->length != mdlen)) 330 return 0; 331 iname = X509_get_subject_name(cert); 332 if (!X509_NAME_digest(iname, dgst, md, NULL)) 333 return -1; 334 if (memcmp(md, cid->issuerNameHash->data, mdlen)) 335 return 0; 336 X509_pubkey_digest(cert, dgst, md, NULL); 337 if (memcmp(md, cid->issuerKeyHash->data, mdlen)) 338 return 0; 339 340 return 1; 341 342 } else { 343 /* We have to match the whole lot */ 344 int i, ret; 345 OCSP_CERTID *tmpid; 346 for (i = 0; i < sk_OCSP_SINGLERESP_num(sresp); i++) { 347 tmpid = sk_OCSP_SINGLERESP_value(sresp, i)->certId; 348 ret = ocsp_match_issuerid(cert, tmpid, NULL); 349 if (ret <= 0) 350 return ret; 351 } 352 return 1; 353 } 354 355} 356 357static int ocsp_check_delegated(X509 *x, int flags) 358{ 359 X509_check_purpose(x, -1, 0); 360 if ((x->ex_flags & EXFLAG_XKUSAGE) && (x->ex_xkusage & XKU_OCSP_SIGN)) 361 return 1; 362 OCSPerr(OCSP_F_OCSP_CHECK_DELEGATED, OCSP_R_MISSING_OCSPSIGNING_USAGE); 363 return 0; 364} 365 366/* 367 * Verify an OCSP request. This is fortunately much easier than OCSP response 368 * verify. Just find the signers certificate and verify it against a given 369 * trust value. 370 */ 371 372int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, 373 X509_STORE *store, unsigned long flags) 374{ 375 X509 *signer; 376 X509_NAME *nm; 377 GENERAL_NAME *gen; 378 int ret; 379 X509_STORE_CTX ctx; 380 if (!req->optionalSignature) { 381 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_REQUEST_NOT_SIGNED); 382 return 0; 383 } 384 gen = req->tbsRequest->requestorName; 385 if (!gen || gen->type != GEN_DIRNAME) { 386 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, 387 OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE); 388 return 0; 389 } 390 nm = gen->d.directoryName; 391 ret = ocsp_req_find_signer(&signer, req, nm, certs, store, flags); 392 if (ret <= 0) { 393 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, 394 OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND); 395 return 0; 396 } 397 if ((ret == 2) && (flags & OCSP_TRUSTOTHER)) 398 flags |= OCSP_NOVERIFY; 399 if (!(flags & OCSP_NOSIGS)) { 400 EVP_PKEY *skey; 401 skey = X509_get_pubkey(signer); 402 ret = OCSP_REQUEST_verify(req, skey); 403 EVP_PKEY_free(skey); 404 if (ret <= 0) { 405 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, OCSP_R_SIGNATURE_FAILURE); 406 return 0; 407 } 408 } 409 if (!(flags & OCSP_NOVERIFY)) { 410 int init_res; 411 if (flags & OCSP_NOCHAIN) 412 init_res = X509_STORE_CTX_init(&ctx, store, signer, NULL); 413 else 414 init_res = X509_STORE_CTX_init(&ctx, store, signer, 415 req->optionalSignature->certs); 416 if (!init_res) { 417 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, ERR_R_X509_LIB); 418 return 0; 419 } 420 421 X509_STORE_CTX_set_purpose(&ctx, X509_PURPOSE_OCSP_HELPER); 422 X509_STORE_CTX_set_trust(&ctx, X509_TRUST_OCSP_REQUEST); 423 ret = X509_verify_cert(&ctx); 424 X509_STORE_CTX_cleanup(&ctx); 425 if (ret <= 0) { 426 ret = X509_STORE_CTX_get_error(&ctx); 427 OCSPerr(OCSP_F_OCSP_REQUEST_VERIFY, 428 OCSP_R_CERTIFICATE_VERIFY_ERROR); 429 ERR_add_error_data(2, "Verify error:", 430 X509_verify_cert_error_string(ret)); 431 return 0; 432 } 433 } 434 return 1; 435} 436 437static int ocsp_req_find_signer(X509 **psigner, OCSP_REQUEST *req, 438 X509_NAME *nm, STACK_OF(X509) *certs, 439 X509_STORE *st, unsigned long flags) 440{ 441 X509 *signer; 442 if (!(flags & OCSP_NOINTERN)) { 443 signer = X509_find_by_subject(req->optionalSignature->certs, nm); 444 if (signer) { 445 *psigner = signer; 446 return 1; 447 } 448 } 449 450 signer = X509_find_by_subject(certs, nm); 451 if (signer) { 452 *psigner = signer; 453 return 2; 454 } 455 return 0; 456} 457