[RFC PATCH] KEYS: Provide keyctls to do public key operations [ver #2]

2016-04-16 Thread David Howells
Here's v2 of the patch with the reported errors fixed.  It's still untested by
me, however.

David
---
KEYS: Provide keyctls to do public key operations

From: David Howells 

Provide keyctl functions to do public key operations (sign, verify, encrypt
and decrypt) if the target key supports them, plus a query function to find
out about the key.

Not-yet-signed-off-by: David Howells 
---
 Documentation/security/keys.txt   |  105 +
 crypto/asymmetric_keys/pkcs7_parser.c |1 
 crypto/asymmetric_keys/public_key.c   |   38 +++
 crypto/asymmetric_keys/signature.c|  150 +
 crypto/asymmetric_keys/x509_cert_parser.c |   21 +-
 include/crypto/public_key.h   |   13 +
 include/keys/asymmetric-subtype.h |   13 +
 include/linux/keyctl.h|   36 +++
 include/uapi/linux/keyctl.h   |   27 ++
 security/keys/Makefile|1 
 security/keys/compat.c|   11 +
 security/keys/internal.h  |   35 +++
 security/keys/keyctl.c|   21 ++
 security/keys/keyctl_pkey.c   |  325 +
 14 files changed, 782 insertions(+), 15 deletions(-)
 create mode 100644 include/linux/keyctl.h
 create mode 100644 security/keys/keyctl_pkey.c

diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 20d05719bceb..de90cdaa1a4e 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -854,6 +854,111 @@ 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,
+   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 decypted.
+
+ 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 *data,
+   void *enc);
+
+   long keyctl(KEYCTL_PKEY_DECRYPT,
+   const struct keyctl_pkey_params *params,
+   const char *info,
+   const void *enc,
+   void *data);
+
+   long keyctl(KEYCTL_PKEY_SIGN,
+   const struct keyctl_pkey_params *params,
+   const char *info,
+   const void *data,
+   void *enc);
+
+   long keyctl(KEYCTL_PKEY_VERIFY,
+   const struct keyctl_pkey_params *params,
+   const char *info,
+   const void *data,
+   const void *enc);
+
+ 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;
+   __s32   password_id;
+   __u32   data_len;
+   __u32   enc_len;
+
+ key_id is the ID of the asymmetric key to be used.  data_len indicates the
+ length of the data or buffer pointed to by data whilst enc_len indicates
+ the length of the data or buffer pointed to by enc.
+
+ If the key must be unlocked with a password before it can be used,
+ password_id should point to a logon-type key that holds this.
+
+ info is a string of key=value pairs that supply supplementary
+ information.  These include:
+
+   enc=  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= If the data buffer contains the output of a hash
+   function 

Re: [RFC PATCH] KEYS: Provide keyctls to do public key operations

2016-04-16 Thread David Howells
Mat Martineau  wrote:

> > The interface for the active ops is a bit clunky as the syscall interface
> > doesn't provide sufficient argument space to pass everything I need to
> > specify.  Some basic integer arguments are specified in a struct and more
> > complex options through a string of key=val pairs - just so I don't have to
> > deal with the compat code for dealing with a struct containing pointers
> > (but I can change to that if it's preferable).
>
> It sounds like the struct would still have pointers to strings that would
> need parsing,

It doesn't:

struct keyctl_pkey_params {
__s32   key_id;
__s32   password_id;
__u32   data_len;
__u32   enc_len;
__u32   __spare[4];
};

because I have sufficient syscall arguments to pass four pointers - the struct
above, one info string and two buffer pointers.

> so I'm not sure it's that much overhead to handle the short
> strings of key=val pairs. But I'll agree that it feels clunky.

... fixes applied ...

> > +   info->supported_ops = KEYCTL_SUPPORTS_VERIFY;
> 
> Did you intend to include encrypt/decrypt/sign here?

When they're implemented there.

David
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] KEYS: Provide keyctls to do public key operations

2016-04-15 Thread Mat Martineau


On Thu, 14 Apr 2016, David Howells wrote:


The interface for the active ops is a bit clunky as the syscall interface
doesn't provide sufficient argument space to pass everything I need to
specify.  Some basic integer arguments are specified in a struct and more
complex options through a string of key=val pairs - just so I don't have to
deal with the compat code for dealing with a struct containing pointers
(but I can change to that if it's preferable).


It sounds like the struct would still have pointers to strings that would 
need parsing, so I'm not sure it's that much overhead to handle the short 
strings of key=val pairs. But I'll agree that it feels clunky.



diff --git a/crypto/asymmetric_keys/public_key.c 
b/crypto/asymmetric_keys/public_key.c
index fd76b5fc3b3a..3a38b177df89 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -57,6 +57,40 @@ static void public_key_destroy(void *payload0, void 
*payload3)
public_key_signature_free(payload3);
}

+/*
+ * Query information about a key.
+ */
+static int software_key_query(const struct key *key,
+ struct kernel_pkey_query *info)
+{
+   struct crypto_akcipher *tfm;
+   struct public_key *pkey = key->payload.data[asym_crypto];
+   int ret, len;
+
+   tfm = crypto_alloc_akcipher(pkey->pkey_algo, 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) * 8;


An extra multiply here.


+   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;


Did you intend to include encrypt/decrypt/sign here?



diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 86eddd6241f3..d9e865ddee8a 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_ENCRYPT25  /* Encrypt a blob using a 
public key */
+#define KEYCTL_PKEY_DECRYPT26  /* 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 {
@@ -68,4 +73,26 @@ struct keyctl_dh_params {
__s32 base;
};

+struct keyctl_pkey_query {
+   __u32   supported_ops;  /* Which ops are supported */
+#define KEYCTL_SUPPORTS_ENCRYPT0x01
+#define KEYCTL_SUPPORTS_DECRYPT0x02
+#define KEYCTL_SUPPORTS_SIGN   0x04
+#define KEYCTL_SUPPORTS_VERIFY 0x05


0x08 for KEYCTL_SUPPORTS_VERIFY?



diff --git a/security/keys/keyctl_pkey.c b/security/keys/keyctl_pkey.c
new file mode 100644
index ..c903e7469beb
--- /dev/null
+++ b/security/keys/keyctl_pkey.c
@@ -0,0 +1,324 @@
+/* Public-key operation keyctls
+ *
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowe...@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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "internal.h"
+
+/*
+ * Query information about an asymmetric key.
+ */
+long keyctl_pkey_query(key_serial_t id,  struct keyctl_pkey_query __user *_res)
+{
+   struct kernel_pkey_query res;
+   struct key *key;
+   key_ref_t key_ref;
+   long ret;
+
+   key_ref = lookup_user_key(id, 0, KEY_NEED_READ);
+   if (IS_ERR(key_ref))
+   return PTR_ERR(key_ref);
+
+   key = key_ref_to_ptr(key_ref);
+
+   ret = query_asymmetric_key(key, );
+   if (ret < 0)
+   goto error_key;
+
+   ret = -EFAULT;
+   if (copy_to_user(_res, , sizeof(res)) == 0 &&
+   clear_user(_res->__spare, sizeof(_res->__spare)) == 0)
+   ret = 0;
+
+error_key:
+   key_put(key);
+   return ret;
+}
+
+static void keyctl_pkey_params_free(struct kernel_pkey_params *params)
+{
+   kfree(params->info);
+   key_put(params->key);
+   key_put(params->password);
+}
+
+enum {
+   Opt_err = -1,
+   Opt_enc,/* "enc=" eg. "enc=oaep" */



Re: [RFC PATCH] KEYS: Provide keyctls to do public key operations

2016-04-15 Thread David Howells
Tadeusz Struk  wrote:

> > --- a/crypto/asymmetric_keys/signature.c
> > +++ b/crypto/asymmetric_keys/signature.c
> 
> Since this file implements the enc/dec operations also
> should it be renamed to crypto/asymmetric_keys/public_key_ops.c
> or something similar? signature.c is a bit confusing now.

Yes.  Or maybe accessors.c.  I'm also tempted to merge it into
asymmetric_type.c.  One question is how many other ops we might want to add.

It might even be worth making the functions key_encrypt_blob(),
key_decrypt_blob(), key_create_signature() and key_verify_signature() and
jumping through the type ops table.  I still haven't decided whether I want to
go to that extent yet as it leads to an extra function call on the stack.

> This will work perfectly for the algif_akcipher. Thanks for providing this.
> I'm going to rebase my patches on top of this and resend.

Note that this is a bit thrown together.  I'm travelling right now and
conferencing next week which is why I haven't managed to test it yet - so
beware, there may be dragons;-)

> Should I use your keys-next as a base for the new version?

That's the base I used.

David
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [RFC PATCH] KEYS: Provide keyctls to do public key operations

2016-04-15 Thread Tadeusz Struk
Hi David,
On 04/14/2016 03:00 PM, David Howells wrote:
> diff --git a/crypto/asymmetric_keys/signature.c 
> b/crypto/asymmetric_keys/signature.c
> index 11b7ba170904..8ecbeda16b53 100644
> --- a/crypto/asymmetric_keys/signature.c
> +++ b/crypto/asymmetric_keys/signature.c

Since this file implements the enc/dec operations also
should it be renamed to crypto/asymmetric_keys/public_key_ops.c
or something similar? signature.c is a bit confusing now.

> +/**
> + * 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").
> + *
> + * If the key needs to be unlocked, a password can be supplied in a logon key
> + * specified by params->password.
> + *
> + * 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)
> +{
> + const struct asymmetric_key_subtype *subtype;
> + struct key *key = params->key;
> + int ret;
> +
> + pr_devel("==>%s()\n", __func__);
> +
> + if (key->type != _type_asymmetric)
> + return -EINVAL;
> + subtype = asymmetric_key_subtype(key);
> + if (!subtype ||
> + !key->payload.data[0])
> + return -EINVAL;
> + if (!subtype->encrypt_blob)
> + return -ENOTSUPP;
> +
> + ret = subtype->encrypt_blob(params, data, enc);
> +
> + pr_devel("<==%s() = %d\n", __func__, ret);
> + return ret;
> +}
> +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").
> + *
> + * If the private key needs to be unlocked, a password can be supplied in a
> + * logon key specified by params->password.
> + *
> + * 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)
> +{
> + const struct asymmetric_key_subtype *subtype;
> + struct key *key = params->key;
> + int ret;
> +
> + pr_devel("==>%s()\n", __func__);
> +
> + if (key->type != _type_asymmetric)
> + return -EINVAL;
> + subtype = asymmetric_key_subtype(key);
> + if (!subtype ||
> + !key->payload.data[0])
> + return -EINVAL;
> + if (!subtype->decrypt_blob)
> + return -ENOTSUPP;
> +
> + ret = subtype->decrypt_blob(params, enc, data);
> +
> + pr_devel("<==%s() = %d\n", __func__, ret);
> + return ret;
> +}
> +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").
> + *
> + * If the private key needs to be unlocked, a password can be supplied in a
> + * logon key specified by params->password.
> + *
> + * 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)
> +{
> + const struct asymmetric_key_subtype *subtype;
> + struct key *key = params->key;
> + int ret;
> +
> + pr_devel("==>%s()\n", __func__);
> +
> + if (key->type != _type_asymmetric)
> + return -EINVAL;
> + subtype = asymmetric_key_subtype(key);
> + if (!subtype ||
> + !key->payload.data[0])
> + return -EINVAL;
> + if (!subtype->create_signature)
> + return -ENOTSUPP;
> +
> + ret = subtype->create_signature(params, data, enc);
> +
> + pr_devel("<==%s() = %d\n", __func__, ret);
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(create_signature);

This will work perfectly for the algif_akcipher. Thanks for providing this.
I'm going to rebase my patches on top of this and resend.
Should I use your keys-next as a base for the new version?
Thanks,
-- 
TS
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in

[RFC PATCH] KEYS: Provide keyctls to do public key operations

2016-04-14 Thread David Howells
Here's a patch that does a first attempt at implementing keyctls for public
key operations using asymmetric-type keys.  This includes provision of a
query function.

[!] Note that whilst this patch compiles, it has not yet been tested.

I make the assumption that the asymmetric key type is the only one that
supports such things and call the asymmetric type accessor functions
directly rather than adding more key_type operations.  It would, however,
be cleaner to go through key_type ops - but would add an extra call into
the stack.

Encrypt, decrypt and sign ops could be combined with an argument to select
which op is desired.

The interface for the active ops is a bit clunky as the syscall interface
doesn't provide sufficient argument space to pass everything I need to
specify.  Some basic integer arguments are specified in a struct and more
complex options through a string of key=val pairs - just so I don't have to
deal with the compat code for dealing with a struct containing pointers
(but I can change to that if it's preferable).

I've specified data and enc buffer pointer for the keyctls, the order of
which are reversed for decrypt.  I'm tempted to change that to in and out
and just accept that for verify, out is actually an input.  I do not want
to pass data out for verify and then leave it to the caller to make the
comparison as I can't assume that hardware crypto will give me the computed
result of the verify crypto operation.

This patch really needs splitting into three: (1) internal op functions to
invoke the subtype (verify_signature() already exists in this set), (2) the
keyctl interface and (3) the software public key subtype methods.

I also have not yet implemented the hoop jumping in public_key.c to get the
software public key implementation to invoke the crypto layer to do the
missing three operations.

David
---
KEYS: Provide keyctls to do public key operations

Provide keyctl functions to do public key operations (sign, verify, encrypt
and decrypt) if the target key supports them, plus a query function to find
out about the key.

Not-yet-signed-off-by: David Howells 
---
 Documentation/security/keys.txt   |  105 +
 crypto/asymmetric_keys/pkcs7_parser.c |1 
 crypto/asymmetric_keys/public_key.c   |   38 +++
 crypto/asymmetric_keys/signature.c|  150 +
 crypto/asymmetric_keys/x509_cert_parser.c |   21 +-
 include/crypto/public_key.h   |   13 +
 include/keys/asymmetric-subtype.h |   13 +
 include/linux/keyctl.h|   36 +++
 include/uapi/linux/keyctl.h   |   27 ++
 security/keys/Makefile|1 
 security/keys/compat.c|   11 +
 security/keys/internal.h  |   35 +++
 security/keys/keyctl.c|   21 ++
 security/keys/keyctl_pkey.c   |  324 +
 14 files changed, 781 insertions(+), 15 deletions(-)
 create mode 100644 include/linux/keyctl.h
 create mode 100644 security/keys/keyctl_pkey.c

diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 20d05719bceb..8a0dbf289631 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -854,6 +854,111 @@ 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,
+   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 decypted.
+
+ 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 *data,
+   void *enc);
+
+   long keyctl(KEYCTL_PKEY_DECRYPT,
+   const struct keyctl_pkey_params *params,
+   const char *info,
+   const void *enc,
+   void *data);
+
+   long keyctl(KEYCTL_PKEY_SIGN,
+   const struct keyctl_pkey_params *params,
+   const char *info,
+