Add a GNUTLS-based GTlsBackend
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsbackend-gnutls.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2010 Red Hat, Inc
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #include "glib.h"
23
24 #include <errno.h>
25
26 #include <gnutls/gnutls.h>
27 #include <gcrypt.h>
28 #ifndef G_OS_WIN32
29 #include <pthread.h>
30 #endif
31
32 #include "gtlsbackend-gnutls.h"
33 #include "gtlscertificate-gnutls.h"
34 #include "gtlsclientconnection-gnutls.h"
35 #include "gtlsserverconnection-gnutls.h"
36
37 static void gtls_gnutls_init (void);
38 static void g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface);
39
40 G_DEFINE_DYNAMIC_TYPE_EXTENDED (GTlsBackendGnutls, g_tls_backend_gnutls, G_TYPE_OBJECT, 0,
41                                 G_IMPLEMENT_INTERFACE_DYNAMIC (G_TYPE_TLS_BACKEND,
42                                                                g_tls_backend_gnutls_interface_init);
43                                 gtls_gnutls_init ();)
44
45 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
46 GCRY_THREAD_OPTION_PTHREAD_IMPL;
47 #endif
48
49 #ifdef G_OS_WIN32
50
51 static int
52 gtls_gcry_win32_mutex_init (void **priv)
53 {
54         int err = 0;
55         CRITICAL_SECTION *lock = (CRITICAL_SECTION*)malloc (sizeof (CRITICAL_SECTION));
56
57         if (!lock)
58                 err = ENOMEM;
59         if (!err) {
60                 InitializeCriticalSection (lock);
61                 *priv = lock;
62         }
63         return err;
64 }
65
66 static int
67 gtls_gcry_win32_mutex_destroy (void **lock)
68 {
69         DeleteCriticalSection ((CRITICAL_SECTION*)*lock);
70         free (*lock);
71         return 0;
72 }
73
74 static int
75 gtls_gcry_win32_mutex_lock (void **lock)
76 {
77         EnterCriticalSection ((CRITICAL_SECTION*)*lock);
78         return 0;
79 }
80
81 static int
82 gtls_gcry_win32_mutex_unlock (void **lock)
83 {
84         LeaveCriticalSection ((CRITICAL_SECTION*)*lock);
85         return 0;
86 }
87
88
89 static struct gcry_thread_cbs gtls_gcry_threads_win32 = {                \
90         (GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)),   \
91         NULL, gtls_gcry_win32_mutex_init, gtls_gcry_win32_mutex_destroy, \
92         gtls_gcry_win32_mutex_lock, gtls_gcry_win32_mutex_unlock,        \
93         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
94
95 #endif
96
97 static void
98 gtls_gnutls_init (void)
99 {
100 #if defined(GCRY_THREAD_OPTION_PTHREAD_IMPL) && !defined(G_OS_WIN32)
101   gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
102 #elif defined(G_OS_WIN32)
103   gcry_control (GCRYCTL_SET_THREAD_CBS, &gtls_gcry_threads_win32);
104 #endif
105   gnutls_global_init ();
106 }
107
108 static void
109 g_tls_backend_gnutls_init (GTlsBackendGnutls *backend)
110 {
111 }
112
113 static void
114 g_tls_backend_gnutls_class_init (GTlsBackendGnutlsClass *backend_class)
115 {
116 }
117
118 static void
119 g_tls_backend_gnutls_class_finalize (GTlsBackendGnutlsClass *backend_class)
120 {
121 }
122
123 static void
124 g_tls_backend_gnutls_interface_init (GTlsBackendInterface *iface)
125 {
126   iface->get_certificate_type       = g_tls_certificate_gnutls_get_type;
127   iface->get_client_connection_type = g_tls_client_connection_gnutls_get_type;
128   iface->get_server_connection_type = g_tls_server_connection_gnutls_get_type;
129 }
130
131 #ifdef GTLS_SYSTEM_CA_FILE
132 /* Parsing the system CA list takes a noticeable amount of time.
133  * So we only do it once, and only when we actually need to see it.
134  */
135 static const GList *
136 get_ca_lists (gnutls_x509_crt_t **cas,
137               int                *num_cas)
138 {
139   static gnutls_x509_crt_t *ca_list_gnutls;
140   static int ca_list_length;
141   static GList *ca_list;
142
143   if (g_once_init_enter ((volatile gsize *)&ca_list_gnutls))
144     {
145       GError *error = NULL;
146       gnutls_x509_crt_t *x509_crts;
147       GList *c;
148       int i;
149
150       ca_list = g_tls_certificate_list_new_from_file (GTLS_SYSTEM_CA_FILE, &error);
151       if (error)
152         {
153           g_warning ("Failed to read system CA file %s: %s.",
154                      GTLS_SYSTEM_CA_FILE, error->message);
155           g_error_free (error);
156           /* Note that this is not a security problem, since if
157            * G_TLS_VALIDATE_CA is set, then this just means validation
158            * will always fail, and if it isn't set, then it doesn't
159            * matter that we couldn't read the CAs.
160            */
161         }
162
163       ca_list_length = g_list_length (ca_list);
164       x509_crts = g_new (gnutls_x509_crt_t, ca_list_length);
165       for (c = ca_list, i = 0; c; c = c->next, i++)
166         x509_crts[i] = g_tls_certificate_gnutls_get_cert (c->data);
167
168       g_once_init_leave ((volatile gsize *)&ca_list_gnutls, GPOINTER_TO_SIZE (x509_crts));
169     }
170
171   if (cas)
172     *cas = ca_list_gnutls;
173   if (num_cas)
174     *num_cas = ca_list_length;
175   
176   return ca_list;
177 }
178 #endif
179
180 const GList *
181 g_tls_backend_gnutls_get_system_ca_list_gtls (void)
182 {
183 #ifdef GTLS_SYSTEM_CA_FILE
184   return get_ca_lists (NULL, NULL);
185 #else
186   return NULL;
187 #endif
188 }
189
190 void
191 g_tls_backend_gnutls_get_system_ca_list_gnutls (gnutls_x509_crt_t **cas,
192                                                 int                *num_cas)
193 {
194 #ifdef GTLS_SYSTEM_CA_FILE
195   get_ca_lists (cas, num_cas);
196 #else
197   *cas = NULL;
198   *num_cas = 0;
199 #endif
200 }
201
202 void
203 g_tls_backend_gnutls_register (GIOModule *module)
204 {
205   g_tls_backend_gnutls_register_type (G_TYPE_MODULE (module));
206   g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME,
207                                   g_tls_backend_gnutls_get_type(),
208                                   "gnutls",
209                                   0);
210 }