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