gnutls: Update for GTlsCertificate changes, implement verify
[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 GTlsCertificateFlags
401 g_tls_connection_gnutls_validate_peer (GTlsConnectionGnutls *gnutls)
402 {
403   int status;
404
405   status = gnutls_certificate_verify_peers (gnutls->priv->session);
406   return g_tls_certificate_gnutls_convert_flags (status);
407 }
408
409 static void
410 begin_gnutls_io (GTlsConnectionGnutls  *gnutls,
411                  gboolean               blocking,
412                  GCancellable          *cancellable)
413 {
414   gnutls->priv->blocking = blocking;
415   gnutls->priv->cancellable = cancellable;
416   gnutls->priv->internal_direction = 0;
417   g_clear_error (&gnutls->priv->error);
418 }
419
420 static int
421 end_gnutls_io (GTlsConnectionGnutls  *gnutls,
422                int                    status,
423                const char            *generic_error,
424                GError               **error)
425 {
426   gnutls->priv->cancellable = NULL;
427
428   if (status >= 0)
429     {
430       g_clear_error (&gnutls->priv->error);
431       return status;
432     }
433
434   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
435     {
436       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
437           status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH ||
438           status == GNUTLS_E_FATAL_ALERT_RECEIVED ||
439           status == GNUTLS_E_UNSUPPORTED_VERSION_PACKET)
440         {
441           g_clear_error (&gnutls->priv->error);
442           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
443                                _("Peer failed to perform TLS handshake"));
444           return GNUTLS_E_PULL_ERROR;
445         }
446     }
447
448   if (gnutls->priv->error)
449     {
450       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
451         status = GNUTLS_E_AGAIN;
452       g_propagate_error (error, gnutls->priv->error);
453       gnutls->priv->error = NULL;
454       return status;
455     }
456   else if (status == GNUTLS_E_REHANDSHAKE)
457     {
458       if (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_NEVER)
459         {
460           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
461                                _("Peer requested illegal TLS rehandshake"));
462           return GNUTLS_E_PULL_ERROR;
463         }
464
465       gnutls->priv->need_handshake = TRUE;
466       return status;
467     }
468   else if (status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH)
469     {
470       if (gnutls->priv->eof)
471         {
472           if (gnutls->priv->require_close_notify)
473             {
474               g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_EOF,
475                                    _("TLS connection closed unexpectedly"));
476               return status;
477             }
478           else
479             return 0;
480         }
481     }
482
483   g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
484                generic_error, gnutls_strerror (status));
485   return status;
486 }
487
488 #define BEGIN_GNUTLS_IO(gnutls, blocking, cancellable)  \
489   begin_gnutls_io (gnutls, blocking, cancellable);      \
490   do {
491
492 #define END_GNUTLS_IO(gnutls, ret, errmsg, error)       \
493   } while ((ret == GNUTLS_E_AGAIN ||                    \
494             ret == GNUTLS_E_WARNING_ALERT_RECEIVED) &&  \
495            !gnutls->priv->error);                       \
496   ret = end_gnutls_io (gnutls, ret, errmsg, error)
497
498 gboolean
499 g_tls_connection_gnutls_check (GTlsConnectionGnutls  *gnutls,
500                                GIOCondition           condition)
501 {
502   if (gnutls->priv->handshaking || gnutls->priv->closing)
503     condition = gnutls->priv->internal_direction;
504
505   if (condition & G_IO_IN)
506     return g_pollable_input_stream_is_readable (gnutls->priv->base_istream);
507   else
508     return g_pollable_output_stream_is_writable (gnutls->priv->base_ostream);
509 }
510
511 typedef struct {
512   GSource source;
513
514   GTlsConnectionGnutls *gnutls;
515   GObject              *stream;
516
517   GSource              *child_source;
518   GIOCondition          base_direction;
519   GIOCondition          current_direction;
520 } GTlsConnectionGnutlsSource;
521
522 static gboolean
523 gnutls_source_prepare (GSource *source,
524                        gint    *timeout)
525 {
526   *timeout = -1;
527   return FALSE;
528 }
529
530 static gboolean
531 gnutls_source_check (GSource *source)
532 {
533   return FALSE;
534 }
535
536 static void
537 gnutls_source_sync_child_source (GTlsConnectionGnutlsSource *gnutls_source,
538                                  GIOCondition                direction)
539 {
540   GTlsConnectionGnutls *gnutls = gnutls_source->gnutls;
541   GSource *source = (GSource *)gnutls_source;
542
543   if (direction == gnutls_source->current_direction)
544     return;
545
546   if (gnutls_source->child_source)
547     {
548       g_source_remove_child_source (source, gnutls_source->child_source);
549       g_source_unref (gnutls_source->child_source);
550     }
551
552   if (direction & G_IO_IN)
553     gnutls_source->child_source = g_pollable_input_stream_create_source (gnutls->priv->base_istream, NULL);
554   else
555     gnutls_source->child_source = g_pollable_output_stream_create_source (gnutls->priv->base_ostream, NULL);
556
557   g_source_set_dummy_callback (gnutls_source->child_source);
558   g_source_add_child_source (source, gnutls_source->child_source);
559   gnutls_source->current_direction = direction;
560 }
561
562 static gboolean
563 gnutls_source_dispatch (GSource     *source,
564                         GSourceFunc  callback,
565                         gpointer     user_data)
566 {
567   GPollableSourceFunc func = (GPollableSourceFunc)callback;
568   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
569   GTlsConnectionGnutls *gnutls = gnutls_source->gnutls;
570   gboolean ret;
571
572   ret = (*func) (gnutls_source->stream, user_data);
573   if (ret)
574     {
575       GIOCondition direction = gnutls->priv->internal_direction ? gnutls->priv->internal_direction : gnutls_source->base_direction;
576
577       gnutls_source_sync_child_source (gnutls_source, direction);
578     }
579
580   return ret;
581 }
582
583 static void
584 gnutls_source_finalize (GSource *source)
585 {
586   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
587
588   g_object_unref (gnutls_source->gnutls);
589
590   if (gnutls_source->child_source)
591     g_source_unref (gnutls_source->child_source);
592 }
593
594 static GSourceFuncs gnutls_source_funcs =
595 {
596   gnutls_source_prepare,
597   gnutls_source_check,
598   gnutls_source_dispatch,
599   gnutls_source_finalize
600 };
601
602 GSource *
603 g_tls_connection_gnutls_create_source (GTlsConnectionGnutls  *gnutls,
604                                        GIOCondition           condition,
605                                        GCancellable          *cancellable)
606 {
607   GSource *source, *cancellable_source;
608   GTlsConnectionGnutlsSource *gnutls_source;
609
610   source = g_source_new (&gnutls_source_funcs, sizeof (GTlsConnectionGnutlsSource));
611   g_source_set_name (source, "GTlsConnectionGnutlsSource");
612   gnutls_source = (GTlsConnectionGnutlsSource *)source;
613   gnutls_source->gnutls = g_object_ref (gnutls);
614   gnutls_source->base_direction = condition & (G_IO_IN | G_IO_OUT);
615   if (gnutls_source->base_direction == G_IO_IN)
616     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_istream);
617   else if (gnutls_source->base_direction == G_IO_OUT)
618     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_ostream);
619   else
620     {
621       gnutls_source->base_direction = gnutls->priv->internal_direction;
622       gnutls_source->stream = NULL;
623     }
624   gnutls_source_sync_child_source (gnutls_source, gnutls_source->base_direction);
625
626   if (cancellable)
627     {
628       cancellable_source = g_cancellable_source_new (cancellable);
629       g_source_set_dummy_callback (cancellable_source);
630       g_source_add_child_source (source, cancellable_source);
631       g_source_unref (cancellable_source);
632     }
633
634   return source;
635 }
636
637 static void
638 set_gnutls_error (GTlsConnectionGnutls *gnutls, GIOCondition direction)
639 {
640   if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
641     gnutls_transport_set_errno (gnutls->priv->session, EINTR);
642   else if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
643     {
644       gnutls_transport_set_errno (gnutls->priv->session, EAGAIN);
645       gnutls->priv->internal_direction = direction;
646     }
647   else
648     gnutls_transport_set_errno (gnutls->priv->session, EIO);
649 }
650
651 static ssize_t
652 g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
653                                    void                   *buf,
654                                    size_t                  buflen)
655 {
656   GTlsConnectionGnutls *gnutls = transport_data;
657   ssize_t ret;
658
659   /* If gnutls->priv->error is non-%NULL when we're called, it means
660    * that an error previously occurred, but gnutls decided not to
661    * propagate it. So it's correct for us to just clear it. (Usually
662    * this means it ignored an EAGAIN after a short read, and now
663    * we'll return EAGAIN again, which it will obey this time.)
664    */
665   g_clear_error (&gnutls->priv->error);
666
667   if (gnutls->priv->blocking)
668     {
669       ret = g_input_stream_read (G_INPUT_STREAM (gnutls->priv->base_istream),
670                                  buf, buflen,
671                                  gnutls->priv->cancellable,
672                                  &gnutls->priv->error);
673     }
674   else
675     {
676       ret = g_pollable_input_stream_read_nonblocking (gnutls->priv->base_istream,
677                                                       buf, buflen,
678                                                       gnutls->priv->cancellable,
679                                                       &gnutls->priv->error);
680     }
681
682   if (ret < 0)
683     set_gnutls_error (gnutls, G_IO_IN);
684   else if (ret == 0)
685     gnutls->priv->eof = TRUE;
686
687   return ret;
688 }
689
690 static ssize_t
691 g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
692                                    const void             *buf,
693                                    size_t                  buflen)
694 {
695   GTlsConnectionGnutls *gnutls = transport_data;
696   ssize_t ret;
697
698   /* See comment in pull_func. */
699   g_clear_error (&gnutls->priv->error);
700
701   if (gnutls->priv->blocking)
702     {
703       ret = g_output_stream_write (G_OUTPUT_STREAM (gnutls->priv->base_ostream),
704                                    buf, buflen,
705                                    gnutls->priv->cancellable,
706                                    &gnutls->priv->error);
707     }
708   else
709     {
710       ret = g_pollable_output_stream_write_nonblocking (gnutls->priv->base_ostream,
711                                                         buf, buflen,
712                                                         gnutls->priv->cancellable,
713                                                         &gnutls->priv->error);
714     }
715   if (ret < 0)
716     set_gnutls_error (gnutls, G_IO_OUT);
717
718   return ret;
719 }
720
721 static gboolean
722 handshake_internal (GTlsConnectionGnutls  *gnutls,
723                     gboolean               blocking,
724                     GCancellable          *cancellable,
725                     GError               **error)
726 {
727   int ret;
728
729   if (G_IS_TLS_SERVER_CONNECTION_GNUTLS (gnutls) &&
730       gnutls->priv->ever_handshaked && !gnutls->priv->need_handshake)
731     {
732       BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
733       ret = gnutls_rehandshake (gnutls->priv->session);
734       END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
735
736       if (ret != 0)
737         return FALSE;
738     }
739
740   g_tls_connection_gnutls_set_handshake_priority (gnutls);
741
742   gnutls->priv->handshaking = TRUE;
743   G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->begin_handshake (gnutls);
744
745   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
746   ret = gnutls_handshake (gnutls->priv->session);
747   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
748
749   if (ret == GNUTLS_E_AGAIN)
750     return FALSE;
751
752   gnutls->priv->handshaking = FALSE;
753   gnutls->priv->need_handshake = FALSE;
754   gnutls->priv->ever_handshaked = TRUE;
755
756   if (ret == 0 &&
757       gnutls_certificate_type_get (gnutls->priv->session) == GNUTLS_CRT_X509)
758     {
759       GTlsCertificate *chain, *cert;
760       const gnutls_datum_t *certs;
761       unsigned int num_certs;
762       int i;
763
764       certs = gnutls_certificate_get_peers (gnutls->priv->session, &num_certs);
765       chain = NULL;
766       if (certs)
767         {
768           for (i = num_certs - 1; i >= 0; i--)
769             {
770               cert = g_tls_certificate_gnutls_new (&certs[i], chain);
771               chain = cert;
772             }
773         }
774
775       g_tls_connection_set_peer_certificate (G_TLS_CONNECTION (gnutls), chain);
776     }
777   else
778     g_tls_connection_set_peer_certificate (G_TLS_CONNECTION (gnutls), NULL);
779
780   return G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->finish_handshake (gnutls, ret == 0, error);
781 }
782
783 static gboolean
784 handshake_in_progress_or_failed (GTlsConnectionGnutls  *gnutls,
785                                  gboolean               blocking,
786                                  GCancellable          *cancellable,
787                                  GError               **error)
788 {
789   if (!(gnutls->priv->need_handshake || gnutls->priv->handshaking))
790     return FALSE;
791
792   return !handshake_internal (gnutls, blocking, cancellable, error);
793 }
794
795 static gboolean
796 g_tls_connection_gnutls_handshake (GTlsConnection   *conn,
797                                    GCancellable     *cancellable,
798                                    GError          **error)
799 {
800   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
801
802   return handshake_internal (gnutls, TRUE, cancellable, error);
803 }
804
805 static gboolean
806 g_tls_connection_gnutls_handshake_ready (GObject  *pollable_stream,
807                                          gpointer  user_data)
808 {
809   GTlsConnectionGnutls *gnutls;
810   GSimpleAsyncResult *simple = user_data;
811   gboolean success;
812   GError *error = NULL;
813
814   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
815   g_object_unref (gnutls);
816
817   success = handshake_internal (gnutls, FALSE, NULL, &error);
818   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
819     {
820       g_error_free (error);
821       return TRUE;
822     }
823
824   if (error)
825     {
826       g_simple_async_result_set_from_error (simple, error);
827       g_error_free (error);
828     }
829   else
830     g_simple_async_result_set_op_res_gboolean (simple, success);
831   g_simple_async_result_complete (simple);
832   g_object_unref (simple);
833
834   return FALSE;
835 }
836
837 static void
838 g_tls_connection_gnutls_handshake_async (GTlsConnection       *conn,
839                                          int                   io_priority,
840                                          GCancellable         *cancellable,
841                                          GAsyncReadyCallback   callback,
842                                          gpointer              user_data)
843 {
844   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
845   GSimpleAsyncResult *simple;
846   gboolean success;
847   GError *error = NULL;
848   GSource *source;
849
850   simple = g_simple_async_result_new (G_OBJECT (conn), callback, user_data,
851                                       g_tls_connection_gnutls_handshake_async);
852   success = handshake_internal (gnutls, FALSE, cancellable, &error);
853   if (success)
854     {
855       g_simple_async_result_set_op_res_gboolean (simple, TRUE);
856       g_simple_async_result_complete_in_idle (simple);
857       g_object_unref (simple);
858     }
859   else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
860     {
861       g_simple_async_result_set_from_error (simple, error);
862       g_error_free (error);
863       g_simple_async_result_complete_in_idle (simple);
864       g_object_unref (simple);
865     }
866
867   source = g_tls_connection_gnutls_create_source (gnutls, 0, cancellable);
868   g_source_set_callback (source,
869                          (GSourceFunc) g_tls_connection_gnutls_handshake_ready,
870                          simple, NULL);
871   g_source_set_priority (source, io_priority);
872   g_source_attach (source, g_main_context_get_thread_default ());
873   g_source_unref (source);
874 }
875
876 static gboolean
877 g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
878                                           GAsyncResult         *result,
879                                           GError              **error)
880 {
881   GSimpleAsyncResult *simple;
882
883   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (conn), g_tls_connection_gnutls_handshake_async), FALSE);
884
885   simple = G_SIMPLE_ASYNC_RESULT (result);
886
887   if (g_simple_async_result_propagate_error (simple, error))
888     return FALSE;
889
890   return g_simple_async_result_get_op_res_gboolean (simple);
891 }
892
893 gssize
894 g_tls_connection_gnutls_read (GTlsConnectionGnutls  *gnutls,
895                               void                  *buffer,
896                               gsize                  count,
897                               gboolean               blocking,
898                               GCancellable          *cancellable,
899                               GError               **error)
900 {
901   gssize ret;
902
903  again:
904   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
905     return -1;
906
907   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
908   ret = gnutls_record_recv (gnutls->priv->session, buffer, count);
909   END_GNUTLS_IO (gnutls, ret, _("Error reading data from TLS socket: %s"), error);
910
911   if (ret >= 0)
912     return ret;
913   else if (ret == GNUTLS_E_REHANDSHAKE)
914     goto again;
915   else
916     return -1;
917 }
918
919 gssize
920 g_tls_connection_gnutls_write (GTlsConnectionGnutls  *gnutls,
921                                const void            *buffer,
922                                gsize                  count,
923                                gboolean               blocking,
924                                GCancellable          *cancellable,
925                                GError               **error)
926 {
927   gssize ret;
928
929  again:
930   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
931     return -1;
932
933   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
934   ret = gnutls_record_send (gnutls->priv->session, buffer, count);
935   END_GNUTLS_IO (gnutls, ret, _("Error writing data to TLS socket: %s"), error);
936
937   if (ret >= 0)
938     return ret;
939   else if (ret == GNUTLS_E_REHANDSHAKE)
940     goto again;
941   else
942     return -1;
943 }
944
945 static GInputStream  *
946 g_tls_connection_gnutls_get_input_stream (GIOStream *stream)
947 {
948   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
949
950   return gnutls->priv->tls_istream;
951 }
952
953 static GOutputStream *
954 g_tls_connection_gnutls_get_output_stream (GIOStream *stream)
955 {
956   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
957
958   return gnutls->priv->tls_ostream;
959 }
960
961 static gboolean
962 close_internal (GTlsConnectionGnutls  *gnutls,
963                 gboolean               blocking,
964                 GCancellable          *cancellable,
965                 GError               **error)
966 {
967   int ret;
968
969   if (!gnutls->priv->require_close_notify)
970     return TRUE;
971
972   /* If we haven't finished the initial handshake yet, there's no
973    * reason to finish it just so we can close.
974    */
975   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
976     return TRUE;
977
978   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
979     return FALSE;
980
981   gnutls->priv->closing = TRUE;
982   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
983   ret = gnutls_bye (gnutls->priv->session, GNUTLS_SHUT_WR);
984   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS close: %s"), error);
985   if (ret == 0 || !error || !g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
986     gnutls->priv->closing = FALSE;
987
988   return ret == 0;
989 }
990
991 static gboolean
992 g_tls_connection_gnutls_close (GIOStream     *stream,
993                                GCancellable  *cancellable,
994                                GError       **error)
995 {
996   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
997
998   if (!close_internal (gnutls, TRUE, cancellable, error))
999     return FALSE;
1000   return g_io_stream_close (gnutls->priv->base_io_stream,
1001                             cancellable, error);
1002 }
1003
1004 typedef struct {
1005   GSimpleAsyncResult *simple;
1006   GCancellable *cancellable;
1007   int io_priority;
1008 } AsyncCloseData;
1009
1010 static void
1011 close_base_stream_cb (GObject      *base_stream,
1012                       GAsyncResult *result,
1013                       gpointer      user_data)
1014 {
1015   gboolean success;
1016   GError *error = NULL;
1017   AsyncCloseData *acd = user_data;
1018
1019   success = g_io_stream_close_finish (G_IO_STREAM (base_stream),
1020                                       result, &error);
1021   if (success)
1022     g_simple_async_result_set_op_res_gboolean (acd->simple, TRUE);
1023   else
1024     {
1025       g_simple_async_result_set_from_error (acd->simple, error);
1026       g_error_free (error);
1027     }
1028
1029   g_simple_async_result_complete (acd->simple);
1030   g_object_unref (acd->simple);
1031   if (acd->cancellable)
1032     g_object_unref (acd->cancellable);
1033   g_slice_free (AsyncCloseData, acd);
1034 }
1035
1036 static gboolean
1037 g_tls_connection_gnutls_close_ready (GObject  *pollable_stream,
1038                                      gpointer  user_data)
1039 {
1040   GTlsConnectionGnutls *gnutls;
1041   AsyncCloseData *acd = user_data;
1042   gboolean success;
1043   GError *error = NULL;
1044
1045   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (acd->simple)));
1046   g_object_unref (gnutls);
1047
1048   success = close_internal (gnutls, FALSE, NULL, &error);
1049   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1050     {
1051       g_error_free (error);
1052       return TRUE;
1053     }
1054
1055   if (error)
1056     {
1057       g_simple_async_result_set_from_error (acd->simple, error);
1058       g_simple_async_result_complete (acd->simple);
1059       g_error_free (error);
1060       g_object_unref (acd->simple);
1061       if (acd->cancellable)
1062         g_object_unref (acd->cancellable);
1063       g_slice_free (AsyncCloseData, acd);
1064     }
1065   else
1066     {
1067       g_io_stream_close_async (gnutls->priv->base_io_stream,
1068                                acd->io_priority, acd->cancellable,
1069                                close_base_stream_cb, acd);
1070     }
1071
1072   return FALSE;
1073 }
1074
1075 static void
1076 g_tls_connection_gnutls_close_async (GIOStream           *stream,
1077                                      int                  io_priority,
1078                                      GCancellable        *cancellable,
1079                                      GAsyncReadyCallback  callback,
1080                                      gpointer             user_data)
1081 {
1082   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1083   GSimpleAsyncResult *simple;
1084   gboolean success;
1085   GError *error = NULL;
1086   AsyncCloseData *acd;
1087   GSource *source;
1088
1089   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
1090                                       g_tls_connection_gnutls_close_async);
1091
1092   success = close_internal (gnutls, FALSE, cancellable, &error);
1093   if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1094     {
1095       g_simple_async_result_set_from_error (simple, error);
1096       g_error_free (error);
1097       g_simple_async_result_complete_in_idle (simple);
1098       g_object_unref (simple);
1099     }
1100
1101   if (error)
1102     g_error_free (error);
1103
1104   acd = g_slice_new (AsyncCloseData);
1105   acd->simple = simple;
1106   acd->cancellable = g_object_ref (cancellable);
1107   acd->io_priority = io_priority;
1108
1109   if (success)
1110     {
1111       g_io_stream_close_async (gnutls->priv->base_io_stream,
1112                                io_priority, cancellable,
1113                                close_base_stream_cb, acd);
1114       return;
1115     }
1116
1117   source = g_tls_connection_gnutls_create_source (gnutls, 0, acd->cancellable);
1118   g_source_set_callback (source,
1119                          (GSourceFunc) g_tls_connection_gnutls_close_ready,
1120                          acd, NULL);
1121   g_source_set_priority (source, acd->io_priority);
1122   g_source_attach (source, g_main_context_get_thread_default ());
1123   g_source_unref (source);
1124 }
1125
1126 static gboolean
1127 g_tls_connection_gnutls_close_finish (GIOStream           *stream,
1128                                       GAsyncResult        *result,
1129                                       GError             **error)
1130 {
1131   GSimpleAsyncResult *simple;
1132
1133   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_connection_gnutls_close_async), FALSE);
1134
1135   simple = G_SIMPLE_ASYNC_RESULT (result);
1136
1137   if (g_simple_async_result_propagate_error (simple, error))
1138     return FALSE;
1139
1140   return g_simple_async_result_get_op_res_gboolean (simple);
1141 }