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