diff options
author | Werner Koch <[email protected]> | 2016-02-14 14:50:12 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2016-02-14 15:01:53 +0000 |
commit | 9b28b82e7c40d1eacc446d5932cd613c56378ed8 (patch) | |
tree | 370ca775e4b925b1fc4194debb4d4545d011d922 /g10/keyedit.c | |
parent | gpg: Improve API documentation. (diff) | |
download | gnupg-9b28b82e7c40d1eacc446d5932cd613c56378ed8.tar.gz gnupg-9b28b82e7c40d1eacc446d5932cd613c56378ed8.zip |
gpg: Add hidden key-edit subcommand "change-usage".
* g10/keyedit.c (cmdCHANGEUSAGE): New.
(cmds): Add command "change-usage".
(keyedit_menu): Handle that command.
(menu_changeusage): New.
* g10/keygen.c (keygen_add_key_flags): New.
(ask_key_flags): Add optional arg current.
--
Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'g10/keyedit.c')
-rw-r--r-- | g10/keyedit.c | 119 |
1 files changed, 118 insertions, 1 deletions
diff --git a/g10/keyedit.c b/g10/keyedit.c index 30f52a4b0..19ddf2922 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -70,6 +70,7 @@ static int menu_clean (KBNODE 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_expire (KBNODE pub_keyblock); +static int menu_changeusage (kbnode_t keyblock); static int menu_backsign (KBNODE pub_keyblock); static int menu_set_primary_uid (KBNODE pub_keyblock); static int menu_set_preferences (KBNODE pub_keyblock); @@ -1362,7 +1363,7 @@ enum cmdids cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, - cmdEXPIRE, cmdBACKSIGN, + cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, #ifndef NO_TRUST_MODELS cmdENABLEKEY, cmdDISABLEKEY, #endif /*!NO_TRUST_MODELS*/ @@ -1393,6 +1394,7 @@ static struct { "key", cmdSELKEY, 0, N_("select subkey N")}, { "check", cmdCHECK, 0, N_("check signatures")}, { "c", cmdCHECK, 0, NULL}, + { "change-usage", cmdCHANGEUSAGE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "cross-certify", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "backsign", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "sign", cmdSIGN, KEYEDIT_NOT_SK | KEYEDIT_TAIL_MATCH, @@ -2122,6 +2124,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, } break; + case cmdCHANGEUSAGE: + if (menu_changeusage (keyblock)) + { + merge_keys_and_selfsig (keyblock); + modified = 1; + redisplay = 1; + } + break; + case cmdBACKSIGN: if (menu_backsign (keyblock)) { @@ -4110,6 +4121,112 @@ menu_expire (KBNODE pub_keyblock) } +/* Change the capability of a selected key. This command should only + * be used to rectify badly created keys and as such is not suggested + * for general use. */ +static int +menu_changeusage (kbnode_t keyblock) +{ + int n1, rc; + int mainkey = 0; + PKT_public_key *main_pk, *sub_pk; + PKT_user_id *uid; + kbnode_t node; + u32 keyid[2]; + + n1 = count_selected_keys (keyblock); + if (n1 > 1) + { + tty_printf (_("You must select exactly one key.\n")); + return 0; + } + else if (n1) + tty_printf ("Changing usage of a subkey.\n"); + else + { + tty_printf ("Changing usage of the primary key.\n"); + mainkey = 1; + } + + /* Now we can actually change the self-signature(s) */ + main_pk = sub_pk = NULL; + uid = NULL; + for (node = keyblock; node; node = node->next) + { + if (node->pkt->pkttype == PKT_PUBLIC_KEY) + { + main_pk = node->pkt->pkt.public_key; + keyid_from_pk (main_pk, keyid); + } + else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) + { + if (node->flag & NODFLG_SELKEY) + sub_pk = node->pkt->pkt.public_key; + else + sub_pk = NULL; + } + else if (node->pkt->pkttype == PKT_USER_ID) + uid = node->pkt->pkt.user_id; + else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE + && (mainkey || sub_pk)) + { + PKT_signature *sig = node->pkt->pkt.signature; + if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] + && ((mainkey && uid + && uid->created && (sig->sig_class & ~3) == 0x10) + || (!mainkey && sig->sig_class == 0x18)) + && sig->flags.chosen_selfsig) + { + /* This is the self-signature which is to be replaced. */ + PKT_signature *newsig; + PACKET *newpkt; + + if ((mainkey && main_pk->version < 4) + || (!mainkey && sub_pk->version < 4)) + { + log_info ("You can't change the capabilities of a v3 key\n"); + return 0; + } + + if (mainkey) + main_pk->pubkey_usage = ask_key_flags (main_pk->pubkey_algo, 0, + main_pk->pubkey_usage); + else + sub_pk->pubkey_usage = ask_key_flags (sub_pk->pubkey_algo, 1, + sub_pk->pubkey_usage); + + if (mainkey) + rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL, + main_pk, keygen_add_key_flags, + main_pk); + else + rc = + update_keysig_packet (&newsig, sig, main_pk, NULL, sub_pk, + main_pk, keygen_add_key_flags, sub_pk); + if (rc) + { + log_error ("make_keysig_packet failed: %s\n", + gpg_strerror (rc)); + return 0; + } + + /* Replace the packet. */ + newpkt = xmalloc_clear (sizeof *newpkt); + newpkt->pkttype = PKT_SIGNATURE; + newpkt->pkt.signature = newsig; + free_packet (node->pkt); + xfree (node->pkt); + node->pkt = newpkt; + sub_pk = NULL; + break; + } + } + } + + return 1; +} + + static int menu_backsign (KBNODE pub_keyblock) { |