mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
dirmngr: Implement trust classes for the cert cache.
* dirmngr/certcache.h (CERTTRUST_CLASS_SYSTEM): New. (CERTTRUST_CLASS_CONFIG): New. (CERTTRUST_CLASS_HKP): New. (CERTTRUST_CLASS_HKPSPOOL): New. * dirmngr/certcache.c (MAX_EXTRA_CACHED_CERTS): Rename to ... (MAX_NONPERM_CACHED_CERTS): this. (total_extra_certificates): Rename to ... (total_nonperm_certificates): this. (total_config_certificates): Remove. (total_trusted_certificates): Remove. (total_system_trusted_certificates): Remove. (cert_item_s): Remove field 'flags'. Add fields 'permanent' and 'trustclasses'. (clean_cache_slot): Clear new fields. (put_cert): Change for new cert_item_t structure. (load_certs_from_dir): Rename arg 'are_trusted' to 'trustclass' (load_certs_from_file): Use CERTTRUST_CLASS_ value for put_cert. (load_certs_from_w32_store): Ditto. (cert_cache_init): Ditto. (cert_cache_print_stats): Rewrite. (is_trusted_cert): Replace arg 'with_systrust' by 'trustclasses'. Chnage the test. * dirmngr/validate.c (allowed_ca): Pass CERTTRUST_CLASS_CONFIG to is_trusted_cert. (validate_cert_chain): Pass CERTTRUST_CLASS_ values to is_trusted_cert. -- These trust classes make it easier to select certain sets of root certificates. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
493c142e58
commit
50b9828eac
@ -33,7 +33,7 @@
|
|||||||
#include "crlfetch.h"
|
#include "crlfetch.h"
|
||||||
#include "certcache.h"
|
#include "certcache.h"
|
||||||
|
|
||||||
#define MAX_EXTRA_CACHED_CERTS 1000
|
#define MAX_NONPERM_CACHED_CERTS 1000
|
||||||
|
|
||||||
/* Constants used to classify search patterns. */
|
/* Constants used to classify search patterns. */
|
||||||
enum pattern_class
|
enum pattern_class
|
||||||
@ -66,15 +66,14 @@ struct cert_item_s
|
|||||||
char *issuer_dn; /* The malloced issuer DN. */
|
char *issuer_dn; /* The malloced issuer DN. */
|
||||||
ksba_sexp_t sn; /* The malloced serial number */
|
ksba_sexp_t sn; /* The malloced serial number */
|
||||||
char *subject_dn; /* The malloced subject DN - maybe NULL. */
|
char *subject_dn; /* The malloced subject DN - maybe NULL. */
|
||||||
struct
|
|
||||||
{
|
/* If this field is set the certificate has been taken from some
|
||||||
unsigned int config:1; /* This has been loaded from the configuration. */
|
* configuration and shall not be flushed from the cache. */
|
||||||
unsigned int trusted:1; /* This is a trusted root certificate. */
|
unsigned int permanent:1;
|
||||||
unsigned int systrust:1;/* The certifciate is trusted because it
|
|
||||||
* is in the system's store of trusted
|
/* If this field is set the certificate is trusted. The actual
|
||||||
* certificates (i.e. not configured using
|
* value is a (possible) combination of CERTTRUST_CLASS values. */
|
||||||
* GnuPG mechanisms. */
|
unsigned int trustclasses:4;
|
||||||
} flags;
|
|
||||||
};
|
};
|
||||||
typedef struct cert_item_s *cert_item_t;
|
typedef struct cert_item_s *cert_item_t;
|
||||||
|
|
||||||
@ -92,13 +91,8 @@ static npth_rwlock_t cert_cache_lock;
|
|||||||
/* Flag to track whether the cache has been initialized. */
|
/* Flag to track whether the cache has been initialized. */
|
||||||
static int initialization_done;
|
static int initialization_done;
|
||||||
|
|
||||||
/* Total number of certificates loaded during initialization
|
/* Total number of non-permanent certificates. */
|
||||||
* (ie. configured), extra certificates cached during operation,
|
static unsigned int total_nonperm_certificates;
|
||||||
* number of trusted and system trusted certificates. */
|
|
||||||
static unsigned int total_config_certificates;
|
|
||||||
static unsigned int total_extra_certificates;
|
|
||||||
static unsigned int total_trusted_certificates;
|
|
||||||
static unsigned int total_system_trusted_certificates;
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_W32_SYSTEM
|
#ifdef HAVE_W32_SYSTEM
|
||||||
@ -245,6 +239,9 @@ clean_cache_slot (cert_item_t ci)
|
|||||||
cert = ci->cert;
|
cert = ci->cert;
|
||||||
ci->cert = NULL;
|
ci->cert = NULL;
|
||||||
|
|
||||||
|
ci->permanent = 0;
|
||||||
|
ci->trustclasses = 0;
|
||||||
|
|
||||||
ksba_cert_release (cert);
|
ksba_cert_release (cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +260,8 @@ clean_cache_slot (cert_item_t ci)
|
|||||||
* will be stored on success or when the function returns
|
* will be stored on success or when the function returns
|
||||||
* GPG_ERR_DUP_VALUE. */
|
* GPG_ERR_DUP_VALUE. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
|
put_cert (ksba_cert_t cert, int permanent, unsigned int trustclass,
|
||||||
|
void *fpr_buffer)
|
||||||
{
|
{
|
||||||
unsigned char help_fpr_buffer[20], *fpr;
|
unsigned char help_fpr_buffer[20], *fpr;
|
||||||
cert_item_t ci;
|
cert_item_t ci;
|
||||||
@ -281,14 +279,14 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
|
|||||||
* implementation is not very efficient but compared to the long
|
* implementation is not very efficient but compared to the long
|
||||||
* time it takes to retrieve a certificate from an external resource
|
* time it takes to retrieve a certificate from an external resource
|
||||||
* it seems to be reasonable. */
|
* it seems to be reasonable. */
|
||||||
if (!from_config && total_extra_certificates >= MAX_EXTRA_CACHED_CERTS)
|
if (!permanent && total_nonperm_certificates >= MAX_NONPERM_CACHED_CERTS)
|
||||||
{
|
{
|
||||||
static int idx;
|
static int idx;
|
||||||
cert_item_t ci_mark;
|
cert_item_t ci_mark;
|
||||||
int i;
|
int i;
|
||||||
unsigned int drop_count;
|
unsigned int drop_count;
|
||||||
|
|
||||||
drop_count = MAX_EXTRA_CACHED_CERTS / 20;
|
drop_count = MAX_NONPERM_CACHED_CERTS / 20;
|
||||||
if (drop_count < 2)
|
if (drop_count < 2)
|
||||||
drop_count = 2;
|
drop_count = 2;
|
||||||
|
|
||||||
@ -298,17 +296,13 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
|
|||||||
{
|
{
|
||||||
ci_mark = NULL;
|
ci_mark = NULL;
|
||||||
for (ci = cert_cache[i]; ci; ci = ci->next)
|
for (ci = cert_cache[i]; ci; ci = ci->next)
|
||||||
if (ci->cert && !ci->flags.config)
|
if (ci->cert && !ci->permanent)
|
||||||
ci_mark = ci;
|
ci_mark = ci;
|
||||||
if (ci_mark)
|
if (ci_mark)
|
||||||
{
|
{
|
||||||
clean_cache_slot (ci_mark);
|
clean_cache_slot (ci_mark);
|
||||||
drop_count--;
|
drop_count--;
|
||||||
total_extra_certificates--;
|
total_nonperm_certificates--;
|
||||||
if (ci->flags.trusted)
|
|
||||||
total_trusted_certificates--;
|
|
||||||
if (ci->flags.systrust)
|
|
||||||
total_system_trusted_certificates--;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i==idx)
|
if (i==idx)
|
||||||
@ -334,8 +328,6 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
|
|||||||
ci->next = cert_cache[*fpr];
|
ci->next = cert_cache[*fpr];
|
||||||
cert_cache[*fpr] = ci;
|
cert_cache[*fpr] = ci;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
memset (&ci->flags, 0, sizeof ci->flags);
|
|
||||||
|
|
||||||
ksba_cert_ref (cert);
|
ksba_cert_ref (cert);
|
||||||
ci->cert = cert;
|
ci->cert = cert;
|
||||||
@ -348,19 +340,11 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
|
|||||||
return gpg_error (GPG_ERR_INV_CERT_OBJ);
|
return gpg_error (GPG_ERR_INV_CERT_OBJ);
|
||||||
}
|
}
|
||||||
ci->subject_dn = ksba_cert_get_subject (cert, 0);
|
ci->subject_dn = ksba_cert_get_subject (cert, 0);
|
||||||
ci->flags.config = !!from_config;
|
ci->permanent = !!permanent;
|
||||||
ci->flags.trusted = !!is_trusted;
|
ci->trustclasses = trustclass;
|
||||||
ci->flags.systrust = (is_trusted && is_trusted == 2);
|
|
||||||
|
|
||||||
if (ci->flags.trusted)
|
if (!permanent)
|
||||||
total_trusted_certificates++;
|
total_nonperm_certificates++;
|
||||||
if (ci->flags.systrust)
|
|
||||||
total_system_trusted_certificates++;
|
|
||||||
|
|
||||||
if (from_config)
|
|
||||||
total_config_certificates++;
|
|
||||||
else
|
|
||||||
total_extra_certificates++;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -371,7 +355,7 @@ put_cert (ksba_cert_t cert, int from_config, int is_trusted, void *fpr_buffer)
|
|||||||
certificates are DER encoded and not PEM encapsulated. The cache
|
certificates are DER encoded and not PEM encapsulated. The cache
|
||||||
should be in a locked state when calling this function. */
|
should be in a locked state when calling this function. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
load_certs_from_dir (const char *dirname, int are_trusted)
|
load_certs_from_dir (const char *dirname, unsigned int trustclass)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
@ -428,12 +412,12 @@ load_certs_from_dir (const char *dirname, int are_trusted)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = put_cert (cert, 1, !!are_trusted, NULL);
|
err = put_cert (cert, 1, trustclass, NULL);
|
||||||
if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
|
if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
|
||||||
log_info (_("certificate '%s' already cached\n"), fname);
|
log_info (_("certificate '%s' already cached\n"), fname);
|
||||||
else if (!err)
|
else if (!err)
|
||||||
{
|
{
|
||||||
if (are_trusted)
|
if (trustclass)
|
||||||
log_info (_("trusted certificate '%s' loaded\n"), fname);
|
log_info (_("trusted certificate '%s' loaded\n"), fname);
|
||||||
else
|
else
|
||||||
log_info (_("certificate '%s' loaded\n"), fname);
|
log_info (_("certificate '%s' loaded\n"), fname);
|
||||||
@ -509,7 +493,7 @@ load_certs_from_file (const char *fname)
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = put_cert (cert, 1, 2, NULL);
|
err = put_cert (cert, 1, CERTTRUST_CLASS_SYSTEM, NULL);
|
||||||
if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
|
if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
|
||||||
log_info (_("certificate '%s' already cached\n"), fname);
|
log_info (_("certificate '%s' already cached\n"), fname);
|
||||||
else if (err)
|
else if (err)
|
||||||
@ -619,7 +603,7 @@ load_certs_from_w32_store (const char *storename)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = put_cert (cert, 1, 2, NULL);
|
err = put_cert (cert, 1, CERTTRUST_CLASS_SYSTEM, NULL);
|
||||||
if (!err)
|
if (!err)
|
||||||
count++;
|
count++;
|
||||||
if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
|
if (gpg_err_code (err) == GPG_ERR_DUP_VALUE)
|
||||||
@ -710,7 +694,7 @@ cert_cache_init (void)
|
|||||||
load_certs_from_system ();
|
load_certs_from_system ();
|
||||||
|
|
||||||
dname = make_filename (gnupg_sysconfdir (), "trusted-certs", NULL);
|
dname = make_filename (gnupg_sysconfdir (), "trusted-certs", NULL);
|
||||||
load_certs_from_dir (dname, 1);
|
load_certs_from_dir (dname, CERTTRUST_CLASS_CONFIG);
|
||||||
xfree (dname);
|
xfree (dname);
|
||||||
|
|
||||||
dname = make_filename (gnupg_sysconfdir (), "extra-certs", NULL);
|
dname = make_filename (gnupg_sysconfdir (), "extra-certs", NULL);
|
||||||
@ -753,10 +737,7 @@ cert_cache_deinit (int full)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
total_config_certificates = 0;
|
total_nonperm_certificates = 0;
|
||||||
total_extra_certificates = 0;
|
|
||||||
total_trusted_certificates = 0;
|
|
||||||
total_system_trusted_certificates = 0;
|
|
||||||
initialization_done = 0;
|
initialization_done = 0;
|
||||||
release_cache_lock ();
|
release_cache_lock ();
|
||||||
}
|
}
|
||||||
@ -765,12 +746,51 @@ cert_cache_deinit (int full)
|
|||||||
void
|
void
|
||||||
cert_cache_print_stats (void)
|
cert_cache_print_stats (void)
|
||||||
{
|
{
|
||||||
|
cert_item_t ci;
|
||||||
|
int idx;
|
||||||
|
unsigned int n_nonperm = 0;
|
||||||
|
unsigned int n_permanent = 0;
|
||||||
|
unsigned int n_trusted = 0;
|
||||||
|
unsigned int n_trustclass_system = 0;
|
||||||
|
unsigned int n_trustclass_config = 0;
|
||||||
|
unsigned int n_trustclass_hkp = 0;
|
||||||
|
unsigned int n_trustclass_hkpspool = 0;
|
||||||
|
|
||||||
|
acquire_cache_read_lock ();
|
||||||
|
for (idx = 0; idx < 256; idx++)
|
||||||
|
for (ci=cert_cache[idx]; ci; ci = ci->next)
|
||||||
|
if (ci->cert)
|
||||||
|
{
|
||||||
|
if (ci->permanent)
|
||||||
|
n_permanent++;
|
||||||
|
else
|
||||||
|
n_nonperm++;
|
||||||
|
if (ci->trustclasses)
|
||||||
|
{
|
||||||
|
n_trusted++;
|
||||||
|
if ((ci->trustclasses & CERTTRUST_CLASS_SYSTEM))
|
||||||
|
n_trustclass_system++;
|
||||||
|
if ((ci->trustclasses & CERTTRUST_CLASS_CONFIG))
|
||||||
|
n_trustclass_config++;
|
||||||
|
if ((ci->trustclasses & CERTTRUST_CLASS_HKP))
|
||||||
|
n_trustclass_hkp++;
|
||||||
|
if ((ci->trustclasses & CERTTRUST_CLASS_HKPSPOOL))
|
||||||
|
n_trustclass_hkpspool++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release_cache_lock ();
|
||||||
|
|
||||||
log_info (_("permanently loaded certificates: %u\n"),
|
log_info (_("permanently loaded certificates: %u\n"),
|
||||||
total_config_certificates);
|
n_permanent);
|
||||||
log_info (_(" runtime cached certificates: %u\n"),
|
log_info (_(" runtime cached certificates: %u\n"),
|
||||||
total_extra_certificates);
|
n_nonperm);
|
||||||
log_info (_(" trusted certificates: %u (%u)\n"),
|
log_info (_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
|
||||||
total_trusted_certificates, total_system_trusted_certificates);
|
n_trusted,
|
||||||
|
n_trustclass_system,
|
||||||
|
n_trustclass_config,
|
||||||
|
n_trustclass_hkp,
|
||||||
|
n_trustclass_hkpspool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1545,10 +1565,10 @@ find_cert_bysubject (ctrl_t ctrl, const char *subject_dn, ksba_sexp_t keyid)
|
|||||||
|
|
||||||
/* Return 0 if the certificate is a trusted certificate. Returns
|
/* Return 0 if the certificate is a trusted certificate. Returns
|
||||||
* GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
|
* GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
|
||||||
* case of systems errors. If WITH_SYSTRUST is set also system
|
* case of systems errors. TRUSTCLASSES are the bitwise ORed
|
||||||
* provided certificates are considered trusted. */
|
* CERTTRUST_CLASS values to use for the check. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
is_trusted_cert (ksba_cert_t cert, int with_systrust)
|
is_trusted_cert (ksba_cert_t cert, unsigned int trustclasses)
|
||||||
{
|
{
|
||||||
unsigned char fpr[20];
|
unsigned char fpr[20];
|
||||||
cert_item_t ci;
|
cert_item_t ci;
|
||||||
@ -1559,8 +1579,10 @@ is_trusted_cert (ksba_cert_t cert, int with_systrust)
|
|||||||
for (ci=cert_cache[*fpr]; ci; ci = ci->next)
|
for (ci=cert_cache[*fpr]; ci; ci = ci->next)
|
||||||
if (ci->cert && !memcmp (ci->fpr, fpr, 20))
|
if (ci->cert && !memcmp (ci->fpr, fpr, 20))
|
||||||
{
|
{
|
||||||
if (ci->flags.trusted && (with_systrust || !ci->flags.systrust))
|
if ((ci->trustclasses & trustclasses))
|
||||||
{
|
{
|
||||||
|
/* The certificate is trusted in one of the given
|
||||||
|
* TRUSTCLASSES. */
|
||||||
release_cache_lock ();
|
release_cache_lock ();
|
||||||
return 0; /* Yes, it is trusted. */
|
return 0; /* Yes, it is trusted. */
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,15 @@
|
|||||||
#ifndef CERTCACHE_H
|
#ifndef CERTCACHE_H
|
||||||
#define CERTCACHE_H
|
#define CERTCACHE_H
|
||||||
|
|
||||||
|
/* The origin of the trusted root certificates. */
|
||||||
|
enum {
|
||||||
|
CERTTRUST_CLASS_SYSTEM = 1, /* From the system's list of trusted certs. */
|
||||||
|
CERTTRUST_CLASS_CONFIG = 2, /* From dirmngr's config files. */
|
||||||
|
CERTTRUST_CLASS_HKP = 4, /* From --hkp-cacert */
|
||||||
|
CERTTRUST_CLASS_HKPSPOOL= 8, /* The one and only from sks-keyservers */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* First time initialization of the certificate cache. */
|
/* First time initialization of the certificate cache. */
|
||||||
void cert_cache_init (void);
|
void cert_cache_init (void);
|
||||||
|
|
||||||
@ -42,9 +51,9 @@ gpg_error_t cache_cert_silent (ksba_cert_t cert, void *fpr_buffer);
|
|||||||
|
|
||||||
/* Return 0 if the certificate is a trusted certificate. Returns
|
/* Return 0 if the certificate is a trusted certificate. Returns
|
||||||
* GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
|
* GPG_ERR_NOT_TRUSTED if it is not trusted or other error codes in
|
||||||
* case of systems errors. If WITH_SYSTRUST is set also system
|
* case of systems errors. TRUSTCLASSES are the bitwise ORed
|
||||||
* provided certificates are considered trusted. */
|
* CERTTRUST_CLASS values to use for the check. */
|
||||||
gpg_error_t is_trusted_cert (ksba_cert_t cert, int with_systrust);
|
gpg_error_t is_trusted_cert (ksba_cert_t cert, unsigned trustclasses);
|
||||||
|
|
||||||
/* Return a certificate object for the given fingerprint. FPR is
|
/* Return a certificate object for the given fingerprint. FPR is
|
||||||
expected to be a 20 byte binary SHA-1 fingerprint. If no matching
|
expected to be a 20 byte binary SHA-1 fingerprint. If no matching
|
||||||
|
@ -203,7 +203,7 @@ allowed_ca (ksba_cert_t cert, int *chainlen)
|
|||||||
return err;
|
return err;
|
||||||
if (!flag)
|
if (!flag)
|
||||||
{
|
{
|
||||||
if (!is_trusted_cert (cert, 0))
|
if (!is_trusted_cert (cert, CERTTRUST_CLASS_CONFIG))
|
||||||
{
|
{
|
||||||
/* The German SigG Root CA's certificate does not flag
|
/* The German SigG Root CA's certificate does not flag
|
||||||
itself as a CA; thus we relax this requirement if we
|
itself as a CA; thus we relax this requirement if we
|
||||||
@ -540,8 +540,10 @@ validate_cert_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
|
|||||||
if (err)
|
if (err)
|
||||||
goto leave; /* No. */
|
goto leave; /* No. */
|
||||||
|
|
||||||
err = is_trusted_cert (subject_cert,
|
err = is_trusted_cert
|
||||||
!!(flags & VALIDATE_FLAG_SYSTRUST));
|
(subject_cert,
|
||||||
|
(CERTTRUST_CLASS_CONFIG
|
||||||
|
| (flags & VALIDATE_FLAG_SYSTRUST)? CERTTRUST_CLASS_SYSTEM : 0));
|
||||||
if (!err)
|
if (!err)
|
||||||
; /* Yes we trust this cert. */
|
; /* Yes we trust this cert. */
|
||||||
else if (gpg_err_code (err) == GPG_ERR_NOT_TRUSTED)
|
else if (gpg_err_code (err) == GPG_ERR_NOT_TRUSTED)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user