dirmngr: Prepare certcache for forthcoming changes.

* dirmngr/certcache.c (cert_item_s): Rename 'flags.loaded' to
'flags.config'.  Add 'flags.systrust'.
(total_loaded_certificates): Rename to total_config_certificates.
(put_cert): Rename args for clarity.  Set SYSTRUST flag.
(load_certs_from_dir): Make sure put_cert does not set the SYSTRUST
flag.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2017-02-16 11:51:57 +01:00
parent 1af733f37b
commit 5c4e67afd6
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
1 changed files with 40 additions and 28 deletions

View File

@ -68,8 +68,12 @@ struct cert_item_s
char *subject_dn; /* The malloced subject DN - maybe NULL. */ char *subject_dn; /* The malloced subject DN - maybe NULL. */
struct struct
{ {
unsigned int loaded:1; /* It has been explicitly loaded. */ unsigned int config:1; /* This has been loaded from the configuration. */
unsigned int trusted:1; /* This is a trusted root certificate. */ unsigned int trusted:1; /* This is a trusted root certificate. */
unsigned int systrust:1;/* The certifciate is trusted because it
* is in the system's store of trusted
* certificates (i.e. not configured using
* GnuPG mechanisms. */
} flags; } flags;
}; };
typedef struct cert_item_s *cert_item_t; typedef struct cert_item_s *cert_item_t;
@ -88,9 +92,9 @@ 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 and /* Total number of certificates loaded during initialization
cached during operation. */ * (ie. configured) and extra certifcates cached during operation. */
static unsigned int total_loaded_certificates; static unsigned int total_config_certificates;
static unsigned int total_extra_certificates; static unsigned int total_extra_certificates;
@ -229,13 +233,20 @@ clean_cache_slot (cert_item_t ci)
/* Put the certificate CERT into the cache. It is assumed that the /* Put the certificate CERT into the cache. It is assumed that the
cache is locked while this function is called. If FPR_BUFFER is not * cache is locked while this function is called.
NULL the fingerprint of the certificate will be stored there. *
FPR_BUFFER neds to point to a buffer of at least 20 bytes. The * FROM_CONFIG indicates that CERT is a permanent certificate and
fingerprint will be stored on success or when the function returns * should stay in the cache. IS_TRUSTED requests that the trusted
gpg_err_code(GPG_ERR_DUP_VALUE). */ * flag is set for the certificate; a value of 1 indicates the the
* cert is trusted due to GnuPG mechanisms, a value of 2 indicates
* that it is trusted because it has been taken from the system's
* store of trusted certificates. If FPR_BUFFER is not NULL the
* fingerprint of the certificate will be stored there. FPR_BUFFER
* needs to point to a buffer of at least 20 bytes. The fingerprint
* will be stored on success or when the function returns
* GPG_ERR_DUP_VALUE. */
static gpg_error_t static gpg_error_t
put_cert (ksba_cert_t cert, int is_loaded, int is_trusted, void *fpr_buffer) put_cert (ksba_cert_t cert, int from_config, int is_trusted, 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;
@ -243,17 +254,17 @@ put_cert (ksba_cert_t cert, int is_loaded, int is_trusted, void *fpr_buffer)
fpr = fpr_buffer? fpr_buffer : &help_fpr_buffer; fpr = fpr_buffer? fpr_buffer : &help_fpr_buffer;
/* If we already reached the caching limit, drop a couple of certs /* If we already reached the caching limit, drop a couple of certs
from the cache. Our dropping strategy is simple: We keep a * from the cache. Our dropping strategy is simple: We keep a
static index counter and use this to start looking for * static index counter and use this to start looking for
certificates, then we drop 5 percent of the oldest certificates * certificates, then we drop 5 percent of the oldest certificates
starting at that index. For a large cache this is a fair way of * starting at that index. For a large cache this is a fair way of
removing items. An LRU strategy would be better of course. * removing items. An LRU strategy would be better of course.
Because we append new entries to the head of the list and we want * Because we append new entries to the head of the list and we want
to remove old ones first, we need to do this from the tail. The * to remove old ones first, we need to do this from the tail. The
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 certifciate 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 (!is_loaded && total_extra_certificates >= MAX_EXTRA_CACHED_CERTS) if (!from_config && total_extra_certificates >= MAX_EXTRA_CACHED_CERTS)
{ {
static int idx; static int idx;
cert_item_t ci_mark; cert_item_t ci_mark;
@ -270,7 +281,7 @@ put_cert (ksba_cert_t cert, int is_loaded, 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.loaded) if (ci->cert && !ci->flags.config)
ci_mark = ci; ci_mark = ci;
if (ci_mark) if (ci_mark)
{ {
@ -316,11 +327,12 @@ put_cert (ksba_cert_t cert, int is_loaded, 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.loaded = !!is_loaded; ci->flags.config = !!from_config;
ci->flags.trusted = !!is_trusted; ci->flags.trusted = !!is_trusted;
ci->flags.systrust = (is_trusted && is_trusted == 2);
if (is_loaded) if (from_config)
total_loaded_certificates++; total_config_certificates++;
else else
total_extra_certificates++; total_extra_certificates++;
@ -390,7 +402,7 @@ 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, !!are_trusted, 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)
@ -476,7 +488,7 @@ cert_cache_deinit (int full)
} }
} }
total_loaded_certificates = 0; total_config_certificates = 0;
total_extra_certificates = 0; total_extra_certificates = 0;
initialization_done = 0; initialization_done = 0;
release_cache_lock (); release_cache_lock ();
@ -487,7 +499,7 @@ void
cert_cache_print_stats (void) cert_cache_print_stats (void)
{ {
log_info (_("permanently loaded certificates: %u\n"), log_info (_("permanently loaded certificates: %u\n"),
total_loaded_certificates); total_config_certificates);
log_info (_(" runtime cached certificates: %u\n"), log_info (_(" runtime cached certificates: %u\n"),
total_extra_certificates); total_extra_certificates);
} }