summaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2018-10-09 19:48:33 +0300
committerJames Morris <james.morris@microsoft.com>2018-10-26 11:30:47 +0300
commitad4b1eb5fb3350c979a4f86eacfe7aac0595f335 (patch)
tree99e98280d4e0af390ab705947800db4f987e4d78 /crypto
parentdff5a61a59614c110d06a5dc1466cdb762b6affd (diff)
downloadlinux-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.c84
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);