Skip to content

Commit

Permalink
KEYS: asym_tpm: Implement encryption operation [ver #2]
Browse files Browse the repository at this point in the history
This patch impelements the pkey_encrypt operation.  The public key
portion extracted from the TPM key blob is used.  The operation is
performed entirely in software using the crypto API.

Signed-off-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: James Morris <james.morris@microsoft.com>
  • Loading branch information
denkenz authored and James Morris committed Oct 26, 2018
1 parent dff5a61 commit ad4b1eb
Showing 1 changed file with 84 additions and 0 deletions.
84 changes: 84 additions & 0 deletions crypto/asymmetric_keys/asym_tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,96 @@ static int tpm_key_query(const struct kernel_pkey_params *params,
info->max_enc_size = len;
info->max_dec_size = tk->key_len / 8;

info->supported_ops = KEYCTL_SUPPORTS_ENCRYPT;

ret = 0;
error_free_tfm:
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}

/*
* Encryption operation is performed with the public key. Hence it is done
* in software
*/
static int tpm_key_encrypt(struct tpm_key *tk,
struct kernel_pkey_params *params,
const void *in, void *out)
{
char alg_name[CRYPTO_MAX_ALG_NAME];
struct crypto_akcipher *tfm;
struct akcipher_request *req;
struct crypto_wait cwait;
struct scatterlist in_sg, out_sg;
uint8_t der_pub_key[PUB_KEY_BUF_SIZE];
uint32_t der_pub_key_len;
int ret;

pr_devel("==>%s()\n", __func__);

ret = determine_akcipher(params->encoding, params->hash_algo, alg_name);
if (ret < 0)
return ret;

tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);

der_pub_key_len = derive_pub_key(tk->pub_key, tk->pub_key_len,
der_pub_key);

ret = crypto_akcipher_set_pub_key(tfm, der_pub_key, der_pub_key_len);
if (ret < 0)
goto error_free_tfm;

req = akcipher_request_alloc(tfm, GFP_KERNEL);
if (!req)
goto error_free_tfm;

sg_init_one(&in_sg, in, params->in_len);
sg_init_one(&out_sg, out, params->out_len);
akcipher_request_set_crypt(req, &in_sg, &out_sg, params->in_len,
params->out_len);
crypto_init_wait(&cwait);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
crypto_req_done, &cwait);

ret = crypto_akcipher_encrypt(req);
ret = crypto_wait_req(ret, &cwait);

if (ret == 0)
ret = req->dst_len;

akcipher_request_free(req);
error_free_tfm:
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}

/*
* Do encryption, decryption and signing ops.
*/
static int tpm_key_eds_op(struct kernel_pkey_params *params,
const void *in, void *out)
{
struct tpm_key *tk = params->key->payload.data[asym_crypto];
int ret = -EOPNOTSUPP;

/* Perform the encryption calculation. */
switch (params->op) {
case kernel_pkey_encrypt:
ret = tpm_key_encrypt(tk, params, in, out);
break;
default:
BUG();
}

return ret;
}

/*
* Parse enough information out of TPM_KEY structure:
* TPM_STRUCT_VER -> 4 bytes
Expand Down Expand Up @@ -329,6 +412,7 @@ struct asymmetric_key_subtype asym_tpm_subtype = {
.describe = asym_tpm_describe,
.destroy = asym_tpm_destroy,
.query = tpm_key_query,
.eds_op = tpm_key_eds_op,
};
EXPORT_SYMBOL_GPL(asym_tpm_subtype);

Expand Down

0 comments on commit ad4b1eb

Please sign in to comment.