Imported Upstream version 2.72.alpha
[platform/upstream/glib-networking.git] / tls / gnutls / gtlsclientconnection-gnutls.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * GIO - GLib Input, Output and Streaming Library
4  *
5  * Copyright 2010 Red Hat, Inc
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General
18  * Public License along with this library; if not, see
19  * <http://www.gnu.org/licenses/>.
20  *
21  * In addition, when the library is used with OpenSSL, a special
22  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
23  */
24
25 #include "config.h"
26 #include "glib.h"
27
28 #include <errno.h>
29 #include <gnutls/gnutls.h>
30 #include <gnutls/x509.h>
31 #include <string.h>
32
33 #include "gtlsconnection-base.h"
34 #include "gtlsclientconnection-gnutls.h"
35 #include "gtlsbackend-gnutls.h"
36 #include "gtlscertificate-gnutls.h"
37 #include <glib/gi18n-lib.h>
38
39 enum
40 {
41   PROP_0,
42   PROP_VALIDATION_FLAGS,
43   PROP_SERVER_IDENTITY,
44   PROP_USE_SSL3,
45   PROP_ACCEPTED_CAS
46 };
47
48 struct _GTlsClientConnectionGnutls
49 {
50   GTlsConnectionGnutls parent_instance;
51
52   GTlsCertificateFlags validation_flags;
53   GSocketConnectable *server_identity;
54   gboolean use_ssl3;
55
56   /* session_data is either the session ticket that was used to resume this
57    * connection, or the most recent session ticket received from the server.
58    * Because session ticket reuse is generally undesirable, it should only be
59    * accessed if session_data_override is set.
60    */
61   GBytes *session_id;
62   GBytes *session_data;
63   gboolean session_data_override;
64
65   GPtrArray *accepted_cas;
66   gboolean accepted_cas_changed;
67
68   gnutls_pcert_st *pcert;
69   unsigned int pcert_length;
70   gnutls_privkey_t pkey;
71 };
72
73 static void g_tls_client_connection_gnutls_initable_interface_init (GInitableIface  *iface);
74
75 static void g_tls_client_connection_gnutls_client_connection_interface_init (GTlsClientConnectionInterface *iface);
76 static void g_tls_client_connection_gnutls_dtls_client_connection_interface_init (GDtlsClientConnectionInterface *iface);
77
78 static int g_tls_client_connection_gnutls_handshake_thread_retrieve_function (gnutls_session_t              session,
79                                                                               const gnutls_datum_t         *req_ca_rdn,
80                                                                               int                           nreqs,
81                                                                               const gnutls_pk_algorithm_t  *pk_algos,
82                                                                               int                           pk_algos_length,
83                                                                               gnutls_pcert_st             **pcert,
84                                                                               unsigned int                 *pcert_length,
85                                                                               gnutls_privkey_t             *pkey);
86
87 static GInitableIface *g_tls_client_connection_gnutls_parent_initable_iface;
88
89 G_DEFINE_TYPE_WITH_CODE (GTlsClientConnectionGnutls, g_tls_client_connection_gnutls, G_TYPE_TLS_CONNECTION_GNUTLS,
90                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
91                                                 g_tls_client_connection_gnutls_initable_interface_init)
92                          G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION,
93                                                 g_tls_client_connection_gnutls_client_connection_interface_init);
94                          G_IMPLEMENT_INTERFACE (G_TYPE_DTLS_CLIENT_CONNECTION,
95                                                 g_tls_client_connection_gnutls_dtls_client_connection_interface_init));
96
97 static void
98 clear_gnutls_certificate_copy (gnutls_pcert_st  **pcert,
99                                guint             *pcert_length,
100                                gnutls_privkey_t  *pkey)
101 {
102   g_tls_certificate_gnutls_copy_free (*pcert, *pcert_length, *pkey);
103
104   *pcert = NULL;
105   *pcert_length = 0;
106   *pkey = NULL;
107 }
108
109 static void
110 g_tls_client_connection_gnutls_init (GTlsClientConnectionGnutls *gnutls)
111 {
112 }
113
114 static const gchar *
115 get_server_identity (GTlsClientConnectionGnutls *gnutls)
116 {
117   if (G_IS_NETWORK_ADDRESS (gnutls->server_identity))
118     return g_network_address_get_hostname (G_NETWORK_ADDRESS (gnutls->server_identity));
119   else if (G_IS_NETWORK_SERVICE (gnutls->server_identity))
120     return g_network_service_get_domain (G_NETWORK_SERVICE (gnutls->server_identity));
121   else
122     return NULL;
123 }
124
125 static void
126 g_tls_client_connection_gnutls_compute_session_id (GTlsClientConnectionGnutls *gnutls)
127 {
128   GSocketConnection *base_conn;
129   GSocketAddress *remote_addr;
130   GInetAddress *iaddr;
131   guint port;
132
133   /* The testsuite expects handshakes to actually happen. E.g. a test might
134    * check to see that a handshake succeeds and then later check that a new
135    * handshake fails. If we get really unlucky and the same port number is
136    * reused for the server socket between connections, then we'll accidentally
137    * resume the old session and skip certificate verification. Such failures
138    * are difficult to debug because they require running the tests hundreds of
139    * times simultaneously to reproduce (the port number does not get reused
140    * quickly enough if the tests are run sequentially).
141    *
142    * So session resumption will just need to be tested manually.
143    */
144   if (g_test_initialized ())
145     return;
146
147   /* Create a TLS "session ID." We base it on the IP address since
148    * different hosts serving the same hostname/service will probably
149    * not share the same session cache. We base it on the
150    * server-identity because at least some servers will fail (rather
151    * than just failing to resume the session) if we don't.
152    * (https://bugs.launchpad.net/bugs/823325)
153    *
154    * Note that our session IDs have no relation to TLS protocol
155    * session IDs, e.g. as provided by gnutls_session_get_id2(). Unlike
156    * our session IDs, actual TLS session IDs can no longer be used for
157    * session resumption.
158    */
159   g_object_get (G_OBJECT (gnutls), "base-io-stream", &base_conn, NULL);
160   if (G_IS_SOCKET_CONNECTION (base_conn))
161     {
162       remote_addr = g_socket_connection_get_remote_address (base_conn, NULL);
163       if (G_IS_INET_SOCKET_ADDRESS (remote_addr))
164         {
165           GInetSocketAddress *isaddr = G_INET_SOCKET_ADDRESS (remote_addr);
166           const gchar *server_hostname;
167           gchar *addrstr, *session_id;
168           GTlsCertificate *cert = NULL;
169           gchar *cert_hash = NULL;
170
171           iaddr = g_inet_socket_address_get_address (isaddr);
172           port = g_inet_socket_address_get_port (isaddr);
173
174           addrstr = g_inet_address_to_string (iaddr);
175           server_hostname = get_server_identity (gnutls);
176
177           /* If we have a certificate, make its hash part of the session ID, so
178            * that different connections to the same server can use different
179            * certificates.
180            */
181           g_object_get (G_OBJECT (gnutls), "certificate", &cert, NULL);
182           if (cert)
183             {
184               GByteArray *der = NULL;
185               g_object_get (G_OBJECT (cert), "certificate", &der, NULL);
186               if (der)
187                 {
188                   cert_hash = g_compute_checksum_for_data (G_CHECKSUM_SHA256, der->data, der->len);
189                   g_byte_array_unref (der);
190                 }
191               g_object_unref (cert);
192             }
193           session_id = g_strdup_printf ("%s/%s/%d/%s", addrstr,
194                                         server_hostname ? server_hostname : "",
195                                         port,
196                                         cert_hash ? cert_hash : "");
197           gnutls->session_id = g_bytes_new_take (session_id, strlen (session_id));
198           g_free (addrstr);
199           g_free (cert_hash);
200         }
201       g_object_unref (remote_addr);
202     }
203   g_clear_object (&base_conn);
204 }
205
206 static int
207 handshake_thread_session_ticket_received_cb (gnutls_session_t      session,
208                                              guint                 htype,
209                                              guint                 when,
210                                              guint                 incoming,
211                                              const gnutls_datum_t *msg)
212 {
213   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (gnutls_session_get_ptr (session));
214   gnutls_datum_t session_datum;
215
216   if (gnutls_session_get_data2 (session, &session_datum) == GNUTLS_E_SUCCESS)
217     {
218       g_clear_pointer (&gnutls->session_data, g_bytes_unref);
219       gnutls->session_data = g_bytes_new_with_free_func (session_datum.data,
220                                                          session_datum.size,
221                                                          (GDestroyNotify)gnutls_free,
222                                                          session_datum.data);
223
224       if (gnutls->session_id)
225         {
226           g_tls_backend_gnutls_store_session_data (gnutls->session_id,
227                                                    gnutls->session_data);
228         }
229     }
230
231   return 0;
232 }
233
234 static void
235 g_tls_client_connection_gnutls_finalize (GObject *object)
236 {
237   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
238
239   g_clear_object (&gnutls->server_identity);
240   g_clear_pointer (&gnutls->accepted_cas, g_ptr_array_unref);
241   g_clear_pointer (&gnutls->session_id, g_bytes_unref);
242   g_clear_pointer (&gnutls->session_data, g_bytes_unref);
243
244   clear_gnutls_certificate_copy (&gnutls->pcert, &gnutls->pcert_length, &gnutls->pkey);
245
246   G_OBJECT_CLASS (g_tls_client_connection_gnutls_parent_class)->finalize (object);
247 }
248
249 static gboolean
250 g_tls_client_connection_gnutls_initable_init (GInitable       *initable,
251                                               GCancellable    *cancellable,
252                                               GError         **error)
253 {
254   GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (initable);
255   gnutls_session_t session;
256   const gchar *hostname;
257   gnutls_certificate_credentials_t creds;
258
259   if (!g_tls_client_connection_gnutls_parent_initable_iface->init (initable, cancellable, error))
260     return FALSE;
261
262   creds = g_tls_connection_gnutls_get_credentials (G_TLS_CONNECTION_GNUTLS (gnutls));
263   gnutls_certificate_set_retrieve_function2 (creds, g_tls_client_connection_gnutls_handshake_thread_retrieve_function);
264
265   session = g_tls_connection_gnutls_get_session (gnutls);
266   hostname = get_server_identity (G_TLS_CLIENT_CONNECTION_GNUTLS (gnutls));
267   if (hostname)
268     {
269       gchar *normalized_hostname = g_strdup (hostname);
270
271       if (hostname[strlen (hostname) - 1] == '.')
272         normalized_hostname[strlen (hostname) - 1] = '\0';
273
274       gnutls_server_name_set (session, GNUTLS_NAME_DNS,
275                               normalized_hostname, strlen (normalized_hostname));
276
277       g_free (normalized_hostname);
278     }
279
280   gnutls_handshake_set_hook_function (session, GNUTLS_HANDSHAKE_NEW_SESSION_TICKET,
281                                       GNUTLS_HOOK_POST, handshake_thread_session_ticket_received_cb);
282
283   return TRUE;
284 }
285
286 static void
287 g_tls_client_connection_gnutls_get_property (GObject    *object,
288                                              guint       prop_id,
289                                              GValue     *value,
290                                              GParamSpec *pspec)
291 {
292   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
293   GList *accepted_cas;
294   gint i;
295
296   switch (prop_id)
297     {
298     case PROP_VALIDATION_FLAGS:
299       g_value_set_flags (value, gnutls->validation_flags);
300       break;
301
302     case PROP_SERVER_IDENTITY:
303       g_value_set_object (value, gnutls->server_identity);
304       break;
305
306     case PROP_USE_SSL3:
307       g_value_set_boolean (value, gnutls->use_ssl3);
308       break;
309
310     case PROP_ACCEPTED_CAS:
311       accepted_cas = NULL;
312       if (gnutls->accepted_cas)
313         {
314           for (i = 0; i < gnutls->accepted_cas->len; ++i)
315             {
316               accepted_cas = g_list_prepend (accepted_cas, g_byte_array_ref (
317                                              gnutls->accepted_cas->pdata[i]));
318             }
319           accepted_cas = g_list_reverse (accepted_cas);
320         }
321       g_value_set_pointer (value, accepted_cas);
322       break;
323
324     default:
325       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326     }
327 }
328
329 static void
330 g_tls_client_connection_gnutls_set_property (GObject      *object,
331                                              guint         prop_id,
332                                              const GValue *value,
333                                              GParamSpec   *pspec)
334 {
335   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (object);
336   const char *hostname;
337
338   switch (prop_id)
339     {
340     case PROP_VALIDATION_FLAGS:
341       gnutls->validation_flags = g_value_get_flags (value);
342       break;
343
344     case PROP_SERVER_IDENTITY:
345       if (gnutls->server_identity)
346         g_object_unref (gnutls->server_identity);
347       gnutls->server_identity = g_value_dup_object (value);
348
349       hostname = get_server_identity (gnutls);
350       if (hostname && !g_hostname_is_ip_address (hostname))
351         {
352           gnutls_session_t session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (gnutls));
353
354           /* This will only be triggered if the identity is set after
355            * initialization */
356           if (session)
357             {
358               gchar *normalized_hostname = g_strdup (hostname);
359
360               if (hostname[strlen (hostname) - 1] == '.')
361                 normalized_hostname[strlen (hostname) - 1] = '\0';
362
363               gnutls_server_name_set (session, GNUTLS_NAME_DNS,
364                                       normalized_hostname, strlen (normalized_hostname));
365
366               g_free (normalized_hostname);
367             }
368         }
369       break;
370
371     case PROP_USE_SSL3:
372       gnutls->use_ssl3 = g_value_get_boolean (value);
373       break;
374
375     default:
376       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
377     }
378 }
379
380 static int
381 g_tls_client_connection_gnutls_handshake_thread_retrieve_function (gnutls_session_t              session,
382                                                                    const gnutls_datum_t         *req_ca_rdn,
383                                                                    int                           nreqs,
384                                                                    const gnutls_pk_algorithm_t  *pk_algos,
385                                                                    int                           pk_algos_length,
386                                                                    gnutls_pcert_st             **pcert,
387                                                                    unsigned int                 *pcert_length,
388                                                                    gnutls_privkey_t             *pkey)
389 {
390   GTlsConnectionBase *tls = gnutls_transport_get_ptr (session);
391   GTlsClientConnectionGnutls *gnutls = gnutls_transport_get_ptr (session);
392   GTlsConnectionGnutls *conn = G_TLS_CONNECTION_GNUTLS (gnutls);
393   GPtrArray *accepted_cas;
394   gboolean had_accepted_cas;
395   GByteArray *dn;
396   int i;
397
398   /* FIXME: Here we are supposed to ensure that the certificate supports one of
399    * the algorithms given in pk_algos.
400    */
401
402   had_accepted_cas = gnutls->accepted_cas != NULL;
403
404   accepted_cas = g_ptr_array_new_with_free_func ((GDestroyNotify)g_byte_array_unref);
405   for (i = 0; i < nreqs; i++)
406     {
407       dn = g_byte_array_new ();
408       g_byte_array_append (dn, req_ca_rdn[i].data, req_ca_rdn[i].size);
409       g_ptr_array_add (accepted_cas, dn);
410     }
411
412   if (gnutls->accepted_cas)
413     g_ptr_array_unref (gnutls->accepted_cas);
414   gnutls->accepted_cas = accepted_cas;
415
416   gnutls->accepted_cas_changed = gnutls->accepted_cas || had_accepted_cas;
417
418   clear_gnutls_certificate_copy (&gnutls->pcert, &gnutls->pcert_length, &gnutls->pkey);
419   g_tls_connection_gnutls_handshake_thread_get_certificate (conn, pcert, pcert_length, pkey);
420
421   if (*pcert_length == 0)
422     {
423       clear_gnutls_certificate_copy (pcert, pcert_length, pkey);
424
425       if (g_tls_connection_base_handshake_thread_request_certificate (tls))
426         g_tls_connection_gnutls_handshake_thread_get_certificate (conn, pcert, pcert_length, pkey);
427
428       if (*pcert_length == 0)
429         {
430           clear_gnutls_certificate_copy (pcert, pcert_length, pkey);
431
432           /* If there is still no client certificate, this connection will
433            * probably fail, but we must not give up yet. The certificate might
434            * be optional, e.g. if the server is using
435            * G_TLS_AUTHENTICATION_REQUESTED, not G_TLS_AUTHENTICATION_REQUIRED.
436            */
437           g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
438           return 0;
439         }
440     }
441
442   if (!*pkey)
443     {
444       clear_gnutls_certificate_copy (pcert, pcert_length, pkey);
445
446       /* No private key. GnuTLS expects it to be non-null if pcert_length is
447        * nonzero, so we have to abort now.
448        */
449       g_tls_connection_base_handshake_thread_set_missing_requested_client_certificate (tls);
450       return -1;
451     }
452
453   /* We'll assume ownership. The return values are unowned. */
454   gnutls->pcert = *pcert;
455   gnutls->pcert_length = *pcert_length;
456   gnutls->pkey = *pkey;
457
458   return 0;
459 }
460
461 static void
462 g_tls_client_connection_gnutls_prepare_handshake (GTlsConnectionBase  *tls,
463                                                   gchar              **advertised_protocols)
464 {
465   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
466
467   g_tls_client_connection_gnutls_compute_session_id (gnutls);
468
469   if (gnutls->session_data_override)
470     {
471       g_assert (gnutls->session_data);
472       gnutls_session_set_data (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)),
473                                g_bytes_get_data (gnutls->session_data, NULL),
474                                g_bytes_get_size (gnutls->session_data));
475     }
476   else if (gnutls->session_id)
477     {
478       GBytes *session_data;
479
480       session_data = g_tls_backend_gnutls_lookup_session_data (gnutls->session_id);
481       if (session_data)
482         {
483           gnutls_session_set_data (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)),
484                                    g_bytes_get_data (session_data, NULL),
485                                    g_bytes_get_size (session_data));
486           g_clear_pointer (&gnutls->session_data, g_bytes_unref);
487           gnutls->session_data = g_steal_pointer (&session_data);
488         }
489     }
490
491   G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->
492     prepare_handshake (tls, advertised_protocols);
493 }
494
495 static void
496 g_tls_client_connection_gnutls_complete_handshake (GTlsConnectionBase   *tls,
497                                                    gboolean              handshake_succeeded,
498                                                    gchar               **negotiated_protocol,
499                                                    GTlsProtocolVersion  *protocol_version,
500                                                    gchar               **ciphersuite_name,
501                                                    GError              **error)
502 {
503   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (tls);
504   gnutls_session_t session;
505   gnutls_protocol_t version;
506
507   G_TLS_CONNECTION_BASE_CLASS (g_tls_client_connection_gnutls_parent_class)->complete_handshake (tls,
508                                                                                                  handshake_succeeded,
509                                                                                                  negotiated_protocol,
510                                                                                                  protocol_version,
511                                                                                                  ciphersuite_name,
512                                                                                                  error);
513
514   /* It may have changed during the handshake, but we have to wait until here
515    * because we can't emit notifies on the handshake thread.
516    */
517   if (gnutls->accepted_cas_changed)
518     g_object_notify (G_OBJECT (gnutls), "accepted-cas");
519
520   if (handshake_succeeded)
521     {
522       /* If we're not using TLS 1.3, store the session ticket here. We
523        * don't normally perform session resumption in TLS 1.2, but we still
524        * support it if the application calls copy_session_state() (which
525        * doesn't exist for DTLS, so do this for TLS only).
526        *
527        * Note to distant future: remove this when dropping TLS 1.2 support.
528        */
529       session = g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls));
530       version = gnutls_protocol_get_version (session);
531       if (version <= GNUTLS_TLS1_2 && !g_tls_connection_base_is_dtls (tls))
532         {
533           gnutls_datum_t session_datum;
534
535           if (gnutls_session_get_data2 (g_tls_connection_gnutls_get_session (G_TLS_CONNECTION_GNUTLS (tls)),
536                                         &session_datum) == 0)
537             {
538               g_clear_pointer (&gnutls->session_data, g_bytes_unref);
539               gnutls->session_data = g_bytes_new_with_free_func (session_datum.data,
540                                                                  session_datum.size,
541                                                                  (GDestroyNotify)gnutls_free,
542                                                                  session_datum.data);
543             }
544         }
545   }
546 }
547
548 static void
549 g_tls_client_connection_gnutls_copy_session_state (GTlsClientConnection *conn,
550                                                    GTlsClientConnection *source)
551 {
552   GTlsClientConnectionGnutls *gnutls = G_TLS_CLIENT_CONNECTION_GNUTLS (conn);
553   GTlsClientConnectionGnutls *gnutls_source = G_TLS_CLIENT_CONNECTION_GNUTLS (source);
554
555   /* Precondition: source has handshaked, conn has not. */
556   g_return_if_fail (!gnutls->session_id);
557   g_return_if_fail (gnutls_source->session_id);
558   g_return_if_fail (!gnutls->session_data);
559
560   /* Prefer to use a new session ticket, if possible. */
561   gnutls->session_data = g_tls_backend_gnutls_lookup_session_data (gnutls_source->session_id);
562
563   if (!gnutls->session_data && gnutls_source->session_data)
564     {
565       /* If it's not possible, we'll try to reuse the old ticket, even though
566        * this is a privacy risk. Applications should not use this function
567        * unless they need us to try as hard as possible to resume a session,
568        * even at the cost of privacy.
569        */
570       gnutls->session_data = g_bytes_ref (gnutls_source->session_data);
571     }
572
573   gnutls->session_data_override = !!gnutls->session_data;
574 }
575
576 static void
577 g_tls_client_connection_gnutls_update_credentials (GTlsConnectionGnutls             *gnutls,
578                                                    gnutls_certificate_credentials_t  credentials)
579 {
580   gnutls_certificate_set_retrieve_function2 (credentials, g_tls_client_connection_gnutls_handshake_thread_retrieve_function);
581 }
582
583 static void
584 g_tls_client_connection_gnutls_class_init (GTlsClientConnectionGnutlsClass *klass)
585 {
586   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
587   GTlsConnectionBaseClass *base_class = G_TLS_CONNECTION_BASE_CLASS (klass);
588   GTlsConnectionGnutlsClass *gnutls_class = G_TLS_CONNECTION_GNUTLS_CLASS (klass);
589
590   gobject_class->get_property = g_tls_client_connection_gnutls_get_property;
591   gobject_class->set_property = g_tls_client_connection_gnutls_set_property;
592   gobject_class->finalize     = g_tls_client_connection_gnutls_finalize;
593
594   base_class->prepare_handshake  = g_tls_client_connection_gnutls_prepare_handshake;
595   base_class->complete_handshake = g_tls_client_connection_gnutls_complete_handshake;
596
597   gnutls_class->update_credentials = g_tls_client_connection_gnutls_update_credentials;
598
599   g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags");
600   g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity");
601   g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3");
602   g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas");
603 }
604
605 static void
606 g_tls_client_connection_gnutls_client_connection_interface_init (GTlsClientConnectionInterface *iface)
607 {
608   iface->copy_session_state = g_tls_client_connection_gnutls_copy_session_state;
609 }
610
611 static void
612 g_tls_client_connection_gnutls_initable_interface_init (GInitableIface  *iface)
613 {
614   g_tls_client_connection_gnutls_parent_initable_iface = g_type_interface_peek_parent (iface);
615
616   iface->init = g_tls_client_connection_gnutls_initable_init;
617 }
618
619 static void
620 g_tls_client_connection_gnutls_dtls_client_connection_interface_init (GDtlsClientConnectionInterface *iface)
621 {
622   /* Nothing here. */
623 }