1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

gpg: Add signature cache support to the keybox.

* g10/keydb.c (parse_keyblock_image): Add arg SIGSTATUS.
(keydb_get_keyblock): Handle it.
(build_keyblock_image): Add arg SIGSTATUS.
(keydb_insert_keyblock): Handle it.
* kbx/keybox-blob.c (pgp_create_sig_part): Add arg SIGSTATUS.
(_keybox_create_openpgp_blob): Ditto.
* kbx/kbxutil.c (import_openpgp): Adjust for above change.
* kbx/keybox.h (KEYBOX_FLAG_SIG_INFO): New.
* kbx/keybox-search.c (_keybox_get_flag_location): Handle new flag.
(keybox_get_keyblock): Add arg R_SIGSTATUS.
* kbx/keybox-update.c (keybox_insert_keyblock): Add arg SIGSTATUS.
--

With this change a key listing using the keybox format is now double
as fast as using a keyring.  The memory use dropped as well.  Measured
with about 1500 keys.
This commit is contained in:
Werner Koch 2012-12-28 17:17:56 +01:00
parent 564d10ea5c
commit 79f08fb069
7 changed files with 155 additions and 27 deletions

View file

@ -617,13 +617,14 @@ unlock_all (KEYDB_HANDLE hd)
static gpg_error_t
parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
parse_keyblock_image (iobuf_t iobuf, const u32 *sigstatus, kbnode_t *r_keyblock)
{
gpg_error_t err;
PACKET *pkt;
kbnode_t keyblock = NULL;
kbnode_t node;
kbnode_t node, *tail;
int in_cert, save_mode;
u32 n_sigs;
*r_keyblock = NULL;
@ -633,6 +634,8 @@ parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
init_packet (pkt);
save_mode = set_packet_list_mode (0);
in_cert = 0;
n_sigs = 0;
tail = NULL;
while ((err = parse_packet (iobuf, pkt)) != -1)
{
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
@ -665,25 +668,57 @@ parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
{
log_error ("error: first packet in a keybox blob is not a "
"public key packet\n");
log_error ("parse_keyblock_image: first packet in a keybox blob "
"is not a public key packet\n");
err = gpg_error (GPG_ERR_INV_KEYRING);
break;
}
if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY
|| pkt->pkttype == PKT_SECRET_KEY))
{
log_error ("error: multiple keyblocks in a keybox blob\n");
log_error ("parse_keyblock_image: "
"multiple keyblocks in a keybox blob\n");
err = gpg_error (GPG_ERR_INV_KEYRING);
break;
}
in_cert = 1;
if (pkt->pkttype == PKT_SIGNATURE && sigstatus)
{
PKT_signature *sig = pkt->pkt.signature;
n_sigs++;
if (n_sigs > sigstatus[0])
{
log_error ("parse_keyblock_image: "
"more signatures than found in the meta data\n");
err = gpg_error (GPG_ERR_INV_KEYRING);
break;
}
if (sigstatus[n_sigs])
{
sig->flags.checked = 1;
if (sigstatus[n_sigs] == 1 )
; /* missing key */
else if (sigstatus[n_sigs] == 2 )
; /* bad signature */
else if (sigstatus[n_sigs] < 0x10000000)
; /* bad flag */
else
{
sig->flags.valid = 1;
/* Fixme: Shall we set the expired flag here? */
}
}
}
node = new_kbnode (pkt);
if (!keyblock)
keyblock = node;
else
add_kbnode (keyblock, node);
*tail = node;
tail = &node->next;
pkt = xtrymalloc (sizeof *pkt);
if (!pkt)
{
@ -697,6 +732,12 @@ parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
if (err == -1 && keyblock)
err = 0; /* Got the entire keyblock. */
if (!err && sigstatus && n_sigs != sigstatus[0])
{
log_error ("parse_keyblock_image: signature count does not match\n");
err = gpg_error (GPG_ERR_INV_KEYRING);
}
if (err)
release_kbnode (keyblock);
else
@ -737,11 +778,14 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
case KEYDB_RESOURCE_TYPE_KEYBOX:
{
iobuf_t iobuf;
u32 *sigstatus;
err = keybox_get_keyblock (hd->active[hd->found].u.kb, &iobuf);
err = keybox_get_keyblock (hd->active[hd->found].u.kb,
&iobuf, &sigstatus);
if (!err)
{
err = parse_keyblock_image (iobuf, ret_kb);
err = parse_keyblock_image (iobuf, sigstatus, ret_kb);
xfree (sigstatus);
iobuf_close (iobuf);
}
}
@ -753,18 +797,33 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
/* Build a keyblock image from KEYBLOCK. Returns 0 on success and
only then stores a new iobuf object at R_IOBUF. */
only then stores a new iobuf object at R_IOBUF and a signature
status vecotor at R_SIGSTATUS. */
static gpg_error_t
build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus)
{
gpg_error_t err;
iobuf_t iobuf;
kbnode_t kbctx, node;
u32 n_sigs;
u32 *sigstatus;
*r_iobuf = NULL;
*r_sigstatus = NULL;
/* Allocate a vector for the signature cache. This is an array of
u32 values with the first value giving the number of elements to
follow and each element descriping the cache status of the
signature. */
for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
if (node->pkt->pkttype == PKT_SIGNATURE)
n_sigs++;
sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus);
if (!sigstatus)
return gpg_error_from_syserror ();
iobuf = iobuf_temp ();
for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));)
{
/* Make sure to use only packets valid on a keyblock. */
switch (node->pkt->pkttype)
@ -787,9 +846,34 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
iobuf_close (iobuf);
return err;
}
/* Build signature status vector. */
if (node->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = node->pkt->pkt.signature;
n_sigs++;
/* Fixme: Detect tye "missing key" status. */
if (sig->flags.checked)
{
if (sig->flags.valid)
{
if (!sig->expiredate)
sigstatus[n_sigs] = 0xffffffff;
else if (sig->expiredate < 0x1000000)
sigstatus[n_sigs] = 0x10000000;
else
sigstatus[n_sigs] = sig->expiredate;
}
else
sigstatus[n_sigs] = 0x00000002; /* Bad signature. */
}
}
}
sigstatus[0] = n_sigs;
*r_iobuf = iobuf;
*r_sigstatus = sigstatus;
return 0;
}
@ -876,13 +960,16 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
included in the keybox code. Eventually we can change this
kludge to have the caller pass the image. */
iobuf_t iobuf;
u32 *sigstatus;
err = build_keyblock_image (kb, &iobuf);
err = build_keyblock_image (kb, &iobuf, &sigstatus);
if (!err)
{
err = keybox_insert_keyblock (hd->active[idx].u.kb,
iobuf_get_temp_buffer (iobuf),
iobuf_get_temp_length (iobuf));
iobuf_get_temp_length (iobuf),
sigstatus);
xfree (sigstatus);
iobuf_close (iobuf);
}
}