d9a22f5084a29e119325da1940b95e48e1fff0b6
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsfiledatabase-gnutls.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright 2010 Collabora, Ltd
6  * Copyright 2018 Igalia S.L.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but 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.
17  *
18  * You should have received a copy of the GNU Lesser General
19  * Public License along with this library; if not, see
20  * <http://www.gnu.org/licenses/>.
21  *
22  * In addition, when the library is used with OpenSSL, a special
23  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
24  *
25  * Author: Stef Walter <stefw@collabora.co.uk>
26  */
27
28 #include "config.h"
29
30 #include "gtlsfiledatabase-gnutls.h"
31
32 #include <gio/gio.h>
33 #include <glib/gi18n-lib.h>
34
35 #include "gtlscertificate-gnutls.h"
36
37 enum
38 {
39   PROP_0,
40   PROP_ANCHORS,
41 };
42
43 struct _GTlsFileDatabaseGnutls
44 {
45   GTlsDatabaseGnutls parent_instance;
46
47   /* read-only after construct */
48   gchar *anchor_filename;
49 };
50
51 static void g_tls_file_database_gnutls_file_database_interface_init (GTlsFileDatabaseInterface *iface);
52
53 G_DEFINE_TYPE_WITH_CODE (GTlsFileDatabaseGnutls, g_tls_file_database_gnutls, G_TYPE_TLS_DATABASE_GNUTLS,
54                          G_IMPLEMENT_INTERFACE (G_TYPE_TLS_FILE_DATABASE,
55                                                 g_tls_file_database_gnutls_file_database_interface_init);
56                          );
57
58 static void
59 g_tls_file_database_gnutls_finalize (GObject *object)
60 {
61   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (object);
62
63   g_clear_pointer (&self->anchor_filename, g_free);
64
65   G_OBJECT_CLASS (g_tls_file_database_gnutls_parent_class)->finalize (object);
66 }
67
68 static void
69 g_tls_file_database_gnutls_get_property (GObject    *object,
70                                          guint       prop_id,
71                                          GValue     *value,
72                                          GParamSpec *pspec)
73 {
74   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (object);
75
76   switch (prop_id)
77     {
78     case PROP_ANCHORS:
79       g_value_set_string (value, self->anchor_filename);
80       break;
81     default:
82       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
83     }
84 }
85
86 static void
87 g_tls_file_database_gnutls_set_property (GObject      *object,
88                                          guint         prop_id,
89                                          const GValue *value,
90                                          GParamSpec   *pspec)
91 {
92   GTlsFileDatabaseGnutls *self = G_TLS_FILE_DATABASE_GNUTLS (object);
93   const char *anchor_path;
94
95   switch (prop_id)
96     {
97     case PROP_ANCHORS:
98       anchor_path = g_value_get_string (value);
99       if (anchor_path && !g_path_is_absolute (anchor_path))
100         {
101           g_warning ("The anchor file name used with a GTlsFileDatabase "
102                      "must be an absolute path, and not relative: %s", anchor_path);
103           return;
104         }
105
106       g_free (self->anchor_filename);
107       self->anchor_filename = g_strdup (anchor_path);
108       break;
109     default:
110       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
111     }
112 }
113
114 static gchar *
115 g_tls_file_database_gnutls_create_handle_for_certificate (GTlsDatabaseGnutls *self,
116                                                           GBytes             *der)
117 {
118   gchar *bookmark;
119   gchar *uri_part;
120   gchar *uri;
121
122   /*
123    * Here we create a URI that looks like
124    * file:///etc/ssl/certs/ca-certificates.crt#11b2641821252596420e468c275771f5e51022c121a17bd7a89a2f37b6336c8f
125    */
126
127   uri_part = g_filename_to_uri (G_TLS_FILE_DATABASE_GNUTLS (self)->anchor_filename,
128                                 NULL, NULL);
129   if (!uri_part)
130     return NULL;
131
132   bookmark = g_compute_checksum_for_bytes (G_CHECKSUM_SHA256, der);
133   uri = g_strconcat (uri_part, "#", bookmark, NULL);
134
135   g_free (bookmark);
136   g_free (uri_part);
137
138   return uri;
139 }
140
141 static gboolean
142 g_tls_file_database_gnutls_populate_trust_list (GTlsDatabaseGnutls        *self,
143                                                 gnutls_x509_trust_list_t   trust_list,
144                                                 GError                   **error)
145 {
146   int ret = gnutls_x509_trust_list_add_trust_file (trust_list,
147                                                    G_TLS_FILE_DATABASE_GNUTLS (self)->anchor_filename,
148                                                    NULL, GNUTLS_X509_FMT_PEM, 0, 0);
149
150   if (ret < 0)
151     {
152       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
153                    _("Failed to populate trust list from %s: %s"),
154                    G_TLS_FILE_DATABASE_GNUTLS (self)->anchor_filename, gnutls_strerror (ret));
155       return FALSE;
156     }
157
158   return TRUE;
159 }
160
161 static void
162 g_tls_file_database_gnutls_init (GTlsFileDatabaseGnutls *self)
163 {
164 }
165
166 static void
167 g_tls_file_database_gnutls_class_init (GTlsFileDatabaseGnutlsClass *klass)
168 {
169   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
170   GTlsDatabaseGnutlsClass *gnutls_database_class = G_TLS_DATABASE_GNUTLS_CLASS (klass);
171
172   gobject_class->get_property = g_tls_file_database_gnutls_get_property;
173   gobject_class->set_property = g_tls_file_database_gnutls_set_property;
174   gobject_class->finalize     = g_tls_file_database_gnutls_finalize;
175
176   gnutls_database_class->create_handle_for_certificate = g_tls_file_database_gnutls_create_handle_for_certificate;
177   gnutls_database_class->populate_trust_list           = g_tls_file_database_gnutls_populate_trust_list;
178
179   g_object_class_override_property (gobject_class, PROP_ANCHORS, "anchors");
180 }
181
182 static void
183 g_tls_file_database_gnutls_file_database_interface_init (GTlsFileDatabaseInterface *iface)
184 {
185 }