#include "gtlscertificate-gnutls.h"
#include <glib/gi18n-lib.h>
+#include "TIZEN.h"
static void g_tls_certificate_gnutls_initable_iface_init (GInitableIface *iface);
PROP_0,
PROP_CERTIFICATE,
- PROP_CERTIFICATE_BYTES,
PROP_CERTIFICATE_PEM,
PROP_PRIVATE_KEY,
- PROP_PRIVATE_KEY_BYTES,
PROP_PRIVATE_KEY_PEM,
PROP_ISSUER
};
G_OBJECT_CLASS (g_tls_certificate_gnutls_parent_class)->finalize (object);
}
-static GByteArray *
-get_der_for_certificate (GTlsCertificateGnutls *self)
-{
- GByteArray *certificate;
- size_t size;
- int status;
-
- size = 0;
- status = gnutls_x509_crt_export (self->priv->cert,
- GNUTLS_X509_FMT_DER,
- NULL, &size);
- if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
- {
- certificate = NULL;
- }
- else
- {
- certificate = g_byte_array_sized_new (size);
- certificate->len = size;
- status = gnutls_x509_crt_export (self->priv->cert,
- GNUTLS_X509_FMT_DER,
- certificate->data, &size);
- if (status != 0)
- {
- g_byte_array_free (certificate, TRUE);
- certificate = NULL;
- }
- }
-
- return certificate;
-}
-
-static gchar *
-get_pem_for_certificate (GTlsCertificateGnutls *self)
-{
- char *certificate_pem;
- int status;
- size_t size;
-
- size = 0;
- status = gnutls_x509_crt_export (self->priv->cert,
- GNUTLS_X509_FMT_PEM,
- NULL, &size);
- if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
- {
- certificate_pem = NULL;
- }
- else
- {
- certificate_pem = g_malloc (size);
- status = gnutls_x509_crt_export (self->priv->cert,
- GNUTLS_X509_FMT_PEM,
- certificate_pem, &size);
- if (status != 0)
- {
- g_free (certificate_pem);
- certificate_pem = NULL;
- }
- }
-
- return certificate_pem;
-}
-
static void
g_tls_certificate_gnutls_get_property (GObject *object,
guint prop_id,
{
GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
GByteArray *certificate;
+ char *certificate_pem;
+ int status;
+ size_t size;
switch (prop_id)
{
case PROP_CERTIFICATE:
- g_value_take_boxed (value, get_der_for_certificate (gnutls));
- break;
-
- case PROP_CERTIFICATE_BYTES:
- certificate = get_der_for_certificate (gnutls);
- if (certificate == NULL)
- g_value_take_boxed (value, NULL);
+ size = 0;
+ status = gnutls_x509_crt_export (gnutls->priv->cert,
+ GNUTLS_X509_FMT_DER,
+ NULL, &size);
+ if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
+ certificate = NULL;
else
- g_value_take_boxed (value, g_byte_array_free_to_bytes (certificate));
+ {
+ certificate = g_byte_array_sized_new (size);
+ certificate->len = size;
+ status = gnutls_x509_crt_export (gnutls->priv->cert,
+ GNUTLS_X509_FMT_DER,
+ certificate->data, &size);
+ if (status != 0)
+ {
+ g_byte_array_free (certificate, TRUE);
+ certificate = NULL;
+ }
+ }
+ g_value_take_boxed (value, certificate);
break;
case PROP_CERTIFICATE_PEM:
- g_value_take_string (value, get_pem_for_certificate (gnutls));
+ size = 0;
+ status = gnutls_x509_crt_export (gnutls->priv->cert,
+ GNUTLS_X509_FMT_PEM,
+ NULL, &size);
+ if (status != GNUTLS_E_SHORT_MEMORY_BUFFER)
+ certificate_pem = NULL;
+ else
+ {
+ certificate_pem = g_malloc (size);
+ status = gnutls_x509_crt_export (gnutls->priv->cert,
+ GNUTLS_X509_FMT_PEM,
+ certificate_pem, &size);
+ if (status != 0)
+ {
+ g_free (certificate_pem);
+ certificate_pem = NULL;
+ }
+ }
+ g_value_take_string (value, certificate_pem);
break;
case PROP_ISSUER:
}
static void
-set_certificate_from_der (GTlsCertificateGnutls *self,
- const guchar *der,
- gsize len)
-{
- gnutls_datum_t data;
- int status;
-
- g_return_if_fail (self->priv->have_cert == FALSE);
- data.data = (guchar *)der;
- data.size = len;
- status = gnutls_x509_crt_import (self->priv->cert, &data,
- GNUTLS_X509_FMT_DER);
- if (status == 0)
- {
- self->priv->have_cert = TRUE;
- }
- else if (!self->priv->construct_error)
- {
- self->priv->construct_error =
- g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Could not parse DER certificate: %s"),
- gnutls_strerror (status));
- }
-}
-
-static void
-set_certificate_from_pem (GTlsCertificateGnutls *self,
- const gchar *string)
-{
- gnutls_datum_t data;
- int status;
-
- g_return_if_fail (self->priv->have_cert == FALSE);
- data.data = (guchar *)string;
- data.size = strlen (string);
- status = gnutls_x509_crt_import (self->priv->cert, &data,
- GNUTLS_X509_FMT_PEM);
- if (status == 0)
- {
- self->priv->have_cert = TRUE;
- }
- else if (!self->priv->construct_error)
- {
- self->priv->construct_error =
- g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Could not parse PEM certificate: %s"),
- gnutls_strerror (status));
- }
-}
-
-static void
-set_private_key_from_der (GTlsCertificateGnutls *self,
- const guchar *der,
- gsize len)
-{
- gnutls_datum_t data;
- int status;
-
- g_return_if_fail (self->priv->have_key == FALSE);
- data.data = (guchar *)der;
- data.size = len;
- if (!self->priv->key)
- gnutls_x509_privkey_init (&self->priv->key);
- status = gnutls_x509_privkey_import (self->priv->key, &data,
- GNUTLS_X509_FMT_DER);
- if (status != 0)
- {
- int pkcs8_status =
- gnutls_x509_privkey_import_pkcs8 (self->priv->key, &data,
- GNUTLS_X509_FMT_DER, NULL,
- GNUTLS_PKCS_PLAIN);
- if (pkcs8_status == 0)
- status = 0;
- }
- if (status == 0)
- {
- self->priv->have_key = TRUE;
- }
- else if (!self->priv->construct_error)
- {
- self->priv->construct_error =
- g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Could not parse DER private key: %s"),
- gnutls_strerror (status));
- }
-}
-
-static void
-set_private_key_from_pem (GTlsCertificateGnutls *self,
- const gchar *string)
-{
- gnutls_datum_t data;
- int status;
-
- g_return_if_fail (self->priv->have_key == FALSE);
- data.data = (guchar *)string;
- data.size = strlen (string);
- if (!self->priv->key)
- gnutls_x509_privkey_init (&self->priv->key);
- status = gnutls_x509_privkey_import (self->priv->key, &data,
- GNUTLS_X509_FMT_PEM);
- if (status != 0)
- {
- int pkcs8_status =
- gnutls_x509_privkey_import_pkcs8 (self->priv->key, &data,
- GNUTLS_X509_FMT_PEM, NULL,
- GNUTLS_PKCS_PLAIN);
- if (pkcs8_status == 0)
- status = 0;
- }
- if (status == 0)
- {
- self->priv->have_key = TRUE;
- }
- else if (!self->priv->construct_error)
- {
- self->priv->construct_error =
- g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
- _("Could not parse PEM private key: %s"),
- gnutls_strerror (status));
- }
-}
-
-static void
g_tls_certificate_gnutls_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GTlsCertificateGnutls *gnutls = G_TLS_CERTIFICATE_GNUTLS (object);
- GByteArray *byte_array;
+ GByteArray *bytes;
const char *string;
- GBytes *bytes;
+ gnutls_datum_t data;
+ int status;
switch (prop_id)
{
case PROP_CERTIFICATE:
- byte_array = g_value_get_boxed (value);
- if (byte_array)
- set_certificate_from_der (gnutls, byte_array->data, byte_array->len);
- break;
-
- case PROP_CERTIFICATE_BYTES:
bytes = g_value_get_boxed (value);
- if (bytes)
- {
- set_certificate_from_der (gnutls, g_bytes_get_data (bytes, NULL),
- g_bytes_get_size (bytes));
- }
+ if (!bytes)
+ break;
+ g_return_if_fail (gnutls->priv->have_cert == FALSE);
+ data.data = bytes->data;
+ data.size = bytes->len;
+ status = gnutls_x509_crt_import (gnutls->priv->cert, &data,
+ GNUTLS_X509_FMT_DER);
+ if (status == 0)
+ gnutls->priv->have_cert = TRUE;
+ else if (!gnutls->priv->construct_error)
+ {
+ gnutls->priv->construct_error =
+ g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Could not parse DER certificate: %s"),
+ gnutls_strerror (status));
+ }
+
break;
case PROP_CERTIFICATE_PEM:
string = g_value_get_string (value);
- if (string)
- set_certificate_from_pem (gnutls, string);
+ if (!string)
+ break;
+ g_return_if_fail (gnutls->priv->have_cert == FALSE);
+ data.data = (void *)string;
+ data.size = strlen (string);
+ status = gnutls_x509_crt_import (gnutls->priv->cert, &data,
+ GNUTLS_X509_FMT_PEM);
+ if (status == 0)
+ gnutls->priv->have_cert = TRUE;
+ else if (!gnutls->priv->construct_error)
+ {
+ gnutls->priv->construct_error =
+ g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Could not parse PEM certificate: %s"),
+ gnutls_strerror (status));
+ }
break;
case PROP_PRIVATE_KEY:
- byte_array = g_value_get_boxed (value);
- if (byte_array)
- set_private_key_from_der (gnutls, byte_array->data, byte_array->len);
- break;
-
- case PROP_PRIVATE_KEY_BYTES:
bytes = g_value_get_boxed (value);
- if (bytes)
- {
- set_private_key_from_der (gnutls, g_bytes_get_data (bytes, NULL),
- g_bytes_get_size (bytes));
- }
+ if (!bytes)
+ break;
+ 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)
+ {
+ gnutls->priv->construct_error =
+ g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Could not parse DER private key: %s"),
+ gnutls_strerror (status));
+ }
break;
case PROP_PRIVATE_KEY_PEM:
string = g_value_get_string (value);
- if (string)
- set_private_key_from_pem (gnutls, string);
+ if (!string)
+ break;
+ 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)
+ {
+ gnutls->priv->construct_error =
+ g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
+ _("Could not parse PEM private key: %s"),
+ gnutls_strerror (status));
+ }
break;
case PROP_ISSUER:
}
}
+#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);
+#if ENABLE(TIZEN_TV_ADJUST_TIME)
+ gnutls_global_set_time_function(correct_time_func);
+#endif
}
static gboolean
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)
* 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++)
{
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
+
if (t == (time_t) -1 || t > now)
gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
t = gnutls_x509_crt_get_expiration_time (chain[i]);
+
+#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;
}
const gchar *interaction_id,
gnutls_retr2_st *st)
{
+ GTlsCertificateGnutls *chain;
gnutls_x509_crt_t cert;
- gnutls_datum data;
+ gnutls_datum_t data;
+ guint num_certs = 0;
size_t 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);
+ /* 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);
- gnutls_x509_crt_init (&cert);
- gnutls_x509_crt_import (cert, &data, GNUTLS_X509_FMT_DER);
- g_free (data.data);
+/* 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);
- st->ncerts = 1;
- st->cert.x509 = gnutls_malloc (sizeof (gnutls_x509_crt_t));
- st->cert.x509[0] = cert;
+ 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)
{
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_BYTES, "certificate-bytes");
g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
- g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_BYTES, "private-key-bytes");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
}
}
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;
void
g_tls_certificate_gnutls_set_data (GTlsCertificateGnutls *gnutls,
- const gnutls_datum *datum)
+ const gnutls_datum_t *datum)
{
g_return_if_fail (G_IS_TLS_CERTIFICATE_GNUTLS (gnutls));
g_return_if_fail (!gnutls->priv->have_cert);
/* 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;
}
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;
+}