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