+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/*
* gtlscertificate-openssl.c
*
#include "openssl-include.h"
#include "gtlscertificate-openssl.h"
-#include "openssl-util.h"
#include <glib/gi18n-lib.h>
-typedef struct _GTlsCertificateOpensslPrivate
+struct _GTlsCertificateOpenssl
{
+ GTlsCertificate parent_instance;
+
X509 *cert;
EVP_PKEY *key;
guint have_cert : 1;
guint have_key : 1;
-} GTlsCertificateOpensslPrivate;
+};
enum
{
PROP_CERTIFICATE_PEM,
PROP_PRIVATE_KEY,
PROP_PRIVATE_KEY_PEM,
- PROP_ISSUER
+ PROP_ISSUER,
+ PROP_NOT_VALID_BEFORE,
+ PROP_NOT_VALID_AFTER,
+ PROP_SUBJECT_NAME,
+ PROP_ISSUER_NAME,
+ PROP_DNS_NAMES,
+ PROP_IP_ADDRESSES,
};
static void g_tls_certificate_openssl_initable_iface_init (GInitableIface *iface);
G_DEFINE_TYPE_WITH_CODE (GTlsCertificateOpenssl, g_tls_certificate_openssl, G_TYPE_TLS_CERTIFICATE,
- G_ADD_PRIVATE (GTlsCertificateOpenssl)
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_tls_certificate_openssl_initable_iface_init))
g_tls_certificate_openssl_finalize (GObject *object)
{
GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
- GTlsCertificateOpensslPrivate *priv;
-
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
- if (priv->cert)
- X509_free (priv->cert);
- if (priv->key)
- EVP_PKEY_free (priv->key);
+ if (openssl->cert)
+ X509_free (openssl->cert);
+ if (openssl->key)
+ EVP_PKEY_free (openssl->key);
- g_clear_object (&priv->issuer);
+ g_clear_object (&openssl->issuer);
- g_clear_error (&priv->construct_error);
+ g_clear_error (&openssl->construct_error);
G_OBJECT_CLASS (g_tls_certificate_openssl_parent_class)->finalize (object);
}
+static GPtrArray *
+get_subject_alt_names (GTlsCertificateOpenssl *cert,
+ guint type)
+{
+ GPtrArray *data = NULL;
+ STACK_OF (GENERAL_NAME) *sans;
+ const guint8 *san = NULL;
+ size_t san_size;
+ guint alt_occurrences;
+ guint i;
+
+ if (type == GEN_IPADD)
+ data = g_ptr_array_new_with_free_func (g_object_unref);
+ else
+ data = g_ptr_array_new_with_free_func ((GDestroyNotify)g_bytes_unref);
+
+ sans = X509_get_ext_d2i (cert->cert, NID_subject_alt_name, NULL, NULL);
+ if (sans)
+ {
+ alt_occurrences = sk_GENERAL_NAME_num (sans);
+ for (i = 0; i < alt_occurrences; i++)
+ {
+ const GENERAL_NAME *value = sk_GENERAL_NAME_value (sans, i);
+ if (value->type != type)
+ continue;
+
+ if (type == GEN_IPADD)
+ {
+ g_assert (value->type == GEN_IPADD);
+ san = ASN1_STRING_get0_data (value->d.ip);
+ san_size = ASN1_STRING_length (value->d.ip);
+ if (san_size == 4)
+ g_ptr_array_add (data, g_inet_address_new_from_bytes (san, G_SOCKET_FAMILY_IPV4));
+ else if (san_size == 16)
+ g_ptr_array_add (data, g_inet_address_new_from_bytes (san, G_SOCKET_FAMILY_IPV6));
+ }
+ else
+ {
+ g_assert (value->type == GEN_DNS);
+ san = ASN1_STRING_get0_data (value->d.ia5);
+ san_size = ASN1_STRING_length (value->d.ia5);
+ g_ptr_array_add (data, g_bytes_new (san, san_size));
+ }
+ }
+
+ for (i = 0; i < alt_occurrences; i++)
+ GENERAL_NAME_free (sk_GENERAL_NAME_value (sans, i));
+ sk_GENERAL_NAME_free (sans);
+ }
+
+ return data;
+}
+
+static void
+export_privkey_to_der (GTlsCertificateOpenssl *openssl,
+ guint8 **output_data,
+ long *output_size)
+{
+ PKCS8_PRIV_KEY_INFO *pkcs8;
+ BIO *bio = NULL;
+ const guint8 *data;
+
+ if (!openssl->key)
+ goto err;
+
+ pkcs8 = EVP_PKEY2PKCS8 (openssl->key);
+ if (!pkcs8)
+ goto err;
+
+ bio = BIO_new (BIO_s_mem ());
+ if (i2d_PKCS8_PRIV_KEY_INFO_bio (bio, pkcs8) == 0)
+ goto err;
+
+ *output_size = BIO_get_mem_data (bio, (char **)&data);
+ if (*output_size <= 0)
+ goto err;
+
+ *output_data = g_malloc (*output_size);
+ memcpy (*output_data, data, *output_size);
+ goto out;
+
+err:
+ *output_data = NULL;
+ *output_size = 0;
+out:
+ if (bio)
+ BIO_free_all (bio);
+ if (pkcs8)
+ PKCS8_PRIV_KEY_INFO_free (pkcs8);
+}
+
+static char *
+export_privkey_to_pem (GTlsCertificateOpenssl *openssl)
+{
+ int ret;
+ BIO *bio = NULL;
+ const char *data = NULL;
+ char *result = NULL;
+
+ if (!openssl->key)
+ return NULL;
+
+ bio = BIO_new (BIO_s_mem ());
+ ret = PEM_write_bio_PKCS8PrivateKey (bio, openssl->key, NULL, NULL, 0, NULL, NULL);
+ if (ret == 0)
+ goto out;
+
+ ret = BIO_write (bio, "\0", 1);
+ if (ret != 1)
+ goto out;
+
+ BIO_get_mem_data (bio, (char **)&data);
+ result = g_strdup (data);
+
+out:
+ BIO_free_all (bio);
+ return result;
+}
+
static void
g_tls_certificate_openssl_get_property (GObject *object,
guint prop_id,
GParamSpec *pspec)
{
GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
- GTlsCertificateOpensslPrivate *priv;
GByteArray *certificate;
guint8 *data;
BIO *bio;
+ GByteArray *byte_array;
char *certificate_pem;
- int size;
+ long size;
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
+ const ASN1_TIME *time_asn1;
+ struct tm time_tm;
+ GDateTime *time;
+ GTimeZone *tz;
+ X509_NAME *name;
+ const char *name_string;
switch (prop_id)
{
case PROP_CERTIFICATE:
/* NOTE: we do the two calls to avoid openssl allocating the buffer for us */
- size = i2d_X509 (priv->cert, NULL);
+ size = i2d_X509 (openssl->cert, NULL);
if (size < 0)
certificate = NULL;
else
certificate = g_byte_array_sized_new (size);
certificate->len = size;
data = certificate->data;
- size = i2d_X509 (priv->cert, &data);
+ size = i2d_X509 (openssl->cert, &data);
if (size < 0)
{
g_byte_array_free (certificate, TRUE);
case PROP_CERTIFICATE_PEM:
bio = BIO_new (BIO_s_mem ());
- if (!PEM_write_bio_X509 (bio, priv->cert) || !BIO_write (bio, "\0", 1))
+ if (!PEM_write_bio_X509 (bio, openssl->cert) || !BIO_write (bio, "\0", 1))
certificate_pem = NULL;
else
{
}
break;
+ case PROP_PRIVATE_KEY:
+ export_privkey_to_der (openssl, &data, &size);
+ if (size > 0 && (gint64)size <= G_MAXUINT)
+ {
+ byte_array = g_byte_array_new_take (data, size);
+ g_value_take_boxed (value, byte_array);
+ }
+ break;
+
+ case PROP_PRIVATE_KEY_PEM:
+ g_value_take_string (value, export_privkey_to_pem (openssl));
+ break;
+
case PROP_ISSUER:
- g_value_set_object (value, priv->issuer);
+ g_value_set_object (value, openssl->issuer);
+ break;
+
+ case PROP_NOT_VALID_BEFORE:
+ time_asn1 = X509_get0_notBefore (openssl->cert);
+ ASN1_TIME_to_tm (time_asn1, &time_tm);
+ tz = g_time_zone_new_utc ();
+ time = g_date_time_new (tz, time_tm.tm_year + 1900, time_tm.tm_mon + 1, time_tm.tm_mday, time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec);
+ g_value_take_boxed (value, time);
+ g_time_zone_unref (tz);
+ break;
+
+ case PROP_NOT_VALID_AFTER:
+ time_asn1 = X509_get0_notAfter (openssl->cert);
+ ASN1_TIME_to_tm (time_asn1, &time_tm);
+ tz = g_time_zone_new_utc ();
+ time = g_date_time_new (tz, time_tm.tm_year + 1900, time_tm.tm_mon + 1, time_tm.tm_mday, time_tm.tm_hour, time_tm.tm_min, time_tm.tm_sec);
+ g_value_take_boxed (value, time);
+ g_time_zone_unref (tz);
+ break;
+
+ case PROP_SUBJECT_NAME:
+ bio = BIO_new (BIO_s_mem ());
+ name = X509_get_subject_name (openssl->cert);
+ X509_NAME_print_ex (bio, name, 0, XN_FLAG_SEP_COMMA_PLUS);
+ BIO_write (bio, "\0", 1);
+ BIO_get_mem_data (bio, (char **)&name_string);
+ g_value_set_string (value, name_string);
+ BIO_free_all (bio);
+ break;
+
+ case PROP_ISSUER_NAME:
+ bio = BIO_new (BIO_s_mem ());
+ name = X509_get_issuer_name (openssl->cert);
+ X509_NAME_print_ex (bio, name, 0, XN_FLAG_SEP_COMMA_PLUS);
+ BIO_write (bio, "\0", 1);
+ BIO_get_mem_data (bio, &name_string);
+ g_value_set_string (value, name_string);
+ BIO_free_all (bio);
+ break;
+
+ case PROP_DNS_NAMES:
+ g_value_take_boxed (value, get_subject_alt_names (openssl, GEN_DNS));
+ break;
+
+ case PROP_IP_ADDRESSES:
+ g_value_take_boxed (value, get_subject_alt_names (openssl, GEN_IPADD));
break;
default:
GParamSpec *pspec)
{
GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (object);
- GTlsCertificateOpensslPrivate *priv;
GByteArray *bytes;
guint8 *data;
BIO *bio;
const char *string;
-
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
+ char error_buffer[256];
switch (prop_id)
{
bytes = g_value_get_boxed (value);
if (!bytes)
break;
- g_return_if_fail (priv->have_cert == FALSE);
+ g_return_if_fail (openssl->have_cert == FALSE);
/* see that we cannot use bytes->data directly since it will move the pointer */
data = bytes->data;
- priv->cert = d2i_X509 (NULL, (const unsigned char **)&data, bytes->len);
- if (priv->cert != NULL)
- priv->have_cert = TRUE;
- else if (!priv->construct_error)
+ openssl->cert = d2i_X509 (NULL, (const unsigned char **)&data, bytes->len);
+ if (openssl->cert)
+ openssl->have_cert = TRUE;
+ else if (!openssl->construct_error)
{
- priv->construct_error =
+ ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
+ openssl->construct_error =
g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Could not parse DER certificate: %s"),
- ERR_error_string (ERR_get_error (), NULL));
+ error_buffer);
}
break;
string = g_value_get_string (value);
if (!string)
break;
- g_return_if_fail (priv->have_cert == FALSE);
+ g_return_if_fail (openssl->have_cert == FALSE);
bio = BIO_new_mem_buf ((gpointer)string, -1);
- priv->cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
+ openssl->cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
BIO_free (bio);
- if (priv->cert != NULL)
- priv->have_cert = TRUE;
- else if (!priv->construct_error)
+ if (openssl->cert)
+ openssl->have_cert = TRUE;
+ else if (!openssl->construct_error)
{
- priv->construct_error =
+ ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
+ openssl->construct_error =
g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Could not parse PEM certificate: %s"),
- ERR_error_string (ERR_get_error (), NULL));
+ error_buffer);
}
break;
bytes = g_value_get_boxed (value);
if (!bytes)
break;
- g_return_if_fail (priv->have_key == FALSE);
+ g_return_if_fail (openssl->have_key == FALSE);
bio = BIO_new_mem_buf (bytes->data, bytes->len);
- priv->key = d2i_PrivateKey_bio (bio, NULL);
+ openssl->key = d2i_PrivateKey_bio (bio, NULL);
BIO_free (bio);
- if (priv->key != NULL)
- priv->have_key = TRUE;
- else if (!priv->construct_error)
+ if (openssl->key)
+ openssl->have_key = TRUE;
+ else if (!openssl->construct_error)
{
- priv->construct_error =
+ ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
+ openssl->construct_error =
g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Could not parse DER private key: %s"),
- ERR_error_string (ERR_get_error (), NULL));
+ error_buffer);
}
break;
string = g_value_get_string (value);
if (!string)
break;
- g_return_if_fail (priv->have_key == FALSE);
+ g_return_if_fail (openssl->have_key == FALSE);
bio = BIO_new_mem_buf ((gpointer)string, -1);
- priv->key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
+ openssl->key = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
BIO_free (bio);
- if (priv->key != NULL)
- priv->have_key = TRUE;
- else if (!priv->construct_error)
+ if (openssl->key)
+ openssl->have_key = TRUE;
+ else if (!openssl->construct_error)
{
- priv->construct_error =
+ ERR_error_string_n (ERR_get_error (), error_buffer, sizeof (error_buffer));
+ openssl->construct_error =
g_error_new (G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("Could not parse PEM private key: %s"),
- ERR_error_string (ERR_get_error (), NULL));
+ error_buffer);
}
break;
case PROP_ISSUER:
- priv->issuer = g_value_dup_object (value);
+ openssl->issuer = g_value_dup_object (value);
break;
default:
GError **error)
{
GTlsCertificateOpenssl *openssl = G_TLS_CERTIFICATE_OPENSSL (initable);
- GTlsCertificateOpensslPrivate *priv;
-
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
- if (priv->construct_error)
+ if (openssl->construct_error)
{
- g_propagate_error (error, priv->construct_error);
- priv->construct_error = NULL;
+ g_propagate_error (error, openssl->construct_error);
+ openssl->construct_error = NULL;
return FALSE;
}
- else if (!priv->have_cert)
+ else if (!openssl->have_cert)
{
g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE,
_("No certificate data provided"));
GTlsCertificate *trusted_ca)
{
GTlsCertificateOpenssl *cert_openssl;
- GTlsCertificateOpensslPrivate *priv;
GTlsCertificateFlags gtls_flags;
X509 *x;
STACK_OF(X509) *untrusted;
- gint i;
cert_openssl = G_TLS_CERTIFICATE_OPENSSL (cert);
- priv = g_tls_certificate_openssl_get_instance_private (cert_openssl);
- x = priv->cert;
+ x = cert_openssl->cert;
untrusted = sk_X509_new_null ();
- for (; cert_openssl; cert_openssl = priv->issuer)
- {
- priv = g_tls_certificate_openssl_get_instance_private (cert_openssl);
- sk_X509_push (untrusted, priv->cert);
- }
+ for (; cert_openssl; cert_openssl = cert_openssl->issuer)
+ sk_X509_push (untrusted, cert_openssl->cert);
gtls_flags = 0;
trusted = sk_X509_new_null ();
cert_openssl = G_TLS_CERTIFICATE_OPENSSL (trusted_ca);
- for (; cert_openssl; cert_openssl = priv->issuer)
- {
- priv = g_tls_certificate_openssl_get_instance_private (cert_openssl);
- sk_X509_push (trusted, priv->cert);
- }
+ for (; cert_openssl; cert_openssl = cert_openssl->issuer)
+ sk_X509_push (trusted, cert_openssl->cert);
X509_STORE_CTX_trusted_stack (csc, trusted);
if (X509_verify_cert (csc) <= 0)
X509_STORE_free (store);
}
- /* We have to check these ourselves since openssl
- * does not give us flags and UNKNOWN_CA will take priority.
- */
- for (i = 0; i < sk_X509_num (untrusted); i++)
- {
- X509 *c = sk_X509_value (untrusted, i);
- ASN1_TIME *not_before = X509_get_notBefore (c);
- ASN1_TIME *not_after = X509_get_notAfter (c);
-
- if (X509_cmp_current_time (not_before) > 0)
- gtls_flags |= G_TLS_CERTIFICATE_NOT_ACTIVATED;
-
- if (X509_cmp_current_time (not_after) < 0)
- gtls_flags |= G_TLS_CERTIFICATE_EXPIRED;
- }
-
sk_X509_free (untrusted);
if (identity)
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key");
g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem");
g_object_class_override_property (gobject_class, PROP_ISSUER, "issuer");
+ g_object_class_override_property (gobject_class, PROP_NOT_VALID_BEFORE, "not-valid-before");
+ g_object_class_override_property (gobject_class, PROP_NOT_VALID_AFTER, "not-valid-after");
+ g_object_class_override_property (gobject_class, PROP_SUBJECT_NAME, "subject-name");
+ g_object_class_override_property (gobject_class, PROP_ISSUER_NAME, "issuer-name");
+ g_object_class_override_property (gobject_class, PROP_DNS_NAMES, "dns-names");
+ g_object_class_override_property (gobject_class, PROP_IP_ADDRESSES, "ip-addresses");
}
static void
GTlsCertificate *issuer)
{
GTlsCertificateOpenssl *openssl;
- GTlsCertificateOpensslPrivate *priv;
openssl = g_object_new (G_TYPE_TLS_CERTIFICATE_OPENSSL,
"issuer", issuer,
NULL);
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
- priv->cert = X509_dup (x);
- priv->have_cert = TRUE;
+ openssl->cert = X509_dup (x);
+ openssl->have_cert = TRUE;
return G_TLS_CERTIFICATE (openssl);
}
g_tls_certificate_openssl_set_data (GTlsCertificateOpenssl *openssl,
GBytes *bytes)
{
- GTlsCertificateOpensslPrivate *priv;
const unsigned char *data;
g_return_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl));
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
- g_return_if_fail (!priv->have_cert);
+ g_return_if_fail (!openssl->have_cert);
data = (const unsigned char *)g_bytes_get_data (bytes, NULL);
- priv->cert = d2i_X509 (NULL, &data, g_bytes_get_size (bytes));
+ openssl->cert = d2i_X509 (NULL, &data, g_bytes_get_size (bytes));
- if (priv->cert != NULL)
- priv->have_cert = TRUE;
+ if (openssl->cert)
+ openssl->have_cert = TRUE;
}
GBytes *
X509 *
g_tls_certificate_openssl_get_cert (GTlsCertificateOpenssl *openssl)
{
- GTlsCertificateOpensslPrivate *priv;
-
g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), FALSE);
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
- return priv->cert;
+ return openssl->cert;
}
EVP_PKEY *
g_tls_certificate_openssl_get_key (GTlsCertificateOpenssl *openssl)
{
- GTlsCertificateOpensslPrivate *priv;
-
g_return_val_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl), FALSE);
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
- return priv->key;
+ return openssl->key;
}
void
g_tls_certificate_openssl_set_issuer (GTlsCertificateOpenssl *openssl,
GTlsCertificateOpenssl *issuer)
{
- GTlsCertificateOpensslPrivate *priv;
-
g_return_if_fail (G_IS_TLS_CERTIFICATE_OPENSSL (openssl));
g_return_if_fail (!issuer || G_IS_TLS_CERTIFICATE_OPENSSL (issuer));
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
- if (g_set_object (&priv->issuer, issuer))
+ if (g_set_object (&openssl->issuer, issuer))
g_object_notify (G_OBJECT (openssl), "issuer");
}
verify_identity_hostname (GTlsCertificateOpenssl *openssl,
GSocketConnectable *identity)
{
- GTlsCertificateOpensslPrivate *priv;
const char *hostname;
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
if (G_IS_NETWORK_ADDRESS (identity))
hostname = g_network_address_get_hostname (G_NETWORK_ADDRESS (identity));
else if (G_IS_NETWORK_SERVICE (identity))
else
return FALSE;
- return g_tls_X509_check_host (priv->cert, hostname, strlen (hostname), 0, NULL) == 1;
+ return X509_check_host (openssl->cert, hostname, strlen (hostname), 0, NULL) == 1;
}
static gboolean
verify_identity_ip (GTlsCertificateOpenssl *openssl,
GSocketConnectable *identity)
{
- GTlsCertificateOpensslPrivate *priv;
GInetAddress *addr;
gsize addr_size;
const guint8 *addr_bytes;
gboolean ret;
- priv = g_tls_certificate_openssl_get_instance_private (openssl);
-
if (G_IS_INET_SOCKET_ADDRESS (identity))
addr = g_object_ref (g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (identity)));
else {
addr_bytes = g_inet_address_to_bytes (addr);
addr_size = g_inet_address_get_native_size (addr);
- ret = g_tls_X509_check_ip (priv->cert, addr_bytes, addr_size, 0) == 1;
+ ret = X509_check_ip (openssl->cert, addr_bytes, addr_size, 0) == 1;
g_object_unref (addr);
return ret;
* subjectAltNames, if appropriate for @identity.
*/
+ TIZEN_LOGE("SSL HandShake - Bad Identity");
return G_TLS_CERTIFICATE_BAD_IDENTITY;
}
break;
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+#ifdef TIZEN_EXT
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+#endif
gtls_flags = G_TLS_CERTIFICATE_UNKNOWN_CA;
break;
default:
- g_message ("certificate error: %s", X509_verify_cert_error_string (openssl_error));
gtls_flags = G_TLS_CERTIFICATE_GENERIC_ERROR;
}
GTlsCertificateOpenssl *result;
guint i, j;
- g_return_val_if_fail (x != NULL, NULL);
+ g_return_val_if_fail (x, NULL);
g_return_val_if_fail (chain, NULL);
glib_certs = g_ptr_array_new_full (sk_X509_num (chain), g_object_unref);