mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	KEYS: Provide keyctls to drive the new key type ops for asymmetric keys [ver #2]
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>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Denis Kenzior <denkenz@gmail.com>
Tested-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: James Morris <james.morris@microsoft.com>
			
			
This commit is contained in:
		
							parent
							
								
									70025f84e5
								
							
						
					
					
						commit
						00d60fd3b9
					
				
					 7 changed files with 541 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -859,6 +859,7 @@ The keyctl syscall functions are:
 | 
			
		|||
     and either the buffer length or the OtherInfo length exceeds the
 | 
			
		||||
     allowed length.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  *  Restrict keyring linkage::
 | 
			
		||||
 | 
			
		||||
	long keyctl(KEYCTL_RESTRICT_KEYRING, key_serial_t keyring,
 | 
			
		||||
| 
						 | 
				
			
			@ -890,6 +891,116 @@ The keyctl syscall functions are:
 | 
			
		|||
     applicable to the asymmetric key type.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  *  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;
 | 
			
		||||
	__u32	key_size;
 | 
			
		||||
	__u16	max_data_size;
 | 
			
		||||
	__u16	max_sig_size;
 | 
			
		||||
	__u16	max_enc_size;
 | 
			
		||||
	__u16	max_dec_size;
 | 
			
		||||
	__u32	__spare[10];
 | 
			
		||||
 | 
			
		||||
     ``supported_ops`` contains a bit mask of flags indicating which ops are
 | 
			
		||||
     supported.  This is constructed from a bitwise-OR of::
 | 
			
		||||
 | 
			
		||||
	KEYCTL_SUPPORTS_{ENCRYPT,DECRYPT,SIGN,VERIFY}
 | 
			
		||||
 | 
			
		||||
     ``key_size`` indicated the size of the key in bits.
 | 
			
		||||
 | 
			
		||||
     ``max_*_size`` indicate 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.
 | 
			
		||||
 | 
			
		||||
     ``__spare[]`` 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
 | 
			
		||||
===============
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,6 +61,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 */
 | 
			
		||||
#define KEYCTL_RESTRICT_KEYRING		29	/* Restrict keys allowed to link to a keyring */
 | 
			
		||||
 | 
			
		||||
/* keyctl structures */
 | 
			
		||||
| 
						 | 
				
			
			@ -87,4 +92,24 @@ struct keyctl_kdf_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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -141,6 +141,24 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
 | 
			
		|||
		return keyctl_restrict_keyring(arg2, compat_ptr(arg3),
 | 
			
		||||
					       compat_ptr(arg4));
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -298,6 +298,45 @@ static inline long compat_keyctl_dh_compute(
 | 
			
		|||
#endif
 | 
			
		||||
#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
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1747,6 +1747,30 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
 | 
			
		|||
					       (const char __user *) arg3,
 | 
			
		||||
					       (const char __user *) arg4);
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										323
									
								
								security/keys/keyctl_pkey.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								security/keys/keyctl_pkey.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in a new issue