2 * gtlsfiledatabase-openssl.c
4 * Copyright (C) 2015 NICE s.r.l.
6 * This file 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 file 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 License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * In addition, when the library is used with OpenSSL, a special
20 * exception applies. Refer to the LICENSE_EXCEPTION file for details.
22 * Authors: Ignacio Casal Quinteiro
27 #include "gtlsfiledatabase-openssl.h"
30 #include <glib/gi18n-lib.h>
31 #include "openssl-include.h"
33 typedef struct _GTlsFileDatabaseOpensslPrivate
35 /* read-only after construct */
36 gchar *anchor_filename;
37 STACK_OF(X509) *trusted;
39 /* protected by mutex */
43 * These are hash tables of gulong -> GPtrArray<GBytes>. The values of
44 * the ptr array are full DER encoded certificate values. The keys are byte
45 * arrays containing either subject DNs, issuer DNs, or full DER encoded certs
51 * This is a table of GBytes -> GBytes. The values and keys are
52 * DER encoded certificate values.
57 * This is a table of gchar * -> GTlsCertificate.
59 GHashTable *certs_by_handle;
60 } GTlsFileDatabaseOpensslPrivate;
76 static void g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface);
78 static void g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface);
80 G_DEFINE_TYPE_WITH_CODE (GTlsFileDatabaseOpenssl, g_tls_file_database_openssl, G_TYPE_TLS_DATABASE_OPENSSL,
81 G_ADD_PRIVATE (GTlsFileDatabaseOpenssl)
82 G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
83 g_tls_file_database_openssl_file_database_interface_init)
84 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
85 g_tls_file_database_openssl_initable_interface_init))
88 bytes_multi_table_new (void)
90 return g_hash_table_new_full (g_int_hash, g_int_equal,
91 (GDestroyNotify)g_free,
92 (GDestroyNotify)g_ptr_array_unref);
96 bytes_multi_table_insert (GHashTable *table,
102 multi = g_hash_table_lookup (table, &key);
107 key_ptr = g_new (int, 1);
109 multi = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
110 g_hash_table_insert (table, key_ptr, multi);
112 g_ptr_array_add (multi, g_bytes_ref (value));
116 bytes_multi_table_lookup_ref_one (GHashTable *table,
121 multi = g_hash_table_lookup (table, &key);
125 g_assert (multi->len > 0);
126 return g_bytes_ref (multi->pdata[0]);
130 bytes_multi_table_lookup_ref_all (GHashTable *table,
137 multi = g_hash_table_lookup (table, &key);
141 for (i = 0; i < multi->len; i++)
142 list = g_list_prepend (list, g_bytes_ref (multi->pdata[i]));
144 return g_list_reverse (list);
148 create_handle_for_certificate (const gchar *filename,
156 * Here we create a URI that looks like:
157 * file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
160 uri_part = g_filename_to_uri (filename, NULL, NULL);
164 bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
165 uri = g_strconcat (uri_part, "#", bookmark, NULL);
174 load_anchor_file (GTlsFileDatabaseOpenssl *file_database,
175 const gchar *filename,
176 GHashTable *subjects,
178 GHashTable *complete,
179 GHashTable *certs_by_handle,
182 GTlsFileDatabaseOpensslPrivate *priv;
187 GError *my_error = NULL;
189 priv = g_tls_file_database_openssl_get_instance_private (file_database);
191 list = g_tls_certificate_list_new_from_file (filename, &my_error);
194 g_propagate_error (error, my_error);
198 for (l = list; l; l = l->next)
201 unsigned long subject;
202 unsigned long issuer;
204 x = g_tls_certificate_openssl_get_cert (l->data);
205 subject = X509_subject_name_hash (x);
206 issuer = X509_issuer_name_hash (x);
208 der = g_tls_certificate_openssl_get_bytes (l->data);
209 g_return_val_if_fail (der != NULL, FALSE);
211 g_hash_table_insert (complete, g_bytes_ref (der),
214 bytes_multi_table_insert (subjects, subject, der);
215 bytes_multi_table_insert (issuers, issuer, der);
217 handle = create_handle_for_certificate (priv->anchor_filename, der);
218 g_hash_table_insert (certs_by_handle, handle, g_object_ref (l->data));
222 g_object_unref (l->data);
230 g_tls_file_database_openssl_finalize (GObject *object)
232 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
233 GTlsFileDatabaseOpensslPrivate *priv;
235 priv = g_tls_file_database_openssl_get_instance_private (file_database);
237 g_clear_pointer (&priv->subjects, g_hash_table_destroy);
238 g_clear_pointer (&priv->issuers, g_hash_table_destroy);
239 g_clear_pointer (&priv->complete, g_hash_table_destroy);
240 g_clear_pointer (&priv->certs_by_handle, g_hash_table_destroy);
242 g_free (priv->anchor_filename);
243 priv->anchor_filename = NULL;
245 if (priv->trusted != NULL)
246 sk_X509_pop_free (priv->trusted, X509_free);
248 g_mutex_clear (&priv->mutex);
250 G_OBJECT_CLASS (g_tls_file_database_openssl_parent_class)->finalize (object);
254 g_tls_file_database_openssl_get_property (GObject *object,
259 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
260 GTlsFileDatabaseOpensslPrivate *priv;
262 priv = g_tls_file_database_openssl_get_instance_private (file_database);
267 g_value_set_string (value, priv->anchor_filename);
270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 static STACK_OF(X509) *
275 load_certs (const gchar *file_name)
278 STACK_OF(X509) *certs;
279 STACK_OF(X509_INFO) *xis = NULL;
282 if (file_name == NULL)
285 bio = BIO_new_file (file_name, "rb");
289 xis = PEM_X509_INFO_read_bio (bio, NULL, NULL, NULL);
293 certs = sk_X509_new_null ();
297 for (i = 0; i < sk_X509_INFO_num (xis); i++)
301 xi = sk_X509_INFO_value (xis, i);
302 if (xi->x509 != NULL)
304 if (!sk_X509_push (certs, xi->x509))
311 sk_X509_INFO_pop_free (xis, X509_INFO_free);
313 if (sk_X509_num (certs) == 0)
315 sk_X509_pop_free (certs, X509_free);
323 g_tls_file_database_openssl_set_property (GObject *object,
328 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
329 GTlsFileDatabaseOpensslPrivate *priv;
330 const gchar *anchor_path;
332 priv = g_tls_file_database_openssl_get_instance_private (file_database);
337 anchor_path = g_value_get_string (value);
338 if (anchor_path && !g_path_is_absolute (anchor_path))
340 g_warning ("The anchor file name used with a GTlsFileDatabase "
341 "must be an absolute path, and not relative: %s", anchor_path);
345 if (priv->anchor_filename)
347 g_free (priv->anchor_filename);
348 if (priv->trusted != NULL)
349 sk_X509_pop_free (priv->trusted, X509_free);
352 priv->anchor_filename = g_strdup (anchor_path);
353 priv->trusted = load_certs (anchor_path);
356 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
361 g_tls_file_database_openssl_init (GTlsFileDatabaseOpenssl *file_database)
363 GTlsFileDatabaseOpensslPrivate *priv;
365 priv = g_tls_file_database_openssl_get_instance_private (file_database);
367 g_mutex_init (&priv->mutex);
371 g_tls_file_database_openssl_create_certificate_handle (GTlsDatabase *database,
372 GTlsCertificate *certificate)
374 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
375 GTlsFileDatabaseOpensslPrivate *priv;
378 gchar *handle = NULL;
380 priv = g_tls_file_database_openssl_get_instance_private (file_database);
382 der = g_tls_certificate_openssl_get_bytes (G_TLS_CERTIFICATE_OPENSSL (certificate));
383 g_return_val_if_fail (der != NULL, FALSE);
385 g_mutex_lock (&priv->mutex);
387 /* At the same time look up whether this certificate is in list */
388 contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
390 g_mutex_unlock (&priv->mutex);
392 /* Certificate is in the database */
394 handle = create_handle_for_certificate (priv->anchor_filename, der);
400 static GTlsCertificate *
401 g_tls_file_database_openssl_lookup_certificate_for_handle (GTlsDatabase *database,
403 GTlsInteraction *interaction,
404 GTlsDatabaseLookupFlags flags,
405 GCancellable *cancellable,
408 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
409 GTlsFileDatabaseOpensslPrivate *priv;
410 GTlsCertificate *cert;
412 priv = g_tls_file_database_openssl_get_instance_private (file_database);
414 if (g_cancellable_set_error_if_cancelled (cancellable, error))
420 g_mutex_lock (&priv->mutex);
422 cert = g_hash_table_lookup (priv->certs_by_handle, handle);
424 g_mutex_unlock (&priv->mutex);
426 return cert ? g_object_ref (cert) : NULL;
429 static GTlsCertificate *
430 g_tls_file_database_openssl_lookup_certificate_issuer (GTlsDatabase *database,
431 GTlsCertificate *certificate,
432 GTlsInteraction *interaction,
433 GTlsDatabaseLookupFlags flags,
434 GCancellable *cancellable,
437 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
438 GTlsFileDatabaseOpensslPrivate *priv;
440 unsigned long issuer_hash;
442 GTlsCertificate *issuer = NULL;
444 priv = g_tls_file_database_openssl_get_instance_private (file_database);
446 g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (certificate), NULL);
448 if (g_cancellable_set_error_if_cancelled (cancellable, error))
451 if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
454 /* Dig out the issuer of this certificate */
455 x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (certificate));
456 issuer_hash = X509_issuer_name_hash (x);
458 g_mutex_lock (&priv->mutex);
459 der = bytes_multi_table_lookup_ref_one (priv->subjects, issuer_hash);
460 g_mutex_unlock (&priv->mutex);
462 if (g_cancellable_set_error_if_cancelled (cancellable, error))
464 else if (der != NULL)
465 issuer = g_tls_certificate_openssl_new (der, NULL);
475 g_tls_file_database_openssl_lookup_certificates_issued_by (GTlsDatabase *database,
476 GByteArray *issuer_raw_dn,
477 GTlsInteraction *interaction,
478 GTlsDatabaseLookupFlags flags,
479 GCancellable *cancellable,
482 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
483 GTlsFileDatabaseOpensslPrivate *priv;
485 const unsigned char *in;
486 GList *issued = NULL;
488 priv = g_tls_file_database_openssl_get_instance_private (file_database);
490 if (g_cancellable_set_error_if_cancelled (cancellable, error))
493 /* We don't have any private keys here */
494 if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
497 in = issuer_raw_dn->data;
498 x_name = d2i_X509_NAME (NULL, &in, issuer_raw_dn->len);
501 unsigned long issuer_hash;
504 issuer_hash = X509_NAME_hash (x_name);
506 /* Find the full DER value of the certificate */
507 g_mutex_lock (&priv->mutex);
508 ders = bytes_multi_table_lookup_ref_all (priv->issuers, issuer_hash);
509 g_mutex_unlock (&priv->mutex);
511 for (l = ders; l != NULL; l = g_list_next (l))
513 if (g_cancellable_set_error_if_cancelled (cancellable, error))
515 g_list_free_full (issued, g_object_unref);
520 issued = g_list_prepend (issued, g_tls_certificate_openssl_new (l->data, NULL));
523 g_list_free_full (ders, (GDestroyNotify)g_bytes_unref);
524 X509_NAME_free (x_name);
530 static STACK_OF(X509) *
531 convert_certificate_chain_to_openssl (GTlsCertificateOpenssl *chain)
533 GTlsCertificate *cert;
534 STACK_OF(X509) *openssl_chain;
536 openssl_chain = sk_X509_new_null ();
538 for (cert = G_TLS_CERTIFICATE (chain); cert; cert = g_tls_certificate_get_issuer (cert))
539 sk_X509_push (openssl_chain, g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (cert)));
541 return openssl_chain;
544 static GTlsCertificateFlags
545 g_tls_file_database_openssl_verify_chain (GTlsDatabase *database,
546 GTlsCertificate *chain,
547 const gchar *purpose,
548 GSocketConnectable *identity,
549 GTlsInteraction *interaction,
550 GTlsDatabaseVerifyFlags flags,
551 GCancellable *cancellable,
554 GTlsFileDatabaseOpenssl *file_database;
555 GTlsFileDatabaseOpensslPrivate *priv;
556 STACK_OF(X509) *certs;
560 GTlsCertificateFlags result = 0;
562 g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
563 G_TLS_CERTIFICATE_GENERIC_ERROR);
565 file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
567 priv = g_tls_file_database_openssl_get_instance_private (file_database);
569 if (g_cancellable_set_error_if_cancelled (cancellable, error))
570 return G_TLS_CERTIFICATE_GENERIC_ERROR;
572 certs = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
574 store = X509_STORE_new ();
575 csc = X509_STORE_CTX_new ();
577 x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
578 if (!X509_STORE_CTX_init (csc, store, x, certs))
580 X509_STORE_CTX_free (csc);
581 X509_STORE_free (store);
582 sk_X509_free (certs);
583 return G_TLS_CERTIFICATE_GENERIC_ERROR;
588 X509_STORE_CTX_trusted_stack (csc, priv->trusted);
591 if (X509_verify_cert (csc) <= 0)
592 result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (csc));
594 X509_STORE_CTX_free (csc);
595 X509_STORE_free (store);
596 sk_X509_free (certs);
598 if (g_cancellable_set_error_if_cancelled (cancellable, error))
599 return G_TLS_CERTIFICATE_GENERIC_ERROR;
602 result |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (chain),
609 g_tls_file_database_openssl_class_init (GTlsFileDatabaseOpensslClass *klass)
611 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
612 GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
614 gobject_class->get_property = g_tls_file_database_openssl_get_property;
615 gobject_class->set_property = g_tls_file_database_openssl_set_property;
616 gobject_class->finalize = g_tls_file_database_openssl_finalize;
618 database_class->create_certificate_handle = g_tls_file_database_openssl_create_certificate_handle;
619 database_class->lookup_certificate_for_handle = g_tls_file_database_openssl_lookup_certificate_for_handle;
620 database_class->lookup_certificate_issuer = g_tls_file_database_openssl_lookup_certificate_issuer;
621 database_class->lookup_certificates_issued_by = g_tls_file_database_openssl_lookup_certificates_issued_by;
622 database_class->verify_chain = g_tls_file_database_openssl_verify_chain;
624 g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
628 g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface)
633 g_tls_file_database_openssl_initable_init (GInitable *initable,
634 GCancellable *cancellable,
637 GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (initable);
638 GTlsFileDatabaseOpensslPrivate *priv;
639 GHashTable *subjects, *issuers, *complete, *certs_by_handle;
642 priv = g_tls_file_database_openssl_get_instance_private (file_database);
644 if (g_cancellable_set_error_if_cancelled (cancellable, error))
647 subjects = bytes_multi_table_new ();
648 issuers = bytes_multi_table_new ();
650 complete = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
651 (GDestroyNotify)g_bytes_unref,
652 (GDestroyNotify)g_bytes_unref);
654 certs_by_handle = g_hash_table_new_full (g_str_hash, g_str_equal,
655 (GDestroyNotify)g_free,
656 (GDestroyNotify)g_object_unref);
658 if (priv->anchor_filename)
659 result = load_anchor_file (file_database,
660 priv->anchor_filename,
661 subjects, issuers, complete,
667 if (g_cancellable_set_error_if_cancelled (cancellable, error))
672 g_mutex_lock (&priv->mutex);
675 priv->subjects = subjects;
680 priv->issuers = issuers;
685 priv->complete = complete;
688 if (!priv->certs_by_handle)
690 priv->certs_by_handle = certs_by_handle;
691 certs_by_handle = NULL;
693 g_mutex_unlock (&priv->mutex);
696 if (subjects != NULL)
697 g_hash_table_unref (subjects);
699 g_hash_table_unref (issuers);
700 if (complete != NULL)
701 g_hash_table_unref (complete);
702 if (certs_by_handle != NULL)
703 g_hash_table_unref (certs_by_handle);
708 g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface)
710 iface->init = g_tls_file_database_openssl_initable_init;
714 g_tls_file_database_openssl_verify_ocsp_response (GTlsDatabase *database,
715 GTlsCertificate *chain,
718 GTlsCertificateFlags errors = 0;
719 #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
720 !defined(OPENSSL_NO_OCSP)
721 GTlsFileDatabaseOpenssl *file_database;
722 GTlsFileDatabaseOpensslPrivate *priv;
723 STACK_OF(X509) *chain_openssl = NULL;
724 X509_STORE *store = NULL;
725 OCSP_BASICRESP *basic_resp = NULL;
729 ocsp_status = OCSP_response_status (resp);
730 if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
732 errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
736 basic_resp = OCSP_response_get1_basic (resp);
737 if (basic_resp == NULL)
739 errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
743 chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
744 file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
745 priv = g_tls_file_database_openssl_get_instance_private (file_database);
746 store = X509_STORE_new ();
747 if ((chain_openssl == NULL) ||
748 (file_database == NULL) ||
750 (priv->trusted == NULL) ||
753 errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
757 for (i = 0; i < sk_X509_num (priv->trusted); i++)
759 X509_STORE_add_cert (store, sk_X509_value (priv->trusted, i));
762 if (OCSP_basic_verify (basic_resp, chain_openssl, store, 0) <= 0)
764 errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
768 for (i = 0; i < OCSP_resp_count (basic_resp); i++)
770 OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i);
771 ASN1_GENERALIZEDTIME *revocation_time = NULL;
772 ASN1_GENERALIZEDTIME *this_update_time = NULL;
773 ASN1_GENERALIZEDTIME *next_update_time = NULL;
777 if (single_resp == NULL)
780 cert_status = OCSP_single_get0_status (single_resp,
785 if (!OCSP_check_validity (this_update_time,
790 errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
796 case V_OCSP_CERTSTATUS_GOOD:
798 case V_OCSP_CERTSTATUS_REVOKED:
799 errors = G_TLS_CERTIFICATE_REVOKED;
801 case V_OCSP_CERTSTATUS_UNKNOWN:
802 errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
809 X509_STORE_free (store);
811 if (basic_resp != NULL)
812 OCSP_BASICRESP_free (basic_resp);
815 OCSP_RESPONSE_free (resp);