Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move non-TSS-specific code to gnutls_tpm2.c
In preparation for potentially implementing a version using ibmtss.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
dwmw2 committed Oct 11, 2018
1 parent 12aefa1 commit ff4fb5c
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 124 deletions.
7 changes: 7 additions & 0 deletions gnutls.h
Expand Up @@ -34,6 +34,13 @@ void release_tpm2_ctx(struct openconnect_info *info);
int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig,
unsigned int parent, int emptyauth, gnutls_datum_t *privdata, gnutls_datum_t *pubdata);

int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
const gnutls_datum_t *data, gnutls_datum_t *sig);
int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
const gnutls_datum_t *data, gnutls_datum_t *sig);

/* GnuTLS 3.6.0+ provides this. We have our own for older GnuTLS. There is
* also _gnutls_encode_ber_rs_raw() in some older versions, but there were
* zero-padding bugs in that, and some of the... less diligently maintained
Expand Down
109 changes: 109 additions & 0 deletions gnutls_tpm2.c
Expand Up @@ -45,6 +45,90 @@ const asn1_static_node tpmkey_asn1_tab[] = {
{ NULL, 0, NULL }
};

#if GNUTLS_VERSION_NUMBER < 0x030600
static int tpm2_rsa_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
return tpm2_rsa_sign_hash_fn(key, GNUTLS_SIGN_UNKNOWN, _vpninfo, 0, data, sig);
}


static int tpm2_ec_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
struct openconnect_info *vpninfo = _vpninfo;
gnutls_sign_algorithm_t algo;

switch (data->size) {
case 20: algo = GNUTLS_SIGN_ECDSA_SHA1; break;
case 32: algo = GNUTLS_SIGN_ECDSA_SHA256; break;
case 48: algo = GNUTLS_SIGN_ECDSA_SHA384; break;
case 64: algo = GNUTLS_SIGN_ECDSA_SHA512; break;
default:
vpn_progress(vpninfo, PRG_ERR,
_("Unknown TPM2 EC digest size %d\n"),
data->size);
return GNUTLS_E_PK_SIGN_FAILED;
}

return tpm2_ec_sign_hash_fn(key, algo, vpninfo, 0, data, sig);
}
#endif

#if GNUTLS_VERSION_NUMBER >= 0x030600
static int rsa_key_info(gnutls_privkey_t key, unsigned int flags, void *_vpninfo)
{
if (flags & GNUTLS_PRIVKEY_INFO_PK_ALGO)
return GNUTLS_PK_RSA;

if (flags & GNUTLS_PRIVKEY_INFO_HAVE_SIGN_ALGO) {
gnutls_sign_algorithm_t algo = GNUTLS_FLAGS_TO_SIGN_ALGO(flags);
switch (algo) {
case GNUTLS_SIGN_RSA_RAW:
case GNUTLS_SIGN_RSA_SHA1:
case GNUTLS_SIGN_RSA_SHA256:
case GNUTLS_SIGN_RSA_SHA384:
case GNUTLS_SIGN_RSA_SHA512:
return 1;

default:
return 0;
}
}

if (flags & GNUTLS_PRIVKEY_INFO_SIGN_ALGO)
return GNUTLS_SIGN_RSA_RAW;

return -1;
}
#endif

#if GNUTLS_VERSION_NUMBER >= 0x030400
static int ec_key_info(gnutls_privkey_t key, unsigned int flags, void *_vpninfo)
{
if (flags & GNUTLS_PRIVKEY_INFO_PK_ALGO)
return GNUTLS_PK_EC;

#ifdef GNUTLS_PRIVKEY_INFO_HAVE_SIGN_ALGO
if (flags & GNUTLS_PRIVKEY_INFO_HAVE_SIGN_ALGO) {
gnutls_sign_algorithm_t algo = GNUTLS_FLAGS_TO_SIGN_ALGO(flags);
switch (algo) {
case GNUTLS_SIGN_ECDSA_SHA1:
case GNUTLS_SIGN_ECDSA_SHA256:
return 1;

default:
return 0;
}
}
#endif

if (flags & GNUTLS_PRIVKEY_INFO_SIGN_ALGO)
return GNUTLS_SIGN_ECDSA_SHA256;

return -1;
}
#endif

static int decode_data(ASN1_TYPE n, gnutls_datum_t *r)
{
Expand Down Expand Up @@ -159,6 +243,31 @@ int load_tpm2_key(struct openconnect_info *vpninfo, gnutls_datum_t *fdata,
/* Now we've extracted what we need from the ASN.1, invoke the
* actual TPM2 code (whichever implementation we end up with */
ret = install_tpm2_key(vpninfo, pkey, pkey_sig, parent, emptyauth, &privdata, &pubdata);
if (ret < 0)
goto out_tpmkey;

gnutls_privkey_init(pkey);

switch(ret) {
case GNUTLS_PK_RSA:
#if GNUTLS_VERSION_NUMBER >= 0x030600
gnutls_privkey_import_ext4(*pkey, vpninfo, NULL, tpm2_rsa_sign_hash_fn, NULL, NULL, rsa_key_info, 0);
#else
gnutls_privkey_import_ext(*pkey, GNUTLS_PK_RSA, vpninfo, tpm2_rsa_sign_fn, NULL, 0);
#endif
break;

case GNUTLS_PK_ECDSA:
#if GNUTLS_VERSION_NUMBER >= 0x030600
gnutls_privkey_import_ext4(*pkey, vpninfo, NULL, tpm2_ec_sign_hash_fn, NULL, NULL, ec_key_info, 0);
#elif GNUTLS_VERSION_NUMBER >= 0x030400
gnutls_privkey_import_ext3(*pkey, vpninfo, tpm2_ec_sign_fn, NULL, NULL, ec_key_info, 0);
#else
gnutls_privkey_import_ext(*pkey, GNUTLS_PK_EC, vpninfo, tpm2_ec_sign_fn, NULL, 0);
#endif
break;
}
ret = 0;

out_tpmkey:
asn1_delete_structure(&tpmkey);
Expand Down
139 changes: 15 additions & 124 deletions gnutls_tpm2_esys.c
Expand Up @@ -312,10 +312,9 @@ static int auth_tpm2_key(struct openconnect_info *vpninfo, ESYS_CONTEXT *ctx, ES

#define PKCS1_PAD_OVERHEAD 11

/* Signing function for TPM privkeys, set with gnutls_privkey_import_ext() */
static int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
const gnutls_datum_t *data, gnutls_datum_t *sig)
int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
struct openconnect_info *vpninfo = _vpninfo;
int ret = GNUTLS_E_PK_SIGN_FAILED;
Expand Down Expand Up @@ -389,10 +388,9 @@ static int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t a
return ret;
}

/* Signing function for TPM privkeys, set with gnutls_privkey_import_ext() */
static int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
const gnutls_datum_t *data, gnutls_datum_t *sig)
int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
void *_vpninfo, unsigned int flags,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
struct openconnect_info *vpninfo = _vpninfo;
int ret = GNUTLS_E_PK_SIGN_FAILED;
Expand Down Expand Up @@ -467,91 +465,6 @@ static int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t al
return ret;
}

#if GNUTLS_VERSION_NUMBER < 0x030600
static int tpm2_rsa_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
return tpm2_rsa_sign_hash_fn(key, GNUTLS_SIGN_UNKNOWN, _vpninfo, 0, data, sig);
}


static int tpm2_ec_sign_fn(gnutls_privkey_t key, void *_vpninfo,
const gnutls_datum_t *data, gnutls_datum_t *sig)
{
struct openconnect_info *vpninfo = _vpninfo;
gnutls_sign_algorithm_t algo;

switch (data->size) {
case 20: algo = GNUTLS_SIGN_ECDSA_SHA1; break;
case 32: algo = GNUTLS_SIGN_ECDSA_SHA256; break;
case 48: algo = GNUTLS_SIGN_ECDSA_SHA384; break;
case 64: algo = GNUTLS_SIGN_ECDSA_SHA512; break;
default:
vpn_progress(vpninfo, PRG_ERR,
_("Unknown TPM2 EC digest size %d\n"),
data->size);
return GNUTLS_E_PK_SIGN_FAILED;
}

return tpm2_ec_sign_hash_fn(key, algo, vpninfo, 0, data, sig);
}
#endif

#if GNUTLS_VERSION_NUMBER >= 0x030600
static int rsa_key_info(gnutls_privkey_t key, unsigned int flags, void *_vpninfo)
{
if (flags & GNUTLS_PRIVKEY_INFO_PK_ALGO)
return GNUTLS_PK_RSA;

if (flags & GNUTLS_PRIVKEY_INFO_HAVE_SIGN_ALGO) {
gnutls_sign_algorithm_t algo = GNUTLS_FLAGS_TO_SIGN_ALGO(flags);
switch (algo) {
case GNUTLS_SIGN_RSA_RAW:
case GNUTLS_SIGN_RSA_SHA1:
case GNUTLS_SIGN_RSA_SHA256:
case GNUTLS_SIGN_RSA_SHA384:
case GNUTLS_SIGN_RSA_SHA512:
return 1;

default:
return 0;
}
}

if (flags & GNUTLS_PRIVKEY_INFO_SIGN_ALGO)
return GNUTLS_SIGN_RSA_RAW;

return -1;
}
#endif

#if GNUTLS_VERSION_NUMBER >= 0x030400
static int ec_key_info(gnutls_privkey_t key, unsigned int flags, void *_vpninfo)
{
if (flags & GNUTLS_PRIVKEY_INFO_PK_ALGO)
return GNUTLS_PK_EC;

#ifdef GNUTLS_PRIVKEY_INFO_HAVE_SIGN_ALGO
if (flags & GNUTLS_PRIVKEY_INFO_HAVE_SIGN_ALGO) {
gnutls_sign_algorithm_t algo = GNUTLS_FLAGS_TO_SIGN_ALGO(flags);
switch (algo) {
case GNUTLS_SIGN_ECDSA_SHA1:
case GNUTLS_SIGN_ECDSA_SHA256:
return 1;

default:
return 0;
}
}
#endif

if (flags & GNUTLS_PRIVKEY_INFO_SIGN_ALGO)
return GNUTLS_SIGN_ECDSA_SHA256;

return -1;
}
#endif

int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig,
unsigned int parent, int emptyauth, gnutls_datum_t *privdata, gnutls_datum_t *pubdata)
{
Expand All @@ -574,9 +487,7 @@ int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, g
vpn_progress(vpninfo, PRG_ERR,
_("Failed to import TPM2 private key data: 0x%x\n"),
r);
err_out:
release_tpm2_ctx(vpninfo);
return -EINVAL;
goto err_out;
}

r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(pubdata->data, pubdata->size, NULL,
Expand All @@ -590,37 +501,17 @@ int install_tpm2_key(struct openconnect_info *vpninfo, gnutls_privkey_t *pkey, g

vpninfo->tpm2->need_userauth = !emptyauth;

gnutls_privkey_init(pkey);

switch(vpninfo->tpm2->pub.publicArea.type) {
case TPM2_ALG_RSA:
#if GNUTLS_VERSION_NUMBER >= 0x030600
gnutls_privkey_import_ext4(*pkey, vpninfo, NULL, tpm2_rsa_sign_hash_fn, NULL, NULL, rsa_key_info, 0);
#else
gnutls_privkey_import_ext(*pkey, GNUTLS_PK_RSA, vpninfo, tpm2_rsa_sign_fn, NULL, 0);
#endif
break;

case TPM2_ALG_ECC:
#if GNUTLS_VERSION_NUMBER >= 0x030600
gnutls_privkey_import_ext4(*pkey, vpninfo, NULL, tpm2_ec_sign_hash_fn, NULL, NULL, ec_key_info, 0);
#elif GNUTLS_VERSION_NUMBER >= 0x030400
gnutls_privkey_import_ext3(*pkey, vpninfo, tpm2_ec_sign_fn, NULL, NULL, ec_key_info, 0);
#else
gnutls_privkey_import_ext(*pkey, GNUTLS_PK_EC, vpninfo, tpm2_ec_sign_fn, NULL, 0);
#endif
break;

default:
vpn_progress(vpninfo, PRG_ERR,
_("Unsupported TPM2 key type %d\n"),
vpninfo->tpm2->pub.publicArea.type);
gnutls_privkey_deinit(*pkey);
*pkey = NULL;
goto err_out;
case TPM2_ALG_RSA: return GNUTLS_PK_RSA;
case TPM2_ALG_ECC: return GNUTLS_PK_ECDSA;
}

return 0;
vpn_progress(vpninfo, PRG_ERR,
_("Unsupported TPM2 key type %d\n"),
vpninfo->tpm2->pub.publicArea.type);
err_out:
release_tpm2_ctx(vpninfo);
return -EINVAL;
}


Expand Down

0 comments on commit ff4fb5c

Please sign in to comment.