mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-03 22:56:33 +02: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:
parent
7eb39815bd
commit
eafe175320
12 changed files with 495 additions and 55 deletions
237
g10/keyedit.c
237
g10/keyedit.c
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue