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