1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-11-08 21:18:51 +01:00
gnupg/agent/divert-tpm2.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

148 lines
3.7 KiB
C
Raw Normal View History

agent: Add new shadow key type and functions to call tpm2daemon * agent/call-tpm2d.c: New. * divert-tpm2.c: New. * agent/Makefile.am: Add new files. * agent/agent.h (DAEMON_TPM2D): New. Add stub fucntions. * agent/call-daemon.c (GNUPG_MODULE_NAME_TPM2DAEMON): New. * agent/command.c (do_one_keyinfo): Handle tpmv2. * agent/gpg-agent.c (oTpm2daemonProgram): New. (opts): New option --tpm2daemon-program. (parse_rereadable_options): Handle option. * agent/pkdecrypt.c (agent_pkdecrypt): Divert to tpm2d. (agent_pksign_do): Ditto. --- A new shadow key type: "tpm2-v1" is introduced signalling that the shadowed key is handled by the tpm2daemon. A function to identify this type is introduced and diversions to the tpm2daemon functions are conditioned on this function for pkign and pkdecrypt where the same diversions to scd are currently done. The (info) field of the shadowed key stores the actual TPM key. The TPM key is encrypted so only the physical TPM it was created on can read it (so no special protection is required for the info filed), but if the (info) field becomes corrupt or damaged, the key will be lost (unlike the token case, where the key is actually moved inside the token). Note, this commit adds handling for existing TPM format shadow keys, but there is still no way to create them. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Additional changes: * Add ChangeLog entries. * Some minor indentation fixes. * agent/Makefile.am (gpg_agent_SOURCES): Change to make distcheck work. * agent/agent.h [!HAVE_LIBTSS]: Do not return -EINVAL but an gpg_error_t. Mark args as unused. * agent/protect.c (agent_is_tpm2_key): Free BUF. Signed-off-by: Werner Koch <wk@gnupg.org>
2021-03-09 22:50:29 +01:00
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#include "agent.h"
#include "../common/i18n.h"
#include "../common/sexp-parse.h"
int
divert_tpm2_pksign (ctrl_t ctrl, const char *desc_text,
const unsigned char *digest, size_t digestlen, int algo,
const unsigned char *shadow_info, unsigned char **r_sig,
size_t *r_siglen)
{
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 <James.Bottomley@HansenPartnership.com> Very minor cosmetic changes. Signed-off-by: Werner Koch <wk@gnupg.org>
2021-03-09 22:50:30 +01:00
(void)desc_text;
(void)algo;
agent: Add new shadow key type and functions to call tpm2daemon * agent/call-tpm2d.c: New. * divert-tpm2.c: New. * agent/Makefile.am: Add new files. * agent/agent.h (DAEMON_TPM2D): New. Add stub fucntions. * agent/call-daemon.c (GNUPG_MODULE_NAME_TPM2DAEMON): New. * agent/command.c (do_one_keyinfo): Handle tpmv2. * agent/gpg-agent.c (oTpm2daemonProgram): New. (opts): New option --tpm2daemon-program. (parse_rereadable_options): Handle option. * agent/pkdecrypt.c (agent_pkdecrypt): Divert to tpm2d. (agent_pksign_do): Ditto. --- A new shadow key type: "tpm2-v1" is introduced signalling that the shadowed key is handled by the tpm2daemon. A function to identify this type is introduced and diversions to the tpm2daemon functions are conditioned on this function for pkign and pkdecrypt where the same diversions to scd are currently done. The (info) field of the shadowed key stores the actual TPM key. The TPM key is encrypted so only the physical TPM it was created on can read it (so no special protection is required for the info filed), but if the (info) field becomes corrupt or damaged, the key will be lost (unlike the token case, where the key is actually moved inside the token). Note, this commit adds handling for existing TPM format shadow keys, but there is still no way to create them. Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Additional changes: * Add ChangeLog entries. * Some minor indentation fixes. * agent/Makefile.am (gpg_agent_SOURCES): Change to make distcheck work. * agent/agent.h [!HAVE_LIBTSS]: Do not return -EINVAL but an gpg_error_t. Mark args as unused. * agent/protect.c (agent_is_tpm2_key): Free BUF. Signed-off-by: Werner Koch <wk@gnupg.org>
2021-03-09 22:50:29 +01:00
return agent_tpm2d_pksign(ctrl, digest, digestlen,
shadow_info, r_sig, r_siglen);
}
static gpg_error_t
agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
unsigned char *shadow_info)
{
gpg_error_t err;
unsigned char *shdkey;
unsigned char *pkbuf;
size_t len;
gcry_sexp_t s_pkey;
err = agent_public_key_from_file (ctrl, grip, &s_pkey);
len = gcry_sexp_sprint(s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
pkbuf = xtrymalloc (len);
gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, pkbuf, len);
gcry_sexp_release (s_pkey);
err = agent_shadow_key_type (pkbuf, shadow_info, "tpm2-v1", &shdkey);
xfree (pkbuf);
if (err)
{
log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
return err;
}
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
err = agent_write_private_key (grip, shdkey, len, 1 /*force*/,
NULL, NULL, 0);
xfree (shdkey);
if (err)
log_error ("error writing key: %s\n", gpg_strerror (err));
return err;
}
int
divert_tpm2_writekey (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t s_skey)
{
int ret;
/* shadow_info is always shielded so no special handling required */
unsigned char *shadow_info;
ret = agent_tpm2d_writekey(ctrl, &shadow_info, s_skey);
if (!ret) {
ret = agent_write_tpm2_shadow_key (ctrl, grip, shadow_info);
xfree (shadow_info);
}
return ret;
}
int
divert_tpm2_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *cipher,
const unsigned char *shadow_info,
char **r_buf, size_t *r_len, int *r_padding)
{
const unsigned char *s;
size_t n;
*r_padding = -1;
(void)desc_text;
s = cipher;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "enc-val"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "rsa"))
{
*r_padding = 0;
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (!smatch (&s, n, "a"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
n = snext (&s);
}
else if (smatch (&s, n, "ecdh"))
{
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
s++;
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "s"))
{
n = snext (&s);
s += n;
if (*s++ != ')')
return gpg_error (GPG_ERR_INV_SEXP);
if (*s++ != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
n = snext (&s);
if (!n)
return gpg_error (GPG_ERR_INV_SEXP);
}
if (!smatch (&s, n, "e"))
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
n = snext (&s);
}
else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
return agent_tpm2d_pkdecrypt (ctrl, s, n, shadow_info, r_buf, r_len);
}