gnutls: Add gnutls-pkcs11 TLS backend
[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, see
17  * <http://www.gnu.org/licenses/>.
18  */
19
20 #include "config.h"
21 #include "glib.h"
22
23 #include <errno.h>
24 #include <gnutls/gnutls.h>
25 #include <gnutls/x509.h>
26
27 #include "gtlsconnection-gnutls.h"
28 #include "gtlsbackend-gnutls.h"
29 #include "gtlscertificate-gnutls.h"
30 #include "gtlsinputstream-gnutls.h"
31 #include "gtlsoutputstream-gnutls.h"
32 #include "gtlsserverconnection-gnutls.h"
33
34 #ifdef HAVE_PKCS11
35 #include <p11-kit/pin.h>
36 #include "pkcs11/gpkcs11pin.h"
37 #endif
38
39 #include <glib/gi18n-lib.h>
40
41 static void g_tls_connection_gnutls_get_property (GObject    *object,
42                                                   guint       prop_id,
43                                                   GValue     *value,
44                                                   GParamSpec *pspec);
45 static void g_tls_connection_gnutls_set_property (GObject      *object,
46                                                   guint         prop_id,
47                                                   const GValue *value,
48                                                   GParamSpec   *pspec);
49 static void g_tls_connection_gnutls_finalize     (GObject      *object);
50
51 static gboolean     g_tls_connection_gnutls_handshake        (GTlsConnection       *connection,
52                                                               GCancellable         *cancellable,
53                                                               GError              **error);
54 static void         g_tls_connection_gnutls_handshake_async  (GTlsConnection       *conn,
55                                                               int                   io_priority,
56                                                               GCancellable         *cancellable,
57                                                               GAsyncReadyCallback   callback,
58                                                               gpointer              user_data);
59 static gboolean     g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
60                                                               GAsyncResult         *result,
61                                                               GError              **error);
62
63 static GInputStream  *g_tls_connection_gnutls_get_input_stream  (GIOStream *stream);
64 static GOutputStream *g_tls_connection_gnutls_get_output_stream (GIOStream *stream);
65
66 static gboolean     g_tls_connection_gnutls_close        (GIOStream           *stream,
67                                                           GCancellable        *cancellable,
68                                                           GError             **error);
69 static void         g_tls_connection_gnutls_close_async  (GIOStream           *stream,
70                                                           int                  io_priority,
71                                                           GCancellable        *cancellable,
72                                                           GAsyncReadyCallback  callback,
73                                                           gpointer             user_data);
74 static gboolean     g_tls_connection_gnutls_close_finish (GIOStream           *stream,
75                                                           GAsyncResult        *result,
76                                                           GError             **error);
77
78 static ssize_t g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
79                                                   const void             *buf,
80                                                   size_t                  buflen);
81 static ssize_t g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
82                                                   void                   *buf,
83                                                   size_t                  buflen);
84
85 static void     g_tls_connection_gnutls_initable_iface_init (GInitableIface  *iface);
86 static gboolean g_tls_connection_gnutls_initable_init       (GInitable       *initable,
87                                                              GCancellable    *cancellable,
88                                                              GError         **error);
89
90 #ifdef HAVE_PKCS11
91 static P11KitPin*    on_pin_prompt_callback  (const char     *pinfile,
92                                               P11KitUri      *pin_uri,
93                                               const char     *pin_description,
94                                               P11KitPinFlags  pin_flags,
95                                               void           *callback_data);
96 #endif
97
98 static void g_tls_connection_gnutls_init_priorities (void);
99
100 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GTlsConnectionGnutls, g_tls_connection_gnutls, G_TYPE_TLS_CONNECTION,
101                                   G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
102                                                          g_tls_connection_gnutls_initable_iface_init);
103                                   g_tls_connection_gnutls_init_priorities ();
104                                   );
105
106
107 enum
108 {
109   PROP_0,
110   PROP_BASE_IO_STREAM,
111   PROP_REQUIRE_CLOSE_NOTIFY,
112   PROP_REHANDSHAKE_MODE,
113   PROP_USE_SYSTEM_CERTDB,
114   PROP_DATABASE,
115   PROP_CERTIFICATE,
116   PROP_INTERACTION,
117   PROP_PEER_CERTIFICATE,
118   PROP_PEER_CERTIFICATE_ERRORS
119 };
120
121 struct _GTlsConnectionGnutlsPrivate
122 {
123   GIOStream *base_io_stream;
124   GPollableInputStream *base_istream;
125   GPollableOutputStream *base_ostream;
126
127   gnutls_certificate_credentials creds;
128   gnutls_session session;
129
130   GTlsCertificate *certificate, *peer_certificate;
131   GTlsCertificateFlags peer_certificate_errors;
132   gboolean require_close_notify;
133   GTlsRehandshakeMode rehandshake_mode;
134   gboolean is_system_certdb;
135   GTlsDatabase *database;
136   gboolean database_is_unset;
137   gboolean need_handshake, handshaking, ever_handshaked;
138   gboolean closing;
139
140   GInputStream *tls_istream;
141   GOutputStream *tls_ostream;
142
143   GTlsInteraction *interaction;
144   gchar *interaction_id;
145
146   GError *error;
147   GCancellable *cancellable;
148   gboolean blocking;
149 #ifndef GNUTLS_E_PREMATURE_TERMINATION
150   gboolean eof;
151 #endif
152   GIOCondition internal_direction;
153 };
154
155 static gint unique_interaction_id = 0;
156
157 static void
158 g_tls_connection_gnutls_class_init (GTlsConnectionGnutlsClass *klass)
159 {
160   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
161   GTlsConnectionClass *connection_class = G_TLS_CONNECTION_CLASS (klass);
162   GIOStreamClass *iostream_class = G_IO_STREAM_CLASS (klass);
163
164   g_type_class_add_private (klass, sizeof (GTlsConnectionGnutlsPrivate));
165
166   gobject_class->get_property = g_tls_connection_gnutls_get_property;
167   gobject_class->set_property = g_tls_connection_gnutls_set_property;
168   gobject_class->finalize     = g_tls_connection_gnutls_finalize;
169
170   connection_class->handshake        = g_tls_connection_gnutls_handshake;
171   connection_class->handshake_async  = g_tls_connection_gnutls_handshake_async;
172   connection_class->handshake_finish = g_tls_connection_gnutls_handshake_finish;
173
174   iostream_class->get_input_stream  = g_tls_connection_gnutls_get_input_stream;
175   iostream_class->get_output_stream = g_tls_connection_gnutls_get_output_stream;
176   iostream_class->close_fn          = g_tls_connection_gnutls_close;
177   iostream_class->close_async       = g_tls_connection_gnutls_close_async;
178   iostream_class->close_finish      = g_tls_connection_gnutls_close_finish;
179
180   g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream");
181   g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify");
182   g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode");
183   g_object_class_override_property (gobject_class, PROP_USE_SYSTEM_CERTDB, "use-system-certdb");
184   g_object_class_override_property (gobject_class, PROP_DATABASE, "database");
185   g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
186   g_object_class_override_property (gobject_class, PROP_INTERACTION, "interaction");
187   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE, "peer-certificate");
188   g_object_class_override_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, "peer-certificate-errors");
189 }
190
191 static void
192 g_tls_connection_gnutls_initable_iface_init (GInitableIface *iface)
193 {
194   iface->init = g_tls_connection_gnutls_initable_init;
195 }
196
197 static void
198 g_tls_connection_gnutls_init (GTlsConnectionGnutls *gnutls)
199 {
200   gint unique_id;
201
202   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls, G_TYPE_TLS_CONNECTION_GNUTLS, GTlsConnectionGnutlsPrivate);
203
204   gnutls_certificate_allocate_credentials (&gnutls->priv->creds);
205   gnutls_certificate_set_verify_flags (gnutls->priv->creds,
206                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
207
208   gnutls->priv->need_handshake = TRUE;
209
210   gnutls->priv->database_is_unset = TRUE;
211   gnutls->priv->is_system_certdb = TRUE;
212
213   unique_id = g_atomic_int_add (&unique_interaction_id, 1);
214   gnutls->priv->interaction_id = g_strdup_printf ("gtls:%d", unique_id);
215
216 #ifdef HAVE_PKCS11
217   p11_kit_pin_register_callback (gnutls->priv->interaction_id,
218                                  on_pin_prompt_callback, gnutls, NULL);
219 #endif
220 }
221
222 static gnutls_priority_t priorities[2][2];
223
224 static void
225 g_tls_connection_gnutls_init_priorities (void)
226 {
227   /* First field is "ssl3 only", second is "allow unsafe rehandshaking" */
228
229   gnutls_priority_init (&priorities[FALSE][FALSE],
230                         "NORMAL:%COMPAT",
231                         NULL);
232   gnutls_priority_init (&priorities[TRUE][FALSE],
233                         "NORMAL:%COMPAT:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0",
234                         NULL);
235   gnutls_priority_init (&priorities[FALSE][TRUE],
236                         "NORMAL:%COMPAT:%UNSAFE_RENEGOTIATION",
237                         NULL);
238   gnutls_priority_init (&priorities[TRUE][TRUE],
239                         "NORMAL:%COMPAT:!VERS-TLS1.2:!VERS-TLS1.1:!VERS-TLS1.0:%UNSAFE_RENEGOTIATION",
240                         NULL);
241 }
242
243 static void
244 g_tls_connection_gnutls_set_handshake_priority (GTlsConnectionGnutls *gnutls)
245 {
246   gboolean use_ssl3, unsafe_rehandshake;
247
248   if (G_IS_TLS_CLIENT_CONNECTION (gnutls))
249     use_ssl3 = g_tls_client_connection_get_use_ssl3 (G_TLS_CLIENT_CONNECTION (gnutls));
250   else
251     use_ssl3 = FALSE;
252   unsafe_rehandshake = (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_UNSAFELY);
253   gnutls_priority_set (gnutls->priv->session,
254                        priorities[use_ssl3][unsafe_rehandshake]);
255 }
256
257 static gboolean
258 g_tls_connection_gnutls_initable_init (GInitable     *initable,
259                                        GCancellable  *cancellable,
260                                        GError       **error)
261 {
262   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
263   int status;
264
265   g_return_val_if_fail (gnutls->priv->base_istream != NULL &&
266                         gnutls->priv->base_ostream != NULL, FALSE);
267
268   /* Make sure gnutls->priv->session has been initialized (it may have
269    * already been initialized by a construct-time property setter).
270    */
271   g_tls_connection_gnutls_get_session (gnutls);
272
273   status = gnutls_credentials_set (gnutls->priv->session,
274                                    GNUTLS_CRD_CERTIFICATE,
275                                    gnutls->priv->creds);
276   if (status != 0)
277     {
278       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
279                    _("Could not create TLS connection: %s"),
280                    gnutls_strerror (status));
281       return FALSE;
282     }
283
284   /* Some servers (especially on embedded devices) use tiny keys that
285    * gnutls will reject by default. We want it to accept them.
286    */
287   gnutls_dh_set_prime_bits (gnutls->priv->session, 256);
288
289   gnutls_transport_set_push_function (gnutls->priv->session,
290                                       g_tls_connection_gnutls_push_func);
291   gnutls_transport_set_pull_function (gnutls->priv->session,
292                                       g_tls_connection_gnutls_pull_func);
293   gnutls_transport_set_ptr (gnutls->priv->session, gnutls);
294
295   gnutls->priv->tls_istream = g_tls_input_stream_gnutls_new (gnutls);
296   gnutls->priv->tls_ostream = g_tls_output_stream_gnutls_new (gnutls);
297
298   return TRUE;
299 }
300
301 static void
302 g_tls_connection_gnutls_finalize (GObject *object)
303 {
304   GTlsConnectionGnutls *connection = G_TLS_CONNECTION_GNUTLS (object);
305
306   if (connection->priv->base_io_stream)
307     g_object_unref (connection->priv->base_io_stream);
308
309   if (connection->priv->session)
310     gnutls_deinit (connection->priv->session);
311
312   if (connection->priv->tls_istream)
313     g_object_unref (connection->priv->tls_istream);
314   if (connection->priv->tls_ostream) 
315     g_object_unref (connection->priv->tls_ostream);
316
317   if (connection->priv->creds)
318     gnutls_certificate_free_credentials (connection->priv->creds);
319
320   if (connection->priv->database)
321     g_object_unref (connection->priv->database);
322   if (connection->priv->certificate)
323     g_object_unref (connection->priv->certificate);
324   if (connection->priv->peer_certificate)
325     g_object_unref (connection->priv->peer_certificate);
326
327   g_clear_object (&connection->priv->interaction);
328
329   if (connection->priv->error)
330     g_error_free (connection->priv->error);
331
332 #ifdef HAVE_PKCS11
333   p11_kit_pin_unregister_callback (connection->priv->interaction_id,
334                                    on_pin_prompt_callback, connection);
335 #endif
336   g_free (connection->priv->interaction_id);
337
338   G_OBJECT_CLASS (g_tls_connection_gnutls_parent_class)->finalize (object);
339 }
340
341 static void
342 g_tls_connection_gnutls_get_property (GObject    *object,
343                                       guint       prop_id,
344                                       GValue     *value,
345                                       GParamSpec *pspec)
346 {
347   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
348   GTlsBackend *backend;
349
350   switch (prop_id)
351     {
352     case PROP_BASE_IO_STREAM:
353       g_value_set_object (value, gnutls->priv->base_io_stream);
354       break;
355
356     case PROP_REQUIRE_CLOSE_NOTIFY:
357       g_value_set_boolean (value, gnutls->priv->require_close_notify);
358       break;
359
360     case PROP_REHANDSHAKE_MODE:
361       g_value_set_enum (value, gnutls->priv->rehandshake_mode);
362       break;
363
364     case PROP_USE_SYSTEM_CERTDB:
365       g_value_set_boolean (value, gnutls->priv->is_system_certdb);
366       break;
367
368     case PROP_DATABASE:
369       if (gnutls->priv->database_is_unset)
370         {
371           backend = g_tls_backend_get_default ();
372           gnutls->priv->database =  g_tls_backend_get_default_database (backend);
373           gnutls->priv->database_is_unset = FALSE;
374         }
375       g_value_set_object (value, gnutls->priv->database);
376       break;
377
378     case PROP_CERTIFICATE:
379       g_value_set_object (value, gnutls->priv->certificate);
380       break;
381
382     case PROP_INTERACTION:
383       g_value_set_object (value, gnutls->priv->interaction);
384       break;
385
386     case PROP_PEER_CERTIFICATE:
387       g_value_set_object (value, gnutls->priv->peer_certificate);
388       break;
389
390     case PROP_PEER_CERTIFICATE_ERRORS:
391       g_value_set_flags (value, gnutls->priv->peer_certificate_errors);
392       break;
393
394     default:
395       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
396     }
397 }
398
399 static void
400 g_tls_connection_gnutls_set_property (GObject      *object,
401                                       guint         prop_id,
402                                       const GValue *value,
403                                       GParamSpec   *pspec)
404 {
405   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (object);
406   GInputStream *istream;
407   GOutputStream *ostream;
408   gboolean system_certdb;
409   GTlsBackend *backend;
410
411   switch (prop_id)
412     {
413     case PROP_BASE_IO_STREAM:
414       if (gnutls->priv->base_io_stream)
415         {
416           g_object_unref (gnutls->priv->base_io_stream);
417           gnutls->priv->base_istream = NULL;
418           gnutls->priv->base_ostream = NULL;
419         }
420       gnutls->priv->base_io_stream = g_value_dup_object (value);
421       if (!gnutls->priv->base_io_stream)
422         return;
423
424       istream = g_io_stream_get_input_stream (gnutls->priv->base_io_stream);
425       ostream = g_io_stream_get_output_stream (gnutls->priv->base_io_stream);
426
427       if (G_IS_POLLABLE_INPUT_STREAM (istream) &&
428           g_pollable_input_stream_can_poll (G_POLLABLE_INPUT_STREAM (istream)))
429         gnutls->priv->base_istream = G_POLLABLE_INPUT_STREAM (istream);
430       if (G_IS_POLLABLE_OUTPUT_STREAM (ostream) &&
431           g_pollable_output_stream_can_poll (G_POLLABLE_OUTPUT_STREAM (ostream)))
432         gnutls->priv->base_ostream = G_POLLABLE_OUTPUT_STREAM (ostream);
433       break;
434
435     case PROP_REQUIRE_CLOSE_NOTIFY:
436       gnutls->priv->require_close_notify = g_value_get_boolean (value);
437       break;
438
439     case PROP_REHANDSHAKE_MODE:
440       gnutls->priv->rehandshake_mode = g_value_get_enum (value);
441       break;
442
443     case PROP_USE_SYSTEM_CERTDB:
444       system_certdb = g_value_get_boolean (value);
445       if (system_certdb != gnutls->priv->is_system_certdb)
446         {
447           g_clear_object (&gnutls->priv->database);
448           if (system_certdb)
449             {
450               backend = g_tls_backend_get_default ();
451               gnutls->priv->database = g_tls_backend_get_default_database (backend);
452             }
453           gnutls->priv->is_system_certdb = system_certdb;
454         }
455       break;
456
457     case PROP_DATABASE:
458       g_clear_object (&gnutls->priv->database);
459       gnutls->priv->database = g_value_dup_object (value);
460       gnutls->priv->is_system_certdb = FALSE;
461       gnutls->priv->database_is_unset = FALSE;
462       break;
463
464     case PROP_CERTIFICATE:
465       if (gnutls->priv->certificate)
466         g_object_unref (gnutls->priv->certificate);
467       gnutls->priv->certificate = g_value_dup_object (value);
468       break;
469
470     case PROP_INTERACTION:
471       g_clear_object (&gnutls->priv->interaction);
472       gnutls->priv->interaction = g_value_dup_object (value);
473       break;
474
475     default:
476       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
477     }
478 }
479
480 gnutls_certificate_credentials
481 g_tls_connection_gnutls_get_credentials (GTlsConnectionGnutls *gnutls)
482 {
483   return gnutls->priv->creds;
484 }
485
486 gnutls_session
487 g_tls_connection_gnutls_get_session (GTlsConnectionGnutls *gnutls)
488 {
489   /* Ideally we would initialize gnutls->priv->session from
490    * g_tls_connection_gnutls_init(), but we can't tell if it's a
491    * client or server connection at that point... And
492    * g_tls_connection_gnutls_initiable_init() is too late, because
493    * construct-time property setters may need to modify it.
494    */
495   if (!gnutls->priv->session)
496     {
497       gboolean client = G_IS_TLS_CLIENT_CONNECTION (gnutls);
498       gnutls_init (&gnutls->priv->session, client ? GNUTLS_CLIENT : GNUTLS_SERVER);
499     }
500
501   return gnutls->priv->session;
502 }
503
504 void
505 g_tls_connection_gnutls_get_certificate (GTlsConnectionGnutls *gnutls,
506                                          gnutls_retr2_st      *st)
507 {
508   GTlsCertificate *cert;
509
510   cert = g_tls_connection_get_certificate (G_TLS_CONNECTION (gnutls));
511
512   st->cert_type = GNUTLS_CRT_X509;
513   st->ncerts = 0;
514
515   if (cert)
516       g_tls_certificate_gnutls_copy (G_TLS_CERTIFICATE_GNUTLS (cert),
517                                      gnutls->priv->interaction_id, st);
518 }
519
520 static void
521 begin_gnutls_io (GTlsConnectionGnutls  *gnutls,
522                  gboolean               blocking,
523                  GCancellable          *cancellable)
524 {
525   gnutls->priv->blocking = blocking;
526   gnutls->priv->cancellable = cancellable;
527   gnutls->priv->internal_direction = 0;
528   if (cancellable)
529     g_cancellable_push_current (cancellable);
530   g_clear_error (&gnutls->priv->error);
531 }
532
533 static int
534 end_gnutls_io (GTlsConnectionGnutls  *gnutls,
535                int                    status,
536                GError               **error)
537 {
538   if (gnutls->priv->cancellable)
539     g_cancellable_pop_current (gnutls->priv->cancellable);
540   gnutls->priv->cancellable = NULL;
541
542   if (status >= 0)
543     {
544       g_clear_error (&gnutls->priv->error);
545       return status;
546     }
547
548   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
549     {
550       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_FAILED) ||
551           status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH ||
552           status == GNUTLS_E_FATAL_ALERT_RECEIVED ||
553           status == GNUTLS_E_DECRYPTION_FAILED ||
554           status == GNUTLS_E_UNSUPPORTED_VERSION_PACKET)
555         {
556           g_clear_error (&gnutls->priv->error);
557           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_NOT_TLS,
558                                _("Peer failed to perform TLS handshake"));
559           return GNUTLS_E_PULL_ERROR;
560         }
561     }
562
563   if (gnutls->priv->error)
564     {
565       if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
566         status = GNUTLS_E_AGAIN;
567       g_propagate_error (error, gnutls->priv->error);
568       gnutls->priv->error = NULL;
569       return status;
570     }
571   else if (status == GNUTLS_E_REHANDSHAKE)
572     {
573       if (gnutls->priv->rehandshake_mode == G_TLS_REHANDSHAKE_NEVER)
574         {
575           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC,
576                                _("Peer requested illegal TLS rehandshake"));
577           return GNUTLS_E_PULL_ERROR;
578         }
579
580       gnutls->priv->need_handshake = TRUE;
581       return status;
582     }
583   else if (
584 #ifdef GNUTLS_E_PREMATURE_TERMINATION
585            status == GNUTLS_E_PREMATURE_TERMINATION
586 #else
587            status == GNUTLS_E_UNEXPECTED_PACKET_LENGTH && gnutls->priv->eof
588 #endif
589            )
590     {
591       if (gnutls->priv->require_close_notify)
592         {
593           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_EOF,
594                                _("TLS connection closed unexpectedly"));
595           return status;
596         }
597       else
598         return 0;
599     }
600
601   return status;
602 }
603
604 #define BEGIN_GNUTLS_IO(gnutls, blocking, cancellable)  \
605   begin_gnutls_io (gnutls, blocking, cancellable);      \
606   do {
607
608 #define END_GNUTLS_IO(gnutls, ret, errmsg, error)       \
609   } while ((ret == GNUTLS_E_AGAIN ||                    \
610             ret == GNUTLS_E_WARNING_ALERT_RECEIVED) &&  \
611            !gnutls->priv->error);                       \
612   ret = end_gnutls_io (gnutls, ret, error);             \
613   if (ret < 0 && ret != GNUTLS_E_REHANDSHAKE && error && !*error) \
614     {                                                   \
615       g_set_error (error, G_TLS_ERROR, G_TLS_ERROR_MISC,\
616                    errmsg, gnutls_strerror (ret));      \
617     }                                                   \
618   ;
619
620 gboolean
621 g_tls_connection_gnutls_check (GTlsConnectionGnutls  *gnutls,
622                                GIOCondition           condition)
623 {
624   if (!gnutls->priv->internal_direction)
625     return TRUE;
626
627   if (gnutls->priv->handshaking || gnutls->priv->closing)
628     condition = gnutls->priv->internal_direction;
629
630   if (condition & G_IO_IN)
631     return g_pollable_input_stream_is_readable (gnutls->priv->base_istream);
632   else
633     return g_pollable_output_stream_is_writable (gnutls->priv->base_ostream);
634 }
635
636 typedef struct {
637   GSource source;
638
639   GTlsConnectionGnutls *gnutls;
640   GObject              *stream;
641
642   GSource              *child_source;
643   GIOCondition          current_direction;
644 } GTlsConnectionGnutlsSource;
645
646 static gboolean
647 gnutls_source_prepare (GSource *source,
648                        gint    *timeout)
649 {
650   *timeout = -1;
651   return FALSE;
652 }
653
654 static gboolean
655 gnutls_source_check (GSource *source)
656 {
657   return FALSE;
658 }
659
660 static gboolean
661 gnutls_source_sync_child_source (GTlsConnectionGnutlsSource *gnutls_source)
662 {
663   GTlsConnectionGnutls *gnutls = gnutls_source->gnutls;
664   GSource *source = (GSource *)gnutls_source;
665   GIOCondition direction;
666
667   if (gnutls->priv->handshaking || gnutls->priv->closing)
668     direction = gnutls->priv->internal_direction;
669   else if (!gnutls_source->stream)
670     return FALSE;
671   else if (G_IS_TLS_INPUT_STREAM_GNUTLS (gnutls_source->stream))
672     direction = G_IO_IN;
673   else
674     direction = G_IO_OUT;
675
676   if (direction == gnutls_source->current_direction)
677     return TRUE;
678
679   if (gnutls_source->child_source)
680     {
681       g_source_remove_child_source (source, gnutls_source->child_source);
682       g_source_unref (gnutls_source->child_source);
683     }
684
685   if (direction & G_IO_IN)
686     gnutls_source->child_source = g_pollable_input_stream_create_source (gnutls->priv->base_istream, NULL);
687   else
688     gnutls_source->child_source = g_pollable_output_stream_create_source (gnutls->priv->base_ostream, NULL);
689
690   g_source_set_dummy_callback (gnutls_source->child_source);
691   g_source_add_child_source (source, gnutls_source->child_source);
692   gnutls_source->current_direction = direction;
693   return TRUE;
694 }
695
696 static gboolean
697 gnutls_source_dispatch (GSource     *source,
698                         GSourceFunc  callback,
699                         gpointer     user_data)
700 {
701   GPollableSourceFunc func = (GPollableSourceFunc)callback;
702   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
703   gboolean ret;
704
705   ret = (*func) (gnutls_source->stream, user_data);
706   if (ret)
707     ret = gnutls_source_sync_child_source (gnutls_source);
708
709   return ret;
710 }
711
712 static void
713 gnutls_source_finalize (GSource *source)
714 {
715   GTlsConnectionGnutlsSource *gnutls_source = (GTlsConnectionGnutlsSource *)source;
716
717   g_object_unref (gnutls_source->gnutls);
718
719   if (gnutls_source->child_source)
720     g_source_unref (gnutls_source->child_source);
721 }
722
723 static gboolean
724 g_tls_connection_gnutls_source_closure_callback (GObject  *stream,
725                                                  gpointer  data)
726 {
727   GClosure *closure = data;
728
729   GValue param = { 0, };
730   GValue result_value = { 0, };
731   gboolean result;
732
733   g_value_init (&result_value, G_TYPE_BOOLEAN);
734
735   g_value_init (&param, G_TYPE_OBJECT);
736   g_value_set_object (&param, stream);
737
738   g_closure_invoke (closure, &result_value, 1, &param, NULL);
739
740   result = g_value_get_boolean (&result_value);
741   g_value_unset (&result_value);
742   g_value_unset (&param);
743
744   return result;
745 }
746
747 static GSourceFuncs gnutls_source_funcs =
748 {
749   gnutls_source_prepare,
750   gnutls_source_check,
751   gnutls_source_dispatch,
752   gnutls_source_finalize,
753   (GSourceFunc)g_tls_connection_gnutls_source_closure_callback,
754   (GSourceDummyMarshal)g_cclosure_marshal_generic
755 };
756
757 GSource *
758 g_tls_connection_gnutls_create_source (GTlsConnectionGnutls  *gnutls,
759                                        GIOCondition           condition,
760                                        GCancellable          *cancellable)
761 {
762   GSource *source, *cancellable_source;
763   GTlsConnectionGnutlsSource *gnutls_source;
764
765   source = g_source_new (&gnutls_source_funcs, sizeof (GTlsConnectionGnutlsSource));
766   g_source_set_name (source, "GTlsConnectionGnutlsSource");
767   gnutls_source = (GTlsConnectionGnutlsSource *)source;
768   gnutls_source->gnutls = g_object_ref (gnutls);
769   if (condition & G_IO_IN)
770     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_istream);
771   else if (condition & G_IO_OUT)
772     gnutls_source->stream = G_OBJECT (gnutls->priv->tls_ostream);
773   gnutls_source_sync_child_source (gnutls_source);
774
775   if (cancellable)
776     {
777       cancellable_source = g_cancellable_source_new (cancellable);
778       g_source_set_dummy_callback (cancellable_source);
779       g_source_add_child_source (source, cancellable_source);
780       g_source_unref (cancellable_source);
781     }
782
783   return source;
784 }
785
786 static void
787 set_gnutls_error (GTlsConnectionGnutls *gnutls, GIOCondition direction)
788 {
789   if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
790     gnutls_transport_set_errno (gnutls->priv->session, EINTR);
791   else if (g_error_matches (gnutls->priv->error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
792     {
793       gnutls_transport_set_errno (gnutls->priv->session, EAGAIN);
794       gnutls->priv->internal_direction = direction;
795     }
796   else
797     gnutls_transport_set_errno (gnutls->priv->session, EIO);
798 }
799
800 static ssize_t
801 g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t  transport_data,
802                                    void                   *buf,
803                                    size_t                  buflen)
804 {
805   GTlsConnectionGnutls *gnutls = transport_data;
806   ssize_t ret;
807
808   /* If gnutls->priv->error is non-%NULL when we're called, it means
809    * that an error previously occurred, but gnutls decided not to
810    * propagate it. So it's correct for us to just clear it. (Usually
811    * this means it ignored an EAGAIN after a short read, and now
812    * we'll return EAGAIN again, which it will obey this time.)
813    */
814   g_clear_error (&gnutls->priv->error);
815
816   if (gnutls->priv->blocking)
817     {
818       ret = g_input_stream_read (G_INPUT_STREAM (gnutls->priv->base_istream),
819                                  buf, buflen,
820                                  gnutls->priv->cancellable,
821                                  &gnutls->priv->error);
822     }
823   else
824     {
825       ret = g_pollable_input_stream_read_nonblocking (gnutls->priv->base_istream,
826                                                       buf, buflen,
827                                                       gnutls->priv->cancellable,
828                                                       &gnutls->priv->error);
829     }
830
831   if (ret < 0)
832     set_gnutls_error (gnutls, G_IO_IN);
833 #ifndef GNUTLS_E_PREMATURE_TERMINATION
834   else if (ret == 0)
835     gnutls->priv->eof = TRUE;
836 #endif
837
838   return ret;
839 }
840
841 static ssize_t
842 g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t  transport_data,
843                                    const void             *buf,
844                                    size_t                  buflen)
845 {
846   GTlsConnectionGnutls *gnutls = transport_data;
847   ssize_t ret;
848
849   /* See comment in pull_func. */
850   g_clear_error (&gnutls->priv->error);
851
852   if (gnutls->priv->blocking)
853     {
854       ret = g_output_stream_write (G_OUTPUT_STREAM (gnutls->priv->base_ostream),
855                                    buf, buflen,
856                                    gnutls->priv->cancellable,
857                                    &gnutls->priv->error);
858     }
859   else
860     {
861       ret = g_pollable_output_stream_write_nonblocking (gnutls->priv->base_ostream,
862                                                         buf, buflen,
863                                                         gnutls->priv->cancellable,
864                                                         &gnutls->priv->error);
865     }
866   if (ret < 0)
867     set_gnutls_error (gnutls, G_IO_OUT);
868
869   return ret;
870 }
871
872 static gboolean
873 handshake_internal (GTlsConnectionGnutls  *gnutls,
874                     gboolean               blocking,
875                     GCancellable          *cancellable,
876                     GError               **error)
877 {
878   GTlsCertificate *peer_certificate = NULL;
879   GTlsCertificateFlags peer_certificate_errors = 0;
880   int ret;
881
882   if (G_IS_TLS_SERVER_CONNECTION_GNUTLS (gnutls) &&
883       gnutls->priv->ever_handshaked && !gnutls->priv->handshaking &&
884       !gnutls->priv->need_handshake)
885     {
886       BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
887       ret = gnutls_rehandshake (gnutls->priv->session);
888       END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
889
890       if (ret != 0)
891         return FALSE;
892     }
893
894   if (!gnutls->priv->handshaking)
895     {
896       gnutls->priv->handshaking = TRUE;
897
898       if (gnutls->priv->peer_certificate)
899         {
900           g_object_unref (gnutls->priv->peer_certificate);
901           gnutls->priv->peer_certificate = NULL;
902           gnutls->priv->peer_certificate_errors = 0;
903
904           g_object_notify (G_OBJECT (gnutls), "peer-certificate");
905           g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
906         }
907
908       g_tls_connection_gnutls_set_handshake_priority (gnutls);
909       G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->begin_handshake (gnutls);
910     }
911
912   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
913   ret = gnutls_handshake (gnutls->priv->session);
914   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS handshake: %s"), error);
915
916   if (ret == GNUTLS_E_AGAIN)
917     return FALSE;
918
919   gnutls->priv->handshaking = FALSE;
920   gnutls->priv->need_handshake = FALSE;
921   gnutls->priv->ever_handshaked = TRUE;
922
923   if (ret == 0 &&
924       gnutls_certificate_type_get (gnutls->priv->session) == GNUTLS_CRT_X509)
925     {
926       GTlsCertificate *chain, *cert;
927       const gnutls_datum_t *certs;
928       unsigned int num_certs;
929       int i;
930
931       certs = gnutls_certificate_get_peers (gnutls->priv->session, &num_certs);
932       chain = NULL;
933       if (certs)
934         {
935           for (i = num_certs - 1; i >= 0; i--)
936             {
937               cert = g_tls_certificate_gnutls_new (&certs[i], chain);
938               if (chain)
939                 g_object_unref (chain);
940               chain = cert;
941             }
942         }
943
944       peer_certificate = chain;
945     }
946
947   if (peer_certificate)
948     {
949       gboolean accepted;
950
951       accepted = G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->verify_peer (gnutls, peer_certificate, &peer_certificate_errors);
952
953       gnutls->priv->peer_certificate = peer_certificate;
954       gnutls->priv->peer_certificate_errors = peer_certificate_errors;
955
956       g_object_notify (G_OBJECT (gnutls), "peer-certificate");
957       g_object_notify (G_OBJECT (gnutls), "peer-certificate-errors");
958
959       if (!accepted)
960         {
961           g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
962                                _("Unacceptable TLS certificate"));
963           return FALSE;
964         }
965     }
966
967   G_TLS_CONNECTION_GNUTLS_GET_CLASS (gnutls)->finish_handshake (gnutls, ret == 0, error);
968   return (ret == 0);
969 }
970
971 static gboolean
972 handshake_in_progress_or_failed (GTlsConnectionGnutls  *gnutls,
973                                  gboolean               blocking,
974                                  GCancellable          *cancellable,
975                                  GError               **error)
976 {
977   if (!(gnutls->priv->need_handshake || gnutls->priv->handshaking))
978     return FALSE;
979
980   return !handshake_internal (gnutls, blocking, cancellable, error);
981 }
982
983 static gboolean
984 g_tls_connection_gnutls_handshake (GTlsConnection   *conn,
985                                    GCancellable     *cancellable,
986                                    GError          **error)
987 {
988   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
989
990   return handshake_internal (gnutls, TRUE, cancellable, error);
991 }
992
993 static gboolean
994 g_tls_connection_gnutls_handshake_ready (GObject  *pollable_stream,
995                                          gpointer  user_data)
996 {
997   GTlsConnectionGnutls *gnutls;
998   GSimpleAsyncResult *simple = user_data;
999   gboolean success;
1000   GError *error = NULL;
1001
1002   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
1003   g_object_unref (gnutls);
1004
1005   success = handshake_internal (gnutls, FALSE, NULL, &error);
1006   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1007     {
1008       g_error_free (error);
1009       return TRUE;
1010     }
1011
1012   if (error)
1013     {
1014       g_simple_async_result_set_from_error (simple, error);
1015       g_error_free (error);
1016     }
1017   else
1018     g_simple_async_result_set_op_res_gboolean (simple, success);
1019   g_simple_async_result_complete (simple);
1020   g_object_unref (simple);
1021
1022   return FALSE;
1023 }
1024
1025 static void
1026 g_tls_connection_gnutls_handshake_async (GTlsConnection       *conn,
1027                                          int                   io_priority,
1028                                          GCancellable         *cancellable,
1029                                          GAsyncReadyCallback   callback,
1030                                          gpointer              user_data)
1031 {
1032   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
1033   GSimpleAsyncResult *simple;
1034   gboolean success;
1035   GError *error = NULL;
1036   GSource *source;
1037
1038   simple = g_simple_async_result_new (G_OBJECT (conn), callback, user_data,
1039                                       g_tls_connection_gnutls_handshake_async);
1040   success = handshake_internal (gnutls, FALSE, cancellable, &error);
1041   if (success)
1042     {
1043       g_simple_async_result_set_op_res_gboolean (simple, TRUE);
1044       g_simple_async_result_complete_in_idle (simple);
1045       g_object_unref (simple);
1046     }
1047   else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1048     {
1049       g_simple_async_result_set_from_error (simple, error);
1050       g_error_free (error);
1051       g_simple_async_result_complete_in_idle (simple);
1052       g_object_unref (simple);
1053     }
1054   else if (error)
1055     g_error_free (error);
1056
1057   source = g_tls_connection_gnutls_create_source (gnutls, 0, cancellable);
1058   g_source_set_callback (source,
1059                          (GSourceFunc) g_tls_connection_gnutls_handshake_ready,
1060                          simple, NULL);
1061   g_source_set_priority (source, io_priority);
1062   g_source_attach (source, g_main_context_get_thread_default ());
1063   g_source_unref (source);
1064 }
1065
1066 static gboolean
1067 g_tls_connection_gnutls_handshake_finish (GTlsConnection       *conn,
1068                                           GAsyncResult         *result,
1069                                           GError              **error)
1070 {
1071   GSimpleAsyncResult *simple;
1072
1073   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (conn), g_tls_connection_gnutls_handshake_async), FALSE);
1074
1075   simple = G_SIMPLE_ASYNC_RESULT (result);
1076
1077   if (g_simple_async_result_propagate_error (simple, error))
1078     return FALSE;
1079
1080   return g_simple_async_result_get_op_res_gboolean (simple);
1081 }
1082
1083 gssize
1084 g_tls_connection_gnutls_read (GTlsConnectionGnutls  *gnutls,
1085                               void                  *buffer,
1086                               gsize                  count,
1087                               gboolean               blocking,
1088                               GCancellable          *cancellable,
1089                               GError               **error)
1090 {
1091   gssize ret;
1092
1093  again:
1094   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1095     return -1;
1096
1097   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1098   ret = gnutls_record_recv (gnutls->priv->session, buffer, count);
1099   END_GNUTLS_IO (gnutls, ret, _("Error reading data from TLS socket: %s"), error);
1100
1101   if (ret >= 0)
1102     return ret;
1103   else if (ret == GNUTLS_E_REHANDSHAKE)
1104     goto again;
1105   else
1106     return -1;
1107 }
1108
1109 gssize
1110 g_tls_connection_gnutls_write (GTlsConnectionGnutls  *gnutls,
1111                                const void            *buffer,
1112                                gsize                  count,
1113                                gboolean               blocking,
1114                                GCancellable          *cancellable,
1115                                GError               **error)
1116 {
1117   gssize ret;
1118
1119  again:
1120   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1121     return -1;
1122
1123   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1124   ret = gnutls_record_send (gnutls->priv->session, buffer, count);
1125   END_GNUTLS_IO (gnutls, ret, _("Error writing data to TLS socket: %s"), error);
1126
1127   if (ret >= 0)
1128     return ret;
1129   else if (ret == GNUTLS_E_REHANDSHAKE)
1130     goto again;
1131   else
1132     return -1;
1133 }
1134
1135 static GInputStream  *
1136 g_tls_connection_gnutls_get_input_stream (GIOStream *stream)
1137 {
1138   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1139
1140   return gnutls->priv->tls_istream;
1141 }
1142
1143 static GOutputStream *
1144 g_tls_connection_gnutls_get_output_stream (GIOStream *stream)
1145 {
1146   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1147
1148   return gnutls->priv->tls_ostream;
1149 }
1150
1151 static gboolean
1152 close_internal (GTlsConnectionGnutls  *gnutls,
1153                 gboolean               blocking,
1154                 GCancellable          *cancellable,
1155                 GError               **error)
1156 {
1157   int ret;
1158
1159   /* If we haven't finished the initial handshake yet, there's no
1160    * reason to finish it just so we can close.
1161    */
1162   if (gnutls->priv->handshaking && !gnutls->priv->ever_handshaked)
1163     return TRUE;
1164
1165   if (handshake_in_progress_or_failed (gnutls, blocking, cancellable, error))
1166     return FALSE;
1167
1168   gnutls->priv->closing = TRUE;
1169   BEGIN_GNUTLS_IO (gnutls, blocking, cancellable);
1170   ret = gnutls_bye (gnutls->priv->session, GNUTLS_SHUT_WR);
1171   END_GNUTLS_IO (gnutls, ret, _("Error performing TLS close: %s"), error);
1172   if (ret == 0 || !error || !g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1173     gnutls->priv->closing = FALSE;
1174
1175   return ret == 0;
1176 }
1177
1178 static gboolean
1179 g_tls_connection_gnutls_close (GIOStream     *stream,
1180                                GCancellable  *cancellable,
1181                                GError       **error)
1182 {
1183   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1184
1185   if (!close_internal (gnutls, TRUE, cancellable, error))
1186     return FALSE;
1187   return g_io_stream_close (gnutls->priv->base_io_stream,
1188                             cancellable, error);
1189 }
1190
1191 typedef struct {
1192   GSimpleAsyncResult *simple;
1193   GCancellable *cancellable;
1194   int io_priority;
1195 } AsyncCloseData;
1196
1197 static void
1198 close_base_stream_cb (GObject      *base_stream,
1199                       GAsyncResult *result,
1200                       gpointer      user_data)
1201 {
1202   gboolean success;
1203   GError *error = NULL;
1204   AsyncCloseData *acd = user_data;
1205
1206   success = g_io_stream_close_finish (G_IO_STREAM (base_stream),
1207                                       result, &error);
1208   if (success)
1209     g_simple_async_result_set_op_res_gboolean (acd->simple, TRUE);
1210   else
1211     {
1212       g_simple_async_result_set_from_error (acd->simple, error);
1213       g_error_free (error);
1214     }
1215
1216   g_simple_async_result_complete (acd->simple);
1217   g_object_unref (acd->simple);
1218   if (acd->cancellable)
1219     g_object_unref (acd->cancellable);
1220   g_slice_free (AsyncCloseData, acd);
1221 }
1222
1223 static gboolean
1224 g_tls_connection_gnutls_close_ready (GObject  *pollable_stream,
1225                                      gpointer  user_data)
1226 {
1227   GTlsConnectionGnutls *gnutls;
1228   AsyncCloseData *acd = user_data;
1229   gboolean success;
1230   GError *error = NULL;
1231
1232   gnutls = G_TLS_CONNECTION_GNUTLS (g_async_result_get_source_object (G_ASYNC_RESULT (acd->simple)));
1233   g_object_unref (gnutls);
1234
1235   success = close_internal (gnutls, FALSE, NULL, &error);
1236   if (!success && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1237     {
1238       g_error_free (error);
1239       return TRUE;
1240     }
1241
1242   if (error)
1243     {
1244       g_simple_async_result_set_from_error (acd->simple, error);
1245       g_simple_async_result_complete (acd->simple);
1246       g_error_free (error);
1247       g_object_unref (acd->simple);
1248       if (acd->cancellable)
1249         g_object_unref (acd->cancellable);
1250       g_slice_free (AsyncCloseData, acd);
1251     }
1252   else
1253     {
1254       g_io_stream_close_async (gnutls->priv->base_io_stream,
1255                                acd->io_priority, acd->cancellable,
1256                                close_base_stream_cb, acd);
1257     }
1258
1259   return FALSE;
1260 }
1261
1262 static void
1263 g_tls_connection_gnutls_close_async (GIOStream           *stream,
1264                                      int                  io_priority,
1265                                      GCancellable        *cancellable,
1266                                      GAsyncReadyCallback  callback,
1267                                      gpointer             user_data)
1268 {
1269   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (stream);
1270   GSimpleAsyncResult *simple;
1271   gboolean success;
1272   GError *error = NULL;
1273   AsyncCloseData *acd;
1274   GSource *source;
1275
1276   simple = g_simple_async_result_new (G_OBJECT (stream), callback, user_data,
1277                                       g_tls_connection_gnutls_close_async);
1278
1279   success = close_internal (gnutls, FALSE, cancellable, &error);
1280   if (error && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1281     {
1282       g_simple_async_result_set_from_error (simple, error);
1283       g_error_free (error);
1284       g_simple_async_result_complete_in_idle (simple);
1285       g_object_unref (simple);
1286     }
1287
1288   if (error)
1289     g_error_free (error);
1290
1291   acd = g_slice_new (AsyncCloseData);
1292   acd->simple = simple;
1293   acd->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
1294   acd->io_priority = io_priority;
1295
1296   if (success)
1297     {
1298       g_io_stream_close_async (gnutls->priv->base_io_stream,
1299                                io_priority, cancellable,
1300                                close_base_stream_cb, acd);
1301       return;
1302     }
1303
1304   source = g_tls_connection_gnutls_create_source (gnutls, 0, acd->cancellable);
1305   g_source_set_callback (source,
1306                          (GSourceFunc) g_tls_connection_gnutls_close_ready,
1307                          acd, NULL);
1308   g_source_set_priority (source, acd->io_priority);
1309   g_source_attach (source, g_main_context_get_thread_default ());
1310   g_source_unref (source);
1311 }
1312
1313 static gboolean
1314 g_tls_connection_gnutls_close_finish (GIOStream           *stream,
1315                                       GAsyncResult        *result,
1316                                       GError             **error)
1317 {
1318   GSimpleAsyncResult *simple;
1319
1320   g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (stream), g_tls_connection_gnutls_close_async), FALSE);
1321
1322   simple = G_SIMPLE_ASYNC_RESULT (result);
1323
1324   if (g_simple_async_result_propagate_error (simple, error))
1325     return FALSE;
1326
1327   return g_simple_async_result_get_op_res_gboolean (simple);
1328 }
1329
1330 #ifdef HAVE_PKCS11
1331
1332 static P11KitPin*
1333 on_pin_prompt_callback (const char     *pinfile,
1334                         P11KitUri      *pin_uri,
1335                         const char     *pin_description,
1336                         P11KitPinFlags  pin_flags,
1337                         void           *callback_data)
1338 {
1339   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (callback_data);
1340   GTlsInteractionResult result;
1341   GTlsPasswordFlags flags = 0;
1342   GTlsPassword *password;
1343   P11KitPin *pin = NULL;
1344   GError *error = NULL;
1345
1346   if (!gnutls->priv->interaction)
1347     return NULL;
1348
1349   if (pin_flags & P11_KIT_PIN_FLAGS_RETRY)
1350     flags |= G_TLS_PASSWORD_RETRY;
1351   if (pin_flags & P11_KIT_PIN_FLAGS_MANY_TRIES)
1352     flags |= G_TLS_PASSWORD_MANY_TRIES;
1353   if (pin_flags & P11_KIT_PIN_FLAGS_FINAL_TRY)
1354     flags |= G_TLS_PASSWORD_FINAL_TRY;
1355
1356   password = g_pkcs11_pin_new (flags, pin_description);
1357
1358   result = g_tls_interaction_ask_password (gnutls->priv->interaction, password,
1359                                            g_cancellable_get_current (), &error);
1360
1361   switch (result)
1362     {
1363     case G_TLS_INTERACTION_FAILED:
1364       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
1365         g_warning ("couldn't ask for password: %s", error->message);
1366       pin = NULL;
1367       break;
1368     case G_TLS_INTERACTION_UNHANDLED:
1369       pin = NULL;
1370       break;
1371     case G_TLS_INTERACTION_HANDLED:
1372       pin = g_pkcs11_pin_steal_internal (G_PKCS11_PIN (password));
1373       break;
1374     }
1375
1376   g_object_unref (password);
1377   return pin;
1378 }
1379
1380 #endif /* HAVE_PKCS11 */