aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/build-packet.c12
-rw-r--r--g10/card-util.c17
-rw-r--r--g10/free-packet.c30
-rw-r--r--g10/getkey.c25
-rw-r--r--g10/gpg.c98
-rw-r--r--g10/gpgv.c2
-rw-r--r--g10/import.c1
-rw-r--r--g10/key-clean.c76
-rw-r--r--g10/keydb.c31
-rw-r--r--g10/keydb.h15
-rw-r--r--g10/keyedit.c288
-rw-r--r--g10/keyedit.h1
-rw-r--r--g10/keygen.c167
-rw-r--r--g10/keylist.c69
-rw-r--r--g10/main.h9
-rw-r--r--g10/mainproc.c5
-rw-r--r--g10/misc.c15
-rw-r--r--g10/options.h8
-rw-r--r--g10/packet.h18
-rw-r--r--g10/pkclist.c36
-rw-r--r--g10/sig-check.c3
-rw-r--r--g10/sign.c30
-rw-r--r--g10/t-keydb-get-keyblock.c9
-rw-r--r--g10/t-keydb.c10
-rw-r--r--g10/t-stutter.c9
-rw-r--r--g10/trust.c2
-rw-r--r--g10/verify.c124
27 files changed, 919 insertions, 191 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c
index f33d156b3..192dfaef5 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -1345,19 +1345,23 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
/*
* Put all the required stuff from SIG into subpackets of sig.
- * PKSK is the signing key.
+ * PKSK is the signing key. SIGNHINTS are various flags like
+ * SIGNHINT_ADSK.
* Hmmm, should we delete those subpackets which are in a wrong area?
*/
void
-build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
+build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
+ unsigned int signhints)
{
u32 u;
byte buf[1+MAX_FINGERPRINT_LEN];
size_t fprlen;
/* For v4 keys we need to write the ISSUER subpacket. We do not
- * want that for a future v5 format. */
- if (pksk->version < 5)
+ * want that for a future v5 format. We also don't write it if
+ * only the new RENC keyflag is set (implementations with support
+ * for this key flag should understand the ISSUER_FPR). */
+ if (pksk->version < 5 && !(signhints & SIGNHINT_ADSK))
{
u = sig->keyid[0];
buf[0] = (u >> 24) & 0xff;
diff --git a/g10/card-util.c b/g10/card-util.c
index 02de241f2..6451b31e7 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -1781,12 +1781,13 @@ card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock)
}
-/* Store the key at NODE into the smartcard and modify NODE to
- carry the serialno stuff instead of the actual secret key
- parameters. USE is the usage for that key; 0 means any
- usage. */
+/* Store the key at NODE into the smartcard and modify NODE to carry
+ the serialno stuff instead of the actual secret key parameters.
+ USE is the usage for that key; 0 means any usage. If
+ PROCESSED_KEYS is not NULL it is a poiter to an strlist which will
+ be filled with the keygrips of successfully stored keys. */
int
-card_store_subkey (KBNODE node, int use)
+card_store_subkey (KBNODE node, int use, strlist_t *processed_keys)
{
struct agent_card_info_s info;
int okay = 0;
@@ -1875,7 +1876,11 @@ card_store_subkey (KBNODE node, int use)
if (rc)
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
else
- okay = 1;
+ {
+ okay = 1;
+ if (processed_keys)
+ add_to_strlist (processed_keys, hexgrip);
+ }
xfree (hexgrip);
leave:
diff --git a/g10/free-packet.c b/g10/free-packet.c
index 243cc7518..b0642043e 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -211,10 +211,10 @@ copy_prefs (const prefitem_t *prefs)
/* Copy the public key S to D. If D is NULL allocate a new public key
- structure. If S has seckret key infos, only the public stuff is
- copied. */
+ * structure. Only the basic stuff is copied; not any ancillary
+ * data. */
PKT_public_key *
-copy_public_key (PKT_public_key *d, PKT_public_key *s)
+copy_public_key_basics (PKT_public_key *d, PKT_public_key *s)
{
int n, i;
@@ -222,8 +222,8 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
d = xmalloc (sizeof *d);
memcpy (d, s, sizeof *d);
d->seckey_info = NULL;
- d->user_id = scopy_user_id (s->user_id);
- d->prefs = copy_prefs (s->prefs);
+ d->user_id = NULL;
+ d->prefs = NULL;
n = pubkey_get_npkey (s->pubkey_algo);
i = 0;
@@ -237,6 +237,24 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
for (; i < PUBKEY_MAX_NSKEY; i++)
d->pkey[i] = NULL;
+ d->revkey = NULL;
+ d->serialno = NULL;
+ d->updateurl = NULL;
+
+ return d;
+}
+
+
+/* Copy the public key S to D. If D is NULL allocate a new public key
+ structure. If S has seckret key infos, only the public stuff is
+ copied. */
+PKT_public_key *
+copy_public_key (PKT_public_key *d, PKT_public_key *s)
+{
+ d = copy_public_key_basics (d, s);
+ d->user_id = scopy_user_id (s->user_id);
+ d->prefs = copy_prefs (s->prefs);
+
if (!s->revkey && s->numrevkeys)
BUG();
if (s->numrevkeys)
@@ -244,8 +262,6 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
}
- else
- d->revkey = NULL;
if (s->serialno)
d->serialno = xstrdup (s->serialno);
diff --git a/g10/getkey.c b/g10/getkey.c
index 6363fea9f..1b37c597d 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1718,7 +1718,8 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
*
* 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.
+ * is not found. If R_KEYBLOCK is not NULL and a key was found the
+ * keyblock is stored there; otherwiese NULL is stored there.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by
@@ -1726,13 +1727,17 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
* free_public_key).
*/
gpg_error_t
-get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
+get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname,
+ kbnode_t *r_keyblock)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t found_key;
unsigned int infoflags;
+ if (r_keyblock)
+ *r_keyblock = NULL;
+
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
if (!err)
{
@@ -1747,7 +1752,10 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
- release_kbnode (keyblock);
+ if (!err && r_keyblock)
+ *r_keyblock = keyblock;
+ else
+ release_kbnode (keyblock);
return err;
}
@@ -1809,12 +1817,12 @@ get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
* returned public key may be a subkey rather than the primary key.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
- * release_public_key_parts (or, if PK was allocated using xfree, you
+ * release_public_key_parts (or, if PK was allocated using xmalloc, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If PK->REQ_USAGE is set, it is used to filter the search results.
- * (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the
+ * Thus, if PK is not NULL, PK->REQ_USAGE must be valid! See the
* documentation for finish_lookup to understand exactly how this is
* used.
*
@@ -2417,7 +2425,8 @@ merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock)
}
-static int
+/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
+unsigned int
parse_key_usage (PKT_signature * sig)
{
int key_usage = 0;
@@ -2707,7 +2716,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
* and there was no way to change it, so we start with the one
* from the key packet. We do not support v3 keys anymore but
* we keep the code in case a future key versions introduces a
- * hadr expire time again. */
+ * hard expire time again. */
key_expire = pk->max_expiredate;
key_expire_seen = 1;
}
@@ -3247,7 +3256,7 @@ buf_to_sig (const byte * buf, size_t len)
* has_expired
* expired_date
*
- * On this subkey's most revent valid self-signed packet, the
+ * On this subkey's most recent valid self-signed packet, the
* following field is set:
*
* flags.chosen_selfsig
diff --git a/g10/gpg.c b/g10/gpg.c
index dd0bf0167..b759cc1cf 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -130,6 +130,7 @@ enum cmd_and_opt_values
aQuickRevSig,
aQuickAddUid,
aQuickAddKey,
+ aQuickAddADSK,
aQuickRevUid,
aQuickSetExpire,
aQuickSetPrimaryUid,
@@ -337,6 +338,7 @@ enum cmd_and_opt_values
oEncryptToDefaultKey,
oLoggerFD,
oLoggerFile,
+ oLogTime,
oUtf8Strings,
oNoUtf8Strings,
oDisableCipherAlgo,
@@ -443,6 +445,8 @@ enum cmd_and_opt_values
oForbidGenKey,
oRequireCompliance,
oCompatibilityFlags,
+ oAddDesigRevoker,
+ oAssertSigner,
oNoop
};
@@ -484,6 +488,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_c (aQuickAddUid, "quick-adduid", "@"),
ARGPARSE_c (aQuickAddKey, "quick-add-key", "@"),
ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"),
+ ARGPARSE_c (aQuickAddADSK, "quick-add-adsk", "@"),
ARGPARSE_c (aQuickRevUid, "quick-revoke-uid",
N_("quickly revoke a user-id")),
ARGPARSE_c (aQuickRevUid, "quick-revuid", "@"),
@@ -599,6 +604,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oLoggerFile, "log-file",
N_("|FILE|write server mode logs to FILE")),
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
+ ARGPARSE_s_n (oLogTime, "log-time", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@@ -702,7 +708,8 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"),
ARGPARSE_s_n (oNoAutoTrustNewKey, "no-auto-trust-new-key", "@"),
#endif
-
+ ARGPARSE_s_s (oAddDesigRevoker, "add-desig-revoker", "@"),
+ ARGPARSE_s_s (oAssertSigner, "assert-signer", "@"),
ARGPARSE_header ("Input", N_("Options controlling the input")),
@@ -1026,8 +1033,12 @@ static struct compatibility_flags_s compatibility_flags [] =
/* The list of the default AKL methods. */
#define DEFAULT_AKL_LIST "local,wkd"
-
+/* Can be set to true to force gpg to return with EXIT_FAILURE. */
int g10_errors_seen = 0;
+/* If opt.assert_signer_list is used and this variabale is not true
+ * gpg will be forced to return EXIT_FAILURE. */
+int assert_signer_true = 0;
+
static int utf8_strings =
#ifdef HAVE_W32_SYSTEM
@@ -1039,6 +1050,7 @@ static int utf8_strings =
static int maybe_setuid = 1;
static unsigned int opt_set_iobuf_size;
static unsigned int opt_set_iobuf_size_used;
+static int opt_log_time;
/* Collection of options used only in this module. */
static struct {
@@ -2047,6 +2059,8 @@ parse_list_options(char *str)
char *subpackets=""; /* something that isn't NULL */
struct parse_options lopts[]=
{
+ {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL,
+ NULL},
{"show-photos",LIST_SHOW_PHOTOS,NULL,
N_("display photo IDs during key listings")},
{"show-usage",LIST_SHOW_USAGE,NULL,
@@ -2069,6 +2083,8 @@ parse_list_options(char *str)
N_("show revoked and expired user IDs in key listings")},
{"show-unusable-subkeys",LIST_SHOW_UNUSABLE_SUBKEYS,NULL,
N_("show revoked and expired subkeys in key listings")},
+ {"show-unusable-sigs",LIST_SHOW_UNUSABLE_SIGS,NULL,
+ N_("show signatures with invalid algorithms during signature listings")},
{"show-keyring",LIST_SHOW_KEYRING,NULL,
N_("show the keyring name in key listings")},
{"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL,
@@ -2077,20 +2093,25 @@ parse_list_options(char *str)
N_("show preferences")},
{"show-pref-verbose", LIST_SHOW_PREF_VERBOSE, NULL,
N_("show preferences")},
- {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL,
- NULL},
{"show-only-fpr-mbox",LIST_SHOW_ONLY_FPR_MBOX, NULL,
NULL},
{"sort-sigs", LIST_SORT_SIGS, NULL,
NULL},
{NULL,0,NULL,NULL}
};
+ int i;
/* C99 allows for non-constant initializers, but we'd like to
compile everywhere, so fill in the show-sig-subpackets argument
here. Note that if the parse_options array changes, we'll have
- to change the subscript here. */
- lopts[13].value=&subpackets;
+ to change the subscript here. We use a loop here in case the
+ list above is reordered. */
+ for (i=0; lopts[i].name; i++)
+ if (lopts[i].bit == LIST_SHOW_SIG_SUBPACKETS)
+ {
+ lopts[i].value = &subpackets;
+ break;
+ }
if(parse_options(str,&opt.list_options,lopts,1))
{
@@ -2677,6 +2698,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
+ case aQuickAddADSK:
case aQuickRevUid:
case aQuickSetExpire:
case aQuickSetPrimaryUid:
@@ -2853,6 +2875,9 @@ main (int argc, char **argv)
case oLoggerFile:
logfile = pargs.r.ret_str;
break;
+ case oLogTime:
+ opt_log_time = 1;
+ break;
case oWithFingerprint:
opt.with_fingerprint = 1;
@@ -3707,6 +3732,18 @@ main (int argc, char **argv)
opt.flags.require_compliance = 1;
break;
+ case oAddDesigRevoker:
+ if (!strcmp (pargs.r.ret_str, "clear"))
+ FREE_STRLIST (opt.desig_revokers);
+ else
+ append_to_strlist (&opt.desig_revokers, pargs.r.ret_str);
+ break;
+
+ case oAssertSigner:
+ add_to_strlist (&opt.assert_signer_list, pargs.r.ret_str);
+ break;
+
+
case oNoop: break;
default:
@@ -3811,6 +3848,9 @@ main (int argc, char **argv)
| GPGRT_LOG_WITH_TIME
| GPGRT_LOG_WITH_PID ));
}
+ else if (opt_log_time)
+ log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY
+ |GPGRT_LOG_WITH_TIME));
if (opt.verbose > 2)
log_info ("using character set '%s'\n", get_native_charset ());
@@ -4157,17 +4197,27 @@ main (int argc, char **argv)
* 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 or --use-keyboxd has
- * been used. */
+ * been used. Note that keydb_add_resource may create a new
+ * homedir and also tries to write a common.conf to enable the use
+ * of the keyboxd - in this case a special error code is returned
+ * and use_keyboxd is then also set. */
if (!opt.use_keyboxd
&& default_keyring >= 0
&& (ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{
+ gpg_error_t tmperr = 0;
+
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 )
- keydb_add_resource (sl->d, sl->flags);
+ tmperr = keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
+ KEYDB_RESOURCE_FLAG_DEFAULT);
+ if (gpg_err_code (tmperr) == GPG_ERR_TRUE && opt.use_keyboxd)
+ ; /* The keyboxd has been enabled. */
+ else
+ {
+ for (sl = nrings; sl; sl = sl->next )
+ keydb_add_resource (sl->d, sl->flags);
+ }
}
FREE_STRLIST(nrings);
@@ -4275,6 +4325,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
+ case aQuickAddADSK:
case aQuickRevUid:
case aQuickSetPrimaryUid:
case aQuickUpdatePref:
@@ -4742,6 +4793,17 @@ main (int argc, char **argv)
}
break;
+ case aQuickAddADSK:
+ {
+ if (argc != 2)
+ wrong_args ("--quick-add-adsk FINGERPRINT ADSK-FINGERPRINT");
+ if (mopt.forbid_gen_key)
+ gen_key_forbidden ();
+ else
+ keyedit_quick_addadsk (ctrl, argv[0], argv[1]);
+ }
+ break;
+
case aQuickRevUid:
{
const char *uid, *uidtorev;
@@ -5048,9 +5110,6 @@ main (int argc, char **argv)
size_t nn;
p = gcry_random_bytes (n, level);
-#ifdef HAVE_DOSISH_SYSTEM
- setmode ( fileno(stdout), O_BINARY );
-#endif
if (hexhack)
{
for (nn = 0; nn < n; nn++)
@@ -5068,6 +5127,7 @@ main (int argc, char **argv)
}
else
{
+ es_set_binary (es_stdout);
es_fwrite( p, n, 1, es_stdout );
}
xfree(p);
@@ -5398,7 +5458,15 @@ g10_exit( int rc )
gnupg_block_all_signals ();
emergency_cleanup ();
- rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;
+ if (rc)
+ ;
+ else if (log_get_errorcount(0))
+ rc = 2;
+ else if (g10_errors_seen)
+ rc = 1;
+ else if (opt.assert_signer_list && !assert_signer_true)
+ rc = 1;
+
exit (rc);
}
diff --git a/g10/gpgv.c b/g10/gpgv.c
index ceded4af9..f2895563e 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -118,7 +118,7 @@ static struct debug_flags_s debug_flags [] =
int g10_errors_seen = 0;
-
+int assert_signer_true = 0;
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
diff --git a/g10/import.c b/g10/import.c
index 9fab46ca6..1ed40a63c 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -2656,6 +2656,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
* in case of cv25519. We have only opaque MPIs here. */
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH
&& !strcmp (curvestr, "1.3.6.1.4.1.3029.1.5.1")
+ && !gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1)
&& gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
{
const unsigned char *pp;
diff --git a/g10/key-clean.c b/g10/key-clean.c
index 9320428c8..c8a6efe50 100644
--- a/g10/key-clean.c
+++ b/g10/key-clean.c
@@ -35,14 +35,19 @@
#include "key-clean.h"
+#define NF_USABLE 8 /* Usable signature and not a revocation. */
+#define NF_CONSIDER 9 /* Internal use. */
+#define NF_PROCESSED 10 /* Internal use. */
+#define NF_REVOC 11 /* Usable revocation. */
+#define NF_NOKEY 12 /* Key not available. */
+
/*
* Mark the signature of the given UID which are used to certify it.
* To do this, we first remove all signatures which are not valid and
* from the remaining we look for the latest one. If this is not a
* certification revocation signature we mark the signature by setting
- * node flag bit 8. Revocations are marked with flag 11, and sigs
- * from unavailable keys are marked with flag 12. Note that flag bits
- * 9 and 10 are used for internal purposes.
+ * node flag bit NF_USABLE. Revocations are marked with NF_REVOC, and
+ * sigs from unavailable keys are marked with NF_NOKEY.
*/
void
mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
@@ -57,7 +62,8 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
{
int rc;
- node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
+ node->flag &= ~(1<<NF_USABLE | 1<<NF_CONSIDER
+ | 1<<NF_PROCESSED | 1<<NF_REVOC | 1<<NF_NOKEY);
if (node->pkt->pkttype == PKT_USER_ID
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
@@ -81,19 +87,20 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
/* we ignore anything that won't verify, but tag the
no_pubkey case */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
- node->flag |= 1<<12;
+ node->flag |= 1<<NF_NOKEY;
continue;
}
- node->flag |= 1<<9;
+ node->flag |= 1<<NF_CONSIDER;
}
/* Reset the remaining flags. */
for (; node; node = node->next)
- node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
+ node->flag &= ~(1<<NF_USABLE | 1<<NF_CONSIDER
+ | 1<<NF_PROCESSED | 1<<NF_REVOC | 1<<NF_NOKEY);
- /* kbnode flag usage: bit 9 is here set for signatures to consider,
- * bit 10 will be set by the loop to keep track of keyIDs already
- * processed, bit 8 will be set for the usable signatures, and bit
- * 11 will be set for usable revocations. */
+ /* kbnode flag usage: bit NF_CONSIDER is here set for signatures to consider,
+ * bit NF_PROCESSED will be set by the loop to keep track of keyIDs already
+ * processed, bit NF_USABLE will be set for the usable signatures, and bit
+ * NF_REVOC will be set for usable revocations. */
/* For each cert figure out the latest valid one. */
for (node=uidnode->next; node; node = node->next)
@@ -105,11 +112,11 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
break;
- if ( !(node->flag & (1<<9)) )
+ if ( !(node->flag & (1<<NF_CONSIDER)) )
continue; /* not a node to look at */
- if ( (node->flag & (1<<10)) )
+ if ( (node->flag & (1<<NF_PROCESSED)) )
continue; /* signature with a keyID already processed */
- node->flag |= (1<<10); /* mark this node as processed */
+ node->flag |= (1<<NF_PROCESSED); /* mark this node as processed */
sig = node->pkt->pkt.signature;
signode = node;
sigdate = sig->timestamp;
@@ -121,14 +128,14 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| n->pkt->pkttype == PKT_SECRET_SUBKEY)
break;
- if ( !(n->flag & (1<<9)) )
+ if ( !(n->flag & (1<<NF_CONSIDER)) )
continue;
- if ( (n->flag & (1<<10)) )
+ if ( (n->flag & (1<<NF_PROCESSED)) )
continue; /* shortcut already processed signatures */
sig = n->pkt->pkt.signature;
if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
continue;
- n->flag |= (1<<10); /* mark this node as processed */
+ n->flag |= (1<<NF_PROCESSED); /* mark this node as processed */
/* If signode is nonrevocable and unexpired and n isn't,
then take signode (skip). It doesn't matter which is
@@ -197,13 +204,13 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
if (expire==0 || expire > curtime )
{
- signode->flag |= (1<<8); /* yeah, found a good cert */
+ signode->flag |= (1<<NF_USABLE); /* yeah, found a good cert */
if (next_expire && expire && expire < *next_expire)
*next_expire = expire;
}
}
else
- signode->flag |= (1<<11);
+ signode->flag |= (1<<NF_REVOC);
}
}
@@ -231,12 +238,13 @@ clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
signatures are out, as are any signatures that aren't the last of
a series of uid sigs or revocations It breaks down like this:
coming out of mark_usable_uid_certs, if a sig is unflagged, it is
- not even a candidate. If a sig has flag 9 or 10, that means it
- was selected as a candidate and vetted. If a sig has flag 8 it
- is a usable signature. If a sig has flag 11 it is a usable
- revocation. If a sig has flag 12 it was issued by an unavailable
- key. "Usable" here means the most recent valid
- signature/revocation in a series from a particular signer.
+ not even a candidate. If a sig has flag NF_CONSIDER or
+ NF_PROCESSED, that means it was selected as a candidate and
+ vetted. If a sig has flag NF_USABLE it is a usable signature.
+ If a sig has flag NF_REVOC it is a usable revocation. If a sig
+ has flag NF_NOKEY it was issued by an unavailable key. "Usable"
+ here means the most recent valid signature/revocation in a series
+ from a particular signer.
Delete everything that isn't a usable uid sig (which might be
expired), a usable revocation, or a sig from an unavailable
@@ -252,34 +260,34 @@ clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
&& node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
/* Keep usable uid sigs ... */
- if ((node->flag & (1<<8)) && keep)
+ if ((node->flag & (1<<NF_USABLE)) && keep)
continue;
/* ... and usable revocations... */
- if ((node->flag & (1<<11)) && keep)
+ if ((node->flag & (1<<NF_REVOC)) && keep)
continue;
/* ... and sigs from unavailable keys. */
/* disabled for now since more people seem to want sigs from
unavailable keys removed altogether. */
/*
- if(node->flag & (1<<12))
+ if(node->flag & (1<<NF_NOKEY))
continue;
*/
/* Everything else we delete */
- /* At this point, if 12 is set, the signing key was unavailable.
- If 9 or 10 is set, it's superseded. Otherwise, it's
- invalid. */
+ /* At this point, if NF_NOKEY is set, the signing key was
+ * unavailable. If NF_CONSIDER or NF_PROCESSED is set, it's
+ * superseded. Otherwise, it's invalid. */
if (noisy)
log_info ("removing signature from key %s on user ID \"%s\": %s\n",
keystr (node->pkt->pkt.signature->keyid),
uidnode->pkt->pkt.user_id->name,
- node->flag&(1<<12)? "key unavailable":
- node->flag&(1<<9)? "signature superseded"
- /* */ :"invalid signature" );
+ node->flag&(1<<NF_NOKEY)? "key unavailable":
+ node->flag&(1<<NF_CONSIDER)? "signature superseded"
+ /* */ : "invalid signature" );
delete_kbnode (node);
deleted++;
diff --git a/g10/keydb.c b/g10/keydb.c
index 3938d7e16..d2d085291 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -37,6 +37,7 @@
#include "../kbx/keybox.h"
#include "keydb.h"
#include "../common/i18n.h"
+#include "../common/comopt.h"
#include "keydb-private.h" /* For struct keydb_handle_s */
@@ -265,8 +266,24 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
*last_slash_in_filename = save_slash;
goto leave;
}
+
+ *last_slash_in_filename = save_slash;
+
+ if (!opt.use_keyboxd
+ && !parse_comopt (GNUPG_MODULE_NAME_GPG, 0)
+ && comopt.use_keyboxd)
+ {
+ /* The above try_make_homedir created a new default hoemdir
+ * and also wrote a new common.conf. Thus we now see that
+ * use-keyboxd has been set. Let's set this option and
+ * return a dedicated error code. */
+ opt.use_keyboxd = comopt.use_keyboxd;
+ rc = gpg_error (GPG_ERR_TRUE);
+ goto leave;
+ }
}
- *last_slash_in_filename = save_slash;
+ else
+ *last_slash_in_filename = save_slash;
/* To avoid races with other instances of gpg trying to create or
update the keyring (it is removed during an update for a short
@@ -555,7 +572,8 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
* If KEYDB_RESOURCE_FLAG_READONLY is set and the resource is a
* keyring (not a keybox), then the keyring is marked as read only and
* operations just as keyring_insert_keyblock will return
- * GPG_ERR_ACCESS. */
+ * GPG_ERR_ACCESS.
+ */
gpg_error_t
keydb_add_resource (const char *url, unsigned int flags)
{
@@ -774,9 +792,12 @@ keydb_add_resource (const char *url, unsigned int flags)
leave:
if (err)
{
- log_error (_("keyblock resource '%s': %s\n"),
- filename, gpg_strerror (err));
- write_status_error ("add_keyblock_resource", err);
+ if (gpg_err_code (err) != GPG_ERR_TRUE)
+ {
+ log_error (_("keyblock resource '%s': %s\n"),
+ filename, gpg_strerror (err));
+ write_status_error ("add_keyblock_resource", err);
+ }
}
else
any_registered = 1;
diff --git a/g10/keydb.h b/g10/keydb.h
index 771bc8e16..9323e3137 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -391,7 +391,8 @@ gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
/* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
- PKT_public_key *pk, const char *fname);
+ PKT_public_key *pk, const char *fname,
+ kbnode_t *r_keyblock);
/* Get a public key from a buffer. */
gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
@@ -468,6 +469,9 @@ void setup_main_keyids (kbnode_t keyblock);
data structures. */
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
+/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
+unsigned int parse_key_usage (PKT_signature *sig);
+
char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
@@ -511,11 +515,18 @@ keyid_cmp (const u32 *a, const u32 *b)
return 0;
}
+/* Return true if both keyids are equal. */
+static int GPGRT_ATTR_UNUSED
+keyid_eq (const u32 *a, const u32 *b)
+{
+ return a[0] == b[0] && a[1] == b[1];
+}
+
/* Return whether PK is a primary key. */
static int GPGRT_ATTR_UNUSED
pk_is_primary (PKT_public_key *pk)
{
- return keyid_cmp (pk_keyid (pk), pk_main_keyid (pk)) == 0;
+ return keyid_eq (pk_keyid (pk), pk_main_keyid (pk));
}
/* Copy the keyid in SRC to DEST and return DEST. */
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 83c20b846..a91cc4447 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -1,7 +1,7 @@
/* keyedit.c - Edit properties of a key
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2017 Werner Koch
- * Copyright (C) 2015, 2016, 2022 g10 Code GmbH
+ * Copyright (C) 2015, 2016, 2022-2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -73,6 +73,8 @@ static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
static void menu_delkey (KBNODE pub_keyblock);
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
+static int menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock,
+ const char *adskfpr);
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
int unattended, u32 newexpiration);
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
@@ -1243,7 +1245,7 @@ enum cmdids
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
- cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN,
+ cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdADDADSK,
#ifndef NO_TRUST_MODELS
cmdENABLEKEY, cmdDISABLEKEY,
#endif /*!NO_TRUST_MODELS*/
@@ -1308,6 +1310,8 @@ static struct
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
N_("add a revocation key")},
+ { "addadsk", cmdADDADSK, KEYEDIT_NEED_SK,
+ N_("add an additional decryption subkey")},
{ "delsig", cmdDELSIG, 0,
N_("delete signatures from the selected user IDs")},
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
@@ -1421,6 +1425,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
int sec_shadowing = 0;
int run_subkey_warnings = 0;
int have_commands = !!commands;
+ strlist_t delseckey_list = NULL;
+ int delseckey_list_warn = 0;
if (opt.command_fd != -1)
;
@@ -1497,6 +1503,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
subkey_expire_warning (keyblock);
}
+ if (delseckey_list_warn)
+ {
+ delseckey_list_warn = 0;
+ tty_printf
+ (_("Note: the local copy of the secret key"
+ " will only be deleted with \"save\".\n"));
+ }
+
do
{
xfree (answer);
@@ -1869,10 +1883,12 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
if (node)
{
PKT_public_key *xxpk = node->pkt->pkt.public_key;
- if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
+ if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0,
+ &delseckey_list))
{
redisplay = 1;
sec_shadowing = 1;
+ delseckey_list_warn = 1;
}
}
}
@@ -1949,7 +1965,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
pkt->pkttype = PKT_PUBLIC_KEY;
/* Ask gpg-agent to store the secret key to card. */
- if (card_store_subkey (node, 0))
+ if (card_store_subkey (node, 0, NULL))
{
redisplay = 1;
sec_shadowing = 1;
@@ -2000,6 +2016,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
}
break;
+ case cmdADDADSK:
+ if (menu_addadsk (ctrl, keyblock, NULL))
+ {
+ redisplay = 1;
+ modified = 1;
+ merge_keys_and_selfsig (ctrl, keyblock);
+ }
+ break;
+
case cmdREVUID:
{
int n1;
@@ -2250,6 +2275,27 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
}
}
+ if (delseckey_list)
+ {
+ strlist_t sl;
+ for (err = 0, sl = delseckey_list; sl; sl = sl->next)
+ {
+ if (*sl->d)
+ {
+ err = agent_delete_key (ctrl, sl->d, NULL, 1/*force*/);
+ if (err)
+ break;
+ *sl->d = 0; /* Mark deleted. */
+ }
+ }
+ if (err)
+ {
+ log_error (_("deleting copy of secret key failed: %s\n"),
+ gpg_strerror (err));
+ break; /* the "save". */
+ }
+ }
+
if (sec_shadowing)
{
err = agent_scd_learn (NULL, 1);
@@ -2279,6 +2325,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
} /* End of the main command loop. */
leave:
+ free_strlist (delseckey_list);
release_kbnode (keyblock);
keydb_release (kdbhd);
xfree (answer);
@@ -3201,6 +3248,69 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
}
+/* Unattended ADSK setup function.
+ *
+ * FPR is the fingerprint of our key. ADSKFPR is the fingerprint of
+ * another subkey which we want to add as ADSK to our key.
+ */
+void
+keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
+{
+ gpg_error_t err;
+ kbnode_t keyblock;
+ KEYDB_HANDLE kdbhd;
+ int modified = 0;
+ PKT_public_key *pk;
+
+#ifdef HAVE_W32_SYSTEM
+ /* See keyedit_menu for why we need this. */
+ check_trustdb_stale (ctrl);
+#endif
+
+ /* We require a fingerprint because only this uniquely identifies a
+ * key and may thus be used to select a key for unattended adsk
+ * adding. */
+ if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
+ goto leave;
+
+ if (fix_keyblock (ctrl, &keyblock))
+ modified++;
+
+ pk = keyblock->pkt->pkt.public_key;
+ if (pk->flags.revoked)
+ {
+ if (!opt.verbose)
+ show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
+ log_error ("%s%s", _("Key is revoked."), "\n");
+ goto leave;
+ }
+
+ /* Locate and add the ADSK. Note that the called function already
+ * prints error messages. */
+ if (menu_addadsk (ctrl, keyblock, adskfpr))
+ modified = 1;
+ else
+ log_inc_errorcount (); /* (We use log_info in menu_adsk) */
+
+ es_fflush (es_stdout);
+
+ /* Store. */
+ if (modified)
+ {
+ err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
+ if (err)
+ {
+ log_error (_("update failed: %s\n"), gpg_strerror (err));
+ goto leave;
+ }
+ }
+
+ leave:
+ release_kbnode (keyblock);
+ keydb_release (kdbhd);
+}
+
+
/* Unattended expiration setting function for the main key. If
* SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is
* expected to be an array of fingerprints for subkeys to change. It
@@ -4643,6 +4753,176 @@ fail:
}
+/*
+ * Ask for a new additional decryption subkey and add it to the key
+ * block. Returns true if the keyblock was changed and false
+ * otherwise. If ADSKFPR is not NULL, this fucntion has been called
+ * by quick_addadsk and gives the fingerprint of the to be added key.
+ */
+static int
+menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock, const char *adskfpr)
+{
+ PKT_public_key *pk;
+ PKT_public_key *sub_pk;
+ PKT_public_key *main_pk;
+ PKT_public_key *adsk_pk = NULL;
+ kbnode_t adsk_keyblock = NULL;
+ PKT_signature *sig = NULL;
+ char *answer = NULL;
+ gpg_error_t err;
+ KEYDB_SEARCH_DESC desc;
+ byte fpr[MAX_FINGERPRINT_LEN];
+ size_t fprlen;
+ kbnode_t node, node2;
+ kbnode_t subkeynode = NULL;
+ PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */
+
+ log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+ main_pk = pub_keyblock->pkt->pkt.public_key;
+
+ for (;;)
+ {
+ xfree (answer);
+ if (adskfpr)
+ answer = xstrdup (adskfpr);
+ else
+ {
+ answer = cpr_get_utf8
+ ("keyedit.addadsk",
+ _("Enter the fingerprint of the additional decryption subkey: "));
+ if (answer[0] == '\0' || answer[0] == CONTROL_D)
+ {
+ err = gpg_error (GPG_ERR_CANCELED);
+ goto leave;
+ }
+ }
+ if (classify_user_id (answer, &desc, 1)
+ || desc.mode != KEYDB_SEARCH_MODE_FPR)
+ {
+ log_info (_("\"%s\" is not a fingerprint\n"), answer);
+ err = gpg_error (GPG_ERR_INV_USER_ID);
+ if (adskfpr)
+ goto leave;
+ continue;
+ }
+
+ free_public_key (adsk_pk);
+ adsk_pk = xcalloc (1, sizeof *adsk_pk);
+ adsk_pk->req_usage = PUBKEY_USAGE_ENC;
+ release_kbnode (adsk_keyblock);
+ adsk_keyblock = NULL;
+ err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, adsk_pk, answer, &adsk_keyblock, NULL, 1);
+ if (err)
+ {
+ log_info (_("key \"%s\" not found: %s\n"), answer,
+ gpg_strerror (err));
+ if ((!opt.batch || adskfpr) && !opt.quiet
+ && gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
+ log_info (_("Did you specify the fingerprint of a subkey?\n"));
+ if (adskfpr)
+ goto leave;
+ continue;
+ }
+
+ for (node = adsk_keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ pk = node->pkt->pkt.public_key;
+ fingerprint_from_pk (pk, fpr, &fprlen);
+ if (fprlen == desc.fprlen
+ && !memcmp (fpr, desc.u.fpr, fprlen)
+ && (pk->pubkey_usage & PUBKEY_USAGE_ENC))
+ break;
+ }
+ }
+ if (!node)
+ {
+ err = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
+ log_info (_("key \"%s\" not found: %s\n"), answer,
+ gpg_strerror (err));
+ if ((!opt.batch || adskfpr) && !opt.quiet)
+ log_info (_("Did you specify the fingerprint of a subkey?\n"));
+ if (adskfpr)
+ goto leave;
+ continue;
+ }
+
+ /* Check that the selected subkey is not yet on our keyblock. */
+ for (node2 = pub_keyblock; node2; node2 = node2->next)
+ {
+ if (node2->pkt->pkttype == PKT_PUBLIC_KEY
+ || node2->pkt->pkttype == PKT_PUBLIC_SUBKEY)
+ {
+ pk = node2->pkt->pkt.public_key;
+ fingerprint_from_pk (pk, fpr, &fprlen);
+ if (fprlen == desc.fprlen
+ && !memcmp (fpr, desc.u.fpr, fprlen))
+ break;
+ }
+ }
+ if (node2)
+ {
+ log_info (_("key \"%s\" is already on this keyblock\n"), answer);
+ err = gpg_error (GPG_ERR_DUP_KEY);
+ if (adskfpr)
+ goto leave;
+ continue;
+ }
+
+ break;
+ }
+
+ /* Append the subkey.
+ * Note that we don't use the ADSK_PK directly because this is the
+ * primary key and in general we use a subkey to which NODE points.
+ * ADSK_PK has only been used to pass the requested key usage to
+ * get_pubkey_byname. SUB_PK will point to the actual adsk. */
+ log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
+ sub_pk = copy_public_key_basics (NULL, node->pkt->pkt.public_key);
+ keyid_from_pk (main_pk, sub_pk->main_keyid); /* Fixup main keyid. */
+ log_assert ((sub_pk->pubkey_usage & PUBKEY_USAGE_ENC));
+ sub_pk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */
+ pkt = xcalloc (1, sizeof *pkt);
+ pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */
+ pkt->pkt.public_key = sub_pk;
+ subkeynode = new_kbnode (pkt);
+
+ /* Make the signature. */
+ err = make_keysig_packet (ctrl, &sig, main_pk, NULL, sub_pk, main_pk, 0x18,
+ sub_pk->timestamp, 0,
+ keygen_add_key_flags_and_expire, sub_pk, NULL);
+ if (err)
+ {
+ write_status_error ("keysig", err);
+ log_error ("creating key binding failed: %s\n", gpg_strerror (err));
+ goto leave;
+ }
+
+ /* Append the subkey packet and the binding signature. */
+ add_kbnode (pub_keyblock, subkeynode);
+ subkeynode = NULL;
+ pkt = xcalloc (1, sizeof *pkt);
+ pkt->pkttype = PKT_SIGNATURE;
+ pkt->pkt.signature = sig;
+ add_kbnode (pub_keyblock, new_kbnode (pkt));
+
+ leave:
+ xfree (answer);
+ free_public_key (adsk_pk);
+ release_kbnode (adsk_keyblock);
+ release_kbnode (subkeynode);
+ if (!err)
+ return 1; /* The keyblock was modified. */
+ else
+ return 0; /* Not modified. */
+
+}
+
+
/* With FORCE_MAINKEY cleared this function handles the interactive
* menu option "expire". With UNATTENDED set to 1 this function only
* sets the expiration date of the primary key to NEWEXPIRATION and
diff --git a/g10/keyedit.h b/g10/keyedit.h
index ea4fd253c..3ed0d0fea 100644
--- a/g10/keyedit.h
+++ b/g10/keyedit.h
@@ -44,6 +44,7 @@ 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_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr);
void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
const char *uidtorev);
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
diff --git a/g10/keygen.c b/g10/keygen.c
index 4dcf7a494..c97783124 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -130,12 +130,6 @@ struct output_control_s
};
-struct opaque_data_usage_and_pk {
- unsigned int usage;
- PKT_public_key *pk;
-};
-
-
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
* aeads is useless, given that we don't expects more than a very few
* algorithms. */
@@ -256,22 +250,27 @@ write_uid (kbnode_t root, const char *s)
static void
do_add_key_flags (PKT_signature *sig, unsigned int use)
{
- byte buf[1];
-
- buf[0] = 0;
+ byte buf[2] = { 0, 0 };
- /* The spec says that all primary keys MUST be able to certify. */
- if(sig->sig_class!=0x18)
- buf[0] |= 0x01;
+ /* The spec says that all primary keys MUST be able to certify. */
+ if ( sig->sig_class != 0x18 )
+ buf[0] |= 0x01;
- if (use & PUBKEY_USAGE_SIG)
- buf[0] |= 0x02;
- if (use & PUBKEY_USAGE_ENC)
- buf[0] |= 0x04 | 0x08;
- if (use & PUBKEY_USAGE_AUTH)
- buf[0] |= 0x20;
-
- build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
+ if (use & PUBKEY_USAGE_SIG)
+ buf[0] |= 0x02;
+ if (use & PUBKEY_USAGE_ENC)
+ buf[0] |= 0x04 | 0x08;
+ if (use & PUBKEY_USAGE_AUTH)
+ buf[0] |= 0x20;
+ if (use & PUBKEY_USAGE_GROUP)
+ buf[0] |= 0x80;
+
+ if (use & PUBKEY_USAGE_RENC)
+ buf[1] |= 0x04;
+ if (use & PUBKEY_USAGE_TIME)
+ buf[1] |= 0x08;
+
+ build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, buf[1]? 2:1);
}
@@ -318,13 +317,11 @@ keygen_add_key_flags (PKT_signature *sig, void *opaque)
}
-static int
+int
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
{
- struct opaque_data_usage_and_pk *oduap = opaque;
-
- do_add_key_flags (sig, oduap->usage);
- return keygen_add_key_expire (sig, oduap->pk);
+ keygen_add_key_flags (sig, opaque);
+ return keygen_add_key_expire (sig, opaque);
}
@@ -1215,7 +1212,6 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
PKT_signature *sig;
KBNODE node;
PKT_public_key *pri_pk, *sub_pk;
- struct opaque_data_usage_and_pk oduap;
if (opt.verbose)
log_info(_("writing key binding signature\n"));
@@ -1241,11 +1237,10 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
BUG();
/* Make the signature. */
- oduap.usage = use;
- oduap.pk = sub_pk;
+ sub_pk->pubkey_usage = use;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
timestamp, 0,
- keygen_add_key_flags_and_expire, &oduap,
+ keygen_add_key_flags_and_expire, sub_pk,
cache_nonce);
if (err)
{
@@ -3792,14 +3787,29 @@ release_parameter_list (struct para_data_s *r)
}
}
+/* Return the N-th parameter of name KEY from PARA. An IDX of 0
+ * returns the first and so on. */
static struct para_data_s *
-get_parameter( struct para_data_s *para, enum para_name key )
+get_parameter_idx (struct para_data_s *para, enum para_name key,
+ unsigned int idx)
{
- struct para_data_s *r;
+ struct para_data_s *r;
- for( r = para; r && r->key != key; r = r->next )
- ;
- return r;
+ for(r = para; r; r = r->next)
+ if (r->key == key)
+ {
+ if (!idx)
+ return r;
+ idx--;
+ }
+ return NULL;
+}
+
+/* Return the first parameter of name KEY from PARA. */
+static struct para_data_s *
+get_parameter (struct para_data_s *para, enum para_name key)
+{
+ return get_parameter_idx (para, key, 0);
}
static const char *
@@ -3947,6 +3957,69 @@ parse_parameter_usage (const char *fname,
}
+/* Parse the revocation key specified by NAME, check that the public
+ * key exists (so that we can get the required public key algorithm),
+ * and return a parameter wit the revocation key information. On
+ * error print a diagnostic and return NULL. */
+static struct para_data_s *
+prepare_desig_revoker (ctrl_t ctrl, const char *name)
+{
+ gpg_error_t err;
+ struct para_data_s *para = NULL;
+ KEYDB_SEARCH_DESC desc;
+ int sensitive = 0;
+ struct revocation_key revkey;
+ PKT_public_key *revoker_pk = NULL;
+ size_t fprlen;
+
+ if (!ascii_strncasecmp (name, "sensitive:", 10) && !spacep (name+10))
+ {
+ name += 10;
+ sensitive = 1;
+ }
+
+ if (classify_user_id (name, &desc, 1)
+ || desc.mode != KEYDB_SEARCH_MODE_FPR)
+ {
+ log_info (_("\"%s\" is not a fingerprint\n"), name);
+ err = gpg_error (GPG_ERR_INV_NAME);
+ goto leave;
+ }
+
+ revoker_pk = xcalloc (1, sizeof *revoker_pk);
+ revoker_pk->req_usage = PUBKEY_USAGE_CERT;
+ err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
+ NULL, revoker_pk, name, NULL, NULL, 1);
+ if (err)
+ goto leave;
+
+ fingerprint_from_pk (revoker_pk, revkey.fpr, &fprlen);
+ if (fprlen != 20 && fprlen != 32)
+ {
+ log_info (_("cannot appoint a PGP 2.x style key as a "
+ "designated revoker\n"));
+ err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
+ goto leave;
+ }
+ revkey.fprlen = fprlen;
+ revkey.class = 0x80;
+ if (sensitive)
+ revkey.class |= 0x40;
+ revkey.algid = revoker_pk->pubkey_algo;
+
+ para = xcalloc (1, sizeof *para);
+ para->key = pREVOKER;
+ memcpy (&para->u.revkey, &revkey, sizeof revkey);
+
+ leave:
+ if (err)
+ log_error ("invalid revocation key '%s': %s\n", name, gpg_strerror (err));
+ free_public_key (revoker_pk);
+ return para;
+}
+
+
+/* Parse a pREVOKER parameter into its dedicated parts. */
static int
parse_revocation_key (const char *fname,
struct para_data_s *para, enum para_name key)
@@ -4030,10 +4103,11 @@ get_parameter_uint( struct para_data_s *para, enum para_name key )
}
static struct revocation_key *
-get_parameter_revkey( struct para_data_s *para, enum para_name key )
+get_parameter_revkey (struct para_data_s *para, enum para_name key,
+ unsigned int idx)
{
- struct para_data_s *r = get_parameter( para, key );
- return r? &r->u.revkey : NULL;
+ struct para_data_s *r = get_parameter_idx (para, key, idx);
+ return r? &r->u.revkey : NULL;
}
static int
@@ -4052,6 +4126,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
const char *s1, *s2, *s3;
size_t n;
char *p;
+ strlist_t sl;
int is_default = 0;
int have_user_id = 0;
int err, algo;
@@ -4197,10 +4272,20 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
}
}
- /* Set revoker, if any. */
+ /* Set revoker from parameter file, if any. Must be done first so
+ * that we don't find a parameter set via prepare_desig_revoker. */
if (parse_revocation_key (fname, para, pREVOKER))
return -1;
+ /* Check and appened revokers from the config file. */
+ for (sl = opt.desig_revokers; sl; sl = sl->next)
+ {
+ r = prepare_desig_revoker (ctrl, sl->d);
+ if (!r)
+ return -1;
+ append_to_parameter (para, r);
+ }
+
/* Make KEYCREATIONDATE from Creation-Date. We ignore this if the
* key has been taken from a card and a keycreationtime has already
@@ -5330,6 +5415,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
const char *key_from_hexgrip = NULL;
int cardkey;
unsigned int keygen_flags;
+ unsigned int idx;
if (outctrl->dryrun)
{
@@ -5464,7 +5550,10 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
keyid_copy (pri_psk->main_keyid, pri_psk->keyid);
}
- if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
+ /* Write all signatures specifying designated revokers. */
+ for (idx=0;
+ !err && (revkey = get_parameter_revkey (para, pREVOKER, idx));
+ idx++)
err = write_direct_sig (ctrl, pub_root, pri_psk,
revkey, signtimestamp, cache_nonce);
diff --git a/g10/keylist.c b/g10/keylist.c
index 1ced732a4..8b7c597cb 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -1216,7 +1216,8 @@ cmp_signodes (const void *av, const void *bv)
}
-/* Helper for list_keyblock_print. */
+/* Helper for list_keyblock_print. The caller must have set
+ * NODFLG_MARK_B to indicate self-signatures. */
static void
list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
struct keylist_context *listctx)
@@ -1247,6 +1248,11 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
case GPG_ERR_UNUSABLE_PUBKEY:
listctx->no_key++;
return;
+ case GPG_ERR_DIGEST_ALGO:
+ case GPG_ERR_PUBKEY_ALGO:
+ if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
+ return;
+ /* fallthru. */
default:
listctx->oth_err++;
sigrc = '%';
@@ -1259,6 +1265,15 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
}
else
{
+ if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
+ && (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
+ == GPG_ERR_PUBKEY_ALGO)
+ || gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
+ == GPG_ERR_DIGEST_ALGO)
+ || (sig->digest_algo == DIGEST_ALGO_SHA1
+ && !(node->flag & NODFLG_MARK_B) /*no selfsig*/
+ && !opt.flags.allow_weak_key_signatures)))
+ return;
rc = 0;
sigrc = ' ';
}
@@ -1306,7 +1321,9 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
else if (sigrc == '?')
;
- else if (!opt.fast_list_mode)
+ else if ((node->flag & NODFLG_MARK_B))
+ es_fputs (_("[self-signature]"), es_stdout);
+ else if (!opt.fast_list_mode )
{
size_t n;
char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
@@ -1585,37 +1602,33 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
else if (opt.list_sigs
&& node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
{
- if ((opt.list_options & LIST_SORT_SIGS))
- {
- kbnode_t n;
- unsigned int sigcount = 0;
- kbnode_t *sigarray;
- unsigned int idx;
+ kbnode_t n;
+ unsigned int sigcount = 0;
+ kbnode_t *sigarray;
+ unsigned int idx;
- for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
- sigcount++;
- sigarray = xcalloc (sigcount, sizeof *sigarray);
+ for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
+ sigcount++;
+ sigarray = xcalloc (sigcount, sizeof *sigarray);
- sigcount = 0;
- for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
- {
- if (!keyid_cmp (mainkid, n->pkt->pkt.signature->keyid))
- n->flag |= NODFLG_MARK_B; /* Is a self-sig. */
- else
- n->flag &= ~NODFLG_MARK_B;
+ sigcount = 0;
+ for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
+ {
+ if (keyid_eq (mainkid, n->pkt->pkt.signature->keyid))
+ n->flag |= NODFLG_MARK_B; /* Is a self-sig. */
+ else
+ n->flag &= ~NODFLG_MARK_B;
- sigarray[sigcount++] = node = n;
- }
- /* Note that NODE is now at the last signature. */
+ sigarray[sigcount++] = node = n;
+ }
+ /* Note that NODE is now at the last signature. */
- qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
+ if ((opt.list_options & LIST_SORT_SIGS))
+ qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
- for (idx=0; idx < sigcount; idx++)
- list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
- xfree (sigarray);
- }
- else
- list_signature_print (ctrl, keyblock, node, listctx);
+ for (idx=0; idx < sigcount; idx++)
+ list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
+ xfree (sigarray);
}
}
es_putc ('\n', es_stdout);
diff --git a/g10/main.h b/g10/main.h
index 62d2651be..b29e23e51 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -42,7 +42,7 @@
#endif
#define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1)
-#define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1
+#define DEFAULT_S2K_DIGEST_ALGO DEFAULT_DIGEST_ALGO
#ifdef HAVE_ZIP
# define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP
#else
@@ -83,6 +83,7 @@ struct weakhash
/*-- gpg.c --*/
extern int g10_errors_seen;
+extern int assert_signer_true;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
void g10_exit(int rc) __attribute__ ((__noreturn__));
@@ -235,7 +236,7 @@ int cpr_get_answer_okay_cancel (const char *keyword,
/*-- helptext.c --*/
void display_online_help( const char *keyword );
-/*-- encode.c --*/
+/*-- encrypt.c --*/
gpg_error_t setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
aead_algo_t use_aead (pk_list_t pk_list, int algo);
int use_mdc (pk_list_t pk_list,int algo);
@@ -315,6 +316,7 @@ int keygen_set_std_prefs (const char *string,int personal);
PKT_user_id *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
int keygen_add_key_flags (PKT_signature *sig, void *opaque);
+int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque);
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
@@ -491,6 +493,7 @@ void print_file_status( int status, const char *name, int what );
int verify_signatures (ctrl_t ctrl, int nfiles, char **files );
int verify_files (ctrl_t ctrl, int nfiles, char **files );
int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp);
+void check_assert_signer_list (const char *mainpkhex, const char *pkhex);
/*-- decrypt.c --*/
int decrypt_message (ctrl_t ctrl, const char *filename );
@@ -515,7 +518,7 @@ void change_pin (int no, int allow_admin);
void card_status (ctrl_t ctrl, estream_t fp, const char *serialno);
void card_edit (ctrl_t ctrl, strlist_t commands);
gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock);
-int card_store_subkey (KBNODE node, int use);
+int card_store_subkey (KBNODE node, int use, strlist_t *processed_keys);
#endif
/*-- migrate.c --*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 4710386ea..ce0fdaaac 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -2410,7 +2410,7 @@ check_sig_and_print (CTX c, kbnode_t node)
}
/* For good signatures print the VALIDSIG status line. */
- if (!rc && is_status_enabled () && pk)
+ if (!rc && (is_status_enabled () || opt.assert_signer_list) && pk)
{
char pkhex[MAX_FINGERPRINT_LEN*2+1];
char mainpkhex[MAX_FINGERPRINT_LEN*2+1];
@@ -2430,6 +2430,8 @@ check_sig_and_print (CTX c, kbnode_t node)
sig->digest_algo,
sig->sig_class,
mainpkhex);
+ /* Handle the --assert-signer option. */
+ check_assert_signer_list (mainpkhex, pkhex);
}
/* Print compliance warning for Good signatures. */
@@ -2510,6 +2512,7 @@ check_sig_and_print (CTX c, kbnode_t node)
is not a detached signature. */
log_info (_("WARNING: not a detached signature; "
"file '%s' was NOT verified!\n"), dfile);
+ assert_signer_true = 0;
}
xfree (dfile);
}
diff --git a/g10/misc.c b/g10/misc.c
index dcf001877..2f4b452dd 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -777,21 +777,21 @@ openpgp_pk_algo_usage ( int algo )
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
- | PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
+ | PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC | PUBKEY_USAGE_AUTH);
break;
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH:
- use = PUBKEY_USAGE_ENC;
+ use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL:
if (RFC2440)
- use = PUBKEY_USAGE_ENC;
+ use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_ELGAMAL_E:
- use = PUBKEY_USAGE_ENC;
+ use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
@@ -1563,9 +1563,10 @@ parse_options(char *str,unsigned int *options,
{
char *tok;
- if (str && !strcmp (str, "help"))
+ if (str && (!strcmp (str, "help") || !strcmp (str, "full-help")))
{
int i,maxlen=0;
+ int full = *str == 'f';
/* Figure out the longest option name so we can line these up
neatly. */
@@ -1577,6 +1578,10 @@ parse_options(char *str,unsigned int *options,
if(opts[i].help)
es_printf("%s%*s%s\n",opts[i].name,
maxlen+2-(int)strlen(opts[i].name),"",_(opts[i].help));
+ if (full)
+ for (i=0; opts[i].name; i++)
+ if(!opts[i].help)
+ es_printf("%s\n",opts[i].name);
g10_exit(0);
}
diff --git a/g10/options.h b/g10/options.h
index 74a6cdb16..9015e321f 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -111,6 +111,9 @@ struct
* the option --sender. */
strlist_t sender_list;
+ /* A list of fingerprints added as designated revokers to new keys. */
+ strlist_t desig_revokers;
+
int def_cert_level;
int min_cert_level;
int ask_cert_level;
@@ -232,6 +235,10 @@ struct
value. */
int limit_card_insert_tries;
+ /* The list of --assert-signer option values. Note: The values are
+ * modify to be uppercase if they represent a fingerrint */
+ strlist_t assert_signer_list;
+
struct
{
/* If set, require an 0x19 backsig to be present on signatures
@@ -426,6 +433,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define LIST_SORT_SIGS (1<<13)
#define LIST_SHOW_PREF (1<<14)
#define LIST_SHOW_PREF_VERBOSE (1<<15)
+#define LIST_SHOW_UNUSABLE_SIGS (1<<16)
#define VERIFY_SHOW_PHOTOS (1<<0)
#define VERIFY_SHOW_POLICY_URLS (1<<1)
diff --git a/g10/packet.h b/g10/packet.h
index eeea9b450..39dab96c9 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -56,9 +56,15 @@
| GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256
# error Please choose another value for PUBKEY_USAGE_NONE
#endif
-#define PUBKEY_USAGE_RENC 512 /* Restricted encryption. */
-#define PUBKEY_USAGE_TIME 1024 /* Timestamp use. */
#define PUBKEY_USAGE_GROUP 512 /* Group flag. */
+#define PUBKEY_USAGE_RENC 1024 /* Restricted encryption. */
+#define PUBKEY_USAGE_TIME 2048 /* Timestamp use. */
+
+/* Bitflags to convey hints on what kind of signature is created. */
+#define SIGNHINT_KEYSIG 1
+#define SIGNHINT_SELFSIG 2
+#define SIGNHINT_ADSK 4
+
/* Helper macros. */
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
@@ -287,7 +293,7 @@ typedef struct
/* The length of ATTRIB_DATA. */
unsigned long attrib_len;
byte *namehash;
- int help_key_usage;
+ u16 help_key_usage;
u32 help_key_expire;
int help_full_count;
int help_marginal_count;
@@ -388,7 +394,7 @@ typedef struct
byte selfsigversion; /* highest version of all of the self-sigs */
/* The public key algorithm. (Serialized.) */
byte pubkey_algo;
- byte pubkey_usage; /* for now only used to pass it to getkey() */
+ u16 pubkey_usage; /* carries the usage info. */
byte req_usage; /* hack to pass a request to getkey() */
byte fprlen; /* 0 or length of FPR. */
u32 has_expired; /* set to the expiration date if expired */
@@ -861,7 +867,8 @@ 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, PKT_public_key *pksk);
+void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
+ unsigned int signhints);
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,
@@ -883,6 +890,7 @@ void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
prefitem_t *copy_prefs (const prefitem_t *prefs);
+PKT_public_key *copy_public_key_basics (PKT_public_key *d, PKT_public_key *s);
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *scopy_user_id (PKT_user_id *sd );
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 459e7595a..2e8932b9c 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -845,7 +845,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{
int rc;
PKT_public_key *pk;
- KBNODE keyblock = NULL;
+ kbnode_t keyblock = NULL;
+ kbnode_t node;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
@@ -856,7 +857,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
pk->req_usage = use;
if (from_file)
- rc = get_pubkey_fromfile (ctrl, pk, name);
+ rc = get_pubkey_fromfile (ctrl, pk, name, &keyblock);
else
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
NULL, pk, name, &keyblock, 0);
@@ -895,10 +896,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int trustlevel;
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
- release_kbnode (keyblock);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
/* Key has been disabled. */
+ release_kbnode (keyblock);
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
@@ -908,6 +909,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
{
/* We don't trust this key. */
+ release_kbnode (keyblock);
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
@@ -926,19 +928,33 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{
pk_list_t r;
- r = xtrymalloc (sizeof *r);
- if (!r)
- {
- rc = gpg_error_from_syserror ();
- free_public_key (pk);
- return rc;
- }
+ r = xmalloc (sizeof *r);
r->pk = pk;
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0;
*pk_list_addr = r;
}
+ for (node = keyblock; node; node = node->next)
+ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+ && ((pk=node->pkt->pkt.public_key)->pubkey_usage & PUBKEY_USAGE_RENC)
+ && pk->flags.valid
+ && !pk->flags.revoked
+ && !pk->flags.disabled
+ && !pk->has_expired
+ && key_present_in_pk_list (*pk_list_addr, pk))
+ {
+ pk_list_t r;
+
+ r = xmalloc (sizeof *r);
+ r->pk = copy_public_key (NULL, pk);
+ r->next = *pk_list_addr;
+ r->flags = mark_hidden? 1:0; /* FIXME: Use PK_LIST_HIDDEN ? */
+ *pk_list_addr = r;
+ }
+
+
+ release_kbnode (keyblock);
return 0;
}
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 7a2c934cd..06329f659 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -363,7 +363,8 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
if (r_revoked)
*r_revoked = 0;
- if (pk->timestamp > sig->timestamp )
+ if (pk->timestamp > sig->timestamp
+ && !(parse_key_usage (sig) & PUBKEY_USAGE_RENC))
{
ulong d = pk->timestamp - sig->timestamp;
if ( d < 86400 )
diff --git a/g10/sign.c b/g10/sign.c
index a66410ebd..b5e9d422d 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -50,11 +50,6 @@
#endif
-/* Bitflags to convey hints on what kind of signayire is created. */
-#define SIGNHINT_KEYSIG 1
-#define SIGNHINT_SELFSIG 2
-
-
/* Hack */
static int recipient_digest_algo;
@@ -416,7 +411,10 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
byte *dp;
char *hexgrip;
- if (pksk->timestamp > sig->timestamp )
+ /* An ADSK key commonly has a creation date older than the primary
+ * key. For example because the ADSK is used as an archive key for
+ * a group of users. */
+ if (pksk->timestamp > sig->timestamp && !(signhints & SIGNHINT_ADSK))
{
ulong d = pksk->timestamp - sig->timestamp;
log_info (ngettext("key %s was created %lu second"
@@ -964,7 +962,7 @@ write_signature_packets (ctrl_t ctrl,
if (gcry_md_copy (&md, hash))
BUG ();
- build_sig_subpkt_from_sig (sig, pk);
+ build_sig_subpkt_from_sig (sig, pk, 0);
mk_notation_policy_etc (ctrl, sig, NULL, pk);
if (opt.flags.include_key_block && IS_SIG (sig))
err = mk_sig_subpkt_key_block (ctrl, sig, pk);
@@ -1758,14 +1756,14 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
*
* SIGCLASS is the type of signature to create.
*
- * DIGEST_ALGO is the digest algorithm. If it is 0 the function
- * selects an appropriate one.
- *
* TIMESTAMP is the timestamp to use for the signature. 0 means "now"
*
* DURATION is the amount of time (in seconds) until the signature
* expires.
*
+ * If CACHED_NONCE is not NULL the agent may use it to avoid
+ * additional pinnetry popups for the same keyblock.
+ *
* This function creates the following subpackets: issuer, created,
* and expire (if duration is not 0). Additional subpackets can be
* added using MKSUBPKT, which is called after these subpackets are
@@ -1833,6 +1831,8 @@ make_keysig_packet (ctrl_t ctrl,
{
/* Hash the subkey binding/backsig/revocation. */
hash_public_key (md, subpk);
+ if ((subpk->pubkey_usage & PUBKEY_USAGE_RENC))
+ signhints |= SIGNHINT_ADSK;
}
else if (sigclass != 0x1F && sigclass != 0x20)
{
@@ -1852,7 +1852,7 @@ make_keysig_packet (ctrl_t ctrl,
sig->expiredate = sig->timestamp + duration;
sig->sig_class = sigclass;
- build_sig_subpkt_from_sig (sig, pksk);
+ build_sig_subpkt_from_sig (sig, pksk, signhints);
mk_notation_policy_etc (ctrl, sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls
@@ -1976,6 +1976,12 @@ update_keysig_packet (ctrl_t ctrl,
}
}
+ /* Detect an ADSK key binding signature. */
+ if ((sig->sig_class == 0x18
+ || sig->sig_class == 0x19 || sig->sig_class == 0x28)
+ && (pk->pubkey_usage & PUBKEY_USAGE_RENC))
+ signhints |= SIGNHINT_ADSK;
+
/* Note that already expired sigs will remain expired (with a
* duration of 1) since build-packet.c:build_sig_subpkt_from_sig
* detects this case. */
@@ -1984,7 +1990,7 @@ update_keysig_packet (ctrl_t ctrl,
* 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, pksk);
+ build_sig_subpkt_from_sig (sig, pksk, signhints);
if (mksubpkt)
rc = (*mksubpkt)(sig, opaque);
diff --git a/g10/t-keydb-get-keyblock.c b/g10/t-keydb-get-keyblock.c
index 90ce6e9a6..e40be9cc1 100644
--- a/g10/t-keydb-get-keyblock.c
+++ b/g10/t-keydb-get-keyblock.c
@@ -67,3 +67,12 @@ do_test (int argc, char *argv[])
release_kbnode (kb1);
xfree (ctrl);
}
+
+int assert_signer_true = 0;
+
+void
+check_assert_signer_list (const char *mainpkhex, const char *pkhex)
+{
+ (void)mainpkhex;
+ (void)pkhex;
+}
diff --git a/g10/t-keydb.c b/g10/t-keydb.c
index 4c78dac48..9055d5b94 100644
--- a/g10/t-keydb.c
+++ b/g10/t-keydb.c
@@ -105,3 +105,13 @@ do_test (int argc, char *argv[])
keydb_release (hd2);
xfree (ctrl);
}
+
+
+int assert_signer_true = 0;
+
+void
+check_assert_signer_list (const char *mainpkhex, const char *pkhex)
+{
+ (void)mainpkhex;
+ (void)pkhex;
+}
diff --git a/g10/t-stutter.c b/g10/t-stutter.c
index 503a92004..7b2ea4b37 100644
--- a/g10/t-stutter.c
+++ b/g10/t-stutter.c
@@ -611,3 +611,12 @@ do_test (int argc, char *argv[])
xfree (filename);
}
+
+int assert_signer_true = 0;
+
+void
+check_assert_signer_list (const char *mainpkhex, const char *pkhex)
+{
+ (void)mainpkhex;
+ (void)pkhex;
+}
diff --git a/g10/trust.c b/g10/trust.c
index 9749bd786..f11dfb759 100644
--- a/g10/trust.c
+++ b/g10/trust.c
@@ -59,7 +59,7 @@ register_trusted_key (const char *string)
/* Some users have conf files with entries like
* trusted-key 0x1234567812345678 # foo
* That is obviously wrong. Before fixing bug#1206 trailing garbage
- * on a key specification if was ignored. We detect the above use case
+ * on a key specification was ignored. We detect the above use case
* here and cut off the junk-looking-like-a comment. */
if (strchr (string, '#'))
{
diff --git a/g10/verify.c b/g10/verify.c
index fc18882b0..e9792939d 100644
--- a/g10/verify.c
+++ b/g10/verify.c
@@ -1,6 +1,8 @@
/* verify.c - Verify signed data
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
* 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2006-2008, 2010-2011, 2015-2017,
+ * 2020, 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -16,6 +18,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <config.h>
@@ -281,3 +284,124 @@ gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp)
release_armor_context (afx);
return rc;
}
+
+
+static int
+is_fingerprint (const char *string)
+{
+ int n;
+
+ if (!string || !*string)
+ return 0;
+ for (n=0; hexdigitp (string); string++)
+ n++;
+ if (!*string && (n == 40 || n == 64))
+ return 1; /* v4 or v5 fingerprint. */
+
+ return 0;
+}
+
+
+/* This function shall be called with the main and subkey fingerprint
+ * iff a signature is fully valid. If the option --assert-signer is
+ * active it check whether the signing key matches one of the keys
+ * given by this option and if so, sets a global flag. */
+void
+check_assert_signer_list (const char *mainpkhex, const char *pkhex)
+{
+ gpg_error_t err;
+ strlist_t item;
+ const char *fname;
+ estream_t fp = NULL;
+ int lnr;
+ int n, c;
+ char *p, *pend;
+ char line[256];
+
+ if (!opt.assert_signer_list)
+ return; /* Nothing to do. */
+ if (assert_signer_true)
+ return; /* Already one valid signature seen. */
+
+ for (item = opt.assert_signer_list; item; item = item->next)
+ {
+ if (is_fingerprint (item->d))
+ {
+ ascii_strupr (item->d);
+ if (!strcmp (item->d, mainpkhex) || !strcmp (item->d, pkhex))
+ {
+ assert_signer_true = 1;
+ write_status_text (STATUS_ASSERT_SIGNER, item->d);
+ if (!opt.quiet)
+ log_info ("signer '%s' matched\n", item->d);
+ goto leave;
+ }
+ }
+ else /* Assume this is a file - read and compare. */
+ {
+ fname = item->d;
+ es_fclose (fp);
+ fp = es_fopen (fname, "r");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ log_error (_("error opening '%s': %s\n"),
+ fname, gpg_strerror (err));
+ continue;
+ }
+
+ lnr = 0;
+ err = 0;
+ while (es_fgets (line, DIM(line)-1, fp))
+ {
+ lnr++;
+
+ n = strlen (line);
+ if (!n || line[n-1] != '\n')
+ {
+ /* Eat until end of line. */
+ while ( (c=es_getc (fp)) != EOF && c != '\n')
+ ;
+ err = gpg_error (GPG_ERR_INCOMPLETE_LINE);
+ log_error (_("file '%s', line %d: %s\n"),
+ fname, lnr, gpg_strerror (err));
+ continue;
+ }
+ line[--n] = 0; /* Chop the LF. */
+ if (n && line[n-1] == '\r')
+ line[--n] = 0; /* Chop an optional CR. */
+
+ /* Allow for empty lines and spaces */
+ for (p=line; spacep (p); p++)
+ ;
+ if (!*p || *p == '#')
+ continue;
+
+ /* Get the first token and ignore trailing stuff. */
+ for (pend = p; *pend && !spacep (pend); pend++)
+ ;
+ *pend = 0;
+ ascii_strupr (p);
+
+ if (!strcmp (p, mainpkhex) || !strcmp (p, pkhex))
+ {
+ assert_signer_true = 1;
+ write_status_text (STATUS_ASSERT_SIGNER, p);
+ if (!opt.quiet)
+ log_info ("signer '%s' matched '%s', line %d\n",
+ p, fname, lnr);
+ goto leave;
+ }
+ }
+ if (!err && !es_feof (fp))
+ {
+ err = gpg_error_from_syserror ();
+ log_error (_("error reading '%s', line %d: %s\n"),
+ fname, lnr, gpg_strerror (err));
+ }
+ }
+ }
+
+ leave:
+ es_fclose (fp);
+}