aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/armor.c22
-rw-r--r--g10/build-packet.c50
-rw-r--r--g10/card-util.c24
-rw-r--r--g10/compress.c4
-rw-r--r--g10/encrypt.c4
-rw-r--r--g10/export.c934
-rw-r--r--g10/free-packet.c1
-rw-r--r--g10/getkey.c148
-rw-r--r--g10/gpg.c134
-rw-r--r--g10/gpgv.c24
-rw-r--r--g10/import.c507
-rw-r--r--g10/kbnode.c4
-rw-r--r--g10/keydb.c1
-rw-r--r--g10/keydb.h22
-rw-r--r--g10/keyedit.c271
-rw-r--r--g10/keygen.c23
-rw-r--r--g10/keylist.c16
-rw-r--r--g10/keyserver.c6
-rw-r--r--g10/main.h15
-rw-r--r--g10/mainproc.c37
-rw-r--r--g10/options.h10
-rw-r--r--g10/packet.h5
-rw-r--r--g10/parse-packet.c20
-rw-r--r--g10/pkclist.c99
-rw-r--r--g10/plaintext.c15
-rw-r--r--g10/revoke.c10
-rw-r--r--g10/server.c6
-rw-r--r--g10/sign.c16
-rw-r--r--g10/t-keydb-get-keyblock.c2
-rw-r--r--g10/t-keydb.c25
-rw-r--r--g10/t-stutter.c1
-rw-r--r--g10/test-stubs.c20
-rw-r--r--g10/textfilter.c1
-rw-r--r--g10/trustdb.c10
34 files changed, 1802 insertions, 685 deletions
diff --git a/g10/armor.c b/g10/armor.c
index fb7465595..9e58520a3 100644
--- a/g10/armor.c
+++ b/g10/armor.c
@@ -190,13 +190,18 @@ initialize(void)
is_initialized=1;
}
-/****************
- * Check whether this is an armored file or not See also
+
+/*
+ * Check whether this is an armored file. See also
* parse-packet.c for details on this code.
+ *
+ * Note that the buffer BUF needs to be at least 2 bytes long. If in
+ * doubt that the second byte to 0.
+ *
* Returns: True if it seems to be armored
*/
static int
-is_armored( const byte *buf )
+is_armored (const byte *buf)
{
int ctb, pkttype;
int indeterminate_length_allowed;
@@ -274,15 +279,17 @@ is_armored( const byte *buf )
int
use_armor_filter( IOBUF a )
{
- byte buf[1];
+ byte buf[2];
int n;
/* fixme: there might be a problem with iobuf_peek */
- n = iobuf_peek(a, buf, 1 );
+ n = iobuf_peek (a, buf, 2);
if( n == -1 )
return 0; /* EOF, doesn't matter whether armored or not */
if( !n )
return 1; /* can't check it: try armored */
+ if (n != 2)
+ return 0; /* short buffer */
return is_armored(buf);
}
@@ -530,7 +537,7 @@ check_input( armor_filter_context_t *afx, IOBUF a )
/* (the line is always a C string but maybe longer) */
if( *line == '\n' || ( len && (*line == '\r' && line[1]=='\n') ) )
;
- else if( !is_armored( line ) ) {
+ else if (len >= 2 && !is_armored (line)) {
afx->inp_checked = 1;
afx->inp_bypass = 1;
return 0;
@@ -1409,8 +1416,9 @@ unarmor_pump (UnarmorPump x, int c)
switch (x->state) {
case STA_init:
{
- byte tmp[1];
+ byte tmp[2];
tmp[0] = c;
+ tmp[1] = 0;
if ( is_armored (tmp) )
x->state = c == '-'? STA_first_dash : STA_wait_newline;
else {
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 2745734b4..86d42efe1 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -635,6 +635,7 @@ do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
write_header(out, ctb, calc_plaintext( pt ) );
log_assert (pt->mode == 'b' || pt->mode == 't' || pt->mode == 'u'
+ || pt->mode == 'm'
|| pt->mode == 'l' || pt->mode == '1');
iobuf_put(out, pt->mode );
iobuf_put(out, pt->namelen );
@@ -972,28 +973,49 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
sig->unhashed = newarea;
}
-/****************
+/*
* Put all the required stuff from SIG into subpackets of sig.
+ * PKSK is the signing key.
* Hmmm, should we delete those subpackets which are in a wrong area?
*/
void
-build_sig_subpkt_from_sig( PKT_signature *sig )
+build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
{
u32 u;
- byte buf[8];
+ byte buf[1+MAX_FINGERPRINT_LEN];
+ size_t fprlen;
- u = sig->keyid[0];
- buf[0] = (u >> 24) & 0xff;
- buf[1] = (u >> 16) & 0xff;
- buf[2] = (u >> 8) & 0xff;
- buf[3] = u & 0xff;
- u = sig->keyid[1];
- buf[4] = (u >> 24) & 0xff;
- buf[5] = (u >> 16) & 0xff;
- buf[6] = (u >> 8) & 0xff;
- buf[7] = u & 0xff;
- build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 );
+ /* For v4 keys we need to write the ISSUER subpacket. We do not
+ * want that for a future v5 format. */
+ if (pksk->version < 5)
+ {
+ u = sig->keyid[0];
+ buf[0] = (u >> 24) & 0xff;
+ buf[1] = (u >> 16) & 0xff;
+ buf[2] = (u >> 8) & 0xff;
+ buf[3] = u & 0xff;
+ u = sig->keyid[1];
+ buf[4] = (u >> 24) & 0xff;
+ buf[5] = (u >> 16) & 0xff;
+ buf[6] = (u >> 8) & 0xff;
+ buf[7] = u & 0xff;
+ build_sig_subpkt (sig, SIGSUBPKT_ISSUER, buf, 8);
+ }
+
+ /* For a future v5 keys we write the ISSUER_FPR subpacket. We
+ * also write that for a v4 key is experimental support for
+ * RFC4880bis is requested. */
+ if (pksk->version > 4 || opt.flags.rfc4880bis)
+ {
+ fingerprint_from_pk (pksk, buf+1, &fprlen);
+ if (fprlen == 20)
+ {
+ buf[0] = pksk->version;
+ build_sig_subpkt (sig, SIGSUBPKT_ISSUER_FPR, buf, 21);
+ }
+ }
+ /* Write the timestamp. */
u = sig->timestamp;
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;
diff --git a/g10/card-util.c b/g10/card-util.c
index be1a593e9..2cb44f996 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -733,28 +733,18 @@ fetch_url (ctrl_t ctrl)
log_error("error retrieving URL from card: %s\n",gpg_strerror(rc));
else
{
- struct keyserver_spec *spec=NULL;
-
rc=agent_scd_getattr("KEY-FPR",&info);
if(rc)
log_error("error retrieving key fingerprint from card: %s\n",
gpg_strerror(rc));
else if (info.pubkey_url && *info.pubkey_url)
- {
- spec = parse_keyserver_uri (info.pubkey_url, 1);
- if(spec && info.fpr1valid)
- {
- /* This is not perfectly right. Currently, all card
- fingerprints are 20 digits, but what about
- fingerprints for a future v5 key? We should get the
- length from somewhere lower in the code. In any
- event, the fpr/keyid is not meaningful for straight
- HTTP fetches, but using it allows the card to point
- to HKP and LDAP servers as well. */
- rc = keyserver_import_fprint (ctrl, info.fpr1, 20, spec);
- free_keyserver_spec(spec);
- }
- }
+ {
+ strlist_t sl = NULL;
+
+ add_to_strlist (&sl, info.pubkey_url);
+ rc = keyserver_fetch (ctrl, sl);
+ free_strlist (sl);
+ }
else if (info.fpr1valid)
{
rc = keyserver_import_fprint (ctrl, info.fpr1, 20, opt.keyserver);
diff --git a/g10/compress.c b/g10/compress.c
index bdddef134..c34beecf7 100644
--- a/g10/compress.c
+++ b/g10/compress.c
@@ -295,6 +295,10 @@ compress_filter( void *opaque, int control,
static void
release_context (compress_filter_context_t *ctx)
{
+ xfree(ctx->inbuf);
+ ctx->inbuf = NULL;
+ xfree(ctx->outbuf);
+ ctx->outbuf = NULL;
xfree (ctx);
}
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 57d24bef1..54a17c31e 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -335,7 +335,7 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
{
/* Note that PT has been initialized above in !no_literal mode. */
pt->timestamp = make_timestamp();
- pt->mode = opt.textmode? 't' : 'b';
+ pt->mode = opt.mimemode? 'm' : opt.textmode? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len;
pt->buf = inp;
@@ -674,7 +674,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (!opt.no_literal)
{
pt->timestamp = make_timestamp();
- pt->mode = opt.textmode ? 't' : 'b';
+ pt->mode = opt.mimemode? 'm' : opt.textmode ? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len;
pt->buf = inp;
diff --git a/g10/export.c b/g10/export.c
index b067376e1..92235fbf6 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -35,6 +35,10 @@
#include "i18n.h"
#include "membuf.h"
#include "host2net.h"
+#include "zb32.h"
+#include "recsel.h"
+#include "mbox-util.h"
+#include "init.h"
#include "trustdb.h"
#include "call-agent.h"
@@ -56,6 +60,16 @@ struct export_stats_s
};
+/* A global variable to store the selector created from
+ * --export-filter keep-uid=EXPR.
+ *
+ * FIXME: We should put this into the CTRL object but that requires a
+ * lot more changes right now.
+ */
+static recsel_expr_t export_keep_uid;
+
+
+
/* Local prototypes. */
static int do_export (ctrl_t ctrl, strlist_t users, int secret,
unsigned int options, export_stats_t stats);
@@ -63,8 +77,18 @@ static int do_export_stream (ctrl_t ctrl, iobuf_t out,
strlist_t users, int secret,
kbnode_t *keyblock_out, unsigned int options,
export_stats_t stats, int *any);
+static gpg_error_t print_pka_or_dane_records
+/**/ (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk,
+ const void *data, size_t datalen,
+ int print_pka, int print_dane);
+static void
+cleanup_export_globals (void)
+{
+ recsel_release (export_keep_uid);
+ export_keep_uid = NULL;
+}
/* Option parser for export options. See parse_options fro
@@ -84,6 +108,10 @@ parse_export_options(char *str,unsigned int *options,int noisy)
N_("remove unusable parts from key during export")},
{"export-minimal",EXPORT_MINIMAL|EXPORT_CLEAN,NULL,
N_("remove as much as possible from key during export")},
+
+ {"export-pka", EXPORT_PKA_FORMAT, NULL, NULL },
+ {"export-dane", EXPORT_DANE_FORMAT, NULL, NULL },
+
/* Aliases for backward compatibility */
{"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
{"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
@@ -100,6 +128,38 @@ parse_export_options(char *str,unsigned int *options,int noisy)
}
+/* Parse and set an export filter from string. STRING has the format
+ * "NAME=EXPR" with NAME being the name of the filter. Spaces before
+ * and after NAME are not allowed. If this function is called several
+ * times all expressions for the same NAME are concatenated.
+ * Supported filter names are:
+ *
+ * - keep-uid :: If the expression evaluates to true for a certain
+ * user ID packet, that packet and all it dependencies
+ * will be exported. The expression may use these
+ * variables:
+ *
+ * - uid :: The entire user ID.
+ * - mbox :: The mail box part of the user ID.
+ * - primary :: Evaluate to true for the primary user ID.
+ */
+gpg_error_t
+parse_and_set_export_filter (const char *string)
+{
+ gpg_error_t err;
+
+ /* Auto register the cleanup function. */
+ register_mem_cleanup_func (cleanup_export_globals);
+
+ if (!strncmp (string, "keep-uid=", 9))
+ err = recsel_parse_expr (&export_keep_uid, string+9);
+ else
+ err = gpg_error (GPG_ERR_INV_NAME);
+
+ return err;
+}
+
+
/* Create a new export stats object initialized to zero. On error
returns NULL and sets ERRNO. */
export_stats_t
@@ -265,7 +325,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
if (rc)
return rc;
- if ( opt.armor )
+ if ( opt.armor && !(options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)) )
{
afx = new_armor_context ();
afx->what = secret? 5 : 1;
@@ -1147,8 +1207,567 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
}
+/* Write KEYBLOCK either to stdout or to the file set with the
+ * --output option. This is a simplified version of do_export_stream
+ * which supports only a few export options. */
+gpg_error_t
+write_keyblock_to_output (kbnode_t keyblock, int with_armor,
+ unsigned int options)
+{
+ gpg_error_t err;
+ const char *fname;
+ iobuf_t out;
+ kbnode_t node;
+ armor_filter_context_t *afx = NULL;
+ iobuf_t out_help = NULL;
+ PKT_public_key *pk = NULL;
+
+ fname = opt.outfile? opt.outfile : "-";
+ if (is_secured_filename (fname) )
+ return gpg_error (GPG_ERR_EPERM);
+
+ out = iobuf_create (fname, 0);
+ if (!out)
+ {
+ err = gpg_error_from_syserror ();
+ log_error(_("can't create '%s': %s\n"), fname, gpg_strerror (err));
+ return err;
+ }
+ if (opt.verbose)
+ log_info (_("writing to '%s'\n"), iobuf_get_fname_nonnull (out));
+
+ if ((options & (EXPORT_PKA_FORMAT|EXPORT_DANE_FORMAT)))
+ {
+ with_armor = 0;
+ out_help = iobuf_temp ();
+ }
+
+ if (with_armor)
+ {
+ afx = new_armor_context ();
+ afx->what = 1;
+ push_armor_filter (afx, out);
+ }
+
+ for (node = keyblock; node; node = node->next)
+ {
+ if (is_deleted_kbnode (node) || node->pkt->pkttype == PKT_RING_TRUST)
+ continue;
+ if (!pk && (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_SECRET_KEY))
+ pk = node->pkt->pkt.public_key;
+
+ err = build_packet (out_help? out_help : out, node->pkt);
+ if (err)
+ {
+ log_error ("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, gpg_strerror (err) );
+ goto leave;
+ }
+ }
+ err = 0;
+
+ if (out_help && pk)
+ {
+ const void *data;
+ size_t datalen;
+
+ iobuf_flush_temp (out_help);
+ data = iobuf_get_temp_buffer (out_help);
+ datalen = iobuf_get_temp_length (out_help);
+
+ err = print_pka_or_dane_records (out,
+ keyblock, pk, data, datalen,
+ (options & EXPORT_PKA_FORMAT),
+ (options & EXPORT_DANE_FORMAT));
+ }
+
+ leave:
+ if (err)
+ iobuf_cancel (out);
+ else
+ iobuf_close (out);
+ iobuf_cancel (out_help);
+ release_armor_context (afx);
+ return err;
+}
+
+
+/* Helper for apply_keep_uid_filter. */
+static const char *
+filter_getval (void *cookie, const char *propname)
+{
+ kbnode_t node = cookie;
+ const char *result;
+
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ if (!strcmp (propname, "uid"))
+ result = node->pkt->pkt.user_id->name;
+ else if (!strcmp (propname, "mbox"))
+ {
+ if (!node->pkt->pkt.user_id->mbox)
+ {
+ node->pkt->pkt.user_id->mbox
+ = mailbox_from_userid (node->pkt->pkt.user_id->name);
+ }
+ return node->pkt->pkt.user_id->mbox;
+ }
+ else if (!strcmp (propname, "primary"))
+ result = node->pkt->pkt.user_id->is_primary? "1":"0";
+ else
+ result = NULL;
+ }
+ else
+ result = NULL;
+
+ return result;
+}
+
+/*
+ * Apply the keep-uid filter to the keyblock. The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+ kbnode_t node;
+
+ for (node = keyblock->next; node; node = node->next )
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ if (!recsel_select (selector, filter_getval, node))
+ {
+ /* log_debug ("keep-uid: deleting '%s'\n", */
+ /* node->pkt->pkt.user_id->name); */
+ /* The UID packet and all following packets up to the
+ * next UID or a subkey. */
+ delete_kbnode (node);
+ for (; node->next
+ && node->next->pkt->pkttype != PKT_USER_ID
+ && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+ && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+ node = node->next)
+ delete_kbnode (node->next);
+ }
+ /* else */
+ /* log_debug ("keep-uid: keeping '%s'\n", */
+ /* node->pkt->pkt.user_id->name); */
+ }
+ }
+}
+
+
+/* Print DANE or PKA records for all user IDs in KEYBLOCK to OUT. The
+ * data for the record is taken from (DATA,DATELEN). PK is the public
+ * key packet with the primary key. */
+static gpg_error_t
+print_pka_or_dane_records (iobuf_t out, kbnode_t keyblock, PKT_public_key *pk,
+ const void *data, size_t datalen,
+ int print_pka, int print_dane)
+{
+ gpg_error_t err = 0;
+ kbnode_t kbctx, node;
+ PKT_user_id *uid;
+ char *mbox = NULL;
+ char hashbuf[32];
+ char *hash = NULL;
+ char *domain;
+ const char *s;
+ unsigned int len;
+ estream_t fp = NULL;
+ char *hexdata = NULL;
+ char *hexfpr;
+
+ hexfpr = hexfingerprint (pk, NULL, 0);
+ hexdata = bin2hex (data, datalen, NULL);
+ if (!hexdata)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ ascii_strlwr (hexdata);
+ fp = es_fopenmem (0, "rw,samethread");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
+ {
+ if (node->pkt->pkttype != PKT_USER_ID)
+ continue;
+ uid = node->pkt->pkt.user_id;
+
+ if (uid->is_expired || uid->is_revoked)
+ continue;
+
+ xfree (mbox);
+ mbox = mailbox_from_userid (uid->name);
+ if (!mbox)
+ continue;
+
+ domain = strchr (mbox, '@');
+ *domain++ = 0;
+
+ if (print_pka)
+ {
+ es_fprintf (fp, "$ORIGIN _pka.%s.\n; %s\n; ", domain, hexfpr);
+ print_utf8_buffer (fp, uid->name, uid->len);
+ es_putc ('\n', fp);
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
+ xfree (hash);
+ hash = zb32_encode (hashbuf, 8*20);
+ if (!hash)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ len = strlen (hexfpr)/2;
+ es_fprintf (fp, "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n\n",
+ hash, 6 + len, len, hexfpr);
+ }
+
+ if (print_dane && hexdata)
+ {
+ es_fprintf (fp, "$ORIGIN _openpgpkey.%s.\n; %s\n; ", domain, hexfpr);
+ print_utf8_buffer (fp, uid->name, uid->len);
+ es_putc ('\n', fp);
+ gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, mbox, strlen (mbox));
+ xfree (hash);
+ hash = bin2hex (hashbuf, 28, NULL);
+ if (!hash)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ ascii_strlwr (hash);
+ len = strlen (hexdata)/2;
+ es_fprintf (fp, "%s TYPE61 \\# %u (\n", hash, len);
+ for (s = hexdata; ;)
+ {
+ es_fprintf (fp, "\t%.64s\n", s);
+ if (strlen (s) < 64)
+ break;
+ s += 64;
+ }
+ es_fputs ("\t)\n\n", fp);
+ }
+ }
+
+ /* Make sure it is a string and write it. */
+ es_fputc (0, fp);
+ {
+ void *vp;
+
+ if (es_fclose_snatch (fp, &vp, NULL))
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ fp = NULL;
+ iobuf_writestr (out, vp);
+ es_free (vp);
+ }
+ err = 0;
+
+ leave:
+ xfree (hash);
+ xfree (mbox);
+ es_fclose (fp);
+ xfree (hexdata);
+ xfree (hexfpr);
+ return err;
+}
+
+
+/* Helper for do_export_stream which writes one keyblock to OUT. */
+static gpg_error_t
+do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
+ iobuf_t out, int secret, unsigned int options,
+ export_stats_t stats, int *any,
+ KEYDB_SEARCH_DESC *desc, size_t ndesc,
+ size_t descindex, gcry_cipher_hd_t cipherhd)
+{
+ gpg_error_t err;
+ char *cache_nonce = NULL;
+ subkey_list_t subkey_list = NULL; /* Track already processed subkeys. */
+ int skip_until_subkey = 0;
+ int cleartext = 0;
+ char *hexgrip = NULL;
+ char *serialno = NULL;
+ PKT_public_key *pk;
+ u32 subkidbuf[2], *subkid;
+ kbnode_t kbctx, node;
+
+ for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+ {
+ if (skip_until_subkey)
+ {
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ skip_until_subkey = 0;
+ else
+ continue;
+ }
+
+ /* We used to use comment packets, but not any longer. In
+ * case we still have comments on a key, strip them here
+ * before we call build_packet(). */
+ if (node->pkt->pkttype == PKT_COMMENT)
+ continue;
+
+ /* Make sure that ring_trust packets never get exported. */
+ if (node->pkt->pkttype == PKT_RING_TRUST)
+ continue;
+
+ /* If exact is set, then we only export what was requested
+ * (plus the primary key, if the user didn't specifically
+ * request it). */
+ if (desc[descindex].exact && node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ if (!exact_subkey_match_p (desc+descindex, node))
+ {
+ /* Before skipping this subkey, check whether any
+ * other description wants an exact match on a
+ * subkey and include that subkey into the output
+ * too. Need to add this subkey to a list so that
+ * it won't get processed a second time.
+ *
+ * So the first step here is to check that list and
+ * skip in any case if the key is in that list.
+ *
+ * We need this whole mess because the import
+ * function of GnuPG < 2.1 is not able to merge
+ * secret keys and thus it is useless to output them
+ * as two separate keys and have import merge them.
+ */
+ if (subkey_in_list_p (subkey_list, node))
+ skip_until_subkey = 1; /* Already processed this one. */
+ else
+ {
+ size_t j;
+
+ for (j=0; j < ndesc; j++)
+ if (j != descindex && desc[j].exact
+ && exact_subkey_match_p (desc+j, node))
+ break;
+ if (!(j < ndesc))
+ skip_until_subkey = 1; /* No other one matching. */
+ }
+ }
+
+ if (skip_until_subkey)
+ continue;
+
+ /* Mark this one as processed. */
+ {
+ subkey_list_t tmp = new_subkey_list_item (node);
+ tmp->next = subkey_list;
+ subkey_list = tmp;
+ }
+ }
+
+ if (node->pkt->pkttype == PKT_SIGNATURE)
+ {
+ /* Do not export packets which are marked as not
+ * exportable. */
+ if (!(options & EXPORT_LOCAL_SIGS)
+ && !node->pkt->pkt.signature->flags.exportable)
+ continue; /* not exportable */
+
+ /* Do not export packets with a "sensitive" revocation key
+ * unless the user wants us to. Note that we do export
+ * these when issuing the actual revocation (see revoke.c). */
+ if (!(options & EXPORT_SENSITIVE_REVKEYS)
+ && node->pkt->pkt.signature->revkey)
+ {
+ int i;
+
+ for (i = 0; i < node->pkt->pkt.signature->numrevkeys; i++)
+ if ((node->pkt->pkt.signature->revkey[i].class & 0x40))
+ break;
+ if (i < node->pkt->pkt.signature->numrevkeys)
+ continue;
+ }
+ }
+
+ /* Don't export attribs? */
+ if (!(options & EXPORT_ATTRIBUTES)
+ && node->pkt->pkttype == PKT_USER_ID
+ && node->pkt->pkt.user_id->attrib_data)
+ {
+ /* Skip until we get to something that is not an attrib or a
+ * signature on an attrib. */
+ while (kbctx->next && kbctx->next->pkt->pkttype == PKT_SIGNATURE)
+ kbctx = kbctx->next;
+
+ continue;
+ }
+
+ if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
+ {
+ pk = node->pkt->pkt.public_key;
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+ subkid = NULL;
+ else
+ {
+ keyid_from_pk (pk, subkidbuf);
+ subkid = subkidbuf;
+ }
+
+ if (pk->seckey_info)
+ {
+ log_error ("key %s: oops: seckey_info already set"
+ " - skipped\n", keystr_with_sub (keyid, subkid));
+ skip_until_subkey = 1;
+ continue;
+ }
+
+ xfree (hexgrip);
+ err = hexkeygrip_from_pk (pk, &hexgrip);
+ if (err)
+ {
+ log_error ("key %s: error computing keygrip: %s"
+ " - skipped\n", keystr_with_sub (keyid, subkid),
+ gpg_strerror (err));
+ skip_until_subkey = 1;
+ err = 0;
+ continue;
+ }
+
+ xfree (serialno);
+ serialno = NULL;
+ if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
+ {
+ /* We are asked not to export the secret parts of the
+ * primary key. Make up an error code to create the
+ * stub. */
+ err = GPG_ERR_NOT_FOUND;
+ }
+ else
+ err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext);
+
+ if ((!err && serialno)
+ && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
+ {
+ /* It does not make sense to export a key with its
+ * primary key on card using a non-key stub. Thus we
+ * skip those keys when used with --export-secret-subkeys. */
+ log_info (_("key %s: key material on-card - skipped\n"),
+ keystr_with_sub (keyid, subkid));
+ skip_until_subkey = 1;
+ }
+ else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
+ || (!err && serialno))
+ {
+ /* Create a key stub. */
+ struct seckey_info *ski;
+ const char *s;
+
+ pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
+ if (!ski)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+
+ ski->is_protected = 1;
+ if (err)
+ ski->s2k.mode = 1001; /* GNU dummy (no secret key). */
+ else
+ {
+ ski->s2k.mode = 1002; /* GNU-divert-to-card. */
+ for (s=serialno; sizeof (ski->ivlen) && *s && s[1];
+ ski->ivlen++, s += 2)
+ ski->iv[ski->ivlen] = xtoi_2 (s);
+ }
+
+ err = build_packet (out, node->pkt);
+ if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+ {
+ stats->exported++;
+ print_status_exported (node->pkt->pkt.public_key);
+ }
+ }
+ else if (!err)
+ {
+ err = receive_seckey_from_agent (ctrl, cipherhd,
+ cleartext, &cache_nonce,
+ hexgrip, pk);
+ if (err)
+ {
+ if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
+ goto leave;
+ skip_until_subkey = 1;
+ err = 0;
+ }
+ else
+ {
+ err = build_packet (out, node->pkt);
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY)
+ {
+ stats->exported++;
+ print_status_exported (node->pkt->pkt.public_key);
+ }
+ }
+ }
+ else
+ {
+ log_error ("key %s: error getting keyinfo from agent: %s"
+ " - skipped\n", keystr_with_sub (keyid, subkid),
+ gpg_strerror (err));
+ skip_until_subkey = 1;
+ err = 0;
+ }
+
+ xfree (pk->seckey_info);
+ pk->seckey_info = NULL;
+ {
+ int i;
+ for (i = pubkey_get_npkey (pk->pubkey_algo);
+ i < pubkey_get_nskey (pk->pubkey_algo); i++)
+ {
+ gcry_mpi_release (pk->pkey[i]);
+ pk->pkey[i] = NULL;
+ }
+ }
+ }
+ else /* Not secret or common packets. */
+ {
+ err = build_packet (out, node->pkt);
+ if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
+ {
+ stats->exported++;
+ print_status_exported (node->pkt->pkt.public_key);
+ }
+ }
+
+ if (err)
+ {
+ log_error ("build_packet(%d) failed: %s\n",
+ node->pkt->pkttype, gpg_strerror (err));
+ goto leave;
+ }
+
+ if (!skip_until_subkey)
+ *any = 1;
+ }
+
+ leave:
+ release_subkey_list (subkey_list);
+ xfree (serialno);
+ xfree (hexgrip);
+ xfree (cache_nonce);
+ return err;
+}
+
+
/* Export the keys identified by the list of strings in USERS to the
- stream OUT. If Secret is false public keys will be exported. With
+ stream OUT. If SECRET is false public keys will be exported. With
secret true secret keys will be exported; in this case 1 means the
entire secret keyblock and 2 only the subkeys. OPTIONS are the
export options to apply. If KEYBLOCK_OUT is not NULL, AND the exit
@@ -1163,17 +1782,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
{
gpg_error_t err = 0;
PACKET pkt;
- KBNODE keyblock = NULL;
- KBNODE kbctx, node;
+ kbnode_t keyblock = NULL;
+ kbnode_t node;
size_t ndesc, descindex;
KEYDB_SEARCH_DESC *desc = NULL;
- subkey_list_t subkey_list = NULL; /* Track already processed subkeys. */
KEYDB_HANDLE kdbhd;
strlist_t sl;
gcry_cipher_hd_t cipherhd = NULL;
- char *cache_nonce = NULL;
struct export_stats_s dummystats;
- int cleartext = 0;
+ iobuf_t out_help = NULL;
if (!stats)
stats = &dummystats;
@@ -1183,10 +1800,14 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
if (!kdbhd)
return gpg_error_from_syserror ();
- /* For the DANE format override the options. */
- if ((options & EXPORT_DANE_FORMAT))
- options = (EXPORT_DANE_FORMAT | EXPORT_MINIMAL | EXPORT_CLEAN);
-
+ /* For the PKA and DANE format open a helper iobuf and for DANE
+ * enforce some options. */
+ if ((options & (EXPORT_PKA_FORMAT | EXPORT_DANE_FORMAT)))
+ {
+ out_help = iobuf_temp ();
+ if ((options & EXPORT_DANE_FORMAT))
+ options |= EXPORT_MINIMAL | EXPORT_CLEAN;
+ }
if (!users)
{
@@ -1258,7 +1879,6 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
for (;;)
{
- int skip_until_subkey = 0;
u32 keyid[2];
PKT_public_key *pk;
@@ -1326,278 +1946,60 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
if ((options & EXPORT_CLEAN))
clean_key (keyblock, opt.verbose, (options&EXPORT_MINIMAL), NULL, NULL);
- /* And write it. */
- xfree (cache_nonce);
- cache_nonce = NULL;
- for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
+ if (export_keep_uid)
{
- if (skip_until_subkey)
- {
- if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
- skip_until_subkey = 0;
- else
- continue;
- }
-
- /* We used to use comment packets, but not any longer. In
- case we still have comments on a key, strip them here
- before we call build_packet(). */
- if (node->pkt->pkttype == PKT_COMMENT)
- continue;
-
- /* Make sure that ring_trust packets never get exported. */
- if (node->pkt->pkttype == PKT_RING_TRUST)
- continue;
-
- /* If exact is set, then we only export what was requested
- (plus the primary key, if the user didn't specifically
- request it). */
- if (desc[descindex].exact
- && node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
- {
- if (!exact_subkey_match_p (desc+descindex, node))
- {
- /* Before skipping this subkey, check whether any
- other description wants an exact match on a
- subkey and include that subkey into the output
- too. Need to add this subkey to a list so that
- it won't get processed a second time.
-
- So the first step here is to check that list and
- skip in any case if the key is in that list.
-
- We need this whole mess because the import
- function of GnuPG < 2.1 is not able to merge
- secret keys and thus it is useless to output them
- as two separate keys and have import merge them. */
- if (subkey_in_list_p (subkey_list, node))
- skip_until_subkey = 1; /* Already processed this one. */
- else
- {
- size_t j;
-
- for (j=0; j < ndesc; j++)
- if (j != descindex && desc[j].exact
- && exact_subkey_match_p (desc+j, node))
- break;
- if (!(j < ndesc))
- skip_until_subkey = 1; /* No other one matching. */
- }
- }
-
- if(skip_until_subkey)
- continue;
-
- /* Mark this one as processed. */
- {
- subkey_list_t tmp = new_subkey_list_item (node);
- tmp->next = subkey_list;
- subkey_list = tmp;
- }
- }
-
- if (node->pkt->pkttype == PKT_SIGNATURE)
- {
- /* Do not export packets which are marked as not
- exportable. */
- if (!(options&EXPORT_LOCAL_SIGS)
- && !node->pkt->pkt.signature->flags.exportable)
- continue; /* not exportable */
-
- /* Do not export packets with a "sensitive" revocation
- key unless the user wants us to. Note that we do
- export these when issuing the actual revocation
- (see revoke.c). */
- if (!(options&EXPORT_SENSITIVE_REVKEYS)
- && node->pkt->pkt.signature->revkey)
- {
- int i;
-
- for (i=0;i<node->pkt->pkt.signature->numrevkeys;i++)
- if ( (node->pkt->pkt.signature->revkey[i].class & 0x40))
- break;
-
- if (i < node->pkt->pkt.signature->numrevkeys)
- continue;
- }
- }
-
- /* Don't export attribs? */
- if (!(options&EXPORT_ATTRIBUTES)
- && node->pkt->pkttype == PKT_USER_ID
- && node->pkt->pkt.user_id->attrib_data )
- {
- /* Skip until we get to something that is not an attrib
- or a signature on an attrib */
- while (kbctx->next && kbctx->next->pkt->pkttype==PKT_SIGNATURE)
- kbctx = kbctx->next;
-
- continue;
- }
-
- if (secret && (node->pkt->pkttype == PKT_PUBLIC_KEY
- || node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
- {
- u32 subkidbuf[2], *subkid;
- char *hexgrip, *serialno;
-
- pk = node->pkt->pkt.public_key;
- if (node->pkt->pkttype == PKT_PUBLIC_KEY)
- subkid = NULL;
- else
- {
- keyid_from_pk (pk, subkidbuf);
- subkid = subkidbuf;
- }
-
- if (pk->seckey_info)
- {
- log_error ("key %s: oops: seckey_info already set"
- " - skipped\n", keystr_with_sub (keyid, subkid));
- skip_until_subkey = 1;
- continue;
- }
-
- err = hexkeygrip_from_pk (pk, &hexgrip);
- if (err)
- {
- log_error ("key %s: error computing keygrip: %s"
- " - skipped\n", keystr_with_sub (keyid, subkid),
- gpg_strerror (err));
- skip_until_subkey = 1;
- err = 0;
- continue;
- }
-
- if (secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
- {
- /* We are asked not to export the secret parts of
- the primary key. Make up an error code to create
- the stub. */
- err = GPG_ERR_NOT_FOUND;
- serialno = NULL;
- }
- else
- err = agent_get_keyinfo (ctrl, hexgrip, &serialno, &cleartext);
-
- if ((!err && serialno)
- && secret == 2 && node->pkt->pkttype == PKT_PUBLIC_KEY)
- {
- /* It does not make sense to export a key with its
- primary key on card using a non-key stub. Thus
- we skip those keys when used with
- --export-secret-subkeys. */
- log_info (_("key %s: key material on-card - skipped\n"),
- keystr_with_sub (keyid, subkid));
- skip_until_subkey = 1;
- }
- else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND
- || (!err && serialno))
- {
- /* Create a key stub. */
- struct seckey_info *ski;
- const char *s;
-
- pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
- if (!ski)
- {
- err = gpg_error_from_syserror ();
- xfree (hexgrip);
- goto leave;
- }
-
- ski->is_protected = 1;
- if (err)
- ski->s2k.mode = 1001; /* GNU dummy (no secret key). */
- else
- {
- ski->s2k.mode = 1002; /* GNU-divert-to-card. */
- for (s=serialno; sizeof (ski->ivlen) && *s && s[1];
- ski->ivlen++, s += 2)
- ski->iv[ski->ivlen] = xtoi_2 (s);
- }
-
- err = build_packet (out, node->pkt);
- if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
- {
- stats->exported++;
- print_status_exported (node->pkt->pkt.public_key);
- }
- }
- else if (!err)
- {
- err = receive_seckey_from_agent (ctrl, cipherhd,
- cleartext, &cache_nonce,
- hexgrip, pk);
- if (err)
- {
- if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
- goto leave;
- skip_until_subkey = 1;
- err = 0;
- }
- else
- {
- err = build_packet (out, node->pkt);
- if (node->pkt->pkttype == PKT_PUBLIC_KEY)
- {
- stats->exported++;
- print_status_exported (node->pkt->pkt.public_key);
- }
- }
- }
- else
- {
- log_error ("key %s: error getting keyinfo from agent: %s"
- " - skipped\n", keystr_with_sub (keyid, subkid),
- gpg_strerror (err));
- skip_until_subkey = 1;
- err = 0;
- }
-
- xfree (pk->seckey_info);
- pk->seckey_info = NULL;
- xfree (hexgrip);
- }
- else
- {
- err = build_packet (out, node->pkt);
- if (!err && node->pkt->pkttype == PKT_PUBLIC_KEY)
- {
- stats->exported++;
- print_status_exported (node->pkt->pkt.public_key);
- }
- }
-
-
- if (err)
- {
- log_error ("build_packet(%d) failed: %s\n",
- node->pkt->pkttype, gpg_strerror (err));
- goto leave;
- }
+ commit_kbnode (&keyblock);
+ apply_keep_uid_filter (keyblock, export_keep_uid);
+ commit_kbnode (&keyblock);
+ }
- if (!skip_until_subkey)
- *any = 1;
- }
+ /* And write it. */
+ err = do_export_one_keyblock (ctrl, keyblock, keyid,
+ out_help? out_help : out,
+ secret, options, stats, any,
+ desc, ndesc, descindex, cipherhd);
+ if (err)
+ break;
if (keyblock_out)
{
*keyblock_out = keyblock;
break;
}
+
+ if (out_help)
+ {
+ /* We want to write PKA or DANE records. OUT_HELP has the
+ * keyblock and we print a record for each uid to OUT. */
+ const void *data;
+ size_t datalen;
+
+ iobuf_flush_temp (out_help);
+ data = iobuf_get_temp_buffer (out_help);
+ datalen = iobuf_get_temp_length (out_help);
+
+ err = print_pka_or_dane_records (out,
+ keyblock, pk, data, datalen,
+ (options & EXPORT_PKA_FORMAT),
+ (options & EXPORT_DANE_FORMAT));
+ if (err)
+ goto leave;
+
+ iobuf_close (out_help);
+ out_help = iobuf_temp ();
+ }
+
}
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
err = 0;
leave:
+ iobuf_cancel (out_help);
gcry_cipher_close (cipherhd);
- release_subkey_list (subkey_list);
xfree(desc);
keydb_release (kdbhd);
if (err || !keyblock_out)
release_kbnode( keyblock );
- xfree (cache_nonce);
if( !*any )
log_info(_("WARNING: nothing exported\n"));
return err;
diff --git a/g10/free-packet.c b/g10/free-packet.c
index 3883f877a..516e9a145 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -311,6 +311,7 @@ free_user_id (PKT_user_id *uid)
free_attributes(uid);
xfree (uid->prefs);
xfree (uid->namehash);
+ xfree (uid->mbox);
xfree (uid);
}
diff --git a/g10/getkey.c b/g10/getkey.c
index ad0148e51..90fd175b4 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1,7 +1,7 @@
/* getkey.c - Get a key from the database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2008, 2010 Free Software Foundation, Inc.
- * Copyright (C) 2015 g10 Code GmbH
+ * Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -143,6 +143,11 @@ static void merge_selfsigs (kbnode_t keyblock);
static int lookup (getkey_ctx_t ctx,
kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
int want_secret);
+static kbnode_t finish_lookup (kbnode_t keyblock,
+ unsigned int req_usage, int want_exact,
+ unsigned int *r_flags);
+static void print_status_key_considered (kbnode_t keyblock, unsigned int flags);
+
#if 0
static void
@@ -659,12 +664,9 @@ get_pubkeys (ctrl_t ctrl,
static void
-pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
- KBNODE found_key)
+pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
{
- KBNODE a = found_key ? found_key : keyblock;
-
- (void) ctx;
+ kbnode_t a = found_key ? found_key : keyblock;
log_assert (a->pkt->pkttype == PKT_PUBLIC_KEY
|| a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
@@ -749,7 +751,7 @@ get_pubkey (PKT_public_key * pk, u32 * keyid)
rc = lookup (&ctx, &kb, &found_key, 0);
if (!rc)
{
- pk_from_block (&ctx, pk, kb, found_key);
+ pk_from_block (pk, kb, found_key);
}
getkey_end (&ctx);
release_kbnode (kb);
@@ -912,7 +914,7 @@ get_seckey (PKT_public_key *pk, u32 *keyid)
err = lookup (&ctx, &keyblock, &found_key, 1);
if (!err)
{
- pk_from_block (&ctx, pk, keyblock, found_key);
+ pk_from_block (pk, keyblock, found_key);
}
getkey_end (&ctx);
release_kbnode (keyblock);
@@ -1118,7 +1120,7 @@ key_byname (GETKEY_CTX *retctx, strlist_t namelist,
rc = lookup (ctx, ret_kb, &found_key, want_secret);
if (!rc && pk)
{
- pk_from_block (ctx, pk, *ret_kb, found_key);
+ pk_from_block (pk, *ret_kb, found_key);
}
release_kbnode (help_kb);
@@ -1457,6 +1459,53 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
}
+/* Get a public key from a file.
+ *
+ * PK is the buffer to store the key. The caller needs to make sure
+ * that PK->REQ_USAGE is valid. PK->REQ_USAGE is passed through to
+ * the lookup function and is a mask of PUBKEY_USAGE_SIG,
+ * PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. If this is non-zero, only
+ * keys with the specified usage will be returned.
+ *
+ * FNAME is the file name. That file should contain exactly one
+ * keyblock.
+ *
+ * This function returns 0 on success. Otherwise, an error code is
+ * returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
+ * is not found.
+ *
+ * The self-signed data has already been merged into the public key
+ * using merge_selfsigs. The caller must release the content of PK by
+ * calling release_public_key_parts (or, if PK was malloced, using
+ * free_public_key).
+ */
+gpg_error_t
+get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
+{
+ gpg_error_t err;
+ kbnode_t keyblock;
+ kbnode_t found_key;
+ unsigned int infoflags;
+
+ err = read_key_from_file (ctrl, fname, &keyblock);
+ if (!err)
+ {
+ /* Warning: node flag bits 0 and 1 should be preserved by
+ * merge_selfsigs. FIXME: Check whether this still holds. */
+ merge_selfsigs (keyblock);
+ found_key = finish_lookup (keyblock, pk->req_usage, 0, &infoflags);
+ print_status_key_considered (keyblock, infoflags);
+ if (found_key)
+ pk_from_block (pk, keyblock, found_key);
+ else
+ err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+ }
+
+ release_kbnode (keyblock);
+ return err;
+}
+
+
/* Lookup a key with the specified fingerprint.
*
* If PK is not NULL, the public key of the first result is returned
@@ -1513,7 +1562,7 @@ get_pubkey_byfprint (PKT_public_key *pk, kbnode_t *r_keyblock,
memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
rc = lookup (&ctx, &kb, &found_key, 0);
if (!rc && pk)
- pk_from_block (&ctx, pk, kb, found_key);
+ pk_from_block (pk, kb, found_key);
if (!rc && r_keyblock)
{
*r_keyblock = kb;
@@ -1903,7 +1952,7 @@ getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
rc = lookup (ctx, ret_keyblock, &found_key, ctx->want_secret);
if (!rc && pk && ret_keyblock)
- pk_from_block (ctx, pk, *ret_keyblock, found_key);
+ pk_from_block (pk, *ret_keyblock, found_key);
return rc;
}
@@ -3053,31 +3102,33 @@ merge_selfsigs (KBNODE keyblock)
/* See whether the key satisfies any additional requirements specified
- * in CTX. If so, return 1 and set CTX->FOUND_KEY to an appropriate
- * key or subkey. Otherwise, return 0 if there was no appropriate
- * key.
+ * in CTX. If so, return the node of an appropriate key or subkey.
+ * Otherwise, return NULL if there was no appropriate key.
*
* In case the primary key is not required, select a suitable subkey.
- * We need the primary key if PUBKEY_USAGE_CERT is set in
- * CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
- * is set in CTX->REQ_USAGE.
+ * We need the primary key if PUBKEY_USAGE_CERT is set in REQ_USAGE or
+ * we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG is set in
+ * REQ_USAGE.
*
* If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
- * are set in CTX->REQ_USAGE, we filter by the key's function.
- * Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
- * we only return a key if it is (at least) either a signing or a
+ * are set in REQ_USAGE, we filter by the key's function. Concretely,
+ * if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then we only
+ * return a key if it is (at least) either a signing or a
* certification key.
*
- * If CTX->REQ_USAGE is set, then we reject any keys that are not good
+ * If REQ_USAGE is set, then we reject any keys that are not good
* (i.e., valid, not revoked, not expired, etc.). This allows the
* getkey functions to be used for plain key listings.
*
* Sets the matched key's user id field (pk->user_id) to the user id
- * that matched the low-level search criteria or NULL. If R_FLAGS is
- * not NULL set certain flags for more detailed error reporting. Used
- * flags are:
+ * that matched the low-level search criteria or NULL.
+ *
+ * If R_FLAGS is not NULL set certain flags for more detailed error
+ * reporting. Used flags are:
+ *
* - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
* been revoked.
+ * - LOOKUP_NOT_SELECTED :: No suitable key found
*
* This function needs to handle several different cases:
*
@@ -3094,40 +3145,41 @@ merge_selfsigs (KBNODE keyblock)
*
*/
static kbnode_t
-finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
+finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
+ unsigned int *r_flags)
{
kbnode_t k;
- /* If CTX->EXACT is set, the key or subkey that actually matched the
+ /* If WANT_EXACT is set, the key or subkey that actually matched the
low-level search criteria. */
kbnode_t foundk = NULL;
/* The user id (if any) that matched the low-level search criteria. */
PKT_user_id *foundu = NULL;
-#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
- unsigned int req_usage = (ctx->req_usage & USAGE_MASK);
-
- /* Request the primary if we're certifying another key, and also
- if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
- do not understand signatures made by a signing subkey. PGP 8
- does. */
- int req_prim = ((ctx->req_usage & PUBKEY_USAGE_CERT)
- || ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)));
-
- u32 curtime = make_timestamp ();
-
u32 latest_date;
kbnode_t latest_key;
PKT_public_key *pk;
-
- log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+ int req_prim;
+ u32 curtime = make_timestamp ();
if (r_flags)
*r_flags = 0;
+#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
+ req_usage &= USAGE_MASK;
+
+ /* Request the primary if we're certifying another key, and also if
+ * signing data while --pgp6 or --pgp7 is on since pgp 6 and 7 do
+ * not understand signatures made by a signing subkey. PGP 8 does. */
+ req_prim = ((req_usage & PUBKEY_USAGE_CERT)
+ || ((PGP6 || PGP7) && (req_usage & PUBKEY_USAGE_SIG)));
+
+
+ log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+
/* For an exact match mark the primary or subkey that matched the
low-level search criteria. */
- if (ctx->exact)
+ if (want_exact)
{
for (k = keyblock; k; k = k->next)
{
@@ -3262,7 +3314,7 @@ finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
* primary key, or,
*
* - we're just considering the primary key. */
- if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
+ if ((!latest_key && !want_exact) || foundk == keyblock || req_prim)
{
if (DBG_LOOKUP && !foundk && !req_prim)
log_debug ("\tno suitable subkeys found - trying primary\n");
@@ -3300,10 +3352,12 @@ finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
{
if (DBG_LOOKUP)
log_debug ("\tno suitable key found - giving up\n");
+ if (r_flags)
+ *r_flags |= LOOKUP_NOT_SELECTED;
return NULL; /* Not found. */
}
-found:
+ found:
if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n",
(ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL));
@@ -3408,12 +3462,10 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
goto skip; /* No secret key available. */
/* Warning: node flag bits 0 and 1 should be preserved by
- * merge_selfsigs. For secret keys, premerge transferred the
- * keys to the keyblock. */
+ * merge_selfsigs. */
merge_selfsigs (keyblock);
- found_key = finish_lookup (ctx, keyblock, &infoflags);
- if (!found_key)
- infoflags |= LOOKUP_NOT_SELECTED;
+ found_key = finish_lookup (keyblock, ctx->req_usage, ctx->exact,
+ &infoflags);
print_status_key_considered (keyblock, infoflags);
if (found_key)
{
diff --git a/g10/gpg.c b/g10/gpg.c
index 1f2d41685..4232a840b 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -81,6 +81,8 @@ enum cmd_and_opt_values
aSym = 'c',
aDecrypt = 'd',
aEncr = 'e',
+ oRecipientFile = 'f',
+ oHiddenRecipientFile = 'F',
oInteractive = 'i',
aListKeys = 'k',
oDryRun = 'n',
@@ -118,6 +120,7 @@ enum cmd_and_opt_values
aQuickLSignKey,
aQuickAddUid,
aQuickAddKey,
+ aQuickRevUid,
aListConfig,
aListGcryptConfig,
aGPGConfList,
@@ -166,6 +169,7 @@ enum cmd_and_opt_values
aServer,
aTOFUPolicy,
+ oMimemode,
oTextmode,
oNoTextmode,
oExpert,
@@ -216,6 +220,7 @@ enum cmd_and_opt_values
oGnuPG,
oRFC2440,
oRFC4880,
+ oRFC4880bis,
oOpenPGP,
oPGP6,
oPGP7,
@@ -246,6 +251,7 @@ enum cmd_and_opt_values
oNoMDCWarn,
oNoArmor,
oNoDefKeyring,
+ oNoKeyring,
oNoGreeting,
oNoTTY,
oNoOptions,
@@ -298,7 +304,9 @@ enum cmd_and_opt_values
oKeyServer,
oKeyServerOptions,
oImportOptions,
+ oImportFilter,
oExportOptions,
+ oExportFilter,
oListOptions,
oVerifyOptions,
oTempDir,
@@ -430,6 +438,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aQuickAddUid, "quick-adduid",
N_("quickly add a new user-id")),
ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"),
+ ARGPARSE_c (aQuickRevUid, "quick-revuid",
+ N_("quickly revoke a user-id")),
ARGPARSE_c (aFullKeygen, "full-gen-key" ,
N_("full featured key pair generation")),
ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")),
@@ -499,6 +509,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"),
+ ARGPARSE_s_s (oRecipientFile, "recipient-file", "@"),
+ ARGPARSE_s_s (oHiddenRecipientFile, "hidden-recipient-file", "@"),
ARGPARSE_s_s (oRecipient, "remote-user", "@"), /* (old option name) */
ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"),
ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", "@"),
@@ -521,7 +533,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"),
ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"),
- ARGPARSE_s_n (oTextmodeShort, NULL, "@"),
+ ARGPARSE_s_n (oMimemode, "mimemode", "@"),
+ ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")),
ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")),
ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"),
@@ -568,7 +581,9 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oKeyServer, "keyserver", "@"),
ARGPARSE_s_s (oKeyServerOptions, "keyserver-options", "@"),
ARGPARSE_s_s (oImportOptions, "import-options", "@"),
+ ARGPARSE_s_s (oImportFilter, "import-filter", "@"),
ARGPARSE_s_s (oExportOptions, "export-options", "@"),
+ ARGPARSE_s_s (oExportFilter, "export-filter", "@"),
ARGPARSE_s_s (oListOptions, "list-options", "@"),
ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
@@ -599,6 +614,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"),
ARGPARSE_s_n (oRFC2440, "rfc2440", "@"),
ARGPARSE_s_n (oRFC4880, "rfc4880", "@"),
+ ARGPARSE_s_n (oRFC4880bis, "rfc4880bis", "@"),
ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")),
ARGPARSE_s_n (oPGP6, "pgp6", "@"),
ARGPARSE_s_n (oPGP7, "pgp7", "@"),
@@ -672,6 +688,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oNoArmor, "no-armor", "@"),
ARGPARSE_s_n (oNoArmor, "no-armour", "@"),
ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"),
+ ARGPARSE_s_n (oNoKeyring, "no-keyring", "@"),
ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"),
ARGPARSE_s_n (oNoOptions, "no-options", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@"),
@@ -2028,6 +2045,7 @@ parse_tofu_db_format (const char *db_format)
}
}
+
/* This function called to initialized a new control object. It is
assumed that this object has been zeroed out before calling this
function. */
@@ -2432,6 +2450,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
+ case aQuickRevUid:
case aExportOwnerTrust:
case aImportOwnerTrust:
case aRebuildKeydbCaches:
@@ -2598,7 +2617,15 @@ main (int argc, char **argv)
}
break;
case oNoArmor: opt.no_armor=1; opt.armor=0; break;
- case oNoDefKeyring: default_keyring = 0; break;
+
+ case oNoDefKeyring:
+ if (default_keyring > 0)
+ default_keyring = 0;
+ break;
+ case oNoKeyring:
+ default_keyring = -1;
+ break;
+
case oNoGreeting: nogreeting = 1; break;
case oNoVerbose:
opt.verbose = 0;
@@ -2686,6 +2713,9 @@ main (int argc, char **argv)
/* Dummy so that gpg 1.4 conf files can work. Should
eventually be removed. */
break;
+ case oRFC4880bis:
+ opt.flags.rfc4880bis = 1;
+ /* fall thru. */
case oOpenPGP:
case oRFC4880:
/* This is effectively the same as RFC2440, but with
@@ -2814,46 +2844,56 @@ main (int argc, char **argv)
else
opt.s2k_count = 0; /* Auto-calibrate when needed. */
break;
- case oNoEncryptTo: opt.no_encrypt_to = 1; break;
- case oEncryptTo: /* store the recipient in the second list */
+
+ case oRecipient:
+ case oHiddenRecipient:
+ case oRecipientFile:
+ case oHiddenRecipientFile:
+ /* Store the recipient. Note that we also store the
+ * option as private data in the flags. This is achieved
+ * by shifting the option value to the left so to keep
+ * enough space for the flags. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
- sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
+ sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
+ if (pargs.r_opt == oHiddenRecipient
+ || pargs.r_opt == oHiddenRecipientFile)
+ sl->flags |= PK_LIST_HIDDEN;
+ if (pargs.r_opt == oRecipientFile
+ || pargs.r_opt == oHiddenRecipientFile)
+ sl->flags |= PK_LIST_FROM_FILE;
+ any_explicit_recipient = 1;
break;
- case oHiddenEncryptTo: /* store the recipient in the second list */
+
+ case oEncryptTo:
+ case oHiddenEncryptTo:
+ /* Store an additional recipient. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
- sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
- | PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
+ sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
+ if (pargs.r_opt == oHiddenEncryptTo)
+ sl->flags |= PK_LIST_HIDDEN;
break;
+
+ case oNoEncryptTo:
+ opt.no_encrypt_to = 1;
+ break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
break;
- case oRecipient: /* store the recipient */
- sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
- sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
- if (configfp)
- sl->flags |= PK_LIST_CONFIG;
- any_explicit_recipient = 1;
- break;
- case oHiddenRecipient: /* store the recipient with a flag */
- sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
- sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
- if (configfp)
- sl->flags |= PK_LIST_CONFIG;
- any_explicit_recipient = 1;
- break;
case oTrySecretKey:
add_to_strlist2 (&opt.secret_keys_to_try,
pargs.r.ret_str, utf8_strings);
break;
+ case oMimemode: opt.mimemode = opt.textmode = 1; break;
case oTextmodeShort: opt.textmode = 2; break;
case oTextmode: opt.textmode=1; break;
- case oNoTextmode: opt.textmode=0; break;
+ case oNoTextmode: opt.textmode=opt.mimemode=0; break;
+
case oExpert: opt.expert = 1; break;
case oNoExpert: opt.expert = 0; break;
case oDefSigExpire:
@@ -3022,6 +3062,11 @@ main (int argc, char **argv)
log_error(_("invalid import options\n"));
}
break;
+ case oImportFilter:
+ rc = parse_and_set_import_filter (pargs.r.ret_str);
+ if (rc)
+ log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
+ break;
case oExportOptions:
if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1))
{
@@ -3032,6 +3077,11 @@ main (int argc, char **argv)
log_error(_("invalid export options\n"));
}
break;
+ case oExportFilter:
+ rc = parse_and_set_export_filter (pargs.r.ret_str);
+ if (rc)
+ log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
+ break;
case oListOptions:
if(!parse_list_options(pargs.r.ret_str))
{
@@ -3399,6 +3449,13 @@ main (int argc, char **argv)
if( may_coredump && !opt.quiet )
log_info(_("WARNING: program may create a core file!\n"));
+ if (opt.flags.rfc4880bis)
+ log_info ("WARNING: using experimental features from RFC4880bis!\n");
+ else
+ {
+ opt.mimemode = 0; /* This will use text mode instead. */
+ }
+
if (eyes_only) {
if (opt.set_filename)
log_info(_("WARNING: %s overrides %s\n"),
@@ -3676,14 +3733,15 @@ main (int argc, char **argv)
if( opt.verbose > 1 )
set_packet_list_mode(1);
- /* Add the keyrings, but not for some special commands.
- We always need to add the keyrings if we are running under
- SELinux, this is so that the rings are added to the list of
- secured files. */
- if( ALWAYS_ADD_KEYRINGS
- || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest) )
+ /* Add the keyrings, but not for some special commands. We always
+ * need to add the keyrings if we are running under SELinux, this
+ * is so that the rings are added to the list of secured files.
+ * We do not add any keyring if --no-keyring has been used. */
+ if (default_keyring >= 0
+ && (ALWAYS_ADD_KEYRINGS
+ || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{
- if (!nrings || default_keyring) /* Add default ring. */
+ if (!nrings || default_keyring > 0) /* Add default ring. */
keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
KEYDB_RESOURCE_FLAG_DEFAULT);
for (sl = nrings; sl; sl = sl->next )
@@ -3777,6 +3835,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
+ case aQuickRevUid:
case aFullKeygen:
case aKeygen:
case aImport:
@@ -4196,6 +4255,18 @@ main (int argc, char **argv)
}
break;
+ case aQuickRevUid:
+ {
+ const char *uid, *uidtorev;
+
+ if (argc != 2)
+ wrong_args ("--quick-revuid USER-ID USER-ID-TO-REVOKE");
+ uid = *argv++; argc--;
+ uidtorev = *argv++; argc--;
+ keyedit_quick_revuid (ctrl, uid, uidtorev);
+ }
+ break;
+
case aFastImport:
opt.import_options |= IMPORT_FAST;
case aImport:
@@ -4648,7 +4719,6 @@ main (int argc, char **argv)
break;
case aListPackets:
- opt.list_packets=2;
default:
if( argc > 1 )
wrong_args(_("[filename]"));
@@ -4677,8 +4747,8 @@ main (int argc, char **argv)
}
}
if( cmd == aListPackets ) {
- set_packet_list_mode(1);
opt.list_packets=1;
+ set_packet_list_mode(1);
}
rc = proc_packets (ctrl, NULL, a );
if( rc )
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 2aed10c2a..d08dc5a7a 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -167,6 +167,8 @@ main( int argc, char **argv )
opt.command_fd = -1; /* no command fd */
opt.keyserver_options.options |= KEYSERVER_AUTO_KEY_RETRIEVE;
opt.trust_model = TM_ALWAYS;
+ opt.no_sig_cache = 1;
+ opt.flags.require_cross_cert = 1;
opt.batch = 1;
opt.weak_digests = NULL;
@@ -365,6 +367,17 @@ keyserver_import_keyid (u32 *keyid, void *dummy)
}
int
+keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
+ struct keyserver_spec *keyserver)
+{
+ (void)ctrl;
+ (void)fprint;
+ (void)fprint_len;
+ (void)keyserver;
+ return -1;
+}
+
+int
keyserver_import_cert (const char *name)
{
(void)name;
@@ -405,6 +418,17 @@ keyserver_import_ldap (const char *name)
return -1;
}
+
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+ (void)ctrl;
+ (void)fname;
+ (void)r_keyblock;
+ return -1;
+}
+
+
/* Stub:
* No encryption here but mainproc links to these functions.
*/
diff --git a/g10/import.c b/g10/import.c
index 7c0d1e2cc..375bd03f8 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -1,6 +1,6 @@
/* import.c - import a key into our key storage.
* Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
- * Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2014, 2016 Werner Koch
*
* This file is part of GnuPG.
*
@@ -35,9 +35,13 @@
#include "i18n.h"
#include "ttyio.h"
#include "status.h"
+#include "recsel.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "../common/membuf.h"
+#include "../common/init.h"
+#include "../common/mbox-util.h"
+
struct import_stats_s
{
@@ -60,6 +64,28 @@ struct import_stats_s
};
+/* Node flag to indicate that a user ID or a subkey has a
+ * valid self-signature. */
+#define NODE_GOOD_SELFSIG 1
+/* Node flag to indicate that a user ID or subkey has
+ * an invalid self-signature. */
+#define NODE_BAD_SELFSIG 2
+/* Node flag to indicate that the node shall be deleted. */
+#define NODE_DELETION_MARK 4
+/* A node flag used to temporary mark a node. */
+#define NODE_FLAG_A 8
+
+
+/* A global variable to store the selector created from
+ * --import-filter keep-uid=EXPR.
+ *
+ * FIXME: We should put this into the CTRL object but that requires a
+ * lot more changes right now.
+ */
+static recsel_expr_t import_keep_uid;
+
+
+
static int import (ctrl_t ctrl,
IOBUF inp, const char* fname, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
@@ -68,32 +94,36 @@ static int read_block (IOBUF a, PACKET **pending_pkt, kbnode_t *ret_root,
int *r_v3keys);
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static int import_one (ctrl_t ctrl,
- const char *fname, kbnode_t keyblock,
+ kbnode_t keyblock,
struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len,
unsigned int options, int from_sk, int silent,
import_screener_t screener, void *screener_arg);
-static int import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
+static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
struct import_stats_s *stats, int batch,
unsigned int options, int for_migration,
import_screener_t screener, void *screener_arg);
-static int import_revoke_cert( const char *fname, kbnode_t node,
- struct import_stats_s *stats);
-static int chk_self_sigs (const char *fname, kbnode_t keyblock,
- PKT_public_key *pk, u32 *keyid, int *non_self );
-static int delete_inv_parts (const char *fname, kbnode_t keyblock,
- u32 *keyid, unsigned int options );
-static int merge_blocks (const char *fname, kbnode_t keyblock_orig,
+static int import_revoke_cert (kbnode_t node, struct import_stats_s *stats);
+static int chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self);
+static int delete_inv_parts (kbnode_t keyblock,
+ u32 *keyid, unsigned int options);
+static int merge_blocks (kbnode_t keyblock_orig,
kbnode_t keyblock, u32 *keyid,
int *n_uids, int *n_sigs, int *n_subk );
-static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
- const char *fname, u32 *keyid );
-static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
- const char *fname, u32 *keyid );
-static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
- const char *fname, u32 *keyid );
-static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
- const char *fname, u32 *keyid );
+static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs);
+static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs);
+static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs);
+static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
+
+
+
+static void
+cleanup_import_globals (void)
+{
+ recsel_release (import_keep_uid);
+ import_keep_uid = NULL;
+}
+
int
parse_import_options(char *str,unsigned int *options,int noisy)
@@ -112,6 +142,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"fast-import",IMPORT_FAST,NULL,
N_("do not update the trustdb after import")},
+ {"import-show",IMPORT_SHOW,NULL,
+ N_("show key during import")},
+
{"merge-only",IMPORT_MERGE_ONLY,NULL,
N_("only accept updates to existing keys")},
@@ -121,6 +154,9 @@ parse_import_options(char *str,unsigned int *options,int noisy)
{"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
N_("remove as much as possible from key after import")},
+ {"import-export", IMPORT_EXPORT, NULL,
+ N_("run import filters and export key immediately")},
+
/* Aliases for backward compatibility */
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
{"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
@@ -137,6 +173,39 @@ parse_import_options(char *str,unsigned int *options,int noisy)
}
+/* Parse and set an import filter from string. STRING has the format
+ * "NAME=EXPR" with NAME being the name of the filter. Spaces before
+ * and after NAME are not allowed. If this function is all called
+ * several times all expressions for the same NAME are concatenated.
+ * Supported filter names are:
+ *
+ * - keep-uid :: If the expression evaluates to true for a certain
+ * user ID packet, that packet and all it dependencies
+ * will be imported. The expression may use these
+ * variables:
+ *
+ * - uid :: The entire user ID.
+ * - mbox :: The mail box part of the user ID.
+ * - primary :: Evaluate to true for the primary user ID.
+ */
+gpg_error_t
+parse_and_set_import_filter (const char *string)
+{
+ gpg_error_t err;
+
+ /* Auto register the cleanup function. */
+ register_mem_cleanup_func (cleanup_import_globals);
+
+ if (!strncmp (string, "keep-uid=", 9))
+ err = recsel_parse_expr (&import_keep_uid, string+9);
+ else
+ err = gpg_error (GPG_ERR_INV_NAME);
+
+ return err;
+}
+
+
+
import_stats_t
import_new_stats_handle (void)
{
@@ -151,6 +220,113 @@ import_release_stats_handle (import_stats_t p)
}
+/* Read a key from a file. Only the first key in the file is
+ * considered and stored at R_KEYBLOCK. FNAME is the name of the
+ * file.
+ */
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+ gpg_error_t err;
+ iobuf_t inp;
+ PACKET *pending_pkt = NULL;
+ kbnode_t keyblock = NULL;
+ u32 keyid[2];
+ int v3keys; /* Dummy */
+ int non_self; /* Dummy */
+
+ (void)ctrl;
+
+ *r_keyblock = NULL;
+
+ inp = iobuf_open (fname);
+ if (!inp)
+ err = gpg_error_from_syserror ();
+ else if (is_secured_file (iobuf_get_fd (inp)))
+ {
+ iobuf_close (inp);
+ inp = NULL;
+ err = gpg_error (GPG_ERR_EPERM);
+ }
+ else
+ err = 0;
+ if (err)
+ {
+ log_error (_("can't open '%s': %s\n"),
+ iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+ gpg_strerror (err));
+ if (gpg_err_code (err) == GPG_ERR_ENOENT)
+ err = gpg_error (GPG_ERR_NO_PUBKEY);
+ goto leave;
+ }
+
+ /* Push the armor filter. */
+ {
+ armor_filter_context_t *afx;
+ afx = new_armor_context ();
+ afx->only_keyblocks = 1;
+ push_armor_filter (afx, inp);
+ release_armor_context (afx);
+ }
+
+ /* Read the first non-v3 keyblock. */
+ while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
+ {
+ if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
+ break;
+ log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
+ release_kbnode (keyblock);
+ keyblock = NULL;
+ }
+ if (err)
+ {
+ if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
+ log_error (_("error reading '%s': %s\n"),
+ iobuf_is_pipe_filename (fname)? "[stdin]": fname,
+ gpg_strerror (err));
+ goto leave;
+ }
+
+ keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
+
+ if (!find_next_kbnode (keyblock, PKT_USER_ID))
+ {
+ err = gpg_error (GPG_ERR_NO_USER_ID);
+ goto leave;
+ }
+
+ collapse_uids (&keyblock);
+
+ clear_kbnode_flags (keyblock);
+ if (chk_self_sigs (keyblock, keyid, &non_self))
+ {
+ err = gpg_error (GPG_ERR_INV_KEYRING);
+ goto leave;
+ }
+
+ if (!delete_inv_parts (keyblock, keyid, 0) )
+ {
+ err = gpg_error (GPG_ERR_NO_USER_ID);
+ goto leave;
+ }
+
+ *r_keyblock = keyblock;
+ keyblock = NULL;
+
+ leave:
+ if (inp)
+ {
+ iobuf_close (inp);
+ /* Must invalidate that ugly cache to actually close the file. */
+ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
+ }
+ release_kbnode (keyblock);
+ /* FIXME: Do we need to free PENDING_PKT ? */
+ return err;
+}
+
+
+
/*
* Import the public keys from the given filename. Input may be armored.
* This function rejects all keys which are not validly self signed on at
@@ -328,16 +504,16 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
{
stats->v3keys += v3keys;
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
- rc = import_one (ctrl, fname, keyblock,
+ rc = import_one (ctrl, keyblock,
stats, fpr, fpr_len, options, 0, 0,
screener, screener_arg);
else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
- rc = import_secret_one (ctrl, fname, keyblock, stats,
+ rc = import_secret_one (ctrl, keyblock, stats,
opt.batch, options, 0,
screener, screener_arg);
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
- rc = import_revoke_cert( fname, keyblock, stats );
+ rc = import_revoke_cert (keyblock, stats);
else
{
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
@@ -401,7 +577,7 @@ import_old_secring (ctrl_t ctrl, const char *fname)
while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
- err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1,
+ err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
NULL, NULL);
release_kbnode (keyblock);
if (err)
@@ -707,8 +883,8 @@ fix_pks_corruption (kbnode_t keyblock)
}
else
{
- sknode->flag |= 1; /* Mark it good so we don't need to
- check it again */
+ /* Mark it good so we don't need to check it again */
+ sknode->flag |= NODE_GOOD_SELFSIG;
changed = 1;
break;
}
@@ -921,6 +1097,74 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
}
+/* Helper for apply_keep_uid_filter. */
+static const char *
+filter_getval (void *cookie, const char *propname)
+{
+ kbnode_t node = cookie;
+ const char *result;
+
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ if (!strcmp (propname, "uid"))
+ result = node->pkt->pkt.user_id->name;
+ else if (!strcmp (propname, "mbox"))
+ {
+ if (!node->pkt->pkt.user_id->mbox)
+ {
+ node->pkt->pkt.user_id->mbox
+ = mailbox_from_userid (node->pkt->pkt.user_id->name);
+ }
+ return node->pkt->pkt.user_id->mbox;
+ }
+ else if (!strcmp (propname, "primary"))
+ result = node->pkt->pkt.user_id->is_primary? "1":"0";
+ else
+ result = NULL;
+ }
+ else
+ result = NULL;
+
+ return result;
+}
+
+/*
+ * Apply the keep-uid filter to the keyblock. The deleted nodes are
+ * marked and thus the caller should call commit_kbnode afterwards.
+ * KEYBLOCK must not have any blocks marked as deleted.
+ */
+static void
+apply_keep_uid_filter (kbnode_t keyblock, recsel_expr_t selector)
+{
+ kbnode_t node;
+
+ for (node = keyblock->next; node; node = node->next )
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ if (!recsel_select (selector, filter_getval, node))
+ {
+
+ /* log_debug ("keep-uid: deleting '%s'\n", */
+ /* node->pkt->pkt.user_id->name); */
+ /* The UID packet and all following packets up to the
+ * next UID or a subkey. */
+ delete_kbnode (node);
+ for (; node->next
+ && node->next->pkt->pkttype != PKT_USER_ID
+ && node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
+ && node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
+ node = node->next)
+ delete_kbnode (node->next);
+ }
+ /* else */
+ /* log_debug ("keep-uid: keeping '%s'\n", */
+ /* node->pkt->pkt.user_id->name); */
+ }
+ }
+}
+
+
/*
* Try to import one keyblock. Return an error only in serious cases,
* but never for an invalid keyblock. It uses log_error to increase
@@ -930,13 +1174,13 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
*/
static int
import_one (ctrl_t ctrl,
- const char *fname, kbnode_t keyblock, struct import_stats_s *stats,
+ kbnode_t keyblock, struct import_stats_s *stats,
unsigned char **fpr, size_t *fpr_len, unsigned int options,
int from_sk, int silent,
import_screener_t screener, void *screener_arg)
{
PKT_public_key *pk;
- PKT_public_key *pk_orig;
+ PKT_public_key *pk_orig = NULL;
kbnode_t node, uidnode;
kbnode_t keyblock_orig = NULL;
byte fpr2[MAX_FINGERPRINT_LEN];
@@ -949,6 +1193,7 @@ import_one (ctrl_t ctrl,
int non_self = 0;
size_t an;
char pkstrbuf[PUBKEY_STRING_SIZE];
+ int merge_keys_done = 0;
/* Get the key and print some info about it. */
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
@@ -1019,26 +1264,28 @@ import_one (ctrl_t ctrl,
log_info (_("key %s: PKS subkey corruption repaired\n"),
keystr_from_pk(pk));
- rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self );
- if (rc )
- return rc== -1? 0:rc;
+ if (chk_self_sigs (keyblock, keyid, &non_self))
+ return 0; /* Invalid keyblock - error already printed. */
/* If we allow such a thing, mark unsigned uids as valid */
if (opt.allow_non_selfsigned_uid)
{
for (node=keyblock; node; node = node->next )
- if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
+ if (node->pkt->pkttype == PKT_USER_ID
+ && !(node->flag & NODE_GOOD_SELFSIG)
+ && !(node->flag & NODE_BAD_SELFSIG) )
{
char *user=utf8_to_native(node->pkt->pkt.user_id->name,
node->pkt->pkt.user_id->len,0);
- node->flag |= 1;
+ /* Fake a good signature status for the user id. */
+ node->flag |= NODE_GOOD_SELFSIG;
log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
keystr_from_pk(pk),user);
xfree(user);
}
}
- if (!delete_inv_parts( fname, keyblock, keyid, options ) )
+ if (!delete_inv_parts (keyblock, keyid, options ) )
{
if (!silent)
{
@@ -1050,6 +1297,46 @@ import_one (ctrl_t ctrl,
return 0;
}
+ /* Get rid of deleted nodes. */
+ commit_kbnode (&keyblock);
+
+ /* Apply import filter. */
+ if (import_keep_uid)
+ {
+ apply_keep_uid_filter (keyblock, import_keep_uid);
+ commit_kbnode (&keyblock);
+ }
+
+
+ /* Show the key in the form it is merged or inserted. We skip this
+ * if "import-export" is also active without --armor or the output
+ * file has explicily been given. */
+ if ((options & IMPORT_SHOW)
+ && !((options & IMPORT_EXPORT) && !opt.armor && !opt.outfile))
+ {
+ merge_keys_and_selfsig (keyblock);
+ merge_keys_done = 1;
+ /* Note that we do not want to show the validity because the key
+ * has not yet imported. */
+ list_keyblock_direct (ctrl, keyblock, 0, 0, 1, 1);
+ es_fflush (es_stdout);
+ }
+
+ /* Write the keyblock to the output and do not actually import. */
+ if ((options & IMPORT_EXPORT))
+ {
+ if (!merge_keys_done)
+ {
+ merge_keys_and_selfsig (keyblock);
+ merge_keys_done = 1;
+ }
+ rc = write_keyblock_to_output (keyblock, opt.armor, opt.export_options);
+ goto leave;
+ }
+
+ if (opt.dry_run)
+ goto leave;
+
/* Do we have this key already in one of our pubrings ? */
pk_orig = xmalloc_clear( sizeof *pk_orig );
rc = get_pubkey_byfprint_fast (pk_orig, fpr2, fpr2len);
@@ -1170,7 +1457,7 @@ import_one (ctrl_t ctrl,
clear_kbnode_flags( keyblock_orig );
clear_kbnode_flags( keyblock );
n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
- rc = merge_blocks( fname, keyblock_orig, keyblock,
+ rc = merge_blocks (keyblock_orig, keyblock,
keyid, &n_uids, &n_sigs, &n_subk );
if (rc )
{
@@ -1258,7 +1545,7 @@ import_one (ctrl_t ctrl,
keydb_release (hd); hd = NULL;
}
- leave:
+ leave:
if (mod_key || new_key || same_key)
{
/* A little explanation for this: we fill in the fingerprint
@@ -1429,6 +1716,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
else
{
const char *curvename = openpgp_oid_to_curve (curvestr, 1);
+ gcry_sexp_release (curve);
err = gcry_sexp_build (&curve, NULL, "(curve %s)",
curvename?curvename:curvestr);
xfree (curvestr);
@@ -1654,7 +1942,7 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
* with the trust calculation.
*/
static int
-import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
+import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
struct import_stats_s *stats, int batch, unsigned int options,
int for_migration,
import_screener_t screener, void *screener_arg)
@@ -1754,7 +2042,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
/* Note that this outputs an IMPORT_OK status message for the
public key block, and below we will output another one for
the secret keys. FIXME? */
- import_one (ctrl, fname, pub_keyblock, stats,
+ import_one (ctrl, pub_keyblock, stats,
NULL, NULL, options, 1, for_migration,
screener, screener_arg);
@@ -1822,8 +2110,7 @@ import_secret_one (ctrl_t ctrl, const char *fname, kbnode_t keyblock,
* Import a revocation certificate; this is a single signature packet.
*/
static int
-import_revoke_cert (const char *fname, kbnode_t node,
- struct import_stats_s *stats)
+import_revoke_cert (kbnode_t node, struct import_stats_s *stats)
{
PKT_public_key *pk = NULL;
kbnode_t onode;
@@ -1832,8 +2119,6 @@ import_revoke_cert (const char *fname, kbnode_t node,
u32 keyid[2];
int rc = 0;
- (void)fname;
-
log_assert (!node->next );
log_assert (node->pkt->pkttype == PKT_SIGNATURE );
log_assert (node->pkt->pkt.signature->sig_class == 0x20 );
@@ -1949,18 +2234,21 @@ import_revoke_cert (const char *fname, kbnode_t node,
}
-/*
- * Loop over the keyblock and check all self signatures.
- * Mark all user-ids with a self-signature by setting flag bit 0.
- * Mark all user-ids with an invalid self-signature by setting bit 1.
- * This works also for subkeys, here the subkey is marked. Invalid or
- * extra subkey sigs (binding or revocation) are marked for deletion.
- * non_self is set to true if there are any sigs other than self-sigs
+/* Loop over the keyblock and check all self signatures. On return
+ * the following bis in the node flags are set:
+ *
+ * - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature
+ * - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature
+ * - NODE_DELETION_MARK :: This node shall be deleted
+ *
+ * NON_SELF is set to true if there are any sigs other than self-sigs
* in this keyblock.
+ *
+ * Returns 0 on success or -1 (but not an error code) if the keyblock
+ * is invalid.
*/
static int
-chk_self_sigs (const char *fname, kbnode_t keyblock,
- PKT_public_key *pk, u32 *keyid, int *non_self )
+chk_self_sigs (kbnode_t keyblock, u32 *keyid, int *non_self )
{
kbnode_t n, knode = NULL;
PKT_signature *sig;
@@ -1968,9 +2256,6 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
u32 bsdate=0, rsdate=0;
kbnode_t bsnode = NULL, rsnode = NULL;
- (void)fname;
- (void)pk;
-
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
{
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
@@ -2009,7 +2294,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
}
/* If it hasn't been marked valid yet, keep trying. */
- if (!(unode->flag&1))
+ if (!(unode->flag & NODE_GOOD_SELFSIG))
{
rc = check_key_signature (keyblock, n, NULL);
if ( rc )
@@ -2029,7 +2314,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
}
}
else
- unode->flag |= 1; /* Mark that signature checked. */
+ unode->flag |= NODE_GOOD_SELFSIG;
}
}
else if (IS_KEY_SIG (sig))
@@ -2042,7 +2327,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
_("key %s: unsupported public key algorithm\n"):
_("key %s: invalid direct key signature\n"),
keystr (keyid));
- n->flag |= 4;
+ n->flag |= NODE_DELETION_MARK;
}
}
else if ( IS_SUBKEY_SIG (sig) )
@@ -2056,7 +2341,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
if (opt.verbose)
log_info (_("key %s: no subkey for key binding\n"),
keystr (keyid));
- n->flag |= 4; /* delete this */
+ n->flag |= NODE_DELETION_MARK;
}
else
{
@@ -2069,19 +2354,19 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
" algorithm\n"):
_("key %s: invalid subkey binding\n"),
keystr (keyid));
- n->flag |= 4;
+ n->flag |= NODE_DELETION_MARK;
}
else
{
/* It's valid, so is it newer? */
if (sig->timestamp >= bsdate)
{
- knode->flag |= 1; /* The subkey is valid. */
+ knode->flag |= NODE_GOOD_SELFSIG; /* Subkey is valid. */
if (bsnode)
{
/* Delete the last binding sig since this
one is newer */
- bsnode->flag |= 4;
+ bsnode->flag |= NODE_DELETION_MARK;
if (opt.verbose)
log_info (_("key %s: removed multiple subkey"
" binding\n"),keystr(keyid));
@@ -2091,7 +2376,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
bsdate = sig->timestamp;
}
else
- n->flag |= 4; /* older */
+ n->flag |= NODE_DELETION_MARK; /* older */
}
}
}
@@ -2107,7 +2392,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
if (opt.verbose)
log_info (_("key %s: no subkey for key revocation\n"),
keystr(keyid));
- n->flag |= 4; /* delete this */
+ n->flag |= NODE_DELETION_MARK;
}
else
{
@@ -2120,7 +2405,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
" key algorithm\n"):
_("key %s: invalid subkey revocation\n"),
keystr(keyid));
- n->flag |= 4;
+ n->flag |= NODE_DELETION_MARK;
}
else
{
@@ -2131,7 +2416,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
{
/* Delete the last revocation sig since
this one is newer. */
- rsnode->flag |= 4;
+ rsnode->flag |= NODE_DELETION_MARK;
if (opt.verbose)
log_info (_("key %s: removed multiple subkey"
" revocation\n"),keystr(keyid));
@@ -2141,7 +2426,7 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
rsdate = sig->timestamp;
}
else
- n->flag |= 4; /* older */
+ n->flag |= NODE_DELETION_MARK; /* older */
}
}
}
@@ -2151,28 +2436,25 @@ chk_self_sigs (const char *fname, kbnode_t keyblock,
}
-/****************
- * delete all parts which are invalid and those signatures whose
- * public key algorithm is not available in this implemenation;
- * but consider RSA as valid, because parse/build_packets knows
- * about it.
- * returns: true if at least one valid user-id is left over.
+/* Delete all parts which are invalid and those signatures whose
+ * public key algorithm is not available in this implemenation; but
+ * consider RSA as valid, because parse/build_packets knows about it.
+ *
+ * Returns: True if at least one valid user-id is left over.
*/
static int
-delete_inv_parts( const char *fname, kbnode_t keyblock,
- u32 *keyid, unsigned int options)
+delete_inv_parts (kbnode_t keyblock, u32 *keyid, unsigned int options)
{
kbnode_t node;
int nvalid=0, uid_seen=0, subkey_seen=0;
- (void)fname;
-
for (node=keyblock->next; node; node = node->next )
{
if (node->pkt->pkttype == PKT_USER_ID)
{
uid_seen = 1;
- if ((node->flag & 2) || !(node->flag & 1) )
+ if ((node->flag & NODE_BAD_SELFSIG)
+ || !(node->flag & NODE_GOOD_SELFSIG))
{
if (opt.verbose )
{
@@ -2198,7 +2480,8 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
else if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY )
{
- if ((node->flag & 2) || !(node->flag & 1) )
+ if ((node->flag & NODE_BAD_SELFSIG)
+ || !(node->flag & NODE_GOOD_SELFSIG))
{
if (opt.verbose )
log_info( _("key %s: skipped subkey\n"),keystr(keyid));
@@ -2286,7 +2569,7 @@ delete_inv_parts( const char *fname, kbnode_t keyblock,
node->pkt->pkt.signature->sig_class);
delete_kbnode(node);
}
- else if ((node->flag & 4) ) /* marked for deletion */
+ else if ((node->flag & NODE_DELETION_MARK))
delete_kbnode( node );
}
@@ -2513,10 +2796,10 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
* the signature's public key yet; verification is done when putting it
* into the trustdb, which is done automagically as soon as this pubkey
* is used.
- * Note: We indicate newly inserted packets with flag bit 0
+ * Note: We indicate newly inserted packets with NODE_FLAG_A.
*/
static int
-merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
+merge_blocks (kbnode_t keyblock_orig, kbnode_t keyblock,
u32 *keyid, int *n_uids, int *n_sigs, int *n_subk )
{
kbnode_t onode, node;
@@ -2549,7 +2832,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
{
kbnode_t n2 = clone_kbnode(node);
insert_kbnode( keyblock_orig, n2, 0 );
- n2->flag |= 1;
+ n2->flag |= NODE_FLAG_A;
++*n_sigs;
if(!opt.quiet)
{
@@ -2589,7 +2872,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
{
kbnode_t n2 = clone_kbnode(node);
insert_kbnode( keyblock_orig, n2, 0 );
- n2->flag |= 1;
+ n2->flag |= NODE_FLAG_A;
++*n_sigs;
if(!opt.quiet)
log_info( _("key %s: direct key signature added\n"),
@@ -2601,7 +2884,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
/* 3rd: try to merge new certificates in */
for (onode=keyblock_orig->next; onode; onode=onode->next)
{
- if (!(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID)
+ if (!(onode->flag & NODE_FLAG_A) && onode->pkt->pkttype == PKT_USER_ID)
{
/* find the user id in the imported keyblock */
for (node=keyblock->next; node; node=node->next)
@@ -2611,7 +2894,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (node ) /* found: merge */
{
- rc = merge_sigs( onode, node, n_sigs, fname, keyid );
+ rc = merge_sigs (onode, node, n_sigs);
if (rc )
return rc;
}
@@ -2631,7 +2914,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (!onode ) /* this is a new user id: append */
{
- rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid);
+ rc = append_uid (keyblock_orig, node, n_sigs);
if (rc )
return rc;
++*n_uids;
@@ -2653,7 +2936,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (!onode ) /* This is a new subkey: append. */
{
- rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
+ rc = append_key (keyblock_orig, node, n_sigs);
if (rc)
return rc;
++*n_subk;
@@ -2669,7 +2952,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
break;
if (!onode ) /* This is a new subkey: append. */
{
- rc = append_key (keyblock_orig, node, n_sigs, fname, keyid);
+ rc = append_key (keyblock_orig, node, n_sigs);
if (rc )
return rc;
++*n_subk;
@@ -2680,7 +2963,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
/* 6th: merge subkey certificates */
for (onode=keyblock_orig->next; onode; onode=onode->next)
{
- if (!(onode->flag & 1)
+ if (!(onode->flag & NODE_FLAG_A)
&& (onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| onode->pkt->pkttype == PKT_SECRET_SUBKEY))
{
@@ -2695,7 +2978,7 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
}
if (node) /* Found: merge. */
{
- rc = merge_keysigs( onode, node, n_sigs, fname, keyid );
+ rc = merge_keysigs( onode, node, n_sigs);
if (rc )
return rc;
}
@@ -2706,19 +2989,15 @@ merge_blocks (const char *fname, kbnode_t keyblock_orig, kbnode_t keyblock,
}
-/*
+/* Helper function for merge_blocks.
* Append the userid starting with NODE and all signatures to KEYBLOCK.
*/
static int
-append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
- const char *fname, u32 *keyid )
+append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs)
{
kbnode_t n;
kbnode_t n_where = NULL;
- (void)fname;
- (void)keyid;
-
log_assert (node->pkt->pkttype == PKT_USER_ID );
/* find the position */
@@ -2744,8 +3023,8 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
}
else
add_kbnode( keyblock, n );
- n->flag |= 1;
- node->flag |= 1;
+ n->flag |= NODE_FLAG_A;
+ node->flag |= NODE_FLAG_A;
if (n->pkt->pkttype == PKT_SIGNATURE )
++*n_sigs;
@@ -2758,20 +3037,16 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs,
}
-/*
+/* Helper function for merge_blocks
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID.
* (how should we handle comment packets here?)
*/
static int
-merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
- const char *fname, u32 *keyid)
+merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs)
{
kbnode_t n, n2;
int found = 0;
- (void)fname;
- (void)keyid;
-
log_assert (dst->pkt->pkttype == PKT_USER_ID);
log_assert (src->pkt->pkttype == PKT_USER_ID);
@@ -2797,8 +3072,8 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
* one is released first */
n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_SIGNATURE );
- n2->flag |= 1;
- n->flag |= 1;
+ n2->flag |= NODE_FLAG_A;
+ n->flag |= NODE_FLAG_A;
++*n_sigs;
}
}
@@ -2807,19 +3082,15 @@ merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs,
}
-/*
+/* Helper function for merge_blocks
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
*/
static int
-merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
- const char *fname, u32 *keyid)
+merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs)
{
kbnode_t n, n2;
int found = 0;
- (void)fname;
- (void)keyid;
-
log_assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| dst->pkt->pkttype == PKT_SECRET_SUBKEY);
@@ -2858,8 +3129,8 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
* one is released first */
n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_SIGNATURE );
- n2->flag |= 1;
- n->flag |= 1;
+ n2->flag |= NODE_FLAG_A;
+ n->flag |= NODE_FLAG_A;
++*n_sigs;
}
}
@@ -2868,19 +3139,15 @@ merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs,
}
-/*
+/* Helper function for merge_blocks.
* Append the subkey starting with NODE and all signatures to KEYBLOCK.
* Mark all new and copied packets by setting flag bit 0.
*/
static int
-append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
- const char *fname, u32 *keyid)
+append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs)
{
kbnode_t n;
- (void)fname;
- (void)keyid;
-
log_assert (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
@@ -2890,8 +3157,8 @@ append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs,
* one is released first */
n = clone_kbnode(node);
add_kbnode( keyblock, n );
- n->flag |= 1;
- node->flag |= 1;
+ n->flag |= NODE_FLAG_A;
+ node->flag |= NODE_FLAG_A;
if (n->pkt->pkttype == PKT_SIGNATURE )
++*n_sigs;
diff --git a/g10/kbnode.c b/g10/kbnode.c
index a1d1f3d77..e814fa802 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -34,18 +34,18 @@
static int cleanup_registered;
static KBNODE unused_nodes;
-#if USE_UNUSED_NODES
static void
release_unused_nodes (void)
{
+#if USE_UNUSED_NODES
while (unused_nodes)
{
kbnode_t next = unused_nodes->next;
xfree (unused_nodes);
unused_nodes = next;
}
-}
#endif /*USE_UNUSED_NODES*/
+}
static kbnode_t
diff --git a/g10/keydb.c b/g10/keydb.c
index 17ddd5d20..e49e25fd9 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -937,6 +937,7 @@ keydb_release (KEYDB_HANDLE hd)
}
}
+ keyblock_cache_clear (hd);
xfree (hd);
}
diff --git a/g10/keydb.h b/g10/keydb.h
index a30cf7ac7..4e8f3f291 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -70,15 +70,16 @@ enum resource_type {
/* Bit flags used with build_pk_list. */
enum
{
- PK_LIST_ENCRYPT_TO=1, /* This is an encrypt-to recipient. */
- PK_LIST_HIDDEN=2, /* This is a hidden recipient. */
- PK_LIST_CONFIG=4 /* Specified via config file. */
+ PK_LIST_ENCRYPT_TO = 1, /* This is an encrypt-to recipient. */
+ PK_LIST_HIDDEN = 2, /* This is a hidden recipient. */
+ PK_LIST_CONFIG = 4, /* Specified via config file. */
+ PK_LIST_FROM_FILE = 8 /* Take key from file with that name. */
};
-/* To store private data in the flags they must be left shifted by
- this value. */
+/* To store private data in the flags the private data must be left
+ shifted by this value. */
enum
{
- PK_LIST_SHIFT=3
+ PK_LIST_SHIFT = 4
};
/****************
@@ -104,7 +105,7 @@ struct pk_list
{
PK_LIST next;
PKT_public_key *pk;
- int flags; /* flag bit 1==throw_keyid */
+ int flags; /* See PK_LIST_ constants. */
};
/* Structure to hold a list of secret key certificates. */
@@ -228,7 +229,8 @@ void release_pk_list (PK_LIST pk_list);
int build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
gpg_error_t find_and_check_key (ctrl_t ctrl,
const char *name, unsigned int use,
- int mark_hidden, pk_list_t *pk_list_addr);
+ int mark_hidden, int from_file,
+ pk_list_t *pk_list_addr);
int algo_available( preftype_t preftype, int algo,
const union pref_hint *hint );
@@ -322,6 +324,10 @@ int get_pubkey_byname (ctrl_t ctrl,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
int include_unusable, int no_akl );
+/* Get a public key directly from file FNAME. */
+gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
+ PKT_public_key *pk, const char *fname);
+
/* Return the public key with the key id KEYID iff the secret key is
* available and store it at PK. */
gpg_error_t get_seckey (PKT_public_key *pk, u32 *keyid);
diff --git a/g10/keyedit.c b/g10/keyedit.c
index d05ea5d01..9ebd643ad 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -87,6 +87,9 @@ static int real_uids_left (KBNODE keyblock);
static int count_selected_keys (KBNODE keyblock);
static int menu_revsig (KBNODE keyblock);
static int menu_revuid (ctrl_t ctrl, kbnode_t keyblock);
+static int core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+ const struct revocation_reason_info *reason,
+ int *modified);
static int menu_revkey (KBNODE pub_keyblock);
static int menu_revsubkey (KBNODE pub_keyblock);
#ifndef NO_TRUST_MODELS
@@ -2937,6 +2940,110 @@ keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid)
keydb_release (kdbhd);
}
+/* Unattended revokation of a keyid. USERNAME specifies the
+ key. UIDTOREV is the user id revoke from the key. */
+void
+keyedit_quick_revuid (ctrl_t ctrl, const char *username, const char *uidtorev)
+{
+ gpg_error_t err;
+ KEYDB_HANDLE kdbhd = NULL;
+ KEYDB_SEARCH_DESC desc;
+ kbnode_t keyblock = NULL;
+ kbnode_t node;
+ int modified = 0;
+ size_t revlen;
+
+#ifdef HAVE_W32_SYSTEM
+ /* See keyedit_menu for why we need this. */
+ check_trustdb_stale (ctrl);
+#endif
+
+ /* Search the key; we don't want the whole getkey stuff here. */
+ kdbhd = keydb_new ();
+ if (!kdbhd)
+ {
+ /* Note that keydb_new has already used log_error. */
+ goto leave;
+ }
+
+ err = classify_user_id (username, &desc, 1);
+ if (!err)
+ err = keydb_search (kdbhd, &desc, 1, NULL);
+ if (!err)
+ {
+ err = keydb_get_keyblock (kdbhd, &keyblock);
+ if (err)
+ {
+ log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+ /* Now with the keyblock retrieved, search again to detect an
+ ambiguous specification. We need to save the found state so
+ that we can do an update later. */
+ keydb_push_found_state (kdbhd);
+ err = keydb_search (kdbhd, &desc, 1, NULL);
+ if (!err)
+ err = gpg_error (GPG_ERR_AMBIGUOUS_NAME);
+ else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
+ err = 0;
+ keydb_pop_found_state (kdbhd);
+
+ if (!err)
+ {
+ /* We require the secret primary key to revoke a UID. */
+ node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
+ if (!node)
+ BUG ();
+ err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key);
+ }
+ }
+ if (err)
+ {
+ log_error (_("secret key \"%s\" not found: %s\n"),
+ username, gpg_strerror (err));
+ goto leave;
+ }
+
+ fix_keyblock (&keyblock);
+ setup_main_keyids (keyblock);
+
+ revlen = strlen (uidtorev);
+ /* find the right UID */
+ for (node = keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID
+ && revlen == node->pkt->pkt.user_id->len
+ && !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen))
+ {
+ struct revocation_reason_info *reason;
+
+ reason = get_default_uid_revocation_reason ();
+ err = core_revuid (ctrl, keyblock, node, reason, &modified);
+ release_revocation_reason_info (reason);
+ if (err)
+ {
+ log_error (_("User ID revocation failed: %s\n"),
+ gpg_strerror (err));
+ goto leave;
+ }
+ err = keydb_update_keyblock (kdbhd, keyblock);
+ if (err)
+ {
+ log_error (_("update failed: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+
+ if (update_trust)
+ revalidation_mark ();
+ goto leave;
+ }
+ }
+
+ leave:
+ release_kbnode (keyblock);
+ keydb_release (kdbhd);
+}
+
/* Find a keyblock by fingerprint because only this uniquely
* identifies a key and may thus be used to select a key for
@@ -6106,6 +6213,95 @@ reloop: /* (must use this, because we are modifing the list) */
}
+/* return 0 if revocation of NODE (which must be a User ID) was
+ successful, non-zero if there was an error. *modified will be set
+ to 1 if a change was made. */
+static int
+core_revuid (ctrl_t ctrl, kbnode_t keyblock, KBNODE node,
+ const struct revocation_reason_info *reason, int *modified)
+{
+ PKT_public_key *pk = keyblock->pkt->pkt.public_key;
+ gpg_error_t rc;
+
+ if (node->pkt->pkttype != PKT_USER_ID)
+ {
+ rc = gpg_error (GPG_ERR_NO_USER_ID);
+ write_status_error ("keysig", rc);
+ log_error (_("tried to revoke a non-user ID: %s\n"), gpg_strerror (rc));
+ return 1;
+ }
+ else
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+
+ if (uid->is_revoked)
+ {
+ char *user = utf8_to_native (uid->name, uid->len, 0);
+ log_info (_("user ID \"%s\" is already revoked\n"), user);
+ xfree (user);
+ }
+ else
+ {
+ PACKET *pkt;
+ PKT_signature *sig;
+ struct sign_attrib attrib;
+ u32 timestamp = make_timestamp ();
+
+ if (uid->created >= timestamp)
+ {
+ /* Okay, this is a problem. The user ID selfsig was
+ created in the future, so we need to warn the user and
+ set our revocation timestamp one second after that so
+ everything comes out clean. */
+
+ log_info (_("WARNING: a user ID signature is dated %d"
+ " seconds in the future\n"),
+ uid->created - timestamp);
+
+ timestamp = uid->created + 1;
+ }
+
+ memset (&attrib, 0, sizeof attrib);
+ /* should not need to cast away const here; but
+ revocation_reason_build_cb needs to take a non-const
+ void* in order to meet the function signtuare for the
+ mksubpkt argument to make_keysig_packet */
+ attrib.reason = (struct revocation_reason_info *)reason;
+
+ rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
+ timestamp, 0,
+ sign_mk_attrib, &attrib, NULL);
+ if (rc)
+ {
+ write_status_error ("keysig", rc);
+ log_error (_("signing failed: %s\n"), gpg_strerror (rc));
+ return 1;
+ }
+ else
+ {
+ pkt = xmalloc_clear (sizeof *pkt);
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = sig;
+ insert_kbnode (node, new_kbnode (pkt), 0);
+
+#ifndef NO_TRUST_MODELS
+ /* If the trustdb has an entry for this key+uid then the
+ trustdb needs an update. */
+ if (!update_trust
+ && ((get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK)
+ >= TRUST_UNDEFINED))
+ update_trust = 1;
+#endif /*!NO_TRUST_MODELS*/
+
+ node->pkt->pkt.user_id->is_revoked = 1;
+ if (modified)
+ *modified = 1;
+ }
+ }
+ return 0;
+ }
+}
+
/* Revoke a user ID (i.e. revoke a user ID selfsig). Return true if
keyblock changed. */
static int
@@ -6132,75 +6328,20 @@ menu_revuid (ctrl_t ctrl, kbnode_t pub_keyblock)
goto leave;
}
- reloop: /* (better this way because we are modifing the keyring) */
+ reloop: /* (better this way because we are modifying the keyring) */
for (node = pub_keyblock; node; node = node->next)
if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID))
{
- PKT_user_id *uid = node->pkt->pkt.user_id;
-
- if (uid->is_revoked)
- {
- char *user = utf8_to_native (uid->name, uid->len, 0);
- log_info (_("user ID \"%s\" is already revoked\n"), user);
- xfree (user);
- }
- else
- {
- PACKET *pkt;
- PKT_signature *sig;
- struct sign_attrib attrib;
- u32 timestamp = make_timestamp ();
-
- if (uid->created >= timestamp)
- {
- /* Okay, this is a problem. The user ID selfsig was
- created in the future, so we need to warn the user and
- set our revocation timestamp one second after that so
- everything comes out clean. */
-
- log_info (_("WARNING: a user ID signature is dated %d"
- " seconds in the future\n"),
- uid->created - timestamp);
-
- timestamp = uid->created + 1;
- }
-
- memset (&attrib, 0, sizeof attrib);
- attrib.reason = reason;
-
+ int modified = 0;
+ rc = core_revuid (ctrl, pub_keyblock, node, reason, &modified);
+ if (rc)
+ goto leave;
+ if (modified)
+ {
node->flag &= ~NODFLG_SELUID;
-
- rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0,
- timestamp, 0,
- sign_mk_attrib, &attrib, NULL);
- if (rc)
- {
- write_status_error ("keysig", rc);
- log_error (_("signing failed: %s\n"), gpg_strerror (rc));
- goto leave;
- }
- else
- {
- pkt = xmalloc_clear (sizeof *pkt);
- pkt->pkttype = PKT_SIGNATURE;
- pkt->pkt.signature = sig;
- insert_kbnode (node, new_kbnode (pkt), 0);
-
-#ifndef NO_TRUST_MODELS
- /* If the trustdb has an entry for this key+uid then the
- trustdb needs an update. */
- if (!update_trust
- && (get_validity (ctrl, pk, uid, NULL, 0) & TRUST_MASK) >=
- TRUST_UNDEFINED)
- update_trust = 1;
-#endif /*!NO_TRUST_MODELS*/
-
- changed = 1;
- node->pkt->pkt.user_id->is_revoked = 1;
-
- goto reloop;
- }
- }
+ changed = 1;
+ goto reloop;
+ }
}
if (changed)
diff --git a/g10/keygen.c b/g10/keygen.c
index 74fd37052..2b3d32886 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -202,7 +202,7 @@ write_uid( KBNODE root, const char *s )
size_t n = strlen(s);
pkt->pkttype = PKT_USER_ID;
- pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 );
+ pkt->pkt.user_id = xmalloc_clear (sizeof *pkt->pkt.user_id + n);
pkt->pkt.user_id->len = n;
pkt->pkt.user_id->ref = 1;
strcpy(pkt->pkt.user_id->name, s);
@@ -413,9 +413,9 @@ keygen_set_std_prefs (const char *string,int personal)
if(strlen(string))
{
- char *tok,*prefstring;
+ char *dup, *tok, *prefstring;
- prefstring=xstrdup(string); /* need a writable string! */
+ dup = prefstring = xstrdup (string); /* need a writable string! */
while((tok=strsep(&prefstring," ,")))
{
@@ -449,7 +449,7 @@ keygen_set_std_prefs (const char *string,int personal)
}
}
- xfree(prefstring);
+ xfree (dup);
}
if(!rc)
@@ -3481,6 +3481,7 @@ read_parameter_file (ctrl_t ctrl, const char *fname )
xfree( outctrl.pub.newfname );
}
+ xfree (line);
release_parameter_list( para );
iobuf_close (fp);
release_armor_context (outctrl.pub.afx);
@@ -3610,7 +3611,13 @@ quick_generate_keypair (ctrl_t ctrl, const char *uid, const char *algostr,
}
}
- if (*algostr || *usagestr || *expirestr)
+
+ if (!strcmp (algostr, "test-default"))
+ {
+ para = quickgen_set_para (para, 0, PUBKEY_ALGO_EDDSA, 0, "Ed25519", 0);
+ para = quickgen_set_para (para, 1, PUBKEY_ALGO_ECDH, 0, "Curve25519", 0);
+ }
+ else if (*algostr || *usagestr || *expirestr)
{
/* Extended unattended mode. Creates only the primary key. */
int algo;
@@ -4340,11 +4347,15 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
gen_standard_revoke (pk, cache_nonce);
+ /* Get rid of the first empty packet. */
+ commit_kbnode (&pub_root);
+
if (!opt.batch)
{
tty_printf (_("public and secret key created and signed.\n") );
tty_printf ("\n");
- list_keyblock_direct (ctrl, pub_root, 0, 1, 1);
+ merge_keys_and_selfsig (pub_root);
+ list_keyblock_direct (ctrl, pub_root, 0, 1, 1, 1);
}
diff --git a/g10/keylist.c b/g10/keylist.c
index 0ac763d65..b8f97f545 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -59,6 +59,7 @@ struct keylist_context
int inv_sigs; /* Counter used if CHECK_SIGS is set. */
int no_key; /* Counter used if CHECK_SIGS is set. */
int oth_err; /* Counter used if CHECK_SIGS is set. */
+ int no_validity; /* Do not show validity. */
};
@@ -920,7 +921,7 @@ list_keyblock_pka (ctrl_t ctrl, kbnode_t keyblock)
/* We do not have an export function which allows to pass a
keyblock, thus we need to search the key again. */
err = export_pubkey_buffer (ctrl, hexfpr,
- EXPORT_DANE_FORMAT, NULL,
+ (EXPORT_MINIMAL | EXPORT_CLEAN), NULL,
&dummy_keyblock, &data, &datalen);
release_kbnode (dummy_keyblock);
if (!err)
@@ -1052,7 +1053,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
secret = 2; /* Key not found. */
}
- check_trustdb_stale (ctrl);
+ if (!listctx->no_validity)
+ check_trustdb_stale (ctrl);
/* Print the "pub" line and in KF_NONE mode the fingerprint. */
print_key_line (es_stdout, pk, secret);
@@ -1090,7 +1092,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
dump_attribs (uid, pk);
if ((uid->is_revoked || uid->is_expired)
- || (opt.list_options & LIST_SHOW_UID_VALIDITY))
+ || ((opt.list_options & LIST_SHOW_UID_VALIDITY)
+ && !listctx->no_validity))
{
const char *validity;
@@ -1755,14 +1758,17 @@ list_keyblock (ctrl_t ctrl,
}
-/* Public function used by keygen to list a keyblock. */
+/* Public function used by keygen to list a keyblock. If NO_VALIDITY
+ * is set the validity of a key is never shown. */
void
list_keyblock_direct (ctrl_t ctrl,
- kbnode_t keyblock, int secret, int has_secret, int fpr)
+ kbnode_t keyblock, int secret, int has_secret, int fpr,
+ int no_validity)
{
struct keylist_context listctx;
memset (&listctx, 0, sizeof (listctx));
+ listctx.no_validity = !!no_validity;
list_keyblock (ctrl, keyblock, secret, has_secret, fpr, &listctx);
keylist_context_release (&listctx);
}
diff --git a/g10/keyserver.c b/g10/keyserver.c
index d7105de02..2e2d6a4bb 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -240,13 +240,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
struct keyserver_spec *keyserver;
const char *idx;
int count;
- char *uri,*options;
+ char *uri, *duped_uri, *options;
log_assert (string);
keyserver=xmalloc_clear(sizeof(struct keyserver_spec));
- uri=xstrdup(string);
+ duped_uri = uri = xstrdup (string);
options=strchr(uri,' ');
if(options)
@@ -434,11 +434,13 @@ parse_keyserver_uri (const char *string,int require_scheme)
goto fail;
}
+ xfree (duped_uri);
return keyserver;
fail:
free_keyserver_spec(keyserver);
+ xfree (duped_uri);
return NULL;
}
diff --git a/g10/main.h b/g10/main.h
index 7b716ffd6..0956f6693 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -289,6 +289,8 @@ void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
const char *newuid);
void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
const char *usagestr, const char *expirestr);
+void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
+ const char *uidtorev);
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
strlist_t uids, strlist_t locusr, int local);
void show_basic_key_info (KBNODE keyblock);
@@ -347,6 +349,9 @@ typedef struct import_stats_s *import_stats_t;
typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg);
int parse_import_options(char *str,unsigned int *options,int noisy);
+gpg_error_t parse_and_set_import_filter (const char *string);
+gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname,
+ kbnode_t *r_keyblock);
void import_keys (ctrl_t ctrl, char **fnames, int nnames,
import_stats_t stats_hd, unsigned int options);
int import_keys_stream (ctrl_t ctrl, iobuf_t inp, import_stats_t stats_hd,
@@ -376,6 +381,7 @@ void export_release_stats (export_stats_t stats);
void export_print_stats (export_stats_t stats);
int parse_export_options(char *str,unsigned int *options,int noisy);
+gpg_error_t parse_and_set_export_filter (const char *string);
int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options,
export_stats_t stats);
@@ -390,9 +396,13 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
int cleartext,
- char **cache_nonce_addr, const char *hexgrip,
+ char **cache_nonce_addr,
+ const char *hexgrip,
PKT_public_key *pk);
+gpg_error_t write_keyblock_to_output (kbnode_t keyblock,
+ int with_armor, unsigned int options);
+
gpg_error_t export_ssh_key (ctrl_t ctrl, const char *userid);
/*-- dearmor.c --*/
@@ -407,6 +417,7 @@ int gen_desig_revoke (ctrl_t ctrl, const char *uname, strlist_t locusr);
int revocation_reason_build_cb( PKT_signature *sig, void *opaque );
struct revocation_reason_info *
ask_revocation_reason( int key_rev, int cert_rev, int hint );
+struct revocation_reason_info * get_default_uid_revocation_reason(void);
void release_revocation_reason_info( struct revocation_reason_info *reason );
/*-- keylist.c --*/
@@ -415,7 +426,7 @@ void secret_key_list (ctrl_t ctrl, strlist_t list );
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,
- int has_secret, int fpr);
+ int has_secret, int fpr, int no_validity);
void print_fingerprint (estream_t fp, PKT_public_key *pk, int mode);
void print_revokers (estream_t fp, PKT_public_key *pk);
void show_policy_url(PKT_signature *sig,int indent,int mode);
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 453d1b07b..4217ccdb4 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -124,8 +124,6 @@ reset_literals_seen(void)
static void
release_list( CTX c )
{
- if (!c->list)
- return;
proc_tree (c, c->list);
release_kbnode (c->list);
while (c->pkenc_list)
@@ -1328,7 +1326,7 @@ do_proc_packets (ctrl_t ctrl, CTX c, iobuf_t a)
/* Stop processing when an invalid packet has been encountered
* but don't do so when we are doing a --list-packets. */
if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
- && opt.list_packets != 2 )
+ && opt.list_packets == 0)
break;
continue;
}
@@ -1805,19 +1803,26 @@ check_sig_and_print (CTX c, kbnode_t node)
* favor this over the WKD method (to be tried next), because an
* arbitrary keyserver is less subject to web bug like
* monitoring. */
- /* if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY */
- /* && signature_hash_full_fingerprint (sig) */
- /* && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE) */
- /* && keyserver_any_configured (c->ctrl)) */
- /* { */
- /* int res; */
-
- /* glo_ctrl.in_auto_key_retrieve++; */
- /* res = keyserver_import_keyid (c->ctrl, sig->keyid, opt.keyserver ); */
- /* glo_ctrl.in_auto_key_retrieve--; */
- /* if (!res) */
- /* rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey ); */
- /* } */
+ if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY
+ && opt.flags.rfc4880bis
+ && (opt.keyserver_options.options&KEYSERVER_AUTO_KEY_RETRIEVE)
+ && keyserver_any_configured (c->ctrl))
+ {
+ int res;
+ const byte *p;
+ size_t n;
+
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_ISSUER_FPR, &n);
+ if (p && n == 21 && p[0] == 4)
+ {
+ /* v4 packet with a SHA-1 fingerprint. */
+ glo_ctrl.in_auto_key_retrieve++;
+ res = keyserver_import_fprint (c->ctrl, p+1, n-1, opt.keyserver);
+ glo_ctrl.in_auto_key_retrieve--;
+ if (!res)
+ rc = do_check_sig (c, node, NULL, &is_expkey, &is_revkey );
+ }
+ }
/* If the above methods didn't work, our next try is to retrieve the
* key from the WKD. */
diff --git a/g10/options.h b/g10/options.h
index 0a87b9011..3c4f0fe38 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -57,6 +57,7 @@ struct
int dry_run;
int autostart;
int list_only;
+ int mimemode;
int textmode;
int expert;
const char *def_sig_expire;
@@ -80,7 +81,7 @@ struct
int print_pka_records;
int print_dane_records;
int no_armor;
- int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
+ int list_packets; /* Option --list-packets active. */
int def_cipher_algo;
int force_mdc;
int disable_mdc;
@@ -235,6 +236,8 @@ struct
unsigned int allow_weak_digest_algos:1;
unsigned int large_rsa:1;
unsigned int disable_signer_uid:1;
+ /* Flag to enbale experimental features from RFC4880bis. */
+ unsigned int rfc4880bis:1;
} flags;
/* Linked list of ways to find a key if the key isn't on the local
@@ -332,11 +335,13 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define IMPORT_LOCAL_SIGS (1<<0)
#define IMPORT_REPAIR_PKS_SUBKEY_BUG (1<<1)
#define IMPORT_FAST (1<<2)
+#define IMPORT_SHOW (1<<3)
#define IMPORT_MERGE_ONLY (1<<4)
#define IMPORT_MINIMAL (1<<5)
#define IMPORT_CLEAN (1<<6)
#define IMPORT_NO_SECKEY (1<<7)
#define IMPORT_KEEP_OWNERTTRUST (1<<8)
+#define IMPORT_EXPORT (1<<9)
#define EXPORT_LOCAL_SIGS (1<<0)
#define EXPORT_ATTRIBUTES (1<<1)
@@ -344,7 +349,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define EXPORT_RESET_SUBKEY_PASSWD (1<<3)
#define EXPORT_MINIMAL (1<<4)
#define EXPORT_CLEAN (1<<5)
-#define EXPORT_DANE_FORMAT (1<<6)
+#define EXPORT_PKA_FORMAT (1<<6)
+#define EXPORT_DANE_FORMAT (1<<7)
#define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1)
diff --git a/g10/packet.h b/g10/packet.h
index 8fb6fc48f..08e2cb7f6 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -291,9 +291,10 @@ typedef struct
unsigned int ks_modify:1;
unsigned int compacted:1;
} flags;
+ char *mbox; /* NULL or the result of mailbox_from_userid. */
/* The text contained in the user id packet, which is normally the
name and email address of the key holder (See RFC 4880 5.11).
- (Serialized.) */
+ (Serialized.). For convenience an extra Nul is always appended. */
char name[1];
} PKT_user_id;
@@ -764,7 +765,7 @@ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
-void build_sig_subpkt_from_sig( PKT_signature *sig );
+void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk);
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen,
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index e02238bfd..ec8a64121 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -211,7 +211,7 @@ set_packet_list_mode (int mode)
enable the list mode only with a special option. */
if (!listfp)
{
- if (opt.list_packets == 2)
+ if (opt.list_packets)
{
listfp = es_stdout;
if (opt.verbose)
@@ -1335,6 +1335,19 @@ dump_sig_subpkt (int hashed, int type, int critical,
(ulong) buf32_to_u32 (buffer),
(ulong) buf32_to_u32 (buffer + 4));
break;
+ case SIGSUBPKT_ISSUER_FPR:
+ if (length >= 21)
+ {
+ char *tmp;
+ es_fprintf (listfp, "issuer fpr v%d ", buffer[0]);
+ tmp = bin2hex (buffer+1, length-1, NULL);
+ if (tmp)
+ {
+ es_fputs (tmp, listfp);
+ xfree (tmp);
+ }
+ }
+ break;
case SIGSUBPKT_NOTATION:
{
es_fputs ("notation: ", listfp);
@@ -1485,6 +1498,10 @@ parse_one_sig_subpkt (const byte * buffer, size_t n, int type)
if (n < 8)
break;
return 0;
+ case SIGSUBPKT_ISSUER_FPR: /* issuer key ID */
+ if (n < 21)
+ break;
+ return 0;
case SIGSUBPKT_NOTATION:
/* minimum length needed, and the subpacket must be well-formed
where the name length and value length all fit inside the
@@ -1543,6 +1560,7 @@ can_handle_critical (const byte * buffer, size_t n, int type)
case SIGSUBPKT_REVOCABLE:
case SIGSUBPKT_REV_KEY:
case SIGSUBPKT_ISSUER: /* issuer key ID */
+ case SIGSUBPKT_ISSUER_FPR: /* issuer fingerprint */
case SIGSUBPKT_PREF_SYM:
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 8efa95432..6315a6d55 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -775,14 +775,16 @@ expand_id(const char *id,strlist_t *into,unsigned int flags)
}
/* For simplicity, and to avoid potential loops, we only expand once -
- you can't make an alias that points to an alias. */
+ * you can't make an alias that points to an alias. */
static strlist_t
-expand_group(strlist_t input)
+expand_group (strlist_t input)
{
- strlist_t sl,output=NULL,rover;
+ strlist_t output = NULL;
+ strlist_t sl, rover;
- for(rover=input;rover;rover=rover->next)
- if(expand_id(rover->d,&output,rover->flags)==0)
+ for (rover = input; rover; rover = rover->next)
+ if (!(rover->flags & PK_LIST_FROM_FILE)
+ && !expand_id(rover->d,&output,rover->flags))
{
/* Didn't find any groups, so use the existing string */
sl=add_to_strlist(&output,rover->d);
@@ -794,17 +796,18 @@ expand_group(strlist_t input)
/* Helper for build_pk_list to find and check one key. This helper is
- also used directly in server mode by the RECIPIENTS command. On
- success the new key is added to PK_LIST_ADDR. NAME is the user id
- of the key. USE the requested usage and a set MARK_HIDDEN will mark
- the key in the updated list as a hidden recipient. */
+ * also used directly in server mode by the RECIPIENTS command. On
+ * success the new key is added to PK_LIST_ADDR. NAME is the user id
+ * of the key. USE the requested usage and a set MARK_HIDDEN will
+ * mark the key in the updated list as a hidden recipient. If
+ * FROM_FILE is true, NAME is is not a user ID but the name of a file
+ * holding a key. */
gpg_error_t
find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
- int mark_hidden, pk_list_t *pk_list_addr)
+ int mark_hidden, int from_file, pk_list_t *pk_list_addr)
{
int rc;
PKT_public_key *pk;
- int trustlevel;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
@@ -814,7 +817,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
return gpg_error_from_syserror ();
pk->req_usage = use;
- rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
+ if (from_file)
+ rc = get_pubkey_fromfile (ctrl, pk, name);
+ else
+ rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
if (rc)
{
int code;
@@ -844,24 +850,28 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
}
/* Key found and usable. Check validity. */
- trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
- if ( (trustlevel & TRUST_FLAG_DISABLED) )
+ if (!from_file)
{
- /* Key has been disabled. */
- send_status_inv_recp (13, name);
- log_info (_("%s: skipped: public key is disabled\n"), name);
- free_public_key (pk);
- return GPG_ERR_UNUSABLE_PUBKEY;
- }
+ int trustlevel;
- if ( !do_we_trust_pre (pk, trustlevel) )
- {
- /* We don't trust this key. */
- send_status_inv_recp (10, name);
- free_public_key (pk);
- return GPG_ERR_UNUSABLE_PUBKEY;
+ trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
+ if ( (trustlevel & TRUST_FLAG_DISABLED) )
+ {
+ /* Key has been disabled. */
+ send_status_inv_recp (13, name);
+ log_info (_("%s: skipped: public key is disabled\n"), name);
+ free_public_key (pk);
+ return GPG_ERR_UNUSABLE_PUBKEY;
+ }
+
+ if ( !do_we_trust_pre (pk, trustlevel) )
+ {
+ /* We don't trust this key. */
+ send_status_inv_recp (10, name);
+ free_public_key (pk);
+ return GPG_ERR_UNUSABLE_PUBKEY;
+ }
}
- /* Note: do_we_trust may have changed the trustlevel. */
/* Skip the actual key if the key is already present in the
list. */
@@ -894,22 +904,24 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
/* This is the central function to collect the keys for recipients.
- It is thus used to prepare a public key encryption. encrypt-to
- keys, default keys and the keys for the actual recipients are all
- collected here. When not in batch mode and no recipient has been
- passed on the commandline, the function will also ask for
- recipients.
-
- RCPTS is a string list with the recipients; NULL is an allowed
- value but not very useful. Group expansion is done on these names;
- they may be in any of the user Id formats we can handle. The flags
- bits for each string in the string list are used for:
- Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
- Bit 1 (PK_LIST_HIDDEN) : This is a hidden recipient.
-
- On success a list of keys is stored at the address RET_PK_LIST; the
- caller must free this list. On error the value at this address is
- not changed.
+ * It is thus used to prepare a public key encryption. encrypt-to
+ * keys, default keys and the keys for the actual recipients are all
+ * collected here. When not in batch mode and no recipient has been
+ * passed on the commandline, the function will also ask for
+ * recipients.
+ *
+ * RCPTS is a string list with the recipients; NULL is an allowed
+ * value but not very useful. Group expansion is done on these names;
+ * they may be in any of the user Id formats we can handle. The flags
+ * bits for each string in the string list are used for:
+ *
+ * - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
+ * - PK_LIST_HIDDEN :: This is a hidden recipient.
+ * - PK_LIST_FROM_FILE :: The argument is a file with a key.
+ *
+ * On success a list of keys is stored at the address RET_PK_LIST; the
+ * caller must free this list. On error the value at this address is
+ * not changed.
*/
int
build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
@@ -1269,6 +1281,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
!!(remusr->flags&PK_LIST_HIDDEN),
+ !!(remusr->flags&PK_LIST_FROM_FILE),
&pk_list);
if (rc)
goto fail;
diff --git a/g10/plaintext.c b/g10/plaintext.c
index e118f6b4d..c9fb67cdc 100644
--- a/g10/plaintext.c
+++ b/g10/plaintext.c
@@ -217,11 +217,16 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
static off_t count = 0;
int err = 0;
int c;
- int convert = (pt->mode == 't' || pt->mode == 'u');
+ int convert;
#ifdef __riscos__
int filetype = 0xfff;
#endif
+ if (pt->mode == 't' || pt->mode == 'u' || pt->mode == 'm')
+ convert = pt->mode;
+ else
+ convert = 0;
+
/* Let people know what the plaintext info is. This allows the
receiving program to try and do something different based on the
format code (say, recode UTF-8 to local). */
@@ -279,8 +284,10 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
if (mfx->md)
gcry_md_putc (mfx->md, c);
#ifndef HAVE_DOSISH_SYSTEM
- if (c == '\r') /* convert to native line ending */
- continue; /* fixme: this hack might be too simple */
+ /* Convert to native line ending. */
+ /* fixme: this hack might be too simple */
+ if (c == '\r' && convert != 'm')
+ continue;
#endif
if (fp)
{
@@ -354,7 +361,7 @@ handle_plaintext (PKT_plaintext * pt, md_filter_context_t * mfx,
if (mfx->md)
gcry_md_putc (mfx->md, c);
#ifndef HAVE_DOSISH_SYSTEM
- if (convert && c == '\r')
+ if (c == '\r' && convert != 'm')
continue; /* fixme: this hack might be too simple */
#endif
if (fp)
diff --git a/g10/revoke.c b/g10/revoke.c
index 218ca59f0..15a91acbf 100644
--- a/g10/revoke.c
+++ b/g10/revoke.c
@@ -862,6 +862,16 @@ ask_revocation_reason( int key_rev, int cert_rev, int hint )
return reason;
}
+struct revocation_reason_info *
+get_default_uid_revocation_reason(void)
+{
+ struct revocation_reason_info *reason;
+ reason = xmalloc( sizeof *reason );
+ reason->code = 0x20; /* uid is no longer valid */
+ reason->desc = strdup(""); /* no text */
+ return reason;
+}
+
void
release_revocation_reason_info( struct revocation_reason_info *reason )
{
diff --git a/g10/server.c b/g10/server.c
index 771a8a7a9..258f08a5d 100644
--- a/g10/server.c
+++ b/g10/server.c
@@ -177,6 +177,7 @@ output_notify (assuan_context_t ctx, char *line)
/* RECIPIENT [--hidden] <userID>
+ RECIPIENT [--hidden] --file <filename>
Set the recipient for the encryption. <userID> should be the
internal representation of the key; the server may accept any other
@@ -192,9 +193,10 @@ cmd_recipient (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- int hidden;
+ int hidden, file;
hidden = has_option (line,"--hidden");
+ file = has_option (line,"--file");
line = skip_options (line);
/* FIXME: Expand groups
@@ -204,7 +206,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
remusr = rcpts;
*/
- err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden,
+ err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden, file,
&ctrl->server_local->recplist);
if (err)
diff --git a/g10/sign.c b/g10/sign.c
index a4974be85..6a7a87e03 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -156,6 +156,7 @@ mk_notation_policy_etc (PKT_signature *sig,
if (DBG_LOOKUP)
log_debug ("setting Signer's UID to '%s'\n", mbox);
build_sig_subpkt (sig, SIGSUBPKT_SIGNERS_UID, mbox, strlen (mbox));
+ xfree (mbox);
}
}
}
@@ -604,7 +605,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
* data, it is not possible to know the used length
* without a double read of the file - to avoid that
* we simple use partial length packets. */
- if ( ptmode == 't' )
+ if ( ptmode == 't' || ptmode == 'u' || ptmode == 'm')
filesize = 0;
}
else
@@ -627,6 +628,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
log_error ("build_packet(PLAINTEXT) failed: %s\n",
gpg_strerror (rc) );
pt->buf = NULL;
+ free_packet (&pkt);
}
else {
byte copy_buffer[4096];
@@ -690,7 +692,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
if (sig->version >= 4)
{
- build_sig_subpkt_from_sig (sig);
+ build_sig_subpkt_from_sig (sig, pk);
mk_notation_policy_etc (sig, NULL, pk);
}
@@ -1031,7 +1033,8 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
}
else {
rc = write_plaintext_packet (out, inp, fname,
- opt.textmode && !outfile ? 't':'b');
+ opt.textmode && !outfile ?
+ (opt.mimemode? 'm':'t'):'b');
}
/* catch errors from above */
@@ -1335,7 +1338,8 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
/* Pipe data through all filters; i.e. write the signed stuff */
/*(current filters: zip - encrypt - armor)*/
- rc = write_plaintext_packet (out, inp, fname, opt.textmode ? 't':'b');
+ rc = write_plaintext_packet (out, inp, fname,
+ opt.textmode ? (opt.mimemode?'m':'t'):'b');
if (rc)
goto leave;
@@ -1456,7 +1460,7 @@ make_keysig_packet (PKT_signature **ret_sig, PKT_public_key *pk,
sig->expiredate=sig->timestamp+duration;
sig->sig_class = sigclass;
- build_sig_subpkt_from_sig( sig );
+ build_sig_subpkt_from_sig (sig, pksk);
mk_notation_policy_etc (sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls
@@ -1559,7 +1563,7 @@ update_keysig_packet( PKT_signature **ret_sig,
automagically lower any sig expiration dates to correctly
correspond to the differences in the timestamps (i.e. the
duration will shrink). */
- build_sig_subpkt_from_sig( sig );
+ build_sig_subpkt_from_sig (sig, pksk);
if (mksubpkt)
rc = (*mksubpkt)(sig, opaque);
diff --git a/g10/t-keydb-get-keyblock.c b/g10/t-keydb-get-keyblock.c
index c12bab182..cab1448da 100644
--- a/g10/t-keydb-get-keyblock.c
+++ b/g10/t-keydb-get-keyblock.c
@@ -59,4 +59,6 @@ do_test (int argc, char *argv[])
rc = keydb_get_keyblock (hd1, &kb1);
TEST_P ("", ! rc);
+
+ keydb_release (hd1);
}
diff --git a/g10/t-keydb.c b/g10/t-keydb.c
index f0b7778b6..3606e2ea2 100644
--- a/g10/t-keydb.c
+++ b/g10/t-keydb.c
@@ -27,7 +27,7 @@ do_test (int argc, char *argv[])
int rc;
KEYDB_HANDLE hd1, hd2;
KEYDB_SEARCH_DESC desc1, desc2;
- KBNODE kb1, kb2;
+ KBNODE kb1, kb2, p;
char *uid1;
char *uid2;
char *fname;
@@ -75,17 +75,19 @@ do_test (int argc, char *argv[])
if (rc)
ABORT ("Failed to get keyblock for DBFC6AD9");
- while (kb1 && kb1->pkt->pkttype != PKT_USER_ID)
- kb1 = kb1->next;
- if (! kb1)
+ p = kb1;
+ while (p && p->pkt->pkttype != PKT_USER_ID)
+ p = p->next;
+ if (! p)
ABORT ("DBFC6AD9 has no user id packet");
- uid1 = kb1->pkt->pkt.user_id->name;
+ uid1 = p->pkt->pkt.user_id->name;
- while (kb2 && kb2->pkt->pkttype != PKT_USER_ID)
- kb2 = kb2->next;
- if (! kb2)
+ p = kb2;
+ while (p && p->pkt->pkttype != PKT_USER_ID)
+ p = p->next;
+ if (! p)
ABORT ("1E42B367 has no user id packet");
- uid2 = kb2->pkt->pkt.user_id->name;
+ uid2 = p->pkt->pkt.user_id->name;
if (verbose)
{
@@ -94,4 +96,9 @@ do_test (int argc, char *argv[])
}
TEST_P ("cache consistency", strcmp (uid1, uid2) != 0);
+
+ release_kbnode (kb1);
+ release_kbnode (kb2);
+ keydb_release (hd1);
+ keydb_release (hd2);
}
diff --git a/g10/t-stutter.c b/g10/t-stutter.c
index 9576027a3..f3fc65330 100644
--- a/g10/t-stutter.c
+++ b/g10/t-stutter.c
@@ -606,5 +606,6 @@ main (int argc, char *argv[])
log_fatal ("Message is too short, nothing to test.\n");
}
+ xfree (filename);
return failed;
}
diff --git a/g10/test-stubs.c b/g10/test-stubs.c
index 42c91f869..6f50759d5 100644
--- a/g10/test-stubs.c
+++ b/g10/test-stubs.c
@@ -177,6 +177,17 @@ keyserver_import_keyid (u32 *keyid, void *dummy)
}
int
+keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
+ struct keyserver_spec *keyserver)
+{
+ (void)ctrl;
+ (void)fprint;
+ (void)fprint_len;
+ (void)keyserver;
+ return -1;
+}
+
+int
keyserver_import_cert (const char *name)
{
(void)name;
@@ -217,6 +228,15 @@ keyserver_import_ldap (const char *name)
return -1;
}
+gpg_error_t
+read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
+{
+ (void)ctrl;
+ (void)fname;
+ (void)r_keyblock;
+ return -1;
+}
+
/* Stub:
* No encryption here but mainproc links to these functions.
*/
diff --git a/g10/textfilter.c b/g10/textfilter.c
index 5929c5f46..6ca4f8806 100644
--- a/g10/textfilter.c
+++ b/g10/textfilter.c
@@ -240,5 +240,6 @@ copy_clearsig_text( IOBUF out, IOBUF inp, gcry_md_hd_t md,
if( truncated )
log_info(_("input line longer than %d characters\n"), MAX_LINELEN );
+ xfree (buffer);
return 0; /* okay */
}
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 527a23d2f..dd74d187b 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -1022,17 +1022,18 @@ tdb_get_validity_core (ctrl_t ctrl,
#ifdef USE_TOFU
if (opt.trust_model == TM_TOFU || opt.trust_model == TM_TOFU_PGP)
{
- kbnode_t user_id_node = NULL; /* Silence -Wmaybe-uninitialized. */
+ kbnode_t user_id_node = NULL;
+ kbnode_t n = NULL; /* Silence -Wmaybe-uninitialized. */
int user_ids = 0;
int user_ids_expired = 0;
/* If the caller didn't supply a user id then iterate over all
uids. */
if (! uid)
- user_id_node = get_pubkeyblock (main_pk->keyid);
+ user_id_node = n = get_pubkeyblock (main_pk->keyid);
while (uid
- || (user_id_node = find_next_kbnode (user_id_node, PKT_USER_ID)))
+ || (n = find_next_kbnode (n, PKT_USER_ID)))
{
unsigned int tl;
PKT_user_id *user_id;
@@ -1040,7 +1041,7 @@ tdb_get_validity_core (ctrl_t ctrl,
if (uid)
user_id = uid;
else
- user_id = user_id_node->pkt->pkt.user_id;
+ user_id = n->pkt->pkt.user_id;
/* If the user id is revoked or expired, then skip it. */
if (user_id->is_revoked || user_id->is_expired)
@@ -1094,6 +1095,7 @@ tdb_get_validity_core (ctrl_t ctrl,
now. */
break;
}
+ release_kbnode (user_id_node);
}
#endif /*USE_TOFU*/