/* GIO - GLib Input, Output and Streaming Library
*
- * Copyright © 2009 Red Hat, Inc
+ * Copyright 2009 Red Hat, Inc
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gtlscertificate-gnutls.h"
#include <glib/gi18n-lib.h>
+#include "TIZEN.h"
static void g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface);
GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
gnutls_x509_crt_deinit (gnutls->priv->cert);
- gnutls_x509_privkey_deinit (gnutls->priv->key);
+ if (gnutls->priv->key)
+ gnutls_x509_privkey_deinit (gnutls->priv->key);
if (gnutls->priv->issuer)
g_object_unref (gnutls->priv->issuer);
g_return_if_fail (gnutls->priv->have_key == FALSE);
data.data = bytes->data;
data.size = bytes->len;
+ if (!gnutls->priv->key)
+ gnutls_x509_privkey_init (&gnutls->priv->key);
status = gnutls_x509_privkey_import (gnutls->priv->key, &data,
GNUTLS_X509_FMT_DER);
+ if (status != 0)
+ {
+ int pkcs8_status =
+ gnutls_x509_privkey_import_pkcs8 (gnutls->priv->key, &data,
+ GNUTLS_X509_FMT_DER, NULL,
+ GNUTLS_PKCS_PLAIN);
+ if (pkcs8_status == 0)
+ status = 0;
+ }
if (status == 0)
gnutls->priv->have_key = TRUE;
else if (!gnutls->priv->construct_error)
g_return_if_fail (gnutls->priv->have_key == FALSE);
data.data = (void *)string;
data.size = strlen (string);
+ if (!gnutls->priv->key)
+ gnutls_x509_privkey_init (&gnutls->priv->key);
status = gnutls_x509_privkey_import (gnutls->priv->key, &data,
GNUTLS_X509_FMT_PEM);
+ if (status != 0)
+ {
+ int pkcs8_status =
+ gnutls_x509_privkey_import_pkcs8 (gnutls->priv->key, &data,
+ GNUTLS_X509_FMT_PEM, NULL,
+ GNUTLS_PKCS_PLAIN);
+ if (pkcs8_status == 0)
+ status = 0;
+ }
if (status == 0)
gnutls->priv->have_key = TRUE;
else if (!gnutls->priv->construct_error)
}
}
+#if ENABLE(TIZEN_TV_ADJUST_TIME)
+extern double soupTimeOffset;
+
+static time_t
+correct_time_func(time_t *t)
+{
+ return time(NULL) + (time_t)(soupTimeOffset / 1000);
+}
+#endif
+
static void
g_tls_certificate_gnutls_init (GTlsCertificateGnutls *gnutls)
{
GTlsCertificateGnutlsPrivate);
gnutls_x509_crt_init (&gnutls->priv->cert);
- gnutls_x509_privkey_init (&gnutls->priv->key);
+#if ENABLE(TIZEN_TV_ADJUST_TIME)
+ gnutls_global_set_time_function(correct_time_func);
+#endif
}
static gboolean
GTlsCertificate *trusted_ca)
{
GTlsCertificateGnutls *cert_gnutls;
- int status;
- guint gnutls_flags, num_certs, i, num_cas;
- gnutls_x509_crt_t *chain, ca;
+ guint num_certs, i;
+ gnutls_x509_crt_t *chain;
GTlsCertificateFlags gtls_flags;
+ time_t t, now;
+#if ENABLE(TIZEN_TV_DLOG)
+ char timebuf[256];
+#endif
+
cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (cert);
for (num_certs = 0; cert_gnutls; cert_gnutls = cert_gnutls->priv->issuer)
if (trusted_ca)
{
- cert_gnutls = G_TLS_CERTIFICATE_GNUTLS (trusted_ca);
- ca = cert_gnutls->priv->cert;
- num_cas = 1;
+ gnutls_x509_crt_t ca;
+ guint gnutls_flags;
+ int status;
+
+ ca = G_TLS_CERTIFICATE_GNUTLS (trusted_ca)->priv->cert;
+ status = gnutls_x509_crt_list_verify (chain, num_certs,
+ &ca, 1,
+ NULL, 0,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+ &gnutls_flags);
+ if (status != 0)
+ {
+ g_free (chain);
+ return G_TLS_CERTIFICATE_GENERIC_ERROR;
+ }
+
+ gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
}
else
+ gtls_flags = 0;
+
+ /* We have to check these ourselves since gnutls_x509_crt_list_verify
+ * won't bother if it gets an UNKNOWN_CA.
+ */
+ now = time (NULL);
+#if ENABLE(TIZEN_TV_ADJUST_TIME)
+ now = time (NULL) + (time_t)(soupTimeOffset / 1000);
+#endif
+ for (i = 0; i < num_certs; i++)
{
- ca = NULL;
- num_cas = 0;
- }
+ t = gnutls_x509_crt_get_activation_time (chain[i]);
+
+#if ENABLE(TIZEN_TV_DLOG)
+ ctime_r(&now, timebuf);
+ TIZEN_LOGI("[Certificate] TV borad time is: %s", timebuf);
+ if (t != (time_t) -1) {
+ ctime_r(&t, timebuf);
+ TIZEN_LOGI("[Certificate] CA activation time is: %s", timebuf);
+ }
+ else
+ TIZEN_LOGI("[Certificate] gnutls_x509_crt_get_activation_time ERROR");
+#endif
- status = gnutls_x509_crt_list_verify (chain, num_certs,
- &ca, num_cas,
- NULL, 0,
- GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
- &gnutls_flags);
- g_free (chain);
+ if (t == (time_t) -1 || t > now)
+ gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
- if (status != 0)
- return G_TLS_CERTIFICATE_GENERIC_ERROR;
+ t = gnutls_x509_crt_get_expiration_time (chain[i]);
- gtls_flags = g_tls_certificate_gnutls_convert_flags (gnutls_flags);
+#if ENABLE(TIZEN_TV_DLOG)
+ if (t != (time_t) -1) {
+ ctime_r(&t, timebuf);
+ TIZEN_LOGI("[Certificate] CA expiration time is: %s", timebuf);
+ }
+ else
+ TIZEN_LOGI("[Certificate] gnutls_x509_crt_get_expiration_time ERROR");
+#endif
+
+ if (t == (time_t) -1 || t < now)
+ gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
+ }
+
+ g_free (chain);
if (identity)
gtls_flags |= g_tls_certificate_gnutls_verify_identity (G_TLS_CERTIFICATE_GNUTLS (cert), identity);
}
static void
+g_tls_certificate_gnutls_real_copy (GTlsCertificateGnutls *gnutls,
+ const gchar *interaction_id,
+ gnutls_retr2_st *st)
+{
+ GTlsCertificateGnutls *chain;
+ gnutls_x509_crt_t cert;
+ gnutls_datum_t data;
+ guint num_certs = 0;
+ size_t size = 0;
+
+ /* We will do this loop twice. It's probably more efficient than
+ * re-allocating memory.
+ */
+ chain = gnutls;
+ while (chain != NULL)
+ {
+ num_certs++;
+ chain = chain->priv->issuer;
+ }
+
+ st->ncerts = 0;
+ st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t) * num_certs);
+
+/* Now do the actual copy of the whole chain. */
+ chain = gnutls;
+ while (chain != NULL)
+ {
+ gnutls_x509_crt_export (chain->priv->cert, GNUTLS_X509_FMT_DER,
+ NULL, &size);
+ data.data = g_malloc (size);
+ data.size = size;
+ gnutls_x509_crt_export (chain->priv->cert, GNUTLS_X509_FMT_DER,
+ data.data, &size);
+
+ gnutls_x509_crt_init (&cert);
+ gnutls_x509_crt_import (cert, &data, GNUTLS_X509_FMT_DER);
+ g_free (data.data);
+
+ st->cert.x509[st->ncerts] = cert;
+ st->ncerts++;
+
+ chain = chain->priv->issuer;
+ }
+
+ if (gnutls->priv->key != NULL)
+ {
+ gnutls_x509_privkey_init (&st->key.x509);
+ gnutls_x509_privkey_cpy (st->key.x509, gnutls->priv->key);
+ st->key_type = GNUTLS_PRIVKEY_X509;
+ }
+
+ st->deinit_all = TRUE;
+}
+
+static void
g_tls_certificate_gnutls_class_init (GTlsCertificateGnutlsClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
certificate_class->verify = g_tls_certificate_gnutls_verify;
+ klass->copy = g_tls_certificate_gnutls_real_copy;
+
g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate");
g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
}
GTlsCertificate *
-g_tls_certificate_gnutls_new (const gnutls_datum *datum,
- GTlsCertificate *issuer)
+g_tls_certificate_gnutls_new (const gnutls_datum_t *datum,
+ GTlsCertificate *issuer)
{
GTlsCertificateGnutls *gnutls;
gnutls = g_object_new (G_TYPE_TLS_CERTIFICATE_GNUTLS,
"issuer", issuer,
NULL);
- if (gnutls_x509_crt_import (gnutls->priv->cert, datum,
- GNUTLS_X509_FMT_DER) == 0)
- gnutls->priv->have_cert = TRUE;
+ g_tls_certificate_gnutls_set_data (gnutls, datum);
return G_TLS_CERTIFICATE (gnutls);
}
-const gnutls_x509_crt_t
-g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls)
+void
+g_tls_certificate_gnutls_set_data (GTlsCertificateGnutls *gnutls,
+ const gnutls_datum_t *datum)
{
- return gnutls->priv->cert;
+ g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
+ g_return_if_fail (!gnutls->priv->have_cert);
+
+ if (gnutls_x509_crt_import (gnutls->priv->cert, datum,
+ GNUTLS_X509_FMT_DER) == 0)
+ gnutls->priv->have_cert = TRUE;
}
-const gnutls_x509_privkey_t
-g_tls_certificate_gnutls_get_key (GTlsCertificateGnutls *gnutls)
+const gnutls_x509_crt_t
+g_tls_certificate_gnutls_get_cert (GTlsCertificateGnutls *gnutls)
{
- return gnutls->priv->key;
+ return gnutls->priv->cert;
}
-gnutls_x509_crt_t
-g_tls_certificate_gnutls_copy_cert (GTlsCertificateGnutls *gnutls)
+gboolean
+g_tls_certificate_gnutls_has_key (GTlsCertificateGnutls *gnutls)
{
- gnutls_x509_crt_t cert;
- gnutls_datum data;
- size_t size;
-
- size = 0;
- gnutls_x509_crt_export (gnutls->priv->cert, GNUTLS_X509_FMT_DER,
- NULL, &size);
- data.data = g_malloc (size);
- data.size = size;
- gnutls_x509_crt_export (gnutls->priv->cert, GNUTLS_X509_FMT_DER,
- data.data, &size);
-
- gnutls_x509_crt_init (&cert);
- gnutls_x509_crt_import (cert, &data, GNUTLS_X509_FMT_DER);
- g_free (data.data);
-
- return cert;
+ return gnutls->priv->have_key;
}
-gnutls_x509_privkey_t
-g_tls_certificate_gnutls_copy_key (GTlsCertificateGnutls *gnutls)
+void
+g_tls_certificate_gnutls_copy (GTlsCertificateGnutls *gnutls,
+ const gchar *interaction_id,
+ gnutls_retr2_st *st)
{
- gnutls_x509_privkey_t key;
-
- gnutls_x509_privkey_init (&key);
- gnutls_x509_privkey_cpy (key, gnutls->priv->key);
- return key;
+ g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
+ g_return_if_fail (st != NULL);
+ g_return_if_fail (G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy);
+ G_TLS_CERTIFICATE_GNUTLS_GET_CLASS (gnutls)->copy (gnutls, interaction_id, st);
}
static const struct {
/* FIXME: check sRVName and uniformResourceIdentifier
* subjectAltNames, if appropriate for @identity.
*/
+#if ENABLE(TIZEN_TV_DLOG)
+ TIZEN_LOGI("[Network] SSL HandShake - Bad Identity");
+#endif
return G_TLS_CERTIFICATE_BAD_IDENTITY;
}
+
+void
+g_tls_certificate_gnutls_set_issuer (GTlsCertificateGnutls *gnutls,
+ GTlsCertificateGnutls *issuer)
+{
+ g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
+ g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_GNUTLS (issuer));
+
+ if (issuer)
+ g_object_ref (issuer);
+ if (gnutls->priv->issuer)
+ g_object_unref (gnutls->priv->issuer);
+ gnutls->priv->issuer = issuer;
+ g_object_notify (G_OBJECT (gnutls), "issuer");
+}
+
+GBytes *
+g_tls_certificate_gnutls_get_bytes (GTlsCertificateGnutls *gnutls)
+{
+ GByteArray *array;
+
+ g_return_val_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls), NULL);
+
+ g_object_get (gnutls, "certificate", &array, NULL);
+ return g_byte_array_free_to_bytes (array);
+}
+
+static gnutls_x509_crt_t *
+convert_data_to_gnutls_certs (const gnutls_datum_t *certs,
+ guint num_certs,
+ gnutls_x509_crt_fmt_t format)
+{
+ gnutls_x509_crt_t *gnutls_certs;
+ guint i;
+
+ gnutls_certs = g_new (gnutls_x509_crt_t, num_certs);
+
+ for (i = 0; i < num_certs; i++)
+ {
+ if (gnutls_x509_crt_init (&gnutls_certs[i]) < 0)
+ {
+ i--;
+ goto error;
+ }
+ }
+
+ for (i = 0; i < num_certs; i++)
+ {
+ if (gnutls_x509_crt_import (gnutls_certs[i], &certs[i], format) < 0)
+ {
+ i = num_certs - 1;
+ goto error;
+ }
+ }
+
+ return gnutls_certs;
+
+error:
+ for (; i != G_MAXUINT; i--)
+ gnutls_x509_crt_deinit (gnutls_certs[i]);
+ g_free (gnutls_certs);
+ return NULL;
+}
+
+GTlsCertificateGnutls *
+g_tls_certificate_gnutls_build_chain (const gnutls_datum_t *certs,
+ guint num_certs,
+ gnutls_x509_crt_fmt_t format)
+{
+ GPtrArray *glib_certs;
+ gnutls_x509_crt_t *gnutls_certs;
+ GTlsCertificateGnutls *issuer;
+ GTlsCertificateGnutls *result;
+ guint i, j;
+
+ g_return_val_if_fail (certs, NULL);
+
+ gnutls_certs = convert_data_to_gnutls_certs (certs, num_certs, format);
+ if (!gnutls_certs)
+ return NULL;
+
+ glib_certs = g_ptr_array_new_full (num_certs, g_object_unref);
+ for (i = 0; i < num_certs; i++)
+ g_ptr_array_add (glib_certs, g_tls_certificate_gnutls_new (&certs[i], NULL));
+
+ /* Some servers send certs out of order, or will send duplicate
+ * certs, so we need to be careful when assigning the issuer of
+ * our new GTlsCertificateGnutls.
+ */
+ for (i = 0; i < num_certs; i++)
+ {
+ issuer = NULL;
+
+ if (i < num_certs - 1 &&
+ gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[i + 1]))
+ {
+ issuer = glib_certs->pdata[i + 1];
+ }
+ else
+ {
+ for (j = 0; j < num_certs; j++)
+ {
+ if (j != i &&
+ gnutls_x509_crt_check_issuer (gnutls_certs[i], gnutls_certs[j]))
+ {
+ issuer = glib_certs->pdata[j];
+ break;
+ }
+ }
+ }
+
+ if (issuer)
+ g_tls_certificate_gnutls_set_issuer (glib_certs->pdata[i], issuer);
+ }
+
+ result = g_object_ref (glib_certs->pdata[0]);
+ g_ptr_array_unref (glib_certs);
+
+ for (i = 0; i < num_certs; i++)
+ gnutls_x509_crt_deinit (gnutls_certs[i]);
+ g_free (gnutls_certs);
+
+ return result;
+}