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