|
Packit |
b00eeb |
/*
|
|
Packit |
b00eeb |
* gnome-keyring
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Copyright (C) 2010 Collabora Ltd
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
b00eeb |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit |
b00eeb |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
b00eeb |
* the License, or (at your option) any later version.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
b00eeb |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
b00eeb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
b00eeb |
* Lesser General Public License for more details.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
b00eeb |
* License along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Author: Stef Walter <stefw@collabora.co.uk>
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
#include "config.h"
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
#include "gcr-certificate-chain.h"
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
#include "gcr-certificate.h"
|
|
Packit |
b00eeb |
#include "gcr-pkcs11-certificate.h"
|
|
Packit |
b00eeb |
#include "gcr-simple-certificate.h"
|
|
Packit |
b00eeb |
#include "gcr-trust.h"
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
#include "gcr/gcr-enum-types-base.h"
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
#include "egg/egg-error.h"
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* SECTION:gcr-certificate-chain
|
|
Packit |
b00eeb |
* @title: GcrCertificateChain
|
|
Packit |
b00eeb |
* @short_description: A certificate chain
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* #GcrCertificateChain represents a chain of certificates, normally used to
|
|
Packit |
b00eeb |
* validate the trust in a certificate. An X.509 certificate chain has one
|
|
Packit |
b00eeb |
* endpoint certificate (the one for which trust is being verified) and then
|
|
Packit |
b00eeb |
* in turn the certificate that issued each previous certificate in the chain.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* This functionality is for building of certificate chains not for validating
|
|
Packit |
b00eeb |
* them. Use your favorite crypto library to validate trust in a certificate
|
|
Packit |
b00eeb |
* chain once its built.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The order of certificates in the chain should be first the endpoint
|
|
Packit |
b00eeb |
* certificates and then the signing certificates.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Create a new certificate chain with gcr_certificate_chain_new() and then
|
|
Packit |
b00eeb |
* add the certificates with gcr_certificate_chain_add().
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* You can then use gcr_certificate_chain_build() to build the remainder of
|
|
Packit |
b00eeb |
* the chain. This will lookup missing certificates in PKCS\#11 modules and
|
|
Packit |
b00eeb |
* also check that each certificate in the chain is the signer of the previous
|
|
Packit |
b00eeb |
* one. If a trust anchor, pinned certificate, or self-signed certificate is
|
|
Packit |
b00eeb |
* found, then the chain is considered built. Any extra certificates are
|
|
Packit |
b00eeb |
* removed from the chain.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Once the certificate chain has been built, you can access its status
|
|
Packit |
b00eeb |
* through gcr_certificate_chain_get_status(). The status signifies whether
|
|
Packit |
b00eeb |
* the chain is anchored on a trust root, self-signed, incomplete etc. See
|
|
Packit |
b00eeb |
* #GcrCertificateChainStatus for information on the various statuses.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* It's important to understand that the building of a certificate chain is
|
|
Packit |
b00eeb |
* merely the first step towards verifying trust in a certificate.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GcrCertificateChain:
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* A chain of certificates.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GcrCertificateChainClass:
|
|
Packit |
b00eeb |
* @parent_class: The parent class
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The class for #GcrCertificateChain.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
enum {
|
|
Packit |
b00eeb |
PROP_0,
|
|
Packit |
b00eeb |
PROP_STATUS,
|
|
Packit |
b00eeb |
PROP_LENGTH,
|
|
Packit |
b00eeb |
};
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
struct _GcrCertificateChainPrivate {
|
|
Packit |
b00eeb |
GPtrArray *certificates;
|
|
Packit |
b00eeb |
GcrCertificateChainStatus status;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Used in build operation */
|
|
Packit |
b00eeb |
gchar *purpose;
|
|
Packit |
b00eeb |
gchar *peer;
|
|
Packit |
b00eeb |
guint flags;
|
|
Packit |
b00eeb |
};
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static GQuark Q_ORIGINAL_CERT = 0;
|
|
Packit |
b00eeb |
static GQuark Q_OPERATION_DATA = 0;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
G_DEFINE_TYPE (GcrCertificateChain, gcr_certificate_chain, G_TYPE_OBJECT);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* -----------------------------------------------------------------------------
|
|
Packit |
b00eeb |
* INTERNAL
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
free_chain_private (gpointer data)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv = data;
|
|
Packit |
b00eeb |
g_ptr_array_unref (pv->certificates);
|
|
Packit |
b00eeb |
g_free (pv->purpose);
|
|
Packit |
b00eeb |
g_free (pv->peer);
|
|
Packit |
b00eeb |
g_slice_free (GcrCertificateChainPrivate, pv);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static GcrCertificateChainPrivate*
|
|
Packit |
b00eeb |
new_chain_private (void)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv = g_slice_new0 (GcrCertificateChainPrivate);
|
|
Packit |
b00eeb |
pv->certificates = g_ptr_array_new_with_free_func (g_object_unref);
|
|
Packit |
b00eeb |
return pv;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static GcrCertificateChainPrivate*
|
|
Packit |
b00eeb |
prep_chain_private (GcrCertificateChainPrivate *orig, const gchar *purpose,
|
|
Packit |
b00eeb |
const gchar *peer, guint flags)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv;
|
|
Packit |
b00eeb |
GcrCertificate *certificate;
|
|
Packit |
b00eeb |
guint i;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_assert (orig);
|
|
Packit |
b00eeb |
g_assert (purpose);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv = new_chain_private ();
|
|
Packit |
b00eeb |
for (i = 0; i < orig->certificates->len; ++i) {
|
|
Packit |
b00eeb |
certificate = g_ptr_array_index (orig->certificates, i);
|
|
Packit |
b00eeb |
g_ptr_array_add (pv->certificates, g_object_ref (certificate));
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv->status = orig->status;
|
|
Packit |
b00eeb |
pv->purpose = g_strdup (purpose);
|
|
Packit |
b00eeb |
pv->peer = g_strdup (peer);
|
|
Packit |
b00eeb |
pv->flags = flags;
|
|
Packit |
b00eeb |
return pv;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static GcrCertificateChainPrivate*
|
|
Packit |
b00eeb |
prep_chain_private_thread_safe (GcrCertificateChainPrivate *orig, const gchar *purpose,
|
|
Packit |
b00eeb |
const gchar *peer, guint flags)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv;
|
|
Packit |
b00eeb |
GcrCertificate *certificate, *safe;
|
|
Packit |
b00eeb |
gconstpointer der;
|
|
Packit |
b00eeb |
gsize n_der;
|
|
Packit |
b00eeb |
guint i;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_assert (orig);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv = prep_chain_private (orig, purpose, peer, flags);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
for (i = 0; i < pv->certificates->len; ++i) {
|
|
Packit |
b00eeb |
certificate = g_ptr_array_index (pv->certificates, i);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* We regard these types as thread safe */
|
|
Packit |
b00eeb |
if (GCR_IS_SIMPLE_CERTIFICATE (certificate) ||
|
|
Packit |
b00eeb |
GCR_IS_PKCS11_CERTIFICATE (certificate)) {
|
|
Packit |
b00eeb |
safe = g_object_ref (certificate);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Otherwise copy the certificate data */
|
|
Packit |
b00eeb |
} else {
|
|
Packit |
b00eeb |
der = gcr_certificate_get_der_data (certificate, &n_der);
|
|
Packit |
b00eeb |
g_return_val_if_fail (der, NULL);
|
|
Packit |
b00eeb |
safe = gcr_simple_certificate_new (der, n_der);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_debug ("copying certificate so it's thread safe");
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Always set the original certificate onto the safe one */
|
|
Packit |
b00eeb |
g_object_set_qdata_full (G_OBJECT (safe), Q_ORIGINAL_CERT,
|
|
Packit |
b00eeb |
g_object_ref (certificate), g_object_unref);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_ptr_array_index (pv->certificates, i) = safe;
|
|
Packit |
b00eeb |
g_object_unref (certificate);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
return pv;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static GcrCertificateChainPrivate*
|
|
Packit |
b00eeb |
cleanup_chain_private (GcrCertificateChainPrivate *pv)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificate *certificate, *orig;
|
|
Packit |
b00eeb |
guint i;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
for (i = 0; i < pv->certificates->len; ++i) {
|
|
Packit |
b00eeb |
certificate = g_ptr_array_index (pv->certificates, i);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* If there's an original certificate set, then replace it back */
|
|
Packit |
b00eeb |
orig = g_object_get_qdata (G_OBJECT (certificate), Q_ORIGINAL_CERT);
|
|
Packit |
b00eeb |
if (orig != NULL) {
|
|
Packit |
b00eeb |
g_ptr_array_index (pv->certificates, i) = g_object_ref (orig);
|
|
Packit |
b00eeb |
g_object_unref (certificate);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
return pv;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static GcrCertificate *
|
|
Packit |
b00eeb |
pop_certificate (GPtrArray *certificates,
|
|
Packit |
b00eeb |
GcrCertificate *issued)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificate *certificate;
|
|
Packit |
b00eeb |
gint i;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
for (i = 0; i < certificates->len; i++) {
|
|
Packit |
b00eeb |
certificate = certificates->pdata[i];
|
|
Packit |
b00eeb |
if (!issued || gcr_certificate_is_issuer (issued, certificate)) {
|
|
Packit |
b00eeb |
g_object_ref (certificate);
|
|
Packit |
b00eeb |
g_ptr_array_remove_index_fast (certificates, i);
|
|
Packit |
b00eeb |
return certificate;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
return NULL;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static gboolean
|
|
Packit |
b00eeb |
perform_build_chain (GcrCertificateChainPrivate *pv, GCancellable *cancellable,
|
|
Packit |
b00eeb |
GError **rerror)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GError *error = NULL;
|
|
Packit |
b00eeb |
GcrCertificate *certificate;
|
|
Packit |
b00eeb |
GcrCertificate *issued;
|
|
Packit |
b00eeb |
GPtrArray *input;
|
|
Packit |
b00eeb |
gboolean lookups;
|
|
Packit |
b00eeb |
gboolean ret;
|
|
Packit |
b00eeb |
guint length;
|
|
Packit |
b00eeb |
gchar *subject;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_assert (pv);
|
|
Packit |
b00eeb |
g_assert (pv->certificates);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN;
|
|
Packit |
b00eeb |
lookups = !((pv->flags & GCR_CERTIFICATE_CHAIN_NO_LOOKUPS) == GCR_CERTIFICATE_CHAIN_NO_LOOKUPS);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* This chain is built */
|
|
Packit |
b00eeb |
if (!pv->certificates->len) {
|
|
Packit |
b00eeb |
g_debug ("empty certificate chain");
|
|
Packit |
b00eeb |
return TRUE;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
input = pv->certificates;
|
|
Packit |
b00eeb |
pv->certificates = g_ptr_array_new_with_free_func (g_object_unref);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* First check for pinned certificates */
|
|
Packit |
b00eeb |
certificate = pop_certificate (input, NULL);
|
|
Packit |
b00eeb |
g_ptr_array_add (pv->certificates, certificate);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
subject = gcr_certificate_get_subject_dn (certificate);
|
|
Packit |
b00eeb |
g_debug ("first certificate: %s", subject);
|
|
Packit |
b00eeb |
g_free (subject);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
if (lookups && pv->peer) {
|
|
Packit |
b00eeb |
ret = gcr_trust_is_certificate_pinned (certificate, pv->purpose,
|
|
Packit |
b00eeb |
pv->peer, cancellable, &error);
|
|
Packit |
b00eeb |
if (!ret && error) {
|
|
Packit |
b00eeb |
g_debug ("failed to lookup pinned certificate: %s",
|
|
Packit |
b00eeb |
egg_error_message (error));
|
|
Packit |
b00eeb |
g_propagate_error (rerror, error);
|
|
Packit |
b00eeb |
g_ptr_array_unref (input);
|
|
Packit |
b00eeb |
return FALSE;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/*
|
|
Packit |
b00eeb |
* This is a pinned certificate and the rest of the chain
|
|
Packit |
b00eeb |
* is irrelevant, so truncate chain and consider built.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
if (ret) {
|
|
Packit |
b00eeb |
g_debug ("found pinned certificate for peer '%s', truncating chain",
|
|
Packit |
b00eeb |
pv->peer);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_ptr_array_unref (input);
|
|
Packit |
b00eeb |
pv->status = GCR_CERTIFICATE_CHAIN_PINNED;
|
|
Packit |
b00eeb |
return TRUE;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* The first certificate is always unconditionally in the chain */
|
|
Packit |
b00eeb |
while (pv->status == GCR_CERTIFICATE_CHAIN_UNKNOWN) {
|
|
Packit |
b00eeb |
issued = certificate;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Stop the chain if previous was self-signed */
|
|
Packit |
b00eeb |
if (gcr_certificate_is_issuer (certificate, certificate)) {
|
|
Packit |
b00eeb |
g_debug ("found self-signed certificate");
|
|
Packit |
b00eeb |
pv->status = GCR_CERTIFICATE_CHAIN_SELFSIGNED;
|
|
Packit |
b00eeb |
break;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Get the next certificate */
|
|
Packit |
b00eeb |
certificate = pop_certificate (input, issued);
|
|
Packit |
b00eeb |
if (certificate) {
|
|
Packit |
b00eeb |
subject = gcr_certificate_get_subject_dn (certificate);
|
|
Packit |
b00eeb |
g_debug ("next certificate: %s", subject);
|
|
Packit |
b00eeb |
g_free (subject);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* No more in chain, try to lookup */
|
|
Packit |
b00eeb |
} else if (lookups) {
|
|
Packit |
b00eeb |
certificate = gcr_pkcs11_certificate_lookup_issuer (issued,
|
|
Packit |
b00eeb |
cancellable, &error);
|
|
Packit |
b00eeb |
if (error != NULL) {
|
|
Packit |
b00eeb |
g_debug ("failed to lookup issuer: %s", error->message);
|
|
Packit |
b00eeb |
g_propagate_error (rerror, error);
|
|
Packit |
b00eeb |
g_ptr_array_unref (input);
|
|
Packit |
b00eeb |
return FALSE;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
} else if (certificate) {
|
|
Packit |
b00eeb |
subject = gcr_certificate_get_subject_dn (certificate);
|
|
Packit |
b00eeb |
g_debug ("found issuer certificate: %s", subject);
|
|
Packit |
b00eeb |
g_free (subject);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
} else {
|
|
Packit |
b00eeb |
g_debug ("no issuer found");
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* No more in chain, and can't lookup */
|
|
Packit |
b00eeb |
} else {
|
|
Packit |
b00eeb |
g_debug ("no more certificates available, and no lookups");
|
|
Packit |
b00eeb |
certificate = NULL;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Stop the chain if nothing found */
|
|
Packit |
b00eeb |
if (certificate == NULL) {
|
|
Packit |
b00eeb |
g_debug ("chain is incomplete");
|
|
Packit |
b00eeb |
pv->status = GCR_CERTIFICATE_CHAIN_INCOMPLETE;
|
|
Packit |
b00eeb |
break;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_ptr_array_add (pv->certificates, certificate);
|
|
Packit |
b00eeb |
++length;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* See if this certificate is an anchor */
|
|
Packit |
b00eeb |
if (lookups) {
|
|
Packit |
b00eeb |
ret = gcr_trust_is_certificate_anchored (certificate, pv->purpose,
|
|
Packit |
b00eeb |
cancellable, &error);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
if (!ret && error) {
|
|
Packit |
b00eeb |
g_debug ("failed to lookup anchored certificate: %s",
|
|
Packit |
b00eeb |
egg_error_message (error));
|
|
Packit |
b00eeb |
g_propagate_error (rerror, error);
|
|
Packit |
b00eeb |
g_ptr_array_unref (input);
|
|
Packit |
b00eeb |
return FALSE;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* Stop the chain at the first anchor */
|
|
Packit |
b00eeb |
} else if (ret) {
|
|
Packit |
b00eeb |
g_debug ("found anchored certificate");
|
|
Packit |
b00eeb |
pv->status = GCR_CERTIFICATE_CHAIN_ANCHORED;
|
|
Packit |
b00eeb |
break;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* TODO: Need to check each certificate in the chain for distrusted */
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_ptr_array_unref (input);
|
|
Packit |
b00eeb |
return TRUE;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
thread_build_chain (GSimpleAsyncResult *result, GObject *object,
|
|
Packit |
b00eeb |
GCancellable *cancellable)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv;
|
|
Packit |
b00eeb |
GError *error = NULL;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv = g_object_get_qdata (G_OBJECT (result), Q_OPERATION_DATA);
|
|
Packit |
b00eeb |
g_assert (pv);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_debug ("building asynchronously in another thread");
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
if (!perform_build_chain (pv, cancellable, &error)) {
|
|
Packit |
b00eeb |
g_simple_async_result_set_from_error (result, error);
|
|
Packit |
b00eeb |
g_clear_error (&error);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* -----------------------------------------------------------------------------
|
|
Packit |
b00eeb |
* OBJECT
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
gcr_certificate_chain_init (GcrCertificateChain *self)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
self->pv = new_chain_private ();
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
gcr_certificate_chain_dispose (GObject *obj)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_ptr_array_set_size (self->pv->certificates, 0);
|
|
Packit |
b00eeb |
self->pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
G_OBJECT_CLASS (gcr_certificate_chain_parent_class)->dispose (obj);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
gcr_certificate_chain_finalize (GObject *obj)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
free_chain_private (self->pv);
|
|
Packit |
b00eeb |
self->pv = NULL;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
G_OBJECT_CLASS (gcr_certificate_chain_parent_class)->finalize (obj);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
gcr_certificate_chain_get_property (GObject *obj, guint prop_id, GValue *value,
|
|
Packit |
b00eeb |
GParamSpec *pspec)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChain *self = GCR_CERTIFICATE_CHAIN (obj);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
switch (prop_id) {
|
|
Packit |
b00eeb |
case PROP_STATUS:
|
|
Packit |
b00eeb |
g_value_set_enum (value, gcr_certificate_chain_get_status (self));
|
|
Packit |
b00eeb |
break;
|
|
Packit |
b00eeb |
case PROP_LENGTH:
|
|
Packit |
b00eeb |
g_value_set_uint (value, gcr_certificate_chain_get_length (self));
|
|
Packit |
b00eeb |
break;
|
|
Packit |
b00eeb |
default:
|
|
Packit |
b00eeb |
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
|
|
Packit |
b00eeb |
break;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
static void
|
|
Packit |
b00eeb |
gcr_certificate_chain_class_init (GcrCertificateChainClass *klass)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
gcr_certificate_chain_parent_class = g_type_class_peek_parent (klass);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
gobject_class->dispose = gcr_certificate_chain_dispose;
|
|
Packit |
b00eeb |
gobject_class->finalize = gcr_certificate_chain_finalize;
|
|
Packit |
b00eeb |
gobject_class->get_property = gcr_certificate_chain_get_property;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GcrCertificateChain:status:
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The certificate chain status. See #GcrCertificateChainStatus
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
g_object_class_install_property (gobject_class, PROP_STATUS,
|
|
Packit |
b00eeb |
g_param_spec_enum ("status", "Status", "Status of certificate chain",
|
|
Packit |
b00eeb |
GCR_TYPE_CERTIFICATE_CHAIN_STATUS,
|
|
Packit |
b00eeb |
GCR_CERTIFICATE_CHAIN_UNKNOWN, G_PARAM_READABLE));
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GcrCertificateChain:length:
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The length of the certificate chain.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
g_object_class_install_property (gobject_class, PROP_LENGTH,
|
|
Packit |
b00eeb |
g_param_spec_uint ("length", "Length", "Length of certificate chain",
|
|
Packit |
b00eeb |
0, G_MAXUINT, 0, G_PARAM_READABLE));
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
Q_ORIGINAL_CERT = g_quark_from_static_string ("gcr-certificate-chain-original-cert");
|
|
Packit |
b00eeb |
Q_OPERATION_DATA = g_quark_from_static_string ("gcr-certificate-chain-operation-data");
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/* -----------------------------------------------------------------------------
|
|
Packit |
b00eeb |
* PUBLIC
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GcrCertificateChainStatus:
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_UNKNOWN: The certificate chain's status is unknown.
|
|
Packit |
b00eeb |
* When a chain is not yet built it has this status. If a chain is modified after
|
|
Packit |
b00eeb |
* being built, it has this status.
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_INCOMPLETE: A full chain could not be loaded. The
|
|
Packit |
b00eeb |
* chain does not end with a self-signed certificate, a trusted anchor, or a
|
|
Packit |
b00eeb |
* pinned certificate.
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_SELFSIGNED: The chain ends with a self-signed
|
|
Packit |
b00eeb |
* certificate. No trust anchor was found.
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_DISTRUSTED: The certificate chain contains a revoked
|
|
Packit |
b00eeb |
* or otherwise explicitly distrusted certificate. The entire chain should
|
|
Packit |
b00eeb |
* be distrusted.
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_ANCHORED: The chain ends with an anchored
|
|
Packit |
b00eeb |
* certificate. The anchored certificate is not necessarily self-signed.
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_PINNED: The chain represents a pinned certificate. A
|
|
Packit |
b00eeb |
* pinned certificate is an exception which trusts a given certificate
|
|
Packit |
b00eeb |
* explicitly for a purpose and communication with a certain peer.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The status of a built certificate chain. Will be set to
|
|
Packit |
b00eeb |
* %GCR_CERTIFICATE_CHAIN_UNKNOWN for certificate chains that have not been
|
|
Packit |
b00eeb |
* built.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GCR_TYPE_CERTIFICATE_CHAIN_STATUS:
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The enum #GType for #GcrCertificateChainStatus.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GcrCertificateChainFlags:
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_NONE: no flags
|
|
Packit |
b00eeb |
* @GCR_CERTIFICATE_CHAIN_NO_LOOKUPS: If this flag is specified then no
|
|
Packit |
b00eeb |
* lookups for anchors or pinned certificates are done, and the resulting chain
|
|
Packit |
b00eeb |
* will be neither anchored or pinned. Additionally no missing certificate
|
|
Packit |
b00eeb |
* authorities are looked up in PKCS\#11.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Flags to be used with the gcr_certificate_chain_build() operation.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* GCR_TYPE_CERTIFICATE_CHAIN_FLAGS:
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The flags #GType for #GcrCertificateChainFlags.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_new:
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Create a new #GcrCertificateChain.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: (transfer full): a newly allocated certificate chain
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
GcrCertificateChain *
|
|
Packit |
b00eeb |
gcr_certificate_chain_new (void)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
return g_object_new (GCR_TYPE_CERTIFICATE_CHAIN, NULL);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_add:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
* @certificate: a #GcrCertificate to add to the chain
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Add @certificate to the chain. The order of certificates in the chain are
|
|
Packit |
b00eeb |
* important. The first certificate should be the endpoint certificate, and
|
|
Packit |
b00eeb |
* then come the signers (certificate authorities) each in turn. If a root
|
|
Packit |
b00eeb |
* certificate authority is present, it should come last.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Adding a certificate an already built chain (see
|
|
Packit |
b00eeb |
* gcr_certificate_chain_build()) resets the type of the certificate chain
|
|
Packit |
b00eeb |
* to %GCR_CERTIFICATE_CHAIN_UNKNOWN
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
void
|
|
Packit |
b00eeb |
gcr_certificate_chain_add (GcrCertificateChain *self, GcrCertificate *certificate)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self));
|
|
Packit |
b00eeb |
g_return_if_fail (GCR_IS_CERTIFICATE (certificate));
|
|
Packit |
b00eeb |
g_ptr_array_add (self->pv->certificates, g_object_ref (certificate));
|
|
Packit |
b00eeb |
self->pv->status = GCR_CERTIFICATE_CHAIN_UNKNOWN;
|
|
Packit |
b00eeb |
g_object_notify (G_OBJECT (self), "status");
|
|
Packit |
b00eeb |
g_object_notify (G_OBJECT (self), "length");
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_get_status:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Get the status of a certificate chain. If the certificate chain has not
|
|
Packit |
b00eeb |
* been built, then the status will be %GCR_CERTIFICATE_CHAIN_UNKNOWN.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* A status of %GCR_CERTIFICATE_CHAIN_ANCHORED does not mean that the
|
|
Packit |
b00eeb |
* certificate chain has been verified, but merely that an anchor has been
|
|
Packit |
b00eeb |
* found.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: the status of the certificate chain.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
GcrCertificateChainStatus
|
|
Packit |
b00eeb |
gcr_certificate_chain_get_status (GcrCertificateChain *self)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), GCR_CERTIFICATE_CHAIN_UNKNOWN);
|
|
Packit |
b00eeb |
return self->pv->status;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_get_anchor:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* If the certificate chain has been built and is of status
|
|
Packit |
b00eeb |
* %GCR_CERTIFICATE_CHAIN_ANCHORED, then this will return the anchor
|
|
Packit |
b00eeb |
* certificate that was found. This is not necessarily a root certificate
|
|
Packit |
b00eeb |
* authority. If an intermediate certificate authority in the chain was
|
|
Packit |
b00eeb |
* found to be anchored, then that certificate will be returned.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* If an anchor is returned it does not mean that the certificate chain has
|
|
Packit |
b00eeb |
* been verified, but merely that an anchor has been found.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: (transfer none): the anchor certificate, or NULL if not anchored.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
GcrCertificate *
|
|
Packit |
b00eeb |
gcr_certificate_chain_get_anchor (GcrCertificateChain *self)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL);
|
|
Packit |
b00eeb |
if (self->pv->status != GCR_CERTIFICATE_CHAIN_ANCHORED)
|
|
Packit |
b00eeb |
return NULL;
|
|
Packit |
b00eeb |
g_assert (self->pv->certificates->len > 0);
|
|
Packit |
b00eeb |
return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates,
|
|
Packit |
b00eeb |
self->pv->certificates->len - 1));
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_get_endpoint:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Get the endpoint certificate in the chain. This is always the first
|
|
Packit |
b00eeb |
* certificate in the chain. The endpoint certificate cannot be anchored.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: (transfer none): the endpoint certificate, or %NULL if the chain
|
|
Packit |
b00eeb |
* is empty
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
GcrCertificate*
|
|
Packit |
b00eeb |
gcr_certificate_chain_get_endpoint (GcrCertificateChain *self)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL);
|
|
Packit |
b00eeb |
if (!self->pv->certificates->len)
|
|
Packit |
b00eeb |
return NULL;
|
|
Packit |
b00eeb |
return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, 0));
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_get_length:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Get the length of the certificate chain.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: the length of the certificate chain
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
guint
|
|
Packit |
b00eeb |
gcr_certificate_chain_get_length (GcrCertificateChain *self)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), 0);
|
|
Packit |
b00eeb |
return self->pv->certificates->len;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_get_certificate:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
* @index: index of the certificate to get
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Get a certificate in the chain. It is an error to call this function
|
|
Packit |
b00eeb |
* with an invalid index.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: (transfer none): the certificate
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
GcrCertificate *
|
|
Packit |
b00eeb |
gcr_certificate_chain_get_certificate (GcrCertificateChain *self, guint index)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), NULL);
|
|
Packit |
b00eeb |
g_return_val_if_fail (index < self->pv->certificates->len, NULL);
|
|
Packit |
b00eeb |
return GCR_CERTIFICATE (g_ptr_array_index (self->pv->certificates, index));
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_build:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
* @purpose: the purpose the certificate chain will be used for
|
|
Packit |
b00eeb |
* @peer: (allow-none): the peer the certificate chain will be used with, or %NULL
|
|
Packit |
b00eeb |
* @flags: chain completion flags
|
|
Packit |
b00eeb |
* @cancellable: a #GCancellable or %NULL
|
|
Packit |
b00eeb |
* @error: a #GError or %NULL
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Complete a certificate chain. Once a certificate chain has been built
|
|
Packit |
b00eeb |
* its status can be examined.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* This operation will lookup missing certificates in PKCS\#11
|
|
Packit |
b00eeb |
* modules and also that each certificate in the chain is the signer of the
|
|
Packit |
b00eeb |
* previous one. If a trust anchor, pinned certificate, or self-signed certificate
|
|
Packit |
b00eeb |
* is found, then the chain is considered built. Any extra certificates are
|
|
Packit |
b00eeb |
* removed from the chain.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* It's important to understand that building of a certificate chain does not
|
|
Packit |
b00eeb |
* constitute verifying that chain. This is merely the first step towards
|
|
Packit |
b00eeb |
* trust verification.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The @purpose is a string like %GCR_PURPOSE_CLIENT_AUTH and is the purpose
|
|
Packit |
b00eeb |
* for which the certificate chain will be used. Trust anchors are looked up
|
|
Packit |
b00eeb |
* for this purpose. This argument is required.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The @peer is usually the host name of the peer whith which this certificate
|
|
Packit |
b00eeb |
* chain is being used. It is used to look up pinned certificates that have
|
|
Packit |
b00eeb |
* been stored for this peer. If %NULL then no pinned certificates will
|
|
Packit |
b00eeb |
* be considered.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* If the %GCR_CERTIFICATE_CHAIN_NO_LOOKUPS flag is specified then no
|
|
Packit |
b00eeb |
* lookups for anchors or pinned certificates are done, and the resulting chain
|
|
Packit |
b00eeb |
* will be neither anchored or pinned. Additionally no missing certificate
|
|
Packit |
b00eeb |
* authorities are looked up in PKCS\#11
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* This call will block, see gcr_certificate_chain_build_async() for the
|
|
Packit |
b00eeb |
* asynchronous version.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: whether the operation completed successfully
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
gboolean
|
|
Packit |
b00eeb |
gcr_certificate_chain_build (GcrCertificateChain *self,
|
|
Packit |
b00eeb |
const gchar *purpose,
|
|
Packit |
b00eeb |
const gchar *peer,
|
|
Packit |
b00eeb |
GcrCertificateChainFlags flags,
|
|
Packit |
b00eeb |
GCancellable *cancellable,
|
|
Packit |
b00eeb |
GError **error)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv;
|
|
Packit |
b00eeb |
gboolean ret;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), FALSE);
|
|
Packit |
b00eeb |
g_return_val_if_fail (purpose != NULL, FALSE);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv = prep_chain_private (self->pv, purpose, peer, flags);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
ret = perform_build_chain (pv, cancellable, error);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
if (ret) {
|
|
Packit |
b00eeb |
free_chain_private (self->pv);
|
|
Packit |
b00eeb |
self->pv = cleanup_chain_private (pv);
|
|
Packit |
b00eeb |
g_object_notify (G_OBJECT (self), "status");
|
|
Packit |
b00eeb |
g_object_notify (G_OBJECT (self), "length");
|
|
Packit |
b00eeb |
} else {
|
|
Packit |
b00eeb |
free_chain_private (pv);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
return ret;
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_build_async:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
* @purpose: the purpose the certificate chain will be used for
|
|
Packit |
b00eeb |
* @peer: (allow-none): the peer the certificate chain will be used with, or %NULL
|
|
Packit |
b00eeb |
* @flags: chain completion flags
|
|
Packit |
b00eeb |
* @cancellable: a #GCancellable or %NULL
|
|
Packit |
b00eeb |
* @callback: this will be called when the operation completes.
|
|
Packit |
b00eeb |
* @user_data: data to pass to the callback
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Complete a certificate chain. Once a certificate chain has been built
|
|
Packit |
b00eeb |
* its status can be examined.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* This will lookup missing certificates in PKCS\#11
|
|
Packit |
b00eeb |
* modules and also that each certificate in the chain is the signer of the
|
|
Packit |
b00eeb |
* previous one. If a trust anchor, pinned certificate, or self-signed certificate
|
|
Packit |
b00eeb |
* is found, then the chain is considered built. Any extra certificates are
|
|
Packit |
b00eeb |
* removed from the chain.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* It's important to understand that building of a certificate chain does not
|
|
Packit |
b00eeb |
* constitute verifying that chain. This is merely the first step towards
|
|
Packit |
b00eeb |
* trust verification.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The @purpose is a string like %GCR_PURPOSE_CLIENT_AUTH and is the purpose
|
|
Packit |
b00eeb |
* for which the certificate chain will be used. Trust anchors are looked up
|
|
Packit |
b00eeb |
* for this purpose. This argument is required.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* The @peer is usually the host name of the peer whith which this certificate
|
|
Packit |
b00eeb |
* chain is being used. It is used to look up pinned certificates that have
|
|
Packit |
b00eeb |
* been stored for this peer. If %NULL then no pinned certificates will
|
|
Packit |
b00eeb |
* be considered.
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* If the %GCR_CERTIFICATE_CHAIN_NO_LOOKUPS flag is specified then no
|
|
Packit |
b00eeb |
* lookups for anchors or pinned certificates are done, and the resulting chain
|
|
Packit |
b00eeb |
* will be neither anchored or pinned. Additionally no missing certificate
|
|
Packit |
b00eeb |
* authorities are looked up in PKCS\#11
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* When the operation is finished, @callback will be called. You can then call
|
|
Packit |
b00eeb |
* gcr_certificate_chain_build_finish() to get the result of the operation.
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
void
|
|
Packit |
b00eeb |
gcr_certificate_chain_build_async (GcrCertificateChain *self,
|
|
Packit |
b00eeb |
const gchar *purpose,
|
|
Packit |
b00eeb |
const gchar *peer,
|
|
Packit |
b00eeb |
GcrCertificateChainFlags flags,
|
|
Packit |
b00eeb |
GCancellable *cancellable,
|
|
Packit |
b00eeb |
GAsyncReadyCallback callback,
|
|
Packit |
b00eeb |
gpointer user_data)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv;
|
|
Packit |
b00eeb |
GSimpleAsyncResult *result;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self));
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_return_if_fail (GCR_IS_CERTIFICATE_CHAIN (self));
|
|
Packit |
b00eeb |
g_return_if_fail (purpose);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv = prep_chain_private_thread_safe (self->pv, purpose, peer, flags);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
result = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
|
|
Packit |
b00eeb |
gcr_certificate_chain_build_async);
|
|
Packit |
b00eeb |
g_object_set_qdata_full (G_OBJECT (result), Q_OPERATION_DATA, pv, free_chain_private);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_simple_async_result_run_in_thread (result, thread_build_chain,
|
|
Packit |
b00eeb |
G_PRIORITY_DEFAULT, cancellable);
|
|
Packit |
b00eeb |
g_object_unref (result);
|
|
Packit |
b00eeb |
}
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
/**
|
|
Packit |
b00eeb |
* gcr_certificate_chain_build_finish:
|
|
Packit |
b00eeb |
* @self: the #GcrCertificateChain
|
|
Packit |
b00eeb |
* @result: the #GAsyncResult passed to the callback
|
|
Packit |
b00eeb |
* @error: a #GError, or NULL
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Finishes an asynchronous operation started by
|
|
Packit |
b00eeb |
* gcr_certificate_chain_build_async().
|
|
Packit |
b00eeb |
*
|
|
Packit |
b00eeb |
* Returns: whether the operation succeeded
|
|
Packit |
b00eeb |
*/
|
|
Packit |
b00eeb |
gboolean
|
|
Packit |
b00eeb |
gcr_certificate_chain_build_finish (GcrCertificateChain *self, GAsyncResult *result,
|
|
Packit |
b00eeb |
GError **error)
|
|
Packit |
b00eeb |
{
|
|
Packit |
b00eeb |
GcrCertificateChainPrivate *pv;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_return_val_if_fail (GCR_IS_CERTIFICATE_CHAIN (self), FALSE);
|
|
Packit |
b00eeb |
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
|
|
Packit |
b00eeb |
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
|
|
Packit |
b00eeb |
gcr_certificate_chain_build_async), FALSE);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
|
|
Packit |
b00eeb |
return FALSE;
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
pv = g_object_steal_qdata (G_OBJECT (result), Q_OPERATION_DATA);
|
|
Packit |
b00eeb |
g_return_val_if_fail (pv, FALSE);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
free_chain_private (self->pv);
|
|
Packit |
b00eeb |
self->pv = cleanup_chain_private (pv);
|
|
Packit |
b00eeb |
|
|
Packit |
b00eeb |
g_object_notify (G_OBJECT (self), "status");
|
|
Packit |
b00eeb |
g_object_notify (G_OBJECT (self), "length");
|
|
Packit |
b00eeb |
return TRUE;
|
|
Packit |
b00eeb |
}
|