gnutls: Implement certificate-bytes and private-key-bytes properties
[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
20 #include "config.h"
21
22 #include <gnutls/gnutls.h>
23 #include <gnutls/x509.h>
24 #include <string.h>
25
26 #include "gtlscertificate-gnutls.h"
27 #include <glib/gi18n-lib.h>
28
29 static void     g_tls_certificate_gnutls_initable_iface_init (GInitableIface  *iface);
30
31 G_DEFINE_TYPE_WITH_CODE (GTlsCertificateGnutls, g_tls_certificate_gnutls, G_TYPE_TLS_CERTIFICATE,
32                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
33                                                 g_tls_certificate_gnutls_initable_iface_init);)
34
35 enum
36 {
37   PROP_0,
38
39   PROP_CERTIFICATE,
40   PROP_CERTIFICATE_BYTES,
41   PROP_CERTIFICATE_PEM,
42   PROP_PRIVATE_KEY,
43   PROP_PRIVATE_KEY_BYTES,
44   PROP_PRIVATE_KEY_PEM,
45   PROP_ISSUER
46 };
47
48 struct _GTlsCertificateGnutlsPrivate
49 {
50   gnutls_x509_crt_t cert;
51   gnutls_x509_privkey_t key;
52
53   GTlsCertificateGnutls *issuer;
54
55   GError *construct_error;
56
57   guint have_cert : 1;
58   guint have_key  : 1;
59 };
60
61 static void
62 g_tls_certificate_gnutls_finalize (GObject *object)
63 {
64   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
65
66   gnutls_x509_crt_deinit (gnutls->priv->cert);
67   if (gnutls->priv->key)
68     gnutls_x509_privkey_deinit (gnutls->priv->key);
69
70   if (gnutls->priv->issuer)
71     g_object_unref (gnutls->priv->issuer);
72
73   g_clear_error (&gnutls->priv->construct_error);
74
75   G_OBJECT_CLASS (g_tls_certificate_gnutls_parent_class)->finalize (object);
76 }
77
78 static GByteArray *
79 get_der_for_certificate (GTlsCertificateGnutls *self)
80 {
81   GByteArray *certificate;
82   size_t size;
83   int status;
84
85   size = 0;
86   status = gnutls_x509_crt_export (self->priv->cert,
87                                    GNUTLS_X509_FMT_DER,
88                                    NULL, &size);
89   if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
90     {
91       certificate = NULL;
92     }
93   else
94     {
95       certificate = g_byte_array_sized_new (size);
96       certificate->len = size;
97       status = gnutls_x509_crt_export (self->priv->cert,
98                                        GNUTLS_X509_FMT_DER,
99                                        certificate->data, &size);
100       if (status != 0)
101         {
102           g_byte_array_free (certificate, TRUE);
103           certificate = NULL;
104         }
105     }
106
107   return certificate;
108 }
109
110 static gchar *
111 get_pem_for_certificate (GTlsCertificateGnutls *self)
112 {
113   char *certificate_pem;
114   int status;
115   size_t size;
116
117   size = 0;
118   status = gnutls_x509_crt_export (self->priv->cert,
119                                    GNUTLS_X509_FMT_PEM,
120                                    NULL, &size);
121   if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
122     {
123       certificate_pem = NULL;
124     }
125   else
126     {
127       certificate_pem = g_malloc (size);
128       status = gnutls_x509_crt_export (self->priv->cert,
129                                        GNUTLS_X509_FMT_PEM,
130                                        certificate_pem, &size);
131       if (status != 0)
132         {
133           g_free (certificate_pem);
134           certificate_pem = NULL;
135         }
136     }
137
138   return certificate_pem;
139 }
140
141 static void
142 g_tls_certificate_gnutls_get_property (GObject    *object,
143                                        guint       prop_id,
144                                        GValue     *value,
145                                        GParamSpec *pspec)
146 {
147   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
148   GByteArray *certificate;
149
150   switch (prop_id)
151     {
152     case PROP_CERTIFICATE:
153       g_value_take_boxed (value, get_der_for_certificate (gnutls));
154       break;
155
156     case PROP_CERTIFICATE_BYTES:
157       certificate = get_der_for_certificate (gnutls);
158       if (certificate == NULL)
159         g_value_take_boxed (value, NULL);
160       else
161         g_value_take_boxed (value, g_byte_array_free_to_bytes (certificate));
162       break;
163
164     case PROP_CERTIFICATE_PEM:
165       g_value_take_string (value, get_pem_for_certificate (gnutls));
166       break;
167
168     case PROP_ISSUER:
169       g_value_set_object (value, gnutls->priv->issuer);
170       break;
171
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174     }
175 }
176
177 static void
178 set_certificate_from_der (GTlsCertificateGnutls *self,
179                           const guchar *der,
180                           gsize len)
181 {
182   gnutls_datum_t data;
183   int status;
184
185   g_return_if_fail (self->priv->have_cert == FALSE);
186   data.data = (guchar *)der;
187   data.size = len;
188   status = gnutls_x509_crt_import (self->priv->cert, &data,
189                                    GNUTLS_X509_FMT_DER);
190   if (status == 0)
191     {
192       self->priv->have_cert = TRUE;
193     }
194   else if (!self->priv->construct_error)
195     {
196       self->priv->construct_error =
197         g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
198                      _("Could not parse DER certificate: %s"),
199                      gnutls_strerror (status));
200     }
201 }
202
203 static void
204 set_certificate_from_pem (GTlsCertificateGnutls *self,
205                           const gchar *string)
206 {
207   gnutls_datum_t data;
208   int status;
209
210   g_return_if_fail (self->priv->have_cert == FALSE);
211   data.data = (guchar *)string;
212   data.size = strlen (string);
213   status = gnutls_x509_crt_import (self->priv->cert, &data,
214                                    GNUTLS_X509_FMT_PEM);
215   if (status == 0)
216     {
217       self->priv->have_cert = TRUE;
218     }
219   else if (!self->priv->construct_error)
220     {
221       self->priv->construct_error =
222         g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
223                      _("Could not parse PEM certificate: %s"),
224                      gnutls_strerror (status));
225     }
226 }
227
228 static void
229 set_private_key_from_der (GTlsCertificateGnutls *self,
230                           const guchar *der,
231                           gsize len)
232 {
233   gnutls_datum_t data;
234   int status;
235
236   g_return_if_fail (self->priv->have_key == FALSE);
237   data.data = (guchar *)der;
238   data.size = len;
239   if (!self->priv->key)
240     gnutls_x509_privkey_init (&self->priv->key);
241   status = gnutls_x509_privkey_import (self->priv->key, &data,
242                                        GNUTLS_X509_FMT_DER);
243   if (status != 0)
244     {
245       int pkcs8_status =
246         gnutls_x509_privkey_import_pkcs8 (self->priv->key, &data,
247                                           GNUTLS_X509_FMT_DER, NULL,
248                                           GNUTLS_PKCS_PLAIN);
249       if (pkcs8_status == 0)
250         status = 0;
251     }
252   if (status == 0)
253     {
254       self->priv->have_key = TRUE;
255     }
256   else if (!self->priv->construct_error)
257     {
258       self->priv->construct_error =
259         g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
260                      _("Could not parse DER private key: %s"),
261                      gnutls_strerror (status));
262     }
263 }
264
265 static void
266 set_private_key_from_pem (GTlsCertificateGnutls *self,
267                           const gchar *string)
268 {
269   gnutls_datum_t data;
270   int status;
271
272   g_return_if_fail (self->priv->have_key == FALSE);
273   data.data = (guchar *)string;
274   data.size = strlen (string);
275   if (!self->priv->key)
276     gnutls_x509_privkey_init (&self->priv->key);
277   status = gnutls_x509_privkey_import (self->priv->key, &data,
278                                        GNUTLS_X509_FMT_PEM);
279   if (status != 0)
280     {
281       int pkcs8_status =
282         gnutls_x509_privkey_import_pkcs8 (self->priv->key, &data,
283                                           GNUTLS_X509_FMT_PEM, NULL,
284                                           GNUTLS_PKCS_PLAIN);
285       if (pkcs8_status == 0)
286         status = 0;
287     }
288   if (status == 0)
289     {
290       self->priv->have_key = TRUE;
291     }
292   else if (!self->priv->construct_error)
293     {
294       self->priv->construct_error =
295         g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
296                      _("Could not parse PEM private key: %s"),
297                      gnutls_strerror (status));
298     }
299 }
300
301 static void
302 g_tls_certificate_gnutls_set_property (GObject      *object,
303                                        guint         prop_id,
304                                        const GValue *value,
305                                        GParamSpec   *pspec)
306 {
307   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
308   GByteArray *byte_array;
309   const char *string;
310   GBytes *bytes;
311
312   switch (prop_id)
313     {
314     case PROP_CERTIFICATE:
315       byte_array = g_value_get_boxed (value);
316       if (byte_array)
317         set_certificate_from_der (gnutls, byte_array->data, byte_array->len);
318       break;
319
320     case PROP_CERTIFICATE_BYTES:
321       bytes = g_value_get_boxed (value);
322       if (bytes)
323         {
324           set_certificate_from_der (gnutls, g_bytes_get_data (bytes, NULL),
325                                     g_bytes_get_size (bytes));
326         }
327       break;
328
329     case PROP_CERTIFICATE_PEM:
330       string = g_value_get_string (value);
331       if (string)
332         set_certificate_from_pem (gnutls, string);
333       break;
334
335     case PROP_PRIVATE_KEY:
336       byte_array = g_value_get_boxed (value);
337       if (byte_array)
338         set_private_key_from_der (gnutls, byte_array->data, byte_array->len);
339       break;
340
341     case PROP_PRIVATE_KEY_BYTES:
342       bytes = g_value_get_boxed (value);
343       if (bytes)
344         {
345           set_private_key_from_der (gnutls, g_bytes_get_data (bytes, NULL),
346                                     g_bytes_get_size (bytes));
347         }
348       break;
349
350     case PROP_PRIVATE_KEY_PEM:
351       string = g_value_get_string (value);
352       if (string)
353         set_private_key_from_pem (gnutls, string);
354       break;
355
356     case PROP_ISSUER:
357       gnutls->priv->issuer = g_value_dup_object (value);
358       break;
359
360     default:
361       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
362     }
363 }
364
365 static void
366 g_tls_certificate_gnutls_init (GTlsCertificateGnutls *gnutls)
367 {
368   gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls,
369                                               G_TYPE_TLS_CERTIFICATE_GNUTLS,
370                                               GTlsCertificateGnutlsPrivate);
371
372   gnutls_x509_crt_init (&gnutls->priv->cert);
373 }
374
375 static gboolean
376 g_tls_certificate_gnutls_initable_init (GInitable       *initable,
377                                         GCancellable    *cancellable,
378                                         GError         **error)
379 {
380   GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (initable);
381
382   if (gnutls->priv->construct_error)
383     {
384       g_propagate_error (error, gnutls->priv->construct_error);
385       gnutls->priv->construct_error = NULL;
386       return FALSE;
387     }
388   else if (!gnutls->priv->have_cert)
389     {
390       g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
391                            _("No certificate data provided"));
392       return FALSE;
393     }
394   else
395     return TRUE;
396 }
397
398 static GTlsCertificateFlags
399 g_tls_certificate_gnutls_verify (GTlsCertificate     *cert,
400                                  GSocketConnectable  *identity,
401                                  GTlsCertificate     *trusted_ca)
402 {
403   GTlsCertificateGnutls *cert_gnutls;
404   guint num_certs, i;
405   gnutls_x509_crt_t *chain;
406   GTlsCertificateFlags gtls_flags;
407   time_t t, now;
408   
409   cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
410   for (num_certs = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer)
411     num_certs++;
412   chain = g_new (gnutls_x509_crt_t, num_certs);
413   cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
414   for (i = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer, i++)
415     chain[i] = cert_gnutls->priv->cert;
416
417   if (trusted_ca)
418     {
419       gnutls_x509_crt_t ca;
420       guint gnutls_flags;
421       int status;
422
423       ca = G_TLS_CERTIFICATE_GNUTLS (trusted_ca)->priv->cert;
424       status = gnutls_x509_crt_list_verify (chain, num_certs,
425                                             &ca, 1,
426                                             NULL, 0,
427                                             GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
428                                             &gnutls_flags);
429       if (status != 0)
430         {
431           g_free (chain);
432           return G_TLS_CERTIFICATE_GENERIC_ERROR;
433         }
434
435       gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
436     }
437   else
438     gtls_flags = 0;
439
440   /* We have to check these ourselves since gnutls_x509_crt_list_verify
441    * won't bother if it gets an UNKNOWN_CA.
442    */
443   now = time (NULL);
444   for (i = 0; i < num_certs; i++)
445     {
446       t = gnutls_x509_crt_get_activation_time (chain[i]);
447       if (t == (time_t) -1 || t > now)
448         gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
449
450       t = gnutls_x509_crt_get_expiration_time (chain[i]);
451       if (t == (time_t) -1 || t < now)
452         gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
453     }
454
455   g_free (chain);
456
457   if (identity)
458     gtls_flags |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (cert), identity);
459
460   return gtls_flags;
461 }
462
463 static void
464 g_tls_certificate_gnutls_real_copy (GTlsCertificateGnutls    *gnutls,
465                                     const gchar              *interaction_id,
466                                     gnutls_retr2_st          *st)
467 {
468   gnutls_x509_crt_t cert;
469   gnutls_datum data;
470   size_t size = 0;
471
472   gnutls_x509_crt_export (gnutls->priv->cert, GNUTLS_X509_FMT_DER,
473                           NULL, &size);
474   data.data = g_malloc (size);
475   data.size = size;
476   gnutls_x509_crt_export (gnutls->priv->cert, GNUTLS_X509_FMT_DER,
477                           data.data, &size);
478
479   gnutls_x509_crt_init (&cert);
480   gnutls_x509_crt_import (cert, &data, GNUTLS_X509_FMT_DER);
481   g_free (data.data);
482
483   st->ncerts = 1;
484   st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t));
485   st->cert.x509[0] = cert;
486
487   if (gnutls->priv->key != NULL)
488     {
489       gnutls_x509_privkey_init (&st->key.x509);
490       gnutls_x509_privkey_cpy (st->key.x509, gnutls->priv->key);
491       st->key_type = GNUTLS_PRIVKEY_X509;
492     }
493
494   st->deinit_all = TRUE;
495 }
496
497 static void
498 g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
499 {
500   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
501   GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
502
503   g_type_class_add_private (klass, sizeof (GTlsCertificateGnutlsPrivate));
504
505   gobject_class->get_property = g_tls_certificate_gnutls_get_property;
506   gobject_class->set_property = g_tls_certificate_gnutls_set_property;
507   gobject_class->finalize     = g_tls_certificate_gnutls_finalize;
508
509   certificate_class->verify = g_tls_certificate_gnutls_verify;
510
511   klass->copy = g_tls_certificate_gnutls_real_copy;
512
513   g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
514   g_object_class_override_property (gobject_class, PROP_CERTIFICATE_BYTES, "certificate-bytes");
515   g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
516   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
517   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_BYTES, "private-key-bytes");
518   g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
519   g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
520 }
521
522 static void
523 g_tls_certificate_gnutls_initable_iface_init (GInitableIface  *iface)
524 {
525   iface->init = g_tls_certificate_gnutls_initable_init;
526 }
527
528 GTlsCertificate *
529 g_tls_certificate_gnutls_new (const gnutls_datum *datum,
530                               GTlsCertificate    *issuer)
531 {
532   GTlsCertificateGnutls *gnutls;
533
534   gnutls = g_object_new (G_TYPE_TLS_CERTIFICATE_GNUTLS,
535                          "issuer", issuer,
536                          NULL);
537   g_tls_certificate_gnutls_set_data (gnutls, datum);
538
539   return G_TLS_CERTIFICATE (gnutls);
540 }
541
542 void
543 g_tls_certificate_gnutls_set_data (GTlsCertificateGnutls *gnutls,
544                                    const gnutls_datum *datum)
545 {
546   g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
547   g_return_if_fail (!gnutls->priv->have_cert);
548
549   if (gnutls_x509_crt_import (gnutls->priv->cert, datum,
550                               GNUTLS_X509_FMT_DER) == 0)
551     gnutls->priv->have_cert = TRUE;
552 }
553
554 const gnutls_x509_crt_t
555 g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls)
556 {
557   return gnutls->priv->cert;
558 }
559
560 gboolean
561 g_tls_certificate_gnutls_has_key (GTlsCertificateGnutls *gnutls)
562 {
563   return gnutls->priv->have_key;
564 }
565
566 void
567 g_tls_certificate_gnutls_copy  (GTlsCertificateGnutls *gnutls,
568                                 const gchar           *interaction_id,
569                                 gnutls_retr2_st       *st)
570 {
571   g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
572   g_return_if_fail (st != NULL);
573   g_return_if_fail (G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy);
574   G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy (gnutls, interaction_id, st);
575 }
576
577 static const struct {
578   int gnutls_flag;
579   GTlsCertificateFlags gtls_flag;
580 } flags_map[] = {
581   { GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA, G_TLS_CERTIFICATE_UNKNOWN_CA },
582   { GNUTLS_CERT_NOT_ACTIVATED, G_TLS_CERTIFICATE_NOT_ACTIVATED },
583   { GNUTLS_CERT_EXPIRED, G_TLS_CERTIFICATE_EXPIRED },
584   { GNUTLS_CERT_REVOKED, G_TLS_CERTIFICATE_REVOKED },
585   { GNUTLS_CERT_INSECURE_ALGORITHM, G_TLS_CERTIFICATE_INSECURE }
586 };
587 static const int flags_map_size = G_N_ELEMENTS (flags_map);
588
589 GTlsCertificateFlags
590 g_tls_certificate_gnutls_convert_flags (guint gnutls_flags)
591 {
592   int i;
593   GTlsCertificateFlags gtls_flags;
594
595   /* Convert GNUTLS status to GTlsCertificateFlags. GNUTLS sets
596    * GNUTLS_CERT_INVALID if it sets any other flag, so we want to
597    * strip that out unless it's the only flag set. Then we convert
598    * specific flags we recognize, and if there are any flags left over
599    * at the end, we add G_TLS_CERTIFICATE_GENERIC_ERROR.
600    */
601   gtls_flags = 0;
602
603   if (gnutls_flags != GNUTLS_CERT_INVALID)
604     gnutls_flags = gnutls_flags & ~GNUTLS_CERT_INVALID;
605   for (i = 0; i < flags_map_size && gnutls_flags != 0; i++)
606     {
607       if (gnutls_flags & flags_map[i].gnutls_flag)
608         {
609           gnutls_flags &= ~flags_map[i].gnutls_flag;
610           gtls_flags |= flags_map[i].gtls_flag;
611         }
612     }
613   if (gnutls_flags)
614     gtls_flags |= G_TLS_CERTIFICATE_GENERIC_ERROR;
615
616   return gtls_flags;
617 }
618
619 GTlsCertificateFlags
620 g_tls_certificate_gnutls_verify_identity (GTlsCertificateGnutls *gnutls,
621                                           GSocketConnectable    *identity)
622 {
623   const char *hostname;
624
625   if (G_IS_NETWORK_ADDRESS (identity))
626     hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
627   else if (G_IS_NETWORK_SERVICE (identity))
628     hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
629   else
630     hostname = NULL;
631
632   if (hostname)
633     {
634       if (gnutls_x509_crt_check_hostname (gnutls->priv->cert, hostname))
635         return 0;
636     }
637
638   /* FIXME: check sRVName and uniformResourceIdentifier
639    * subjectAltNames, if appropriate for @identity.
640    */
641
642   return G_TLS_CERTIFICATE_BAD_IDENTITY;
643 }
644
645 void
646 g_tls_certificate_gnutls_set_issuer (GTlsCertificateGnutls *gnutls,
647                                      GTlsCertificateGnutls *issuer)
648 {
649   g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
650   g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_GNUTLS (issuer));
651
652   if (issuer)
653     g_object_ref (issuer);
654   if (gnutls->priv->issuer)
655     g_object_unref (gnutls->priv->issuer);
656   gnutls->priv->issuer = issuer;
657   g_object_notify (G_OBJECT (gnutls), "issuer");
658 }