47b31e3c547cfa2df52462f62901c5f9551e4ed0
[platform/upstream/glib-networking.git] / tls / openssl / gtlscertificate-openssl.c
1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /*
3  * gtlscertificate-openssl.c
4  *
5  * Copyright (C) 2015 NICE s.r.l.
6  *
7  * This file 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 file 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 Public License
18  * along with this program. If not, see <http://www.gnu.org/licenses/>.
19  *
20  * In addition, when the library is used with OpenSSL, a special
21  * exception applies. Refer to the LICENSE_EXCEPTION file for details.
22  *
23  * Authors: Ignacio Casal Quinteiro
24  */
25
26 #include "config.h"
27
28 #include <string.h>
29 #include "openssl-include.h"
30
31 #include "gtlscertificate-openssl.h"
32 #include <glib/gi18n-lib.h>
33
34 struct _GTlsCertificateOpenssl
35 {
36   GTlsCertificate parent_instance;
37
38   X509 *cert;
39   EVP_PKEY *key;
40
41   GTlsCertificateOpenssl *issuer;
42
43   GError *construct_error;
44
45   guint have_cert : 1;
46   guint have_key  : 1;
47 };
48
49 enum
50 {
51   PROP_0,
52
53   PROP_CERTIFICATE,
54   PROP_CERTIFICATE_PEM,
55   PROP_PRIVATE_KEY,
56   PROP_PRIVATE_KEY_PEM,
57   PROP_ISSUER,
58   PROP_NOT_VALID_BEFORE,
59   PROP_NOT_VALID_AFTER,
60   PROP_SUBJECT_NAME,
61   PROP_ISSUER_NAME,
62   PROP_DNS_NAMES,
63   PROP_IP_ADDRESSES,
64 };
65
66 static void     g_tls_certificate_openssl_initable_iface_init (GInitableIface  *iface);
67
68 G_DEFINE_TYPE_WITH_CODE (GTlsCertificateOpenssl, g_tls_certificate_openssl, G_TYPE_TLS_CERTIFICATE,
69                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
70                                                 g_tls_certificate_openssl_initable_iface_init))
71
72 static void
73 g_tls_certificate_openssl_finalize (GObject *object)
74 {
75   GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
76
77   if (openssl->cert)
78     X509_free (openssl->cert);
79   if (openssl->key)
80     EVP_PKEY_free (openssl->key);
81
82   g_clear_object (&openssl->issuer);
83
84   g_clear_error (&openssl->construct_error);
85
86   G_OBJECT_CLASS (g_tls_certificate_openssl_parent_class)->finalize (object);
87 }
88
89 static GPtrArray *
90 get_subject_alt_names (GTlsCertificateOpenssl *cert,
91                        guint                   type)
92 {
93   GPtrArray *data = NULL;
94   STACK_OF (GENERAL_NAME) *sans;
95   const guint8 *san = NULL;
96   size_t san_size;
97   guint alt_occurrences;
98   guint i;
99
100   if (type == GEN_IPADD)
101     data = g_ptr_array_new_with_free_func (g_object_unref);
102   else
103     data = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
104
105   sans = X509_get_ext_d2i (cert->cert, NID_subject_alt_name, NULL, NULL);
106   if (sans)
107     {
108       alt_occurrences = sk_GENERAL_NAME_num (sans);
109       for (i = 0; i < alt_occurrences; i++)
110         {
111           const GENERAL_NAME *value = sk_GENERAL_NAME_value (sans, i);
112           if (value->type != type)
113             continue;
114
115           if (type == GEN_IPADD)
116             {
117               g_assert (value->type == GEN_IPADD);
118               san = ASN1_STRING_get0_data (value->d.ip);
119               san_size = ASN1_STRING_length (value->d.ip);
120               if (san_size == 4)
121                 g_ptr_array_add (data, g_inet_address_new_from_bytes (san, G_SOCKET_FAMILY_IPV4));
122               else if (san_size == 16)
123                 g_ptr_array_add (data, g_inet_address_new_from_bytes (san, G_SOCKET_FAMILY_IPV6));
124             }
125           else
126             {
127               g_assert (value->type == GEN_DNS);
128               san = ASN1_STRING_get0_data (value->d.ia5);
129               san_size = ASN1_STRING_length (value->d.ia5);
130               g_ptr_array_add (data, g_bytes_new (san, san_size));
131             }
132           }
133
134       for (i = 0; i < alt_occurrences; i++)
135         GENERAL_NAME_free (sk_GENERAL_NAME_value (sans, i));
136       sk_GENERAL_NAME_free (sans);
137     }
138
139   return data;
140 }
141
142 static void
143 export_privkey_to_der (GTlsCertificateOpenssl  *openssl,
144                        guint8                 **output_data,
145                        long                    *output_size)
146 {
147   PKCS8_PRIV_KEY_INFO *pkcs8;
148   BIO *bio = NULL;
149   const guint8 *data;
150
151   if (!openssl->key)
152     goto err;
153
154   pkcs8 = EVP_PKEY2PKCS8 (openssl->key);
155   if (!pkcs8)
156     goto err;
157
158   bio = BIO_new (BIO_s_mem ());
159   if (i2d_PKCS8_PRIV_KEY_INFO_bio (bio, pkcs8) == 0)
160     goto err;
161
162   *output_size = BIO_get_mem_data (bio, (char **)&data);
163   if (*output_size <= 0)
164     goto err;
165
166   *output_data = g_malloc (*output_size);
167   memcpy (*output_data, data, *output_size);
168   goto out;
169
170 err:
171   *output_data = NULL;
172   *output_size = 0;
173 out:
174   if (bio)
175     BIO_free_all (bio);
176   if (pkcs8)
177     PKCS8_PRIV_KEY_INFO_free (pkcs8);
178 }
179
180 static char *
181 export_privkey_to_pem (GTlsCertificateOpenssl *openssl)
182 {
183   int ret;
184   BIO *bio = NULL;
185   const char *data = NULL;
186   char *result = NULL;
187
188   if (!openssl->key)
189     return NULL;
190
191   bio = BIO_new (BIO_s_mem ());
192   ret = PEM_write_bio_PKCS8PrivateKey (bio, openssl->key, NULL, NULL, 0, NULL, NULL);
193   if (ret == 0)
194     goto out;
195
196   ret = BIO_write (bio, "\0", 1);
197   if (ret != 1)
198     goto out;
199
200   BIO_get_mem_data (bio, (char **)&data);
201   result = g_strdup (data);
202
203 out:
204   BIO_free_all (bio);
205   return result;
206 }
207
208 static void
209 g_tls_certificate_openssl_get_property (GObject    *object,
210                                         guint       prop_id,
211                                         GValue     *value,
212                                         GParamSpec *pspec)
213 {
214   GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
215   GByteArray *certificate;
216   guint8 *data;
217   BIO *bio;
218   GByteArray *byte_array;
219   char *certificate_pem;
220   long size;
221
222   const ASN1_TIME *time_asn1;
223   struct tm time_tm;
224   GDateTime *time;
225   GTimeZone *tz;
226   X509_NAME *name;
227   const char *name_string;
228
229   switch (prop_id)
230     {
231     case PROP_CERTIFICATE:
232       /* NOTE: we do the two calls to avoid openssl allocating the buffer for us */
233       size = i2d_X509 (openssl->cert, NULL);
234       if (size < 0)
235         certificate = NULL;
236       else
237         {
238           certificate = g_byte_array_sized_new (size);
239           certificate->len = size;
240           data = certificate->data;
241           size = i2d_X509 (openssl->cert, &data);
242           if (size < 0)
243             {
244               g_byte_array_free (certificate, TRUE);
245               certificate = NULL;
246             }
247         }
248       g_value_take_boxed (value, certificate);
249       break;
250
251     case PROP_CERTIFICATE_PEM:
252       bio = BIO_new (BIO_s_mem ());
253
254       if (!PEM_write_bio_X509 (bio, openssl->cert) || !BIO_write (bio, "\0", 1))
255         certificate_pem = NULL;
256       else
257         {
258           BIO_get_mem_data (bio, &certificate_pem);
259           g_value_set_string (value, certificate_pem);
260
261           BIO_free_all (bio);
262         }
263       break;
264
265     case PROP_PRIVATE_KEY:
266       export_privkey_to_der (openssl, &data, &size);
267       if (size > 0 && (gint64)size <= G_MAXUINT)
268         {
269           byte_array = g_byte_array_new_take (data, size);
270           g_value_take_boxed (value, byte_array);
271         }
272       break;
273
274     case PROP_PRIVATE_KEY_PEM:
275       g_value_take_string (value, export_privkey_to_pem (openssl));
276       break;
277
278     case PROP_ISSUER:
279       g_value_set_object (value, openssl->issuer);
280       break;
281
282     case PROP_NOT_VALID_BEFORE:
283       time_asn1 = X509_get0_notBefore (openssl->cert);
284       ASN1_TIME_to_tm (time_asn1, &time_tm);
285       tz = g_time_zone_new_utc ();
286       time = g_date_time_new (tz, time_tm.tm_year + 1900, time_tm.tm_mon + 1, time_tm.tm_mday, time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec);
287       g_value_take_boxed (value, time);
288       g_time_zone_unref (tz);
289       break;
290
291     case PROP_NOT_VALID_AFTER:
292       time_asn1 = X509_get0_notAfter (openssl->cert);
293       ASN1_TIME_to_tm (time_asn1, &time_tm);
294       tz = g_time_zone_new_utc ();
295       time = g_date_time_new (tz, time_tm.tm_year + 1900, time_tm.tm_mon + 1, time_tm.tm_mday, time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec);
296       g_value_take_boxed (value, time);
297       g_time_zone_unref (tz);
298       break;
299
300     case PROP_SUBJECT_NAME:
301       bio = BIO_new (BIO_s_mem ());
302       name = X509_get_subject_name (openssl->cert);
303       X509_NAME_print_ex (bio, name, 0, XN_FLAG_SEP_COMMA_PLUS);
304       BIO_write (bio, "\0", 1);
305       BIO_get_mem_data (bio, (char **)&name_string);
306       g_value_set_string (value, name_string);
307       BIO_free_all (bio);
308       break;
309
310     case PROP_ISSUER_NAME:
311       bio = BIO_new (BIO_s_mem ());
312       name = X509_get_issuer_name (openssl->cert);
313       X509_NAME_print_ex (bio, name, 0, XN_FLAG_SEP_COMMA_PLUS);
314       BIO_write (bio, "\0", 1);
315       BIO_get_mem_data (bio, &name_string);
316       g_value_set_string (value, name_string);
317       BIO_free_all (bio);
318       break;
319
320     case PROP_DNS_NAMES:
321       g_value_take_boxed (value, get_subject_alt_names (openssl, GEN_DNS));
322       break;
323
324     case PROP_IP_ADDRESSES:
325       g_value_take_boxed (value, get_subject_alt_names (openssl, GEN_IPADD));
326       break;
327
328     default:
329       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
330     }
331 }
332
333 static void
334 g_tls_certificate_openssl_set_property (GObject      *object,
335                                        guint         prop_id,
336                                        const GValue *value,
337                                        GParamSpec   *pspec)
338 {
339   GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
340   GByteArray *bytes;
341   guint8 *data;
342   BIO *bio;
343   const char *string;
344   char error_buffer[256];
345
346   switch (prop_id)
347     {
348     case PROP_CERTIFICATE:
349       bytes = g_value_get_boxed (value);
350       if (!bytes)
351         break;
352       g_return_if_fail (openssl->have_cert == FALSE);
353       /* see that we cannot use bytes->data directly since it will move the pointer */
354       data = bytes->data;
355       openssl->cert = d2i_X509 (NULL, (const unsigned char **)&data, bytes->len);
356       if (openssl->cert)
357         openssl->have_cert = TRUE;
358       else if (!openssl->construct_error)
359         {
360           ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
361           openssl->construct_error =
362             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
363                          _("Could not parse DER certificate: %s"),
364                          error_buffer);
365         }
366
367       break;
368
369     case PROP_CERTIFICATE_PEM:
370       string = g_value_get_string (value);
371       if (!string)
372         break;
373       g_return_if_fail (openssl->have_cert == FALSE);
374       bio = BIO_new_mem_buf ((gpointer)string, -1);
375       openssl->cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
376       BIO_free (bio);
377       if (openssl->cert)
378         openssl->have_cert = TRUE;
379       else if (!openssl->construct_error)
380         {
381           ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
382           openssl->construct_error =
383             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
384                          _("Could not parse PEM certificate: %s"),
385                          error_buffer);
386         }
387       break;
388
389     case PROP_PRIVATE_KEY:
390       bytes = g_value_get_boxed (value);
391       if (!bytes)
392         break;
393       g_return_if_fail (openssl->have_key == FALSE);
394       bio = BIO_new_mem_buf (bytes->data, bytes->len);
395       openssl->key = d2i_PrivateKey_bio (bio, NULL);
396       BIO_free (bio);
397       if (openssl->key)
398         openssl->have_key = TRUE;
399       else if (!openssl->construct_error)
400         {
401           ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
402           openssl->construct_error =
403             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
404                          _("Could not parse DER private key: %s"),
405                          error_buffer);
406         }
407       break;
408
409     case PROP_PRIVATE_KEY_PEM:
410       string = g_value_get_string (value);
411       if (!string)
412         break;
413       g_return_if_fail (openssl->have_key == FALSE);
414       bio = BIO_new_mem_buf ((gpointer)string, -1);
415       openssl->key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
416       BIO_free (bio);
417       if (openssl->key)
418         openssl->have_key = TRUE;
419       else if (!openssl->construct_error)
420         {
421           ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
422           openssl->construct_error =
423             g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
424                          _("Could not parse PEM private key: %s"),
425                          error_buffer);
426         }
427       break;
428
429     case PROP_ISSUER:
430       openssl->issuer = g_value_dup_object (value);
431       break;
432
433     default:
434       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
435     }
436 }
437
438 static void
439 g_tls_certificate_openssl_init (GTlsCertificateOpenssl *openssl)
440 {
441 }
442
443 static gboolean
444 g_tls_certificate_openssl_initable_init (GInitable       *initable,
445                                          GCancellable    *cancellable,
446                                          GError         **error)
447 {
448   GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (initable);
449
450   if (openssl->construct_error)
451     {
452       g_propagate_error (error, openssl->construct_error);
453       openssl->construct_error = NULL;
454       return FALSE;
455     }
456   else if (!openssl->have_cert)
457     {
458       g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
459                            _("No certificate data provided"));
460       return FALSE;
461     }
462   else
463     return TRUE;
464 }
465
466 static GTlsCertificateFlags
467 g_tls_certificate_openssl_verify (GTlsCertificate     *cert,
468                                   GSocketConnectable  *identity,
469                                   GTlsCertificate     *trusted_ca)
470 {
471   GTlsCertificateOpenssl *cert_openssl;
472   GTlsCertificateFlags gtls_flags;
473   X509 *x;
474   STACK_OF(X509) *untrusted;
475
476   cert_openssl = G_TLS_CERTIFICATE_OPENSSL (cert);
477   x = cert_openssl->cert;
478
479   untrusted = sk_X509_new_null ();
480   for (; cert_openssl; cert_openssl = cert_openssl->issuer)
481     sk_X509_push (untrusted, cert_openssl->cert);
482
483   gtls_flags = 0;
484
485   if (trusted_ca)
486     {
487       X509_STORE *store;
488       X509_STORE_CTX *csc;
489       STACK_OF(X509) *trusted;
490
491       store = X509_STORE_new ();
492       csc = X509_STORE_CTX_new ();
493
494       if (!X509_STORE_CTX_init (csc, store, x, untrusted))
495         {
496           sk_X509_free (untrusted);
497           X509_STORE_CTX_free (csc);
498           X509_STORE_free (store);
499           return G_TLS_CERTIFICATE_GENERIC_ERROR;
500         }
501
502       trusted = sk_X509_new_null ();
503       cert_openssl = G_TLS_CERTIFICATE_OPENSSL (trusted_ca);
504       for (; cert_openssl; cert_openssl = cert_openssl->issuer)
505         sk_X509_push (trusted, cert_openssl->cert);
506
507       X509_STORE_CTX_trusted_stack (csc, trusted);
508       if (X509_verify_cert (csc) <= 0)
509         gtls_flags |= g_tls_certificate_openssl_convert_error (X509_STORE_CTX_get_error (csc));
510
511       sk_X509_free (trusted);
512       X509_STORE_CTX_free (csc);
513       X509_STORE_free (store);
514     }
515
516   sk_X509_free (untrusted);
517
518   if (identity)
519     gtls_flags |= g_tls_certificate_openssl_verify_identity (G_TLS_CERTIFICATE_OPENSSL (cert), identity);
520
521   return gtls_flags;
522 }
523
524 static void
525 g_tls_certificate_openssl_class_init (GTlsCertificateOpensslClass *klass)
526 {
527   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
528   GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
529
530   gobject_class->get_property = g_tls_certificate_openssl_get_property;
531   gobject_class->set_property = g_tls_certificate_openssl_set_property;
532   gobject_class->finalize     = g_tls_certificate_openssl_finalize;
533
534   certificate_class->verify = g_tls_certificate_openssl_verify;
535
536   g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
537   g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
538   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
539   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
540   g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
541   g_object_class_override_property (gobject_class, PROP_NOT_VALID_BEFORE, "not-valid-before");
542   g_object_class_override_property (gobject_class, PROP_NOT_VALID_AFTER, "not-valid-after");
543   g_object_class_override_property (gobject_class, PROP_SUBJECT_NAME, "subject-name");
544   g_object_class_override_property (gobject_class, PROP_ISSUER_NAME, "issuer-name");
545   g_object_class_override_property (gobject_class, PROP_DNS_NAMES, "dns-names");
546   g_object_class_override_property (gobject_class, PROP_IP_ADDRESSES, "ip-addresses");
547 }
548
549 static void
550 g_tls_certificate_openssl_initable_iface_init (GInitableIface  *iface)
551 {
552   iface->init = g_tls_certificate_openssl_initable_init;
553 }
554
555 GTlsCertificate *
556 g_tls_certificate_openssl_new (GBytes          *bytes,
557                                GTlsCertificate *issuer)
558 {
559   GTlsCertificateOpenssl *openssl;
560
561   openssl = g_object_new (G_TYPE_TLS_CERTIFICATE_OPENSSL,
562                           "issuer", issuer,
563                           NULL);
564   g_tls_certificate_openssl_set_data (openssl, bytes);
565
566   return G_TLS_CERTIFICATE (openssl);
567 }
568
569 GTlsCertificate *
570 g_tls_certificate_openssl_new_from_x509 (X509            *x,
571                                          GTlsCertificate *issuer)
572 {
573   GTlsCertificateOpenssl *openssl;
574
575   openssl = g_object_new (G_TYPE_TLS_CERTIFICATE_OPENSSL,
576                           "issuer", issuer,
577                           NULL);
578
579   openssl->cert = X509_dup (x);
580   openssl->have_cert = TRUE;
581
582   return G_TLS_CERTIFICATE (openssl);
583 }
584
585 void
586 g_tls_certificate_openssl_set_data (GTlsCertificateOpenssl *openssl,
587                                     GBytes                 *bytes)
588 {
589   const unsigned char *data;
590
591   g_return_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl));
592
593   g_return_if_fail (!openssl->have_cert);
594
595   data = (const unsigned char *)g_bytes_get_data (bytes, NULL);
596   openssl->cert = d2i_X509 (NULL, &data, g_bytes_get_size (bytes));
597
598   if (openssl->cert)
599     openssl->have_cert = TRUE;
600 }
601
602 GBytes *
603 g_tls_certificate_openssl_get_bytes (GTlsCertificateOpenssl *openssl)
604 {
605   GByteArray *array;
606
607   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), NULL);
608
609   g_object_get (openssl, "certificate", &array, NULL);
610   return g_byte_array_free_to_bytes (array);
611 }
612
613 X509 *
614 g_tls_certificate_openssl_get_cert (GTlsCertificateOpenssl *openssl)
615 {
616   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), FALSE);
617
618   return openssl->cert;
619 }
620
621 EVP_PKEY *
622 g_tls_certificate_openssl_get_key (GTlsCertificateOpenssl *openssl)
623 {
624   g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), FALSE);
625
626   return openssl->key;
627 }
628
629 void
630 g_tls_certificate_openssl_set_issuer (GTlsCertificateOpenssl *openssl,
631                                       GTlsCertificateOpenssl *issuer)
632 {
633   g_return_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl));
634   g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_OPENSSL (issuer));
635
636   if (g_set_object (&openssl->issuer, issuer))
637     g_object_notify (G_OBJECT (openssl), "issuer");
638 }
639
640 static gboolean
641 verify_identity_hostname (GTlsCertificateOpenssl *openssl,
642                           GSocketConnectable     *identity)
643 {
644   const char *hostname;
645
646   if (G_IS_NETWORK_ADDRESS (identity))
647     hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
648   else if (G_IS_NETWORK_SERVICE (identity))
649     hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
650   else
651     return FALSE;
652
653   return X509_check_host (openssl->cert, hostname, strlen (hostname), 0, NULL) == 1;
654 }
655
656 static gboolean
657 verify_identity_ip (GTlsCertificateOpenssl *openssl,
658                     GSocketConnectable     *identity)
659 {
660   GInetAddress *addr;
661   gsize addr_size;
662   const guint8 *addr_bytes;
663   gboolean ret;
664
665   if (G_IS_INET_SOCKET_ADDRESS (identity))
666     addr = g_object_ref (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity)));
667   else {
668     const char *hostname;
669
670     if (G_IS_NETWORK_ADDRESS (identity))
671       hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
672     else if (G_IS_NETWORK_SERVICE (identity))
673       hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
674     else
675       return FALSE;
676
677     addr = g_inet_address_new_from_string (hostname);
678     if (!addr)
679       return FALSE;
680   }
681
682   addr_bytes = g_inet_address_to_bytes (addr);
683   addr_size = g_inet_address_get_native_size (addr);
684
685   ret = X509_check_ip (openssl->cert, addr_bytes, addr_size, 0) == 1;
686
687   g_object_unref (addr);
688   return ret;
689 }
690
691 GTlsCertificateFlags
692 g_tls_certificate_openssl_verify_identity (GTlsCertificateOpenssl *openssl,
693                                            GSocketConnectable     *identity)
694 {
695   if (verify_identity_hostname (openssl, identity))
696     return 0;
697   else if (verify_identity_ip (openssl, identity))
698     return 0;
699
700   /* FIXME: check sRVName and uniformResourceIdentifier
701    * subjectAltNames, if appropriate for @identity.
702    */
703
704   return G_TLS_CERTIFICATE_BAD_IDENTITY;
705 }
706
707 GTlsCertificateFlags
708 g_tls_certificate_openssl_convert_error (guint openssl_error)
709 {
710   GTlsCertificateFlags gtls_flags;
711
712   gtls_flags = 0;
713
714   /* FIXME: should we add more ? */
715   switch (openssl_error)
716     {
717     case X509_V_OK:
718       break;
719     case X509_V_ERR_CERT_NOT_YET_VALID:
720       gtls_flags = G_TLS_CERTIFICATE_NOT_ACTIVATED;
721       break;
722     case X509_V_ERR_CERT_HAS_EXPIRED:
723       gtls_flags = G_TLS_CERTIFICATE_EXPIRED;
724       break;
725     case X509_V_ERR_CERT_REVOKED:
726       gtls_flags = G_TLS_CERTIFICATE_REVOKED;
727       break;
728     case X509_V_ERR_AKID_SKID_MISMATCH:
729       gtls_flags = G_TLS_CERTIFICATE_BAD_IDENTITY;
730       break;
731     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
732     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
733 #ifdef TIZEN_EXT
734     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
735 #endif
736       gtls_flags = G_TLS_CERTIFICATE_UNKNOWN_CA;
737       break;
738     default:
739       gtls_flags = G_TLS_CERTIFICATE_GENERIC_ERROR;
740     }
741
742   return gtls_flags;
743 }
744
745 static gboolean
746 is_issuer (GTlsCertificateOpenssl *cert,
747            GTlsCertificateOpenssl *issuer)
748 {
749   X509 *x;
750   X509 *issuer_x;
751   X509_STORE *store;
752   X509_STORE_CTX *csc;
753   STACK_OF(X509) *trusted;
754   gboolean ret = FALSE;
755   gint err;
756
757   x = g_tls_certificate_openssl_get_cert (cert);
758   issuer_x = g_tls_certificate_openssl_get_cert (issuer);
759
760   store = X509_STORE_new ();
761   csc = X509_STORE_CTX_new ();
762
763   if (!X509_STORE_CTX_init (csc, store, x, NULL))
764     goto end;
765
766   trusted = sk_X509_new_null ();
767   sk_X509_push (trusted, issuer_x);
768
769   X509_STORE_CTX_trusted_stack (csc, trusted);
770   X509_STORE_CTX_set_flags (csc, X509_V_FLAG_CB_ISSUER_CHECK);
771
772   /* FIXME: is this the right way to do it? */
773   if (X509_verify_cert (csc) <= 0)
774     {
775       err = X509_STORE_CTX_get_error (csc);
776       if (err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)
777         ret = TRUE;
778     }
779   else
780     ret = TRUE;
781
782   sk_X509_free (trusted);
783
784 end:
785   X509_STORE_CTX_free (csc);
786   X509_STORE_free (store);
787
788   return ret;
789 }
790
791 GTlsCertificateOpenssl *
792 g_tls_certificate_openssl_build_chain (X509            *x,
793                                        STACK_OF (X509) *chain)
794 {
795   GPtrArray *glib_certs;
796   GTlsCertificateOpenssl *issuer;
797   GTlsCertificateOpenssl *result;
798   guint i, j;
799
800   g_return_val_if_fail (x, NULL);
801   g_return_val_if_fail (chain, NULL);
802
803   glib_certs = g_ptr_array_new_full (sk_X509_num (chain), g_object_unref);
804   g_ptr_array_add (glib_certs, g_tls_certificate_openssl_new_from_x509 (x, NULL));
805   for (i = 1; i < sk_X509_num (chain); i++)
806     g_ptr_array_add (glib_certs, g_tls_certificate_openssl_new_from_x509 (sk_X509_value (chain, i), NULL));
807
808   /* Some servers send certs out of order, or will send duplicate
809    * certs, so we need to be careful when assigning the issuer of
810    * our new GTlsCertificateOpenssl.
811    */
812   for (i = 0; i < glib_certs->len; i++)
813     {
814       issuer = NULL;
815
816       /* Check if the cert issued itself */
817       if (is_issuer (glib_certs->pdata[i], glib_certs->pdata[i]))
818         continue;
819
820       if (i < glib_certs->len - 1 &&
821           is_issuer (glib_certs->pdata[i], glib_certs->pdata[i + 1]))
822         {
823           issuer = glib_certs->pdata[i + 1];
824         }
825       else
826         {
827           for (j = 0; j < glib_certs->len; j++)
828             {
829               if (j != i &&
830                   is_issuer (glib_certs->pdata[i], glib_certs->pdata[j]))
831                 {
832                   issuer = glib_certs->pdata[j];
833                   break;
834                 }
835             }
836         }
837
838       if (issuer)
839         g_tls_certificate_openssl_set_issuer (glib_certs->pdata[i], issuer);
840     }
841
842   result = g_object_ref (glib_certs->pdata[0]);
843   g_ptr_array_unref (glib_certs);
844
845   return result;
846 }