gpg: New option --add-desig-revoker

* g10/gpg.c (oAddDesigRevoker): New.
(opts): Add new option.
* g10/options.h (opt): Add field desig_revokers.
* g10/keygen.c (get_parameter_idx): New.
(get_parameter): Make use of get_parameter_idx.
(prepare_desig_revoker): New.
(get_parameter_revkey): Add arg idx.
(proc_parameter_file): Add designated revokers.
(do_generate_keypair): Write all designated revokers.
This commit is contained in:
Werner Koch 2023-02-16 18:09:22 +01:00
parent 49fe6a2821
commit 3d094e2bcf
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
6 changed files with 132 additions and 11 deletions

2
NEWS
View File

@ -1,6 +1,8 @@
Noteworthy changes in version 2.4.1 (unreleased) Noteworthy changes in version 2.4.1 (unreleased)
------------------------------------------------ ------------------------------------------------
* gpg: New option --add-desig-revoker.
* gpg: New list-option "show-unusable-sigs". * gpg: New list-option "show-unusable-sigs".
* gpg: Show "[self-signature]" instead of the user-id in key * gpg: Show "[self-signature]" instead of the user-id in key

View File

@ -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 available but an LDAP keyserver is configured the missing key is
imported from that server. 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@} @item --trust-model @{pgp|classic|tofu|tofu+pgp|direct|always|auto@}
@opindex trust-model @opindex trust-model
Set what trust model GnuPG should follow. The models are: Set what trust model GnuPG should follow. The models are:

View File

@ -443,6 +443,7 @@ enum cmd_and_opt_values
oForbidGenKey, oForbidGenKey,
oRequireCompliance, oRequireCompliance,
oCompatibilityFlags, oCompatibilityFlags,
oAddDesigRevoker,
oNoop oNoop
}; };
@ -702,6 +703,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"), ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"),
ARGPARSE_s_n (oNoAutoTrustNewKey, "no-auto-trust-new-key", "@"), ARGPARSE_s_n (oNoAutoTrustNewKey, "no-auto-trust-new-key", "@"),
#endif #endif
ARGPARSE_s_s (oAddDesigRevoker, "add-desig-revoker", "@"),
ARGPARSE_header ("Input", N_("Options controlling the input")), ARGPARSE_header ("Input", N_("Options controlling the input")),
@ -3716,6 +3718,13 @@ main (int argc, char **argv)
opt.flags.require_compliance = 1; opt.flags.require_compliance = 1;
break; 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; case oNoop: break;
default: default:

View File

@ -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 * 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 ) for(r = para; r; r = r->next)
; if (r->key == key)
return r; {
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 * 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 (&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 static int
parse_revocation_key (const char *fname, parse_revocation_key (const char *fname,
struct para_data_s *para, enum para_name key) 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 * 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 ); struct para_data_s *r = get_parameter_idx (para, key, idx);
return r? &r->u.revkey : NULL; return r? &r->u.revkey : NULL;
} }
static int 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; const char *s1, *s2, *s3;
size_t n; size_t n;
char *p; char *p;
strlist_t sl;
int is_default = 0; int is_default = 0;
int have_user_id = 0; int have_user_id = 0;
int err, algo; 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)) if (parse_revocation_key (fname, para, pREVOKER))
return -1; 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 /* Make KEYCREATIONDATE from Creation-Date. We ignore this if the
* key has been taken from a card and a keycreationtime has already * 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; const char *key_from_hexgrip = NULL;
int cardkey; int cardkey;
unsigned int keygen_flags; unsigned int keygen_flags;
unsigned int idx;
if (outctrl->dryrun) 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); 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, err = write_direct_sig (ctrl, pub_root, pri_psk,
revkey, signtimestamp, cache_nonce); revkey, signtimestamp, cache_nonce);

View File

@ -111,6 +111,9 @@ struct
* the option --sender. */ * the option --sender. */
strlist_t sender_list; strlist_t sender_list;
/* A list of fingerprints added as designated revokers to new keys. */
strlist_t desig_revokers;
int def_cert_level; int def_cert_level;
int min_cert_level; int min_cert_level;
int ask_cert_level; int ask_cert_level;

View File

@ -59,7 +59,7 @@ register_trusted_key (const char *string)
/* Some users have conf files with entries like /* Some users have conf files with entries like
* trusted-key 0x1234567812345678 # foo * trusted-key 0x1234567812345678 # foo
* That is obviously wrong. Before fixing bug#1206 trailing garbage * 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. */ * here and cut off the junk-looking-like-a comment. */
if (strchr (string, '#')) if (strchr (string, '#'))
{ {