aboutsummaryrefslogtreecommitdiffstats
path: root/g10/keydb.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/keydb.c')
-rw-r--r--g10/keydb.c189
1 files changed, 172 insertions, 17 deletions
diff --git a/g10/keydb.c b/g10/keydb.c
index ab727b6c6..acd7f8a43 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -616,6 +616,97 @@ unlock_all (KEYDB_HANDLE hd)
}
+static gpg_error_t
+parse_keyblock_image (iobuf_t iobuf, kbnode_t *r_keyblock)
+{
+ gpg_error_t err;
+ PACKET *pkt;
+ kbnode_t keyblock = NULL;
+ kbnode_t node;
+ int in_cert, save_mode;
+
+ *r_keyblock = NULL;
+
+ pkt = xtrymalloc (sizeof *pkt);
+ if (!pkt)
+ return gpg_error_from_syserror ();
+ init_packet (pkt);
+ save_mode = set_packet_list_mode (0);
+ in_cert = 0;
+ while ((err = parse_packet (iobuf, pkt)) != -1)
+ {
+ if (gpg_err_code (err) == GPG_ERR_UNKNOWN_PACKET)
+ {
+ free_packet (pkt);
+ init_packet (pkt);
+ continue;
+ }
+ if (err)
+ {
+ log_error ("parse_keyblock_image: read error: %s\n",
+ gpg_strerror (err));
+ err = gpg_error (GPG_ERR_INV_KEYRING);
+ break;
+ }
+ if (pkt->pkttype == PKT_COMPRESSED)
+ {
+ log_error ("skipped compressed packet in keybox blob\n");
+ free_packet(pkt);
+ init_packet(pkt);
+ continue;
+ }
+ if (pkt->pkttype == PKT_RING_TRUST)
+ {
+ log_info ("skipped ring trust packet in keybox blob\n");
+ free_packet(pkt);
+ init_packet(pkt);
+ continue;
+ }
+
+ if (!in_cert && pkt->pkttype != PKT_PUBLIC_KEY)
+ {
+ log_error ("error: 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");
+ err = gpg_error (GPG_ERR_INV_KEYRING);
+ break;
+ }
+ in_cert = 1;
+
+ node = new_kbnode (pkt);
+ if (!keyblock)
+ keyblock = node;
+ else
+ add_kbnode (keyblock, node);
+ pkt = xtrymalloc (sizeof *pkt);
+ if (!pkt)
+ {
+ err = gpg_error_from_syserror ();
+ break;
+ }
+ init_packet (pkt);
+ }
+ set_packet_list_mode (save_mode);
+
+ if (err == -1 && keyblock)
+ err = 0; /* Got the entire keyblock. */
+
+ if (err)
+ release_kbnode (keyblock);
+ else
+ *r_keyblock = keyblock;
+ free_packet (pkt);
+ xfree (pkt);
+ return err;
+}
+
+
/*
* Return the last found keyring. Caller must free it.
* The returned keyblock has the kbode flag bit 0 set for the node with
@@ -627,6 +718,8 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
{
gpg_error_t err = 0;
+ *ret_kb = NULL;
+
if (!hd)
return gpg_error (GPG_ERR_INV_ARG);
@@ -641,16 +734,66 @@ keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb)
case KEYDB_RESOURCE_TYPE_KEYRING:
err = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb);
break;
- /* case KEYDB_RESOURCE_TYPE_KEYBOX: */
- /* err = keybox_get_keyblock (hd->active[hd->found].u.kb, ret_kb); */
- /* if (!err) */
- /* err = parse_keyblock (image, imagelen) */
- /* break; */
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ {
+ iobuf_t iobuf;
+
+ err = keybox_get_keyblock (hd->active[hd->found].u.kb, &iobuf);
+ if (!err)
+ {
+ err = parse_keyblock_image (iobuf, ret_kb);
+ iobuf_close (iobuf);
+ }
+ }
+ break;
}
return err;
}
+
+/* Build a keyblock image from KEYBLOCK. Returns 0 on success and
+ only then stores a new iobuf object at R_IOBUF. */
+static gpg_error_t
+build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf)
+{
+ gpg_error_t err;
+ iobuf_t iobuf;
+ kbnode_t kbctx, node;
+
+ *r_iobuf = NULL;
+
+ iobuf = iobuf_temp ();
+ for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+ {
+ /* Make sure to use only packets valid on a keyblock. */
+ switch (node->pkt->pkttype)
+ {
+ case PKT_PUBLIC_KEY:
+ case PKT_PUBLIC_SUBKEY:
+ case PKT_SIGNATURE:
+ case PKT_USER_ID:
+ case PKT_ATTRIBUTE:
+ /* Note that we don't want the ring trust packets. They are
+ not useful. */
+ break;
+ default:
+ continue;
+ }
+
+ err = build_packet (iobuf, node->pkt);
+ if (err)
+ {
+ iobuf_close (iobuf);
+ return err;
+ }
+ }
+
+ *r_iobuf = iobuf;
+ return 0;
+}
+
+
/*
* Update the current keyblock with the keyblock KB
*/
@@ -699,7 +842,7 @@ keydb_update_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
gpg_error_t
keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
{
- int rc;
+ gpg_error_t err;
int idx;
if (!hd)
@@ -715,27 +858,39 @@ keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb)
else
return gpg_error (GPG_ERR_GENERAL);
- rc = lock_all (hd);
- if (rc)
- return rc;
+ err = lock_all (hd);
+ if (err)
+ return err;
switch (hd->active[idx].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_insert_keyblock (hd->active[idx].u.kr, kb);
+ err = keyring_insert_keyblock (hd->active[idx].u.kr, kb);
+ break;
+ case KEYDB_RESOURCE_TYPE_KEYBOX:
+ { /* We need to turn our kbnode_t list of packets into a proper
+ keyblock first. This is required by the OpenPGP key parser
+ included in the keybox code. Eventually we can change this
+ kludge to have the caller pass the image. */
+ iobuf_t iobuf;
+
+ err = build_keyblock_image (kb, &iobuf);
+ if (!err)
+ {
+ err = keybox_insert_keyblock (hd->active[idx].u.kb,
+ iobuf_get_temp_buffer (iobuf),
+ iobuf_get_temp_length (iobuf));
+ iobuf_close (iobuf);
+ }
+ }
break;
- /* case KEYDB_RESOURCE_TYPE_KEYBOX: */
- /* rc = build_keyblock (kb, &image, &imagelen); */
- /* if (!rc) */
- /* rc = keybox_insert_keyblock (hd->active[idx].u.kb, image, imagelen); */
- /* break; */
}
unlock_all (hd);
- return rc;
+ return err;
}