Update to 2.50.0
[platform/upstream/glib-networking.git] / tls / gnutls / gtlscertificate-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  * In addition, when the library is used with OpenSSL, a special
20  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
21  */
22
23 #include "config.h"
24
25 #include <gnutls/gnutls.h>
26 #include <gnutls/x509.h>
27 #include <string.h>
28
29 #include "gtlscertificate-gnutls.h"
30 #include <glib/gi18n-lib.h>
31 #include "TIZEN.h"
32
33 static void     g_tls_certificate_gnutls_initable_iface_init (GInitableIface  *iface);
34
35 G_DEFINE_TYPE_WITH_CODE (GTlsCertificateGnutls, g_tls_certificate_gnutls, G_TYPE_TLS_CERTIFICATE,
36                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
37                                                 g_tls_certificate_gnutls_initable_iface_init);)
38
39 enum
40 {
41   PROP_0,
42
43   PROP_CERTIFICATE,
44   PROP_CERTIFICATE_PEM,
45   PROP_PRIVATE_KEY,
46   PROP_PRIVATE_KEY_PEM,
47   PROP_ISSUER
48 };
49
50 struct _GTlsCertificateGnutlsPrivate
51 {
52   gnutls_x509_crt_t cert;
53   gnutls_x509_privkey_t key;
54
55   GTlsCertificateGnutls *issuer;
56
57   GError *construct_error;
58
59   guint have_cert : 1;
60   guint have_key  : 1;
61 };
62
63 static void
64 g_tls_certificate_gnutls_finalize (GObject *object)
65 {
66   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
67
68   gnutls_x509_crt_deinit (gnutls->priv->cert);
69   if (gnutls->priv->key)
70     gnutls_x509_privkey_deinit (gnutls->priv->key);
71
72   if (gnutls->priv->issuer)
73     g_object_unref (gnutls->priv->issuer);
74
75   g_clear_error (&gnutls->priv->construct_error);
76
77   G_OBJECT_CLASS (g_tls_certificate_gnutls_parent_class)->finalize (object);
78 }
79
80 static void
81 g_tls_certificate_gnutls_get_property (GObject    *object,
82                                        guint       prop_id,
83                                        GValue     *value,
84                                        GParamSpec *pspec)
85 {
86   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
87   GByteArray *certificate;
88   char *certificate_pem;
89   int status;
90   size_t size;
91
92   switch (prop_id)
93     {
94     case PROP_CERTIFICATE:
95       size = 0;
96       status = gnutls_x509_crt_export (gnutls->priv->cert,
97                                        GNUTLS_X509_FMT_DER,
98                                        NULL, &size);
99       if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
100         certificate = NULL;
101       else
102         {
103           certificate = g_byte_array_sized_new (size);
104           certificate->len = size;
105           status = gnutls_x509_crt_export (gnutls->priv->cert,
106                                            GNUTLS_X509_FMT_DER,
107                                            certificate->data, &size);
108           if (status != 0)
109             {
110               g_byte_array_free (certificate, TRUE);
111               certificate = NULL;
112             }
113         }
114       g_value_take_boxed (value, certificate);
115       break;
116
117     case PROP_CERTIFICATE_PEM:
118       size = 0;
119       status = gnutls_x509_crt_export (gnutls->priv->cert,
120                                        GNUTLS_X509_FMT_PEM,
121                                        NULL, &size);
122       if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
123         certificate_pem = NULL;
124       else
125         {
126           certificate_pem = g_malloc (size);
127           status = gnutls_x509_crt_export (gnutls->priv->cert,
128                                            GNUTLS_X509_FMT_PEM,
129                                            certificate_pem, &size);
130           if (status != 0)
131             {
132               g_free (certificate_pem);
133               certificate_pem = NULL;
134             }
135         }
136       g_value_take_string (value, certificate_pem);
137       break;
138
139     case PROP_ISSUER:
140       g_value_set_object (value, gnutls->priv->issuer);
141       break;
142
143     default:
144       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
145     }
146 }
147
148 static void
149 g_tls_certificate_gnutls_set_property (GObject      *object,
150                                        guint         prop_id,
151                                        const GValue *value,
152                                        GParamSpec   *pspec)
153 {
154   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
155   GByteArray *bytes;
156   const char *string;
157   gnutls_datum_t data;
158   int status;
159
160   switch (prop_id)
161     {
162     case PROP_CERTIFICATE:
163       bytes = g_value_get_boxed (value);
164       if (!bytes)
165         break;
166       g_return_if_fail (gnutls->priv->have_cert == FALSE);
167       data.data = bytes->data;
168       data.size = bytes->len;
169       status = gnutls_x509_crt_import (gnutls->priv->cert, &data,
170                                        GNUTLS_X509_FMT_DER);
171       if (status == 0)
172         gnutls->priv->have_cert = TRUE;
173       else if (!gnutls->priv->construct_error)
174         {
175           gnutls->priv->construct_error =
176             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
177                          _("Could not parse DER certificate: %s"),
178                          gnutls_strerror (status));
179         }
180
181       break;
182
183     case PROP_CERTIFICATE_PEM:
184       string = g_value_get_string (value);
185       if (!string)
186         break;
187       g_return_if_fail (gnutls->priv->have_cert == FALSE);
188       data.data = (void *)string;
189       data.size = strlen (string);
190       status = gnutls_x509_crt_import (gnutls->priv->cert, &data,
191                                        GNUTLS_X509_FMT_PEM);
192       if (status == 0)
193         gnutls->priv->have_cert = TRUE;
194       else if (!gnutls->priv->construct_error)
195         {
196           gnutls->priv->construct_error =
197             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
198                          _("Could not parse PEM certificate: %s"),
199                          gnutls_strerror (status));
200         }
201       break;
202
203     case PROP_PRIVATE_KEY:
204       bytes = g_value_get_boxed (value);
205       if (!bytes)
206         break;
207       g_return_if_fail (gnutls->priv->have_key == FALSE);
208       data.data = bytes->data;
209       data.size = bytes->len;
210       if (!gnutls->priv->key)
211         gnutls_x509_privkey_init (&gnutls->priv->key);
212       status = gnutls_x509_privkey_import (gnutls->priv->key, &data,
213                                            GNUTLS_X509_FMT_DER);
214       if (status != 0)
215         {
216           int pkcs8_status =
217             gnutls_x509_privkey_import_pkcs8 (gnutls->priv->key, &data,
218                                               GNUTLS_X509_FMT_DER, NULL,
219                                               GNUTLS_PKCS_PLAIN);
220           if (pkcs8_status == 0)
221             status = 0;
222         }
223       if (status == 0)
224         gnutls->priv->have_key = TRUE;
225       else if (!gnutls->priv->construct_error)
226         {
227           gnutls->priv->construct_error =
228             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
229                          _("Could not parse DER private key: %s"),
230                          gnutls_strerror (status));
231         }
232       break;
233
234     case PROP_PRIVATE_KEY_PEM:
235       string = g_value_get_string (value);
236       if (!string)
237         break;
238       g_return_if_fail (gnutls->priv->have_key == FALSE);
239       data.data = (void *)string;
240       data.size = strlen (string);
241       if (!gnutls->priv->key)
242         gnutls_x509_privkey_init (&gnutls->priv->key);
243       status = gnutls_x509_privkey_import (gnutls->priv->key, &data,
244                                            GNUTLS_X509_FMT_PEM);
245       if (status != 0)
246         {
247           int pkcs8_status =
248             gnutls_x509_privkey_import_pkcs8 (gnutls->priv->key, &data,
249                                               GNUTLS_X509_FMT_PEM, NULL,
250                                               GNUTLS_PKCS_PLAIN);
251           if (pkcs8_status == 0)
252             status = 0;
253         }
254       if (status == 0)
255         gnutls->priv->have_key = TRUE;
256       else if (!gnutls->priv->construct_error)
257         {
258           gnutls->priv->construct_error =
259             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
260                          _("Could not parse PEM private key: %s"),
261                          gnutls_strerror (status));
262         }
263       break;
264
265     case PROP_ISSUER:
266       gnutls->priv->issuer = g_value_dup_object (value);
267       break;
268
269     default:
270       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271     }
272 }
273
274 #if ENABLE(TIZEN_TV_ADJUST_TIME)
275 extern double soupTimeOffset;
276
277 static time_t
278 correct_time_func(time_t *t)
279 {
280   return time(NULL) + (time_t)(soupTimeOffset / 1000);
281 }
282 #endif
283
284 static void
285 g_tls_certificate_gnutls_init (GTlsCertificateGnutls *gnutls)
286 {
287   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls,
288                                               G_TYPE_TLS_CERTIFICATE_GNUTLS,
289                                               GTlsCertificateGnutlsPrivate);
290
291   gnutls_x509_crt_init (&gnutls->priv->cert);
292 #if ENABLE(TIZEN_TV_ADJUST_TIME)
293   gnutls_global_set_time_function(correct_time_func);
294 #endif
295 }
296
297 static gboolean
298 g_tls_certificate_gnutls_initable_init (GInitable       *initable,
299                                         GCancellable    *cancellable,
300                                         GError         **error)
301 {
302   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (initable);
303
304   if (gnutls->priv->construct_error)
305     {
306       g_propagate_error (error, gnutls->priv->construct_error);
307       gnutls->priv->construct_error = NULL;
308       return FALSE;
309     }
310   else if (!gnutls->priv->have_cert)
311     {
312       g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
313                            _("No certificate data provided"));
314       return FALSE;
315     }
316   else
317     return TRUE;
318 }
319
320 static GTlsCertificateFlags
321 g_tls_certificate_gnutls_verify (GTlsCertificate     *cert,
322                                  GSocketConnectable  *identity,
323                                  GTlsCertificate     *trusted_ca)
324 {
325   GTlsCertificateGnutls *cert_gnutls;
326   guint num_certs, i;
327   gnutls_x509_crt_t *chain;
328   GTlsCertificateFlags gtls_flags;
329   time_t t, now;
330 #if ENABLE(TIZEN_TV_ADJUST_TIME) && ENABLE(TIZEN_DLOG)
331   char timebuf[256];
332 #endif
333
334   cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
335   for (num_certs = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer)
336     num_certs++;
337   chain = g_new (gnutls_x509_crt_t, num_certs);
338   cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
339   for (i = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer, i++)
340     chain[i] = cert_gnutls->priv->cert;
341
342   if (trusted_ca)
343     {
344       gnutls_x509_crt_t ca;
345       guint gnutls_flags;
346       int status;
347
348       ca = G_TLS_CERTIFICATE_GNUTLS (trusted_ca)->priv->cert;
349       status = gnutls_x509_crt_list_verify (chain, num_certs,
350                                             &ca, 1,
351                                             NULL, 0,
352                                             GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
353                                             &gnutls_flags);
354       if (status != 0)
355         {
356           g_free (chain);
357           return G_TLS_CERTIFICATE_GENERIC_ERROR;
358         }
359
360       gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
361     }
362   else
363     gtls_flags = 0;
364
365   /* We have to check these ourselves since gnutls_x509_crt_list_verify
366    * won't bother if it gets an UNKNOWN_CA.
367    */
368   now = time (NULL);
369 #if ENABLE(TIZEN_TV_ADJUST_TIME)
370   now = time (NULL) + (time_t)(soupTimeOffset / 1000);
371 #endif
372   for (i = 0; i < num_certs; i++)
373     {
374       t = gnutls_x509_crt_get_activation_time (chain[i]);
375
376 #if ENABLE(TIZEN_TV_ADJUST_TIME) && ENABLE(TIZEN_DLOG)
377           ctime_r(&now, timebuf);
378           TIZEN_LOGI("[Certificate] TV borad time is: %s", timebuf);
379           if (t != (time_t) -1) {
380                   ctime_r(&t, timebuf);
381                   TIZEN_LOGI("[Certificate] CA activation time is: %s", timebuf);
382           }
383           else
384                   TIZEN_LOGI("[Certificate] gnutls_x509_crt_get_activation_time ERROR");
385 #endif
386
387       if (t == (time_t) -1 || t > now)
388         gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
389
390       t = gnutls_x509_crt_get_expiration_time (chain[i]);
391
392 #if ENABLE(TIZEN_TV_ADJUST_TIME) && ENABLE(TIZEN_DLOG)
393       if (t != (time_t) -1) {
394         ctime_r(&t, timebuf);
395         TIZEN_LOGI("[Certificate] CA expiration time is: %s", timebuf);
396       }
397       else
398         TIZEN_LOGI("[Certificate] gnutls_x509_crt_get_expiration_time ERROR");
399 #endif
400
401       if (t == (time_t) -1 || t < now)
402         gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
403     }
404
405   g_free (chain);
406
407   if (identity)
408     gtls_flags |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (cert), identity);
409
410   return gtls_flags;
411 }
412
413 static void
414 g_tls_certificate_gnutls_real_copy (GTlsCertificateGnutls    *gnutls,
415                                     const gchar              *interaction_id,
416                                     gnutls_retr2_st          *st)
417 {
418   GTlsCertificateGnutls *chain;
419   gnutls_x509_crt_t cert;
420   gnutls_datum_t data;
421   guint num_certs = 0;
422   size_t size = 0;
423   int status;
424
425   /* We will do this loop twice. It's probably more efficient than
426    * re-allocating memory.
427    */
428   chain = gnutls;
429   while (chain != NULL)
430     {
431       num_certs++;
432       chain = chain->priv->issuer;
433     }
434
435   st->ncerts = 0;
436   st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t) * num_certs);
437
438   /* Now do the actual copy of the whole chain. */
439   chain = gnutls;
440   while (chain != NULL)
441     {
442       gnutls_x509_crt_export (chain->priv->cert, GNUTLS_X509_FMT_DER,
443                               NULL, &size);
444       data.data = g_malloc (size);
445       data.size = size;
446       gnutls_x509_crt_export (chain->priv->cert, GNUTLS_X509_FMT_DER,
447                               data.data, &size);
448
449       gnutls_x509_crt_init (&cert);
450       status = gnutls_x509_crt_import (cert, &data, GNUTLS_X509_FMT_DER);
451       g_warn_if_fail (status == 0);
452       g_free (data.data);
453
454       st->cert.x509[st->ncerts] = cert;
455       st->ncerts++;
456
457       chain = chain->priv->issuer;
458     }
459
460   if (gnutls->priv->key != NULL)
461     {
462       gnutls_x509_privkey_init (&st->key.x509);
463       gnutls_x509_privkey_cpy (st->key.x509, gnutls->priv->key);
464       st->key_type = GNUTLS_PRIVKEY_X509;
465     }
466
467   st->deinit_all = TRUE;
468 }
469
470 static void
471 g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
472 {
473   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
474   GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
475
476   g_type_class_add_private (klass, sizeof (GTlsCertificateGnutlsPrivate));
477
478   gobject_class->get_property = g_tls_certificate_gnutls_get_property;
479   gobject_class->set_property = g_tls_certificate_gnutls_set_property;
480   gobject_class->finalize     = g_tls_certificate_gnutls_finalize;
481
482   certificate_class->verify = g_tls_certificate_gnutls_verify;
483
484   klass->copy = g_tls_certificate_gnutls_real_copy;
485
486   g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
487   g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
488   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
489   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
490   g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
491 }
492
493 static void
494 g_tls_certificate_gnutls_initable_iface_init (GInitableIface  *iface)
495 {
496   iface->init = g_tls_certificate_gnutls_initable_init;
497 }
498
499 GTlsCertificate *
500 g_tls_certificate_gnutls_new (const gnutls_datum_t *datum,
501                               GTlsCertificate      *issuer)
502 {
503   GTlsCertificateGnutls *gnutls;
504
505   gnutls = g_object_new (G_TYPE_TLS_CERTIFICATE_GNUTLS,
506                          "issuer", issuer,
507                          NULL);
508   g_tls_certificate_gnutls_set_data (gnutls, datum);
509
510   return G_TLS_CERTIFICATE (gnutls);
511 }
512
513 void
514 g_tls_certificate_gnutls_set_data (GTlsCertificateGnutls *gnutls,
515                                    const gnutls_datum_t  *datum)
516 {
517   g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
518   g_return_if_fail (!gnutls->priv->have_cert);
519
520   if (gnutls_x509_crt_import (gnutls->priv->cert, datum,
521                               GNUTLS_X509_FMT_DER) == 0)
522     gnutls->priv->have_cert = TRUE;
523 }
524
525 const gnutls_x509_crt_t
526 g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls)
527 {
528   return gnutls->priv->cert;
529 }
530
531 gboolean
532 g_tls_certificate_gnutls_has_key (GTlsCertificateGnutls *gnutls)
533 {
534   return gnutls->priv->have_key;
535 }
536
537 void
538 g_tls_certificate_gnutls_copy  (GTlsCertificateGnutls *gnutls,
539                                 const gchar           *interaction_id,
540                                 gnutls_retr2_st       *st)
541 {
542   g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
543   g_return_if_fail (st != NULL);
544   g_return_if_fail (G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy);
545   G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy (gnutls, interaction_id, st);
546 }
547
548 static const struct {
549   int gnutls_flag;
550   GTlsCertificateFlags gtls_flag;
551 } flags_map[] = {
552   { GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA, G_TLS_CERTIFICATE_UNKNOWN_CA },
553   { GNUTLS_CERT_NOT_ACTIVATED, G_TLS_CERTIFICATE_NOT_ACTIVATED },
554   { GNUTLS_CERT_EXPIRED, G_TLS_CERTIFICATE_EXPIRED },
555   { GNUTLS_CERT_REVOKED, G_TLS_CERTIFICATE_REVOKED },
556   { GNUTLS_CERT_INSECURE_ALGORITHM, G_TLS_CERTIFICATE_INSECURE },
557   { GNUTLS_CERT_UNEXPECTED_OWNER, G_TLS_CERTIFICATE_BAD_IDENTITY }
558 };
559 static const int flags_map_size = G_N_ELEMENTS (flags_map);
560
561 GTlsCertificateFlags
562 g_tls_certificate_gnutls_convert_flags (guint gnutls_flags)
563 {
564   int i;
565   GTlsCertificateFlags gtls_flags;
566
567   /* Convert GNUTLS status to GTlsCertificateFlags. GNUTLS sets
568    * GNUTLS_CERT_INVALID if it sets any other flag, so we want to
569    * strip that out unless it's the only flag set. Then we convert
570    * specific flags we recognize, and if there are any flags left over
571    * at the end, we add G_TLS_CERTIFICATE_GENERIC_ERROR.
572    */
573   gtls_flags = 0;
574
575   if (gnutls_flags != GNUTLS_CERT_INVALID)
576     gnutls_flags = gnutls_flags & ~GNUTLS_CERT_INVALID;
577   for (i = 0; i < flags_map_size && gnutls_flags != 0; i++)
578     {
579       if (gnutls_flags & flags_map[i].gnutls_flag)
580         {
581           gnutls_flags &= ~flags_map[i].gnutls_flag;
582           gtls_flags |= flags_map[i].gtls_flag;
583         }
584     }
585   if (gnutls_flags)
586     gtls_flags |= G_TLS_CERTIFICATE_GENERIC_ERROR;
587
588   return gtls_flags;
589 }
590
591 static gboolean
592 verify_identity_hostname (GTlsCertificateGnutls *gnutls,
593                           GSocketConnectable    *identity)
594 {
595   const char *hostname;
596
597   if (G_IS_NETWORK_ADDRESS (identity))
598     hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
599   else if (G_IS_NETWORK_SERVICE (identity))
600     hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
601   else
602     return FALSE;
603
604   return gnutls_x509_crt_check_hostname (gnutls->priv->cert, hostname);
605 }
606
607 static gboolean
608 verify_identity_ip (GTlsCertificateGnutls *gnutls,
609                     GSocketConnectable    *identity)
610 {
611   GInetAddress *addr;
612   int i, ret = 0;
613   gsize addr_size;
614   const guint8 *addr_bytes;
615
616   if (G_IS_INET_SOCKET_ADDRESS (identity))
617     addr = g_object_ref (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity)));
618   else {
619     const char *hostname;
620
621     if (G_IS_NETWORK_ADDRESS (identity))
622       hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
623     else if (G_IS_NETWORK_SERVICE (identity))
624       hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
625     else
626       return FALSE;
627
628     addr = g_inet_address_new_from_string (hostname);
629     if (!addr)
630       return FALSE;
631   }
632
633   addr_bytes = g_inet_address_to_bytes (addr);
634   addr_size = g_inet_address_get_native_size (addr);
635
636   for (i = 0; ret >= 0; i++)
637     {
638       char san[500];
639       size_t san_size;
640
641       san_size = sizeof (san);
642       ret = gnutls_x509_crt_get_subject_alt_name (gnutls->priv->cert, i,
643                                                   san, &san_size, NULL);
644
645       if ((ret == GNUTLS_SAN_IPADDRESS) && (addr_size == san_size))
646         {
647           if (memcmp (addr_bytes, san, addr_size) == 0)
648             {
649               g_object_unref (addr);
650               return TRUE;
651             }
652         }
653     }
654
655   g_object_unref (addr);
656   return FALSE;
657 }
658
659 GTlsCertificateFlags
660 g_tls_certificate_gnutls_verify_identity (GTlsCertificateGnutls *gnutls,
661                                           GSocketConnectable    *identity)
662 {
663   if (verify_identity_hostname (gnutls, identity))
664     return 0;
665   else if (verify_identity_ip (gnutls, identity))
666     return 0;
667
668   /* FIXME: check sRVName and uniformResourceIdentifier
669    * subjectAltNames, if appropriate for @identity.
670    */
671 #if ENABLE(TIZEN_DLOG)
672   TIZEN_LOGI("[Network] SSL HandShake - Bad Identity");
673 #endif
674
675   return G_TLS_CERTIFICATE_BAD_IDENTITY;
676 }
677
678 void
679 g_tls_certificate_gnutls_set_issuer (GTlsCertificateGnutls *gnutls,
680                                      GTlsCertificateGnutls *issuer)
681 {
682   g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
683   g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_GNUTLS (issuer));
684
685   if (issuer)
686     g_object_ref (issuer);
687   if (gnutls->priv->issuer)
688     g_object_unref (gnutls->priv->issuer);
689   gnutls->priv->issuer = issuer;
690   g_object_notify (G_OBJECT (gnutls), "issuer");
691 }
692
693 GBytes *
694 g_tls_certificate_gnutls_get_bytes (GTlsCertificateGnutls *gnutls)
695 {
696   GByteArray *array;
697
698   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls), NULL);
699
700   g_object_get (gnutls, "certificate", &array, NULL);
701   return g_byte_array_free_to_bytes (array);
702 }
703
704 static gnutls_x509_crt_t *
705 convert_data_to_gnutls_certs (const gnutls_datum_t  *certs,
706                               guint                  num_certs,
707                               gnutls_x509_crt_fmt_t  format)
708 {
709   gnutls_x509_crt_t *gnutls_certs;
710   guint i;
711
712   gnutls_certs = g_new (gnutls_x509_crt_t, num_certs);
713
714   for (i = 0; i < num_certs; i++)
715     {
716       if (gnutls_x509_crt_init (&gnutls_certs[i]) < 0)
717         {
718           i--;
719           goto error;
720         }
721     }
722
723   for (i = 0; i < num_certs; i++)
724     {
725       if (gnutls_x509_crt_import (gnutls_certs[i], &certs[i], format) < 0)
726         {
727           i = num_certs - 1;
728           goto error;
729         }
730     }
731
732   return gnutls_certs;
733
734 error:
735   for (; i != G_MAXUINT; i--)
736     gnutls_x509_crt_deinit (gnutls_certs[i]);
737   g_free (gnutls_certs);
738   return NULL;
739 }
740
741 GTlsCertificateGnutls *
742 g_tls_certificate_gnutls_build_chain (const gnutls_datum_t  *certs,
743                                       guint                  num_certs,
744                                       gnutls_x509_crt_fmt_t  format)
745 {
746   GPtrArray *glib_certs;
747   gnutls_x509_crt_t *gnutls_certs;
748   GTlsCertificateGnutls *issuer;
749   GTlsCertificateGnutls *result;
750   guint i, j;
751
752   g_return_val_if_fail (certs, NULL);
753
754   gnutls_certs = convert_data_to_gnutls_certs (certs, num_certs, format);
755   if (!gnutls_certs)
756     return NULL;
757
758   glib_certs = g_ptr_array_new_full (num_certs, g_object_unref);
759   for (i = 0; i < num_certs; i++)
760     g_ptr_array_add (glib_certs, g_tls_certificate_gnutls_new (&certs[i], NULL));
761
762   /* Some servers send certs out of order, or will send duplicate
763    * certs, so we need to be careful when assigning the issuer of
764    * our new GTlsCertificateGnutls.
765    */
766   for (i = 0; i < num_certs; i++)
767     {
768       issuer = NULL;
769
770       /* Check if the cert issued itself */
771       if (gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[i]))
772         continue;
773
774       if (i < num_certs - 1 &&
775           gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[i + 1]))
776         {
777           issuer = glib_certs->pdata[i + 1];
778         }
779       else
780         {
781           for (j = 0; j < num_certs; j++)
782             {
783               if (j != i &&
784                   gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[j]))
785                 {
786                   issuer = glib_certs->pdata[j];
787                   break;
788                 }
789             }
790         }
791
792       if (issuer)
793         g_tls_certificate_gnutls_set_issuer (glib_certs->pdata[i], issuer);
794     }
795
796   result = g_object_ref (glib_certs->pdata[0]);
797   g_ptr_array_unref (glib_certs);
798
799   for (i = 0; i < num_certs; i++)
800     gnutls_x509_crt_deinit (gnutls_certs[i]);
801   g_free (gnutls_certs);
802
803   return result;
804 }