1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00
gnupg/agent/divert-tpm2.c
Werner Koch fb0470a9f5
agent: Minor cleanup of the TPM patches.
* configure.ac (AC_CHECK_HEADERS): Add tss2/tss.h.
* agent/divert-tpm2.c: Print an error if that file is not available.
* agent/Makefile.am (gpg_agent_SOURCES): Add tpm.h
* agent/command.c (do_one_keyinfo): Replace xstrdup by xtrystrdup.
* agent/protect.c (agent_get_shadow_info_type): Check error of
xtrystrdup.

Signed-off-by: Werner Koch <wk@gnupg.org>
2018-03-09 10:36:14 +01:00

225 lines
5.5 KiB
C

#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>
/* FIXME: Until we have a proper checking in configure we give a hint
* on what to do */
#ifndef HAVE_TSS2_TSS_H
# error Please install the libtss2 dev package first
#endif
#include "agent.h"
#include "../common/i18n.h"
#include "../common/sexp-parse.h"
#include "tpm2.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)
{
TSS_CONTEXT *tssc;
TPM_HANDLE key;
TPMI_ALG_PUBLIC type;
int ret;
ret = tpm2_start(&tssc);
if (ret)
return ret;
ret = tpm2_load_key(tssc, shadow_info, &key, &type);
if (ret)
goto out;
ret = tpm2_sign(ctrl, tssc, key, type, digest, digestlen, r_sig, r_siglen);
tpm2_flush_handle(tssc, key);
out:
tpm2_end(tssc);
return ret;
}
static unsigned char *
make_tpm2_shadow_info (uint32_t parent, const char *pub, int pub_len,
const char *priv, int priv_len)
{
gcry_sexp_t s_exp;
size_t len;
char *info;
gcry_sexp_build(&s_exp, NULL, "(%u%b%b)", parent, pub_len, pub, priv_len, priv);
len = gcry_sexp_sprint(s_exp, GCRYSEXP_FMT_CANON, NULL, 0);
info = xtrymalloc(len);
gcry_sexp_sprint(s_exp, GCRYSEXP_FMT_CANON, info, len);
gcry_sexp_release(s_exp);
return (unsigned char *)info;
}
static gpg_error_t
agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
int parent, char *pub, int pub_len,
char *priv, int priv_len)
{
gpg_error_t err;
unsigned char *shadow_info;
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);
shadow_info = make_tpm2_shadow_info (parent, pub, pub_len, priv, priv_len);
if (!shadow_info) {
xfree (pkbuf);
return gpg_error_from_syserror ();
}
err = agent_shadow_key_type (pkbuf, shadow_info, "tpm2-v1", &shdkey);
xfree (shadow_info);
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*/);
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)
{
TSS_CONTEXT *tssc;
int ret, pub_len, priv_len;
/* priv is always shielded so no special handling required */
char pub[sizeof(TPM2B_PUBLIC)], priv[sizeof(TPM2B_PRIVATE)];
ret = tpm2_start(&tssc);
if (ret)
return ret;
ret = tpm2_import_key (ctrl, tssc, pub, &pub_len, priv, &priv_len, s_skey);
if (ret)
goto out;
ret = agent_write_tpm2_shadow_key (ctrl, grip, TPM2_PARENT, pub, pub_len,
priv, priv_len);
out:
tpm2_end(tssc);
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)
{
TSS_CONTEXT *tssc;
TPM_HANDLE key;
TPMI_ALG_PUBLIC type;
int ret;
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);
/* know we have RSA to decrypt at s,n */
ret = tpm2_start(&tssc);
if (ret)
return ret;
ret = tpm2_load_key(tssc, shadow_info, &key, &type);
if (ret)
goto out;
if (type == TPM_ALG_RSA)
ret = tpm2_rsa_decrypt(ctrl, tssc, key, s, n, r_buf, r_len);
else if (type == TPM_ALG_ECC)
ret = tpm2_ecc_decrypt(ctrl, tssc, key, s, n, r_buf, r_len);
tpm2_flush_handle(tssc, key);
out:
tpm2_end(tssc);
return ret;
}