diff --git a/NEWS b/NEWS index 176f92740..340742c20 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ Noteworthy changes in version 2.4.1 (unreleased) ------------------------------------------------ + * gpg: New option --add-desig-revoker. + * gpg: New list-option "show-unusable-sigs". * gpg: Show "[self-signature]" instead of the user-id in key diff --git a/doc/gpg.texi b/doc/gpg.texi index eb8b65242..45cd97241 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1750,6 +1750,19 @@ recipient's or signator's key. If the given key is not locally available but an LDAP keyserver is configured the missing key is imported from that server. +@item --add-desig-revoker [sensitive:]@var{fingerprint} +@opindex add-desig-revoker +Add the key specified by @var{fingerprint} as a designated revoker to +newly created keys. If the fingerprint is prefixed with the keyword +``sensitive:'' that info is normally not exported wit the key. This +option may be given several time to add more than one designated +revoker. If the keyword ``clear'' is used instead of a fingerprint, +all designated options previously encountered are discarded. +Designated revokers are marked on the key as non-revocable. Note that +a designated revoker specified using a parameter file will also be +added to the key. + + @item --trust-model @{pgp|classic|tofu|tofu+pgp|direct|always|auto@} @opindex trust-model Set what trust model GnuPG should follow. The models are: diff --git a/g10/gpg.c b/g10/gpg.c index 31cb066c9..9ec956ac3 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -443,6 +443,7 @@ enum cmd_and_opt_values oForbidGenKey, oRequireCompliance, oCompatibilityFlags, + oAddDesigRevoker, oNoop }; @@ -702,6 +703,7 @@ 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_header ("Input", N_("Options controlling the input")), @@ -3716,6 +3718,13 @@ 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 oNoop: break; default: diff --git a/g10/keygen.c b/g10/keygen.c index 4dcf7a494..2e07015c6 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -3792,14 +3792,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 +3962,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 (¶->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 +4108,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 +4131,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 +4277,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 +5420,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 +5555,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/options.h b/g10/options.h index 499544cdf..3ecf57ffb 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; 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, '#')) {