2017-11-14 20:38:01 +03:00
// SPDX-License-Identifier: GPL-2.0
2016-11-02 16:37:20 +03:00
/*
* pkey device driver
*
* Copyright IBM Corp . 2017
* Author ( s ) : Harald Freudenberger
*/
# define KMSG_COMPONENT "pkey"
# define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
# include <linux/fs.h>
# include <linux/init.h>
# include <linux/miscdevice.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/kallsyms.h>
# include <linux/debugfs.h>
2018-08-23 11:06:26 +03:00
# include <linux/random.h>
2016-11-02 16:37:20 +03:00
# include <asm/zcrypt.h>
# include <asm/cpacf.h>
# include <asm/pkey.h>
2018-08-23 18:49:38 +03:00
# include <crypto/aes.h>
2016-11-02 16:37:20 +03:00
# include "zcrypt_api.h"
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " IBM Corporation " ) ;
MODULE_DESCRIPTION ( " s390 protected key interface " ) ;
/* Size of parameter block used for all cca requests/replies */
# define PARMBSIZE 512
/* Size of vardata block used for some of the cca requests/replies */
# define VARDATASIZE 4096
/*
* debug feature data and functions
*/
static debug_info_t * debug_info ;
# define DEBUG_DBG(...) debug_sprintf_event(debug_info, 6, ##__VA_ARGS__)
# define DEBUG_INFO(...) debug_sprintf_event(debug_info, 5, ##__VA_ARGS__)
# define DEBUG_WARN(...) debug_sprintf_event(debug_info, 4, ##__VA_ARGS__)
# define DEBUG_ERR(...) debug_sprintf_event(debug_info, 3, ##__VA_ARGS__)
static void __init pkey_debug_init ( void )
{
debug_info = debug_register ( " pkey " , 1 , 1 , 4 * sizeof ( long ) ) ;
debug_register_view ( debug_info , & debug_sprintf_view ) ;
debug_set_level ( debug_info , 3 ) ;
}
static void __exit pkey_debug_exit ( void )
{
debug_unregister ( debug_info ) ;
}
2018-08-23 17:28:16 +03:00
/* Key token types */
# define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */
# define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */
/* For TOKTYPE_NON_CCA: */
# define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */
/* For TOKTYPE_CCA_INTERNAL: */
# define TOKVER_CCA_AES 0x04 /* CCA AES key token */
2018-08-24 12:29:15 +03:00
/* header part of a key token */
struct keytoken_header {
u8 type ; /* one of the TOKTYPE values */
u8 res0 [ 3 ] ;
u8 version ; /* one of the TOKVER values */
u8 res1 [ 3 ] ;
} __packed ;
2016-11-02 16:37:20 +03:00
/* inside view of a secure key token (only type 0x01 version 0x04) */
struct secaeskeytoken {
u8 type ; /* 0x01 for internal key token */
u8 res0 [ 3 ] ;
u8 version ; /* should be 0x04 */
u8 res1 [ 1 ] ;
u8 flag ; /* key flags */
u8 res2 [ 1 ] ;
u64 mkvp ; /* master key verification pattern */
u8 key [ 32 ] ; /* key value (encrypted) */
u8 cv [ 8 ] ; /* control vector */
u16 bitsize ; /* key bit size */
u16 keysize ; /* key byte size */
u8 tvv [ 4 ] ; /* token validation value */
} __packed ;
2018-08-23 17:28:16 +03:00
/* inside view of a protected key token (only type 0x00 version 0x01) */
struct protaeskeytoken {
u8 type ; /* 0x00 for PAES specific key tokens */
u8 res0 [ 3 ] ;
u8 version ; /* should be 0x01 for protected AES key token */
u8 res1 [ 3 ] ;
u32 keytype ; /* key type, one of the PKEY_KEYTYPE values */
u32 len ; /* bytes actually stored in protkey[] */
u8 protkey [ MAXPROTKEYSIZE ] ; /* the protected key blob */
} __packed ;
2016-11-02 16:37:20 +03:00
/*
* Simple check if the token is a valid CCA secure AES key
* token . If keybitsize is given , the bitsize of the key is
* also checked . Returns 0 on success or errno value on failure .
*/
2017-03-15 13:08:27 +03:00
static int check_secaeskeytoken ( const u8 * token , int keybitsize )
2016-11-02 16:37:20 +03:00
{
struct secaeskeytoken * t = ( struct secaeskeytoken * ) token ;
2018-08-23 17:28:16 +03:00
if ( t - > type ! = TOKTYPE_CCA_INTERNAL ) {
2016-11-02 16:37:20 +03:00
DEBUG_ERR (
2018-08-23 17:28:16 +03:00
" %s secure token check failed, type mismatch 0x%02x != 0x%02x \n " ,
__func__ , ( int ) t - > type , TOKTYPE_CCA_INTERNAL ) ;
2016-11-02 16:37:20 +03:00
return - EINVAL ;
}
2018-08-23 17:28:16 +03:00
if ( t - > version ! = TOKVER_CCA_AES ) {
2016-11-02 16:37:20 +03:00
DEBUG_ERR (
2018-08-23 17:28:16 +03:00
" %s secure token check failed, version mismatch 0x%02x != 0x%02x \n " ,
__func__ , ( int ) t - > version , TOKVER_CCA_AES ) ;
2016-11-02 16:37:20 +03:00
return - EINVAL ;
}
if ( keybitsize > 0 & & t - > bitsize ! = keybitsize ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s secure token check failed, bitsize mismatch %d != %d \n " ,
__func__ , ( int ) t - > bitsize , keybitsize ) ;
2016-11-02 16:37:20 +03:00
return - EINVAL ;
}
return 0 ;
}
/*
* Allocate consecutive memory for request CPRB , request param
* block , reply CPRB and reply param block and fill in values
* for the common fields . Returns 0 on success or errno value
* on failure .
*/
static int alloc_and_prep_cprbmem ( size_t paramblen ,
u8 * * pcprbmem ,
struct CPRBX * * preqCPRB ,
struct CPRBX * * prepCPRB )
{
u8 * cprbmem ;
size_t cprbplusparamblen = sizeof ( struct CPRBX ) + paramblen ;
struct CPRBX * preqcblk , * prepcblk ;
/*
* allocate consecutive memory for request CPRB , request param
* block , reply CPRB and reply param block
*/
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 00:03:40 +03:00
cprbmem = kcalloc ( 2 , cprbplusparamblen , GFP_KERNEL ) ;
2016-11-02 16:37:20 +03:00
if ( ! cprbmem )
return - ENOMEM ;
preqcblk = ( struct CPRBX * ) cprbmem ;
prepcblk = ( struct CPRBX * ) ( cprbmem + cprbplusparamblen ) ;
/* fill request cprb struct */
preqcblk - > cprb_len = sizeof ( struct CPRBX ) ;
preqcblk - > cprb_ver_id = 0x02 ;
memcpy ( preqcblk - > func_id , " T2 " , 2 ) ;
preqcblk - > rpl_msgbl = cprbplusparamblen ;
if ( paramblen ) {
preqcblk - > req_parmb =
( ( u8 * ) preqcblk ) + sizeof ( struct CPRBX ) ;
preqcblk - > rpl_parmb =
( ( u8 * ) prepcblk ) + sizeof ( struct CPRBX ) ;
}
* pcprbmem = cprbmem ;
* preqCPRB = preqcblk ;
* prepCPRB = prepcblk ;
return 0 ;
}
/*
* Free the cprb memory allocated with the function above .
* If the scrub value is not zero , the memory is filled
* with zeros before freeing ( useful if there was some
* clear key material in there ) .
*/
static void free_cprbmem ( void * mem , size_t paramblen , int scrub )
{
if ( scrub )
memzero_explicit ( mem , 2 * ( sizeof ( struct CPRBX ) + paramblen ) ) ;
kfree ( mem ) ;
}
/*
* Helper function to prepare the xcrb struct
*/
static inline void prep_xcrb ( struct ica_xcRB * pxcrb ,
u16 cardnr ,
struct CPRBX * preqcblk ,
struct CPRBX * prepcblk )
{
memset ( pxcrb , 0 , sizeof ( * pxcrb ) ) ;
pxcrb - > agent_ID = 0x4341 ; /* 'CA' */
pxcrb - > user_defined = ( cardnr = = 0xFFFF ? AUTOSELECT : cardnr ) ;
pxcrb - > request_control_blk_length =
preqcblk - > cprb_len + preqcblk - > req_parml ;
2017-05-09 13:42:26 +03:00
pxcrb - > request_control_blk_addr = ( void __user * ) preqcblk ;
2016-11-02 16:37:20 +03:00
pxcrb - > reply_control_blk_length = preqcblk - > rpl_msgbl ;
2017-05-09 13:42:26 +03:00
pxcrb - > reply_control_blk_addr = ( void __user * ) prepcblk ;
2016-11-02 16:37:20 +03:00
}
/*
* Helper function which calls zcrypt_send_cprb with
* memory management segment adjusted to kernel space
* so that the copy_from_user called within this
* function do in fact copy from kernel space .
*/
static inline int _zcrypt_send_cprb ( struct ica_xcRB * xcrb )
{
int rc ;
mm_segment_t old_fs = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
rc = zcrypt_send_cprb ( xcrb ) ;
set_fs ( old_fs ) ;
return rc ;
}
/*
* Generate ( random ) AES secure key .
*/
int pkey_genseckey ( u16 cardnr , u16 domain ,
u32 keytype , struct pkey_seckey * seckey )
{
int i , rc , keysize ;
int seckeysize ;
u8 * mem ;
struct CPRBX * preqcblk , * prepcblk ;
struct ica_xcRB xcrb ;
struct kgreqparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
struct lv1 {
u16 len ;
char key_form [ 8 ] ;
char key_length [ 8 ] ;
char key_type1 [ 8 ] ;
char key_type2 [ 8 ] ;
} lv1 ;
struct lv2 {
u16 len ;
struct keyid {
u16 len ;
u16 attr ;
u8 data [ SECKEYBLOBSIZE ] ;
} keyid [ 6 ] ;
} lv2 ;
} * preqparm ;
struct kgrepparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
struct lv3 {
u16 len ;
u16 keyblocklen ;
struct {
u16 toklen ;
u16 tokattr ;
u8 tok [ 0 ] ;
/* ... some more data ... */
} keyblock ;
} lv3 ;
} * prepparm ;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem ( PARMBSIZE , & mem , & preqcblk , & prepcblk ) ;
if ( rc )
return rc ;
/* fill request cprb struct */
preqcblk - > domain = domain ;
/* fill request cprb param block with KG request */
preqparm = ( struct kgreqparm * ) preqcblk - > req_parmb ;
memcpy ( preqparm - > subfunc_code , " KG " , 2 ) ;
preqparm - > rule_array_len = sizeof ( preqparm - > rule_array_len ) ;
preqparm - > lv1 . len = sizeof ( struct lv1 ) ;
memcpy ( preqparm - > lv1 . key_form , " OP " , 8 ) ;
switch ( keytype ) {
case PKEY_KEYTYPE_AES_128 :
keysize = 16 ;
memcpy ( preqparm - > lv1 . key_length , " KEYLN16 " , 8 ) ;
break ;
case PKEY_KEYTYPE_AES_192 :
keysize = 24 ;
memcpy ( preqparm - > lv1 . key_length , " KEYLN24 " , 8 ) ;
break ;
case PKEY_KEYTYPE_AES_256 :
keysize = 32 ;
memcpy ( preqparm - > lv1 . key_length , " KEYLN32 " , 8 ) ;
break ;
default :
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s unknown/unsupported keytype %d \n " ,
__func__ , keytype ) ;
2016-11-02 16:37:20 +03:00
rc = - EINVAL ;
goto out ;
}
memcpy ( preqparm - > lv1 . key_type1 , " AESDATA " , 8 ) ;
preqparm - > lv2 . len = sizeof ( struct lv2 ) ;
for ( i = 0 ; i < 6 ; i + + ) {
preqparm - > lv2 . keyid [ i ] . len = sizeof ( struct keyid ) ;
preqparm - > lv2 . keyid [ i ] . attr = ( i = = 2 ? 0x30 : 0x10 ) ;
}
preqcblk - > req_parml = sizeof ( struct kgreqparm ) ;
/* fill xcrb struct */
prep_xcrb ( & xcrb , cardnr , preqcblk , prepcblk ) ;
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = _zcrypt_send_cprb ( & xcrb ) ;
if ( rc ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d \n " ,
__func__ , ( int ) cardnr , ( int ) domain , rc ) ;
2016-11-02 16:37:20 +03:00
goto out ;
}
/* check response returncode and reasoncode */
if ( prepcblk - > ccp_rtcode ! = 0 ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s secure key generate failure, card response %d/%d \n " ,
__func__ ,
2016-11-02 16:37:20 +03:00
( int ) prepcblk - > ccp_rtcode ,
( int ) prepcblk - > ccp_rscode ) ;
rc = - EIO ;
goto out ;
}
/* process response cprb param block */
prepcblk - > rpl_parmb = ( ( u8 * ) prepcblk ) + sizeof ( struct CPRBX ) ;
prepparm = ( struct kgrepparm * ) prepcblk - > rpl_parmb ;
/* check length of the returned secure key token */
seckeysize = prepparm - > lv3 . keyblock . toklen
- sizeof ( prepparm - > lv3 . keyblock . toklen )
- sizeof ( prepparm - > lv3 . keyblock . tokattr ) ;
if ( seckeysize ! = SECKEYBLOBSIZE ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s secure token size mismatch %d != %d bytes \n " ,
__func__ , seckeysize , SECKEYBLOBSIZE ) ;
2016-11-02 16:37:20 +03:00
rc = - EIO ;
goto out ;
}
/* check secure key token */
rc = check_secaeskeytoken ( prepparm - > lv3 . keyblock . tok , 8 * keysize ) ;
if ( rc ) {
rc = - EIO ;
goto out ;
}
/* copy the generated secure key token */
memcpy ( seckey - > seckey , prepparm - > lv3 . keyblock . tok , SECKEYBLOBSIZE ) ;
out :
free_cprbmem ( mem , PARMBSIZE , 0 ) ;
return rc ;
}
EXPORT_SYMBOL ( pkey_genseckey ) ;
/*
* Generate an AES secure key with given key value .
*/
int pkey_clr2seckey ( u16 cardnr , u16 domain , u32 keytype ,
const struct pkey_clrkey * clrkey ,
struct pkey_seckey * seckey )
{
int rc , keysize , seckeysize ;
u8 * mem ;
struct CPRBX * preqcblk , * prepcblk ;
struct ica_xcRB xcrb ;
struct cmreqparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
char rule_array [ 8 ] ;
struct lv1 {
u16 len ;
u8 clrkey [ 0 ] ;
} lv1 ;
struct lv2 {
u16 len ;
struct keyid {
u16 len ;
u16 attr ;
u8 data [ SECKEYBLOBSIZE ] ;
} keyid ;
} lv2 ;
} * preqparm ;
struct lv2 * plv2 ;
struct cmrepparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
struct lv3 {
u16 len ;
u16 keyblocklen ;
struct {
u16 toklen ;
u16 tokattr ;
u8 tok [ 0 ] ;
/* ... some more data ... */
} keyblock ;
} lv3 ;
} * prepparm ;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem ( PARMBSIZE , & mem , & preqcblk , & prepcblk ) ;
if ( rc )
return rc ;
/* fill request cprb struct */
preqcblk - > domain = domain ;
/* fill request cprb param block with CM request */
preqparm = ( struct cmreqparm * ) preqcblk - > req_parmb ;
memcpy ( preqparm - > subfunc_code , " CM " , 2 ) ;
memcpy ( preqparm - > rule_array , " AES " , 8 ) ;
preqparm - > rule_array_len =
sizeof ( preqparm - > rule_array_len ) + sizeof ( preqparm - > rule_array ) ;
switch ( keytype ) {
case PKEY_KEYTYPE_AES_128 :
keysize = 16 ;
break ;
case PKEY_KEYTYPE_AES_192 :
keysize = 24 ;
break ;
case PKEY_KEYTYPE_AES_256 :
keysize = 32 ;
break ;
default :
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s unknown/unsupported keytype %d \n " ,
__func__ , keytype ) ;
2016-11-02 16:37:20 +03:00
rc = - EINVAL ;
goto out ;
}
preqparm - > lv1 . len = sizeof ( struct lv1 ) + keysize ;
memcpy ( preqparm - > lv1 . clrkey , clrkey - > clrkey , keysize ) ;
plv2 = ( struct lv2 * ) ( ( ( u8 * ) & preqparm - > lv2 ) + keysize ) ;
plv2 - > len = sizeof ( struct lv2 ) ;
plv2 - > keyid . len = sizeof ( struct keyid ) ;
plv2 - > keyid . attr = 0x30 ;
preqcblk - > req_parml = sizeof ( struct cmreqparm ) + keysize ;
/* fill xcrb struct */
prep_xcrb ( & xcrb , cardnr , preqcblk , prepcblk ) ;
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = _zcrypt_send_cprb ( & xcrb ) ;
if ( rc ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d \n " ,
__func__ , ( int ) cardnr , ( int ) domain , rc ) ;
2016-11-02 16:37:20 +03:00
goto out ;
}
/* check response returncode and reasoncode */
if ( prepcblk - > ccp_rtcode ! = 0 ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s clear key import failure, card response %d/%d \n " ,
__func__ ,
2016-11-02 16:37:20 +03:00
( int ) prepcblk - > ccp_rtcode ,
( int ) prepcblk - > ccp_rscode ) ;
rc = - EIO ;
goto out ;
}
/* process response cprb param block */
prepcblk - > rpl_parmb = ( ( u8 * ) prepcblk ) + sizeof ( struct CPRBX ) ;
prepparm = ( struct cmrepparm * ) prepcblk - > rpl_parmb ;
/* check length of the returned secure key token */
seckeysize = prepparm - > lv3 . keyblock . toklen
- sizeof ( prepparm - > lv3 . keyblock . toklen )
- sizeof ( prepparm - > lv3 . keyblock . tokattr ) ;
if ( seckeysize ! = SECKEYBLOBSIZE ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s secure token size mismatch %d != %d bytes \n " ,
__func__ , seckeysize , SECKEYBLOBSIZE ) ;
2016-11-02 16:37:20 +03:00
rc = - EIO ;
goto out ;
}
/* check secure key token */
rc = check_secaeskeytoken ( prepparm - > lv3 . keyblock . tok , 8 * keysize ) ;
if ( rc ) {
rc = - EIO ;
goto out ;
}
/* copy the generated secure key token */
memcpy ( seckey - > seckey , prepparm - > lv3 . keyblock . tok , SECKEYBLOBSIZE ) ;
out :
free_cprbmem ( mem , PARMBSIZE , 1 ) ;
return rc ;
}
EXPORT_SYMBOL ( pkey_clr2seckey ) ;
/*
* Derive a proteced key from the secure key blob .
*/
int pkey_sec2protkey ( u16 cardnr , u16 domain ,
const struct pkey_seckey * seckey ,
struct pkey_protkey * protkey )
{
int rc ;
u8 * mem ;
struct CPRBX * preqcblk , * prepcblk ;
struct ica_xcRB xcrb ;
struct uskreqparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
struct lv1 {
u16 len ;
u16 attr_len ;
u16 attr_flags ;
} lv1 ;
struct lv2 {
u16 len ;
u16 attr_len ;
u16 attr_flags ;
u8 token [ 0 ] ; /* cca secure key token */
} lv2 __packed ;
} * preqparm ;
struct uskrepparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
struct lv3 {
u16 len ;
u16 attr_len ;
u16 attr_flags ;
struct cpacfkeyblock {
u8 version ; /* version of this struct */
u8 flags [ 2 ] ;
u8 algo ;
u8 form ;
u8 pad1 [ 3 ] ;
u16 keylen ;
u8 key [ 64 ] ; /* the key (keylen bytes) */
u16 keyattrlen ;
u8 keyattr [ 32 ] ;
u8 pad2 [ 1 ] ;
u8 vptype ;
u8 vp [ 32 ] ; /* verification pattern */
} keyblock ;
} lv3 __packed ;
} * prepparm ;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem ( PARMBSIZE , & mem , & preqcblk , & prepcblk ) ;
if ( rc )
return rc ;
/* fill request cprb struct */
preqcblk - > domain = domain ;
/* fill request cprb param block with USK request */
preqparm = ( struct uskreqparm * ) preqcblk - > req_parmb ;
memcpy ( preqparm - > subfunc_code , " US " , 2 ) ;
preqparm - > rule_array_len = sizeof ( preqparm - > rule_array_len ) ;
preqparm - > lv1 . len = sizeof ( struct lv1 ) ;
preqparm - > lv1 . attr_len = sizeof ( struct lv1 ) - sizeof ( preqparm - > lv1 . len ) ;
preqparm - > lv1 . attr_flags = 0x0001 ;
preqparm - > lv2 . len = sizeof ( struct lv2 ) + SECKEYBLOBSIZE ;
preqparm - > lv2 . attr_len = sizeof ( struct lv2 )
- sizeof ( preqparm - > lv2 . len ) + SECKEYBLOBSIZE ;
preqparm - > lv2 . attr_flags = 0x0000 ;
memcpy ( preqparm - > lv2 . token , seckey - > seckey , SECKEYBLOBSIZE ) ;
preqcblk - > req_parml = sizeof ( struct uskreqparm ) + SECKEYBLOBSIZE ;
/* fill xcrb struct */
prep_xcrb ( & xcrb , cardnr , preqcblk , prepcblk ) ;
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = _zcrypt_send_cprb ( & xcrb ) ;
if ( rc ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d \n " ,
__func__ , ( int ) cardnr , ( int ) domain , rc ) ;
2016-11-02 16:37:20 +03:00
goto out ;
}
/* check response returncode and reasoncode */
if ( prepcblk - > ccp_rtcode ! = 0 ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s unwrap secure key failure, card response %d/%d \n " ,
__func__ ,
2016-11-02 16:37:20 +03:00
( int ) prepcblk - > ccp_rtcode ,
( int ) prepcblk - > ccp_rscode ) ;
rc = - EIO ;
goto out ;
}
2017-03-15 12:58:07 +03:00
if ( prepcblk - > ccp_rscode ! = 0 ) {
DEBUG_WARN (
2018-08-17 13:36:01 +03:00
" %s unwrap secure key warning, card response %d/%d \n " ,
__func__ ,
2017-03-15 12:58:07 +03:00
( int ) prepcblk - > ccp_rtcode ,
( int ) prepcblk - > ccp_rscode ) ;
}
2016-11-02 16:37:20 +03:00
/* process response cprb param block */
prepcblk - > rpl_parmb = ( ( u8 * ) prepcblk ) + sizeof ( struct CPRBX ) ;
prepparm = ( struct uskrepparm * ) prepcblk - > rpl_parmb ;
/* check the returned keyblock */
if ( prepparm - > lv3 . keyblock . version ! = 0x01 ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s reply param keyblock version mismatch 0x%02x != 0x01 \n " ,
__func__ , ( int ) prepparm - > lv3 . keyblock . version ) ;
2016-11-02 16:37:20 +03:00
rc = - EIO ;
goto out ;
}
/* copy the tanslated protected key */
switch ( prepparm - > lv3 . keyblock . keylen ) {
case 16 + 32 :
protkey - > type = PKEY_KEYTYPE_AES_128 ;
break ;
case 24 + 32 :
protkey - > type = PKEY_KEYTYPE_AES_192 ;
break ;
case 32 + 32 :
protkey - > type = PKEY_KEYTYPE_AES_256 ;
break ;
default :
2018-08-17 13:36:01 +03:00
DEBUG_ERR ( " %s unknown/unsupported keytype %d \n " ,
__func__ , prepparm - > lv3 . keyblock . keylen ) ;
2016-11-02 16:37:20 +03:00
rc = - EIO ;
goto out ;
}
protkey - > len = prepparm - > lv3 . keyblock . keylen ;
memcpy ( protkey - > protkey , prepparm - > lv3 . keyblock . key , protkey - > len ) ;
out :
free_cprbmem ( mem , PARMBSIZE , 0 ) ;
return rc ;
}
EXPORT_SYMBOL ( pkey_sec2protkey ) ;
/*
* Create a protected key from a clear key value .
*/
int pkey_clr2protkey ( u32 keytype ,
const struct pkey_clrkey * clrkey ,
struct pkey_protkey * protkey )
{
long fc ;
int keysize ;
u8 paramblock [ 64 ] ;
switch ( keytype ) {
case PKEY_KEYTYPE_AES_128 :
keysize = 16 ;
fc = CPACF_PCKMO_ENC_AES_128_KEY ;
break ;
case PKEY_KEYTYPE_AES_192 :
keysize = 24 ;
fc = CPACF_PCKMO_ENC_AES_192_KEY ;
break ;
case PKEY_KEYTYPE_AES_256 :
keysize = 32 ;
fc = CPACF_PCKMO_ENC_AES_256_KEY ;
break ;
default :
2018-08-17 13:36:01 +03:00
DEBUG_ERR ( " %s unknown/unsupported keytype %d \n " ,
__func__ , keytype ) ;
2016-11-02 16:37:20 +03:00
return - EINVAL ;
}
/* prepare param block */
memset ( paramblock , 0 , sizeof ( paramblock ) ) ;
memcpy ( paramblock , clrkey - > clrkey , keysize ) ;
/* call the pckmo instruction */
cpacf_pckmo ( fc , paramblock ) ;
/* copy created protected key */
protkey - > type = keytype ;
protkey - > len = keysize + 32 ;
memcpy ( protkey - > protkey , paramblock , keysize + 32 ) ;
return 0 ;
}
EXPORT_SYMBOL ( pkey_clr2protkey ) ;
/*
* query cryptographic facility from adapter
*/
static int query_crypto_facility ( u16 cardnr , u16 domain ,
const char * keyword ,
u8 * rarray , size_t * rarraylen ,
u8 * varray , size_t * varraylen )
{
int rc ;
u16 len ;
u8 * mem , * ptr ;
struct CPRBX * preqcblk , * prepcblk ;
struct ica_xcRB xcrb ;
struct fqreqparm {
u8 subfunc_code [ 2 ] ;
u16 rule_array_len ;
char rule_array [ 8 ] ;
struct lv1 {
u16 len ;
u8 data [ VARDATASIZE ] ;
} lv1 ;
u16 dummylen ;
} * preqparm ;
size_t parmbsize = sizeof ( struct fqreqparm ) ;
struct fqrepparm {
u8 subfunc_code [ 2 ] ;
u8 lvdata [ 0 ] ;
} * prepparm ;
/* get already prepared memory for 2 cprbs with param block each */
rc = alloc_and_prep_cprbmem ( parmbsize , & mem , & preqcblk , & prepcblk ) ;
if ( rc )
return rc ;
/* fill request cprb struct */
preqcblk - > domain = domain ;
/* fill request cprb param block with FQ request */
preqparm = ( struct fqreqparm * ) preqcblk - > req_parmb ;
memcpy ( preqparm - > subfunc_code , " FQ " , 2 ) ;
2018-06-28 14:33:35 +03:00
memcpy ( preqparm - > rule_array , keyword , sizeof ( preqparm - > rule_array ) ) ;
2016-11-02 16:37:20 +03:00
preqparm - > rule_array_len =
sizeof ( preqparm - > rule_array_len ) + sizeof ( preqparm - > rule_array ) ;
preqparm - > lv1 . len = sizeof ( preqparm - > lv1 ) ;
preqparm - > dummylen = sizeof ( preqparm - > dummylen ) ;
preqcblk - > req_parml = parmbsize ;
/* fill xcrb struct */
prep_xcrb ( & xcrb , cardnr , preqcblk , prepcblk ) ;
/* forward xcrb with request CPRB and reply CPRB to zcrypt dd */
rc = _zcrypt_send_cprb ( & xcrb ) ;
if ( rc ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d \n " ,
__func__ , ( int ) cardnr , ( int ) domain , rc ) ;
2016-11-02 16:37:20 +03:00
goto out ;
}
/* check response returncode and reasoncode */
if ( prepcblk - > ccp_rtcode ! = 0 ) {
DEBUG_ERR (
2018-08-17 13:36:01 +03:00
" %s unwrap secure key failure, card response %d/%d \n " ,
__func__ ,
2016-11-02 16:37:20 +03:00
( int ) prepcblk - > ccp_rtcode ,
( int ) prepcblk - > ccp_rscode ) ;
rc = - EIO ;
goto out ;
}
/* process response cprb param block */
prepcblk - > rpl_parmb = ( ( u8 * ) prepcblk ) + sizeof ( struct CPRBX ) ;
prepparm = ( struct fqrepparm * ) prepcblk - > rpl_parmb ;
ptr = prepparm - > lvdata ;
/* check and possibly copy reply rule array */
len = * ( ( u16 * ) ptr ) ;
if ( len > sizeof ( u16 ) ) {
ptr + = sizeof ( u16 ) ;
len - = sizeof ( u16 ) ;
if ( rarray & & rarraylen & & * rarraylen > 0 ) {
* rarraylen = ( len > * rarraylen ? * rarraylen : len ) ;
memcpy ( rarray , ptr , * rarraylen ) ;
}
ptr + = len ;
}
/* check and possible copy reply var array */
len = * ( ( u16 * ) ptr ) ;
if ( len > sizeof ( u16 ) ) {
ptr + = sizeof ( u16 ) ;
len - = sizeof ( u16 ) ;
if ( varray & & varraylen & & * varraylen > 0 ) {
* varraylen = ( len > * varraylen ? * varraylen : len ) ;
memcpy ( varray , ptr , * varraylen ) ;
}
ptr + = len ;
}
out :
free_cprbmem ( mem , parmbsize , 0 ) ;
return rc ;
}
/*
2017-03-15 12:58:07 +03:00
* Fetch the current and old mkvp values via
* query_crypto_facility from adapter .
2016-11-02 16:37:20 +03:00
*/
2017-03-15 12:58:07 +03:00
static int fetch_mkvp ( u16 cardnr , u16 domain , u64 mkvp [ 2 ] )
2016-11-02 16:37:20 +03:00
{
int rc , found = 0 ;
size_t rlen , vlen ;
u8 * rarray , * varray , * pg ;
pg = ( u8 * ) __get_free_page ( GFP_KERNEL ) ;
if ( ! pg )
return - ENOMEM ;
rarray = pg ;
varray = pg + PAGE_SIZE / 2 ;
rlen = vlen = PAGE_SIZE / 2 ;
rc = query_crypto_facility ( cardnr , domain , " STATICSA " ,
rarray , & rlen , varray , & vlen ) ;
if ( rc = = 0 & & rlen > 8 * 8 & & vlen > 184 + 8 ) {
2017-03-15 12:58:07 +03:00
if ( rarray [ 8 * 8 ] = = ' 2 ' ) {
2016-11-02 16:37:20 +03:00
/* current master key state is valid */
2017-03-15 12:58:07 +03:00
mkvp [ 0 ] = * ( ( u64 * ) ( varray + 184 ) ) ;
mkvp [ 1 ] = * ( ( u64 * ) ( varray + 172 ) ) ;
2016-11-02 16:37:20 +03:00
found = 1 ;
}
}
free_page ( ( unsigned long ) pg ) ;
return found ? 0 : - ENOENT ;
}
/* struct to hold cached mkvp info for each card/domain */
struct mkvp_info {
struct list_head list ;
u16 cardnr ;
u16 domain ;
2017-03-15 12:58:07 +03:00
u64 mkvp [ 2 ] ;
2016-11-02 16:37:20 +03:00
} ;
/* a list with mkvp_info entries */
static LIST_HEAD ( mkvp_list ) ;
static DEFINE_SPINLOCK ( mkvp_list_lock ) ;
2017-03-15 12:58:07 +03:00
static int mkvp_cache_fetch ( u16 cardnr , u16 domain , u64 mkvp [ 2 ] )
2016-11-02 16:37:20 +03:00
{
int rc = - ENOENT ;
struct mkvp_info * ptr ;
spin_lock_bh ( & mkvp_list_lock ) ;
list_for_each_entry ( ptr , & mkvp_list , list ) {
if ( ptr - > cardnr = = cardnr & &
ptr - > domain = = domain ) {
2017-03-15 12:58:07 +03:00
memcpy ( mkvp , ptr - > mkvp , 2 * sizeof ( u64 ) ) ;
2016-11-02 16:37:20 +03:00
rc = 0 ;
break ;
}
}
spin_unlock_bh ( & mkvp_list_lock ) ;
return rc ;
}
2017-03-15 12:58:07 +03:00
static void mkvp_cache_update ( u16 cardnr , u16 domain , u64 mkvp [ 2 ] )
2016-11-02 16:37:20 +03:00
{
int found = 0 ;
struct mkvp_info * ptr ;
spin_lock_bh ( & mkvp_list_lock ) ;
list_for_each_entry ( ptr , & mkvp_list , list ) {
if ( ptr - > cardnr = = cardnr & &
ptr - > domain = = domain ) {
2017-03-15 12:58:07 +03:00
memcpy ( ptr - > mkvp , mkvp , 2 * sizeof ( u64 ) ) ;
2016-11-02 16:37:20 +03:00
found = 1 ;
break ;
}
}
if ( ! found ) {
ptr = kmalloc ( sizeof ( * ptr ) , GFP_ATOMIC ) ;
if ( ! ptr ) {
spin_unlock_bh ( & mkvp_list_lock ) ;
return ;
}
ptr - > cardnr = cardnr ;
ptr - > domain = domain ;
2017-03-15 12:58:07 +03:00
memcpy ( ptr - > mkvp , mkvp , 2 * sizeof ( u64 ) ) ;
2016-11-02 16:37:20 +03:00
list_add ( & ptr - > list , & mkvp_list ) ;
}
spin_unlock_bh ( & mkvp_list_lock ) ;
}
static void mkvp_cache_scrub ( u16 cardnr , u16 domain )
{
struct mkvp_info * ptr ;
spin_lock_bh ( & mkvp_list_lock ) ;
list_for_each_entry ( ptr , & mkvp_list , list ) {
if ( ptr - > cardnr = = cardnr & &
ptr - > domain = = domain ) {
list_del ( & ptr - > list ) ;
kfree ( ptr ) ;
break ;
}
}
spin_unlock_bh ( & mkvp_list_lock ) ;
}
static void __exit mkvp_cache_free ( void )
{
struct mkvp_info * ptr , * pnext ;
spin_lock_bh ( & mkvp_list_lock ) ;
list_for_each_entry_safe ( ptr , pnext , & mkvp_list , list ) {
list_del ( & ptr - > list ) ;
kfree ( ptr ) ;
}
spin_unlock_bh ( & mkvp_list_lock ) ;
}
/*
* Search for a matching crypto card based on the Master Key
* Verification Pattern provided inside a secure key .
*/
int pkey_findcard ( const struct pkey_seckey * seckey ,
u16 * pcardnr , u16 * pdomain , int verify )
{
struct secaeskeytoken * t = ( struct secaeskeytoken * ) seckey ;
2018-04-09 17:18:37 +03:00
struct zcrypt_device_status_ext * device_status ;
2016-11-02 16:37:20 +03:00
u16 card , dom ;
2017-03-15 12:58:07 +03:00
u64 mkvp [ 2 ] ;
int i , rc , oi = - 1 ;
2016-11-02 16:37:20 +03:00
/* mkvp must not be zero */
if ( t - > mkvp = = 0 )
return - EINVAL ;
/* fetch status of all crypto cards */
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
device_status = kmalloc_array ( MAX_ZDEV_ENTRIES_EXT ,
sizeof ( struct zcrypt_device_status_ext ) ,
GFP_KERNEL ) ;
2018-04-09 17:18:37 +03:00
if ( ! device_status )
2016-11-02 16:37:20 +03:00
return - ENOMEM ;
2018-04-09 17:18:37 +03:00
zcrypt_device_status_mask_ext ( device_status ) ;
2016-11-02 16:37:20 +03:00
/* walk through all crypto cards */
2018-04-09 17:18:37 +03:00
for ( i = 0 ; i < MAX_ZDEV_ENTRIES_EXT ; i + + ) {
card = AP_QID_CARD ( device_status [ i ] . qid ) ;
dom = AP_QID_QUEUE ( device_status [ i ] . qid ) ;
if ( device_status [ i ] . online & &
device_status [ i ] . functions & 0x04 ) {
2016-11-02 16:37:20 +03:00
/* an enabled CCA Coprocessor card */
/* try cached mkvp */
2017-03-15 12:58:07 +03:00
if ( mkvp_cache_fetch ( card , dom , mkvp ) = = 0 & &
t - > mkvp = = mkvp [ 0 ] ) {
2016-11-02 16:37:20 +03:00
if ( ! verify )
break ;
/* verify: fetch mkvp from adapter */
2017-03-15 12:58:07 +03:00
if ( fetch_mkvp ( card , dom , mkvp ) = = 0 ) {
2016-11-02 16:37:20 +03:00
mkvp_cache_update ( card , dom , mkvp ) ;
2017-03-15 12:58:07 +03:00
if ( t - > mkvp = = mkvp [ 0 ] )
2016-11-02 16:37:20 +03:00
break ;
}
}
} else {
/* Card is offline and/or not a CCA card. */
/* del mkvp entry from cache if it exists */
mkvp_cache_scrub ( card , dom ) ;
}
}
2018-04-09 17:18:37 +03:00
if ( i > = MAX_ZDEV_ENTRIES_EXT ) {
2016-11-02 16:37:20 +03:00
/* nothing found, so this time without cache */
2018-04-09 17:18:37 +03:00
for ( i = 0 ; i < MAX_ZDEV_ENTRIES_EXT ; i + + ) {
if ( ! ( device_status [ i ] . online & &
device_status [ i ] . functions & 0x04 ) )
2016-11-02 16:37:20 +03:00
continue ;
2018-04-09 17:18:37 +03:00
card = AP_QID_CARD ( device_status [ i ] . qid ) ;
dom = AP_QID_QUEUE ( device_status [ i ] . qid ) ;
2016-11-02 16:37:20 +03:00
/* fresh fetch mkvp from adapter */
2017-03-15 12:58:07 +03:00
if ( fetch_mkvp ( card , dom , mkvp ) = = 0 ) {
2016-11-02 16:37:20 +03:00
mkvp_cache_update ( card , dom , mkvp ) ;
2017-03-15 12:58:07 +03:00
if ( t - > mkvp = = mkvp [ 0 ] )
2016-11-02 16:37:20 +03:00
break ;
2017-03-15 12:58:07 +03:00
if ( t - > mkvp = = mkvp [ 1 ] & & oi < 0 )
oi = i ;
2016-11-02 16:37:20 +03:00
}
}
2018-04-09 17:18:37 +03:00
if ( i > = MAX_ZDEV_ENTRIES_EXT & & oi > = 0 ) {
2017-03-15 12:58:07 +03:00
/* old mkvp matched, use this card then */
2018-04-09 17:18:37 +03:00
card = AP_QID_CARD ( device_status [ oi ] . qid ) ;
dom = AP_QID_QUEUE ( device_status [ oi ] . qid ) ;
2017-03-15 12:58:07 +03:00
}
2016-11-02 16:37:20 +03:00
}
2018-04-09 17:18:37 +03:00
if ( i < MAX_ZDEV_ENTRIES_EXT | | oi > = 0 ) {
2016-11-02 16:37:20 +03:00
if ( pcardnr )
* pcardnr = card ;
if ( pdomain )
* pdomain = dom ;
rc = 0 ;
} else
rc = - ENODEV ;
2018-04-09 17:18:37 +03:00
kfree ( device_status ) ;
2016-11-02 16:37:20 +03:00
return rc ;
}
EXPORT_SYMBOL ( pkey_findcard ) ;
/*
* Find card and transform secure key into protected key .
*/
int pkey_skey2pkey ( const struct pkey_seckey * seckey ,
struct pkey_protkey * protkey )
{
u16 cardnr , domain ;
int rc , verify ;
/*
* The pkey_sec2protkey call may fail when a card has been
* addressed where the master key was changed after last fetch
* of the mkvp into the cache . So first try without verify then
* with verify enabled ( thus refreshing the mkvp for each card ) .
*/
for ( verify = 0 ; verify < 2 ; verify + + ) {
rc = pkey_findcard ( seckey , & cardnr , & domain , verify ) ;
if ( rc )
continue ;
rc = pkey_sec2protkey ( cardnr , domain , seckey , protkey ) ;
if ( rc = = 0 )
break ;
}
if ( rc )
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s failed rc=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
return rc ;
}
EXPORT_SYMBOL ( pkey_skey2pkey ) ;
2017-03-15 13:08:27 +03:00
/*
* Verify key and give back some info about the key .
*/
int pkey_verifykey ( const struct pkey_seckey * seckey ,
u16 * pcardnr , u16 * pdomain ,
u16 * pkeysize , u32 * pattributes )
{
struct secaeskeytoken * t = ( struct secaeskeytoken * ) seckey ;
u16 cardnr , domain ;
u64 mkvp [ 2 ] ;
int rc ;
/* check the secure key for valid AES secure key */
rc = check_secaeskeytoken ( ( u8 * ) seckey , 0 ) ;
if ( rc )
goto out ;
if ( pattributes )
* pattributes = PKEY_VERIFY_ATTR_AES ;
if ( pkeysize )
* pkeysize = t - > bitsize ;
/* try to find a card which can handle this key */
rc = pkey_findcard ( seckey , & cardnr , & domain , 1 ) ;
if ( rc )
goto out ;
/* check mkvp for old mkvp match */
rc = mkvp_cache_fetch ( cardnr , domain , mkvp ) ;
if ( rc )
goto out ;
if ( t - > mkvp = = mkvp [ 1 ] ) {
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s secure key has old mkvp \n " , __func__ ) ;
2017-03-15 13:08:27 +03:00
if ( pattributes )
* pattributes | = PKEY_VERIFY_ATTR_OLD_MKVP ;
}
if ( pcardnr )
* pcardnr = cardnr ;
if ( pdomain )
* pdomain = domain ;
out :
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s rc=%d \n " , __func__ , rc ) ;
2017-03-15 13:08:27 +03:00
return rc ;
}
EXPORT_SYMBOL ( pkey_verifykey ) ;
2018-08-23 11:06:26 +03:00
/*
* Generate a random protected key
*/
int pkey_genprotkey ( __u32 keytype , struct pkey_protkey * protkey )
{
struct pkey_clrkey clrkey ;
int keysize ;
int rc ;
switch ( keytype ) {
case PKEY_KEYTYPE_AES_128 :
keysize = 16 ;
break ;
case PKEY_KEYTYPE_AES_192 :
keysize = 24 ;
break ;
case PKEY_KEYTYPE_AES_256 :
keysize = 32 ;
break ;
default :
DEBUG_ERR ( " %s unknown/unsupported keytype %d \n " , __func__ ,
keytype ) ;
return - EINVAL ;
}
/* generate a dummy random clear key */
get_random_bytes ( clrkey . clrkey , keysize ) ;
/* convert it to a dummy protected key */
rc = pkey_clr2protkey ( keytype , & clrkey , protkey ) ;
if ( rc )
return rc ;
/* replace the key part of the protected key with random bytes */
get_random_bytes ( protkey - > protkey , keysize ) ;
return 0 ;
}
EXPORT_SYMBOL ( pkey_genprotkey ) ;
2018-08-23 18:49:38 +03:00
/*
* Verify if a protected key is still valid
*/
int pkey_verifyprotkey ( const struct pkey_protkey * protkey )
{
unsigned long fc ;
struct {
u8 iv [ AES_BLOCK_SIZE ] ;
u8 key [ MAXPROTKEYSIZE ] ;
} param ;
u8 null_msg [ AES_BLOCK_SIZE ] ;
u8 dest_buf [ AES_BLOCK_SIZE ] ;
unsigned int k ;
switch ( protkey - > type ) {
case PKEY_KEYTYPE_AES_128 :
fc = CPACF_KMC_PAES_128 ;
break ;
case PKEY_KEYTYPE_AES_192 :
fc = CPACF_KMC_PAES_192 ;
break ;
case PKEY_KEYTYPE_AES_256 :
fc = CPACF_KMC_PAES_256 ;
break ;
default :
DEBUG_ERR ( " %s unknown/unsupported keytype %d \n " , __func__ ,
protkey - > type ) ;
return - EINVAL ;
}
memset ( null_msg , 0 , sizeof ( null_msg ) ) ;
memset ( param . iv , 0 , sizeof ( param . iv ) ) ;
memcpy ( param . key , protkey - > protkey , sizeof ( param . key ) ) ;
k = cpacf_kmc ( fc | CPACF_ENCRYPT , & param , null_msg , dest_buf ,
sizeof ( null_msg ) ) ;
if ( k ! = sizeof ( null_msg ) ) {
DEBUG_ERR ( " %s protected key is not valid \n " , __func__ ) ;
return - EKEYREJECTED ;
}
return 0 ;
}
EXPORT_SYMBOL ( pkey_verifyprotkey ) ;
2018-08-24 12:29:15 +03:00
/*
* Transform a non - CCA key token into a protected key
*/
static int pkey_nonccatok2pkey ( const __u8 * key , __u32 keylen ,
struct pkey_protkey * protkey )
{
struct keytoken_header * hdr = ( struct keytoken_header * ) key ;
struct protaeskeytoken * t ;
switch ( hdr - > version ) {
case TOKVER_PROTECTED_KEY :
if ( keylen ! = sizeof ( struct protaeskeytoken ) )
return - EINVAL ;
t = ( struct protaeskeytoken * ) key ;
protkey - > len = t - > len ;
protkey - > type = t - > keytype ;
memcpy ( protkey - > protkey , t - > protkey ,
sizeof ( protkey - > protkey ) ) ;
return pkey_verifyprotkey ( protkey ) ;
default :
DEBUG_ERR ( " %s unknown/unsupported non-CCA token version %d \n " ,
__func__ , hdr - > version ) ;
return - EINVAL ;
}
}
/*
* Transform a CCA internal key token into a protected key
*/
static int pkey_ccainttok2pkey ( const __u8 * key , __u32 keylen ,
struct pkey_protkey * protkey )
{
struct keytoken_header * hdr = ( struct keytoken_header * ) key ;
switch ( hdr - > version ) {
case TOKVER_CCA_AES :
if ( keylen ! = sizeof ( struct secaeskeytoken ) )
return - EINVAL ;
return pkey_skey2pkey ( ( struct pkey_seckey * ) key ,
protkey ) ;
default :
DEBUG_ERR ( " %s unknown/unsupported CCA internal token version %d \n " ,
__func__ , hdr - > version ) ;
return - EINVAL ;
}
}
/*
* Transform a key blob ( of any type ) into a protected key
*/
int pkey_keyblob2pkey ( const __u8 * key , __u32 keylen ,
struct pkey_protkey * protkey )
{
struct keytoken_header * hdr = ( struct keytoken_header * ) key ;
if ( keylen < sizeof ( struct keytoken_header ) )
return - EINVAL ;
switch ( hdr - > type ) {
case TOKTYPE_NON_CCA :
return pkey_nonccatok2pkey ( key , keylen , protkey ) ;
case TOKTYPE_CCA_INTERNAL :
return pkey_ccainttok2pkey ( key , keylen , protkey ) ;
default :
DEBUG_ERR ( " %s unknown/unsupported blob type %d \n " , __func__ ,
hdr - > type ) ;
return - EINVAL ;
}
}
EXPORT_SYMBOL ( pkey_keyblob2pkey ) ;
2016-11-02 16:37:20 +03:00
/*
* File io functions
*/
static long pkey_unlocked_ioctl ( struct file * filp , unsigned int cmd ,
unsigned long arg )
{
int rc ;
switch ( cmd ) {
case PKEY_GENSECK : {
struct pkey_genseck __user * ugs = ( void __user * ) arg ;
struct pkey_genseck kgs ;
if ( copy_from_user ( & kgs , ugs , sizeof ( kgs ) ) )
return - EFAULT ;
rc = pkey_genseckey ( kgs . cardnr , kgs . domain ,
kgs . keytype , & kgs . seckey ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_genseckey()=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
if ( rc )
break ;
if ( copy_to_user ( ugs , & kgs , sizeof ( kgs ) ) )
return - EFAULT ;
break ;
}
case PKEY_CLR2SECK : {
struct pkey_clr2seck __user * ucs = ( void __user * ) arg ;
struct pkey_clr2seck kcs ;
if ( copy_from_user ( & kcs , ucs , sizeof ( kcs ) ) )
return - EFAULT ;
rc = pkey_clr2seckey ( kcs . cardnr , kcs . domain , kcs . keytype ,
& kcs . clrkey , & kcs . seckey ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_clr2seckey()=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
if ( rc )
break ;
if ( copy_to_user ( ucs , & kcs , sizeof ( kcs ) ) )
return - EFAULT ;
memzero_explicit ( & kcs , sizeof ( kcs ) ) ;
break ;
}
case PKEY_SEC2PROTK : {
struct pkey_sec2protk __user * usp = ( void __user * ) arg ;
struct pkey_sec2protk ksp ;
if ( copy_from_user ( & ksp , usp , sizeof ( ksp ) ) )
return - EFAULT ;
rc = pkey_sec2protkey ( ksp . cardnr , ksp . domain ,
& ksp . seckey , & ksp . protkey ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_sec2protkey()=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
if ( rc )
break ;
if ( copy_to_user ( usp , & ksp , sizeof ( ksp ) ) )
return - EFAULT ;
break ;
}
case PKEY_CLR2PROTK : {
struct pkey_clr2protk __user * ucp = ( void __user * ) arg ;
struct pkey_clr2protk kcp ;
if ( copy_from_user ( & kcp , ucp , sizeof ( kcp ) ) )
return - EFAULT ;
rc = pkey_clr2protkey ( kcp . keytype ,
& kcp . clrkey , & kcp . protkey ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_clr2protkey()=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
if ( rc )
break ;
if ( copy_to_user ( ucp , & kcp , sizeof ( kcp ) ) )
return - EFAULT ;
memzero_explicit ( & kcp , sizeof ( kcp ) ) ;
break ;
}
case PKEY_FINDCARD : {
struct pkey_findcard __user * ufc = ( void __user * ) arg ;
struct pkey_findcard kfc ;
if ( copy_from_user ( & kfc , ufc , sizeof ( kfc ) ) )
return - EFAULT ;
rc = pkey_findcard ( & kfc . seckey ,
& kfc . cardnr , & kfc . domain , 1 ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_findcard()=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
if ( rc )
break ;
if ( copy_to_user ( ufc , & kfc , sizeof ( kfc ) ) )
return - EFAULT ;
break ;
}
case PKEY_SKEY2PKEY : {
struct pkey_skey2pkey __user * usp = ( void __user * ) arg ;
struct pkey_skey2pkey ksp ;
if ( copy_from_user ( & ksp , usp , sizeof ( ksp ) ) )
return - EFAULT ;
rc = pkey_skey2pkey ( & ksp . seckey , & ksp . protkey ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_skey2pkey()=%d \n " , __func__ , rc ) ;
2016-11-02 16:37:20 +03:00
if ( rc )
break ;
if ( copy_to_user ( usp , & ksp , sizeof ( ksp ) ) )
return - EFAULT ;
break ;
}
2017-03-15 13:08:27 +03:00
case PKEY_VERIFYKEY : {
struct pkey_verifykey __user * uvk = ( void __user * ) arg ;
struct pkey_verifykey kvk ;
if ( copy_from_user ( & kvk , uvk , sizeof ( kvk ) ) )
return - EFAULT ;
rc = pkey_verifykey ( & kvk . seckey , & kvk . cardnr , & kvk . domain ,
& kvk . keysize , & kvk . attributes ) ;
2018-08-17 13:36:01 +03:00
DEBUG_DBG ( " %s pkey_verifykey()=%d \n " , __func__ , rc ) ;
2017-03-15 13:08:27 +03:00
if ( rc )
break ;
if ( copy_to_user ( uvk , & kvk , sizeof ( kvk ) ) )
return - EFAULT ;
break ;
}
2018-08-23 11:06:26 +03:00
case PKEY_GENPROTK : {
struct pkey_genprotk __user * ugp = ( void __user * ) arg ;
struct pkey_genprotk kgp ;
if ( copy_from_user ( & kgp , ugp , sizeof ( kgp ) ) )
return - EFAULT ;
rc = pkey_genprotkey ( kgp . keytype , & kgp . protkey ) ;
DEBUG_DBG ( " %s pkey_genprotkey()=%d \n " , __func__ , rc ) ;
if ( rc )
break ;
if ( copy_to_user ( ugp , & kgp , sizeof ( kgp ) ) )
return - EFAULT ;
break ;
}
2018-08-23 18:49:38 +03:00
case PKEY_VERIFYPROTK : {
struct pkey_verifyprotk __user * uvp = ( void __user * ) arg ;
struct pkey_verifyprotk kvp ;
if ( copy_from_user ( & kvp , uvp , sizeof ( kvp ) ) )
return - EFAULT ;
rc = pkey_verifyprotkey ( & kvp . protkey ) ;
DEBUG_DBG ( " %s pkey_verifyprotkey()=%d \n " , __func__ , rc ) ;
break ;
}
2018-08-24 12:29:15 +03:00
case PKEY_KBLOB2PROTK : {
struct pkey_kblob2pkey __user * utp = ( void __user * ) arg ;
struct pkey_kblob2pkey ktp ;
__u8 __user * ukey ;
__u8 * kkey ;
if ( copy_from_user ( & ktp , utp , sizeof ( ktp ) ) )
return - EFAULT ;
if ( ktp . keylen < MINKEYBLOBSIZE | |
ktp . keylen > MAXKEYBLOBSIZE )
return - EINVAL ;
ukey = ktp . key ;
kkey = kmalloc ( ktp . keylen , GFP_KERNEL ) ;
if ( kkey = = NULL )
return - ENOMEM ;
if ( copy_from_user ( kkey , ukey , ktp . keylen ) ) {
kfree ( kkey ) ;
return - EFAULT ;
}
rc = pkey_keyblob2pkey ( kkey , ktp . keylen , & ktp . protkey ) ;
DEBUG_DBG ( " %s pkey_keyblob2pkey()=%d \n " , __func__ , rc ) ;
kfree ( kkey ) ;
if ( rc )
break ;
if ( copy_to_user ( utp , & ktp , sizeof ( ktp ) ) )
return - EFAULT ;
break ;
}
2016-11-02 16:37:20 +03:00
default :
/* unknown/unsupported ioctl cmd */
return - ENOTTY ;
}
return rc ;
}
/*
* Sysfs and file io operations
*/
2018-08-23 17:59:30 +03:00
/*
* Sysfs attribute read function for all protected key binary attributes .
* The implementation can not deal with partial reads , because a new random
* protected key blob is generated with each read . In case of partial reads
* ( i . e . off ! = 0 or count < key blob size ) - EINVAL is returned .
*/
static ssize_t pkey_protkey_aes_attr_read ( u32 keytype , bool is_xts , char * buf ,
loff_t off , size_t count )
{
struct protaeskeytoken protkeytoken ;
struct pkey_protkey protkey ;
int rc ;
if ( off ! = 0 | | count < sizeof ( protkeytoken ) )
return - EINVAL ;
if ( is_xts )
if ( count < 2 * sizeof ( protkeytoken ) )
return - EINVAL ;
memset ( & protkeytoken , 0 , sizeof ( protkeytoken ) ) ;
protkeytoken . type = TOKTYPE_NON_CCA ;
protkeytoken . version = TOKVER_PROTECTED_KEY ;
protkeytoken . keytype = keytype ;
rc = pkey_genprotkey ( protkeytoken . keytype , & protkey ) ;
if ( rc )
return rc ;
protkeytoken . len = protkey . len ;
memcpy ( & protkeytoken . protkey , & protkey . protkey , protkey . len ) ;
memcpy ( buf , & protkeytoken , sizeof ( protkeytoken ) ) ;
if ( is_xts ) {
rc = pkey_genprotkey ( protkeytoken . keytype , & protkey ) ;
if ( rc )
return rc ;
protkeytoken . len = protkey . len ;
memcpy ( & protkeytoken . protkey , & protkey . protkey , protkey . len ) ;
memcpy ( buf + sizeof ( protkeytoken ) , & protkeytoken ,
sizeof ( protkeytoken ) ) ;
return 2 * sizeof ( protkeytoken ) ;
}
return sizeof ( protkeytoken ) ;
}
static ssize_t protkey_aes_128_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_protkey_aes_attr_read ( PKEY_KEYTYPE_AES_128 , false , buf ,
off , count ) ;
}
static ssize_t protkey_aes_192_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_protkey_aes_attr_read ( PKEY_KEYTYPE_AES_192 , false , buf ,
off , count ) ;
}
static ssize_t protkey_aes_256_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_protkey_aes_attr_read ( PKEY_KEYTYPE_AES_256 , false , buf ,
off , count ) ;
}
static ssize_t protkey_aes_128_xts_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_protkey_aes_attr_read ( PKEY_KEYTYPE_AES_128 , true , buf ,
off , count ) ;
}
static ssize_t protkey_aes_256_xts_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_protkey_aes_attr_read ( PKEY_KEYTYPE_AES_256 , true , buf ,
off , count ) ;
}
static BIN_ATTR_RO ( protkey_aes_128 , sizeof ( struct protaeskeytoken ) ) ;
static BIN_ATTR_RO ( protkey_aes_192 , sizeof ( struct protaeskeytoken ) ) ;
static BIN_ATTR_RO ( protkey_aes_256 , sizeof ( struct protaeskeytoken ) ) ;
static BIN_ATTR_RO ( protkey_aes_128_xts , 2 * sizeof ( struct protaeskeytoken ) ) ;
static BIN_ATTR_RO ( protkey_aes_256_xts , 2 * sizeof ( struct protaeskeytoken ) ) ;
static struct bin_attribute * protkey_attrs [ ] = {
& bin_attr_protkey_aes_128 ,
& bin_attr_protkey_aes_192 ,
& bin_attr_protkey_aes_256 ,
& bin_attr_protkey_aes_128_xts ,
& bin_attr_protkey_aes_256_xts ,
NULL
} ;
static struct attribute_group protkey_attr_group = {
. name = " protkey " ,
. bin_attrs = protkey_attrs ,
} ;
2018-08-24 11:29:43 +03:00
/*
* Sysfs attribute read function for all secure key ccadata binary attributes .
* The implementation can not deal with partial reads , because a new random
* protected key blob is generated with each read . In case of partial reads
* ( i . e . off ! = 0 or count < key blob size ) - EINVAL is returned .
*/
static ssize_t pkey_ccadata_aes_attr_read ( u32 keytype , bool is_xts , char * buf ,
loff_t off , size_t count )
{
int rc ;
if ( off ! = 0 | | count < sizeof ( struct secaeskeytoken ) )
return - EINVAL ;
if ( is_xts )
if ( count < 2 * sizeof ( struct secaeskeytoken ) )
return - EINVAL ;
rc = pkey_genseckey ( - 1 , - 1 , keytype , ( struct pkey_seckey * ) buf ) ;
if ( rc )
return rc ;
if ( is_xts ) {
buf + = sizeof ( struct pkey_seckey ) ;
rc = pkey_genseckey ( - 1 , - 1 , keytype , ( struct pkey_seckey * ) buf ) ;
if ( rc )
return rc ;
return 2 * sizeof ( struct secaeskeytoken ) ;
}
return sizeof ( struct secaeskeytoken ) ;
}
static ssize_t ccadata_aes_128_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_ccadata_aes_attr_read ( PKEY_KEYTYPE_AES_128 , false , buf ,
off , count ) ;
}
static ssize_t ccadata_aes_192_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_ccadata_aes_attr_read ( PKEY_KEYTYPE_AES_192 , false , buf ,
off , count ) ;
}
static ssize_t ccadata_aes_256_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_ccadata_aes_attr_read ( PKEY_KEYTYPE_AES_256 , false , buf ,
off , count ) ;
}
static ssize_t ccadata_aes_128_xts_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_ccadata_aes_attr_read ( PKEY_KEYTYPE_AES_128 , true , buf ,
off , count ) ;
}
static ssize_t ccadata_aes_256_xts_read ( struct file * filp ,
struct kobject * kobj ,
struct bin_attribute * attr ,
char * buf , loff_t off ,
size_t count )
{
return pkey_ccadata_aes_attr_read ( PKEY_KEYTYPE_AES_256 , true , buf ,
off , count ) ;
}
static BIN_ATTR_RO ( ccadata_aes_128 , sizeof ( struct secaeskeytoken ) ) ;
static BIN_ATTR_RO ( ccadata_aes_192 , sizeof ( struct secaeskeytoken ) ) ;
static BIN_ATTR_RO ( ccadata_aes_256 , sizeof ( struct secaeskeytoken ) ) ;
static BIN_ATTR_RO ( ccadata_aes_128_xts , 2 * sizeof ( struct secaeskeytoken ) ) ;
static BIN_ATTR_RO ( ccadata_aes_256_xts , 2 * sizeof ( struct secaeskeytoken ) ) ;
static struct bin_attribute * ccadata_attrs [ ] = {
& bin_attr_ccadata_aes_128 ,
& bin_attr_ccadata_aes_192 ,
& bin_attr_ccadata_aes_256 ,
& bin_attr_ccadata_aes_128_xts ,
& bin_attr_ccadata_aes_256_xts ,
NULL
} ;
static struct attribute_group ccadata_attr_group = {
. name = " ccadata " ,
. bin_attrs = ccadata_attrs ,
} ;
2018-08-23 17:59:30 +03:00
static const struct attribute_group * pkey_attr_groups [ ] = {
& protkey_attr_group ,
2018-08-24 11:29:43 +03:00
& ccadata_attr_group ,
2018-08-23 17:59:30 +03:00
NULL ,
} ;
2016-11-02 16:37:20 +03:00
static const struct file_operations pkey_fops = {
. owner = THIS_MODULE ,
. open = nonseekable_open ,
. llseek = no_llseek ,
. unlocked_ioctl = pkey_unlocked_ioctl ,
} ;
static struct miscdevice pkey_dev = {
. name = " pkey " ,
. minor = MISC_DYNAMIC_MINOR ,
. mode = 0666 ,
. fops = & pkey_fops ,
2018-08-23 17:59:30 +03:00
. groups = pkey_attr_groups ,
2016-11-02 16:37:20 +03:00
} ;
/*
* Module init
*/
2017-05-09 13:44:21 +03:00
static int __init pkey_init ( void )
2016-11-02 16:37:20 +03:00
{
2018-08-23 18:49:38 +03:00
cpacf_mask_t pckmo_functions , kmc_functions ;
2016-11-02 16:37:20 +03:00
/* check for pckmo instructions available */
if ( ! cpacf_query ( CPACF_PCKMO , & pckmo_functions ) )
return - EOPNOTSUPP ;
if ( ! cpacf_test_func ( & pckmo_functions , CPACF_PCKMO_ENC_AES_128_KEY ) | |
! cpacf_test_func ( & pckmo_functions , CPACF_PCKMO_ENC_AES_192_KEY ) | |
! cpacf_test_func ( & pckmo_functions , CPACF_PCKMO_ENC_AES_256_KEY ) )
return - EOPNOTSUPP ;
2018-08-23 18:49:38 +03:00
/* check for kmc instructions available */
if ( ! cpacf_query ( CPACF_KMC , & kmc_functions ) )
return - EOPNOTSUPP ;
if ( ! cpacf_test_func ( & kmc_functions , CPACF_KMC_PAES_128 ) | |
! cpacf_test_func ( & kmc_functions , CPACF_KMC_PAES_192 ) | |
! cpacf_test_func ( & kmc_functions , CPACF_KMC_PAES_256 ) )
return - EOPNOTSUPP ;
2016-11-02 16:37:20 +03:00
pkey_debug_init ( ) ;
return misc_register ( & pkey_dev ) ;
}
/*
* Module exit
*/
static void __exit pkey_exit ( void )
{
misc_deregister ( & pkey_dev ) ;
mkvp_cache_free ( ) ;
pkey_debug_exit ( ) ;
}
module_init ( pkey_init ) ;
module_exit ( pkey_exit ) ;