From: David Howells <dhowells@redhat.com>
To: mathew.j.martineau@linux.intel.com, tadeusz.struk@intel.com
Cc: linux-kernel@vger.kernel.org, dhowells@redhat.com,
linux-security-module@vger.kernel.org, keyrings@vger.kernel.org,
linux-crypto@vger.kernel.org, dwmw2@infradead.org
Subject: [RFC PATCH 7/8] KEYS: Implement encrypt, decrypt and sign for software asymmetric key [ver 3]
Date: Wed, 11 May 2016 15:22:45 +0100 [thread overview]
Message-ID: <20160511142245.4743.77379.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <20160511142152.4743.14414.stgit@warthog.procyon.org.uk>
Implement the encrypt, decrypt and sign operations for the software
asymmetric key subtype. This mostly involves offloading the call to the
crypto layer.
Note that the decrypt and sign operations require a private key to be
supplied. Encrypt (and also verify) will work with either a public or a
private key. A public key can be supplied with an X.509 certificate and a
private key can be supplied using a PKCS#8 blob:
# j=`openssl pkcs8 -in ~/pkcs7/firmwarekey2.priv -topk8 -nocrypt -outform DER | keyctl padd asymmetric foo @s`
# keyctl pkey_query $j - enc=pkcs1
key_size=4096
max_data_size=512
max_sig_size=512
max_enc_size=512
max_dec_size=512
encrypt=y
decrypt=y
sign=y
verify=y
# keyctl pkey_encrypt $j 0 data enc=pkcs1 >/tmp/enc
# keyctl pkey_decrypt $j 0 /tmp/enc enc=pkcs1 >/tmp/dec
# cmp data /tmp/dec
# keyctl pkey_sign $j 0 data enc=pkcs1 hash=sha1 >/tmp/sig
# keyctl pkey_verify $j 0 data /tmp/sig enc=pkcs1 hash=sha1
#
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/public_key.c | 89 ++++++++++++++++++++++++++++++++++-
1 file changed, 86 insertions(+), 3 deletions(-)
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 92997d4e8173..2bdb673cf074 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -128,7 +128,11 @@ static int software_key_query(const struct kernel_pkey_params *params,
info->max_sig_size = len;
info->max_enc_size = len;
info->max_dec_size = len;
- info->supported_ops = KEYCTL_SUPPORTS_VERIFY;
+ info->supported_ops = (KEYCTL_SUPPORTS_ENCRYPT |
+ KEYCTL_SUPPORTS_VERIFY);
+ if (pkey->key_is_private)
+ info->supported_ops |= (KEYCTL_SUPPORTS_DECRYPT |
+ KEYCTL_SUPPORTS_SIGN);
ret = 0;
error_free_tfm:
@@ -142,7 +146,7 @@ struct public_key_completion {
int err;
};
-static void public_key_verify_done(struct crypto_async_request *req, int err)
+static void public_key_crypto_done(struct crypto_async_request *req, int err)
{
struct public_key_completion *compl = req->data;
@@ -154,6 +158,84 @@ static void public_key_verify_done(struct crypto_async_request *req, int err)
}
/*
+ * Do encryption, decryption and signing ops.
+ */
+static int software_key_eds_op(struct kernel_pkey_params *params,
+ const void *in, void *out)
+{
+ struct public_key_completion compl;
+ const struct public_key *pkey = params->key->payload.data[asym_crypto];
+ struct akcipher_request *req;
+ struct crypto_akcipher *tfm;
+ struct scatterlist in_sg, out_sg;
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ ret = software_key_determine_akcipher(params->encoding,
+ params->hash_algo,
+ pkey, alg_name);
+ if (ret < 0)
+ return ret;
+
+ tfm = crypto_alloc_akcipher(alg_name, 0, 0);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ req = akcipher_request_alloc(tfm, GFP_KERNEL);
+ if (!req)
+ goto error_free_tfm;
+
+ if (pkey->key_is_private)
+ ret = crypto_akcipher_set_priv_key(tfm,
+ pkey->key, pkey->keylen);
+ else
+ ret = crypto_akcipher_set_pub_key(tfm,
+ pkey->key, pkey->keylen);
+ if (ret)
+ goto error_free_req;
+
+ 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);
+ init_completion(&compl.completion);
+ akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP,
+ public_key_crypto_done, &compl);
+
+ /* Perform the encryption calculation. */
+ switch (params->op) {
+ case kernel_pkey_encrypt:
+ ret = crypto_akcipher_encrypt(req);
+ break;
+ case kernel_pkey_decrypt:
+ ret = crypto_akcipher_decrypt(req);
+ break;
+ case kernel_pkey_sign:
+ ret = crypto_akcipher_sign(req);
+ break;
+ default:
+ BUG();
+ }
+ if (ret == -EINPROGRESS) {
+ wait_for_completion(&compl.completion);
+ ret = compl.err;
+ }
+
+ if (ret == 0)
+ ret = req->dst_len;
+
+error_free_req:
+ akcipher_request_free(req);
+error_free_tfm:
+ crypto_free_akcipher(tfm);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+/*
* Verify a signature using a public key.
*/
int public_key_verify_signature(const struct public_key *pkey,
@@ -210,7 +292,7 @@ int public_key_verify_signature(const struct public_key *pkey,
init_completion(&compl.completion);
akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
CRYPTO_TFM_REQ_MAY_SLEEP,
- public_key_verify_done, &compl);
+ public_key_crypto_done, &compl);
/* Perform the verification calculation. This doesn't actually do the
* verification, but rather calculates the hash expected by the
@@ -258,6 +340,7 @@ struct asymmetric_key_subtype public_key_subtype = {
.describe = public_key_describe,
.destroy = public_key_destroy,
.query = software_key_query,
+ .eds_op = software_key_eds_op,
.verify_signature = public_key_verify_signature_2,
};
EXPORT_SYMBOL_GPL(public_key_subtype);
next prev parent reply other threads:[~2016-05-11 14:22 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-05-11 14:21 [RFC PATCH 0/8] KEYS: keyctl operations for asymmetric keys [ver 3] David Howells
2016-05-11 14:22 ` [RFC PATCH 1/8] KEYS: Provide key type operations for asymmetric key ops " David Howells
2016-05-11 14:22 ` [RFC PATCH 2/8] KEYS: Provide keyctls to drive the new key type ops for asymmetric keys " David Howells
2016-05-11 22:17 ` Mat Martineau
2016-05-12 10:16 ` David Howells
2016-05-12 11:04 ` David Woodhouse
2016-05-11 14:22 ` [RFC PATCH 3/8] KEYS: Provide missing asymmetric key subops for new key type ops " David Howells
2016-05-11 14:22 ` [RFC PATCH 4/8] KEYS: Make the X.509 and PKCS7 parsers supply the sig encoding type " David Howells
2016-05-11 14:22 ` [RFC PATCH 5/8] KEYS: Provide software public key query function " David Howells
2016-05-11 23:50 ` Mat Martineau
2016-05-12 0:17 ` Tadeusz Struk
2016-05-12 10:19 ` David Howells
2016-05-12 17:01 ` Mat Martineau
2016-05-11 14:22 ` [RFC PATCH 6/8] KEYS: Allow the public_key struct to hold a private key " David Howells
2016-05-11 14:22 ` David Howells [this message]
2016-05-11 14:22 ` [RFC PATCH 8/8] KEYS: Implement PKCS#8 RSA Private Key parser " David Howells
2016-05-11 19:11 ` David Woodhouse
2016-05-12 0:09 ` Mat Martineau
2016-05-12 10:20 ` David Howells
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160511142245.4743.77379.stgit@warthog.procyon.org.uk \
--to=dhowells@redhat.com \
--cc=dwmw2@infradead.org \
--cc=keyrings@vger.kernel.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=mathew.j.martineau@linux.intel.com \
--cc=tadeusz.struk@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox