diff options
author | Denis Kenzior <denkenz@gmail.com> | 2018-10-09 19:48:33 +0300 |
---|---|---|
committer | James Morris <james.morris@microsoft.com> | 2018-10-26 11:30:47 +0300 |
commit | ad4b1eb5fb3350c979a4f86eacfe7aac0595f335 (patch) | |
tree | 99e98280d4e0af390ab705947800db4f987e4d78 /crypto | |
parent | dff5a61a59614c110d06a5dc1466cdb762b6affd (diff) | |
download | linux-ad4b1eb5fb3350c979a4f86eacfe7aac0595f335.tar.xz |
KEYS: asym_tpm: Implement encryption operation [ver #2]
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>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/asymmetric_keys/asym_tpm.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/crypto/asymmetric_keys/asym_tpm.c b/crypto/asymmetric_keys/asym_tpm.c index 837472d107d5..8edca3c4c193 100644 --- a/crypto/asymmetric_keys/asym_tpm.c +++ b/crypto/asymmetric_keys/asym_tpm.c @@ -165,6 +165,8 @@ 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); @@ -173,6 +175,87 @@ error_free_tfm: } /* + * 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 * TPM_KEY_USAGE -> 2 bytes @@ -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); |