From 92b601fceec7da64939591001dba94e202f6e6a0 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 9 Mar 2021 13:50:30 -0800 Subject: 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 Very minor cosmetic changes. Signed-off-by: Werner Koch --- agent/command.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'agent/command.c') diff --git a/agent/command.c b/agent/command.c index 87446a233..095f38ba3 100644 --- a/agent/command.c +++ b/agent/command.c @@ -3113,6 +3113,57 @@ cmd_put_secret (assuan_context_t ctx, char *line) } + +static const char hlp_keytotpm[] = + "KEYTOTPM \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 \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; -- cgit v1.2.3