diff options
author | Werner Koch <[email protected]> | 2023-03-01 16:22:20 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2023-03-01 16:22:20 +0000 |
commit | 3a18378a92af63f5bccbe78efa546acb04e8a0f8 (patch) | |
tree | a373fb90df2102fd82f9a265353cf3afb8ef0b6c /g10/keyedit.c | |
parent | agent: Show "no secret key" instead of "card removed". (diff) | |
download | gnupg-3a18378a92af63f5bccbe78efa546acb04e8a0f8.tar.gz gnupg-3a18378a92af63f5bccbe78efa546acb04e8a0f8.zip |
gpg: Allow adding of Additional Decryption Subkeys.
* g10/free-packet.c (copy_public_key): Factor some code out to ...
(copy_public_key_basics): new.
* g10/build-packet.c (build_sig_subpkt_from_sig): New arg signhints.
* g10/packet.h (PUBKEY_USAGE_RENC): Fix value.
(SIGNHINT_KEYSIG, SIGNHINT_SELFSIG): Moved from sign.c.
(SIGNHINT_ADSK): New.
(PKT_public_key): Change pubkey_usage from byte to u16.
(PKT_user_id): Cosmetic fix: change help_key_usage from int to u16.
* g10/getkey.c (parse_key_usage): Make public.
* g10/misc.c (openpgp_pk_algo_usage): Take PUBKEY_USAGE_RENC in
account.
* g10/sign.c (update_keysig_packet): Set SIGNHINT_ADSK.
(make_keysig_packet): Ditto.
(do_sign): No time warp check in ADSK mode.
* g10/sig-check.c (check_signature_metadata_validity): Ditto.
* g10/keygen.c (struct opaque_data_usage_and_pk): Remove.
(write_keybinding): Do not use the removed struct.
(do_add_key_flags): Support PUBKEY_USAGE_RENC and others.
(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.
--
This makes use of a new encryption flag:
The "restricted encryption key" (2nd,0x04) does not take part in any
automatic selection of encryption keys. It is only found on a
subkey signature (type 0x18), one that refers to the key the flag
applies to.
Followup patches will add encryption support and a --quick command.
GnuPG-bug-id: 6395
Diffstat (limited to '')
-rw-r--r-- | g10/keyedit.c | 169 |
1 files changed, 167 insertions, 2 deletions
diff --git a/g10/keyedit.c b/g10/keyedit.c index 83c20b846..6c45fd640 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,7 +1,7 @@ /* keyedit.c - Edit properties of a key * Copyright (C) 1998-2010 Free Software Foundation, Inc. * Copyright (C) 1998-2017 Werner Koch - * Copyright (C) 2015, 2016, 2022 g10 Code GmbH + * Copyright (C) 2015, 2016, 2022-2023 g10 Code GmbH * * This file is part of GnuPG. * @@ -73,6 +73,7 @@ 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); 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); @@ -1243,7 +1244,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*/ @@ -1308,6 +1309,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, @@ -2000,6 +2003,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, } break; + case cmdADDADSK: + if (menu_addadsk (ctrl, keyblock)) + { + redisplay = 1; + modified = 1; + merge_keys_and_selfsig (ctrl, keyblock); + } + break; + case cmdREVUID: { int n1; @@ -4643,6 +4655,159 @@ fail: } +/* + * Ask for a new additional decryption subkey and add it to the key + * block. Returns true if the keybloxk was changed and false + * otherwise. + */ +static int +menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock) +{ + PKT_public_key *pk; + PKT_public_key *sub_pk; + PKT_public_key *main_pk; + PKT_public_key *adsk_pk = NULL; + kbnode_t adsk_keyblock = NULL; + PKT_signature *sig = NULL; + char *answer = NULL; + gpg_error_t err; + KEYDB_SEARCH_DESC desc; + byte fpr[MAX_FINGERPRINT_LEN]; + size_t fprlen; + kbnode_t node, node2; + kbnode_t subkeynode = NULL; + PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */ + + log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY); + main_pk = pub_keyblock->pkt->pkt.public_key; + + for (;;) + { + xfree (answer); + 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) + { + log_info (_("\"%s\" is not a fingerprint\n"), answer); + continue; + } + + 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 && gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY) + log_info (_("Did you specify the fingerprint of a subkey?\n")); + 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 == desc.fprlen + && !memcmp (fpr, desc.u.fpr, fprlen) + && (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) + log_info (_("Did you specify the fingerprint of a subkey?\n")); + 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 == desc.fprlen + && !memcmp (fpr, desc.u.fpr, fprlen)) + break; + } + } + if (node2) + { + log_info (_("key \"%s\" is already on this keyblock\n"), answer); + continue; + } + + break; + } + + /* Append the subkey. + * Note that we don't use the ADSK_PK directly because this is the + * primary key and in general we use a subkey to which NODE points. + * ADSK_PK has only been used to pass the requested key usage to + * get_pubkey_byname. SUB_PK will point to the actual adsk. */ + log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY + || node->pkt->pkttype == PKT_PUBLIC_SUBKEY); + sub_pk = copy_public_key_basics (NULL, node->pkt->pkt.public_key); + keyid_from_pk (main_pk, sub_pk->main_keyid); /* Fixup main keyid. */ + log_assert ((sub_pk->pubkey_usage & PUBKEY_USAGE_ENC)); + sub_pk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */ + pkt = xcalloc (1, sizeof *pkt); + pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */ + pkt->pkt.public_key = sub_pk; + subkeynode = new_kbnode (pkt); + + /* Make the signature. */ + err = make_keysig_packet (ctrl, &sig, main_pk, NULL, sub_pk, main_pk, 0x18, + sub_pk->timestamp, 0, + keygen_add_key_flags_and_expire, sub_pk, NULL); + 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 (pub_keyblock, subkeynode); + subkeynode = NULL; + pkt = xcalloc (1, sizeof *pkt); + pkt->pkttype = PKT_SIGNATURE; + pkt->pkt.signature = sig; + add_kbnode (pub_keyblock, new_kbnode (pkt)); + + leave: + xfree (answer); + free_public_key (adsk_pk); + release_kbnode (adsk_keyblock); + release_kbnode (subkeynode); + 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 |