*** empty log message ***
[gnutls.git] / lib / x509_verify.c
blob87d031064b477a7505a784b38f1e5026cac78bb1
1 /*
2 * Copyright (C) 2001,2002 Nikos Mavroyanopoulos <nmav@hellug.gr>
4 * This file is part of GNUTLS.
6 * GNUTLS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GNUTLS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 #include "gnutls_int.h"
22 #include "gnutls_errors.h"
23 #include "gnutls_cert.h"
24 #include "x509_asn1.h"
25 #include "x509_der.h"
26 #include "gnutls_global.h"
27 #include "gnutls_num.h" /* GMAX */
28 #include <gnutls_sig.h>
29 #include <gnutls_str.h>
32 /* Return 0 or INVALID, if the issuer is a CA,
33 * or not.
35 static int check_if_ca(const gnutls_cert * cert,
36 const gnutls_cert * issuer)
38 CertificateStatus ret = GNUTLS_CERT_INVALID;
40 /* Check if the issuer is the same with the
41 * certificate. This is added in order for trusted
42 * certificates to be able to verify themselves.
44 if (cert->raw.size == issuer->raw.size) {
45 if (memcmp
46 (cert->raw.data, issuer->raw.data,
47 cert->raw.size) == 0) {
48 return 0;
52 if (issuer->CA == 1) {
53 ret = 0;
54 } else
55 gnutls_assert();
57 return ret;
62 void _gnutls_int2str(int k, char *data);
64 #define MAX_DN_ELEM 1024
66 /* This function checks if 'certs' issuer is 'issuer_cert'.
67 * This does a straight (DER) compare of the issuer/subject fields in
68 * the given certificates.
70 * FIXME: use a real DN comparison algorithm.
72 static
73 int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
75 node_asn *c2, *c3;
76 int result, len1;
77 int len2;
78 char tmpstr[512];
79 int start1, start2, end1, end2;
81 /* get the issuer of 'cert'
83 if ((result =
84 asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate",
85 &c2, "certificate2")) != ASN_OK) {
86 gnutls_assert();
87 return _gnutls_asn2err(result);
90 result = asn1_get_der(c2, cert->raw.data, cert->raw.size);
91 if (result != ASN_OK) {
92 /* couldn't decode DER */
93 gnutls_assert();
94 asn1_delete_structure(c2);
95 return _gnutls_asn2err(result);
100 /* get the 'subject' info of 'issuer_cert'
102 if ((result =
103 asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate",
104 &c3, "certificate2")) != ASN_OK) {
105 gnutls_assert();
106 asn1_delete_structure(c2);
107 return _gnutls_asn2err(result);
110 result =
111 asn1_get_der(c3, issuer_cert->raw.data, issuer_cert->raw.size);
112 if (result != ASN_OK) {
113 /* couldn't decode DER */
114 gnutls_assert();
115 asn1_delete_structure(c2);
116 return _gnutls_asn2err(result);
120 _gnutls_str_cpy(tmpstr, sizeof(tmpstr),
121 "certificate2.tbsCertificate.issuer");
122 result =
123 asn1_get_start_end_der(c2, cert->raw.data, cert->raw.size,
124 tmpstr, &start1, &end1);
125 asn1_delete_structure(c2);
127 if (result != ASN_OK) {
128 gnutls_assert();
129 asn1_delete_structure(c3);
130 return _gnutls_asn2err(result);
133 len1 = end1 - start1 + 1;
135 _gnutls_str_cpy(tmpstr, sizeof(tmpstr),
136 "certificate2.tbsCertificate.subject");
137 result =
138 asn1_get_start_end_der(c3, issuer_cert->raw.data,
139 issuer_cert->raw.size, tmpstr, &start2,
140 &end2);
141 asn1_delete_structure(c3);
143 if (result != ASN_OK) {
144 gnutls_assert();
145 return _gnutls_asn2err(result);
148 len2 = end2 - start2 + 1;
150 /* The error code returned does not really matter
151 * here.
153 if (len1 != len2) {
154 gnutls_assert();
155 return GNUTLS_E_UNKNOWN_ERROR;
157 if (memcmp(&issuer_cert->raw.data[start2],
158 &cert->raw.data[start1], len1) != 0) {
159 gnutls_assert();
160 return GNUTLS_E_UNKNOWN_ERROR;
163 /* they match */
164 return 0;
168 static gnutls_cert *find_issuer(gnutls_cert * cert,
169 gnutls_cert * trusted_cas, int tcas_size)
171 int i;
173 /* this is serial search.
176 for (i = 0; i < tcas_size; i++) {
177 if (compare_dn(cert, &trusted_cas[i]) == 0)
178 return &trusted_cas[i];
181 gnutls_assert();
182 return NULL;
185 /* ret_trust is the value to return when the certificate chain is ok
186 * ret_else is the value to return otherwise.
188 int gnutls_verify_certificate2(gnutls_cert * cert,
189 gnutls_cert * trusted_cas, int tcas_size,
190 void *CRLs, int crls_size, int ret_trust,
191 int ret_else)
193 /* CRL is ignored for now */
195 gnutls_cert *issuer;
196 int ret;
198 if (tcas_size >= 1)
199 issuer = find_issuer(cert, trusted_cas, tcas_size);
200 else {
201 gnutls_assert();
202 return ret_else;
205 /* issuer is not in trusted certificate
206 * authorities.
208 if (issuer == NULL) {
209 gnutls_assert();
210 return ret_else;
213 ret = check_if_ca(cert, issuer);
214 if (ret != 0) {
215 gnutls_assert();
216 return ret_else | GNUTLS_CERT_INVALID;
219 ret = gnutls_x509_verify_signature(cert, issuer);
220 if (ret != 0) {
221 gnutls_assert();
222 return ret_else | GNUTLS_CERT_INVALID;
225 /* FIXME: Check CRL --not done yet.
229 return ret_trust;
232 /* The algorithm used is:
233 * 1. Check the certificate chain given by the peer, if it is ok.
234 * 2. If any certificate in the chain are revoked, not
235 * valid, or they are not CAs then the certificate is invalid.
236 * 3. If 1 is ok, then find a certificate in the trusted CAs file
237 * that has the DN of the issuer field in the last certificate
238 * in the peer's certificate chain.
239 * 4. If it does exist then verify it. If verification is ok then
240 * it is trusted. Otherwise it is just valid (but not trusted).
242 /* This function verifies a X.509 certificate list. The certificate list should
243 * lead to a trusted CA in order to be trusted.
245 int _gnutls_x509_verify_certificate(gnutls_cert * certificate_list,
246 int clist_size,
247 gnutls_cert * trusted_cas,
248 int tcas_size, void *CRLs,
249 int crls_size)
251 int i = 0, ret;
252 CertificateStatus status = 0;
254 if (clist_size == 0) {
255 return GNUTLS_E_NO_CERTIFICATE_FOUND;
258 /* Verify the certificate path */
259 for (i = 0; i < clist_size; i++) {
260 if (i + 1 >= clist_size)
261 break;
263 if ((ret =
264 gnutls_verify_certificate2(&certificate_list[i],
265 &certificate_list[i + 1],
266 1, NULL, 0, 0,
267 GNUTLS_CERT_INVALID)) !=
268 0) {
270 * We only accept the first certificate to be
271 * expired, revoked etc. If any of the certificates in the
272 * certificate chain is expired then the certificate
273 * is not valid.
275 if (ret > 0) {
276 gnutls_assert();
277 status |= ret;
278 } else {
279 gnutls_assert();
280 return ret;
285 if (status > 0) { /* If there is any problem in the
286 * certificate chain then mark as not trusted
287 * and return immediately.
289 return (status | GNUTLS_CERT_NOT_TRUSTED);
292 /* Now verify the last certificate in the certificate path
293 * against the trusted CA certificate list.
295 * If no CAs are present returns NOT_TRUSTED. Thus works
296 * in self signed etc certificates.
298 ret =
299 gnutls_verify_certificate2(&certificate_list[i], trusted_cas,
300 tcas_size, CRLs, crls_size, 0,
301 GNUTLS_CERT_NOT_TRUSTED);
303 if (ret > 0) {
304 /* if the last certificate in the certificate
305 * list is invalid, then the certificate is not
306 * trusted.
308 gnutls_assert();
309 status |= ret;
312 if (ret < 0) {
313 gnutls_assert();
314 return ret;
317 /* if we got here, then it's trusted.
319 return status;