*** empty log message ***
[gnutls.git] / lib / x509_verify.c
blob9e69f8312f902af28c15ce77204ae0c16d45cfe4
1 /*
2 * Copyright (C) 2001,2002 Nikos Mavroyanopoulos <nmav@hellug.gr>
4 * This file is part of GNUTLS.
6 * The GNUTLS library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "gnutls_int.h"
23 #include "gnutls_errors.h"
24 #include "gnutls_cert.h"
25 #include "x509_asn1.h"
26 #include "x509_der.h"
27 #include "gnutls_global.h"
28 #include "gnutls_num.h" /* GMAX */
29 #include <gnutls_sig.h>
30 #include <gnutls_str.h>
33 /* Return 0 or INVALID, if the issuer is a CA,
34 * or not.
36 static int check_if_ca(const gnutls_cert * cert,
37 const gnutls_cert * issuer)
39 CertificateStatus ret = GNUTLS_CERT_INVALID;
41 /* Check if the issuer is the same with the
42 * certificate. This is added in order for trusted
43 * certificates to be able to verify themselves.
45 if (cert->raw.size == issuer->raw.size) {
46 if (memcmp
47 (cert->raw.data, issuer->raw.data,
48 cert->raw.size) == 0) {
49 return 0;
53 if (issuer->CA == 1) {
54 ret = 0;
55 } else
56 gnutls_assert();
58 return ret;
63 void _gnutls_int2str(int k, char *data);
65 #define MAX_DN_ELEM 1024
67 /* This function checks if 'certs' issuer is 'issuer_cert'.
68 * This does a straight (DER) compare of the issuer/subject fields in
69 * the given certificates.
71 * FIXME: use a real DN comparison algorithm.
73 static
74 int compare_dn(gnutls_cert * cert, gnutls_cert * issuer_cert)
76 node_asn *c2, *c3;
77 int result, len1;
78 int len2;
79 char tmpstr[512];
80 int start1, start2, end1, end2;
82 /* get the issuer of 'cert'
84 if ((result =
85 asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate",
86 &c2, "certificate2")) != ASN_OK) {
87 gnutls_assert();
88 return _gnutls_asn2err(result);
91 result = asn1_get_der(c2, cert->raw.data, cert->raw.size);
92 if (result != ASN_OK) {
93 /* couldn't decode DER */
94 gnutls_assert();
95 asn1_delete_structure(c2);
96 return _gnutls_asn2err(result);
101 /* get the 'subject' info of 'issuer_cert'
103 if ((result =
104 asn1_create_structure(_gnutls_get_pkix(), "PKIX1.Certificate",
105 &c3, "certificate2")) != ASN_OK) {
106 gnutls_assert();
107 asn1_delete_structure(c2);
108 return _gnutls_asn2err(result);
111 result =
112 asn1_get_der(c3, issuer_cert->raw.data, issuer_cert->raw.size);
113 if (result != ASN_OK) {
114 /* couldn't decode DER */
115 gnutls_assert();
116 asn1_delete_structure(c2);
117 return _gnutls_asn2err(result);
121 _gnutls_str_cpy(tmpstr, sizeof(tmpstr),
122 "certificate2.tbsCertificate.issuer");
123 result =
124 asn1_get_start_end_der(c2, cert->raw.data, cert->raw.size,
125 tmpstr, &start1, &end1);
126 asn1_delete_structure(c2);
128 if (result != ASN_OK) {
129 gnutls_assert();
130 asn1_delete_structure(c3);
131 return _gnutls_asn2err(result);
134 len1 = end1 - start1 + 1;
136 _gnutls_str_cpy(tmpstr, sizeof(tmpstr),
137 "certificate2.tbsCertificate.subject");
138 result =
139 asn1_get_start_end_der(c3, issuer_cert->raw.data,
140 issuer_cert->raw.size, tmpstr, &start2,
141 &end2);
142 asn1_delete_structure(c3);
144 if (result != ASN_OK) {
145 gnutls_assert();
146 return _gnutls_asn2err(result);
149 len2 = end2 - start2 + 1;
151 /* The error code returned does not really matter
152 * here.
154 if (len1 != len2) {
155 gnutls_assert();
156 return GNUTLS_E_UNKNOWN_ERROR;
158 if (memcmp(&issuer_cert->raw.data[start2],
159 &cert->raw.data[start1], len1) != 0) {
160 gnutls_assert();
161 return GNUTLS_E_UNKNOWN_ERROR;
164 /* they match */
165 return 0;
169 static gnutls_cert *find_issuer(gnutls_cert * cert,
170 gnutls_cert * trusted_cas, int tcas_size)
172 int i;
174 /* this is serial search.
177 for (i = 0; i < tcas_size; i++) {
178 if (compare_dn(cert, &trusted_cas[i]) == 0)
179 return &trusted_cas[i];
182 gnutls_assert();
183 return NULL;
186 /* ret_trust is the value to return when the certificate chain is ok
187 * ret_else is the value to return otherwise.
189 int gnutls_verify_certificate2(gnutls_cert * cert,
190 gnutls_cert * trusted_cas, int tcas_size,
191 void *CRLs, int crls_size, int ret_trust,
192 int ret_else)
194 /* CRL is ignored for now */
196 gnutls_cert *issuer;
197 int ret;
199 if (tcas_size >= 1)
200 issuer = find_issuer(cert, trusted_cas, tcas_size);
201 else {
202 gnutls_assert();
203 return ret_else;
206 /* issuer is not in trusted certificate
207 * authorities.
209 if (issuer == NULL) {
210 gnutls_assert();
211 return ret_else;
214 ret = check_if_ca(cert, issuer);
215 if (ret != 0) {
216 gnutls_assert();
217 return ret_else | GNUTLS_CERT_INVALID;
220 ret = gnutls_x509_verify_signature(cert, issuer);
221 if (ret != 0) {
222 gnutls_assert();
223 return ret_else | GNUTLS_CERT_INVALID;
226 /* FIXME: Check CRL --not done yet.
230 return ret_trust;
233 /* The algorithm used is:
234 * 1. Check the certificate chain given by the peer, if it is ok.
235 * 2. If any certificate in the chain are revoked, not
236 * valid, or they are not CAs then the certificate is invalid.
237 * 3. If 1 is ok, then find a certificate in the trusted CAs file
238 * that has the DN of the issuer field in the last certificate
239 * in the peer's certificate chain.
240 * 4. If it does exist then verify it. If verification is ok then
241 * it is trusted. Otherwise it is just valid (but not trusted).
243 /* This function verifies a X.509 certificate list. The certificate list should
244 * lead to a trusted CA in order to be trusted.
246 int _gnutls_x509_verify_certificate(gnutls_cert * certificate_list,
247 int clist_size,
248 gnutls_cert * trusted_cas,
249 int tcas_size, void *CRLs,
250 int crls_size)
252 int i = 0, ret;
253 CertificateStatus status = 0;
255 if (clist_size == 0) {
256 return GNUTLS_E_NO_CERTIFICATE_FOUND;
259 /* Verify the certificate path */
260 for (i = 0; i < clist_size; i++) {
261 if (i + 1 >= clist_size)
262 break;
264 if ((ret =
265 gnutls_verify_certificate2(&certificate_list[i],
266 &certificate_list[i + 1],
267 1, NULL, 0, 0,
268 GNUTLS_CERT_INVALID)) !=
269 0) {
271 * We only accept the first certificate to be
272 * expired, revoked etc. If any of the certificates in the
273 * certificate chain is expired then the certificate
274 * is not valid.
276 if (ret > 0) {
277 gnutls_assert();
278 status |= ret;
279 } else {
280 gnutls_assert();
281 return ret;
286 if (status > 0) { /* If there is any problem in the
287 * certificate chain then mark as not trusted
288 * and return immediately.
290 return (status | GNUTLS_CERT_NOT_TRUSTED);
293 /* Now verify the last certificate in the certificate path
294 * against the trusted CA certificate list.
296 * If no CAs are present returns NOT_TRUSTED. Thus works
297 * in self signed etc certificates.
299 ret =
300 gnutls_verify_certificate2(&certificate_list[i], trusted_cas,
301 tcas_size, CRLs, crls_size, 0,
302 GNUTLS_CERT_NOT_TRUSTED);
304 if (ret > 0) {
305 /* if the last certificate in the certificate
306 * list is invalid, then the certificate is not
307 * trusted.
309 gnutls_assert();
310 status |= ret;
313 if (ret < 0) {
314 gnutls_assert();
315 return ret;
318 /* if we got here, then it's trusted.
320 return status;