Imported Upstream version 2.34.0
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsserverconnection-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, see
17  * <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21 #include "glib.h"
22
23 #include <errno.h>
24 #include <gnutls/gnutls.h>
25 #include <gnutls/x509.h>
26
27 #include "gtlsserverconnection-gnutls.h"
28 #include "gtlsbackend-gnutls.h"
29 #include "gtlscertificate-gnutls.h"
30 #include <glib/gi18n-lib.h>
31
32 enum
33 {
34   PROP_0,
35   PROP_AUTHENTICATION_MODE
36 };
37
38 static void     g_tls_server_connection_gnutls_initable_interface_init (GInitableIface  *iface);
39
40 static void g_tls_server_connection_gnutls_server_connection_interface_init (GTlsServerConnectionInterface *iface);
41
42 static int g_tls_server_connection_gnutls_retrieve_function (gnutls_session_t             session,
43                                                              const gnutls_datum_t        *req_ca_rdn,
44                                                              int                          nreqs,
45                                                              const gnutls_pk_algorithm_t *pk_algos,
46                                                              int                          pk_algos_length,
47                                                              gnutls_retr2_st             *st);
48
49 static int            g_tls_server_connection_gnutls_db_store    (void            *user_data,
50                                                                   gnutls_datum_t   key,
51                                                                   gnutls_datum_t   data);
52 static int            g_tls_server_connection_gnutls_db_remove   (void            *user_data,
53                                                                   gnutls_datum_t   key);
54 static gnutls_datum_t g_tls_server_connection_gnutls_db_retrieve (void            *user_data,
55                                                                   gnutls_datum_t   key);
56
57 static GInitableIface *g_tls_server_connection_gnutls_parent_initable_iface;
58
59 G_DEFINE_TYPE_WITH_CODE (GTlsServerConnectionGnutls, g_tls_server_connection_gnutls, G_TYPE_TLS_CONNECTION_GNUTLS,
60                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
61                                                 g_tls_server_connection_gnutls_initable_interface_init)
62                          G_IMPLEMENT_INTERFACE (G_TYPE_TLS_SERVER_CONNECTION,
63                                                 g_tls_server_connection_gnutls_server_connection_interface_init)
64 )
65
66 struct _GTlsServerConnectionGnutlsPrivate
67 {
68   GTlsAuthenticationMode authentication_mode;
69 };
70
71 static void
72 g_tls_server_connection_gnutls_init (GTlsServerConnectionGnutls *gnutls)
73 {
74   gnutls_certificate_credentials_t creds;
75   gnutls_session_t session;
76
77   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls, G_TYPE_TLS_SERVER_CONNECTION_GNUTLS, GTlsServerConnectionGnutlsPrivate);
78
79   creds = g_tls_connection_gnutls_get_credentials (G_TLS_CONNECTION_GNUTLS (gnutls));
80   gnutls_certificate_set_retrieve_function (creds, g_tls_server_connection_gnutls_retrieve_function);
81
82   session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (gnutls));
83   gnutls_db_set_retrieve_function (session, g_tls_server_connection_gnutls_db_retrieve);
84   gnutls_db_set_store_function (session, g_tls_server_connection_gnutls_db_store);
85   gnutls_db_set_remove_function (session, g_tls_server_connection_gnutls_db_remove);
86 }
87
88 static gboolean
89 g_tls_server_connection_gnutls_initable_init (GInitable       *initable,
90                                               GCancellable    *cancellable,
91                                               GError         **error)
92 {
93   GTlsCertificate *cert;
94
95   if (!g_tls_server_connection_gnutls_parent_initable_iface->
96       init (initable, cancellable, error))
97     return FALSE;
98
99   cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (initable));
100   if (cert && !g_tls_certificate_gnutls_has_key (G_TLS_CERTIFICATE_GNUTLS (cert)))
101     {
102       g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
103                            _("Certificate has no private key"));
104       return FALSE;
105     }
106
107   return TRUE;
108 }
109
110 static void
111 g_tls_server_connection_gnutls_get_property (GObject    *object,
112                                              guint       prop_id,
113                                              GValue     *value,
114                                              GParamSpec *pspec)
115 {
116   GTlsServerConnectionGnutls *gnutls = G_TLS_SERVER_CONNECTION_GNUTLS (object);
117
118   switch (prop_id)
119     {
120     case PROP_AUTHENTICATION_MODE:
121       g_value_set_enum (value, gnutls->priv->authentication_mode);
122       break;
123       
124     default:
125       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
126     }
127 }
128
129 static void
130 g_tls_server_connection_gnutls_set_property (GObject      *object,
131                                              guint         prop_id,
132                                              const GValue *value,
133                                              GParamSpec   *pspec)
134 {
135   GTlsServerConnectionGnutls *gnutls = G_TLS_SERVER_CONNECTION_GNUTLS (object);
136
137   switch (prop_id)
138     {
139     case PROP_AUTHENTICATION_MODE:
140       gnutls->priv->authentication_mode = g_value_get_enum (value);
141       break;
142
143     default:
144       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145     }
146 }
147
148 static int
149 g_tls_server_connection_gnutls_retrieve_function (gnutls_session_t             session,
150                                                   const gnutls_datum_t        *req_ca_rdn,
151                                                   int                          nreqs,
152                                                   const gnutls_pk_algorithm_t *pk_algos,
153                                                   int                          pk_algos_length,
154                                                   gnutls_retr2_st             *st)
155 {
156   g_tls_connection_gnutls_get_certificate (gnutls_transport_get_ptr (session), st);
157   return 0;
158 }
159
160 static void
161 g_tls_server_connection_gnutls_failed (GTlsConnectionGnutls *conn)
162 {
163   gnutls_db_remove_session (g_tls_connection_gnutls_get_session (conn));
164 }
165
166 static void
167 g_tls_server_connection_gnutls_begin_handshake (GTlsConnectionGnutls *conn)
168 {
169   GTlsServerConnectionGnutls *gnutls = G_TLS_SERVER_CONNECTION_GNUTLS (conn);
170   gnutls_session_t session;
171   gnutls_certificate_request_t req_mode;
172
173   switch (gnutls->priv->authentication_mode)
174     {
175     case G_TLS_AUTHENTICATION_REQUESTED:
176       req_mode = GNUTLS_CERT_REQUEST;
177       break;
178     case G_TLS_AUTHENTICATION_REQUIRED:
179       req_mode = GNUTLS_CERT_REQUIRE;
180       break;
181     default:
182       req_mode = GNUTLS_CERT_IGNORE;
183       break;
184     }
185
186   session = g_tls_connection_gnutls_get_session (conn);
187   gnutls_certificate_server_set_request (session, req_mode);
188 }
189
190 static void
191 g_tls_server_connection_gnutls_finish_handshake (GTlsConnectionGnutls  *gnutls,
192                                                  GError               **inout_error)
193 {
194 }
195
196 /* Session cache management */
197
198 static int
199 g_tls_server_connection_gnutls_db_store (void            *user_data,
200                                          gnutls_datum_t   key,
201                                          gnutls_datum_t   data)
202 {
203   GBytes *session_id, *session_data;
204
205   session_id = g_bytes_new (key.data, key.size);
206   session_data = g_bytes_new (data.data, data.size);
207   g_tls_backend_gnutls_store_session (GNUTLS_SERVER, session_id, session_data);
208   g_bytes_unref (session_id);
209   g_bytes_unref (session_data);
210
211   return 0;
212 }
213
214 static int
215 g_tls_server_connection_gnutls_db_remove (void            *user_data,
216                                           gnutls_datum_t   key)
217 {
218   GBytes *session_id;
219
220   session_id = g_bytes_new (key.data, key.size);
221   g_tls_backend_gnutls_remove_session (GNUTLS_SERVER, session_id);
222   g_bytes_unref (session_id);
223
224   return 0;
225 }
226
227 static gnutls_datum_t
228 g_tls_server_connection_gnutls_db_retrieve (void            *user_data,
229                                             gnutls_datum_t   key)
230 {
231   GBytes *session_id, *session_data;
232   gnutls_datum_t data;
233
234   session_id = g_bytes_new (key.data, key.size);
235   session_data = g_tls_backend_gnutls_lookup_session (GNUTLS_SERVER, session_id);
236   g_bytes_unref (session_id);
237
238   if (session_data)
239     {
240       data.size = g_bytes_get_size (session_data);
241       data.data = gnutls_malloc (data.size);
242       memcpy (data.data, g_bytes_get_data (session_data, NULL), data.size);
243       g_bytes_unref (session_data);
244     }
245   else
246     {
247       data.size = 0;
248       data.data = NULL;
249     }
250
251   return data;
252 }
253
254 static void
255 g_tls_server_connection_gnutls_class_init (GTlsServerConnectionGnutlsClass *klass)
256 {
257   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
258   GTlsConnectionGnutlsClass *connection_gnutls_class = G_TLS_CONNECTION_GNUTLS_CLASS (klass);
259
260   g_type_class_add_private (klass, sizeof (GTlsServerConnectionGnutlsPrivate));
261
262   gobject_class->get_property = g_tls_server_connection_gnutls_get_property;
263   gobject_class->set_property = g_tls_server_connection_gnutls_set_property;
264
265   connection_gnutls_class->failed           = g_tls_server_connection_gnutls_failed;
266   connection_gnutls_class->begin_handshake  = g_tls_server_connection_gnutls_begin_handshake;
267   connection_gnutls_class->finish_handshake = g_tls_server_connection_gnutls_finish_handshake;
268
269   g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode");
270 }
271
272 static void
273 g_tls_server_connection_gnutls_server_connection_interface_init (GTlsServerConnectionInterface *iface)
274 {
275 }
276
277 static void
278 g_tls_server_connection_gnutls_initable_interface_init (GInitableIface  *iface)
279 {
280   g_tls_server_connection_gnutls_parent_initable_iface = g_type_interface_peek_parent (iface);
281
282   iface->init = g_tls_server_connection_gnutls_initable_init;
283 }