1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-03 22:56:33 +02:00

gpg: New command --quick-tsign-key.

* g10/gpg.c (aQuickTSignKey): New.
(opts): Add new command.
(main): Parse args for it.
* g10/keyedit.c: Include mbox-util.h.
(parse_trustsig_string): New.
(sign_uids): Add arg trustsig for use in quick mode.
(keyedit_quick_sign): Also add arg trustsig and print a diagnostic on
error.
This commit is contained in:
Werner Koch 2025-04-29 18:35:29 +02:00
parent 6d49e86bba
commit d90b290f97
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
5 changed files with 183 additions and 18 deletions

8
NEWS
View file

@ -4,10 +4,12 @@ Noteworthy changes in version 2.5.6 (unreleased)
* gpg: Add a flag to the filter expressions for left anchored * gpg: Add a flag to the filter expressions for left anchored
substring match. [rGc12b7d047e] substring match. [rGc12b7d047e]
* gpg: Fix double free of internal data. [T7547]
* gpg: New list option "show-trustsig" to avoid resorting to colon * gpg: New list option "show-trustsig" to avoid resorting to colon
mode for this info. mode for this info. [rG41d6ae8f41]
* gpg: New command --quick-tsign-key to create a trust signature.
* gpg: Fix double free of internal data. [T7547]
* gpgsm: Extend --learn-card by an optional s/n argument. [T7379] * gpgsm: Extend --learn-card by an optional s/n argument. [T7379]

View file

@ -1137,8 +1137,10 @@ from @option{--edit-key}.
@item --quick-sign-key @var{fpr} [@var{names}] @item --quick-sign-key @var{fpr} [@var{names}]
@itemx --quick-lsign-key @var{fpr} [@var{names}] @itemx --quick-lsign-key @var{fpr} [@var{names}]
@itemx --quick-tsign-key @var{fpr} @var{trustspec} [@var{names}]
@opindex quick-sign-key @opindex quick-sign-key
@opindex quick-lsign-key @opindex quick-lsign-key
@opindex quick-tsign-key
Directly sign a key from the passphrase without any further user Directly sign a key from the passphrase without any further user
interaction. The @var{fpr} must be the verified primary fingerprint interaction. The @var{fpr} must be the verified primary fingerprint
of a key in the local keyring. If no @var{names} are given, all of a key in the local keyring. If no @var{names} are given, all
@ -1153,6 +1155,17 @@ non-exportable. If such a non-exportable signature already exists the
you need to update an existing signature, for example to add or change you need to update an existing signature, for example to add or change
notation data, you need to use the option @option{--force-sign-key}. notation data, you need to use the option @option{--force-sign-key}.
The command @option{--quick-tsign-key} creates a trust signature using
the information from the @var{trustspec} string. The @var{trustspec}
uses the format [T=]@var{dept},@var{value}[,@var{domain}]. @var{depth}
is the length of the trust chain in the range 0 (identical to a
standard key signature) to 255 (ridiculous long trust chain); the most
common lengths for trust signatures are 1 and 2. @var{value} is
either "f" or "full" which are mapped to a value of 120 or "m" or
"marginal" which are mapped to a value of 60. The allowed range is 0
to 255 but it is highly suggested to use only 60 or 120. @var{domain}
is optional and a plain domain name like "example.org".
This command uses reasonable defaults and thus does not provide the This command uses reasonable defaults and thus does not provide the
full flexibility of the "sign" subcommand from @option{--edit-key}. full flexibility of the "sign" subcommand from @option{--edit-key}.
Its intended use is to help unattended key signing by utilizing a list Its intended use is to help unattended key signing by utilizing a list

View file

@ -130,6 +130,7 @@ enum cmd_and_opt_values
aLSignKey, aLSignKey,
aQuickSignKey, aQuickSignKey,
aQuickLSignKey, aQuickLSignKey,
aQuickTSignKey,
aQuickRevSig, aQuickRevSig,
aQuickAddUid, aQuickAddUid,
aQuickAddKey, aQuickAddKey,
@ -529,6 +530,8 @@ static gpgrt_opt_t opts[] = {
N_("quickly sign a key")), N_("quickly sign a key")),
ARGPARSE_c (aQuickLSignKey, "quick-lsign-key", ARGPARSE_c (aQuickLSignKey, "quick-lsign-key",
N_("quickly sign a key locally")), N_("quickly sign a key locally")),
ARGPARSE_c (aQuickTSignKey, "quick-tsign-key",
N_("quickly sign a key with a trust signature")),
ARGPARSE_c (aQuickRevSig, "quick-revoke-sig" , ARGPARSE_c (aQuickRevSig, "quick-revoke-sig" ,
N_("quickly revoke a key signature")), N_("quickly revoke a key signature")),
ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")), ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")),
@ -2734,6 +2737,7 @@ main (int argc, char **argv)
case aSign: case aSign:
case aQuickSignKey: case aQuickSignKey:
case aQuickLSignKey: case aQuickLSignKey:
case aQuickTSignKey:
case aQuickRevSig: case aQuickRevSig:
case aSignKey: case aSignKey:
case aLSignKey: case aLSignKey:
@ -4715,7 +4719,25 @@ main (int argc, char **argv)
sl = NULL; sl = NULL;
for( ; argc; argc--, argv++) for( ; argc; argc--, argv++)
append_to_strlist2 (&sl, *argv, utf8_strings); append_to_strlist2 (&sl, *argv, utf8_strings);
keyedit_quick_sign (ctrl, fpr, sl, locusr, (cmd == aQuickLSignKey)); keyedit_quick_sign (ctrl, fpr, sl, locusr,
NULL, (cmd == aQuickLSignKey));
free_strlist (sl);
}
break;
case aQuickTSignKey:
{
const char *fpr, *tsig;
if (argc < 2)
wrong_args ("--quick-tsign-key fingerprint"
" depth,[m|f][,domain] [userids]");
fpr = *argv++; argc--;
tsig = *argv++; argc--;
sl = NULL;
for( ; argc; argc--, argv++)
append_to_strlist2 (&sl, *argv, utf8_strings);
keyedit_quick_sign (ctrl, fpr, sl, locusr, tsig, 0);
free_strlist (sl); free_strlist (sl);
} }
break; break;

View file

@ -44,6 +44,7 @@
#include "../common/ttyio.h" #include "../common/ttyio.h"
#include "../common/status.h" #include "../common/status.h"
#include "../common/i18n.h" #include "../common/i18n.h"
#include "../common/mbox-util.h"
#include "keyserver-internal.h" #include "keyserver-internal.h"
#include "call-agent.h" #include "call-agent.h"
#include "../common/host2net.h" #include "../common/host2net.h"
@ -380,6 +381,92 @@ sign_mk_attrib (PKT_signature * sig, void *opaque)
} }
/* Parse a trust signature specification string into the 3 return
* args. Returns 0 on success or an errorcode. Format for the string
* is
* ['T=']<depth>,<value>[,<domain>]
* The optional prefix is just to allow c+p from the --check-sigs
* output. The domain is optional, <depth> must be a value in the
* range 0 to 255, value may either be value in the same range or -
* preferred - 'm' or 'f'.
*/
static gpg_error_t
parse_trustsig_string (const char *string,
byte *trust_value, byte *trust_depth, char **regexp)
{
gpg_error_t err = 0;
char **fields;
int nfields;
int along;
char *endp;
*trust_value = 0;
*trust_depth = 0;
*regexp = NULL;
if (!string)
return gpg_error (GPG_ERR_INV_ARG);
if (*string == 'T' && string[1] == '=')
string += 2;
fields = strtokenize (string, ",");
if (!fields)
return gpg_error_from_syserror ();
for (nfields=0; fields[nfields]; nfields++)
;
if (nfields < 2 || nfields > 3)
{
err = gpg_error (GPG_ERR_SYNTAX);
goto leave;
}
along = strtol (fields[0], &endp, 10);
if (along < 0 || along > 255 || fields[0] == endp || *endp)
{
err = gpg_error (GPG_ERR_ERANGE);
goto leave;
}
*trust_depth = along;
if (!strcmp (fields[1], "m")|| !strcmp (fields[1], "marginal"))
along = 60;
else if (!strcmp (fields[1], "f")|| !strcmp (fields[1], "full"))
along = 120;
else
{
along = strtol (fields[1], &endp, 10);
if (along < 0 || along > 255 || fields[1] == endp || *endp)
{
err = gpg_error (GPG_ERR_ERANGE);
goto leave;
}
}
*trust_value = along;
if (nfields == 3)
{
if (!is_valid_domain_name (fields[2]))
err = gpg_error (GPG_ERR_NO_NAME);
else
{
*regexp = strconcat ("<[^>]+[@.]", fields[2], ">$", NULL);
if (!*regexp)
err = gpg_error_from_syserror ();
}
}
leave:
xfree (fields);
if (err && *regexp)
{
xfree (*regexp);
*regexp = NULL;
}
return err;
}
/* Interactive version of parse_trustsig_string. */
static void static void
trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp) trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
{ {
@ -485,12 +572,13 @@ trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp)
* is marked, all user ids will be signed; if some user_ids are marked * is marked, all user ids will be signed; if some user_ids are marked
* only those will be signed. FLAGS are the SIGN_UIDS_* constants. * only those will be signed. FLAGS are the SIGN_UIDS_* constants.
* For example with SIGN_UIDS_QUICK the function won't ask the user * For example with SIGN_UIDS_QUICK the function won't ask the user
* and use sensible defaults. * and use sensible defaults. TRUSTSIGSTR is only used if also
* SIGN_UIDS_TRUSTSIG is set.
*/ */
static int static int
sign_uids (ctrl_t ctrl, estream_t fp, sign_uids (ctrl_t ctrl, estream_t fp,
kbnode_t keyblock, strlist_t locusr, unsigned int flags, kbnode_t keyblock, strlist_t locusr, unsigned int flags,
int *ret_modified) const char *trustsigstr, int *ret_modified)
{ {
int rc = 0; int rc = 0;
SK_LIST sk_list = NULL; SK_LIST sk_list = NULL;
@ -498,9 +586,11 @@ sign_uids (ctrl_t ctrl, estream_t fp,
PKT_public_key *pk = NULL; PKT_public_key *pk = NULL;
KBNODE node, uidnode; KBNODE node, uidnode;
PKT_public_key *primary_pk = NULL; PKT_public_key *primary_pk = NULL;
char *trust_regexp = NULL;
int select_all = (!count_selected_uids (keyblock) int select_all = (!count_selected_uids (keyblock)
|| (flags & SIGN_UIDS_INTERACTIVE)); || (flags & SIGN_UIDS_INTERACTIVE));
/* Build a list of all signators. /* Build a list of all signators.
* *
* We use the CERT flag to request the primary which must always * We use the CERT flag to request the primary which must always
@ -516,7 +606,7 @@ sign_uids (ctrl_t ctrl, estream_t fp,
for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next)
{ {
u32 sk_keyid[2], pk_keyid[2]; u32 sk_keyid[2], pk_keyid[2];
char *p, *trust_regexp = NULL; char *p;
int class = 0, selfsig = 0; int class = 0, selfsig = 0;
u32 duration = 0, timestamp = 0; u32 duration = 0, timestamp = 0;
byte trust_depth = 0, trust_value = 0; byte trust_depth = 0, trust_value = 0;
@ -917,9 +1007,21 @@ sign_uids (ctrl_t ctrl, estream_t fp,
} }
} }
if ((flags & SIGN_UIDS_TRUSTSIG) && !(flags & SIGN_UIDS_QUICK)) if ((flags & SIGN_UIDS_TRUSTSIG))
trustsig_prompt (&trust_value, &trust_depth, &trust_regexp); {
} xfree (trust_regexp);
trust_regexp = NULL;
if ((flags & SIGN_UIDS_QUICK))
{
rc = parse_trustsig_string (trustsigstr, &trust_value,
&trust_depth, &trust_regexp);
if (rc)
goto leave;
}
else
trustsig_prompt (&trust_value, &trust_depth, &trust_regexp);
}
}
if (!(flags & SIGN_UIDS_QUICK)) if (!(flags & SIGN_UIDS_QUICK))
{ {
@ -1065,6 +1167,8 @@ sign_uids (ctrl_t ctrl, estream_t fp,
} /* End loop over signators. */ } /* End loop over signators. */
leave: leave:
xfree (trust_regexp);
trust_regexp = NULL;
release_sk_list (sk_list); release_sk_list (sk_list);
return rc; return rc;
} }
@ -1730,7 +1834,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
break; break;
} }
sign_uids (ctrl, NULL, keyblock, locusr, myflags, &modified); sign_uids (ctrl, NULL, keyblock, locusr, myflags, NULL, &modified);
} }
break; break;
@ -2910,10 +3014,12 @@ find_by_primary_fpr (ctrl_t ctrl, const char *fpr,
key are signed using the default signing key. If UIDS is an empty key are signed using the default signing key. If UIDS is an empty
list all usable UIDs are signed, if it is not empty, only those list all usable UIDs are signed, if it is not empty, only those
user ids matching one of the entries of the list are signed. With user ids matching one of the entries of the list are signed. With
LOCAL being true the signatures are marked as non-exportable. */ LOCAL being true the signatures are marked as non-exportable. If
TRUSTSIG is given a trust signature is created; see
parse_trustsig_string(). */
void void
keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
strlist_t locusr, int local) strlist_t locusr, const char *trustsig, int local)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
kbnode_t keyblock = NULL; kbnode_t keyblock = NULL;
@ -2929,6 +3035,20 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
check_trustdb_stale (ctrl); check_trustdb_stale (ctrl);
#endif #endif
/* Do an early check on an arg for an immediate error message. */
if (trustsig)
{
byte trust_depth, trust_value;
char *trust_regexp;
err = parse_trustsig_string (trustsig, &trust_value,
&trust_depth, &trust_regexp);
xfree (trust_regexp);
(void)trust_depth;
(void)trust_value;
if (err)
goto leave;
}
/* We require a fingerprint because only this uniquely identifies a /* We require a fingerprint because only this uniquely identifies a
key and may thus be used to select a key for unattended key key and may thus be used to select a key for unattended key
signing. */ signing. */
@ -3036,10 +3156,14 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
} }
/* Sign. */ /* Sign. */
sign_uids (ctrl, es_stdout, keyblock, locusr, err = sign_uids (ctrl, es_stdout, keyblock, locusr,
(SIGN_UIDS_QUICK | (local? SIGN_UIDS_LOCAL : 0)), (SIGN_UIDS_QUICK
&modified); | (local? SIGN_UIDS_LOCAL : 0)
| (trustsig? SIGN_UIDS_TRUSTSIG : 0)),
trustsig, &modified);
es_fflush (es_stdout); es_fflush (es_stdout);
if (err)
goto leave;
if (modified) if (modified)
{ {
@ -3058,7 +3182,10 @@ keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids,
leave: leave:
if (err) if (err)
write_status_error ("keyedit.sign-key", err); {
log_error (_("creating key signature failed: %s\n"), gpg_strerror (err));
write_status_error ("keyedit.sign-key", err);
}
release_kbnode (keyblock); release_kbnode (keyblock);
keydb_release (kdbhd); keydb_release (kdbhd);
} }

View file

@ -48,7 +48,8 @@ void keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr);
void keyedit_quick_revuid (ctrl_t ctrl, const char *username, void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
const char *uidtorev); const char *uidtorev);
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr, void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,
strlist_t uids, strlist_t locusr, int local); strlist_t uids, strlist_t locusr,
const char *trustsig, int local);
void keyedit_quick_revsig (ctrl_t ctrl, const char *username, void keyedit_quick_revsig (ctrl_t ctrl, const char *username,
const char *sigtorev, strlist_t affected_uids); const char *sigtorev, strlist_t affected_uids);
void keyedit_quick_set_expire (ctrl_t ctrl, void keyedit_quick_set_expire (ctrl_t ctrl,