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