diff options
author | James Bottomley <[email protected]> | 2021-03-09 21:50:30 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2021-03-10 12:34:18 +0000 |
commit | 92b601fceec7da64939591001dba94e202f6e6a0 (patch) | |
tree | 0b7f481af3d3a223893082e171b53f30e4dede2e | |
parent | agent: Add new shadow key type and functions to call tpm2daemon (diff) | |
download | gnupg-92b601fceec7da64939591001dba94e202f6e6a0.tar.gz gnupg-92b601fceec7da64939591001dba94e202f6e6a0.zip |
gpg: Add new command keytotpm to convert a private key to TPM format
* agent/command.c (cmd_keytotpm): New.
(agent/command.c): Register new command KEYTOTPM.
* g10/call-agent.c (agent_keytotpm): New.
* g10/keyedit.c (cmdKEYTOTPM): New command "keytotpm".
(keyedit_menu): Implement.
--
The plumbing is done in two parts: the agent is modified to understand
a KEYTOTPM assuan command taking the key grip as an argument. This
simply obtains the key s expression and calls the existing writeky
diversion to the tpm2daemon. The daemon reponds with the TPM
conversion of the key and that key is then stored in the keyfile as a
shadowed-private-key with "tpm2-v1" type.
To effect the conversion, all the user does from gpg --edit-key is
select which private key they wish to move (or move the primary if no
key is selected) and type keytotpm. The conversion to TPM form is
instantaneous and once converted, the actual key cannot be recovered,
meaning that if you want your gpg key to move to a new laptop you must
keep an unconverted backup copy in a safe location.
When you do a list command, all TPM keys show up as
card-no: TPM-Protected
The key is stored encrypted to the TPM2 storage seed and since each
TPM has a unique seed, only the single TPM contained in your laptop
can now read the key. This means you cannot simply copy the shadowed
key file over to a new laptop, you must copy over the backup copy and
then convert it to TPM form on the new laptop.
To decomission your laptop, execute a tssclear command which
regenerates the storage seed and effectively shreds all keys. Note
when you have done this *every* TPM2 shadowed private key becomes
unreadable by any TPM and all are effectively destroyed.
Signed-off-by: James Bottomley <[email protected]>
Very minor cosmetic changes.
Signed-off-by: Werner Koch <[email protected]>
-rw-r--r-- | agent/command.c | 52 | ||||
-rw-r--r-- | agent/divert-tpm2.c | 2 | ||||
-rw-r--r-- | g10/call-agent.c | 22 | ||||
-rw-r--r-- | g10/call-agent.h | 3 | ||||
-rw-r--r-- | g10/keyedit.c | 45 |
5 files changed, 123 insertions, 1 deletions
diff --git a/agent/command.c b/agent/command.c index 87446a233..095f38ba3 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3114,6 +3114,57 @@ cmd_put_secret (assuan_context_t ctx, char *line) +static const char hlp_keytotpm[] = + "KEYTOTPM <hexstring_with_keygrip>\n" + "\n"; +static gpg_error_t +cmd_keytotpm (assuan_context_t ctx, char *line) +{ + ctrl_t ctrl = assuan_get_pointer (ctx); + gpg_error_t err = 0; + unsigned char grip[20]; + gcry_sexp_t s_skey; + unsigned char *shadow_info = NULL; + + if (ctrl->restricted) + return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); + + err = parse_keygrip (ctx, line, grip); + if (err) + goto leave; + + if (agent_key_available (grip)) + { + err =gpg_error (GPG_ERR_NO_SECKEY); + goto leave; + } + + err = agent_key_from_file (ctrl, NULL, ctrl->server_local->keydesc, grip, + &shadow_info, CACHE_MODE_IGNORE, NULL, + &s_skey, NULL); + if (err) + { + xfree (shadow_info); + goto leave; + } + if (shadow_info) + { + /* Key is on a TPM or smartcard already. */ + xfree (shadow_info); + gcry_sexp_release (s_skey); + err = gpg_error (GPG_ERR_UNUSABLE_SECKEY); + goto leave; + } + + err = divert_tpm2_writekey (ctrl, grip, s_skey); + gcry_sexp_release (s_skey); + + leave: + return leave_cmd (ctx, err); +} + + + static const char hlp_getval[] = "GETVAL <key>\n" "\n" @@ -3812,6 +3863,7 @@ register_commands (assuan_context_t ctx) { "RELOADAGENT", cmd_reloadagent,hlp_reloadagent }, { "GETINFO", cmd_getinfo, hlp_getinfo }, { "KEYTOCARD", cmd_keytocard, hlp_keytocard }, + { "KEYTOTPM", cmd_keytotpm, hlp_keytotpm }, { NULL } }; int i, rc; diff --git a/agent/divert-tpm2.c b/agent/divert-tpm2.c index 4946f7a8a..0741c6847 100644 --- a/agent/divert-tpm2.c +++ b/agent/divert-tpm2.c @@ -18,6 +18,8 @@ divert_tpm2_pksign (ctrl_t ctrl, const char *desc_text, const unsigned char *shadow_info, unsigned char **r_sig, size_t *r_siglen) { + (void)desc_text; + (void)algo; return agent_tpm2d_pksign(ctrl, digest, digestlen, shadow_info, r_sig, r_siglen); } diff --git a/g10/call-agent.c b/g10/call-agent.c index a553ef67a..fb80489b2 100644 --- a/g10/call-agent.c +++ b/g10/call-agent.c @@ -1060,6 +1060,28 @@ agent_scd_apdu (const char *hexapdu, unsigned int *r_sw) return err; } +int +agent_keytotpm (ctrl_t ctrl, const char *hexgrip) +{ + int rc; + char line[ASSUAN_LINELENGTH]; + struct default_inq_parm_s parm; + + snprintf(line, DIM(line), "KEYTOTPM %s\n", hexgrip); + + rc = start_agent (ctrl, 0); + if (rc) + return rc; + parm.ctx = agent_ctx; + parm.ctrl = ctrl; + + rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm, + NULL, NULL); + if (rc) + log_log (GPGRT_LOGLVL_ERROR, _("error from TPM: %s\n"), gpg_strerror (rc)); + return rc; +} + /* Used by: * card_store_subkey diff --git a/g10/call-agent.h b/g10/call-agent.h index 4a66af2aa..efea7ec4a 100644 --- a/g10/call-agent.h +++ b/g10/call-agent.h @@ -126,6 +126,9 @@ gpg_error_t agent_scd_getattr_one (const char *name, char **r_value); /* Update INFO with the attribute NAME. */ int agent_scd_getattr (const char *name, struct agent_card_info_s *info); +/* send the KEYTOTPM command */ +int agent_keytotpm (ctrl_t ctrl, const char *hexgrip); + /* Send the KEYTOCARD command. */ int agent_keytocard (const char *hexgrip, int keyno, int force, const char *serialno, const char *timestamp); diff --git a/g10/keyedit.c b/g10/keyedit.c index 596662dda..c8a127551 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1247,7 +1247,7 @@ enum cmdids #endif /*!NO_TRUST_MODELS*/ cmdSHOWPREF, cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, - cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, + cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdKEYTOTPM, cmdBKUPTOCARD, cmdCLEAN, cmdMINIMIZE, cmdGRIP, cmdNOP }; @@ -1298,6 +1298,8 @@ static struct N_("add a key to a smartcard")}, { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, N_("move a key to a smartcard")}, + { "keytotpm", cmdKEYTOTPM, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, + N_("convert a key to TPM form using the local TPM")}, { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK, N_("move a backup key to a smartcard")}, #endif /*ENABLE_CARD_SUPPORT */ @@ -1796,6 +1798,47 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, } break; + case cmdKEYTOTPM: + /* FIXME need to store the key and not commit until later */ + { + kbnode_t node = NULL; + switch (count_selected_keys (keyblock)) + { + case 0: + if (cpr_get_answer_is_yes + ("keyedit.keytocard.use_primary", + /* TRANSLATORS: Please take care: This is about + moving the key and not about removing it. */ + _("Really move the primary key? (y/N) "))) + node = keyblock; + break; + case 1: + for (node = keyblock; node; node = node->next) + { + if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY + && node->flag & NODFLG_SELKEY) + break; + } + break; + default: + tty_printf (_("You must select exactly one key.\n")); + break; + } + if (node) + { + PKT_public_key *xxpk = node->pkt->pkt.public_key; + char *hexgrip; + + hexkeygrip_from_pk (xxpk, &hexgrip); + if (!agent_keytotpm (ctrl, hexgrip)) + { + redisplay = 1; + } + xfree (hexgrip); + } + } + break; + case cmdKEYTOCARD: { KBNODE node = NULL; |