2 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
8 * The GnuTLS is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
24 #include <gnutls_errors.h>
26 #include <gnutls_global.h>
27 #include <gnutls_num.h> /* MAX */
28 #include <gnutls_sig.h>
29 #include <gnutls_str.h>
30 #include <gnutls_datum.h>
31 #include <hash-pjw-bare.h>
34 #include "verify-high.h"
36 struct named_cert_st
{
37 gnutls_x509_crt_t cert
;
38 uint8_t name
[MAX_SERVER_NAME_SIZE
];
39 unsigned int name_size
;
43 /* The trusted certificates */
44 gnutls_x509_crt_t
*trusted_cas
;
45 unsigned int trusted_ca_size
;
47 struct named_cert_st
*named_certs
;
48 unsigned int named_cert_size
;
50 /* The trusted CRLs */
51 gnutls_x509_crl_t
*crls
;
52 unsigned int crl_size
;
55 struct gnutls_x509_trust_list_st
{
60 #define DEFAULT_SIZE 503
63 * gnutls_x509_trust_list_init:
64 * @list: The structure to be initialized
65 * @size: The size of the internal hash table. Use (0) for default size.
67 * This function will initialize an X.509 trust list structure.
69 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
70 * negative error value.
75 gnutls_x509_trust_list_init(gnutls_x509_trust_list_t
* list
,
78 gnutls_x509_trust_list_t tmp
=
79 gnutls_calloc(1, sizeof(struct gnutls_x509_trust_list_st
));
82 return GNUTLS_E_MEMORY_ERROR
;
88 tmp
->node
= gnutls_calloc(1, tmp
->size
* sizeof(tmp
->node
[0]));
89 if (tmp
->node
== NULL
) {
92 return GNUTLS_E_MEMORY_ERROR
;
97 return 0; /* success */
101 * gnutls_x509_trust_list_deinit:
102 * @list: The structure to be deinitialized
103 * @all: if non-(0) it will deinitialize all the certificates and CRLs contained in the structure.
105 * This function will deinitialize a trust list.
110 gnutls_x509_trust_list_deinit(gnutls_x509_trust_list_t list
,
118 for (i
= 0; i
< list
->size
; i
++) {
120 for (j
= 0; j
< list
->node
[i
].trusted_ca_size
; j
++) {
121 gnutls_x509_crt_deinit(list
->node
[i
].trusted_cas
[j
]);
123 gnutls_free(list
->node
[i
].trusted_cas
);
126 for (j
= 0; j
< list
->node
[i
].crl_size
; j
++) {
127 gnutls_x509_crl_deinit(list
->node
[i
].crls
[j
]);
129 gnutls_free(list
->node
[i
].crls
);
132 for (j
= 0; j
< list
->node
[i
].named_cert_size
; j
++) {
133 gnutls_x509_crt_deinit(list
->node
[i
].named_certs
[j
].cert
);
135 gnutls_free(list
->node
[i
].named_certs
);
138 gnutls_free(list
->node
);
143 * gnutls_x509_trust_list_add_cas:
144 * @list: The structure of the list
145 * @clist: A list of CAs
146 * @clist_size: The length of the CA list
147 * @flags: should be 0.
149 * This function will add the given certificate authorities
150 * to the trusted list. The list of CAs must not be deinitialized
151 * during this structure's lifetime.
153 * Returns: The number of added elements is returned.
158 gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list
,
159 const gnutls_x509_crt_t
* clist
,
160 int clist_size
, unsigned int flags
)
166 for (i
= 0; i
< clist_size
; i
++) {
167 ret
= gnutls_x509_crt_get_raw_dn(clist
[i
], &dn
);
173 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
176 _gnutls_free_datum(&dn
);
177 list
->node
[hash
].trusted_cas
=
178 gnutls_realloc_fast(list
->node
[hash
].trusted_cas
,
179 (list
->node
[hash
].trusted_ca_size
+
181 sizeof(list
->node
[hash
].trusted_cas
[0]));
182 if (list
->node
[hash
].trusted_cas
== NULL
) {
187 list
->node
[hash
].trusted_cas
[list
->node
[hash
].trusted_ca_size
] =
189 list
->node
[hash
].trusted_ca_size
++;
196 * gnutls_x509_trust_list_add_named_crt:
197 * @list: The structure of the list
198 * @cert: A certificate
199 * @name: An identifier for the certificate
200 * @name_size: The size of the identifier
201 * @flags: should be 0.
203 * This function will add the given certificate to the trusted
204 * list and associate it with a name. The certificate will not be
205 * be used for verification with gnutls_x509_trust_list_verify_crt()
206 * but only with gnutls_x509_trust_list_verify_named_crt().
208 * In principle this function can be used to set individual "server"
209 * certificates that are trusted by the user for that specific server
210 * but for no other purposes.
212 * The certificate must not be deinitialized during the lifetime
213 * of the trusted list.
215 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
216 * negative error value.
221 gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list
,
222 gnutls_x509_crt_t cert
,
223 const void *name
, size_t name_size
,
230 if (name_size
>= MAX_SERVER_NAME_SIZE
)
231 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
233 ret
= gnutls_x509_crt_get_raw_issuer_dn(cert
, &dn
);
239 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
242 _gnutls_free_datum(&dn
);
244 list
->node
[hash
].named_certs
=
245 gnutls_realloc_fast(list
->node
[hash
].named_certs
,
246 (list
->node
[hash
].named_cert_size
+
247 1) * sizeof(list
->node
[hash
].named_certs
[0]));
248 if (list
->node
[hash
].named_certs
== NULL
)
249 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
251 list
->node
[hash
].named_certs
[list
->node
[hash
].named_cert_size
].cert
=
253 memcpy(list
->node
[hash
].named_certs
[list
->node
[hash
].named_cert_size
].
254 name
, name
, name_size
);
255 list
->node
[hash
].named_certs
[list
->node
[hash
].named_cert_size
].
256 name_size
= name_size
;
258 list
->node
[hash
].named_cert_size
++;
264 * gnutls_x509_trust_list_add_crls:
265 * @list: The structure of the list
266 * @crl_list: A list of CRLs
267 * @crl_size: The length of the CRL list
268 * @flags: if GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added.
269 * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
271 * This function will add the given certificate revocation lists
272 * to the trusted list. The list of CRLs must not be deinitialized
273 * during this structure's lifetime.
275 * This function must be called after gnutls_x509_trust_list_add_cas()
276 * to allow verifying the CRLs for validity.
278 * Returns: The number of added elements is returned.
283 gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list
,
284 const gnutls_x509_crl_t
* crl_list
,
285 int crl_size
, unsigned int flags
,
286 unsigned int verification_flags
)
290 unsigned int vret
= 0;
293 /* Probably we can optimize things such as removing duplicates
297 if (crl_size
== 0 || crl_list
== NULL
)
300 for (i
= 0; i
< crl_size
; i
++) {
301 ret
= gnutls_x509_crl_get_raw_issuer_dn(crl_list
[i
], &dn
);
307 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
310 _gnutls_free_datum(&dn
);
312 if (flags
& GNUTLS_TL_VERIFY_CRL
) {
315 gnutls_x509_crl_verify(crl_list
[i
],
316 list
->node
[hash
].trusted_cas
,
317 list
->node
[hash
].trusted_ca_size
,
318 verification_flags
, &vret
);
319 if (ret
< 0 || vret
!= 0)
323 list
->node
[hash
].crls
=
324 gnutls_realloc_fast(list
->node
[hash
].crls
,
325 (list
->node
[hash
].crl_size
+
327 sizeof(list
->node
[hash
].trusted_cas
[0]));
328 if (list
->node
[hash
].crls
== NULL
) {
333 list
->node
[hash
].crls
[list
->node
[hash
].crl_size
] = crl_list
[i
];
334 list
->node
[hash
].crl_size
++;
341 /* Takes a certificate list and shortens it if there are
342 * intermedia certificates already trusted by us.
344 * FIXME: This is very similar to _gnutls_x509_verify_certificate().
346 * Returns the new size of the list or a negative number on error.
348 static int shorten_clist(gnutls_x509_trust_list_t list
,
349 gnutls_x509_crt_t
* certificate_list
,
350 unsigned int clist_size
)
357 if (clist_size
> 1) {
358 /* Check if the last certificate in the path is self signed.
359 * In that case ignore it (a certificate is trusted only if it
360 * leads to a trusted party by us, not the server's).
362 * This prevents from verifying self signed certificates against
363 * themselves. This (although not bad) caused verification
364 * failures on some root self signed certificates that use the
367 if (gnutls_x509_crt_check_issuer(certificate_list
[clist_size
- 1],
368 certificate_list
[clist_size
-
374 /* We want to shorten the chain by removing the cert that matches
375 * one of the certs we trust and all the certs after that i.e. if
376 * cert chain is A signed-by B signed-by C signed-by D (signed-by
377 * self-signed E but already removed above), and we trust B, remove
379 for (i
= 1; i
< clist_size
; i
++) {
380 ret
= gnutls_x509_crt_get_raw_issuer_dn(certificate_list
[i
], &dn
);
386 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
389 _gnutls_free_datum(&dn
);
391 for (j
= 0; j
< list
->node
[hash
].trusted_ca_size
; j
++) {
392 if (check_if_same_cert
393 (certificate_list
[i
],
394 list
->node
[hash
].trusted_cas
[j
]) == 0) {
395 /* cut the list at the point of first the trusted certificate */
400 /* clist_size may have been changed which gets out of loop */
406 /* Takes a certificate list and orders it with subject, issuer order.
408 * *clist_size contains the size of the ordered list (which is always less or
409 * equal to the original).
411 * Returns the sorted list which may be the original clist.
413 static gnutls_x509_crt_t
* sort_clist(gnutls_x509_crt_t sorted
[DEFAULT_MAX_VERIFY_DEPTH
],
414 gnutls_x509_crt_t
* clist
,
415 unsigned int *clist_size
)
419 int issuer
[DEFAULT_MAX_VERIFY_DEPTH
]; /* contain the index of the issuers */
421 /* Do not bother sorting if too many certificates are given.
422 * Prevent any DoS attacks.
424 if (*clist_size
> DEFAULT_MAX_VERIFY_DEPTH
)
427 for (i
=0;i
<DEFAULT_MAX_VERIFY_DEPTH
;i
++)
430 /* Find the issuer of each certificate and store it
433 for(i
=0;i
<*clist_size
;i
++)
435 for (j
=1;j
<*clist_size
;j
++)
439 if (gnutls_x509_crt_check_issuer(clist
[i
],
455 sorted
[0] = clist
[0];
456 for (i
=1;i
<*clist_size
;i
++)
459 if (prev
== -1) /* no issuer */
464 sorted
[i
] = clist
[prev
];
471 * gnutls_x509_trust_list_get_issuer:
472 * @list: The structure of the list
473 * @cert: is the certificate to find issuer for
474 * @issuer: Will hold the issuer if any. Should be treated as constant.
477 * This function will attempt to find the issuer of the
480 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
481 * negative error value.
485 int gnutls_x509_trust_list_get_issuer(gnutls_x509_trust_list_t list
,
486 gnutls_x509_crt_t cert
,
487 gnutls_x509_crt_t
* issuer
,
495 ret
= gnutls_x509_crt_get_raw_issuer_dn(cert
, &dn
);
501 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
504 _gnutls_free_datum(&dn
);
506 for (i
= 0; i
< list
->node
[hash
].trusted_ca_size
; i
++) {
508 gnutls_x509_crt_check_issuer(cert
,
509 list
->node
[hash
].trusted_cas
[i
]);
511 *issuer
= list
->node
[hash
].trusted_cas
[i
];
516 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
520 * gnutls_x509_trust_list_verify_crt:
521 * @list: The structure of the list
522 * @cert_list: is the certificate list to be verified
523 * @cert_list_size: is the certificate list size
524 * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
525 * @verify: will hold the certificate verification output.
526 * @func: If non-null will be called on each chain element verification with the output.
528 * This function will try to verify the given certificate and return
529 * its status. The @verify parameter will hold an OR'ed sequence of
530 * %gnutls_certificate_status_t flags.
532 * Limitation: Pathlen constraints or key usage flags are not consulted.
534 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
535 * negative error value.
540 gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list
,
541 gnutls_x509_crt_t
* cert_list
,
542 unsigned int cert_list_size
,
544 unsigned int *verify
,
545 gnutls_verify_output_function func
)
551 gnutls_x509_crt_t sorted
[DEFAULT_MAX_VERIFY_DEPTH
];
553 if (cert_list
== NULL
|| cert_list_size
< 1)
554 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
556 if (!(flags
& GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN
))
557 cert_list
= sort_clist(sorted
, cert_list
, &cert_list_size
);
559 cert_list_size
= shorten_clist(list
, cert_list
, cert_list_size
);
560 if (cert_list_size
<= 0)
561 return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR
);
564 gnutls_x509_crt_get_raw_issuer_dn(cert_list
[cert_list_size
- 1],
571 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
574 _gnutls_free_datum(&dn
);
576 *verify
= _gnutls_x509_verify_certificate(cert_list
, cert_list_size
,
577 list
->node
[hash
].trusted_cas
,
579 trusted_ca_size
, flags
,
582 if (*verify
!= 0 || (flags
& GNUTLS_VERIFY_DISABLE_CRL_CHECKS
))
585 /* Check revocation of individual certificates.
586 * start with the last one that we already have its hash
588 ret
= _gnutls_x509_crt_check_revocation(cert_list
[cert_list_size
- 1],
589 list
->node
[hash
].crls
,
590 list
->node
[hash
].crl_size
,
592 if (ret
== 1) { /* revoked */
593 *verify
|= GNUTLS_CERT_REVOKED
;
594 *verify
|= GNUTLS_CERT_INVALID
;
598 for (i
= 0; i
< cert_list_size
- 1; i
++) {
599 ret
= gnutls_x509_crt_get_raw_issuer_dn(cert_list
[i
], &dn
);
605 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
608 _gnutls_free_datum(&dn
);
610 ret
= _gnutls_x509_crt_check_revocation(cert_list
[i
],
611 list
->node
[hash
].crls
,
612 list
->node
[hash
].crl_size
,
614 if (ret
== 1) { /* revoked */
615 *verify
|= GNUTLS_CERT_REVOKED
;
616 *verify
|= GNUTLS_CERT_INVALID
;
625 * gnutls_x509_trust_list_verify_named_crt:
626 * @list: The structure of the list
627 * @cert: is the certificate to be verified
628 * @name: is the certificate's name
629 * @name_size: is the certificate's name size
630 * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
631 * @verify: will hold the certificate verification output.
632 * @func: If non-null will be called on each chain element verification with the output.
634 * This function will try to find a certificate that is associated with the provided
635 * name --see gnutls_x509_trust_list_add_named_crt(). If a match is found the certificate is considered valid. In addition to that
636 * this function will also check CRLs. The @verify parameter will hold an OR'ed sequence of
637 * %gnutls_certificate_status_t flags.
639 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
640 * negative error value.
645 gnutls_x509_trust_list_verify_named_crt(gnutls_x509_trust_list_t list
,
646 gnutls_x509_crt_t cert
,
650 unsigned int *verify
,
651 gnutls_verify_output_function func
)
658 ret
= gnutls_x509_crt_get_raw_issuer_dn(cert
, &dn
);
664 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
667 _gnutls_free_datum(&dn
);
669 *verify
= GNUTLS_CERT_INVALID
| GNUTLS_CERT_SIGNER_NOT_FOUND
;
671 for (i
= 0; i
< list
->node
[hash
].named_cert_size
; i
++) {
672 if (check_if_same_cert(cert
, list
->node
[hash
].named_certs
[i
].cert
) == 0) { /* check if name matches */
673 if (list
->node
[hash
].named_certs
[i
].name_size
== name_size
&&
674 memcmp(list
->node
[hash
].named_certs
[i
].name
, name
,
682 if (*verify
!= 0 || (flags
& GNUTLS_VERIFY_DISABLE_CRL_CHECKS
))
685 /* Check revocation of individual certificates.
686 * start with the last one that we already have its hash
688 ret
= _gnutls_x509_crt_check_revocation(cert
,
689 list
->node
[hash
].crls
,
690 list
->node
[hash
].crl_size
,
692 if (ret
== 1) { /* revoked */
693 *verify
|= GNUTLS_CERT_REVOKED
;
694 *verify
|= GNUTLS_CERT_INVALID
;
701 /* return 0 if @cert is in @list, 1 if not, or < 0 on error. */
703 _gnutls_trustlist_inlist (gnutls_x509_trust_list_t list
,
704 gnutls_x509_crt_t cert
)
711 ret
= gnutls_x509_crt_get_raw_dn (cert
, &dn
);
718 hash
= hash_pjw_bare(dn
.data
, dn
.size
);
721 _gnutls_free_datum (&dn
);
723 for (i
= 0; i
< list
->node
[hash
].trusted_ca_size
; i
++)
725 ret
= check_if_same_cert (cert
, list
->node
[hash
].trusted_cas
[i
]);