+static GSList *
+parse_and_create_certificate_list (const gchar *data,
+ gsize data_len,
+ GError **error)
+{
+ GSList *first_pem_list = NULL, *pem_list = NULL;
+ gchar *first_pem;
+ const gchar *p, *end;
+
+ p = data;
+ end = p + data_len;
+
+ /* Make sure we can load, at least, one certificate. */
+ first_pem = parse_next_pem_certificate (&p, end, TRUE, error);
+ if (!first_pem)
+ return NULL;
+
+ /* Create a list with a single element. If we load more certificates
+ * below, we will concatenate the two lists at the end. */
+ first_pem_list = g_slist_prepend (first_pem_list, first_pem);
+
+ /* If we read one certificate successfully, let's see if we can read
+ * some more. If not, we will simply return a list with the first one.
+ */
+ while (p && *p)
+ {
+ gchar *cert_pem;
+
+ cert_pem = parse_next_pem_certificate (&p, end, FALSE, NULL);
+ if (!cert_pem)
+ {
+ g_slist_free_full (pem_list, g_free);
+ return first_pem_list;
+ }
+
+ pem_list = g_slist_prepend (pem_list, cert_pem);
+ }
+
+ pem_list = g_slist_concat (pem_list, first_pem_list);
+
+ return pem_list;
+}
+
+static GTlsCertificate *
+create_certificate_chain_from_list (GSList *pem_list,
+ const gchar *key_pem)
+{
+ GTlsCertificate *cert = NULL, *issuer = NULL, *root = NULL;
+ GTlsCertificateFlags flags;
+ GSList *pem;
+
+ pem = pem_list;
+ while (pem)
+ {
+ const gchar *key = NULL;
+
+ /* Private key belongs only to the first certificate. */
+ if (!pem->next)
+ key = key_pem;
+
+ /* We assume that the whole file is a certificate chain, so we use
+ * each certificate as the issuer of the next one (list is in
+ * reverse order).
+ */
+ issuer = cert;
+ cert = g_tls_certificate_new_internal (pem->data, key, issuer, NULL);
+ if (issuer)
+ g_object_unref (issuer);
+
+ if (!cert)
+ return NULL;
+
+ /* root will point to the last certificate in the file. */
+ if (!root)
+ root = cert;
+
+ pem = g_slist_next (pem);
+ }
+
+ /* Verify that the certificates form a chain. (We don't care at this
+ * point if there are other problems with it.)
+ */
+ flags = g_tls_certificate_verify (cert, NULL, root);
+ if (flags & G_TLS_CERTIFICATE_UNKNOWN_CA)
+ {
+ /* It wasn't a chain, it's just a bunch of unrelated certs. */
+ g_clear_object (&cert);
+ }
+
+ return cert;
+}
+
+static GTlsCertificate *
+parse_and_create_certificate (const gchar *data,
+ gsize data_len,
+ const gchar *key_pem,
+ GError **error)
+
+{
+ GSList *pem_list;
+ GTlsCertificate *cert;
+
+ pem_list = parse_and_create_certificate_list (data, data_len, error);
+ if (!pem_list)
+ return NULL;
+
+ /* We don't pass the error here because, if it fails, we still want to
+ * load and return the first certificate.
+ */
+ cert = create_certificate_chain_from_list (pem_list, key_pem);
+ if (!cert)
+ {
+ GSList *last = NULL;
+
+ /* Get the first certificate (which is the last one as the list is
+ * in reverse order).
+ */
+ last = g_slist_last (pem_list);
+
+ cert = g_tls_certificate_new_internal (last->data, key_pem, NULL, error);
+ }
+
+ g_slist_free_full (pem_list, g_free);
+
+ return cert;
+}
+