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