gnutls: finish implementing GTlsRehandshakeMode
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsconnection-gnutls.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2009 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 #include <gnutls/gnutls.h>
26 #include <gnutls/x509.h>
27
28 #include "gtlsconnection-gnutls.h"
29 #include "gtlsbackend-gnutls.h"
30 #include "gtlscertificate-gnutls.h"
31 #include "gtlsinputstream-gnutls.h"
32 #include "gtlsoutputstream-gnutls.h"
33 #include "gtlsserverconnection-gnutls.h"
34 #include <glib/gi18n-lib.h>
35
36 static void g_tls_connection_gnutls_get_property (GObject    *object,
37                                                   guint       prop_id,
38                                                   GValue     *value,
39                                                   GParamSpec *pspec);
40 static void g_tls_connection_gnutls_set_property (GObject      *object,
41                                                   guint         prop_id,
42                                                   const GValue *value,
43                                                   GParamSpec   *pspec);
44 static void g_tls_connection_gnutls_finalize     (GObject      *object);
45
46 static gboolean     g_tls_connection_gnutls_handshake        (GTlsConnection       *connection,
47                                                               GCancellable         *cancellable,
48                                                               GError              **error);
49 static void         g_tls_connection_gnutls_handshake_async  (GTlsConnection       *conn,
50                                                               int                   io_priority,
51                                                               GCancellable         *cancellable,
52                                                               GAsyncReadyCallback   callback,
53                                                               gpointer              user_data);
54 static gboolean     g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
55                                                               GAsyncResult         *result,
56                                                               GError              **error);
57
58 static GInputStream  *g_tls_connection_gnutls_get_input_stream  (GIOStream *stream);
59 static GOutputStream *g_tls_connection_gnutls_get_output_stream (GIOStream *stream);
60
61 static gboolean     g_tls_connection_gnutls_close        (GIOStream           *stream,
62                                                           GCancellable        *cancellable,
63                                                           GError             **error);
64 static void         g_tls_connection_gnutls_close_async  (GIOStream           *stream,
65                                                           int                  io_priority,
66                                                           GCancellable        *cancellable,
67                                                           GAsyncReadyCallback  callback,
68                                                           gpointer             user_data);
69 static gboolean     g_tls_connection_gnutls_close_finish (GIOStream           *stream,
70                                                           GAsyncResult        *result,
71                                                           GError             **error);
72
73 static ssize_t g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
74                                                   const void             *buf,
75                                                   size_t                  buflen);
76 static ssize_t g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
77                                                   void                   *buf,
78                                                   size_t                  buflen);
79
80 static void     g_tls_connection_gnutls_initable_iface_init (GInitableIface  *iface);
81 static gboolean g_tls_connection_gnutls_initable_init       (GInitable       *initable,
82                                                              GCancellable    *cancellable,
83                                                              GError         **error);
84
85 static void g_tls_connection_gnutls_init_priorities (void);
86
87 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionGnutls, g_tls_connection_gnutls, G_TYPE_TLS_CONNECTION,
88                                   G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
89                                                          g_tls_connection_gnutls_initable_iface_init);
90                                   g_tls_connection_gnutls_init_priorities ();
91                                   );
92
93
94 enum
95 {
96   PROP_0,
97   PROP_BASE_IO_STREAM,
98   PROP_REQUIRE_CLOSE_NOTIFY,
99   PROP_REHANDSHAKE_MODE
100 };
101
102 struct _GTlsConnectionGnutlsPrivate
103 {
104   GIOStream *base_io_stream;
105   GPollableInputStream *base_istream;
106   GPollableOutputStream *base_ostream;
107
108   GList *ca_list;
109   gnutls_certificate_credentials creds;
110   gnutls_session session;
111   gboolean require_close_notify;
112   GTlsRehandshakeMode rehandshake_mode;
113   gboolean need_handshake, handshaking, ever_handshaked;
114   gboolean closing;
115
116   GInputStream *tls_istream;
117   GOutputStream *tls_ostream;
118
119   GError *error;
120   GCancellable *cancellable;
121   gboolean blocking, eof;
122   GIOCondition internal_direction;
123 };
124
125 static void
126 g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
127 {
128   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129   GTlsConnectionClass *connection_class = G_TLS_CONNECTION_CLASS (klass);
130   GIOStreamClass *iostream_class = G_IO_STREAM_CLASS (klass);
131
132   g_type_class_add_private (klass, sizeof (GTlsConnectionGnutlsPrivate));
133
134   gobject_class->get_property = g_tls_connection_gnutls_get_property;
135   gobject_class->set_property = g_tls_connection_gnutls_set_property;
136   gobject_class->finalize     = g_tls_connection_gnutls_finalize;
137
138   connection_class->handshake        = g_tls_connection_gnutls_handshake;
139   connection_class->handshake_async  = g_tls_connection_gnutls_handshake_async;
140   connection_class->handshake_finish = g_tls_connection_gnutls_handshake_finish;
141
142   iostream_class->get_input_stream  = g_tls_connection_gnutls_get_input_stream;
143   iostream_class->get_output_stream = g_tls_connection_gnutls_get_output_stream;
144   iostream_class->close_fn          = g_tls_connection_gnutls_close;
145   iostream_class->close_async       = g_tls_connection_gnutls_close_async;
146   iostream_class->close_finish      = g_tls_connection_gnutls_close_finish;
147
148   g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
149   g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
150   g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode");
151 }
152
153 static void
154 g_tls_connection_gnutls_initable_iface_init (GInitableIface *iface)
155 {
156   iface->init = g_tls_connection_gnutls_initable_init;
157 }
158
159 static void
160 g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
161 {
162   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls, G_TYPE_TLS_CONNECTION_GNUTLS, GTlsConnectionGnutlsPrivate);
163
164   gnutls_certificate_allocate_credentials (&gnutls->priv->creds);
165   gnutls_certificate_set_verify_flags (gnutls->priv->creds,
166                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
167
168   gnutls->priv->need_handshake = TRUE;
169 }
170
171 static gnutls_priority_t priorities[2][2];
172
173 static void
174 g_tls_connection_gnutls_init_priorities (void)
175 {
176   /* First field is "ssl3 only", second is "allow unsafe rehandshaking" */
177
178   gnutls_priority_init (&priorities[FALSE][FALSE],
179                         "NORMAL",
180                         NULL);
181   gnutls_priority_init (&priorities[TRUE][FALSE],
182                         "NORMAL:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0",
183                         NULL);
184   gnutls_priority_init (&priorities[FALSE][TRUE],
185                         "NORMAL:%UNSAFE_RENEGOTIATION",
186                         NULL);
187   gnutls_priority_init (&priorities[TRUE][TRUE],
188                         "NORMAL:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0:%UNSAFE_RENEGOTIATION",
189                         NULL);
190 }
191
192 static void
193 g_tls_connection_gnutls_set_handshake_priority (GTlsConnectionGnutls *gnutls)
194 {
195   gboolean use_ssl3, unsafe_rehandshake;
196
197   if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
198     use_ssl3 = g_tls_client_connection_get_use_ssl3 (G_TLS_CLIENT_CONNECTION (gnutls));
199   unsafe_rehandshake = (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_UNSAFELY);
200   gnutls_priority_set (gnutls->priv->session,
201                        priorities[use_ssl3][unsafe_rehandshake]);
202 }
203
204 static gboolean
205 g_tls_connection_gnutls_initable_init (GInitable     *initable,
206                                        GCancellable  *cancellable,
207                                        GError       **error)
208 {
209   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
210   gnutls_x509_crt_t *cas;
211   int num_cas;
212   int status;
213
214   g_return_val_if_fail (gnutls->priv->base_istream != NULL &&
215                         gnutls->priv->base_ostream != NULL, FALSE);
216
217   /* Make sure gnutls->priv->session has been initialized (it may have
218    * already been initialized by a construct-time property setter).
219    */
220   g_tls_connection_gnutls_get_session (gnutls);
221
222   g_tls_backend_gnutls_get_system_ca_list_gnutls (&cas, &num_cas);
223   gnutls_certificate_set_x509_trust (gnutls->priv->creds, cas, num_cas);
224
225   status = gnutls_credentials_set (gnutls->priv->session,
226                                    GNUTLS_CRD_CERTIFICATE,
227                                    gnutls->priv->creds);
228   if (status != 0)
229     {
230       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
231                    _("Could not create TLS connection: %s"),
232                    gnutls_strerror (status));
233       return FALSE;
234     }
235
236   gnutls_transport_set_push_function (gnutls->priv->session,
237                                       g_tls_connection_gnutls_push_func);
238   gnutls_transport_set_pull_function (gnutls->priv->session,
239                                       g_tls_connection_gnutls_pull_func);
240   gnutls_transport_set_ptr (gnutls->priv->session, gnutls);
241
242   gnutls->priv->tls_istream = g_tls_input_stream_gnutls_new (gnutls);
243   gnutls->priv->tls_ostream = g_tls_output_stream_gnutls_new (gnutls);
244
245   return TRUE;
246 }
247
248 static void
249 g_tls_connection_gnutls_finalize (GObject *object)
250 {
251   GTlsConnectionGnutls *connection = G_TLS_CONNECTION_GNUTLS (object);
252
253   if (connection->priv->base_io_stream)
254     g_object_unref (connection->priv->base_io_stream);
255
256   if (connection->priv->session)
257     gnutls_deinit (connection->priv->session);
258
259   if (connection->priv->tls_istream)
260     g_object_unref (connection->priv->tls_istream);
261   if (connection->priv->tls_ostream) 
262     g_object_unref (connection->priv->tls_ostream);
263
264   if (connection->priv->creds)
265     gnutls_certificate_free_credentials (connection->priv->creds);
266
267   if (connection->priv->error)
268     g_error_free (connection->priv->error);
269
270   G_OBJECT_CLASS (g_tls_connection_gnutls_parent_class)->finalize (object);
271 }
272
273 static void
274 g_tls_connection_gnutls_get_property (GObject    *object,
275                                       guint       prop_id,
276                                       GValue     *value,
277                                       GParamSpec *pspec)
278 {
279   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
280
281   switch (prop_id)
282     {
283     case PROP_BASE_IO_STREAM:
284       g_value_set_object (value, gnutls->priv->base_io_stream);
285       break;
286
287     case PROP_REQUIRE_CLOSE_NOTIFY:
288       g_value_set_boolean (value, gnutls->priv->require_close_notify);
289       break;
290
291     case PROP_REHANDSHAKE_MODE:
292       g_value_set_enum (value, gnutls->priv->rehandshake_mode);
293       break;
294
295     default:
296       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
297     }
298 }
299
300 static void
301 g_tls_connection_gnutls_set_property (GObject      *object,
302                                       guint         prop_id,
303                                       const GValue *value,
304                                       GParamSpec   *pspec)
305 {
306   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
307   GInputStream *istream;
308   GOutputStream *ostream;
309
310   switch (prop_id)
311     {
312     case PROP_BASE_IO_STREAM:
313       if (gnutls->priv->base_io_stream)
314         {
315           g_object_unref (gnutls->priv->base_io_stream);
316           gnutls->priv->base_istream = NULL;
317           gnutls->priv->base_ostream = NULL;
318         }
319       gnutls->priv->base_io_stream = g_value_dup_object (value);
320       if (!gnutls->priv->base_io_stream)
321         return;
322
323       istream = g_io_stream_get_input_stream (gnutls->priv->base_io_stream);
324       ostream = g_io_stream_get_output_stream (gnutls->priv->base_io_stream);
325
326       if (G_IS_POLLABLE_INPUT_STREAM (istream) &&
327           g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (istream)))
328         gnutls->priv->base_istream = G_POLLABLE_INPUT_STREAM (istream);
329       if (G_IS_POLLABLE_OUTPUT_STREAM (ostream) &&
330           g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (ostream)))
331         gnutls->priv->base_ostream = G_POLLABLE_OUTPUT_STREAM (ostream);
332       break;
333
334     case PROP_REQUIRE_CLOSE_NOTIFY:
335       gnutls->priv->require_close_notify = g_value_get_boolean (value);
336       break;
337
338     case PROP_REHANDSHAKE_MODE:
339       gnutls->priv->rehandshake_mode = g_value_get_enum (value);
340       break;
341
342     default:
343       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
344     }
345 }
346
347 gnutls_certificate_credentials
348 g_tls_connection_gnutls_get_credentials (GTlsConnectionGnutls *gnutls)
349 {
350   return gnutls->priv->creds;
351 }
352
353 gnutls_session
354 g_tls_connection_gnutls_get_session (GTlsConnectionGnutls *gnutls)
355 {
356   /* Ideally we would initialize gnutls->priv->session from
357    * g_tls_connection_gnutls_init(), but we can't tell if it's a
358    * client or server connection at that point... And
359    * g_tls_connection_gnutls_initiable_init() is too late, because
360    * construct-time property setters may need to modify it.
361    */
362   if (!gnutls->priv->session)
363     {
364       gboolean client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
365       gnutls_init (&gnutls->priv->session, client ? GNUTLS_CLIENT : GNUTLS_SERVER);
366     }
367
368   return gnutls->priv->session;
369 }
370
371 void
372 g_tls_connection_gnutls_get_certificate (GTlsConnectionGnutls *gnutls,
373                                          gnutls_retr_st       *st)
374 {
375   GTlsCertificate *cert;
376
377   cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (gnutls));
378   if (cert)
379     g_object_ref (cert);
380   else
381     cert = g_tls_connection_emit_need_certificate (G_TLS_CONNECTION (gnutls));
382
383   st->type = GNUTLS_CRT_X509;
384   if (cert)
385     {
386       GTlsCertificateGnutls *gnutlscert = G_TLS_CERTIFICATE_GNUTLS (cert);
387
388       st->ncerts = 1;
389       st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t));
390       st->cert.x509[0] = g_tls_certificate_gnutls_copy_cert (gnutlscert);
391       st->key.x509 = g_tls_certificate_gnutls_copy_key (gnutlscert);
392       st->deinit_all = TRUE;
393
394       g_object_unref (cert);
395     }
396   else
397     st->ncerts = 0;
398 }
399
400 static const struct {
401   int gnutls_flag;
402   GTlsCertificateFlags gtls_flag;
403 } flags_map[] = {
404   { GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA, G_TLS_CERTIFICATE_UNKNOWN_CA },
405   { GNUTLS_CERT_NOT_ACTIVATED, G_TLS_CERTIFICATE_NOT_ACTIVATED },
406   { GNUTLS_CERT_EXPIRED, G_TLS_CERTIFICATE_EXPIRED },
407   { GNUTLS_CERT_REVOKED, G_TLS_CERTIFICATE_REVOKED },
408   { GNUTLS_CERT_INSECURE_ALGORITHM, G_TLS_CERTIFICATE_INSECURE }
409 };
410 static const int flags_map_size = G_N_ELEMENTS (flags_map);
411
412 GTlsCertificateFlags
413 g_tls_connection_gnutls_validate_peer (GTlsConnectionGnutls *gnutls)
414 {
415   int status, i;
416   GTlsCertificateFlags gtls_errors;
417
418   status = gnutls_certificate_verify_peers (gnutls->priv->session);
419
420   /* Convert GNUTLS status to GTlsCertificateFlags. GNUTLS sets
421    * GNUTLS_CERT_INVALID if it sets any other flag, so we want to
422    * strip that out unless it's the only flag set. Then we convert
423    * specific flags we recognize, and if there are any flags left over
424    * at the end, we add G_TLS_CERTIFICATE_GENERIC_ERROR.
425    */
426   gtls_errors = 0;
427
428   if (status != GNUTLS_CERT_INVALID)
429     status = status & ~GNUTLS_CERT_INVALID;
430   for (i = 0; i < flags_map_size && status != 0; i++)
431     {
432       if (status & flags_map[i].gnutls_flag)
433         {
434           status &= ~flags_map[i].gnutls_flag;
435           gtls_errors |= flags_map[i].gtls_flag;
436         }
437     }
438   if (status)
439     gtls_errors |= G_TLS_CERTIFICATE_GENERIC_ERROR;
440
441   return gtls_errors;
442 }
443
444 static void
445 begin_gnutls_io (GTlsConnectionGnutls  *gnutls,
446                  gboolean               blocking,
447                  GCancellable          *cancellable)
448 {
449   gnutls->priv->blocking = blocking;
450   gnutls->priv->cancellable = cancellable;
451   gnutls->priv->internal_direction = 0;
452   g_clear_error (&gnutls->priv->error);
453 }
454
455 static int
456 end_gnutls_io (GTlsConnectionGnutls  *gnutls,
457                int                    status,
458                const char            *generic_error,
459                GError               **error)
460 {
461   gnutls->priv->cancellable = NULL;
462
463   if (status >= 0)
464     {
465       g_clear_error (&gnutls->priv->error);
466       return status;
467     }
468
469   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
470     {
471       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
472           status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH ||
473           status == GNUTLS_E_FATAL_ALERT_RECEIVED ||
474           status == GNUTLS_E_UNSUPPORTED_VERSION_PACKET)
475         {
476           g_clear_error (&gnutls->priv->error);
477           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
478                                _("Peer failed to perform TLS handshake"));
479           return GNUTLS_E_PULL_ERROR;
480         }
481     }
482
483   if (gnutls->priv->error)
484     {
485       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
486         status = GNUTLS_E_AGAIN;
487       g_propagate_error (error, gnutls->priv->error);
488       gnutls->priv->error = NULL;
489       return status;
490     }
491   else if (status == GNUTLS_E_REHANDSHAKE)
492     {
493       if (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_NEVER)
494         {
495           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
496                                _("Peer requested illegal TLS rehandshake"));
497           return GNUTLS_E_PULL_ERROR;
498         }
499
500       gnutls->priv->need_handshake = TRUE;
501       return status;
502     }
503   else if (status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
504     {
505       if (gnutls->priv->eof)
506         {
507           if (gnutls->priv->require_close_notify)
508             {
509               g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_EOF,
510                                    _("TLS connection closed unexpectedly"));
511               return status;
512             }
513           else
514             return 0;
515         }
516     }
517
518   g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
519                generic_error, gnutls_strerror (status));
520   return status;
521 }
522
523 #define BEGIN_GNUTLS_IO(gnutls, blocking, cancellable)  \
524   begin_gnutls_io (gnutls, blocking, cancellable);      \
525   do {
526
527 #define END_GNUTLS_IO(gnutls, ret, errmsg, error)       \
528   } while ((ret == GNUTLS_E_AGAIN ||                    \
529             ret == GNUTLS_E_WARNING_ALERT_RECEIVED) &&  \
530            !gnutls->priv->error);                       \
531   ret = end_gnutls_io (gnutls, ret, errmsg, error)
532
533 gboolean
534 g_tls_connection_gnutls_check (GTlsConnectionGnutls  *gnutls,
535                                GIOCondition           condition)
536 {
537   if (gnutls->priv->handshaking || gnutls->priv->closing)
538     condition = gnutls->priv->internal_direction;
539
540   if (condition & G_IO_IN)
541     return g_pollable_input_stream_is_readable (gnutls->priv->base_istream);
542   else
543     return g_pollable_output_stream_is_writable (gnutls->priv->base_ostream);
544 }
545
546 typedef struct {
547   GSource source;
548
549   GTlsConnectionGnutls *gnutls;
550   GObject              *stream;
551
552   GSource              *child_source;
553   GIOCondition          base_direction;
554   GIOCondition          current_direction;
555 } GTlsConnectionGnutlsSource;
556
557 static gboolean
558 gnutls_source_prepare (GSource *source,
559                        gint    *timeout)
560 {
561   *timeout = -1;
562   return FALSE;
563 }
564
565 static gboolean
566 gnutls_source_check (GSource *source)
567 {
568   return FALSE;
569 }
570
571 static void
572 gnutls_source_sync_child_source (GTlsConnectionGnutlsSource *gnutls_source,
573                                  GIOCondition                direction)
574 {
575   GTlsConnectionGnutls *gnutls = gnutls_source->gnutls;
576   GSource *source = (GSource *)gnutls_source;
577
578   if (direction == gnutls_source->current_direction)
579     return;
580
581   if (gnutls_source->child_source)
582     {
583       g_source_remove_child_source (source, gnutls_source->child_source);
584       g_source_unref (gnutls_source->child_source);
585     }
586
587   if (direction & G_IO_IN)
588     gnutls_source->child_source = g_pollable_input_stream_create_source (gnutls->priv->base_istream, NULL);
589   else
590     gnutls_source->child_source = g_pollable_output_stream_create_source (gnutls->priv->base_ostream, NULL);
591
592   g_source_set_dummy_callback (gnutls_source->child_source);
593   g_source_add_child_source (source, gnutls_source->child_source);
594   gnutls_source->current_direction = direction;
595 }
596
597 static gboolean
598 gnutls_source_dispatch (GSource     *source,
599                         GSourceFunc  callback,
600                         gpointer     user_data)
601 {
602   GPollableSourceFunc func = (GPollableSourceFunc)callback;
603   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
604   GTlsConnectionGnutls *gnutls = gnutls_source->gnutls;
605   gboolean ret;
606
607   ret = (*func) (gnutls_source->stream, user_data);
608   if (ret)
609     {
610       GIOCondition direction = gnutls->priv->internal_direction ? gnutls->priv->internal_direction : gnutls_source->base_direction;
611
612       gnutls_source_sync_child_source (gnutls_source, direction);
613     }
614
615   return ret;
616 }
617
618 static void
619 gnutls_source_finalize (GSource *source)
620 {
621   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
622
623   g_object_unref (gnutls_source->gnutls);
624
625   if (gnutls_source->child_source)
626     g_source_unref (gnutls_source->child_source);
627 }
628
629 static GSourceFuncs gnutls_source_funcs =
630 {
631   gnutls_source_prepare,
632   gnutls_source_check,
633   gnutls_source_dispatch,
634   gnutls_source_finalize
635 };
636
637 GSource *
638 g_tls_connection_gnutls_create_source (GTlsConnectionGnutls  *gnutls,
639                                        GIOCondition           condition,
640                                        GCancellable          *cancellable)
641 {
642   GSource *source, *cancellable_source;
643   GTlsConnectionGnutlsSource *gnutls_source;
644
645   source = g_source_new (&gnutls_source_funcs, sizeof (GTlsConnectionGnutlsSource));
646   g_source_set_name (source, "GTlsConnectionGnutlsSource");
647   gnutls_source = (GTlsConnectionGnutlsSource *)source;
648   gnutls_source->gnutls = g_object_ref (gnutls);
649   gnutls_source->base_direction = condition & (G_IO_IN | G_IO_OUT);
650   if (gnutls_source->base_direction == G_IO_IN)
651     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_istream);
652   else if (gnutls_source->base_direction == G_IO_OUT)
653     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_ostream);
654   else
655     {
656       gnutls_source->base_direction = gnutls->priv->internal_direction;
657       gnutls_source->stream = NULL;
658     }
659   gnutls_source_sync_child_source (gnutls_source, gnutls_source->base_direction);
660
661   if (cancellable)
662     {
663       cancellable_source = g_cancellable_source_new (cancellable);
664       g_source_set_dummy_callback (cancellable_source);
665       g_source_add_child_source (source, cancellable_source);
666       g_source_unref (cancellable_source);
667     }
668
669   return source;
670 }
671
672 static void
673 set_gnutls_error (GTlsConnectionGnutls *gnutls, GIOCondition direction)
674 {
675   if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
676     gnutls_transport_set_errno (gnutls->priv->session, EINTR);
677   else if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
678     {
679       gnutls_transport_set_errno (gnutls->priv->session, EAGAIN);
680       gnutls->priv->internal_direction = direction;
681     }
682   else
683     gnutls_transport_set_errno (gnutls->priv->session, EIO);
684 }
685
686 static ssize_t
687 g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
688                                    void                   *buf,
689                                    size_t                  buflen)
690 {
691   GTlsConnectionGnutls *gnutls = transport_data;
692   ssize_t ret;
693
694   /* If gnutls->priv->error is non-%NULL when we're called, it means
695    * that an error previously occurred, but gnutls decided not to
696    * propagate it. So it's correct for us to just clear it. (Usually
697    * this means it ignored an EAGAIN after a short read, and now
698    * we'll return EAGAIN again, which it will obey this time.)
699    */
700   g_clear_error (&gnutls->priv->error);
701
702   if (gnutls->priv->blocking)
703     {
704       ret = g_input_stream_read (G_INPUT_STREAM (gnutls->priv->base_istream),
705                                  buf, buflen,
706                                  gnutls->priv->cancellable,
707                                  &gnutls->priv->error);
708     }
709   else
710     {
711       ret = g_pollable_input_stream_read_nonblocking (gnutls->priv->base_istream,
712                                                       buf, buflen,
713                                                       gnutls->priv->cancellable,
714                                                       &gnutls->priv->error);
715     }
716
717   if (ret < 0)
718     set_gnutls_error (gnutls, G_IO_IN);
719   else if (ret == 0)
720     gnutls->priv->eof = TRUE;
721
722   return ret;
723 }
724
725 static ssize_t
726 g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
727                                    const void             *buf,
728                                    size_t                  buflen)
729 {
730   GTlsConnectionGnutls *gnutls = transport_data;
731   ssize_t ret;
732
733   /* See comment in pull_func. */
734   g_clear_error (&gnutls->priv->error);
735
736   if (gnutls->priv->blocking)
737     {
738       ret = g_output_stream_write (G_OUTPUT_STREAM (gnutls->priv->base_ostream),
739                                    buf, buflen,
740                                    gnutls->priv->cancellable,
741                                    &gnutls->priv->error);
742     }
743   else
744     {
745       ret = g_pollable_output_stream_write_nonblocking (gnutls->priv->base_ostream,
746                                                         buf, buflen,
747                                                         gnutls->priv->cancellable,
748                                                         &gnutls->priv->error);
749     }
750   if (ret < 0)
751     set_gnutls_error (gnutls, G_IO_OUT);
752
753   return ret;
754 }
755
756 static gboolean
757 handshake_internal (GTlsConnectionGnutls  *gnutls,
758                     gboolean               blocking,
759                     GCancellable          *cancellable,
760                     GError               **error)
761 {
762   int ret;
763
764   if (G_IS_TLS_SERVER_CONNECTION_GNUTLS (gnutls) &&
765       gnutls->priv->ever_handshaked && !gnutls->priv->need_handshake)
766     {
767       BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
768       ret = gnutls_rehandshake (gnutls->priv->session);
769       END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
770
771       if (ret != 0)
772         return FALSE;
773     }
774
775   g_tls_connection_gnutls_set_handshake_priority (gnutls);
776
777   gnutls->priv->handshaking = TRUE;
778   G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->begin_handshake (gnutls);
779
780   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
781   ret = gnutls_handshake (gnutls->priv->session);
782   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
783
784   if (ret == GNUTLS_E_AGAIN)
785     return FALSE;
786
787   gnutls->priv->handshaking = FALSE;
788   gnutls->priv->need_handshake = FALSE;
789   gnutls->priv->ever_handshaked = TRUE;
790
791   if (ret == 0 &&
792       gnutls_certificate_type_get (gnutls->priv->session) == GNUTLS_CRT_X509)
793     {
794       GTlsCertificate *chain, *cert;
795       const gnutls_datum_t *certs;
796       unsigned int num_certs;
797       int i;
798
799       certs = gnutls_certificate_get_peers (gnutls->priv->session, &num_certs);
800       chain = NULL;
801       if (certs)
802         {
803           for (i = num_certs - 1; i >= 0; i--)
804             {
805               cert = g_tls_certificate_gnutls_new (&certs[i], chain);
806               chain = cert;
807             }
808         }
809
810       g_tls_connection_set_peer_certificate (G_TLS_CONNECTION (gnutls), chain);
811     }
812   else
813     g_tls_connection_set_peer_certificate (G_TLS_CONNECTION (gnutls), NULL);
814
815   return G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->finish_handshake (gnutls, ret == 0, error);
816 }
817
818 static gboolean
819 handshake_in_progress_or_failed (GTlsConnectionGnutls  *gnutls,
820                                  gboolean               blocking,
821                                  GCancellable          *cancellable,
822                                  GError               **error)
823 {
824   if (!(gnutls->priv->need_handshake || gnutls->priv->handshaking))
825     return FALSE;
826
827   return !handshake_internal (gnutls, blocking, cancellable, error);
828 }
829
830 static gboolean
831 g_tls_connection_gnutls_handshake (GTlsConnection   *conn,
832                                    GCancellable     *cancellable,
833                                    GError          **error)
834 {
835   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
836
837   return handshake_internal (gnutls, TRUE, cancellable, error);
838 }
839
840 static gboolean
841 g_tls_connection_gnutls_handshake_ready (GObject  *pollable_stream,
842                                          gpointer  user_data)
843 {
844   GTlsConnectionGnutls *gnutls;
845   GSimpleAsyncResult *simple = user_data;
846   gboolean success;
847   GError *error = NULL;
848
849   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
850   g_object_unref (gnutls);
851
852   success = handshake_internal (gnutls, FALSE, NULL, &error);
853   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
854     {
855       g_error_free (error);
856       return TRUE;
857     }
858
859   if (error)
860     {
861       g_simple_async_result_set_from_error (simple, error);
862       g_error_free (error);
863     }
864   else
865     g_simple_async_result_set_op_res_gboolean (simple, success);
866   g_simple_async_result_complete (simple);
867   g_object_unref (simple);
868
869   return FALSE;
870 }
871
872 static void
873 g_tls_connection_gnutls_handshake_async (GTlsConnection       *conn,
874                                          int                   io_priority,
875                                          GCancellable         *cancellable,
876                                          GAsyncReadyCallback   callback,
877                                          gpointer              user_data)
878 {
879   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
880   GSimpleAsyncResult *simple;
881   gboolean success;
882   GError *error = NULL;
883   GSource *source;
884
885   simple = g_simple_async_result_new (G_OBJECT (conn), callback, user_data,
886                                       g_tls_connection_gnutls_handshake_async);
887   success = handshake_internal (gnutls, FALSE, cancellable, &error);
888   if (success)
889     {
890       g_simple_async_result_set_op_res_gboolean (simple, TRUE);
891       g_simple_async_result_complete_in_idle (simple);
892       g_object_unref (simple);
893     }
894   else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
895     {
896       g_simple_async_result_set_from_error (simple, error);
897       g_error_free (error);
898       g_simple_async_result_complete_in_idle (simple);
899       g_object_unref (simple);
900     }
901
902   source = g_tls_connection_gnutls_create_source (gnutls, 0, cancellable);
903   g_source_set_callback (source,
904                          (GSourceFunc) g_tls_connection_gnutls_handshake_ready,
905                          simple, NULL);
906   g_source_set_priority (source, io_priority);
907   g_source_attach (source, g_main_context_get_thread_default ());
908   g_source_unref (source);
909 }
910
911 static gboolean
912 g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
913                                           GAsyncResult         *result,
914                                           GError              **error)
915 {
916   GSimpleAsyncResult *simple;
917
918   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (conn), g_tls_connection_gnutls_handshake_async), FALSE);
919
920   simple = G_SIMPLE_ASYNC_RESULT (result);
921
922   if (g_simple_async_result_propagate_error (simple, error))
923     return FALSE;
924
925   return g_simple_async_result_get_op_res_gboolean (simple);
926 }
927
928 gssize
929 g_tls_connection_gnutls_read (GTlsConnectionGnutls  *gnutls,
930                               void                  *buffer,
931                               gsize                  count,
932                               gboolean               blocking,
933                               GCancellable          *cancellable,
934                               GError               **error)
935 {
936   gssize ret;
937
938  again:
939   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
940     return -1;
941
942   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
943   ret = gnutls_record_recv (gnutls->priv->session, buffer, count);
944   END_GNUTLS_IO (gnutls, ret, _("Error reading data from TLS socket: %s"), error);
945
946   if (ret >= 0)
947     return ret;
948   else if (ret == GNUTLS_E_REHANDSHAKE)
949     goto again;
950   else
951     return -1;
952 }
953
954 gssize
955 g_tls_connection_gnutls_write (GTlsConnectionGnutls  *gnutls,
956                                const void            *buffer,
957                                gsize                  count,
958                                gboolean               blocking,
959                                GCancellable          *cancellable,
960                                GError               **error)
961 {
962   gssize ret;
963
964  again:
965   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
966     return -1;
967
968   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
969   ret = gnutls_record_send (gnutls->priv->session, buffer, count);
970   END_GNUTLS_IO (gnutls, ret, _("Error writing data to TLS socket: %s"), error);
971
972   if (ret >= 0)
973     return ret;
974   else if (ret == GNUTLS_E_REHANDSHAKE)
975     goto again;
976   else
977     return -1;
978 }
979
980 static GInputStream  *
981 g_tls_connection_gnutls_get_input_stream (GIOStream *stream)
982 {
983   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
984
985   return gnutls->priv->tls_istream;
986 }
987
988 static GOutputStream *
989 g_tls_connection_gnutls_get_output_stream (GIOStream *stream)
990 {
991   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
992
993   return gnutls->priv->tls_ostream;
994 }
995
996 static gboolean
997 close_internal (GTlsConnectionGnutls  *gnutls,
998                 gboolean               blocking,
999                 GCancellable          *cancellable,
1000                 GError               **error)
1001 {
1002   int ret;
1003
1004   if (!gnutls->priv->require_close_notify)
1005     return TRUE;
1006
1007   /* If we haven't finished the initial handshake yet, there's no
1008    * reason to finish it just so we can close.
1009    */
1010   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
1011     return TRUE;
1012
1013   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1014     return FALSE;
1015
1016   gnutls->priv->closing = TRUE;
1017   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1018   ret = gnutls_bye (gnutls->priv->session, GNUTLS_SHUT_WR);
1019   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS close: %s"), error);
1020   if (ret == 0 || !error || !g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1021     gnutls->priv->closing = FALSE;
1022
1023   return ret == 0;
1024 }
1025
1026 static gboolean
1027 g_tls_connection_gnutls_close (GIOStream     *stream,
1028                                GCancellable  *cancellable,
1029                                GError       **error)
1030 {
1031   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1032
1033   if (!close_internal (gnutls, TRUE, cancellable, error))
1034     return FALSE;
1035   return g_io_stream_close (gnutls->priv->base_io_stream,
1036                             cancellable, error);
1037 }
1038
1039 typedef struct {
1040   GSimpleAsyncResult *simple;
1041   GCancellable *cancellable;
1042   int io_priority;
1043 } AsyncCloseData;
1044
1045 static void
1046 close_base_stream_cb (GObject      *base_stream,
1047                       GAsyncResult *result,
1048                       gpointer      user_data)
1049 {
1050   gboolean success;
1051   GError *error = NULL;
1052   AsyncCloseData *acd = user_data;
1053
1054   success = g_io_stream_close_finish (G_IO_STREAM (base_stream),
1055                                       result, &error);
1056   if (success)
1057     g_simple_async_result_set_op_res_gboolean (acd->simple, TRUE);
1058   else
1059     {
1060       g_simple_async_result_set_from_error (acd->simple, error);
1061       g_error_free (error);
1062     }
1063
1064   g_simple_async_result_complete (acd->simple);
1065   g_object_unref (acd->simple);
1066   if (acd->cancellable)
1067     g_object_unref (acd->cancellable);
1068   g_slice_free (AsyncCloseData, acd);
1069 }
1070
1071 static gboolean
1072 g_tls_connection_gnutls_close_ready (GObject  *pollable_stream,
1073                                      gpointer  user_data)
1074 {
1075   GTlsConnectionGnutls *gnutls;
1076   AsyncCloseData *acd = user_data;
1077   gboolean success;
1078   GError *error = NULL;
1079
1080   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (acd->simple)));
1081   g_object_unref (gnutls);
1082
1083   success = close_internal (gnutls, FALSE, NULL, &error);
1084   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1085     {
1086       g_error_free (error);
1087       return TRUE;
1088     }
1089
1090   if (error)
1091     {
1092       g_simple_async_result_set_from_error (acd->simple, error);
1093       g_simple_async_result_complete (acd->simple);
1094       g_error_free (error);
1095       g_object_unref (acd->simple);
1096       if (acd->cancellable)
1097         g_object_unref (acd->cancellable);
1098       g_slice_free (AsyncCloseData, acd);
1099     }
1100   else
1101     {
1102       g_io_stream_close_async (gnutls->priv->base_io_stream,
1103                                acd->io_priority, acd->cancellable,
1104                                close_base_stream_cb, acd);
1105     }
1106
1107   return FALSE;
1108 }
1109
1110 static void
1111 g_tls_connection_gnutls_close_async (GIOStream           *stream,
1112                                      int                  io_priority,
1113                                      GCancellable        *cancellable,
1114                                      GAsyncReadyCallback  callback,
1115                                      gpointer             user_data)
1116 {
1117   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1118   GSimpleAsyncResult *simple;
1119   gboolean success;
1120   GError *error = NULL;
1121   AsyncCloseData *acd;
1122   GSource *source;
1123
1124   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
1125                                       g_tls_connection_gnutls_close_async);
1126
1127   success = close_internal (gnutls, FALSE, cancellable, &error);
1128   if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1129     {
1130       g_simple_async_result_set_from_error (simple, error);
1131       g_error_free (error);
1132       g_simple_async_result_complete_in_idle (simple);
1133       g_object_unref (simple);
1134     }
1135
1136   if (error)
1137     g_error_free (error);
1138
1139   acd = g_slice_new (AsyncCloseData);
1140   acd->simple = simple;
1141   acd->cancellable = g_object_ref (cancellable);
1142   acd->io_priority = io_priority;
1143
1144   if (success)
1145     {
1146       g_io_stream_close_async (gnutls->priv->base_io_stream,
1147                                io_priority, cancellable,
1148                                close_base_stream_cb, acd);
1149       return;
1150     }
1151
1152   source = g_tls_connection_gnutls_create_source (gnutls, 0, acd->cancellable);
1153   g_source_set_callback (source,
1154                          (GSourceFunc) g_tls_connection_gnutls_close_ready,
1155                          acd, NULL);
1156   g_source_set_priority (source, acd->io_priority);
1157   g_source_attach (source, g_main_context_get_thread_default ());
1158   g_source_unref (source);
1159 }
1160
1161 static gboolean
1162 g_tls_connection_gnutls_close_finish (GIOStream           *stream,
1163                                       GAsyncResult        *result,
1164                                       GError             **error)
1165 {
1166   GSimpleAsyncResult *simple;
1167
1168   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_connection_gnutls_close_async), FALSE);
1169
1170   simple = G_SIMPLE_ASYNC_RESULT (result);
1171
1172   if (g_simple_async_result_propagate_error (simple, error))
1173     return FALSE;
1174
1175   return g_simple_async_result_get_op_res_gboolean (simple);
1176 }