1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-10-29 19:48:43 +01:00

gpg: New option --default-new-key-adsk and "addadsk" for edit-key.

* g10/free-packet.c (copy_public_key): Factor some code out to ...
(copy_public_key_basics): new.
* keygen.c (keygen_add_key_flags_and_expire): Rewrite and make public.
* g10/keyedit.c (enum cmdids): Add cmdADDADSK.
(keyedit_menu): Add command "addadsk".
(menu_addadsk): New.

* g10/options.h (opt): Add field def_new_key_adsks.
* g10/gpg.c (oDefaultNewKeyADSK): New.
(opts): Add --default-new-key-adsk.
(main): Parse option.
* g10/keyedit.c (menu_addadsk): Factor some code out to ...
(append_adsk_to_key): new.  Add compliance check.
* g10/keygen.c (pADSK): New.
(para_data_s): Add adsk to the union.
(release_parameter_list): Free the adsk.
(prepare_adsk): New.
(get_parameter_adsk): New.
(get_parameter_revkey): Remove unneeded arg key and change callers.
(proc_parameter_file): Prepare adsk parameter from the configured
fingerprints.
(do_generate_keypair): Create adsk.
--

GnuPG-bug-id: 6882
(cherry picked from commit ed118e2ed5)
and modified to adjust to other code changes
This commit is contained in:
Werner Koch 2024-09-26 10:37:32 +02:00
parent 7eb39815bd
commit eafe175320
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
12 changed files with 495 additions and 55 deletions

View File

@ -1729,13 +1729,26 @@ this option at all (e.g. due to the @option{--no-options} option).
@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
``sensitive:'' that info is normally not exported with the key. This
option may be given several times 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.
all previously given fingerprints 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 --default-new-key-adsk @var{fingerprint}
@opindex default-new-key-adsk
Add the subkey specified by @var{fingerprint} as an Additional
Decryption Subkey (ADSK) to newly created keys. This option may be
given several time to add more than one ADSK. It is also possible to
give several fingerprints delimited by space or comma as value to this
option. If the keyword ``clear'' is used instead of a fingerprint,
all previously specified fingerprints are discarded (useful to
override options given in a config file). The fingerprint is expected
to specify a subkey and it does not need an exclamation mark as
suffix; it must be given in cmpact format (40 or 64 hex-digits without
any spaces).
@item --trust-model @{pgp|classic|tofu|tofu+pgp|direct|always|auto@}

View File

@ -1123,19 +1123,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;

View File

@ -189,10 +189,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;
@ -200,8 +200,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;
@ -215,6 +215,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)

View File

@ -422,6 +422,7 @@ enum cmd_and_opt_values
oTOFUDefaultPolicy,
oTOFUDBFormat,
oDefaultNewKeyAlgo,
oDefaultNewKeyADSK,
oWeakDigest,
oUnwrap,
oOnlySignTextIDs,
@ -627,6 +628,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oPGP7, "pgp7", "@"),
ARGPARSE_s_n (oPGP8, "pgp8", "@"),
ARGPARSE_s_s (oDefaultNewKeyAlgo, "default-new-key-algo", "@"),
ARGPARSE_s_s (oDefaultNewKeyADSK, "default-new-key-adsk", "@"),
ARGPARSE_p_u (oMinRSALength, "min-rsa-length", "@"),
#ifndef NO_TRUST_MODELS
ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
@ -2309,6 +2311,7 @@ main (int argc, char **argv)
const char *fname;
char *username;
int may_coredump;
gpg_error_t tmperr;
strlist_t sl;
strlist_t remusr = NULL;
strlist_t locusr = NULL;
@ -3648,6 +3651,16 @@ main (int argc, char **argv)
opt.def_new_key_algo = pargs.r.ret_str;
break;
case oDefaultNewKeyADSK:
if (!strcmp (pargs.r.ret_str, "clear"))
FREE_STRLIST (opt.def_new_key_adsks);
else if (!tokenize_to_strlist (&opt.def_new_key_adsks,
pargs.r.ret_str, " \t,")
&& (tmperr = gpg_err_code_from_syserror()) != GPG_ERR_ENOENT)
log_info (_("error parsing value for option '%s': %s\n"),
"--default-new-key-algo", gpg_strerror (tmperr));
break;
case oUseOnlyOpenPGPCard:
opt.flags.use_only_openpgp_card = 1;
break;

View File

@ -3122,3 +3122,13 @@ keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
(void) extended;
return 0;
}
gpg_error_t
append_adsk_to_key (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *adsk)
{
(void)ctrl;
(void)keyblock;
(void)adsk;
return GPG_ERR_NOT_IMPLEMENTED;
}

View File

@ -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);
@ -1240,7 +1242,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*/
@ -1303,6 +1305,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 additional decryption subkeys")},
{ "delsig", cmdDELSIG, 0,
N_("delete signatures from the selected user IDs")},
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
@ -1966,6 +1970,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;
@ -4639,6 +4652,228 @@ fail:
}
/* Core function to add an ADSK to the KEYBLOCK. Returns 0 on success
* or an error code. */
gpg_error_t
append_adsk_to_key (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *adsk)
{
gpg_error_t err;
PKT_public_key *main_pk; /* The primary key. */
PKT_signature *sig = NULL;
kbnode_t adsknode = NULL;
PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */
/* First get a copy. */
adsk = copy_public_key_basics (NULL, adsk);
/* Check compliance. */
if (!gnupg_pk_is_compliant (opt.compliance, adsk->pubkey_algo, 0,
adsk->pkey, nbits_from_pk (adsk), NULL))
{
char pkhex[MAX_FINGERPRINT_LEN*2+1];
hexfingerprint (adsk, pkhex, sizeof pkhex);
log_error (_("WARNING: key %s is not suitable for encryption"
" in %s mode\n"),
pkhex, gnupg_compliance_option_string (opt.compliance));
err = gpg_error (GPG_ERR_FORBIDDEN);
goto leave;
}
/* Get the primary key. */
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
main_pk = keyblock->pkt->pkt.public_key;
/* Prepare and append the adsk. */
keyid_from_pk (main_pk, adsk->main_keyid); /* Fixup main keyid. */
log_assert ((adsk->pubkey_usage & PUBKEY_USAGE_ENC));
adsk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
{
err = gpg_error_from_syserror ();
goto leave;
}
pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */
pkt->pkt.public_key = adsk;
adsknode = new_kbnode (pkt);
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, main_pk, NULL, adsk, main_pk, 0x18, 0,
adsk->timestamp, 0,
keygen_add_key_flags_and_expire, adsk, NULL);
adsk = NULL; /* (owned by adsknode - avoid double free.) */
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 (keyblock, adsknode);
adsknode = NULL;
pkt = xtrycalloc (1, sizeof *pkt);
if (!pkt)
{
err = gpg_error_from_syserror ();
goto leave;
}
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode (keyblock, new_kbnode (pkt));
leave:
release_kbnode (adsknode);
free_public_key (adsk); /* Release our copy. */
return err;
}
/*
* 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 function 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 *adsk_pk = NULL;
kbnode_t adsk_keyblock = NULL;
char *answer = NULL;
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
kbnode_t node, node2;
log_assert (pub_keyblock->pkt->pkttype == 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
|| desc.mode == KEYDB_SEARCH_MODE_FPR20))
{
log_info (_("\"%s\" is not a fingerprint\n"), answer);
err = gpg_error (GPG_ERR_INV_USER_ID);
if (adskfpr)
goto leave;
continue;
}
/* Force searching for that exact fingerprint and for any key
* which has a key with that fingerprint. */
if (!strchr (answer, '!'))
{
char *tmpstr = xstrconcat (answer, "!", NULL);
xfree (answer);
answer = tmpstr;
}
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 == 20
&& !memcmp (fpr, desc.u.fpr, 20)
&& (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 == 20
&& !memcmp (fpr, desc.u.fpr, 20))
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. */
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
err = append_adsk_to_key (ctrl, pub_keyblock, node->pkt->pkt.public_key);
leave:
xfree (answer);
free_public_key (adsk_pk);
release_kbnode (adsk_keyblock);
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

View File

@ -55,6 +55,8 @@ void keyedit_quick_set_expire (ctrl_t ctrl,
void keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
const char *primaryuid);
void keyedit_quick_update_pref (ctrl_t ctrl, const char *username);
gpg_error_t append_adsk_to_key (ctrl_t ctrl, kbnode_t keyblock,
PKT_public_key *adsk);
void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock, int print_sec);
int keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
int rc, kbnode_t keyblock,

View File

@ -91,6 +91,7 @@ enum para_name {
pKEYSERVER,
pKEYGRIP,
pSUBKEYGRIP,
pADSK /* this uses u.adsk */
};
struct para_data_s {
@ -102,6 +103,7 @@ struct para_data_s {
u32 creation;
unsigned int usage;
struct revocation_key revkey;
PKT_public_key *adsk; /* used with key == pADSK */
char value[1];
} u;
};
@ -246,22 +248,26 @@ write_uid (kbnode_t root, const char *s)
static void
do_add_key_flags (PKT_signature *sig, unsigned int use)
{
byte buf[1];
byte buf[2] = { 0, 0 };
buf[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;
if (use & PUBKEY_USAGE_GROUP)
buf[0] |= 0x80;
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_RENC)
buf[1] |= 0x04;
if (use & PUBKEY_USAGE_TIME)
buf[1] |= 0x08;
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, buf[1]? 2:1);
}
@ -308,10 +314,18 @@ keygen_add_key_flags (PKT_signature *sig, void *opaque)
}
int
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
{
keygen_add_key_flags (sig, opaque);
return keygen_add_key_expire (sig, opaque);
}
/* This is only used to write the key binding signature. It is not
* used for the primary key. */
static int
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
keygen_add_key_flags_from_oduap (PKT_signature *sig, void *opaque)
{
struct opaque_data_usage_and_pk *oduap = opaque;
@ -1224,7 +1238,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
oduap.pk = sub_pk;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
0, timestamp, 0,
keygen_add_key_flags_and_expire, &oduap,
keygen_add_key_flags_from_oduap, &oduap,
cache_nonce);
if (err)
{
@ -3693,6 +3707,9 @@ release_parameter_list (struct para_data_s *r)
r2 = r->next;
if (r->key == pPASSPHRASE && *r->u.value)
wipememory (r->u.value, strlen (r->u.value));
else if (r->key == pADSK)
free_public_key (r->u.adsk);
xfree (r);
}
}
@ -3889,7 +3906,8 @@ prepare_desig_revoker (ctrl_t ctrl, const char *name)
}
if (classify_user_id (name, &desc, 1)
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
|| !(desc.mode == KEYDB_SEARCH_MODE_FPR
|| desc.mode == KEYDB_SEARCH_MODE_FPR20))
{
log_info (_("\"%s\" is not a fingerprint\n"), name);
err = gpg_error (GPG_ERR_INV_NAME);
@ -3928,6 +3946,60 @@ prepare_desig_revoker (ctrl_t ctrl, const char *name)
}
/* Parse asn ADSK specified by NAME, check that the public key exists
* and return a parameter with the adsk information. On error print a
* diagnostic and return NULL. */
static struct para_data_s *
prepare_adsk (ctrl_t ctrl, const char *name)
{
gpg_error_t err;
char *namebuffer = NULL;
struct para_data_s *para = NULL;
KEYDB_SEARCH_DESC desc;
PKT_public_key *adsk_pk = NULL;
char *p;
if (classify_user_id (name, &desc, 1)
|| !(desc.mode == KEYDB_SEARCH_MODE_FPR
|| desc.mode == KEYDB_SEARCH_MODE_FPR20))
{
log_info (_("\"%s\" is not a fingerprint\n"), name);
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
/* Force searching for that exact fingerprint. */
if (!strchr (name, '!'))
{
namebuffer = xstrconcat (name, "!", NULL);
name = namebuffer;
}
adsk_pk = xcalloc (1, sizeof *adsk_pk);
adsk_pk->req_usage = PUBKEY_USAGE_ENC;
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, adsk_pk, name, NULL, NULL, 1);
if (err)
goto leave;
para = xcalloc (1, sizeof *para);
para->key = pADSK;
para->u.adsk = adsk_pk;
adsk_pk = NULL;
leave:
if (err)
{
if (namebuffer && (p=strchr (namebuffer, '!')))
*p = 0; /* Strip the ! for the diagnostic. */
log_error ("invalid ADSK '%s' specified: %s\n", name, gpg_strerror (err));
}
free_public_key (adsk_pk);
xfree (namebuffer);
return para;
}
/* Parse a pREVOKER parameter into its dedicated parts. */
static int
parse_revocation_key (const char *fname,
@ -4007,13 +4079,19 @@ 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,
unsigned int idx)
get_parameter_revkey (struct para_data_s *para, unsigned int idx)
{
struct para_data_s *r = get_parameter_idx (para, key, idx);
struct para_data_s *r = get_parameter_idx (para, pREVOKER, idx);
return r? &r->u.revkey : NULL;
}
static PKT_public_key *
get_parameter_adsk (struct para_data_s *para, unsigned int idx)
{
struct para_data_s *r = get_parameter_idx (para, pADSK, idx);
return r? r->u.adsk : NULL;
}
static int
proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
struct output_control_s *outctrl, int card )
@ -4022,7 +4100,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;
strlist_t sl, slr;
int is_default = 0;
int have_user_id = 0;
int err, algo;
@ -4182,8 +4260,36 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
append_to_parameter (para, r);
}
/* Check and append ADSKs from the config file. While doing this
* also check for duplicate specifications. In addition we remove
* an optional '!' suffix for easier comparing; the suffix is anyway
* re-added later. */
for (sl = opt.def_new_key_adsks; sl; sl = sl->next)
{
if (!*sl->d)
continue;
p = strchr (sl->d, '!');
if (p)
*p = 0;
for (slr = opt.def_new_key_adsks; slr != sl; slr = slr->next)
if (!ascii_strcasecmp (sl->d, slr->d))
{
*sl->d = 0; /* clear fpr to mark this as a duplicate. */
break;
}
if (!*sl->d)
continue;
/* Make KEYCREATIONDATE from Creation-Date. */
r = prepare_adsk (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
* been set. This is so that we don't generate a key with a
* fingerprint different from the one stored on the OpenPGP card. */
r = get_parameter (para, pCREATIONDATE);
if (r && *r->u.value)
{
@ -5243,6 +5349,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
u32 expire;
const char *key_from_hexgrip = NULL;
unsigned int idx;
int any_adsk = 0;
if (outctrl->dryrun)
{
@ -5345,11 +5452,11 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
}
/* 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, timestamp, cache_nonce);
for (idx=0; !err && (revkey = get_parameter_revkey (para, idx)); idx++)
{
err = write_direct_sig (ctrl, pub_root, pri_psk,
revkey, timestamp, cache_nonce);
}
if (!err && (s = get_parameter_value (para, pUSERID)))
{
@ -5426,6 +5533,25 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
did_sub = 1;
}
/* Get rid of the first empty packet. */
if (!err)
commit_kbnode (&pub_root);
/* Add ADSKs if any are specified. */
if (!err)
{
PKT_public_key *adsk;
for (idx=0; (adsk = get_parameter_adsk (para, idx)); idx++)
{
err = append_adsk_to_key (ctrl, pub_root, adsk);
if (err)
break;
any_adsk++;
}
}
if (!err && outctrl->use_files) /* Direct write to specified files. */
{
err = write_keyblock (outctrl->pub.stream, pub_root);
@ -5482,9 +5608,6 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
gen_standard_revoke (ctrl, pk, cache_nonce);
/* Get rid of the first empty packet. */
commit_kbnode (&pub_root);
if (!opt.batch)
{
tty_printf (_("public and secret key created and signed.\n") );
@ -5526,6 +5649,9 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
PKT_PUBLIC_KEY)->pkt->pkt.public_key;
print_status_key_created (did_sub? 'B':'P', pk,
get_parameter_value (para, pHANDLE));
es_fflush (es_stdout);
if (any_adsk)
log_info (_("Note: The key has been created with one or more ADSK!\n"));
}
release_kbnode (pub_root);

View File

@ -310,6 +310,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);

View File

@ -125,6 +125,8 @@ struct
const char *def_new_key_algo;
strlist_t def_new_key_adsks; /* Option --default-new-key-adsk. */
/* Options to be passed to the gpg-agent */
session_env_t session_env;
char *lc_ctype;

View File

@ -68,6 +68,11 @@
/* The usage bits which define encryption. */
#define PUBKEY_USAGE_XENC_MASK (PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC)
/* 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 \
@ -863,7 +868,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,
@ -885,7 +891,10 @@ 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 );
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );

View File

@ -49,10 +49,6 @@
#define LF "\n"
#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=0;
@ -355,7 +351,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"
@ -864,7 +863,7 @@ write_signature_packets (ctrl_t ctrl,
if (sig->version >= 4)
{
build_sig_subpkt_from_sig (sig, pk);
build_sig_subpkt_from_sig (sig, pk, 0);
mk_notation_policy_etc (sig, NULL, pk);
if (opt.flags.include_key_block && IS_SIG (sig))
err = mk_sig_subpkt_key_block (ctrl, sig, pk);
@ -1687,6 +1686,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 )
{
@ -1709,7 +1710,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 (sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls
@ -1759,7 +1760,7 @@ update_keysig_packet (ctrl_t ctrl,
int digest_algo;
gcry_md_hd_t md;
u32 pk_keyid[2], pksk_keyid[2];
unsigned int signhints;
unsigned int signhints = 0;
if ((!orig_sig || !pk || !pksk)
|| (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid)
@ -1820,6 +1821,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. */
@ -1828,7 +1835,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);