2019-05-20 20:08:01 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
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>
2018-10-09 19:46:59 +03:00
/* Public-key operation keyctls
*
* Copyright ( C ) 2016 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*/
# 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 {
2018-12-17 22:39:57 +03:00
Opt_err ,
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>
2018-10-09 19:46:59 +03:00
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 ) ;
2018-11-03 20:30:35 +03:00
if ( token = = Opt_err )
return - EINVAL ;
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>
2018-10-09 19:46:59 +03:00
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 ( & params , 0 , sizeof ( params ) ) ;
ret = keyctl_pkey_params_get ( id , _info , & params ) ;
if ( ret < 0 )
goto error ;
ret = params . key - > type - > asym_query ( & params , & 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 ( & params ) ;
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 , & params ) ;
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 ( & params , 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 ( & params ) ;
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 ,
& params ) ;
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 ( & params , in , in2 ) ;
kfree ( in2 ) ;
error_in :
kfree ( in ) ;
error_params :
keyctl_pkey_params_free ( & params ) ;
return ret ;
}