openssl: remove manual check for certificate expiration
[platform/upstream/glib-networking.git] / tls / openssl / gtlsfiledatabase-openssl.c
1 /*
2  * gtlsfiledatabase-openssl.c
3  *
4  * Copyright (C) 2015 NICE s.r.l.
5  *
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.
10  *
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.
15  *
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/>.
18  *
19  * In addition, when the library is used with OpenSSL, a special
20  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
21  *
22  * Authors: Ignacio Casal Quinteiro
23  */
24
25 #include "config.h"
26
27 #include "gtlsfiledatabase-openssl.h"
28
29 #include <gio/gio.h>
30 #include <glib/gi18n-lib.h>
31 #include "openssl-include.h"
32
33 typedef struct _GTlsFileDatabaseOpensslPrivate
34 {
35   /* read-only after construct */
36   gchar *anchor_filename;
37   STACK_OF(X509) *trusted;
38
39   /* protected by mutex */
40   GMutex mutex;
41
42   /*
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
46    */
47   GHashTable *subjects;
48   GHashTable *issuers;
49
50   /*
51    * This is a table of GBytes -> GBytes. The values and keys are
52    * DER encoded certificate values.
53    */
54   GHashTable *complete;
55
56   /*
57    * This is a table of gchar * -> GTlsCertificate.
58    */
59   GHashTable *certs_by_handle;
60 } GTlsFileDatabaseOpensslPrivate;
61
62 enum {
63   STATUS_FAILURE,
64   STATUS_INCOMPLETE,
65   STATUS_SELFSIGNED,
66   STATUS_PINNED,
67   STATUS_ANCHORED,
68 };
69
70 enum
71 {
72   PROP_0,
73   PROP_ANCHORS,
74 };
75
76 static void g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface);
77
78 static void g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface);
79
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))
86
87 static GHashTable *
88 bytes_multi_table_new (void)
89 {
90   return g_hash_table_new_full (g_int_hash, g_int_equal,
91                                 (GDestroyNotify)g_free,
92                                 (GDestroyNotify)g_ptr_array_unref);
93 }
94
95 static void
96 bytes_multi_table_insert (GHashTable *table,
97                           gulong      key,
98                           GBytes     *value)
99 {
100   GPtrArray *multi;
101
102   multi = g_hash_table_lookup (table, &key);
103   if (multi == NULL)
104     {
105       int *key_ptr;
106
107       key_ptr = g_new (int, 1);
108       *key_ptr = (int)key;
109       multi = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
110       g_hash_table_insert (table, key_ptr, multi);
111     }
112   g_ptr_array_add (multi, g_bytes_ref (value));
113 }
114
115 static GBytes *
116 bytes_multi_table_lookup_ref_one (GHashTable *table,
117                                   gulong      key)
118 {
119   GPtrArray *multi;
120
121   multi = g_hash_table_lookup (table, &key);
122   if (multi == NULL)
123     return NULL;
124
125   g_assert (multi->len > 0);
126   return g_bytes_ref (multi->pdata[0]);
127 }
128
129 static GList *
130 bytes_multi_table_lookup_ref_all (GHashTable *table,
131                                   gulong      key)
132 {
133   GPtrArray *multi;
134   GList *list = NULL;
135   guint i;
136
137   multi = g_hash_table_lookup (table, &key);
138   if (multi == NULL)
139     return NULL;
140
141   for (i = 0; i < multi->len; i++)
142     list = g_list_prepend (list, g_bytes_ref (multi->pdata[i]));
143
144   return g_list_reverse (list);
145 }
146
147 static gchar *
148 create_handle_for_certificate (const gchar *filename,
149                                GBytes      *der)
150 {
151   gchar *bookmark;
152   gchar *uri_part;
153   gchar *uri;
154
155   /*
156    * Here we create a URI that looks like:
157    * file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
158    */
159
160   uri_part = g_filename_to_uri (filename, NULL, NULL);
161   if (!uri_part)
162     return NULL;
163
164   bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
165   uri = g_strconcat (uri_part, "#", bookmark, NULL);
166
167   g_free (bookmark);
168   g_free (uri_part);
169
170   return uri;
171 }
172
173 static gboolean
174 load_anchor_file (GTlsFileDatabaseOpenssl  *file_database,
175                   const gchar              *filename,
176                   GHashTable               *subjects,
177                   GHashTable               *issuers,
178                   GHashTable               *complete,
179                   GHashTable               *certs_by_handle,
180                   GError                  **error)
181 {
182   GTlsFileDatabaseOpensslPrivate *priv;
183   GList *list;
184   GList *l;
185   GBytes *der;
186   gchar *handle;
187   GError *my_error = NULL;
188
189   priv = g_tls_file_database_openssl_get_instance_private (file_database);
190
191   list = g_tls_certificate_list_new_from_file (filename, &my_error);
192   if (my_error)
193     {
194       g_propagate_error (error, my_error);
195       return FALSE;
196     }
197
198   for (l = list; l; l = l->next)
199     {
200       X509 *x;
201       unsigned long subject;
202       unsigned long issuer;
203
204       x = g_tls_certificate_openssl_get_cert (l->data);
205       subject = X509_subject_name_hash (x);
206       issuer = X509_issuer_name_hash (x);
207
208       der = g_tls_certificate_openssl_get_bytes (l->data);
209       g_return_val_if_fail (der != NULL, FALSE);
210
211       g_hash_table_insert (complete, g_bytes_ref (der),
212                            g_bytes_ref (der));
213
214       bytes_multi_table_insert (subjects, subject, der);
215       bytes_multi_table_insert (issuers, issuer, der);
216
217       handle = create_handle_for_certificate (priv->anchor_filename, der);
218       g_hash_table_insert (certs_by_handle, handle, g_object_ref (l->data));
219
220       g_bytes_unref (der);
221
222       g_object_unref (l->data);
223     }
224   g_list_free (list);
225
226   return TRUE;
227 }
228
229 static void
230 g_tls_file_database_openssl_finalize (GObject *object)
231 {
232   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
233   GTlsFileDatabaseOpensslPrivate *priv;
234
235   priv = g_tls_file_database_openssl_get_instance_private (file_database);
236
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);
241
242   g_free (priv->anchor_filename);
243   priv->anchor_filename = NULL;
244
245   if (priv->trusted != NULL)
246     sk_X509_pop_free (priv->trusted, X509_free);
247
248   g_mutex_clear (&priv->mutex);
249
250   G_OBJECT_CLASS (g_tls_file_database_openssl_parent_class)->finalize (object);
251 }
252
253 static void
254 g_tls_file_database_openssl_get_property (GObject    *object,
255                                           guint       prop_id,
256                                           GValue     *value,
257                                           GParamSpec *pspec)
258 {
259   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
260   GTlsFileDatabaseOpensslPrivate *priv;
261
262   priv = g_tls_file_database_openssl_get_instance_private (file_database);
263
264   switch (prop_id)
265     {
266     case PROP_ANCHORS:
267       g_value_set_string (value, priv->anchor_filename);
268       break;
269     default:
270       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271     }
272 }
273
274 static STACK_OF(X509) *
275 load_certs (const gchar *file_name)
276 {
277   BIO *bio;
278   STACK_OF(X509) *certs;
279   STACK_OF(X509_INFO) *xis = NULL;
280   gint i;
281
282   if (file_name == NULL)
283     return NULL;
284
285   bio = BIO_new_file (file_name, "rb");
286   if (bio == NULL)
287     return NULL;
288
289   xis = PEM_X509_INFO_read_bio (bio, NULL, NULL, NULL);
290
291   BIO_free (bio);
292
293   certs = sk_X509_new_null ();
294   if (certs == NULL)
295     goto end;
296
297   for (i = 0; i < sk_X509_INFO_num (xis); i++)
298     {
299       X509_INFO *xi;
300
301       xi = sk_X509_INFO_value (xis, i);
302       if (xi->x509 != NULL)
303         {
304           if (!sk_X509_push (certs, xi->x509))
305             goto end;
306           xi->x509 = NULL;
307         }
308     }
309
310 end:
311   sk_X509_INFO_pop_free (xis, X509_INFO_free);
312
313   if (sk_X509_num (certs) == 0)
314     {
315       sk_X509_pop_free (certs, X509_free);
316       certs = NULL;
317     }
318
319   return certs;
320 }
321
322 static void
323 g_tls_file_database_openssl_set_property (GObject      *object,
324                                           guint         prop_id,
325                                           const GValue *value,
326                                           GParamSpec   *pspec)
327 {
328   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (object);
329   GTlsFileDatabaseOpensslPrivate *priv;
330   const gchar *anchor_path;
331
332   priv = g_tls_file_database_openssl_get_instance_private (file_database);
333
334   switch (prop_id)
335     {
336     case PROP_ANCHORS:
337       anchor_path = g_value_get_string (value);
338       if (anchor_path && !g_path_is_absolute (anchor_path))
339         {
340           g_warning ("The anchor file name used with a GTlsFileDatabase "
341                      "must be an absolute path, and not relative: %s", anchor_path);
342           return;
343         }
344
345       if (priv->anchor_filename)
346         {
347           g_free (priv->anchor_filename);
348           if (priv->trusted != NULL)
349             sk_X509_pop_free (priv->trusted, X509_free);
350         }
351
352       priv->anchor_filename = g_strdup (anchor_path);
353       priv->trusted = load_certs (anchor_path);
354       break;
355     default:
356       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
357     }
358 }
359
360 static void
361 g_tls_file_database_openssl_init (GTlsFileDatabaseOpenssl *file_database)
362 {
363   GTlsFileDatabaseOpensslPrivate *priv;
364
365   priv = g_tls_file_database_openssl_get_instance_private (file_database);
366
367   g_mutex_init (&priv->mutex);
368 }
369
370 static gchar *
371 g_tls_file_database_openssl_create_certificate_handle (GTlsDatabase    *database,
372                                                        GTlsCertificate *certificate)
373 {
374   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
375   GTlsFileDatabaseOpensslPrivate *priv;
376   GBytes *der;
377   gboolean contains;
378   gchar *handle = NULL;
379
380   priv = g_tls_file_database_openssl_get_instance_private (file_database);
381
382   der = g_tls_certificate_openssl_get_bytes (G_TLS_CERTIFICATE_OPENSSL (certificate));
383   g_return_val_if_fail (der != NULL, FALSE);
384
385   g_mutex_lock (&priv->mutex);
386
387   /* At the same time look up whether this certificate is in list */
388   contains = g_hash_table_lookup (priv->complete, der) ? TRUE : FALSE;
389
390   g_mutex_unlock (&priv->mutex);
391
392   /* Certificate is in the database */
393   if (contains)
394     handle = create_handle_for_certificate (priv->anchor_filename, der);
395
396   g_bytes_unref (der);
397   return handle;
398 }
399
400 static GTlsCertificate *
401 g_tls_file_database_openssl_lookup_certificate_for_handle (GTlsDatabase            *database,
402                                                            const gchar             *handle,
403                                                            GTlsInteraction         *interaction,
404                                                            GTlsDatabaseLookupFlags  flags,
405                                                            GCancellable            *cancellable,
406                                                            GError                 **error)
407 {
408   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
409   GTlsFileDatabaseOpensslPrivate *priv;
410   GTlsCertificate *cert;
411
412   priv = g_tls_file_database_openssl_get_instance_private (file_database);
413
414   if (g_cancellable_set_error_if_cancelled (cancellable, error))
415     return NULL;
416
417   if (!handle)
418     return NULL;
419
420   g_mutex_lock (&priv->mutex);
421
422   cert = g_hash_table_lookup (priv->certs_by_handle, handle);
423
424   g_mutex_unlock (&priv->mutex);
425
426   return cert ? g_object_ref (cert) : NULL;
427 }
428
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,
435                                                        GError                  **error)
436 {
437   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
438   GTlsFileDatabaseOpensslPrivate *priv;
439   X509 *x;
440   unsigned long issuer_hash;
441   GBytes *der;
442   GTlsCertificate *issuer = NULL;
443
444   priv = g_tls_file_database_openssl_get_instance_private (file_database);
445
446   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (certificate), NULL);
447
448   if (g_cancellable_set_error_if_cancelled (cancellable, error))
449     return NULL;
450
451   if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
452     return NULL;
453
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);
457
458   g_mutex_lock (&priv->mutex);
459   der = bytes_multi_table_lookup_ref_one (priv->subjects, issuer_hash);
460   g_mutex_unlock (&priv->mutex);
461
462   if (g_cancellable_set_error_if_cancelled (cancellable, error))
463     issuer = NULL;
464   else if (der != NULL)
465     issuer = g_tls_certificate_openssl_new (der, NULL);
466
467   if (der != NULL)
468     g_bytes_unref (der);
469   return issuer;
470
471   return NULL;
472 }
473
474 static GList *
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,
480                                                            GError                  **error)
481 {
482   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
483   GTlsFileDatabaseOpensslPrivate *priv;
484   X509_NAME *x_name;
485   const unsigned char *in;
486   GList *issued = NULL;
487
488   priv = g_tls_file_database_openssl_get_instance_private (file_database);
489
490   if (g_cancellable_set_error_if_cancelled (cancellable, error))
491     return NULL;
492
493   /* We don't have any private keys here */
494   if (flags & G_TLS_DATABASE_LOOKUP_KEYPAIR)
495     return NULL;
496
497   in = issuer_raw_dn->data;
498   x_name = d2i_X509_NAME (NULL, &in, issuer_raw_dn->len);
499   if (x_name != NULL)
500     {
501       unsigned long issuer_hash;
502       GList *ders, *l;
503
504       issuer_hash = X509_NAME_hash (x_name);
505
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);
510
511       for (l = ders; l != NULL; l = g_list_next (l))
512         {
513           if (g_cancellable_set_error_if_cancelled (cancellable, error))
514             {
515               g_list_free_full (issued, g_object_unref);
516               issued = NULL;
517               break;
518             }
519
520           issued = g_list_prepend (issued, g_tls_certificate_openssl_new (l->data, NULL));
521         }
522
523       g_list_free_full (ders, (GDestroyNotify)g_bytes_unref);
524       X509_NAME_free (x_name);
525     }
526
527   return issued;
528 }
529
530 static STACK_OF(X509) *
531 convert_certificate_chain_to_openssl (GTlsCertificateOpenssl *chain)
532 {
533   GTlsCertificate *cert;
534   STACK_OF(X509) *openssl_chain;
535
536   openssl_chain = sk_X509_new_null ();
537
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)));
540
541   return openssl_chain;
542 }
543
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,
552                                           GError                  **error)
553 {
554   GTlsFileDatabaseOpenssl *file_database;
555   GTlsFileDatabaseOpensslPrivate *priv;
556   STACK_OF(X509) *certs;
557   X509_STORE *store;
558   X509_STORE_CTX *csc;
559   X509 *x;
560   GTlsCertificateFlags result = 0;
561
562   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (chain),
563                         G_TLS_CERTIFICATE_GENERIC_ERROR);
564
565   file_database = G_TLS_FILE_DATABASE_OPENSSL (database);
566
567   priv = g_tls_file_database_openssl_get_instance_private (file_database);
568
569   if (g_cancellable_set_error_if_cancelled (cancellable, error))
570     return G_TLS_CERTIFICATE_GENERIC_ERROR;
571
572   certs = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain));
573
574   store = X509_STORE_new ();
575   csc = X509_STORE_CTX_new ();
576
577   x = g_tls_certificate_openssl_get_cert (G_TLS_CERTIFICATE_OPENSSL (chain));
578   if (!X509_STORE_CTX_init (csc, store, x, certs))
579     {
580       X509_STORE_CTX_free (csc);
581       X509_STORE_free (store);
582       sk_X509_free (certs);
583       return G_TLS_CERTIFICATE_GENERIC_ERROR;
584     }
585
586   if (priv->trusted)
587     {
588       X509_STORE_CTX_trusted_stack (csc, priv->trusted);
589     }
590
591   if (X509_verify_cert (csc) <= 0)
592     result = g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (csc));
593
594   X509_STORE_CTX_free (csc);
595   X509_STORE_free (store);
596   sk_X509_free (certs);
597
598   if (g_cancellable_set_error_if_cancelled (cancellable, error))
599     return G_TLS_CERTIFICATE_GENERIC_ERROR;
600
601   if (identity)
602     result |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (chain),
603                                                          identity);
604
605   return result;
606 }
607
608 static void
609 g_tls_file_database_openssl_class_init (GTlsFileDatabaseOpensslClass *klass)
610 {
611   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
612   GTlsDatabaseClass *database_class = G_TLS_DATABASE_CLASS (klass);
613
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;
617
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;
623
624   g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
625 }
626
627 static void
628 g_tls_file_database_openssl_file_database_interface_init (GTlsFileDatabaseInterface *iface)
629 {
630 }
631
632 static gboolean
633 g_tls_file_database_openssl_initable_init (GInitable    *initable,
634                                            GCancellable *cancellable,
635                                            GError      **error)
636 {
637   GTlsFileDatabaseOpenssl *file_database = G_TLS_FILE_DATABASE_OPENSSL (initable);
638   GTlsFileDatabaseOpensslPrivate *priv;
639   GHashTable *subjects, *issuers, *complete, *certs_by_handle;
640   gboolean result;
641
642   priv = g_tls_file_database_openssl_get_instance_private (file_database);
643
644   if (g_cancellable_set_error_if_cancelled (cancellable, error))
645     return FALSE;
646
647   subjects = bytes_multi_table_new ();
648   issuers = bytes_multi_table_new ();
649
650   complete = g_hash_table_new_full (g_bytes_hash, g_bytes_equal,
651                                     (GDestroyNotify)g_bytes_unref,
652                                     (GDestroyNotify)g_bytes_unref);
653
654   certs_by_handle = g_hash_table_new_full (g_str_hash, g_str_equal,
655                                            (GDestroyNotify)g_free,
656                                            (GDestroyNotify)g_object_unref);
657
658   if (priv->anchor_filename)
659     result = load_anchor_file (file_database,
660                                priv->anchor_filename,
661                                subjects, issuers, complete,
662                                certs_by_handle,
663                                error);
664   else
665     result = TRUE;
666
667   if (g_cancellable_set_error_if_cancelled (cancellable, error))
668     result = FALSE;
669
670   if (result)
671     {
672       g_mutex_lock (&priv->mutex);
673       if (!priv->subjects)
674         {
675           priv->subjects = subjects;
676           subjects = NULL;
677         }
678       if (!priv->issuers)
679         {
680           priv->issuers = issuers;
681           issuers = NULL;
682         }
683       if (!priv->complete)
684         {
685           priv->complete = complete;
686           complete = NULL;
687         }
688       if (!priv->certs_by_handle)
689         {
690           priv->certs_by_handle = certs_by_handle;
691           certs_by_handle = NULL;
692         }
693       g_mutex_unlock (&priv->mutex);
694     }
695
696   if (subjects != NULL)
697     g_hash_table_unref (subjects);
698   if (issuers != NULL)
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);
704   return result;
705 }
706
707 static void
708 g_tls_file_database_openssl_initable_interface_init (GInitableIface *iface)
709 {
710   iface->init = g_tls_file_database_openssl_initable_init;
711 }
712
713 GTlsCertificateFlags
714 g_tls_file_database_openssl_verify_ocsp_response (GTlsDatabase    *database,
715                                                   GTlsCertificate *chain,
716                                                   OCSP_RESPONSE   *resp)
717 {
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;
726   int ocsp_status = 0;
727   int i;
728
729   ocsp_status = OCSP_response_status (resp);
730   if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL)
731     {
732       errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
733       goto end;
734     }
735
736   basic_resp = OCSP_response_get1_basic (resp);
737   if (basic_resp == NULL)
738     {
739       errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
740       goto end;
741     }
742
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) ||
749       (priv == NULL) ||
750       (priv->trusted == NULL) ||
751       (store == NULL))
752     {
753       errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
754       goto end;
755     }
756
757   for (i = 0; i < sk_X509_num (priv->trusted); i++)
758     {
759       X509_STORE_add_cert (store, sk_X509_value (priv->trusted, i));
760     }
761
762   if (OCSP_basic_verify (basic_resp, chain_openssl, store, 0) <= 0)
763     {
764       errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
765       goto end;
766     }
767
768   for (i = 0; i < OCSP_resp_count (basic_resp); i++)
769     {
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;
774       int crl_reason = 0;
775       int cert_status = 0;
776
777       if (single_resp == NULL)
778         continue;
779
780       cert_status = OCSP_single_get0_status (single_resp,
781                                              &crl_reason,
782                                              &revocation_time,
783                                              &this_update_time,
784                                              &next_update_time);
785       if (!OCSP_check_validity (this_update_time,
786                                 next_update_time,
787                                 300L,
788                                 -1L))
789         {
790           errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
791           goto end;
792         }
793
794       switch (cert_status)
795         {
796         case V_OCSP_CERTSTATUS_GOOD:
797           break;
798         case V_OCSP_CERTSTATUS_REVOKED:
799           errors = G_TLS_CERTIFICATE_REVOKED;
800           goto end;
801         case V_OCSP_CERTSTATUS_UNKNOWN:
802           errors = G_TLS_CERTIFICATE_GENERIC_ERROR;
803           goto end;
804         }
805     }
806
807 end:
808   if (store != NULL)
809     X509_STORE_free (store);
810
811   if (basic_resp != NULL)
812     OCSP_BASICRESP_free (basic_resp);
813
814   if (resp != NULL)
815     OCSP_RESPONSE_free (resp);
816
817 #endif
818   return errors;
819 }