1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright 2009 Red Hat, Inc
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.
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.
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/>.
19 * In addition, when the library is used with OpenSSL, a special
20 * exception applies. Refer to the LICENSE_EXCEPTION file for details.
25 #include <gnutls/gnutls.h>
26 #include <gnutls/x509.h>
29 #include "gtlscertificate-gnutls.h"
30 #include <glib/gi18n-lib.h>
32 static void g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface);
34 G_DEFINE_TYPE_WITH_CODE (GTlsCertificateGnutls, g_tls_certificate_gnutls, G_TYPE_TLS_CERTIFICATE,
35 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
36 g_tls_certificate_gnutls_initable_iface_init);)
49 struct _GTlsCertificateGnutlsPrivate
51 gnutls_x509_crt_t cert;
52 gnutls_x509_privkey_t key;
54 GTlsCertificateGnutls *issuer;
56 GError *construct_error;
63 g_tls_certificate_gnutls_finalize (GObject *object)
65 GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
67 gnutls_x509_crt_deinit (gnutls->priv->cert);
68 if (gnutls->priv->key)
69 gnutls_x509_privkey_deinit (gnutls->priv->key);
71 if (gnutls->priv->issuer)
72 g_object_unref (gnutls->priv->issuer);
74 g_clear_error (&gnutls->priv->construct_error);
76 G_OBJECT_CLASS (g_tls_certificate_gnutls_parent_class)->finalize (object);
80 g_tls_certificate_gnutls_get_property (GObject *object,
85 GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
86 GByteArray *certificate;
87 char *certificate_pem;
93 case PROP_CERTIFICATE:
95 status = gnutls_x509_crt_export (gnutls->priv->cert,
98 if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
102 certificate = g_byte_array_sized_new (size);
103 certificate->len = size;
104 status = gnutls_x509_crt_export (gnutls->priv->cert,
106 certificate->data, &size);
109 g_byte_array_free (certificate, TRUE);
113 g_value_take_boxed (value, certificate);
116 case PROP_CERTIFICATE_PEM:
118 status = gnutls_x509_crt_export (gnutls->priv->cert,
121 if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
122 certificate_pem = NULL;
125 certificate_pem = g_malloc (size);
126 status = gnutls_x509_crt_export (gnutls->priv->cert,
128 certificate_pem, &size);
131 g_free (certificate_pem);
132 certificate_pem = NULL;
135 g_value_take_string (value, certificate_pem);
139 g_value_set_object (value, gnutls->priv->issuer);
143 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
148 g_tls_certificate_gnutls_set_property (GObject *object,
153 GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
161 case PROP_CERTIFICATE:
162 bytes = g_value_get_boxed (value);
165 g_return_if_fail (gnutls->priv->have_cert == FALSE);
166 data.data = bytes->data;
167 data.size = bytes->len;
168 status = gnutls_x509_crt_import (gnutls->priv->cert, &data,
169 GNUTLS_X509_FMT_DER);
171 gnutls->priv->have_cert = TRUE;
172 else if (!gnutls->priv->construct_error)
174 gnutls->priv->construct_error =
175 g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
176 _("Could not parse DER certificate: %s"),
177 gnutls_strerror (status));
182 case PROP_CERTIFICATE_PEM:
183 string = g_value_get_string (value);
186 g_return_if_fail (gnutls->priv->have_cert == FALSE);
187 data.data = (void *)string;
188 data.size = strlen (string);
189 status = gnutls_x509_crt_import (gnutls->priv->cert, &data,
190 GNUTLS_X509_FMT_PEM);
192 gnutls->priv->have_cert = TRUE;
193 else if (!gnutls->priv->construct_error)
195 gnutls->priv->construct_error =
196 g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
197 _("Could not parse PEM certificate: %s"),
198 gnutls_strerror (status));
202 case PROP_PRIVATE_KEY:
203 bytes = g_value_get_boxed (value);
206 g_return_if_fail (gnutls->priv->have_key == FALSE);
207 data.data = bytes->data;
208 data.size = bytes->len;
209 if (!gnutls->priv->key)
210 gnutls_x509_privkey_init (&gnutls->priv->key);
211 status = gnutls_x509_privkey_import (gnutls->priv->key, &data,
212 GNUTLS_X509_FMT_DER);
216 gnutls_x509_privkey_import_pkcs8 (gnutls->priv->key, &data,
217 GNUTLS_X509_FMT_DER, NULL,
219 if (pkcs8_status == 0)
223 gnutls->priv->have_key = TRUE;
224 else if (!gnutls->priv->construct_error)
226 gnutls->priv->construct_error =
227 g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
228 _("Could not parse DER private key: %s"),
229 gnutls_strerror (status));
233 case PROP_PRIVATE_KEY_PEM:
234 string = g_value_get_string (value);
237 g_return_if_fail (gnutls->priv->have_key == FALSE);
238 data.data = (void *)string;
239 data.size = strlen (string);
240 if (!gnutls->priv->key)
241 gnutls_x509_privkey_init (&gnutls->priv->key);
242 status = gnutls_x509_privkey_import (gnutls->priv->key, &data,
243 GNUTLS_X509_FMT_PEM);
247 gnutls_x509_privkey_import_pkcs8 (gnutls->priv->key, &data,
248 GNUTLS_X509_FMT_PEM, NULL,
250 if (pkcs8_status == 0)
254 gnutls->priv->have_key = TRUE;
255 else if (!gnutls->priv->construct_error)
257 gnutls->priv->construct_error =
258 g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
259 _("Could not parse PEM private key: %s"),
260 gnutls_strerror (status));
265 gnutls->priv->issuer = g_value_dup_object (value);
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 g_tls_certificate_gnutls_init (GTlsCertificateGnutls *gnutls)
276 gnutls->priv = G_TYPE_INSTANCE_GET_PRIVATE (gnutls,
277 G_TYPE_TLS_CERTIFICATE_GNUTLS,
278 GTlsCertificateGnutlsPrivate);
280 gnutls_x509_crt_init (&gnutls->priv->cert);
284 g_tls_certificate_gnutls_initable_init (GInitable *initable,
285 GCancellable *cancellable,
288 GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (initable);
290 if (gnutls->priv->construct_error)
292 g_propagate_error (error, gnutls->priv->construct_error);
293 gnutls->priv->construct_error = NULL;
296 else if (!gnutls->priv->have_cert)
298 g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
299 _("No certificate data provided"));
306 static GTlsCertificateFlags
307 g_tls_certificate_gnutls_verify (GTlsCertificate *cert,
308 GSocketConnectable *identity,
309 GTlsCertificate *trusted_ca)
311 GTlsCertificateGnutls *cert_gnutls;
313 gnutls_x509_crt_t *chain;
314 GTlsCertificateFlags gtls_flags;
317 cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
318 for (num_certs = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer)
320 chain = g_new (gnutls_x509_crt_t, num_certs);
321 cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
322 for (i = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer, i++)
323 chain[i] = cert_gnutls->priv->cert;
327 gnutls_x509_crt_t ca;
331 ca = G_TLS_CERTIFICATE_GNUTLS (trusted_ca)->priv->cert;
332 status = gnutls_x509_crt_list_verify (chain, num_certs,
335 GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
340 return G_TLS_CERTIFICATE_GENERIC_ERROR;
343 gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
348 /* We have to check these ourselves since gnutls_x509_crt_list_verify
349 * won't bother if it gets an UNKNOWN_CA.
352 for (i = 0; i < num_certs; i++)
354 t = gnutls_x509_crt_get_activation_time (chain[i]);
355 if (t == (time_t) -1 || t > now)
356 gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
358 t = gnutls_x509_crt_get_expiration_time (chain[i]);
359 if (t == (time_t) -1 || t < now)
360 gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
366 gtls_flags |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (cert), identity);
372 g_tls_certificate_gnutls_real_copy (GTlsCertificateGnutls *gnutls,
373 const gchar *interaction_id,
376 GTlsCertificateGnutls *chain;
377 gnutls_x509_crt_t cert;
383 /* We will do this loop twice. It's probably more efficient than
384 * re-allocating memory.
387 while (chain != NULL)
390 chain = chain->priv->issuer;
394 st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t) * num_certs);
396 /* Now do the actual copy of the whole chain. */
398 while (chain != NULL)
400 gnutls_x509_crt_export (chain->priv->cert, GNUTLS_X509_FMT_DER,
402 data.data = g_malloc (size);
404 gnutls_x509_crt_export (chain->priv->cert, GNUTLS_X509_FMT_DER,
407 gnutls_x509_crt_init (&cert);
408 status = gnutls_x509_crt_import (cert, &data, GNUTLS_X509_FMT_DER);
409 g_warn_if_fail (status == 0);
412 st->cert.x509[st->ncerts] = cert;
415 chain = chain->priv->issuer;
418 if (gnutls->priv->key != NULL)
420 gnutls_x509_privkey_init (&st->key.x509);
421 gnutls_x509_privkey_cpy (st->key.x509, gnutls->priv->key);
422 st->key_type = GNUTLS_PRIVKEY_X509;
425 st->deinit_all = TRUE;
429 g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
431 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
432 GTlsCertificateClass *certificate_class = G_TLS_CERTIFICATE_CLASS (klass);
434 g_type_class_add_private (klass, sizeof (GTlsCertificateGnutlsPrivate));
436 gobject_class->get_property = g_tls_certificate_gnutls_get_property;
437 gobject_class->set_property = g_tls_certificate_gnutls_set_property;
438 gobject_class->finalize = g_tls_certificate_gnutls_finalize;
440 certificate_class->verify = g_tls_certificate_gnutls_verify;
442 klass->copy = g_tls_certificate_gnutls_real_copy;
444 g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
445 g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
446 g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
447 g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
448 g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
452 g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface)
454 iface->init = g_tls_certificate_gnutls_initable_init;
458 g_tls_certificate_gnutls_new (const gnutls_datum_t *datum,
459 GTlsCertificate *issuer)
461 GTlsCertificateGnutls *gnutls;
463 gnutls = g_object_new (G_TYPE_TLS_CERTIFICATE_GNUTLS,
466 g_tls_certificate_gnutls_set_data (gnutls, datum);
468 return G_TLS_CERTIFICATE (gnutls);
472 g_tls_certificate_gnutls_set_data (GTlsCertificateGnutls *gnutls,
473 const gnutls_datum_t *datum)
475 g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
476 g_return_if_fail (!gnutls->priv->have_cert);
478 if (gnutls_x509_crt_import (gnutls->priv->cert, datum,
479 GNUTLS_X509_FMT_DER) == 0)
480 gnutls->priv->have_cert = TRUE;
483 const gnutls_x509_crt_t
484 g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls)
486 return gnutls->priv->cert;
490 g_tls_certificate_gnutls_has_key (GTlsCertificateGnutls *gnutls)
492 return gnutls->priv->have_key;
496 g_tls_certificate_gnutls_copy (GTlsCertificateGnutls *gnutls,
497 const gchar *interaction_id,
500 g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
501 g_return_if_fail (st != NULL);
502 g_return_if_fail (G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy);
503 G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy (gnutls, interaction_id, st);
506 static const struct {
508 GTlsCertificateFlags gtls_flag;
510 { GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_SIGNER_NOT_CA, G_TLS_CERTIFICATE_UNKNOWN_CA },
511 { GNUTLS_CERT_NOT_ACTIVATED, G_TLS_CERTIFICATE_NOT_ACTIVATED },
512 { GNUTLS_CERT_EXPIRED, G_TLS_CERTIFICATE_EXPIRED },
513 { GNUTLS_CERT_REVOKED, G_TLS_CERTIFICATE_REVOKED },
514 { GNUTLS_CERT_INSECURE_ALGORITHM, G_TLS_CERTIFICATE_INSECURE },
515 { GNUTLS_CERT_UNEXPECTED_OWNER, G_TLS_CERTIFICATE_BAD_IDENTITY }
517 static const int flags_map_size = G_N_ELEMENTS (flags_map);
520 g_tls_certificate_gnutls_convert_flags (guint gnutls_flags)
523 GTlsCertificateFlags gtls_flags;
525 /* Convert GNUTLS status to GTlsCertificateFlags. GNUTLS sets
526 * GNUTLS_CERT_INVALID if it sets any other flag, so we want to
527 * strip that out unless it's the only flag set. Then we convert
528 * specific flags we recognize, and if there are any flags left over
529 * at the end, we add G_TLS_CERTIFICATE_GENERIC_ERROR.
533 if (gnutls_flags != GNUTLS_CERT_INVALID)
534 gnutls_flags = gnutls_flags & ~GNUTLS_CERT_INVALID;
535 for (i = 0; i < flags_map_size && gnutls_flags != 0; i++)
537 if (gnutls_flags & flags_map[i].gnutls_flag)
539 gnutls_flags &= ~flags_map[i].gnutls_flag;
540 gtls_flags |= flags_map[i].gtls_flag;
544 gtls_flags |= G_TLS_CERTIFICATE_GENERIC_ERROR;
550 verify_identity_hostname (GTlsCertificateGnutls *gnutls,
551 GSocketConnectable *identity)
553 const char *hostname;
555 if (G_IS_NETWORK_ADDRESS (identity))
556 hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
557 else if (G_IS_NETWORK_SERVICE (identity))
558 hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
562 return gnutls_x509_crt_check_hostname (gnutls->priv->cert, hostname);
566 verify_identity_ip (GTlsCertificateGnutls *gnutls,
567 GSocketConnectable *identity)
572 const guint8 *addr_bytes;
574 if (G_IS_INET_SOCKET_ADDRESS (identity))
575 addr = g_object_ref (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity)));
577 const char *hostname;
579 if (G_IS_NETWORK_ADDRESS (identity))
580 hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
581 else if (G_IS_NETWORK_SERVICE (identity))
582 hostname = g_network_service_get_domain (G_NETWORK_SERVICE (identity));
586 addr = g_inet_address_new_from_string (hostname);
591 addr_bytes = g_inet_address_to_bytes (addr);
592 addr_size = g_inet_address_get_native_size (addr);
594 for (i = 0; ret >= 0; i++)
599 san_size = sizeof (san);
600 ret = gnutls_x509_crt_get_subject_alt_name (gnutls->priv->cert, i,
601 san, &san_size, NULL);
603 if ((ret == GNUTLS_SAN_IPADDRESS) && (addr_size == san_size))
605 if (memcmp (addr_bytes, san, addr_size) == 0)
607 g_object_unref (addr);
613 g_object_unref (addr);
618 g_tls_certificate_gnutls_verify_identity (GTlsCertificateGnutls *gnutls,
619 GSocketConnectable *identity)
621 if (verify_identity_hostname (gnutls, identity))
623 else if (verify_identity_ip (gnutls, identity))
626 /* FIXME: check sRVName and uniformResourceIdentifier
627 * subjectAltNames, if appropriate for @identity.
630 return G_TLS_CERTIFICATE_BAD_IDENTITY;
634 g_tls_certificate_gnutls_set_issuer (GTlsCertificateGnutls *gnutls,
635 GTlsCertificateGnutls *issuer)
637 g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
638 g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_GNUTLS (issuer));
641 g_object_ref (issuer);
642 if (gnutls->priv->issuer)
643 g_object_unref (gnutls->priv->issuer);
644 gnutls->priv->issuer = issuer;
645 g_object_notify (G_OBJECT (gnutls), "issuer");
649 g_tls_certificate_gnutls_get_bytes (GTlsCertificateGnutls *gnutls)
653 g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls), NULL);
655 g_object_get (gnutls, "certificate", &array, NULL);
656 return g_byte_array_free_to_bytes (array);
659 static gnutls_x509_crt_t *
660 convert_data_to_gnutls_certs (const gnutls_datum_t *certs,
662 gnutls_x509_crt_fmt_t format)
664 gnutls_x509_crt_t *gnutls_certs;
667 gnutls_certs = g_new (gnutls_x509_crt_t, num_certs);
669 for (i = 0; i < num_certs; i++)
671 if (gnutls_x509_crt_init (&gnutls_certs[i]) < 0)
678 for (i = 0; i < num_certs; i++)
680 if (gnutls_x509_crt_import (gnutls_certs[i], &certs[i], format) < 0)
690 for (; i != G_MAXUINT; i--)
691 gnutls_x509_crt_deinit (gnutls_certs[i]);
692 g_free (gnutls_certs);
696 GTlsCertificateGnutls *
697 g_tls_certificate_gnutls_build_chain (const gnutls_datum_t *certs,
699 gnutls_x509_crt_fmt_t format)
701 GPtrArray *glib_certs;
702 gnutls_x509_crt_t *gnutls_certs;
703 GTlsCertificateGnutls *issuer;
704 GTlsCertificateGnutls *result;
707 g_return_val_if_fail (certs, NULL);
709 gnutls_certs = convert_data_to_gnutls_certs (certs, num_certs, format);
713 glib_certs = g_ptr_array_new_full (num_certs, g_object_unref);
714 for (i = 0; i < num_certs; i++)
715 g_ptr_array_add (glib_certs, g_tls_certificate_gnutls_new (&certs[i], NULL));
717 /* Some servers send certs out of order, or will send duplicate
718 * certs, so we need to be careful when assigning the issuer of
719 * our new GTlsCertificateGnutls.
721 for (i = 0; i < num_certs; i++)
725 /* Check if the cert issued itself */
726 if (gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[i]))
729 if (i < num_certs - 1 &&
730 gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[i + 1]))
732 issuer = glib_certs->pdata[i + 1];
736 for (j = 0; j < num_certs; j++)
739 gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[j]))
741 issuer = glib_certs->pdata[j];
748 g_tls_certificate_gnutls_set_issuer (glib_certs->pdata[i], issuer);
751 result = g_object_ref (glib_certs->pdata[0]);
752 g_ptr_array_unref (glib_certs);
754 for (i = 0; i < num_certs; i++)
755 gnutls_x509_crt_deinit (gnutls_certs[i]);
756 g_free (gnutls_certs);