From 5499942571a88a1223a7318992605c6d29858866 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 15 Nov 2013 15:54:31 +0100 Subject: [PATCH] kbx: Implement update operation for OpenPGP keyblocks. * kbx/keybox-update.c (keybox_update_keyblock): Implement. * kbx/keybox-search.c (get_blob_flags): Move to ... * kbx/keybox-defs.h (blob_get_type): here. * kbx/keybox-file.c (_keybox_read_blob2): Fix calling without R_BLOB. * g10/keydb.c (build_keyblock_image): Allow calling without R_SIGSTATUS. (keydb_update_keyblock): Implement for keybox. * kbx/keybox-dump.c (_keybox_dump_blob): Fix printing of the unhashed size. Print "does not expire" also on 64 bit platforms. Signed-off-by: Werner Koch --- g10/keydb.c | 68 +++++++++++++++++++++++++++++---------------- kbx/keybox-blob.c | 5 ++-- kbx/keybox-defs.h | 16 ++++++++++- kbx/keybox-dump.c | 4 +-- kbx/keybox-file.c | 5 ++-- kbx/keybox-search.c | 13 --------- kbx/keybox-update.c | 45 +++++++++++++++++++++++++++--- 7 files changed, 108 insertions(+), 48 deletions(-) diff --git a/g10/keydb.c b/g10/keydb.c index 79ab5afc6..9085012f7 100644 --- a/g10/keydb.c +++ b/g10/keydb.c @@ -1,6 +1,7 @@ /* keydb.c - key database dispatcher * Copyright (C) 2001, 2002, 2003, 2004, 2005, * 2008, 2009, 2011, 2013 Free Software Foundation, Inc. + * Coyrright (C) 2013 Werner Koch * * This file is part of GnuPG. * @@ -896,18 +897,24 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus) u32 *sigstatus; *r_iobuf = NULL; - *r_sigstatus = NULL; + if (r_sigstatus) + *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 (); + if (r_sigstatus) + { + 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 (); + } + else + sigstatus = NULL; iobuf = iobuf_temp (); for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));) @@ -940,8 +947,8 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus) PKT_signature *sig = node->pkt->pkt.signature; n_sigs++; - /* Fixme: Detect tye "missing key" status. */ - if (sig->flags.checked) + /* Fixme: Detect the "missing key" status. */ + if (sig->flags.checked && sigstatus) { if (sig->flags.valid) { @@ -957,10 +964,12 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus) } } } - sigstatus[0] = n_sigs; + if (sigstatus) + sigstatus[0] = n_sigs; *r_iobuf = iobuf; - *r_sigstatus = sigstatus; + if (r_sigstatus) + *r_sigstatus = sigstatus; return 0; } @@ -971,7 +980,7 @@ build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus) gpg_error_t keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb) { - gpg_error_t rc; + gpg_error_t err; if (!hd) return gpg_error (GPG_ERR_INV_ARG); @@ -984,28 +993,36 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb) if (opt.dry_run) return 0; - rc = lock_all (hd); - if (rc) - return rc; + err = lock_all (hd); + if (err) + return err; switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: - rc = gpg_error (GPG_ERR_GENERAL); /* oops */ + err = gpg_error (GPG_ERR_GENERAL); /* oops */ break; case KEYDB_RESOURCE_TYPE_KEYRING: - rc = keyring_update_keyblock (hd->active[hd->found].u.kr, kb); + err = keyring_update_keyblock (hd->active[hd->found].u.kr, kb); + break; + case KEYDB_RESOURCE_TYPE_KEYBOX: + { + iobuf_t iobuf; + + err = build_keyblock_image (kb, &iobuf, NULL); + if (!err) + { + err = keybox_update_keyblock (hd->active[hd->found].u.kb, + iobuf_get_temp_buffer (iobuf), + iobuf_get_temp_length (iobuf)); + iobuf_close (iobuf); + } + } break; - /* case KEYDB_RESOURCE_TYPE_KEYRING: */ - /* rc = build_keyblock (kb, &image, &imagelen); */ - /* if (!rc) */ - /* rc = keybox_update_keyblock (hd->active[hd->found].u.kb, */ - /* image, imagelen); */ - /* break; */ } unlock_all (hd); - return rc; + return err; } @@ -1197,6 +1214,9 @@ keydb_rebuild_caches (int noisy) log_error (_("failed to rebuild keyring cache: %s\n"), g10_errstr (rc)); break; + case KEYDB_RESOURCE_TYPE_KEYBOX: + /* N/A. */ + break; } } } diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c index 64935275e..a38f991a9 100644 --- a/kbx/keybox-blob.c +++ b/kbx/keybox-blob.c @@ -120,8 +120,9 @@ - bN Arbitrary space for example used to store data which is not part of the keyblock or certificate. For example the v3 key IDs go here. - - bN Space for the keyblock or certifciate. - - bN RFU + - bN Space for the keyblock or certificate. + - bN RFU. This is the remaining space after keyblock and before + the checksum. Is is not covered by the checksum. - b20 SHA-1 checksum (useful for KS syncronisation?) Note, that KBX versions before GnuPG 2.1 used an MD5 checksum. However it was only created but never checked. diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h index ad8e49d3f..f79c093fd 100644 --- a/kbx/keybox-defs.h +++ b/kbx/keybox-defs.h @@ -1,4 +1,4 @@ -/* keybox-defs.h - interal Keybox defintions +/* keybox-defs.h - internal Keybox definitions * Copyright (C) 2001, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -193,6 +193,20 @@ gpg_err_code_t _keybox_get_flag_location (const unsigned char *buffer, int what, size_t *flag_off, size_t *flag_size); +static inline int +blob_get_type (KEYBOXBLOB blob) +{ + const unsigned char *buffer; + size_t length; + + buffer = _keybox_get_blob_image (blob, &length); + if (length < 32) + return -1; /* blob too short */ + + return buffer[4]; +} + + /*-- keybox-dump.c --*/ int _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp); int _keybox_dump_file (const char *filename, int stats_only, FILE *outfp); diff --git a/kbx/keybox-dump.c b/kbx/keybox-dump.c index 1af6a9cba..af9052d69 100644 --- a/kbx/keybox-dump.c +++ b/kbx/keybox-dump.c @@ -245,7 +245,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) || rawdata_len + 4 > length || rawdata_off+rawdata_len + 4 > length) fprintf (fp, "[Error: raw data larger than blob]\n"); - unhashed = get32 (buffer + rawdata_off + rawdata_len); + unhashed = length - rawdata_off - rawdata_len; fprintf (fp, "Unhashed: %lu\n", unhashed); nkeys = get16 (buffer + 16); @@ -378,7 +378,7 @@ _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp) fputs ("[bad signature]", fp); else if (sflags < 0x10000000) fprintf (fp, "[bad flag %0lx]", sflags); - else if (sflags == 0xffffffff) + else if (sflags == (ulong)(-1)) fputs ("[good - does not expire]", fp ); else fprintf (fp, "[good - expires at %lu]", sflags); diff --git a/kbx/keybox-file.c b/kbx/keybox-file.c index 027bcf8d7..f72099348 100644 --- a/kbx/keybox-file.c +++ b/kbx/keybox-file.c @@ -43,7 +43,7 @@ ftello (FILE *stream) /* Read a block at the current postion and return it in r_blob. - r_blob may be NULL to simply skip the current block */ + r_blob may be NULL to simply skip the current block. */ int _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted) { @@ -55,7 +55,8 @@ _keybox_read_blob2 (KEYBOXBLOB *r_blob, FILE *fp, int *skipped_deleted) *skipped_deleted = 0; again: - *r_blob = NULL; + if (r_blob) + *r_blob = NULL; off = ftello (fp); if (off == (off_t)-1) return gpg_error_from_syserror (); diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c index 5e6432fa6..798079488 100644 --- a/kbx/keybox-search.c +++ b/kbx/keybox-search.c @@ -65,19 +65,6 @@ get16 (const byte *buffer) -static inline int -blob_get_type (KEYBOXBLOB blob) -{ - const unsigned char *buffer; - size_t length; - - buffer = _keybox_get_blob_image (blob, &length); - if (length < 32) - return -1; /* blob too short */ - - return buffer[4]; -} - static inline unsigned int blob_get_blob_flags (KEYBOXBLOB blob) { diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c index 1fdf4351c..6ade9e79c 100644 --- a/kbx/keybox-update.c +++ b/kbx/keybox-update.c @@ -425,10 +425,47 @@ keybox_insert_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen, gpg_error_t keybox_update_keyblock (KEYBOX_HANDLE hd, const void *image, size_t imagelen) { - (void)hd; - (void)image; - (void)imagelen; - return gpg_error (GPG_ERR_NOT_IMPLEMENTED); + gpg_error_t err; + const char *fname; + off_t off; + KEYBOXBLOB blob; + size_t nparsed; + struct _keybox_openpgp_info info; + + if (!hd || !image || !imagelen) + return gpg_error (GPG_ERR_INV_VALUE); + if (!hd->found.blob) + return gpg_error (GPG_ERR_NOTHING_FOUND); + if (blob_get_type (hd->found.blob) != BLOBTYPE_PGP) + return gpg_error (GPG_ERR_WRONG_BLOB_TYPE); + fname = hd->kb->fname; + if (!fname) + return gpg_error (GPG_ERR_INV_HANDLE); + + off = _keybox_get_blob_fileoffset (hd->found.blob); + if (off == (off_t)-1) + return gpg_error (GPG_ERR_GENERAL); + + /* Close this the file so that we do no mess up the position for a + next search. */ + _keybox_close_file (hd); + + /* Build a new blob. */ + err = _keybox_parse_openpgp (image, imagelen, &nparsed, &info); + if (err) + return err; + assert (nparsed <= imagelen); + err = _keybox_create_openpgp_blob (&blob, &info, image, imagelen, + NULL, hd->ephemeral); + _keybox_destroy_openpgp_info (&info); + + /* Update the keyblock. */ + if (!err) + { + err = blob_filecopy (FILECOPY_UPDATE, fname, blob, hd->secret, off); + _keybox_release_blob (blob); + } + return err; }