159191Skris/* x509_trs.c */
2194206Ssimon/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
359191Skris * project 1999.
459191Skris */
559191Skris/* ====================================================================
659191Skris * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
759191Skris *
859191Skris * Redistribution and use in source and binary forms, with or without
959191Skris * modification, are permitted provided that the following conditions
1059191Skris * are met:
1159191Skris *
1259191Skris * 1. Redistributions of source code must retain the above copyright
1359191Skris *    notice, this list of conditions and the following disclaimer.
1459191Skris *
1559191Skris * 2. Redistributions in binary form must reproduce the above copyright
1659191Skris *    notice, this list of conditions and the following disclaimer in
1759191Skris *    the documentation and/or other materials provided with the
1859191Skris *    distribution.
1959191Skris *
2059191Skris * 3. All advertising materials mentioning features or use of this
2159191Skris *    software must display the following acknowledgment:
2259191Skris *    "This product includes software developed by the OpenSSL Project
2359191Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2459191Skris *
2559191Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2659191Skris *    endorse or promote products derived from this software without
2759191Skris *    prior written permission. For written permission, please contact
2859191Skris *    licensing@OpenSSL.org.
2959191Skris *
3059191Skris * 5. Products derived from this software may not be called "OpenSSL"
3159191Skris *    nor may "OpenSSL" appear in their names without prior written
3259191Skris *    permission of the OpenSSL Project.
3359191Skris *
3459191Skris * 6. Redistributions of any form whatsoever must retain the following
3559191Skris *    acknowledgment:
3659191Skris *    "This product includes software developed by the OpenSSL Project
3759191Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3859191Skris *
3959191Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4059191Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4159191Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4259191Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4359191Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4459191Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4559191Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4659191Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4759191Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4859191Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4959191Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5059191Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5159191Skris * ====================================================================
5259191Skris *
5359191Skris * This product includes cryptographic software written by Eric Young
5459191Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5559191Skris * Hudson (tjh@cryptsoft.com).
5659191Skris *
5759191Skris */
5859191Skris
5959191Skris#include <stdio.h>
6059191Skris#include "cryptlib.h"
6159191Skris#include <openssl/x509v3.h>
6259191Skris
6359191Skris
6468651Skrisstatic int tr_cmp(const X509_TRUST * const *a,
6568651Skris		const X509_TRUST * const *b);
6659191Skrisstatic void trtable_free(X509_TRUST *p);
6759191Skris
6859191Skrisstatic int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
69109998Smarkmstatic int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
7059191Skrisstatic int trust_compat(X509_TRUST *trust, X509 *x, int flags);
7159191Skris
7259191Skrisstatic int obj_trust(int id, X509 *x, int flags);
7359191Skrisstatic int (*default_trust)(int id, X509 *x, int flags) = obj_trust;
7459191Skris
7559191Skris/* WARNING: the following table should be kept in order of trust
7659191Skris * and without any gaps so we can just subtract the minimum trust
7759191Skris * value to get an index into the table
7859191Skris */
7959191Skris
8059191Skrisstatic X509_TRUST trstandard[] = {
8159191Skris{X509_TRUST_COMPAT, 0, trust_compat, "compatible", 0, NULL},
8259191Skris{X509_TRUST_SSL_CLIENT, 0, trust_1oidany, "SSL Client", NID_client_auth, NULL},
8389837Skris{X509_TRUST_SSL_SERVER, 0, trust_1oidany, "SSL Server", NID_server_auth, NULL},
8459191Skris{X509_TRUST_EMAIL, 0, trust_1oidany, "S/MIME email", NID_email_protect, NULL},
85120631Snectar{X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, "Object Signer", NID_code_sign, NULL},
86109998Smarkm{X509_TRUST_OCSP_SIGN, 0, trust_1oid, "OCSP responder", NID_OCSP_sign, NULL},
87238405Sjkim{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, "OCSP request", NID_ad_OCSP, NULL},
88238405Sjkim{X509_TRUST_TSA, 0, trust_1oidany, "TSA server", NID_time_stamp, NULL}
8959191Skris};
9059191Skris
9159191Skris#define X509_TRUST_COUNT	(sizeof(trstandard)/sizeof(X509_TRUST))
9259191Skris
9359191SkrisIMPLEMENT_STACK_OF(X509_TRUST)
9459191Skris
9559191Skrisstatic STACK_OF(X509_TRUST) *trtable = NULL;
9659191Skris
9768651Skrisstatic int tr_cmp(const X509_TRUST * const *a,
9868651Skris		const X509_TRUST * const *b)
9959191Skris{
10059191Skris	return (*a)->trust - (*b)->trust;
10159191Skris}
10259191Skris
10359191Skrisint (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int)
10459191Skris{
105109998Smarkm	int (*oldtrust)(int , X509 *, int);
106109998Smarkm	oldtrust = default_trust;
107109998Smarkm	default_trust = trust;
108109998Smarkm	return oldtrust;
10959191Skris}
11059191Skris
11159191Skris
11259191Skrisint X509_check_trust(X509 *x, int id, int flags)
11359191Skris{
11459191Skris	X509_TRUST *pt;
11559191Skris	int idx;
11659191Skris	if(id == -1) return 1;
11759191Skris	idx = X509_TRUST_get_by_id(id);
11859191Skris	if(idx == -1) return default_trust(id, x, flags);
11959191Skris	pt = X509_TRUST_get0(idx);
12059191Skris	return pt->check_trust(pt, x, flags);
12159191Skris}
12259191Skris
12359191Skrisint X509_TRUST_get_count(void)
12459191Skris{
12559191Skris	if(!trtable) return X509_TRUST_COUNT;
12659191Skris	return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
12759191Skris}
12859191Skris
12959191SkrisX509_TRUST * X509_TRUST_get0(int idx)
13059191Skris{
13159191Skris	if(idx < 0) return NULL;
132160814Ssimon	if(idx < (int)X509_TRUST_COUNT) return trstandard + idx;
13359191Skris	return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
13459191Skris}
13559191Skris
13659191Skrisint X509_TRUST_get_by_id(int id)
13759191Skris{
13859191Skris	X509_TRUST tmp;
13959191Skris	int idx;
14059191Skris	if((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX))
14159191Skris				 return id - X509_TRUST_MIN;
14259191Skris	tmp.trust = id;
14359191Skris	if(!trtable) return -1;
14459191Skris	idx = sk_X509_TRUST_find(trtable, &tmp);
14559191Skris	if(idx == -1) return -1;
14659191Skris	return idx + X509_TRUST_COUNT;
14759191Skris}
14859191Skris
149109998Smarkmint X509_TRUST_set(int *t, int trust)
150109998Smarkm{
151109998Smarkm	if(X509_TRUST_get_by_id(trust) == -1) {
152109998Smarkm		X509err(X509_F_X509_TRUST_SET, X509_R_INVALID_TRUST);
153109998Smarkm		return 0;
154109998Smarkm	}
155109998Smarkm	*t = trust;
156109998Smarkm	return 1;
157109998Smarkm}
158109998Smarkm
15959191Skrisint X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
16059191Skris					char *name, int arg1, void *arg2)
16159191Skris{
16259191Skris	int idx;
16359191Skris	X509_TRUST *trtmp;
16459191Skris	/* This is set according to what we change: application can't set it */
16559191Skris	flags &= ~X509_TRUST_DYNAMIC;
16659191Skris	/* This will always be set for application modified trust entries */
16759191Skris	flags |= X509_TRUST_DYNAMIC_NAME;
16859191Skris	/* Get existing entry if any */
16959191Skris	idx = X509_TRUST_get_by_id(id);
17059191Skris	/* Need a new entry */
17159191Skris	if(idx == -1) {
17268651Skris		if(!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) {
17359191Skris			X509err(X509_F_X509_TRUST_ADD,ERR_R_MALLOC_FAILURE);
17459191Skris			return 0;
17559191Skris		}
17659191Skris		trtmp->flags = X509_TRUST_DYNAMIC;
17759191Skris	} else trtmp = X509_TRUST_get0(idx);
17859191Skris
17968651Skris	/* OPENSSL_free existing name if dynamic */
18068651Skris	if(trtmp->flags & X509_TRUST_DYNAMIC_NAME) OPENSSL_free(trtmp->name);
18159191Skris	/* dup supplied name */
18259191Skris	if(!(trtmp->name = BUF_strdup(name))) {
18359191Skris		X509err(X509_F_X509_TRUST_ADD,ERR_R_MALLOC_FAILURE);
18459191Skris		return 0;
18559191Skris	}
18659191Skris	/* Keep the dynamic flag of existing entry */
18759191Skris	trtmp->flags &= X509_TRUST_DYNAMIC;
18859191Skris	/* Set all other flags */
18959191Skris	trtmp->flags |= flags;
19059191Skris
19159191Skris	trtmp->trust = id;
19259191Skris	trtmp->check_trust = ck;
19359191Skris	trtmp->arg1 = arg1;
19459191Skris	trtmp->arg2 = arg2;
19559191Skris
19659191Skris	/* If its a new entry manage the dynamic table */
19759191Skris	if(idx == -1) {
19859191Skris		if(!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) {
19959191Skris			X509err(X509_F_X509_TRUST_ADD,ERR_R_MALLOC_FAILURE);
20059191Skris			return 0;
20159191Skris		}
20259191Skris		if (!sk_X509_TRUST_push(trtable, trtmp)) {
20359191Skris			X509err(X509_F_X509_TRUST_ADD,ERR_R_MALLOC_FAILURE);
20459191Skris			return 0;
20559191Skris		}
20659191Skris	}
20759191Skris	return 1;
20859191Skris}
20959191Skris
21059191Skrisstatic void trtable_free(X509_TRUST *p)
21159191Skris	{
21259191Skris	if(!p) return;
21359191Skris	if (p->flags & X509_TRUST_DYNAMIC)
21459191Skris		{
21559191Skris		if (p->flags & X509_TRUST_DYNAMIC_NAME)
21668651Skris			OPENSSL_free(p->name);
21768651Skris		OPENSSL_free(p);
21859191Skris		}
21959191Skris	}
22059191Skris
22159191Skrisvoid X509_TRUST_cleanup(void)
22259191Skris{
223160814Ssimon	unsigned int i;
22459191Skris	for(i = 0; i < X509_TRUST_COUNT; i++) trtable_free(trstandard + i);
22559191Skris	sk_X509_TRUST_pop_free(trtable, trtable_free);
22659191Skris	trtable = NULL;
22759191Skris}
22859191Skris
22959191Skrisint X509_TRUST_get_flags(X509_TRUST *xp)
23059191Skris{
23159191Skris	return xp->flags;
23259191Skris}
23359191Skris
23459191Skrischar *X509_TRUST_get0_name(X509_TRUST *xp)
23559191Skris{
23659191Skris	return xp->name;
23759191Skris}
23859191Skris
23959191Skrisint X509_TRUST_get_trust(X509_TRUST *xp)
24059191Skris{
24159191Skris	return xp->trust;
24259191Skris}
24359191Skris
24459191Skrisstatic int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
24559191Skris{
24679998Skris	if(x->aux && (x->aux->trust || x->aux->reject))
24779998Skris		return obj_trust(trust->arg1, x, flags);
24859191Skris	/* we don't have any trust settings: for compatibility
24959191Skris	 * we return trusted if it is self signed
25059191Skris	 */
25159191Skris	return trust_compat(trust, x, flags);
25259191Skris}
25359191Skris
254109998Smarkmstatic int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
255109998Smarkm{
256109998Smarkm	if(x->aux) return obj_trust(trust->arg1, x, flags);
257109998Smarkm	return X509_TRUST_UNTRUSTED;
258109998Smarkm}
259109998Smarkm
26059191Skrisstatic int trust_compat(X509_TRUST *trust, X509 *x, int flags)
26159191Skris{
26259191Skris	X509_check_purpose(x, -1, 0);
26359191Skris	if(x->ex_flags & EXFLAG_SS) return X509_TRUST_TRUSTED;
26459191Skris	else return X509_TRUST_UNTRUSTED;
26559191Skris}
26659191Skris
26759191Skrisstatic int obj_trust(int id, X509 *x, int flags)
26859191Skris{
26959191Skris	ASN1_OBJECT *obj;
27059191Skris	int i;
27159191Skris	X509_CERT_AUX *ax;
27259191Skris	ax = x->aux;
27359191Skris	if(!ax) return X509_TRUST_UNTRUSTED;
27459191Skris	if(ax->reject) {
27559191Skris		for(i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
27659191Skris			obj = sk_ASN1_OBJECT_value(ax->reject, i);
27759191Skris			if(OBJ_obj2nid(obj) == id) return X509_TRUST_REJECTED;
27859191Skris		}
27959191Skris	}
28059191Skris	if(ax->trust) {
28159191Skris		for(i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
28259191Skris			obj = sk_ASN1_OBJECT_value(ax->trust, i);
28359191Skris			if(OBJ_obj2nid(obj) == id) return X509_TRUST_TRUSTED;
28459191Skris		}
28559191Skris	}
28659191Skris	return X509_TRUST_UNTRUSTED;
28759191Skris}
28859191Skris
289