* [PATCH v8 0/6] crypto: algif - add akcipher
From: Tadeusz Struk @ 2016-06-23 22:55 UTC (permalink / raw)
To: dhowells
Cc: herbert, tadeusz.struk, smueller, linux-api, marcel,
mathew.j.martineau, linux-kernel, keyrings, linux-crypto, dwmw2,
davem
First four patches are a resend algif_akcipher from
Stephan Mueller, with minor changes after rebase on top of 4.7-rc1.
The next three patches add support for keys stored in system
keyring subsystem.
First patch adds algif_akcipher nokey hadlers.
Second patch adds generic sign, verify, encrypt, decrypt accessors
functions to the asymmetric key type. These will be defined by
asymmetric subtypes, similarly to how public_key currently defines
the verify_signature function.
Third patch adds support for ALG_SET_KEY_ID and ALG_SET_PUBKEY_ID
commands to AF_ALG and setkeyid operation to the af_alg_type struct.
If the keyid is used then the afalg layer acquires the key for the
keyring subsystem and uses the new asymmetric accessor functions
instead of akcipher api. The asymmetric subtypes can use akcipher
api internally.
Patches are generate against:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-next
v8 hanges:
- copy the result to user for verify after the signature_verify
operation. Before only the return code was checked, but not the
actual data. Reported by Mat Martineau
- remove the constrain on the output buffer size as requested by
Mat Martineau
- ifx uninitialize variable issue, reported by Mat Martineau
v7 changes:
- update to reflect changes in kernel_pkey_params struct
v6 changes:
- rabased on top of
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-asym-keyctl
v5 changes:
- drop public key changes and use new version provided by David
v4 changes:
- don't use internal public_key struct in af_alg.
- add generic accessor functions to asymmetric key type, which take
the generic struct key type and resolve the specific subtype internally
v3 changes:
- include Stephan's patches (rebased on 4.6-rc1)
- add algif_akcipher nokey hadlers
- add public_key info struct to public_key and helper query functions
- add a check if a key is a software accessible key on af_alg, and
return -ENOKEY if it isn't
v2 changes:
- pass the original skcipher request in ablkcipher.base.data instead of
casting it back from the ablkcipher request.
- rename _req to base_req
- dropped 3/3
---
Stephan Mueller (4):
crypto: AF_ALG -- add sign/verify API
crypto: AF_ALG -- add setpubkey setsockopt call
crypto: AF_ALG -- add asymmetric cipher interface
crypto: algif_akcipher - enable compilation
Tadeusz Struk (2):
crypto: algif_akcipher - add ops_nokey
crypto: AF_ALG - add support for key_id
crypto/Kconfig | 9
crypto/Makefile | 1
crypto/af_alg.c | 28 +
crypto/algif_akcipher.c | 878 +++++++++++++++++++++++++++++++++++++++++++
include/crypto/if_alg.h | 2
include/uapi/linux/if_alg.h | 5
6 files changed, 918 insertions(+), 5 deletions(-)
create mode 100644 crypto/algif_akcipher.c
--
TS
^ permalink raw reply
* Re: Doing crypto in small stack buffers (bluetooth vs vmalloc-stack crash, etc)
From: Andy Lutomirski @ 2016-06-23 22:11 UTC (permalink / raw)
To: Herbert Xu
Cc: Andy Lutomirski, linux-bluetooth, Johan Hedberg, Gustavo Padovan,
Marcel Holtmann, linux-crypto, David S. Miller,
linux-kernel@vger.kernel.org, Linus Torvalds, Network Development
In-Reply-To: <20160623064137.GA8958@gondor.apana.org.au>
On Wed, Jun 22, 2016 at 11:41 PM, Herbert Xu
<herbert@gondor.apana.org.au> wrote:
> On Thu, Jun 23, 2016 at 11:48:25AM +0800, Herbert Xu wrote:
>>
>> No we never had such an API in the kernel. However, I see that
>> rxkad does some pretty silly things and we should be able to avoid
>> using the stack in pretty much all cases. Let me try to come up with
>> something.
>
> Here it is:
>
> ---8<---
> Subject: rxrpc: Avoid using stack memory in SG lists in rxkad
Looks reasonable to me. Unless anyone tells me otherwise, my plan is
to queue it in my virtually-mapped stack series and to ask Ingo to
apply it via -tip.
If it went in via the networking tree, that would work as well, but it
would introduce a bisectability problem.
Thanks!
--Andy
^ permalink raw reply
* [cryptodev:master 79/79] (.text+0x330de0): multiple definition of `ecdh_shared_secret'
From: kbuild test robot @ 2016-06-23 19:47 UTC (permalink / raw)
Cc: kbuild-all, linux-crypto, Herbert Xu, Salvatore Benedetto
[-- Attachment #1: Type: text/plain, Size: 860 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
head: 3c4b23901a0c766879dff680cd6bdab47bcdbbd2
commit: 3c4b23901a0c766879dff680cd6bdab47bcdbbd2 [79/79] crypto: ecdh - Add ECDH software support
config: i386-allyesconfig (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
git checkout 3c4b23901a0c766879dff680cd6bdab47bcdbbd2
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
net/built-in.o: In function `ecdh_shared_secret':
>> (.text+0x330de0): multiple definition of `ecdh_shared_secret'
crypto/built-in.o:(.text+0xb1b0): first defined here
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 54419 bytes --]
^ permalink raw reply
* Re: [PATCH 5/8] KEYS: Provide software public key query function [ver #2]
From: Mat Martineau @ 2016-06-23 15:46 UTC (permalink / raw)
To: David Howells
Cc: mathew.j.martineau, dwmw2, tadeusz.struk, linux-security-module,
keyrings, linux-kernel, linux-crypto
In-Reply-To: <146668969255.2977.2158699976750892093.stgit@warthog.procyon.org.uk>
David,
On Thu, 23 Jun 2016, David Howells wrote:
> Provide a query function for the software public key implementation. This
> permits information about such a key to be obtained using
> query_asymmetric_key() or KEYCTL_PKEY_QUERY.
>
> Signed-off-by: David Howells <dhowells@redhat.com>
> ---
>
> crypto/asymmetric_keys/public_key.c | 96 ++++++++++++++++++++++++++++++-----
> 1 file changed, 82 insertions(+), 14 deletions(-)
>
> diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
> index fd76b5fc3b3a..a48a47a1dff0 100644
> --- a/crypto/asymmetric_keys/public_key.c
> +++ b/crypto/asymmetric_keys/public_key.c
> @@ -57,6 +57,81 @@ static void public_key_destroy(void *payload0, void *payload3)
> public_key_signature_free(payload3);
> }
>
> +/*
> + * Determine the crypto algorithm name.
> + */
> +static
> +int software_key_determine_akcipher(const char *encoding,
> + const char *hash_algo,
> + const struct public_key *pkey,
> + char alg_name[CRYPTO_MAX_ALG_NAME])
> +{
> + int n;
> +
> + if (strcmp(encoding, "pkcs1") == 0) {
> + /* The data wangled by the RSA algorithm is typically padded
> + * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
> + * sec 8.2].
> + */
> + if (!hash_algo)
> + n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
> + "pkcs1pad(%s)",
> + pkey->pkey_algo);
Did you see Herbert's patch that strips out non-hash pkcs1pad capabilities
(and the ensuing discussion)?
http://www.spinics.net/lists/linux-crypto/index.html#20432
I'm making use of pkcs1pad(rsa) with a TLS implementation, so it's good to
see it supported here.
> + else
> + n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
> + "pkcs1pad(%s,%s)",
> + pkey->pkey_algo, hash_algo);
> + return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
> + }
> +
> + if (strcmp(encoding, "raw") == 0) {
> + strcpy(alg_name, pkey->pkey_algo);
> + return 0;
> + }
> +
> + return -ENOPKG;
> +}
Regards,
--
Mat Martineau
Intel OTC
^ permalink raw reply
* Re: crypto: rsa - Do not gratuitously drop leading zeroes
From: Tadeusz Struk @ 2016-06-23 15:25 UTC (permalink / raw)
To: Herbert Xu, Andrzej Zaborowski, Linux Crypto Mailing List
Cc: Tudor Ambarus, Stephan Mueller
In-Reply-To: <20160622101432.GA30454@gondor.apana.org.au>
Hi Herbert,
On 06/22/2016 03:14 AM, Herbert Xu wrote:
> This was prompted by the caam RSA submission where a lot of work
> was done just to strip the RSA output of leading zeroes. This is
> in fact completely pointless because the only user of RSA in the
> kernel then promptly puts them back.
>
> This patch series resolves this madness by simply leaving any
> leading zeroes in place.
The reason why mpi_write_to_sgl() strips the leading zeros is only
because we said that it needs to work in the same way as the
mpi_read_buffer(), which does remove it for whatever reason.
So should we now change the mpi_read_buffer() as well?
The mpi_read_buffer() is called from mpi_get_buffer(), which is used
only by lib/digsig.c
We also need to change the qat rsa implementation because it does remove
zeros as well, but it will be very easy to do.
Thanks,
--
TS
^ permalink raw reply
* Re: [PATCH v6 3/6] crypto: AF_ALG -- add asymmetric cipher interface
From: Denis Kenzior @ 2016-06-23 15:22 UTC (permalink / raw)
To: Stephan Mueller, Mat Martineau
Cc: Tadeusz Struk, dhowells-H+wXaHxf7aLQT0dZR+AlfA,
herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q,
linux-api-u79uwXL29TY76Z2rM5mHXA, marcel-kz+m5ild9QBg9hUCZPvPmw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
keyrings-u79uwXL29TY76Z2rM5mHXA,
linux-crypto-u79uwXL29TY76Z2rM5mHXA, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <3250613.UAo0YkFYZb-gNvIQDDl/k7Ia13z/PHSgg@public.gmane.org>
Hi Stephan,
>>
>> This brings me to another proposal for read buffer sizing: AF_ALG akcipher
>> can guarantee that partial reads (where the read buffer is shorter than
>> the output of the crypto op) will work using the same semantics as
>> SOCK_DGRAM/SOCK_SEQPACKET. With those sockets, as much data as will fit is
>> copied in to the read buffer and the remainder is discarded.
>>
>> I realize there's a performance and memory tradeoff, since the crypto
>> algorithm needs a sufficiently large output buffer that would have to be
>> created by AF_ALG akcipher. The user could manage that tradeoff by
>> providing a larger buffer (typically key_size?) if it wants to avoid
>> allocating and copying intermediate buffers inside the kernel.
>
> How shall the user know that something got truncated or that the kernel
> created memory?
>
To the former point, recall the signature of recv:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
Traditionally, userspace apps can know that the buffer provided to recv
was too small in two ways:
The return value from recv / recvmsg was >= len.
In the case of recvmsg, the MSG_TRUNC flag is set.
To quote man recv:
"All three calls return the length of the message on successful comple‐
tion. If a message is too long to fit in the supplied buffer, excess
bytes may be discarded depending on the type of socket the message is
received from."
and
"MSG_TRUNC (since Linux 2.2)
For raw (AF_PACKET), Internet datagram (since Linux
2.4.27/2.6.8), netlink (since Linux 2.6.22), and UNIX datagram
(since Linux 3.4) sockets: return the real length of the packet
or datagram, even when it was longer than the passed buffer.
"
Regards,
-Denis
^ permalink raw reply
* Re: [PATCH] crypto: user - re-add size check for CRYPTO_MSG_GETALG
From: Stephan Mueller @ 2016-06-23 14:46 UTC (permalink / raw)
To: Herbert Xu
Cc: Mathias Krause, David S. Miller, linux-crypto, Steffen Klassert
In-Reply-To: <20160623104357.GA10350@gondor.apana.org.au>
Am Donnerstag, 23. Juni 2016, 18:43:57 schrieb Herbert Xu:
Hi Herbert,
> On Wed, Jun 22, 2016 at 08:29:37PM +0200, Mathias Krause wrote:
> > Commit 9aa867e46565 ("crypto: user - Add CRYPTO_MSG_DELRNG")
> > accidentally removed the minimum size check for CRYPTO_MSG_GETALG
> > netlink messages. This allows userland to send a truncated
> > CRYPTO_MSG_GETALG message as short as a netlink header only making
> > crypto_report() operate on uninitialized memory by accessing data
> > beyond the end of the netlink message.
> >
> > Fix this be re-adding the minimum required size of CRYPTO_MSG_GETALG
> > messages to the crypto_msg_min[] array.
> >
> > Fixes: 9aa867e46565 ("crypto: user - Add CRYPTO_MSG_DELRNG")
> > Cc: stable@vger.kernel.org # v4.2
> > Signed-off-by: Mathias Krause <minipli@googlemail.com>
> > Cc: Steffen Klassert <steffen.klassert@secunet.com>
> > ---
> > This should go on top of crypto-2.6/master.
>
> Patch applied to crypto. Thanks!
Please revert my patch eed1e1afd8d542d9644534c1b712599b5d680007 as requested
by Matthias.
Ciao
Stephan
^ permalink raw reply
* [PATCH 8/8] KEYS: Implement PKCS#8 RSA Private Key parser [ver #2]
From: David Howells @ 2016-06-23 13:48 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Implement PKCS#8 RSA Private Key format [RFC 5208] parser for the
asymmetric key type. For the moment, this will only support unencrypted
DER blobs. PEM and decryption can be added later.
PKCS#8 keys can be loaded like this:
openssl pkcs8 -in private_key.pem -topk8 -nocrypt -outform DER | \
keyctl padd asymmetric foo @s
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/crypto/asymmetric-keys.txt | 2
crypto/asymmetric_keys/Kconfig | 10 ++
crypto/asymmetric_keys/Makefile | 13 ++
crypto/asymmetric_keys/pkcs8.asn1 | 24 ++++
crypto/asymmetric_keys/pkcs8_parser.c | 184 ++++++++++++++++++++++++++++++
5 files changed, 233 insertions(+)
create mode 100644 crypto/asymmetric_keys/pkcs8.asn1
create mode 100644 crypto/asymmetric_keys/pkcs8_parser.c
diff --git a/Documentation/crypto/asymmetric-keys.txt b/Documentation/crypto/asymmetric-keys.txt
index cdf2aca41b2c..80d45b5776b0 100644
--- a/Documentation/crypto/asymmetric-keys.txt
+++ b/Documentation/crypto/asymmetric-keys.txt
@@ -247,6 +247,8 @@ Examples of blob formats for which parsers could be implemented include:
- X.509 ASN.1 stream.
- Pointer to TPM key.
- Pointer to UEFI key.
+ - PKCS#8 private key [RFC 5208].
+ - PKCS#5 encrypted private key [RFC 2898].
During key instantiation each parser in the list is tried until one doesn't
return -EBADMSG.
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 331f6baf2df8..338fbed30a32 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -30,6 +30,16 @@ config X509_CERTIFICATE_PARSER
data and provides the ability to instantiate a crypto key from a
public key packet found inside the certificate.
+config PKCS8_PRIVATE_KEY_PARSER
+ tristate "PKCS#8 private key parser"
+ depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+ select ASN1
+ select OID_REGISTRY
+ help
+ This option provides support for parsing PKCS#8 format blobs for
+ private key data and provides the ability to instantiate a crypto key
+ from that data.
+
config PKCS7_MESSAGE_PARSER
tristate "PKCS#7 message parser"
depends on X509_CERTIFICATE_PARSER
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 6516855bec18..ac877577d677 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -32,6 +32,19 @@ clean-files += x509-asn1.c x509-asn1.h
clean-files += x509_akid-asn1.c x509_akid-asn1.h
#
+# PKCS#8 private key handling
+#
+obj-$(CONFIG_PKCS8_PRIVATE_KEY_PARSER) += pkcs8_key_parser.o
+pkcs8_key_parser-y := \
+ pkcs8-asn1.o \
+ pkcs8_parser.o
+
+$(obj)/pkcs8_parser.o: $(obj)/pkcs8-asn1.h
+$(obj)/pkcs8-asn1.o: $(obj)/pkcs8-asn1.c $(obj)/pkcs8-asn1.h
+
+clean-files += pkcs8-asn1.c pkcs8-asn1.h
+
+#
# PKCS#7 message handling
#
obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
diff --git a/crypto/asymmetric_keys/pkcs8.asn1 b/crypto/asymmetric_keys/pkcs8.asn1
new file mode 100644
index 000000000000..702c41a3c713
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8.asn1
@@ -0,0 +1,24 @@
+--
+-- This is the unencrypted variant
+--
+PrivateKeyInfo ::= SEQUENCE {
+ version Version,
+ privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ privateKey PrivateKey,
+ attributes [0] IMPLICIT Attributes OPTIONAL
+}
+
+Version ::= INTEGER ({ pkcs8_note_version })
+
+PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier ({ pkcs8_note_algo })
+
+PrivateKey ::= OCTET STRING ({ pkcs8_note_key })
+
+Attributes ::= SET OF Attribute
+
+Attribute ::= ANY
+
+AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER ({ pkcs8_note_OID }),
+ parameters ANY OPTIONAL
+}
diff --git a/crypto/asymmetric_keys/pkcs8_parser.c b/crypto/asymmetric_keys/pkcs8_parser.c
new file mode 100644
index 000000000000..26a73c0b7eef
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8_parser.c
@@ -0,0 +1,184 @@
+/* PKCS#8 Private Key parser [RFC 5208].
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "PKCS8: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#include <crypto/public_key.h>
+#include "pkcs8-asn1.h"
+
+struct pkcs8_parse_context {
+ struct public_key *pub;
+ unsigned long data; /* Start of data */
+ enum OID last_oid; /* Last OID encountered */
+ enum OID algo_oid; /* Algorithm OID */
+ u32 key_size;
+ const void *key;
+};
+
+/*
+ * Note an OID when we find one for later processing when we know how to
+ * interpret it.
+ */
+int pkcs8_note_OID(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs8_parse_context *ctx = context;
+
+ ctx->last_oid = look_up_OID(value, vlen);
+ if (ctx->last_oid == OID__NR) {
+ char buffer[50];
+
+ sprint_oid(value, vlen, buffer, sizeof(buffer));
+ pr_info("Unknown OID: [%lu] %s\n",
+ (unsigned long)value - ctx->data, buffer);
+ }
+ return 0;
+}
+
+/*
+ * Note the version number of the ASN.1 blob.
+ */
+int pkcs8_note_version(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ if (vlen != 1 || ((const u8 *)value)[0] != 0) {
+ pr_warn("Unsupported PKCS#8 version\n");
+ return -EBADMSG;
+ }
+ return 0;
+}
+
+/*
+ * Note the public algorithm.
+ */
+int pkcs8_note_algo(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs8_parse_context *ctx = context;
+
+ if (ctx->last_oid != OID_rsaEncryption)
+ return -ENOPKG;
+
+ ctx->pub->pkey_algo = "rsa";
+ return 0;
+}
+
+/*
+ * Note the key data of the ASN.1 blob.
+ */
+int pkcs8_note_key(void *context, size_t hdrlen,
+ unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct pkcs8_parse_context *ctx = context;
+
+ ctx->key = value;
+ ctx->key_size = vlen;
+ return 0;
+}
+
+/*
+ * Parse a PKCS#8 private key blob.
+ */
+static struct public_key *pkcs8_parse(const void *data, size_t datalen)
+{
+ struct pkcs8_parse_context ctx;
+ struct public_key *pub;
+ long ret;
+
+ memset(&ctx, 0, sizeof(ctx));
+
+ ret = -ENOMEM;
+ ctx.pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
+ if (!ctx.pub)
+ goto error;
+
+ ctx.data = (unsigned long)data;
+
+ /* Attempt to decode the private key */
+ ret = asn1_ber_decoder(&pkcs8_decoder, &ctx, data, datalen);
+ if (ret < 0)
+ goto error_decode;
+
+ ret = -ENOMEM;
+ pub = ctx.pub;
+ pub->key = kmemdup(ctx.key, ctx.key_size, GFP_KERNEL);
+ if (!pub->key)
+ goto error_decode;
+
+ pub->keylen = ctx.key_size;
+ pub->key_is_private = true;
+ return pub;
+
+error_decode:
+ kfree(ctx.pub);
+error:
+ return ERR_PTR(ret);
+}
+
+/*
+ * Attempt to parse a data blob for a key as a PKCS#8 private key.
+ */
+static int pkcs8_key_preparse(struct key_preparsed_payload *prep)
+{
+ struct public_key *pub;
+
+ pub = pkcs8_parse(prep->data, prep->datalen);
+ if (IS_ERR(pub))
+ return PTR_ERR(pub);
+
+ pr_devel("Cert Key Algo: %s\n", pub->pkey_algo);
+ pub->id_type = "PKCS8";
+
+ /* We're pinning the module by being linked against it */
+ __module_get(public_key_subtype.owner);
+ prep->payload.data[asym_subtype] = &public_key_subtype;
+ prep->payload.data[asym_key_ids] = NULL;
+ prep->payload.data[asym_crypto] = pub;
+ prep->payload.data[asym_auth] = NULL;
+ prep->quotalen = 100;
+ return 0;
+}
+
+static struct asymmetric_key_parser pkcs8_key_parser = {
+ .owner = THIS_MODULE,
+ .name = "pkcs8",
+ .parse = pkcs8_key_preparse,
+};
+
+/*
+ * Module stuff
+ */
+static int __init pkcs8_key_init(void)
+{
+ return register_asymmetric_key_parser(&pkcs8_key_parser);
+}
+
+static void __exit pkcs8_key_exit(void)
+{
+ unregister_asymmetric_key_parser(&pkcs8_key_parser);
+}
+
+module_init(pkcs8_key_init);
+module_exit(pkcs8_key_exit);
+
+MODULE_DESCRIPTION("PKCS#8 certificate parser");
+MODULE_LICENSE("GPL");
^ permalink raw reply related
* [PATCH 7/8] KEYS: Implement encrypt, decrypt and sign for software asymmetric key [ver #2]
From: David Howells @ 2016-06-23 13:48 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.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 a29ca01a41a0..8be2586028b6 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
@@ -257,6 +339,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);
^ permalink raw reply related
* [PATCH 6/8] KEYS: Allow the public_key struct to hold a private key [ver #2]
From: David Howells @ 2016-06-23 13:48 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Put a flag in the public_key struct to indicate if the structure is holding
a private key. The private key must be held ASN.1 encoded in the format
specified in RFC 3447 A.1.2. This is the form required by crypto/rsa.c.
The software encryption subtype's verification and query functions then
need to select the appropriate crypto function to set the key.
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/public_key.c | 14 ++++++++++++--
include/crypto/public_key.h | 1 +
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index a48a47a1dff0..a29ca01a41a0 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -113,7 +113,12 @@ static int software_key_query(const struct kernel_pkey_params *params,
if (IS_ERR(tfm))
return PTR_ERR(tfm);
- ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
+ 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 < 0)
goto error_free_tfm;
@@ -184,7 +189,12 @@ int public_key_verify_signature(const struct public_key *pkey,
if (!req)
goto error_free_tfm;
- ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
+ 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;
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index c46140d3729c..c5e569b2a73e 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -25,6 +25,7 @@
struct public_key {
void *key;
u32 keylen;
+ bool key_is_private;
const char *id_type;
const char *pkey_algo;
};
^ permalink raw reply related
* [PATCH 5/8] KEYS: Provide software public key query function [ver #2]
From: David Howells @ 2016-06-23 13:48 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Provide a query function for the software public key implementation. This
permits information about such a key to be obtained using
query_asymmetric_key() or KEYCTL_PKEY_QUERY.
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/public_key.c | 96 ++++++++++++++++++++++++++++++-----
1 file changed, 82 insertions(+), 14 deletions(-)
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index fd76b5fc3b3a..a48a47a1dff0 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -57,6 +57,81 @@ static void public_key_destroy(void *payload0, void *payload3)
public_key_signature_free(payload3);
}
+/*
+ * Determine the crypto algorithm name.
+ */
+static
+int software_key_determine_akcipher(const char *encoding,
+ const char *hash_algo,
+ const struct public_key *pkey,
+ char alg_name[CRYPTO_MAX_ALG_NAME])
+{
+ int n;
+
+ if (strcmp(encoding, "pkcs1") == 0) {
+ /* The data wangled by the RSA algorithm is typically padded
+ * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
+ * sec 8.2].
+ */
+ if (!hash_algo)
+ n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
+ "pkcs1pad(%s)",
+ pkey->pkey_algo);
+ else
+ n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
+ "pkcs1pad(%s,%s)",
+ pkey->pkey_algo, hash_algo);
+ return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
+ }
+
+ if (strcmp(encoding, "raw") == 0) {
+ strcpy(alg_name, pkey->pkey_algo);
+ return 0;
+ }
+
+ return -ENOPKG;
+}
+
+/*
+ * Query information about a key.
+ */
+static int software_key_query(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info)
+{
+ struct crypto_akcipher *tfm;
+ struct public_key *pkey = params->key->payload.data[asym_crypto];
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ int ret, len;
+
+ 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);
+
+ ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
+ if (ret < 0)
+ goto error_free_tfm;
+
+ len = crypto_akcipher_maxsize(tfm);
+ info->key_size = len * 8;
+ info->max_data_size = len;
+ info->max_sig_size = len;
+ info->max_enc_size = len;
+ info->max_dec_size = len;
+ info->supported_ops = KEYCTL_SUPPORTS_VERIFY;
+ ret = 0;
+
+error_free_tfm:
+ crypto_free_akcipher(tfm);
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
struct public_key_completion {
struct completion completion;
int err;
@@ -83,8 +158,7 @@ int public_key_verify_signature(const struct public_key *pkey,
struct crypto_akcipher *tfm;
struct akcipher_request *req;
struct scatterlist sig_sg, digest_sg;
- const char *alg_name;
- char alg_name_buf[CRYPTO_MAX_ALG_NAME];
+ char alg_name[CRYPTO_MAX_ALG_NAME];
void *output;
unsigned int outlen;
int ret = -ENOMEM;
@@ -96,18 +170,11 @@ int public_key_verify_signature(const struct public_key *pkey,
BUG_ON(!sig->digest);
BUG_ON(!sig->s);
- alg_name = sig->pkey_algo;
- if (strcmp(sig->pkey_algo, "rsa") == 0) {
- /* The data wangled by the RSA algorithm is typically padded
- * and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
- * sec 8.2].
- */
- if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
- "pkcs1pad(rsa,%s)", sig->hash_algo
- ) >= CRYPTO_MAX_ALG_NAME)
- return -EINVAL;
- alg_name = alg_name_buf;
- }
+ ret = software_key_determine_akcipher(sig->encoding,
+ sig->hash_algo,
+ pkey, alg_name);
+ if (ret < 0)
+ return ret;
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
@@ -179,6 +246,7 @@ struct asymmetric_key_subtype public_key_subtype = {
.name_len = sizeof("public_key") - 1,
.describe = public_key_describe,
.destroy = public_key_destroy,
+ .query = software_key_query,
.verify_signature = public_key_verify_signature_2,
};
EXPORT_SYMBOL_GPL(public_key_subtype);
^ permalink raw reply related
* [PATCH 4/8] KEYS: Make the X.509 and PKCS7 parsers supply the sig encoding type [ver #2]
From: David Howells @ 2016-06-23 13:48 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Make the X.509 and PKCS7 parsers fill in the signature encoding type field
recently added to the public_key_signature struct.
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/pkcs7_parser.c | 1 +
crypto/asymmetric_keys/x509_cert_parser.c | 21 +++++++++------------
2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index af4cd8649117..5f0c6755a55b 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -261,6 +261,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_rsaEncryption:
ctx->sinfo->sig->pkey_algo = "rsa";
+ ctx->sinfo->sig->encoding = "pkcs1";
break;
default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 865f46ea724f..1f1899d5ab43 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -199,35 +199,32 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
case OID_md4WithRSAEncryption:
ctx->cert->sig->hash_algo = "md4";
- ctx->cert->sig->pkey_algo = "rsa";
- break;
+ goto rsa_pkcs1;
case OID_sha1WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha1";
- ctx->cert->sig->pkey_algo = "rsa";
- break;
+ goto rsa_pkcs1;
case OID_sha256WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha256";
- ctx->cert->sig->pkey_algo = "rsa";
- break;
+ goto rsa_pkcs1;
case OID_sha384WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha384";
- ctx->cert->sig->pkey_algo = "rsa";
- break;
+ goto rsa_pkcs1;
case OID_sha512WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha512";
- ctx->cert->sig->pkey_algo = "rsa";
- break;
+ goto rsa_pkcs1;
case OID_sha224WithRSAEncryption:
ctx->cert->sig->hash_algo = "sha224";
- ctx->cert->sig->pkey_algo = "rsa";
- break;
+ goto rsa_pkcs1;
}
+rsa_pkcs1:
+ ctx->cert->sig->pkey_algo = "rsa";
+ ctx->cert->sig->encoding = "pkcs1";
ctx->algo_oid = ctx->last_oid;
return 0;
}
^ permalink raw reply related
* [PATCH 3/8] KEYS: Provide missing asymmetric key subops for new key type ops [ver #2]
From: David Howells @ 2016-06-23 13:47 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Provide the missing asymmetric key subops for new key type ops. This
include query, encrypt, decrypt and create signature. Verify signature
already exists. Also provided are accessor functions for this:
int query_asymmetric_key(const struct key *key,
struct kernel_pkey_query *info);
int encrypt_blob(struct kernel_pkey_params *params,
const void *data, void *enc);
int decrypt_blob(struct kernel_pkey_params *params,
const void *enc, void *data);
int create_signature(struct kernel_pkey_params *params,
const void *data, void *enc);
The public_key_signature struct gains an encoding field to carry the
encoding for verify_signature().
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/crypto/asymmetric-keys.txt | 24 ++++++--
crypto/asymmetric_keys/asymmetric_keys.h | 3 +
crypto/asymmetric_keys/asymmetric_type.c | 59 ++++++++++++++++---
crypto/asymmetric_keys/signature.c | 95 ++++++++++++++++++++++++++++++
include/crypto/public_key.h | 13 +++-
include/keys/asymmetric-subtype.h | 9 +++
6 files changed, 188 insertions(+), 15 deletions(-)
diff --git a/Documentation/crypto/asymmetric-keys.txt b/Documentation/crypto/asymmetric-keys.txt
index 8c07e0ea6bc0..cdf2aca41b2c 100644
--- a/Documentation/crypto/asymmetric-keys.txt
+++ b/Documentation/crypto/asymmetric-keys.txt
@@ -182,6 +182,10 @@ and looks like the following:
void (*describe)(const struct key *key, struct seq_file *m);
void (*destroy)(void *payload);
+ int (*query)(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info);
+ int (*eds_op)(struct kernel_pkey_params *params,
+ const void *in, void *out);
int (*verify_signature)(const struct key *key,
const struct public_key_signature *sig);
};
@@ -206,12 +210,22 @@ There are a number of operations defined by the subtype:
asymmetric key will look after freeing the fingerprint and releasing the
reference on the subtype module.
- (3) verify_signature().
+ (3) query().
- Optional. These are the entry points for the key usage operations.
- Currently there is only the one defined. If not set, the caller will be
- given -ENOTSUPP. The subtype may do anything it likes to implement an
- operation, including offloading to hardware.
+ Mandatory. This is a function for querying the capabilities of a key.
+
+ (4) eds_op().
+
+ Optional. This is the entry point for the encryption, decryption and
+ signature creation operations (which are distinguished by the operation ID
+ in the parameter struct). The subtype may do anything it likes to
+ implement an operation, including offloading to hardware.
+
+ (5) verify_signature().
+
+ Optional. This is the entry point for signature verification. The
+ subtype may do anything it likes to implement an operation, including
+ offloading to hardware.
==========================
diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
index ca8e9ac34ce6..7be1ccf4fa9f 100644
--- a/crypto/asymmetric_keys/asymmetric_keys.h
+++ b/crypto/asymmetric_keys/asymmetric_keys.h
@@ -16,3 +16,6 @@ extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
extern int __asymmetric_key_hex_to_key_id(const char *id,
struct asymmetric_key_id *match_id,
size_t hexlen);
+
+extern int asymmetric_key_eds_op(struct kernel_pkey_params *params,
+ const void *in, void *out);
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 6600181d5d01..77aa44abd7a6 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ctype.h>
+#include <keys/user-type.h>
#include "asymmetric_keys.h"
MODULE_LICENSE("GPL");
@@ -451,15 +452,57 @@ static void asymmetric_key_destroy(struct key *key)
asymmetric_key_free_kids(kids);
}
+int asymmetric_key_eds_op(struct kernel_pkey_params *params,
+ const void *in, void *out)
+{
+ const struct asymmetric_key_subtype *subtype;
+ struct key *key = params->key;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (key->type != &key_type_asymmetric)
+ return -EINVAL;
+ subtype = asymmetric_key_subtype(key);
+ if (!subtype ||
+ !key->payload.data[0])
+ return -EINVAL;
+ if (!subtype->eds_op)
+ return -ENOTSUPP;
+
+ ret = subtype->eds_op(params, in, out);
+
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+
+static int asymmetric_key_verify_signature(struct kernel_pkey_params *params,
+ const void *in, const void *in2)
+{
+ struct public_key_signature sig = {
+ .s_size = params->in2_len,
+ .digest_size = params->in_len,
+ .encoding = params->encoding,
+ .hash_algo = params->hash_algo,
+ .digest = (void *)in,
+ .s = (void *)in2,
+ };
+
+ return verify_signature(params->key, &sig);
+}
+
struct key_type key_type_asymmetric = {
- .name = "asymmetric",
- .preparse = asymmetric_key_preparse,
- .free_preparse = asymmetric_key_free_preparse,
- .instantiate = generic_key_instantiate,
- .match_preparse = asymmetric_key_match_preparse,
- .match_free = asymmetric_key_match_free,
- .destroy = asymmetric_key_destroy,
- .describe = asymmetric_key_describe,
+ .name = "asymmetric",
+ .preparse = asymmetric_key_preparse,
+ .free_preparse = asymmetric_key_free_preparse,
+ .instantiate = generic_key_instantiate,
+ .match_preparse = asymmetric_key_match_preparse,
+ .match_free = asymmetric_key_match_free,
+ .destroy = asymmetric_key_destroy,
+ .describe = asymmetric_key_describe,
+ .asym_query = query_asymmetric_key,
+ .asym_eds_op = asymmetric_key_eds_op,
+ .asym_verify_signature = asymmetric_key_verify_signature,
};
EXPORT_SYMBOL_GPL(key_type_asymmetric);
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index 11b7ba170904..78545b446400 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -16,7 +16,9 @@
#include <linux/export.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/keyctl.h>
#include <crypto/public_key.h>
+#include <keys/user-type.h>
#include "asymmetric_keys.h"
/*
@@ -37,6 +39,99 @@ void public_key_signature_free(struct public_key_signature *sig)
EXPORT_SYMBOL_GPL(public_key_signature_free);
/**
+ * query_asymmetric_key - Get information about an aymmetric key.
+ * @params: Various parameters.
+ * @info: Where to put the information.
+ */
+int query_asymmetric_key(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info)
+{
+ const struct asymmetric_key_subtype *subtype;
+ struct key *key = params->key;
+ int ret;
+
+ pr_devel("==>%s()\n", __func__);
+
+ if (key->type != &key_type_asymmetric)
+ return -EINVAL;
+ subtype = asymmetric_key_subtype(key);
+ if (!subtype ||
+ !key->payload.data[0])
+ return -EINVAL;
+ if (!subtype->query)
+ return -ENOTSUPP;
+
+ ret = subtype->query(params, info);
+
+ pr_devel("<==%s() = %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(query_asymmetric_key);
+
+/**
+ * encrypt_blob - Encrypt data using an asymmetric key
+ * @params: Various parameters
+ * @data: Data blob to be encrypted, length params->data_len
+ * @enc: Encrypted data buffer, length params->enc_len
+ *
+ * Encrypt the specified data blob using the private key specified by
+ * params->key. The encrypted data is wrapped in an encoding if
+ * params->encoding is specified (eg. "pkcs1").
+ *
+ * Returns the length of the data placed in the encrypted data buffer or an
+ * error.
+ */
+int encrypt_blob(struct kernel_pkey_params *params,
+ const void *data, void *enc)
+{
+ params->op = kernel_pkey_encrypt;
+ return asymmetric_key_eds_op(params, data, enc);
+}
+EXPORT_SYMBOL_GPL(encrypt_blob);
+
+/**
+ * decrypt_blob - Decrypt data using an asymmetric key
+ * @params: Various parameters
+ * @enc: Encrypted data to be decrypted, length params->enc_len
+ * @data: Decrypted data buffer, length params->data_len
+ *
+ * Decrypt the specified data blob using the private key specified by
+ * params->key. The decrypted data is wrapped in an encoding if
+ * params->encoding is specified (eg. "pkcs1").
+ *
+ * Returns the length of the data placed in the decrypted data buffer or an
+ * error.
+ */
+int decrypt_blob(struct kernel_pkey_params *params,
+ const void *enc, void *data)
+{
+ params->op = kernel_pkey_decrypt;
+ return asymmetric_key_eds_op(params, enc, data);
+}
+EXPORT_SYMBOL_GPL(decrypt_blob);
+
+/**
+ * create_signature - Sign some data using an asymmetric key
+ * @params: Various parameters
+ * @data: Data blob to be signed, length params->data_len
+ * @enc: Signature buffer, length params->enc_len
+ *
+ * Sign the specified data blob using the private key specified by params->key.
+ * The signature is wrapped in an encoding if params->encoding is specified
+ * (eg. "pkcs1"). If the encoding needs to know the digest type, this can be
+ * passed through params->hash_algo (eg. "sha1").
+ *
+ * Returns the length of the data placed in the signature buffer or an error.
+ */
+int create_signature(struct kernel_pkey_params *params,
+ const void *data, void *enc)
+{
+ params->op = kernel_pkey_sign;
+ return asymmetric_key_eds_op(params, data, enc);
+}
+EXPORT_SYMBOL_GPL(create_signature);
+
+/**
* verify_signature - Initiate the use of an asymmetric key to verify a signature
* @key: The asymmetric key to verify against
* @sig: The signature to check
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 882ca0e1e7a5..c46140d3729c 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -14,6 +14,8 @@
#ifndef _LINUX_PUBLIC_KEY_H
#define _LINUX_PUBLIC_KEY_H
+#include <linux/keyctl.h>
+
/*
* Cryptographic data for the public-key subtype of the asymmetric key type.
*
@@ -40,6 +42,7 @@ struct public_key_signature {
u8 digest_size; /* Number of bytes in digest */
const char *pkey_algo;
const char *hash_algo;
+ const char *encoding;
};
extern void public_key_signature_free(struct public_key_signature *sig);
@@ -54,8 +57,14 @@ extern int restrict_link_by_signature(struct key *trust_keyring,
const struct key_type *type,
const union key_payload *payload);
-extern int verify_signature(const struct key *key,
- const struct public_key_signature *sig);
+extern int query_asymmetric_key(const struct kernel_pkey_params *,
+ struct kernel_pkey_query *);
+
+extern int encrypt_blob(struct kernel_pkey_params *, const void *, void *);
+extern int decrypt_blob(struct kernel_pkey_params *, const void *, void *);
+extern int create_signature(struct kernel_pkey_params *, const void *, void *);
+extern int verify_signature(const struct key *,
+ const struct public_key_signature *);
int public_key_verify_signature(const struct public_key *pkey,
const struct public_key_signature *sig);
diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h
index 2480469ce8fb..bd12733058c6 100644
--- a/include/keys/asymmetric-subtype.h
+++ b/include/keys/asymmetric-subtype.h
@@ -17,6 +17,8 @@
#include <linux/seq_file.h>
#include <keys/asymmetric-type.h>
+struct kernel_pkey_query;
+struct kernel_pkey_params;
struct public_key_signature;
/*
@@ -34,6 +36,13 @@ struct asymmetric_key_subtype {
/* Destroy a key of this subtype */
void (*destroy)(void *payload_crypto, void *payload_auth);
+ int (*query)(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info);
+
+ /* Encrypt/decrypt/sign data */
+ int (*eds_op)(struct kernel_pkey_params *params,
+ const void *in, void *out);
+
/* Verify the signature on a key of this subtype (optional) */
int (*verify_signature)(const struct key *key,
const struct public_key_signature *sig);
^ permalink raw reply related
* [PATCH 2/8] KEYS: Provide keyctls to drive the new key type ops for asymmetric keys [ver #2]
From: David Howells @ 2016-06-23 13:47 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Provide five keyctl functions that permit userspace to make use of the new
key type ops for accessing and driving asymmetric keys.
(*) Query an asymmetric key.
long keyctl(KEYCTL_PKEY_QUERY,
key_serial_t key, unsigned long reserved,
struct keyctl_pkey_query *info);
Get information about an asymmetric key. The information is returned
in the keyctl_pkey_query struct:
__u32 supported_ops;
A bit mask of flags indicating which ops are supported. This is
constructed from a bitwise-OR of:
KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
__u32 key_size;
The size in bits of the key.
__u16 max_data_size;
__u16 max_sig_size;
__u16 max_enc_size;
__u16 max_dec_size;
The maximum sizes in bytes of a blob of data to be signed, a signature
blob, a blob to be encrypted and a blob to be decrypted.
reserved must be set to 0. This is intended for future use to hand
over one or more passphrases needed unlock a key.
If successful, 0 is returned. If the key is not an asymmetric key,
EOPNOTSUPP is returned.
(*) Encrypt, decrypt, sign or verify a blob using an asymmetric key.
long keyctl(KEYCTL_PKEY_ENCRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_DECRYPT,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_SIGN,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
void *out);
long keyctl(KEYCTL_PKEY_VERIFY,
const struct keyctl_pkey_params *params,
const char *info,
const void *in,
const void *in2);
Use an asymmetric key to perform a public-key cryptographic operation
a blob of data.
The parameter block pointed to by params contains a number of integer
values:
__s32 key_id;
__u32 in_len;
__u32 out_len;
__u32 in2_len;
For a given operation, the in and out buffers are used as follows:
Operation ID in,in_len out,out_len in2,in2_len
======================= =============== =============== ===========
KEYCTL_PKEY_ENCRYPT Raw data Encrypted data -
KEYCTL_PKEY_DECRYPT Encrypted data Raw data -
KEYCTL_PKEY_SIGN Raw data Signature -
KEYCTL_PKEY_VERIFY Raw data - Signature
info is a string of key=value pairs that supply supplementary
information.
The __spare space in the parameter block must be set to 0. This is
intended, amongst other things, to allow the passing of passphrases
required to unlock a key.
If successful, encrypt, decrypt and sign all return the amount of data
written into the output buffer. Verification returns 0 on success.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/security/keys.txt | 111 +++++++++++++
include/uapi/linux/keyctl.h | 25 +++
security/keys/Makefile | 1
security/keys/compat.c | 18 ++
security/keys/internal.h | 39 +++++
security/keys/keyctl.c | 24 +++
security/keys/keyctl_pkey.c | 323 +++++++++++++++++++++++++++++++++++++++
7 files changed, 541 insertions(+)
create mode 100644 security/keys/keyctl_pkey.c
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 286b4cab7e68..6844dcbba1ba 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -857,6 +857,117 @@ The keyctl syscall functions are:
supported, error ENOKEY if the key could not be found, or error
EACCES if the key is not readable by the caller.
+
+ (*) Query an asymmetric key.
+
+ long keyctl(KEYCTL_PKEY_QUERY,
+ key_serial_t key_id, unsigned long reserved,
+ struct keyctl_pkey_query *info);
+
+ Get information about an asymmetric key. The information is returned in
+ the keyctl_pkey_query struct:
+
+ __u32 supported_ops;
+
+ A bit mask of flags indicating which ops are supported. This is
+ constructed from a bitwise-OR of:
+
+ KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
+
+ __u32 key_size;
+
+ The size in bits of the key.
+
+ __u16 max_data_size;
+ __u16 max_sig_size;
+ __u16 max_enc_size;
+ __u16 max_dec_size;
+
+ The maximum sizes in bytes of a blob of data to be signed, a signature
+ blob, a blob to be encrypted and a blob to be decrypted.
+
+ reserved must be set to 0. This is intended for future use to hand over
+ one or more passphrases needed unlock a key.
+
+ If successful, 0 is returned. If the key is not an asymmetric key,
+ EOPNOTSUPP is returned.
+
+
+ (*) Encrypt, decrypt, sign or verify a blob using an asymmetric key.
+
+ long keyctl(KEYCTL_PKEY_ENCRYPT,
+ const struct keyctl_pkey_params *params,
+ const char *info,
+ const void *in,
+ void *out);
+
+ long keyctl(KEYCTL_PKEY_DECRYPT,
+ const struct keyctl_pkey_params *params,
+ const char *info,
+ const void *in,
+ void *out);
+
+ long keyctl(KEYCTL_PKEY_SIGN,
+ const struct keyctl_pkey_params *params,
+ const char *info,
+ const void *in,
+ void *out);
+
+ long keyctl(KEYCTL_PKEY_VERIFY,
+ const struct keyctl_pkey_params *params,
+ const char *info,
+ const void *in,
+ const void *in2);
+
+ Use an asymmetric key to perform a public-key cryptographic operation a
+ blob of data. For encryption and verification, the asymmetric key may
+ only need the public parts to be available, but for decryption and signing
+ the private parts are required also.
+
+ The parameter block pointed to by params contains a number of integer
+ values:
+
+ __s32 key_id;
+ __u32 in_len;
+ __u32 out_len;
+ __u32 in2_len;
+
+ key_id is the ID of the asymmetric key to be used. in_len and in2_len
+ indicate the amount of data in the in and in2 buffers and out_len
+ indicates the size of the out buffer as appropriate for the above
+ operations.
+
+ For a given operation, the in and out buffers are used as follows:
+
+ Operation ID in,in_len out,out_len in2,in2_len
+ ======================= =============== =============== ===============
+ KEYCTL_PKEY_ENCRYPT Raw data Encrypted data -
+ KEYCTL_PKEY_DECRYPT Encrypted data Raw data -
+ KEYCTL_PKEY_SIGN Raw data Signature -
+ KEYCTL_PKEY_VERIFY Raw data - Signature
+
+ info is a string of key=value pairs that supply supplementary information.
+ These include:
+
+ enc=<encoding> The encoding of the encrypted/signature blob. This can
+ be "pkcs1" for RSASSA-PKCS1-v1.5 or RSAES-PKCS1-v1.5;
+ "pss" for "RSASSA-PSS"; "oaep" for "RSAES-OAEP". If
+ omitted or is "raw", the raw output of the encryption
+ function is specified.
+
+ hash=<algo> If the data buffer contains the output of a hash
+ function and the encoding includes some indication of
+ which hash function was used, the hash function can be
+ specified with this, eg. "hash=sha256".
+
+ The __spare space in the parameter block must be set to 0. This is
+ intended, amongst other things, to allow the passing of passphrases
+ required to unlock a key.
+
+ If successful, encrypt, decrypt and sign all return the amount of data
+ written into the output buffer. Verification returns 0 on success.
+
+
===============
KERNEL SERVICES
===============
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 8ac2c5fbc8fc..93ebd25b1427 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -60,6 +60,11 @@
#define KEYCTL_INVALIDATE 21 /* invalidate a key */
#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */
#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */
+#define KEYCTL_PKEY_QUERY 24 /* Query public key parameters */
+#define KEYCTL_PKEY_ENCRYPT 25 /* Encrypt a blob using a public key */
+#define KEYCTL_PKEY_DECRYPT 26 /* Decrypt a blob using a public key */
+#define KEYCTL_PKEY_SIGN 27 /* Create a public key signature */
+#define KEYCTL_PKEY_VERIFY 28 /* Verify a public key signature */
/* keyctl structures */
struct keyctl_dh_params {
@@ -73,4 +78,24 @@ struct keyctl_dh_params {
#define KEYCTL_SUPPORTS_SIGN 0x04
#define KEYCTL_SUPPORTS_VERIFY 0x08
+struct keyctl_pkey_query {
+ __u32 supported_ops; /* Which ops are supported */
+ __u32 key_size; /* Size of the key in bits */
+ __u16 max_data_size; /* Maximum size of raw data to sign in bytes */
+ __u16 max_sig_size; /* Maximum size of signature in bytes */
+ __u16 max_enc_size; /* Maximum size of encrypted blob in bytes */
+ __u16 max_dec_size; /* Maximum size of decrypted blob in bytes */
+ __u32 __spare[10];
+};
+
+struct keyctl_pkey_params {
+ __s32 key_id; /* Serial no. of public key to use */
+ __u32 in_len; /* Input data size */
+ union {
+ __u32 out_len; /* Output buffer size (encrypt/decrypt/sign) */
+ __u32 in2_len; /* 2nd input data size (verify) */
+ };
+ __u32 __spare[7];
+};
+
#endif /* _LINUX_KEYCTL_H */
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 1fd4a16e6daf..981be73e938f 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_SYSCTL) += sysctl.o
obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o
+obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += keyctl_pkey.o
#
# Key types
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 36c80bf5b89c..519010ae3f4f 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -136,6 +136,24 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
arg4, compat_ptr(arg5));
+ case KEYCTL_PKEY_QUERY:
+ if (arg3 != 0)
+ return -EINVAL;
+ return keyctl_pkey_query(arg2,
+ compat_ptr(arg4),
+ compat_ptr(arg5));
+
+ case KEYCTL_PKEY_ENCRYPT:
+ case KEYCTL_PKEY_DECRYPT:
+ case KEYCTL_PKEY_SIGN:
+ return keyctl_pkey_e_d_s(option,
+ compat_ptr(arg2), compat_ptr(arg3),
+ compat_ptr(arg4), compat_ptr(arg5));
+
+ case KEYCTL_PKEY_VERIFY:
+ return keyctl_pkey_verify(compat_ptr(arg2), compat_ptr(arg3),
+ compat_ptr(arg4), compat_ptr(arg5));
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index a705a7d92ad7..7c34fab5be70 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -270,6 +270,45 @@ static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
}
#endif
+#ifdef CONFIG_ASYMMETRIC_KEY_TYPE
+extern long keyctl_pkey_query(key_serial_t,
+ const char __user *,
+ struct keyctl_pkey_query __user *);
+
+extern long keyctl_pkey_verify(const struct keyctl_pkey_params __user *,
+ const char __user *,
+ const void __user *, const void __user *);
+
+extern long keyctl_pkey_e_d_s(int,
+ const struct keyctl_pkey_params __user *,
+ const char __user *,
+ const void __user *, void __user *);
+#else
+static inline long keyctl_pkey_query(key_serial_t id,
+ const char __user *_info,
+ struct keyctl_pkey_query __user *_res)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline long keyctl_pkey_verify(const struct keyctl_pkey_params __user *params,
+ const char __user *_info,
+ const void __user *_in,
+ const void __user *_in2)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline long keyctl_pkey_e_d_s(int op,
+ const struct keyctl_pkey_params __user *params,
+ const char __user *_info,
+ const void __user *_in,
+ void __user *_out)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
/*
* Debugging key validation
*/
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index d580ad06b792..1fb1ac472341 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1691,6 +1691,30 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
(char __user *) arg3, (size_t) arg4,
(void __user *) arg5);
+ case KEYCTL_PKEY_QUERY:
+ if (arg3 != 0)
+ return -EINVAL;
+ return keyctl_pkey_query((key_serial_t)arg2,
+ (const char __user *)arg4,
+ (struct keyctl_pkey_query *)arg5);
+
+ case KEYCTL_PKEY_ENCRYPT:
+ case KEYCTL_PKEY_DECRYPT:
+ case KEYCTL_PKEY_SIGN:
+ return keyctl_pkey_e_d_s(
+ option,
+ (const struct keyctl_pkey_params __user *)arg2,
+ (const char __user *)arg3,
+ (const void __user *)arg4,
+ (void __user *)arg5);
+
+ case KEYCTL_PKEY_VERIFY:
+ return keyctl_pkey_verify(
+ (const struct keyctl_pkey_params __user *)arg2,
+ (const char __user *)arg3,
+ (const void __user *)arg4,
+ (const void __user *)arg5);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c
new file mode 100644
index 000000000000..783978842f13
--- /dev/null
+++ b/security/keys/keyctl_pkey.c
@@ -0,0 +1,323 @@
+/* Public-key operation keyctls
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/key.h>
+#include <linux/keyctl.h>
+#include <linux/parser.h>
+#include <linux/uaccess.h>
+#include <keys/user-type.h>
+#include "internal.h"
+
+static void keyctl_pkey_params_free(struct kernel_pkey_params *params)
+{
+ kfree(params->info);
+ key_put(params->key);
+}
+
+enum {
+ Opt_err = -1,
+ Opt_enc, /* "enc=<encoding>" eg. "enc=oaep" */
+ Opt_hash, /* "hash=<digest-name>" eg. "hash=sha1" */
+};
+
+static const match_table_t param_keys = {
+ { Opt_enc, "enc=%s" },
+ { Opt_hash, "hash=%s" },
+ { Opt_err, NULL }
+};
+
+/*
+ * Parse the information string which consists of key=val pairs.
+ */
+static int keyctl_pkey_params_parse(struct kernel_pkey_params *params)
+{
+ unsigned long token_mask = 0;
+ substring_t args[MAX_OPT_ARGS];
+ char *c = params->info, *p, *q;
+ int token;
+
+ while ((p = strsep(&c, " \t"))) {
+ if (*p == '\0' || *p == ' ' || *p == '\t')
+ continue;
+ token = match_token(p, param_keys, args);
+ if (__test_and_set_bit(token, &token_mask))
+ return -EINVAL;
+ q = args[0].from;
+ if (!q[0])
+ return -EINVAL;
+
+ switch (token) {
+ case Opt_enc:
+ params->encoding = q;
+ break;
+
+ case Opt_hash:
+ params->hash_algo = q;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Interpret parameters. Callers must always call the free function
+ * on params, even if an error is returned.
+ */
+static int keyctl_pkey_params_get(key_serial_t id,
+ const char __user *_info,
+ struct kernel_pkey_params *params)
+{
+ key_ref_t key_ref;
+ void *p;
+ int ret;
+
+ memset(params, 0, sizeof(*params));
+ params->encoding = "raw";
+
+ p = strndup_user(_info, PAGE_SIZE);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+ params->info = p;
+
+ ret = keyctl_pkey_params_parse(params);
+ if (ret < 0)
+ return ret;
+
+ key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
+ if (IS_ERR(key_ref))
+ return PTR_ERR(key_ref);
+ params->key = key_ref_to_ptr(key_ref);
+
+ if (!params->key->type->asym_query)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+/*
+ * Get parameters from userspace. Callers must always call the free function
+ * on params, even if an error is returned.
+ */
+static int keyctl_pkey_params_get_2(const struct keyctl_pkey_params __user *_params,
+ const char __user *_info,
+ int op,
+ struct kernel_pkey_params *params)
+{
+ struct keyctl_pkey_params uparams;
+ struct kernel_pkey_query info;
+ int ret;
+
+ memset(params, 0, sizeof(*params));
+ params->encoding = "raw";
+
+ if (copy_from_user(&uparams, _params, sizeof(uparams)) != 0)
+ return -EFAULT;
+
+ ret = keyctl_pkey_params_get(uparams.key_id, _info, params);
+ if (ret < 0)
+ return ret;
+
+ ret = params->key->type->asym_query(params, &info);
+ if (ret < 0)
+ return ret;
+
+ switch (op) {
+ case KEYCTL_PKEY_ENCRYPT:
+ case KEYCTL_PKEY_DECRYPT:
+ if (uparams.in_len > info.max_enc_size ||
+ uparams.out_len > info.max_dec_size)
+ return -EINVAL;
+ break;
+ case KEYCTL_PKEY_SIGN:
+ case KEYCTL_PKEY_VERIFY:
+ if (uparams.in_len > info.max_sig_size ||
+ uparams.out_len > info.max_data_size)
+ return -EINVAL;
+ break;
+ default:
+ BUG();
+ }
+
+ params->in_len = uparams.in_len;
+ params->out_len = uparams.out_len;
+ return 0;
+}
+
+/*
+ * Query information about an asymmetric key.
+ */
+long keyctl_pkey_query(key_serial_t id,
+ const char __user *_info,
+ struct keyctl_pkey_query __user *_res)
+{
+ struct kernel_pkey_params params;
+ struct kernel_pkey_query res;
+ long ret;
+
+ memset(¶ms, 0, sizeof(params));
+
+ ret = keyctl_pkey_params_get(id, _info, ¶ms);
+ if (ret < 0)
+ goto error;
+
+ ret = params.key->type->asym_query(¶ms, &res);
+ if (ret < 0)
+ goto error;
+
+ ret = -EFAULT;
+ if (copy_to_user(_res, &res, sizeof(res)) == 0 &&
+ clear_user(_res->__spare, sizeof(_res->__spare)) == 0)
+ ret = 0;
+
+error:
+ keyctl_pkey_params_free(¶ms);
+ return ret;
+}
+
+/*
+ * Encrypt/decrypt/sign
+ *
+ * Encrypt data, decrypt data or sign data using a public key.
+ *
+ * _info is a string of supplementary information in key=val format. For
+ * instance, it might contain:
+ *
+ * "enc=pkcs1 hash=sha256"
+ *
+ * where enc= specifies the encoding and hash= selects the OID to go in that
+ * particular encoding if required. If enc= isn't supplied, it's assumed that
+ * the caller is supplying raw values.
+ *
+ * If successful, the amount of data written into the output buffer is
+ * returned.
+ */
+long keyctl_pkey_e_d_s(int op,
+ const struct keyctl_pkey_params __user *_params,
+ const char __user *_info,
+ const void __user *_in,
+ void __user *_out)
+{
+ struct kernel_pkey_params params;
+ void *in, *out;
+ long ret;
+
+ ret = keyctl_pkey_params_get_2(_params, _info, op, ¶ms);
+ if (ret < 0)
+ goto error_params;
+
+ ret = -EOPNOTSUPP;
+ if (!params.key->type->asym_eds_op)
+ goto error_params;
+
+ switch (op) {
+ case KEYCTL_PKEY_ENCRYPT:
+ params.op = kernel_pkey_encrypt;
+ break;
+ case KEYCTL_PKEY_DECRYPT:
+ params.op = kernel_pkey_decrypt;
+ break;
+ case KEYCTL_PKEY_SIGN:
+ params.op = kernel_pkey_sign;
+ break;
+ default:
+ BUG();
+ }
+
+ in = memdup_user(_in, params.in_len);
+ if (IS_ERR(in)) {
+ ret = PTR_ERR(in);
+ goto error_params;
+ }
+
+ ret = -ENOMEM;
+ out = kmalloc(params.out_len, GFP_KERNEL);
+ if (!out)
+ goto error_in;
+
+ ret = params.key->type->asym_eds_op(¶ms, in, out);
+ if (ret < 0)
+ goto error_out;
+
+ if (copy_to_user(_out, out, ret) != 0)
+ ret = -EFAULT;
+
+error_out:
+ kfree(out);
+error_in:
+ kfree(in);
+error_params:
+ keyctl_pkey_params_free(¶ms);
+ return ret;
+}
+
+/*
+ * Verify a signature.
+ *
+ * Verify a public key signature using the given key, or if not given, search
+ * for a matching key.
+ *
+ * _info is a string of supplementary information in key=val format. For
+ * instance, it might contain:
+ *
+ * "enc=pkcs1 hash=sha256"
+ *
+ * where enc= specifies the signature blob encoding and hash= selects the OID
+ * to go in that particular encoding. If enc= isn't supplied, it's assumed
+ * that the caller is supplying raw values.
+ *
+ * If successful, 0 is returned.
+ */
+long keyctl_pkey_verify(const struct keyctl_pkey_params __user *_params,
+ const char __user *_info,
+ const void __user *_in,
+ const void __user *_in2)
+{
+ struct kernel_pkey_params params;
+ void *in, *in2;
+ long ret;
+
+ ret = keyctl_pkey_params_get_2(_params, _info, KEYCTL_PKEY_VERIFY,
+ ¶ms);
+ if (ret < 0)
+ goto error_params;
+
+ ret = -EOPNOTSUPP;
+ if (!params.key->type->asym_verify_signature)
+ goto error_params;
+
+ in = memdup_user(_in, params.in_len);
+ if (IS_ERR(in)) {
+ ret = PTR_ERR(in);
+ goto error_params;
+ }
+
+ in2 = memdup_user(_in2, params.in2_len);
+ if (IS_ERR(in2)) {
+ ret = PTR_ERR(in2);
+ goto error_in;
+ }
+
+ params.op = kernel_pkey_verify;
+ ret = params.key->type->asym_verify_signature(¶ms, in, in2);
+
+ kfree(in2);
+error_in:
+ kfree(in);
+error_params:
+ keyctl_pkey_params_free(¶ms);
+ return ret;
+}
^ permalink raw reply related
* [PATCH 1/8] KEYS: Provide key type operations for asymmetric key ops [ver #2]
From: David Howells @ 2016-06-23 13:47 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
In-Reply-To: <146668965425.2977.13357101274301968911.stgit@warthog.procyon.org.uk>
Provide five new operations in the key_type struct that can be used to
provide access to asymmetric key operations. These will be implemented for
the asymmetric key type in a later patch and may refer to a key retained in
RAM by the kernel or a key retained in crypto hardware.
int (*asym_query)(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info);
int (*asym_eds_op)(struct kernel_pkey_params *params,
const void *in, void *out);
int (*asym_verify_signature)(struct kernel_pkey_params *params,
const void *in, const void *in2);
Since encrypt, decrypt and sign are identical in their interfaces, they're
rolled together in the asym_eds_op() operation and there's an operation ID
in the params argument to distinguish them.
Verify is different in that we supply the data and the signature instead
and get an error value (or 0) as the only result on the expectation that
this may well be how a hardware crypto device may work.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/security/keys.txt | 106 +++++++++++++++++++++++++++++++++++++++
include/linux/key-type.h | 11 ++++
include/linux/keyctl.h | 46 +++++++++++++++++
include/uapi/linux/keyctl.h | 5 ++
4 files changed, 168 insertions(+)
create mode 100644 include/linux/keyctl.h
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 3849814bfe6d..286b4cab7e68 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -1432,6 +1432,112 @@ The structure has a number of fields, some of which are mandatory:
The authorisation key.
+ (*) int (*asym_eds_op)(struct kernel_pkey_params *params,
+ const void *in, void *out);
+ int (*asym_verify_signature)(struct kernel_pkey_params *params,
+ const void *in, const void *in2);
+
+ These methods are optional. If provided the first allows a key to be
+ used to encrypt, decrypt or sign a blob of data, and the second allows a
+ key to verify a signature.
+
+ In all cases, the following information is provided in the params block:
+
+ struct kernel_pkey_params {
+ struct key *key;
+ const char *encoding;
+ const char *hash_algo;
+ char *info;
+ __u32 in_len;
+ union {
+ __u32 out_len;
+ __u32 in2_len;
+ };
+ enum kernel_pkey_operation op : 8;
+ };
+
+ This includes the key to be used; an optional string indicating the
+ encoding to use (for instance, "pkcs1" may be used with an RSA key to
+ indicate RSASSA-PKCS1-v1.5 or RSAES-PKCS1-v1.5 encoding); the name of the
+ hash algorithm used to generate the data for a signature (if appropriate);
+ the sizes of the input and output (or second input) buffers; and the ID of
+ the operation to be performed.
+
+ For a given operation ID, the input and output buffers are used as
+ follows:
+
+ Operation ID in,in_len out,out_len in2,in2_len
+ ======================= =============== =============== ===============
+ kernel_pkey_encrypt Raw data Encrypted data -
+ kernel_pkey_decrypt Encrypted data Raw data -
+ kernel_pkey_sign Raw data Signature -
+ kernel_pkey_verify Raw data - Signature
+
+ asym_eds_op() deals with encryption, decryption and signature creation as
+ specified by params->op. Note that params->op is also set for
+ asym_verify_signature().
+
+ Encrypting and signature creation both take raw data in the input buffer
+ and return the encrypted result in the output buffer. Padding may have
+ been added if an encoding was set. In the case of signature creation,
+ depending on the encoding, the padding created may need to indicate the
+ digest algorithm - the name of which should be supplied in hash_algo.
+
+ Decryption takes encrypted data in the input buffer and returns the raw
+ data in the output buffer. Padding will get checked and stripped off if
+ an encoding was set.
+
+ Verification takes raw data in the input buffer and the signature in the
+ second input buffer and checks that the one matches the other. Padding
+ will be validated. Depending on the encoding, the digest algorithm used
+ to generate the raw data may need to be indicated in hash_algo.
+
+ If successful, asym_eds_op() should return the number of bytes written
+ into the output buffer. asym_verify_signature() should return 0.
+
+ A variety of errors may be returned, including EOPNOTSUPP if the operation
+ is not supported; EKEYREJECTED if verification fails; ENOPKG if the
+ required crypto isn't available.
+
+
+ (*) int (*asym_query)(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info);
+
+ This method is optional. If provided it allows information about the
+ public or asymmetric key held in the key to be determined.
+
+ The parameter block is as for asym_eds_op() and co. but in_len and out_len
+ are unused. The encoding and hash_algo fields should be used to reduce
+ the returned buffer/data sizes as appropriate.
+
+ If successful, the following information is filled in:
+
+ struct kernel_pkey_query {
+ __u32 supported_ops;
+ __u32 key_size;
+ __u16 max_data_size;
+ __u16 max_sig_size;
+ __u16 max_enc_size;
+ __u16 max_dec_size;
+ };
+
+ The supported_ops field will contain a bitmask indicating what operations
+ are supported by the key, including encryption of a blob, decryption of a
+ blob, signing a blob and verifying the signature on a blob. The following
+ constants are defined for this:
+
+ KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
+
+ The key_size field is the size of the key in bits. max_data_size and
+ max_sig_size are the maximum raw data and signature sizes for creation and
+ verification of a signature; max_enc_size and max_dec_size are the maximum
+ raw data and signature sizes for encryption and decryption. The
+ max_*_size fields are measured in bytes.
+
+ If successful, 0 will be returned. If the key doesn't support this,
+ EOPNOTSUPP will be returned.
+
+
============================
REQUEST-KEY CALLBACK SERVICE
============================
diff --git a/include/linux/key-type.h b/include/linux/key-type.h
index eaee981c5558..63b2a92c2085 100644
--- a/include/linux/key-type.h
+++ b/include/linux/key-type.h
@@ -17,6 +17,9 @@
#ifdef CONFIG_KEYS
+struct kernel_pkey_query;
+struct kernel_pkey_params;
+
/*
* key under-construction record
* - passed to the request_key actor if supplied
@@ -147,6 +150,14 @@ struct key_type {
*/
request_key_actor_t request_key;
+ /* Asymmetric key accessor functions. */
+ int (*asym_query)(const struct kernel_pkey_params *params,
+ struct kernel_pkey_query *info);
+ int (*asym_eds_op)(struct kernel_pkey_params *params,
+ const void *in, void *out);
+ int (*asym_verify_signature)(struct kernel_pkey_params *params,
+ const void *in, const void *in2);
+
/* internal fields */
struct list_head link; /* link in types list */
struct lock_class_key lock_class; /* key->sem lock class */
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h
new file mode 100644
index 000000000000..e89b4a4e43d0
--- /dev/null
+++ b/include/linux/keyctl.h
@@ -0,0 +1,46 @@
+/* keyctl kernel bits
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef __LINUX_KEYCTL_H
+#define __LINUX_KEYCTL_H
+
+#include <uapi/linux/keyctl.h>
+
+struct kernel_pkey_query {
+ __u32 supported_ops; /* Which ops are supported */
+ __u32 key_size; /* Size of the key in bits */
+ __u16 max_data_size; /* Maximum size of raw data to sign in bytes */
+ __u16 max_sig_size; /* Maximum size of signature in bytes */
+ __u16 max_enc_size; /* Maximum size of encrypted blob in bytes */
+ __u16 max_dec_size; /* Maximum size of decrypted blob in bytes */
+};
+
+enum kernel_pkey_operation {
+ kernel_pkey_encrypt,
+ kernel_pkey_decrypt,
+ kernel_pkey_sign,
+ kernel_pkey_verify,
+};
+
+struct kernel_pkey_params {
+ struct key *key;
+ const char *encoding; /* Encoding (eg. "oaep" or NULL for raw) */
+ const char *hash_algo; /* Digest algorithm used (eg. "sha1") or NULL if N/A */
+ char *info; /* Modified info string to be released later */
+ __u32 in_len; /* Input data size */
+ union {
+ __u32 out_len; /* Output buffer size (enc/dec/sign) */
+ __u32 in2_len; /* 2nd input data size (verify) */
+ };
+ enum kernel_pkey_operation op : 8;
+};
+
+#endif /* __LINUX_KEYCTL_H */
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 86eddd6241f3..8ac2c5fbc8fc 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -68,4 +68,9 @@ struct keyctl_dh_params {
__s32 base;
};
+#define KEYCTL_SUPPORTS_ENCRYPT 0x01
+#define KEYCTL_SUPPORTS_DECRYPT 0x02
+#define KEYCTL_SUPPORTS_SIGN 0x04
+#define KEYCTL_SUPPORTS_VERIFY 0x08
+
#endif /* _LINUX_KEYCTL_H */
^ permalink raw reply related
* [PATCH 0/8] KEYS: keyctl operations for asymmetric keys [ver #2]
From: David Howells @ 2016-06-23 13:47 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
Here's a set of patches that provides keyctl access for asymmetric keys,
including a query function, and functions to do encryption, decryption,
signature creation and signature verification.
I've added a PKCS#8 asymmetric key parser so that you can load an RSA private
key into the kernel. Currently only DER-encoded and unencrypted PKCS#8 is
supported. Encryption and verification can use a public key from an X.509
cert, but signing and decryption require a private key, though encryption and
verification can use that too.
Example usage:
j=`openssl pkcs8 -in private_key.pem -topk8 -nocrypt -outform DER | \
keyctl padd asymmetric foo @s`
echo -n abcdefghijklmnopqrst >/tmp/data
keyctl pkey_encrypt $j /tmp/data enc=pkcs1 >/tmp/enc
keyctl pkey_decrypt $j /tmp/enc enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec
keyctl pkey_sign $j /tmp/data enc=pkcs1 hash=sha1 >/tmp/sig
keyctl pkey_verify $j /tmp/data /tmp/sig enc=pkcs1 hash=sha1
Changes:
(*) I've taken out the password parameters for the moment as there isn't
yet a subtype that uses them. I have, however, left space in the
keyctl UAPI to add them back later.
The kernel patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-asym-keyctl
The keyutils changes needed can be found here:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/keyutils.git/log/?h=pkey
David
---
David Howells (8):
KEYS: Provide key type operations for asymmetric key ops
KEYS: Provide keyctls to drive the new key type ops for asymmetric keys
KEYS: Provide missing asymmetric key subops for new key type ops
KEYS: Make the X.509 and PKCS7 parsers supply the sig encoding type
KEYS: Provide software public key query function
KEYS: Allow the public_key struct to hold a private key
KEYS: Implement encrypt, decrypt and sign for software asymmetric key
KEYS: Implement PKCS#8 RSA Private Key parser
Documentation/crypto/asymmetric-keys.txt | 26 ++
Documentation/security/keys.txt | 217 +++++++++++++++++++
crypto/asymmetric_keys/Kconfig | 10 +
crypto/asymmetric_keys/Makefile | 13 +
crypto/asymmetric_keys/asymmetric_keys.h | 3
crypto/asymmetric_keys/asymmetric_type.c | 59 +++++
crypto/asymmetric_keys/pkcs7_parser.c | 1
crypto/asymmetric_keys/pkcs8.asn1 | 24 ++
crypto/asymmetric_keys/pkcs8_parser.c | 184 +++++++++++++++++
crypto/asymmetric_keys/public_key.c | 195 ++++++++++++++++--
crypto/asymmetric_keys/signature.c | 95 +++++++++
crypto/asymmetric_keys/x509_cert_parser.c | 21 +-
include/crypto/public_key.h | 14 +
include/keys/asymmetric-subtype.h | 9 +
include/linux/key-type.h | 11 +
include/linux/keyctl.h | 46 ++++
include/uapi/linux/keyctl.h | 30 +++
security/keys/Makefile | 1
security/keys/compat.c | 18 ++
security/keys/internal.h | 39 ++++
security/keys/keyctl.c | 24 ++
security/keys/keyctl_pkey.c | 323 +++++++++++++++++++++++++++++
22 files changed, 1319 insertions(+), 44 deletions(-)
create mode 100644 crypto/asymmetric_keys/pkcs8.asn1
create mode 100644 crypto/asymmetric_keys/pkcs8_parser.c
create mode 100644 include/linux/keyctl.h
create mode 100644 security/keys/keyctl_pkey.c
^ permalink raw reply
* [PATCH 0/8] KEYS: keyctl operations for asymmetric keys
From: David Howells @ 2016-06-23 13:47 UTC (permalink / raw)
To: mathew.j.martineau, dwmw2, tadeusz.struk
Cc: dhowells, linux-security-module, keyrings, linux-kernel,
linux-crypto
Here's a set of patches that provides keyctl access for asymmetric keys,
including a query function, and functions to do encryption, decryption,
signature creation and signature verification.
I've added a PKCS#8 asymmetric key parser so that you can load an RSA private
key into the kernel. Currently only DER-encoded and unencrypted PKCS#8 is
supported. Encryption and verification can use a public key from an X.509
cert, but signing and decryption require a private key, though encryption and
verification can use that too.
Example usage:
j=`openssl pkcs8 -in private_key.pem -topk8 -nocrypt -outform DER | \
keyctl padd asymmetric foo @s`
echo -n abcdefghijklmnopqrst >/tmp/data
keyctl pkey_encrypt $j /tmp/data enc=pkcs1 >/tmp/enc
keyctl pkey_decrypt $j /tmp/enc enc=pkcs1 >/tmp/dec
cmp /tmp/data /tmp/dec
keyctl pkey_sign $j /tmp/data enc=pkcs1 hash=sha1 >/tmp/sig
keyctl pkey_verify $j /tmp/data /tmp/sig enc=pkcs1 hash=sha1
Changes:
(*) I've taken out the password parameters for the moment as there isn't
yet a subtype that uses them. I have, however, left space in the
keyctl UAPI to add them back later.
The kernel patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-asym-keyctl
The keyutils changes needed can be found here:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/keyutils.git/log/?h=pkey
David
---
David Howells (8):
KEYS: Provide key type operations for asymmetric key ops
KEYS: Provide keyctls to drive the new key type ops for asymmetric keys
KEYS: Provide missing asymmetric key subops for new key type ops
KEYS: Make the X.509 and PKCS7 parsers supply the sig encoding type
KEYS: Provide software public key query function
KEYS: Allow the public_key struct to hold a private key
KEYS: Implement encrypt, decrypt and sign for software asymmetric key
KEYS: Implement PKCS#8 RSA Private Key parser
Documentation/crypto/asymmetric-keys.txt | 26 ++
Documentation/security/keys.txt | 217 +++++++++++++++++++
crypto/asymmetric_keys/Kconfig | 10 +
crypto/asymmetric_keys/Makefile | 13 +
crypto/asymmetric_keys/asymmetric_keys.h | 3
crypto/asymmetric_keys/asymmetric_type.c | 59 +++++
crypto/asymmetric_keys/pkcs7_parser.c | 1
crypto/asymmetric_keys/pkcs8.asn1 | 24 ++
crypto/asymmetric_keys/pkcs8_parser.c | 184 +++++++++++++++++
crypto/asymmetric_keys/public_key.c | 195 ++++++++++++++++--
crypto/asymmetric_keys/signature.c | 95 +++++++++
crypto/asymmetric_keys/x509_cert_parser.c | 21 +-
include/crypto/public_key.h | 14 +
include/keys/asymmetric-subtype.h | 9 +
include/linux/key-type.h | 11 +
include/linux/keyctl.h | 46 ++++
include/uapi/linux/keyctl.h | 30 +++
security/keys/Makefile | 1
security/keys/compat.c | 18 ++
security/keys/internal.h | 39 ++++
security/keys/keyctl.c | 24 ++
security/keys/keyctl_pkey.c | 323 +++++++++++++++++++++++++++++
22 files changed, 1319 insertions(+), 44 deletions(-)
create mode 100644 crypto/asymmetric_keys/pkcs8.asn1
create mode 100644 crypto/asymmetric_keys/pkcs8_parser.c
create mode 100644 include/linux/keyctl.h
create mode 100644 security/keys/keyctl_pkey.c
^ permalink raw reply
* Re: [PATCH v6 2/8] crypto: add driver-side scomp interface
From: Herbert Xu @ 2016-06-23 10:50 UTC (permalink / raw)
To: Giovanni Cabiddu; +Cc: linux-crypto
In-Reply-To: <20160622155350.GA22247@sivswdev01.ir.intel.com>
On Wed, Jun 22, 2016 at 04:53:50PM +0100, Giovanni Cabiddu wrote:
> On Mon, Jun 13, 2016 at 04:56:12PM +0800, Herbert Xu wrote:
> > The backup path is also very unlikely to work because we'll be
> > hitting this with 64K sizes and this just won't work with a 4K
> > page size.
> Is scatterwalk_map_and_copy broken?
No that's not the problem. The problem is that you can't kmalloc
64K of memory. kmalloc requires physically contiguous memory and
you cannot rely on having 64K of contiguous memory.
> > This totally breaks down once you go to DMA, where an SG list is
> > required.
> scomp backends should be used only for software implementations.
> A driver backend which needs DMA should plug into acomp.
What I'm saying is that the current strategy of using vmalloc
memory as input/output buffers cannot possibly work with acomp
since you cannot do DMA over vmalloc memory.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] crypto : async implementation for sha1-mb
From: Herbert Xu @ 2016-06-23 10:45 UTC (permalink / raw)
To: Megha Dey
Cc: tim.c.chen, davem, linux-crypto, linux-kernel, fenghua.yu,
Megha Dey
In-Reply-To: <1466558506-3189-1-git-send-email-megha.dey@intel.com>
On Tue, Jun 21, 2016 at 06:21:46PM -0700, Megha Dey wrote:
> From: Megha Dey <megha.dey@linux.intel.com>
>
> Herbert wants the sha1-mb algorithm to have an async implementation:
> https://lkml.org/lkml/2016/4/5/286.
> Currently, sha1-mb uses an async interface for the outer algorithm
> and a sync interface for the inner algorithm. This patch introduces
> a async interface for even the inner algorithm.
>
> Signed-off-by: Megha Dey <megha.dey@linux.intel.com>
> Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Patch applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH v3 02/10] crypto: marvell: Check engine is not already running when enabling a req
From: Herbert Xu @ 2016-06-23 10:44 UTC (permalink / raw)
To: Romain Perier
Cc: boris.brezillon, arno, gregory.clement, thomas.petazzoni, davem,
linux, linux-crypto, linux-arm-kernel
In-Reply-To: <576A753B.7070507@free-electrons.com>
On Wed, Jun 22, 2016 at 01:23:39PM +0200, Romain Perier wrote:
> Hello,
>
> Le 22/06/2016 12:33, Herbert Xu a écrit :
> >Romain Perier <romain.perier@free-electrons.com> wrote:
> >>Add a BUG_ON() call when the driver tries to launch a crypto request
> >>while the engine is still processing the previous one. This replaces
> >>a silent system hang by a verbose kernel panic with the associated
> >>backtrace to let the user know that something went wrong in the CESA
> >>driver.
> >
> >Hmm, so how can this happen?
> If it is triggerable then we better
> >try to recover from it more gracefully. If it is not triggerable
> >then why bother?
> >
>
> Well, It does not happen with the current driver (in mainline). This
> is bug I had when I added support to chain requests. Take a look at
> the patch 008/010, it changes the way the requests are "prepared".
> If you really enable a request while the engine is running, that's
> very hard to debug. This is more useful to have a backtrace to let
> the user know that something is wrong instead of having a silent
> system hang. That's easier to debug and you can detect regressions.
OK. All applied. Thanks.
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH v11 0/3] Key-agreement Protocol Primitives (KPP) API
From: Herbert Xu @ 2016-06-23 10:44 UTC (permalink / raw)
To: Salvatore Benedetto; +Cc: linux-crypto
In-Reply-To: <1466614155-24840-1-git-send-email-salvatore.benedetto@intel.com>
On Wed, Jun 22, 2016 at 05:49:12PM +0100, Salvatore Benedetto wrote:
> Hi Herb,
>
> the following patchset introduces a new API for abstracting key-agreement
> protocols such as DH and ECDH. It provides the primitives required for implementing
> the protocol, thus the name KPP (Key-agreement Protocol Primitives).
>
> Regards,
> Salvatore
>
> Changes from v10:
> * Remove all DH/ECDH code from testmgr. Secret is now encoded both
> in little and big endian in the testvector
All applied. Thanks!
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: [PATCH] crypto: user - re-add size check for CRYPTO_MSG_GETALG
From: Herbert Xu @ 2016-06-23 10:43 UTC (permalink / raw)
To: Mathias Krause; +Cc: David S. Miller, linux-crypto, Steffen Klassert
In-Reply-To: <1466620177-10998-1-git-send-email-minipli@googlemail.com>
On Wed, Jun 22, 2016 at 08:29:37PM +0200, Mathias Krause wrote:
> Commit 9aa867e46565 ("crypto: user - Add CRYPTO_MSG_DELRNG")
> accidentally removed the minimum size check for CRYPTO_MSG_GETALG
> netlink messages. This allows userland to send a truncated
> CRYPTO_MSG_GETALG message as short as a netlink header only making
> crypto_report() operate on uninitialized memory by accessing data
> beyond the end of the netlink message.
>
> Fix this be re-adding the minimum required size of CRYPTO_MSG_GETALG
> messages to the crypto_msg_min[] array.
>
> Fixes: 9aa867e46565 ("crypto: user - Add CRYPTO_MSG_DELRNG")
> Cc: stable@vger.kernel.org # v4.2
> Signed-off-by: Mathias Krause <minipli@googlemail.com>
> Cc: Steffen Klassert <steffen.klassert@secunet.com>
> ---
> This should go on top of crypto-2.6/master.
Patch applied to crypto. Thanks!
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
* Re: Doing crypto in small stack buffers (bluetooth vs vmalloc-stack crash, etc)
From: Herbert Xu @ 2016-06-23 6:41 UTC (permalink / raw)
To: Andy Lutomirski
Cc: Andy Lutomirski, linux-bluetooth, Johan Hedberg, Gustavo Padovan,
Marcel Holtmann, linux-crypto, David S. Miller,
linux-kernel@vger.kernel.org, Linus Torvalds, netdev
In-Reply-To: <20160623034825.GB7819@gondor.apana.org.au>
On Thu, Jun 23, 2016 at 11:48:25AM +0800, Herbert Xu wrote:
>
> No we never had such an API in the kernel. However, I see that
> rxkad does some pretty silly things and we should be able to avoid
> using the stack in pretty much all cases. Let me try to come up with
> something.
Here it is:
---8<---
Subject: rxrpc: Avoid using stack memory in SG lists in rxkad
rxkad uses stack memory in SG lists which would not work if stacks
were allocated from vmalloc memory. In fact, in most cases this
isn't even necessary as the stack memory ends up getting copied
over to kmalloc memory.
This patch eliminates all the unnecessary stack memory uses by
supplying the final destination directly to the crypto API. In
two instances where a temporary buffer is actually needed we also
switch use the skb->cb area instead of the stack.
Finally there is no need to split a split-page buffer into two SG
entries so code dealing with that has been removed.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index f0b807a..8ee5933 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -277,6 +277,7 @@ struct rxrpc_connection {
struct key *key; /* security for this connection (client) */
struct key *server_key; /* security for this service */
struct crypto_skcipher *cipher; /* encryption handle */
+ struct rxrpc_crypt csum_iv_head; /* leading block for csum_iv */
struct rxrpc_crypt csum_iv; /* packet checksum base */
unsigned long events;
#define RXRPC_CONN_CHALLENGE 0 /* send challenge packet */
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index 6b726a0..ee142de 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -105,11 +105,9 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
{
struct rxrpc_key_token *token;
SKCIPHER_REQUEST_ON_STACK(req, conn->cipher);
- struct scatterlist sg[2];
+ struct rxrpc_crypt *csum_iv;
+ struct scatterlist sg;
struct rxrpc_crypt iv;
- struct {
- __be32 x[4];
- } tmpbuf __attribute__((aligned(16))); /* must all be in same page */
_enter("");
@@ -119,24 +117,21 @@ static void rxkad_prime_packet_security(struct rxrpc_connection *conn)
token = conn->key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
- tmpbuf.x[0] = htonl(conn->epoch);
- tmpbuf.x[1] = htonl(conn->cid);
- tmpbuf.x[2] = 0;
- tmpbuf.x[3] = htonl(conn->security_ix);
+ csum_iv = &conn->csum_iv_head;
+ csum_iv[0].x[0] = htonl(conn->epoch);
+ csum_iv[0].x[1] = htonl(conn->cid);
+ csum_iv[1].x[0] = 0;
+ csum_iv[1].x[1] = htonl(conn->security_ix);
- sg_init_one(&sg[0], &tmpbuf, sizeof(tmpbuf));
- sg_init_one(&sg[1], &tmpbuf, sizeof(tmpbuf));
+ sg_init_one(&sg, csum_iv, 16);
skcipher_request_set_tfm(req, conn->cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg[1], &sg[0], sizeof(tmpbuf), iv.x);
+ skcipher_request_set_crypt(req, &sg, &sg, 16, iv.x);
crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
- memcpy(&conn->csum_iv, &tmpbuf.x[2], sizeof(conn->csum_iv));
- ASSERTCMP((u32 __force)conn->csum_iv.n[0], ==, (u32 __force)tmpbuf.x[2]);
-
_leave("");
}
@@ -150,12 +145,9 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
{
struct rxrpc_skb_priv *sp;
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
+ struct rxkad_level1_hdr hdr;
struct rxrpc_crypt iv;
- struct scatterlist sg[2];
- struct {
- struct rxkad_level1_hdr hdr;
- __be32 first; /* first four bytes of data and padding */
- } tmpbuf __attribute__((aligned(8))); /* must all be in same page */
+ struct scatterlist sg;
u16 check;
sp = rxrpc_skb(skb);
@@ -165,24 +157,21 @@ static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
check = sp->hdr.seq ^ sp->hdr.callNumber;
data_size |= (u32)check << 16;
- tmpbuf.hdr.data_size = htonl(data_size);
- memcpy(&tmpbuf.first, sechdr + 4, sizeof(tmpbuf.first));
+ hdr.data_size = htonl(data_size);
+ memcpy(sechdr, &hdr, sizeof(hdr));
/* start the encryption afresh */
memset(&iv, 0, sizeof(iv));
- sg_init_one(&sg[0], &tmpbuf, sizeof(tmpbuf));
- sg_init_one(&sg[1], &tmpbuf, sizeof(tmpbuf));
+ sg_init_one(&sg, sechdr, 8);
skcipher_request_set_tfm(req, call->conn->cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg[1], &sg[0], sizeof(tmpbuf), iv.x);
+ skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
- memcpy(sechdr, &tmpbuf, sizeof(tmpbuf));
-
_leave(" = 0");
return 0;
}
@@ -196,8 +185,7 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
void *sechdr)
{
const struct rxrpc_key_token *token;
- struct rxkad_level2_hdr rxkhdr
- __attribute__((aligned(8))); /* must be all on one page */
+ struct rxkad_level2_hdr rxkhdr;
struct rxrpc_skb_priv *sp;
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
struct rxrpc_crypt iv;
@@ -216,17 +204,17 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
rxkhdr.data_size = htonl(data_size | (u32)check << 16);
rxkhdr.checksum = 0;
+ memcpy(sechdr, &rxkhdr, sizeof(rxkhdr));
/* encrypt from the session key */
token = call->conn->key->payload.data[0];
memcpy(&iv, token->kad->session_key, sizeof(iv));
sg_init_one(&sg[0], sechdr, sizeof(rxkhdr));
- sg_init_one(&sg[1], &rxkhdr, sizeof(rxkhdr));
skcipher_request_set_tfm(req, call->conn->cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg[1], &sg[0], sizeof(rxkhdr), iv.x);
+ skcipher_request_set_crypt(req, &sg[0], &sg[0], sizeof(rxkhdr), iv.x);
crypto_skcipher_encrypt(req);
@@ -265,10 +253,11 @@ static int rxkad_secure_packet(const struct rxrpc_call *call,
struct rxrpc_skb_priv *sp;
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
struct rxrpc_crypt iv;
- struct scatterlist sg[2];
- struct {
+ struct scatterlist sg;
+ union {
__be32 x[2];
- } tmpbuf __attribute__((aligned(8))); /* must all be in same page */
+ __be64 xl;
+ } tmpbuf;
u32 x, y;
int ret;
@@ -294,16 +283,19 @@ static int rxkad_secure_packet(const struct rxrpc_call *call,
tmpbuf.x[0] = htonl(sp->hdr.callNumber);
tmpbuf.x[1] = htonl(x);
- sg_init_one(&sg[0], &tmpbuf, sizeof(tmpbuf));
- sg_init_one(&sg[1], &tmpbuf, sizeof(tmpbuf));
+ swap(tmpbuf.xl, *(__be64 *)sp);
+
+ sg_init_one(&sg, sp, sizeof(tmpbuf));
skcipher_request_set_tfm(req, call->conn->cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg[1], &sg[0], sizeof(tmpbuf), iv.x);
+ skcipher_request_set_crypt(req, &sg, &sg, sizeof(tmpbuf), iv.x);
crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
+ swap(tmpbuf.xl, *(__be64 *)sp);
+
y = ntohl(tmpbuf.x[1]);
y = (y >> 16) & 0xffff;
if (y == 0)
@@ -503,10 +495,11 @@ static int rxkad_verify_packet(const struct rxrpc_call *call,
SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
struct rxrpc_skb_priv *sp;
struct rxrpc_crypt iv;
- struct scatterlist sg[2];
- struct {
+ struct scatterlist sg;
+ union {
__be32 x[2];
- } tmpbuf __attribute__((aligned(8))); /* must all be in same page */
+ __be64 xl;
+ } tmpbuf;
u16 cksum;
u32 x, y;
int ret;
@@ -534,16 +527,19 @@ static int rxkad_verify_packet(const struct rxrpc_call *call,
tmpbuf.x[0] = htonl(call->call_id);
tmpbuf.x[1] = htonl(x);
- sg_init_one(&sg[0], &tmpbuf, sizeof(tmpbuf));
- sg_init_one(&sg[1], &tmpbuf, sizeof(tmpbuf));
+ swap(tmpbuf.xl, *(__be64 *)sp);
+
+ sg_init_one(&sg, sp, sizeof(tmpbuf));
skcipher_request_set_tfm(req, call->conn->cipher);
skcipher_request_set_callback(req, 0, NULL, NULL);
- skcipher_request_set_crypt(req, &sg[1], &sg[0], sizeof(tmpbuf), iv.x);
+ skcipher_request_set_crypt(req, &sg, &sg, sizeof(tmpbuf), iv.x);
crypto_skcipher_encrypt(req);
skcipher_request_zero(req);
+ swap(tmpbuf.xl, *(__be64 *)sp);
+
y = ntohl(tmpbuf.x[1]);
cksum = (y >> 16) & 0xffff;
if (cksum == 0)
@@ -708,26 +704,13 @@ static void rxkad_calc_response_checksum(struct rxkad_response *response)
}
/*
- * load a scatterlist with a potentially split-page buffer
+ * load a scatterlist
*/
-static void rxkad_sg_set_buf2(struct scatterlist sg[2],
+static void rxkad_sg_set_buf2(struct scatterlist sg[1],
void *buf, size_t buflen)
{
- int nsg = 1;
-
- sg_init_table(sg, 2);
-
+ sg_init_table(sg, 1);
sg_set_buf(&sg[0], buf, buflen);
- if (sg[0].offset + buflen > PAGE_SIZE) {
- /* the buffer was split over two pages */
- sg[0].length = PAGE_SIZE - sg[0].offset;
- sg_set_buf(&sg[1], buf + sg[0].length, buflen - sg[0].length);
- nsg++;
- }
-
- sg_mark_end(&sg[nsg - 1]);
-
- ASSERTCMP(sg[0].length + sg[1].length, ==, buflen);
}
/*
@@ -739,7 +722,7 @@ static void rxkad_encrypt_response(struct rxrpc_connection *conn,
{
SKCIPHER_REQUEST_ON_STACK(req, conn->cipher);
struct rxrpc_crypt iv;
- struct scatterlist sg[2];
+ struct scatterlist sg[1];
/* continue encrypting from where we left off */
memcpy(&iv, s2->session_key, sizeof(iv));
@@ -999,7 +982,7 @@ static void rxkad_decrypt_response(struct rxrpc_connection *conn,
const struct rxrpc_crypt *session_key)
{
SKCIPHER_REQUEST_ON_STACK(req, rxkad_ci);
- struct scatterlist sg[2];
+ struct scatterlist sg[1];
struct rxrpc_crypt iv;
_enter(",,%08x%08x",
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply related
* Re: [PATCH v6 3/6] crypto: AF_ALG -- add asymmetric cipher interface
From: Stephan Mueller @ 2016-06-23 5:07 UTC (permalink / raw)
To: Mat Martineau
Cc: Tadeusz Struk, dhowells-H+wXaHxf7aLQT0dZR+AlfA,
herbert-lOAM2aK0SrRLBo1qDEOMRrpzq4S04n8Q,
linux-api-u79uwXL29TY76Z2rM5mHXA, marcel-kz+m5ild9QBg9hUCZPvPmw,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
keyrings-u79uwXL29TY76Z2rM5mHXA,
linux-crypto-u79uwXL29TY76Z2rM5mHXA, dwmw2-wEGCiKHe2LqWVfeAwA7xHQ,
davem-fT/PcQaiUtIeIZ0/mPfg9Q
In-Reply-To: <alpine.OSX.2.20.1606221515040.16377-zaFMaa3cLiZe6KzckbbZvYT4S9po1h25@public.gmane.org>
Am Mittwoch, 22. Juni 2016, 15:45:38 schrieb Mat Martineau:
Hi Mat,
> >
> > Ok, I'll update the patch.
>
> Thanks, that helps (especially with pkcs1pad).
Tadeusz received the updated patch from me to integrate it into his patch set.
>
> This brings me to another proposal for read buffer sizing: AF_ALG akcipher
> can guarantee that partial reads (where the read buffer is shorter than
> the output of the crypto op) will work using the same semantics as
> SOCK_DGRAM/SOCK_SEQPACKET. With those sockets, as much data as will fit is
> copied in to the read buffer and the remainder is discarded.
>
> I realize there's a performance and memory tradeoff, since the crypto
> algorithm needs a sufficiently large output buffer that would have to be
> created by AF_ALG akcipher. The user could manage that tradeoff by
> providing a larger buffer (typically key_size?) if it wants to avoid
> allocating and copying intermediate buffers inside the kernel.
How shall the user know that something got truncated or that the kernel
created memory?
Ciao
Stephan
^ permalink raw reply
* Re: [PATCHv2 00/27] crypto: fixes for omap family of devices
From: Tony Lindgren @ 2016-06-23 4:49 UTC (permalink / raw)
To: Tero Kristo
Cc: linux-omap, linux-crypto, herbert, davem, lokeshvutla,
linux-arm-kernel
In-Reply-To: <1466601840-18486-1-git-send-email-t-kristo@ti.com>
* Tero Kristo <t-kristo@ti.com> [160622 06:27]:
> Hi,
>
> Changes compared to v1 of the series:
>
> - dropped first patch from the series (crypto: omap-aes: Fix registration of
> algorithms) as it was queued by Herbert already
> - modified the second (now first) patch of the series to use runtime auto-
> suspend instead of getting static sync over a cra lifetime
> - re-ordered the DTS / hwmod changes in the series, the merge order of
> these must be maintained to avoid issues
>
> Patches #01 .. #14 should be merged via crypto tree, the rest should be
> handled by Tony.
Next time, please post sets like these split into three separate sets
with the cover letter listing possible dependencies. Picking patches
from sets in certain order is a big pain to follow up, and some
maintainers tend to ignore patchsets with dependencies.
> Merging the omap / dts parts can be done safely separately, assuming
> you just use omap2plus_defconfig (enabling crypto features will
> cause some issues without the driver level fixes.)
I've already applied the dts changes I believe.. So reposting already
applied patches further confuses things. Now I have to figure out what
is already applied..
Regards,
Tony
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox