gnupg/kbx/backend-kbx.c

329 lines
8.3 KiB
C
Raw Normal View History

/* backend-kbx.c - Keybox format backend for keyboxd
* Copyright (C) 2019 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "keyboxd.h"
#include "../common/i18n.h"
#include "backend.h"
#include "keybox.h"
/* Our definition of the backend handle. */
struct backend_handle_s
{
enum database_types db_type; /* Always DB_TYPE_KBX. */
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
unsigned int backend_id; /* Always the id of the backend. */
void *token; /* Used to create a new KEYBOX_HANDLE. */
char filename[1];
};
/* Check that the file FILENAME is a valid keybox file which can be
* used here. Common return codes:
*
* 0 := Valid keybox file
* GPG_ERR_ENOENT := No such file
* GPG_ERR_NO_OBJ := File exists with size zero.
* GPG_ERR_INV_OBJ:= File exists but is not a keybox file.
*/
static gpg_error_t
check_kbx_file_magic (const char *filename)
{
gpg_error_t err;
u32 magic;
unsigned char verbuf[4];
estream_t fp;
fp = es_fopen (filename, "rb");
if (!fp)
return gpg_error_from_syserror ();
err = gpg_error (GPG_ERR_INV_OBJ);
if (es_fread (&magic, 4, 1, fp) == 1 )
{
if (es_fread (&verbuf, 4, 1, fp) == 1
&& verbuf[0] == 1
&& es_fread (&magic, 4, 1, fp) == 1
&& !memcmp (&magic, "KBXf", 4))
{
err = 0;
}
}
else /* Maybe empty: Let's create it. */
err = gpg_error (GPG_ERR_NO_OBJ);
es_fclose (fp);
return err;
}
/* Create new keybox file. This can also be used if the keybox
* already exists but has a length of zero. Do not use it in any
* other cases. */
static gpg_error_t
create_keybox (const char *filename)
{
gpg_error_t err;
dotlock_t lockhd = NULL;
estream_t fp;
/* To avoid races with other temporary instances of keyboxd trying
* to create or update the keybox, we do the next stuff in a locked
* state. */
lockhd = dotlock_create (filename, 0);
if (!lockhd)
{
err = gpg_error_from_syserror ();
/* A reason for this to fail is that the directory is not
* writable. However, this whole locking stuff does not make
* sense if this is the case. An empty non-writable directory
* with no keybox is not really useful at all. */
if (opt.verbose)
log_info ("can't allocate lock for '%s': %s\n",
filename, gpg_strerror (err));
return err;
}
if ( dotlock_take (lockhd, -1) )
{
err = gpg_error_from_syserror ();
/* This is something bad. Probably a stale lockfile. */
log_info ("can't lock '%s': %s\n", filename, gpg_strerror (err));
goto leave;
}
/* Make sure that at least one record is in a new keybox file, so
* that the detection magic will work the next time it is used.
* We always set the OpenPGP blobs maybe availabale flag. */
fp = es_fopen (filename, "w+b,mode=-rw-------");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error (_("error creating keybox '%s': %s\n"),
filename, gpg_strerror (err));
goto leave;
}
err = _keybox_write_header_blob (NULL, fp, 1);
es_fclose (fp);
if (err)
{
log_error (_("error creating keybox '%s': %s\n"),
filename, gpg_strerror (err));
goto leave;
}
if (!opt.quiet)
log_info (_("keybox '%s' created\n"), filename);
err = 0;
leave:
if (lockhd)
{
dotlock_release (lockhd);
dotlock_destroy (lockhd);
}
return err;
}
/* Install a new resource and return a handle for that backend. */
gpg_error_t
be_kbx_add_resource (ctrl_t ctrl, backend_handle_t *r_hd,
const char *filename, int readonly)
{
gpg_error_t err;
backend_handle_t hd;
void *token;
(void)ctrl;
*r_hd = NULL;
hd = xtrycalloc (1, sizeof *hd + strlen (filename));
if (!hd)
return gpg_error_from_syserror ();
hd->db_type = DB_TYPE_KBX;
strcpy (hd->filename, filename);
err = check_kbx_file_magic (filename);
switch (gpg_err_code (err))
{
case 0:
break;
case GPG_ERR_ENOENT:
case GPG_ERR_NO_OBJ:
if (readonly)
{
err = gpg_error (GPG_ERR_ENOENT);
goto leave;
}
err = create_keybox (filename);
if (err)
goto leave;
break;
default:
goto leave;
}
err = keybox_register_file (filename, 0, &token);
if (err)
goto leave;
hd->backend_id = be_new_backend_id ();
hd->token = token;
*r_hd = hd;
hd = NULL;
leave:
xfree (hd);
return 0;
}
/* Release the backend handle HD and all its resources. HD is not
* valid after a call to this function. */
void
be_kbx_release_resource (ctrl_t ctrl, backend_handle_t hd)
{
(void)ctrl;
if (!hd)
return;
hd->db_type = DB_TYPE_NONE;
xfree (hd);
}
void
be_kbx_release_kbx_hd (KEYBOX_HANDLE kbx_hd)
{
keybox_release (kbx_hd);
}
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
/* Helper for be_find_request_part to initialize a kbx request part. */
gpg_error_t
be_kbx_init_request_part (backend_handle_t backend_hd, db_request_part_t part)
{
part->kbx_hd = keybox_new_openpgp (backend_hd->token, 0);
if (!part->kbx_hd)
return gpg_error_from_syserror ();
return 0;
}
/* Search for the keys described by (DESC,NDESC) and return them to
* the caller. BACKEND_HD is the handle for this backend and REQUEST
* is the current database request object. */
gpg_error_t
be_kbx_search (ctrl_t ctrl, backend_handle_t backend_hd, db_request_t request,
KEYDB_SEARCH_DESC *desc, unsigned int ndesc)
{
gpg_error_t err;
db_request_part_t part;
size_t descindex;
unsigned long skipped_long_blobs;
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
log_assert (request);
/* Find the specific request part or allocate it. */
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
err = be_find_request_part (backend_hd, request, &part);
if (err)
goto leave;
if (!desc)
err = keybox_search_reset (part->kbx_hd);
else
err = keybox_search (part->kbx_hd, desc, ndesc, KEYBOX_BLOBTYPE_PGP,
&descindex, &skipped_long_blobs);
if (err == -1)
err = gpg_error (GPG_ERR_EOF);
if (desc && !err)
{
/* Successful search operation. */
void *buffer;
size_t buflen;
enum pubkey_types pubkey_type;
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
unsigned char blobid[20];
err = keybox_get_data (part->kbx_hd, &buffer, &buflen, &pubkey_type);
if (err)
goto leave;
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
gcry_md_hash_buffer (GCRY_MD_SHA1, blobid, buffer, buflen);
err = be_return_pubkey (ctrl, buffer, buflen, pubkey_type, blobid);
if (!err)
be_cache_pubkey (ctrl, blobid, buffer, buflen, pubkey_type);
xfree (buffer);
}
leave:
return err;
}
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
/* Seek in the keybox to the given UBID. BACKEND_HD is the handle for
* this backend and REQUEST is the current database request object.
* This does a dummy read so that the next search operation starts
* right after that UBID. */
gpg_error_t
be_kbx_seek (ctrl_t ctrl, backend_handle_t backend_hd,
db_request_t request, unsigned char *ubid)
{
gpg_error_t err;
db_request_part_t part;
size_t descindex;
unsigned long skipped_long_blobs;
KEYDB_SEARCH_DESC desc;
(void)ctrl;
kbx: First take on a cache for the keyboxd. * kbx/backend.h (enum database_types): Add DB_TYPE_CACHE. (struct db_request_part_s): Add seqno fields. (struct db_request_s): Add infos for the cache backend. * kbx/backend-support.c (struct backend_handle_s): Add 'backend_id'. (strdbtype): Support DB_TYPE_CACHE. (be_generic_release_backend): Ditto. (be_find_request_part): New. (be_return_pubkey): New arg UBID and chnage status name. * kbx/backend-cache.c: New. * kbx/backend-kbx.c (be_kbx_init_request_part): New. (be_kbx_search): Factor some code out to a support function. (be_kbx_seek): New. * kbx/frontend.c (kbxd_add_resource): Support DB_TYPE_CACHE. (kbxd_search): Support the NEXR operation with the cache. * kbx/keybox-search-desc.h (KEYDB_SEARCH_MODE_UBID): New. (struct keydb_search_desc): Add field u.ubid. * kbx/keybox-search.c (has_ubid): New. (keybox_search): Support the UBID search. -- This adds a caching backend to the keyboxd. This tries to accommodate for duplicate use of fingerprints and thus be correct in case a fingerprint is used in several keys. It also turned out that we need to have a unique identifier (UBID) to identify a keyblock or X.509 certificate. In particular with an OpenPGP keyblob we can't easily use the primary fingerprint as an identifier because that fingerprint may also be used as subkey in another key. Thus using a hash of the entire keyblock is a better identifier to be used to address a keyblock for restarting a search or for identifying the keyblock to be updated. Note that this new UBID is not a permanent identifier because it changes with all keyblock update; it should be viewed as a handle to the keyblock or X509 cert.
2019-09-27 09:24:58 +02:00
log_assert (backend_hd && backend_hd->db_type == DB_TYPE_KBX);
log_assert (request);
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_UBID;
memcpy (desc.u.ubid, ubid, 20);
/* Find the specific request part or allocate it. */
err = be_find_request_part (backend_hd, request, &part);
if (err)
goto leave;
err = keybox_search_reset (part->kbx_hd);
if (!err)
err = keybox_search (part->kbx_hd, &desc, 1, 0,
&descindex, &skipped_long_blobs);
if (err == -1)
err = gpg_error (GPG_ERR_EOF);
leave:
return err;
}