2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-11-24 02:55:35 +03:00
/*
* Copyright ( C ) 2010 IBM Corporation
2011-06-27 15:45:42 +04:00
* Copyright ( C ) 2010 Politecnico di Torino , Italy
2020-07-06 00:45:12 +03:00
* TORSEC group - - https : //security.polito.it
2010-11-24 02:55:35 +03:00
*
2011-06-27 15:45:42 +04:00
* Authors :
2010-11-24 02:55:35 +03:00
* Mimi Zohar < zohar @ us . ibm . com >
2011-06-27 15:45:42 +04:00
* Roberto Sassu < roberto . sassu @ polito . it >
2010-11-24 02:55:35 +03:00
*
2017-05-13 14:51:53 +03:00
* See Documentation / security / keys / trusted - encrypted . rst
2010-11-24 02:55:35 +03:00
*/
# include <linux/uaccess.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/slab.h>
# include <linux/parser.h>
# include <linux/string.h>
2010-11-30 00:20:04 +03:00
# include <linux/err.h>
2010-11-24 02:55:35 +03:00
# include <keys/user-type.h>
# include <keys/trusted-type.h>
# include <keys/encrypted-type.h>
# include <linux/key-type.h>
# include <linux/random.h>
# include <linux/rcupdate.h>
# include <linux/scatterlist.h>
2011-06-27 15:45:44 +04:00
# include <linux/ctype.h>
2016-09-20 15:35:55 +03:00
# include <crypto/aes.h>
2017-06-08 16:48:32 +03:00
# include <crypto/algapi.h>
2010-11-24 02:55:35 +03:00
# include <crypto/hash.h>
2020-11-13 08:20:21 +03:00
# include <crypto/sha2.h>
2016-01-24 16:18:19 +03:00
# include <crypto/skcipher.h>
2010-11-24 02:55:35 +03:00
2011-01-18 17:07:12 +03:00
# include "encrypted.h"
2011-06-27 15:45:44 +04:00
# include "ecryptfs_format.h"
2010-11-24 02:55:35 +03:00
2010-12-14 00:53:13 +03:00
static const char KEY_TRUSTED_PREFIX [ ] = " trusted: " ;
static const char KEY_USER_PREFIX [ ] = " user: " ;
2010-11-24 02:55:35 +03:00
static const char hash_alg [ ] = " sha256 " ;
static const char hmac_alg [ ] = " hmac(sha256) " ;
static const char blkcipher_alg [ ] = " cbc(aes) " ;
2011-06-27 15:45:42 +04:00
static const char key_format_default [ ] = " default " ;
2011-06-27 15:45:44 +04:00
static const char key_format_ecryptfs [ ] = " ecryptfs " ;
2018-12-04 21:31:33 +03:00
static const char key_format_enc32 [ ] = " enc32 " ;
2010-11-24 02:55:35 +03:00
static unsigned int ivsize ;
static int blksize ;
2010-12-14 00:53:13 +03:00
# define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1)
# define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1)
2011-06-27 15:45:44 +04:00
# define KEY_ECRYPTFS_DESC_LEN 16
2010-12-14 00:53:13 +03:00
# define HASH_SIZE SHA256_DIGEST_SIZE
# define MAX_DATA_SIZE 4096
# define MIN_DATA_SIZE 20
2018-12-04 21:31:33 +03:00
# define KEY_ENC32_PAYLOAD_LEN 32
2010-12-14 00:53:13 +03:00
2017-06-08 16:48:25 +03:00
static struct crypto_shash * hash_tfm ;
2010-11-24 02:55:35 +03:00
enum {
2018-12-18 15:57:41 +03:00
Opt_new , Opt_load , Opt_update , Opt_err
2010-11-24 02:55:35 +03:00
} ;
2011-06-27 15:45:42 +04:00
enum {
2018-12-18 15:57:41 +03:00
Opt_default , Opt_ecryptfs , Opt_enc32 , Opt_error
2011-06-27 15:45:42 +04:00
} ;
static const match_table_t key_format_tokens = {
{ Opt_default , " default " } ,
2011-06-27 15:45:44 +04:00
{ Opt_ecryptfs , " ecryptfs " } ,
2018-12-04 21:31:33 +03:00
{ Opt_enc32 , " enc32 " } ,
2011-06-27 15:45:42 +04:00
{ Opt_error , NULL }
} ;
2010-11-24 02:55:35 +03:00
static const match_table_t key_tokens = {
{ Opt_new , " new " } ,
{ Opt_load , " load " } ,
{ Opt_update , " update " } ,
{ Opt_err , NULL }
} ;
2022-02-15 17:19:53 +03:00
static bool user_decrypted_data = IS_ENABLED ( CONFIG_USER_DECRYPTED_DATA ) ;
module_param ( user_decrypted_data , bool , 0 ) ;
MODULE_PARM_DESC ( user_decrypted_data ,
" Allow instantiation of encrypted keys using provided decrypted data " ) ;
2010-11-24 02:55:35 +03:00
static int aes_get_sizes ( void )
{
2016-01-24 16:18:19 +03:00
struct crypto_skcipher * tfm ;
2010-11-24 02:55:35 +03:00
2016-01-24 16:18:19 +03:00
tfm = crypto_alloc_skcipher ( blkcipher_alg , 0 , CRYPTO_ALG_ASYNC ) ;
2010-11-24 02:55:35 +03:00
if ( IS_ERR ( tfm ) ) {
pr_err ( " encrypted_key: failed to alloc_cipher (%ld) \n " ,
PTR_ERR ( tfm ) ) ;
return PTR_ERR ( tfm ) ;
}
2016-01-24 16:18:19 +03:00
ivsize = crypto_skcipher_ivsize ( tfm ) ;
blksize = crypto_skcipher_blocksize ( tfm ) ;
crypto_free_skcipher ( tfm ) ;
2010-11-24 02:55:35 +03:00
return 0 ;
}
2011-06-27 15:45:44 +04:00
/*
* valid_ecryptfs_desc - verify the description of a new / loaded encrypted key
*
* The description of a encrypted key with format ' ecryptfs ' must contain
* exactly 16 hexadecimal characters .
*
*/
static int valid_ecryptfs_desc ( const char * ecryptfs_desc )
{
int i ;
if ( strlen ( ecryptfs_desc ) ! = KEY_ECRYPTFS_DESC_LEN ) {
pr_err ( " encrypted_key: key description must be %d hexadecimal "
" characters long \n " , KEY_ECRYPTFS_DESC_LEN ) ;
return - EINVAL ;
}
for ( i = 0 ; i < KEY_ECRYPTFS_DESC_LEN ; i + + ) {
if ( ! isxdigit ( ecryptfs_desc [ i ] ) ) {
pr_err ( " encrypted_key: key description must contain "
" only hexadecimal characters \n " ) ;
return - EINVAL ;
}
}
return 0 ;
}
2010-11-24 02:55:35 +03:00
/*
* valid_master_desc - verify the ' key - type : desc ' of a new / updated master - key
*
2011-06-27 15:45:40 +04:00
* key - type : = " trusted: " | " user: "
2010-11-24 02:55:35 +03:00
* desc : = master - key description
*
* Verify that ' key - type ' is valid and that ' desc ' exists . On key update ,
* only the master key description is permitted to change , not the key - type .
* The key - type remains constant .
*
* On success returns 0 , otherwise - EINVAL .
*/
static int valid_master_desc ( const char * new_desc , const char * orig_desc )
{
2017-06-08 16:48:18 +03:00
int prefix_len ;
if ( ! strncmp ( new_desc , KEY_TRUSTED_PREFIX , KEY_TRUSTED_PREFIX_LEN ) )
prefix_len = KEY_TRUSTED_PREFIX_LEN ;
else if ( ! strncmp ( new_desc , KEY_USER_PREFIX , KEY_USER_PREFIX_LEN ) )
prefix_len = KEY_USER_PREFIX_LEN ;
else
return - EINVAL ;
if ( ! new_desc [ prefix_len ] )
return - EINVAL ;
if ( orig_desc & & strncmp ( new_desc , orig_desc , prefix_len ) )
return - EINVAL ;
2010-11-24 02:55:35 +03:00
return 0 ;
}
/*
* datablob_parse - parse the keyctl data
*
* datablob format :
2022-02-15 17:19:53 +03:00
* new [ < format > ] < master - key name > < decrypted data length > [ < decrypted data > ]
2011-06-27 15:45:42 +04:00
* load [ < format > ] < master - key name > < decrypted data length >
* < encrypted iv + data >
2010-11-24 02:55:35 +03:00
* update < new - master - key name >
*
* Tokenizes a copy of the keyctl data , returning a pointer to each token ,
* which is null terminated .
*
* On success returns 0 , otherwise - EINVAL .
*/
2011-06-27 15:45:42 +04:00
static int datablob_parse ( char * datablob , const char * * format ,
char * * master_desc , char * * decrypted_datalen ,
2022-02-15 17:19:53 +03:00
char * * hex_encoded_iv , char * * decrypted_data )
2010-11-24 02:55:35 +03:00
{
substring_t args [ MAX_OPT_ARGS ] ;
int ret = - EINVAL ;
int key_cmd ;
2011-06-27 15:45:42 +04:00
int key_format ;
char * p , * keyword ;
2010-11-24 02:55:35 +03:00
2011-06-27 15:45:41 +04:00
keyword = strsep ( & datablob , " \t " ) ;
if ( ! keyword ) {
pr_info ( " encrypted_key: insufficient parameters specified \n " ) ;
2010-11-24 02:55:35 +03:00
return ret ;
2011-06-27 15:45:41 +04:00
}
key_cmd = match_token ( keyword , key_tokens , args ) ;
2010-11-24 02:55:35 +03:00
2011-06-27 15:45:44 +04:00
/* Get optional format: default | ecryptfs */
2011-06-27 15:45:42 +04:00
p = strsep ( & datablob , " \t " ) ;
if ( ! p ) {
pr_err ( " encrypted_key: insufficient parameters specified \n " ) ;
return ret ;
}
key_format = match_token ( p , key_format_tokens , args ) ;
switch ( key_format ) {
2011-06-27 15:45:44 +04:00
case Opt_ecryptfs :
2018-12-04 21:31:33 +03:00
case Opt_enc32 :
2011-06-27 15:45:42 +04:00
case Opt_default :
* format = p ;
* master_desc = strsep ( & datablob , " \t " ) ;
break ;
case Opt_error :
* master_desc = p ;
break ;
}
2011-06-27 15:45:41 +04:00
if ( ! * master_desc ) {
pr_info ( " encrypted_key: master key parameter is missing \n " ) ;
2010-11-24 02:55:35 +03:00
goto out ;
2011-06-27 15:45:41 +04:00
}
2010-11-24 02:55:35 +03:00
2011-06-27 15:45:41 +04:00
if ( valid_master_desc ( * master_desc , NULL ) < 0 ) {
pr_info ( " encrypted_key: master key parameter \' %s \' "
" is invalid \n " , * master_desc ) ;
2010-11-24 02:55:35 +03:00
goto out ;
2011-06-27 15:45:41 +04:00
}
2010-11-24 02:55:35 +03:00
if ( decrypted_datalen ) {
* decrypted_datalen = strsep ( & datablob , " \t " ) ;
2011-06-27 15:45:41 +04:00
if ( ! * decrypted_datalen ) {
pr_info ( " encrypted_key: keylen parameter is missing \n " ) ;
2010-11-24 02:55:35 +03:00
goto out ;
2011-06-27 15:45:41 +04:00
}
2010-11-24 02:55:35 +03:00
}
switch ( key_cmd ) {
case Opt_new :
2011-06-27 15:45:41 +04:00
if ( ! decrypted_datalen ) {
pr_info ( " encrypted_key: keyword \' %s \' not allowed "
" when called from .update method \n " , keyword ) ;
2010-11-24 02:55:35 +03:00
break ;
2011-06-27 15:45:41 +04:00
}
2022-02-15 17:19:53 +03:00
* decrypted_data = strsep ( & datablob , " \t " ) ;
2010-11-24 02:55:35 +03:00
ret = 0 ;
break ;
case Opt_load :
2011-06-27 15:45:41 +04:00
if ( ! decrypted_datalen ) {
pr_info ( " encrypted_key: keyword \' %s \' not allowed "
" when called from .update method \n " , keyword ) ;
2010-11-24 02:55:35 +03:00
break ;
2011-06-27 15:45:41 +04:00
}
2010-11-24 02:55:35 +03:00
* hex_encoded_iv = strsep ( & datablob , " \t " ) ;
2011-06-27 15:45:41 +04:00
if ( ! * hex_encoded_iv ) {
pr_info ( " encrypted_key: hex blob is missing \n " ) ;
2010-11-24 02:55:35 +03:00
break ;
2011-06-27 15:45:41 +04:00
}
2010-11-24 02:55:35 +03:00
ret = 0 ;
break ;
case Opt_update :
2011-06-27 15:45:41 +04:00
if ( decrypted_datalen ) {
pr_info ( " encrypted_key: keyword \' %s \' not allowed "
" when called from .instantiate method \n " ,
keyword ) ;
2010-11-24 02:55:35 +03:00
break ;
2011-06-27 15:45:41 +04:00
}
2010-11-24 02:55:35 +03:00
ret = 0 ;
break ;
case Opt_err :
2011-06-27 15:45:41 +04:00
pr_info ( " encrypted_key: keyword \' %s \' not recognized \n " ,
keyword ) ;
2010-11-24 02:55:35 +03:00
break ;
}
out :
return ret ;
}
/*
* datablob_format - format as an ascii string , before copying to userspace
*/
static char * datablob_format ( struct encrypted_key_payload * epayload ,
size_t asciiblob_len )
{
char * ascii_buf , * bufp ;
u8 * iv = epayload - > iv ;
int len ;
int i ;
ascii_buf = kmalloc ( asciiblob_len + 1 , GFP_KERNEL ) ;
if ( ! ascii_buf )
goto out ;
ascii_buf [ asciiblob_len ] = ' \0 ' ;
/* copy datablob master_desc and datalen strings */
2011-06-27 15:45:42 +04:00
len = sprintf ( ascii_buf , " %s %s %s " , epayload - > format ,
epayload - > master_desc , epayload - > datalen ) ;
2010-11-24 02:55:35 +03:00
/* convert the hex encoded iv, encrypted-data and HMAC to ascii */
bufp = & ascii_buf [ len ] ;
for ( i = 0 ; i < ( asciiblob_len - len ) / 2 ; i + + )
2011-11-01 04:12:55 +04:00
bufp = hex_byte_pack ( bufp , iv [ i ] ) ;
2010-11-24 02:55:35 +03:00
out :
return ascii_buf ;
}
/*
* request_user_key - request the user key
*
* Use a user provided key to encrypt / decrypt an encrypted - key .
*/
2015-10-21 16:04:48 +03:00
static struct key * request_user_key ( const char * master_desc , const u8 * * master_key ,
2010-12-14 00:53:13 +03:00
size_t * master_keylen )
2010-11-24 02:55:35 +03:00
{
2015-10-21 16:04:48 +03:00
const struct user_key_payload * upayload ;
2010-11-24 02:55:35 +03:00
struct key * ukey ;
2019-07-11 04:43:43 +03:00
ukey = request_key ( & key_type_user , master_desc , NULL ) ;
2010-11-24 02:55:35 +03:00
if ( IS_ERR ( ukey ) )
goto error ;
down_read ( & ukey - > sem ) ;
2017-03-01 18:11:23 +03:00
upayload = user_key_payload_locked ( ukey ) ;
2017-10-09 22:37:49 +03:00
if ( ! upayload ) {
/* key was revoked before we acquired its semaphore */
up_read ( & ukey - > sem ) ;
key_put ( ukey ) ;
ukey = ERR_PTR ( - EKEYREVOKED ) ;
goto error ;
}
2010-11-24 02:55:35 +03:00
* master_key = upayload - > data ;
* master_keylen = upayload - > datalen ;
error :
return ukey ;
}
2017-06-08 16:48:25 +03:00
static int calc_hmac ( u8 * digest , const u8 * key , unsigned int keylen ,
const u8 * buf , unsigned int buflen )
2010-11-24 02:55:35 +03:00
{
2017-06-08 16:48:25 +03:00
struct crypto_shash * tfm ;
int err ;
2010-11-24 02:55:35 +03:00
2018-11-14 23:21:11 +03:00
tfm = crypto_alloc_shash ( hmac_alg , 0 , 0 ) ;
2017-06-08 16:48:25 +03:00
if ( IS_ERR ( tfm ) ) {
pr_err ( " encrypted_key: can't alloc %s transform: %ld \n " ,
hmac_alg , PTR_ERR ( tfm ) ) ;
return PTR_ERR ( tfm ) ;
2010-11-24 02:55:35 +03:00
}
2017-06-08 16:48:25 +03:00
err = crypto_shash_setkey ( tfm , key , keylen ) ;
if ( ! err )
2020-05-02 08:31:21 +03:00
err = crypto_shash_tfm_digest ( tfm , buf , buflen , digest ) ;
2017-06-08 16:48:25 +03:00
crypto_free_shash ( tfm ) ;
return err ;
2010-11-24 02:55:35 +03:00
}
enum derived_key_type { ENC_KEY , AUTH_KEY } ;
/* Derive authentication/encryption key from trusted key */
static int get_derived_key ( u8 * derived_key , enum derived_key_type key_type ,
2010-12-14 00:53:13 +03:00
const u8 * master_key , size_t master_keylen )
2010-11-24 02:55:35 +03:00
{
u8 * derived_buf ;
unsigned int derived_buf_len ;
int ret ;
derived_buf_len = strlen ( " AUTH_KEY " ) + 1 + master_keylen ;
if ( derived_buf_len < HASH_SIZE )
derived_buf_len = HASH_SIZE ;
derived_buf = kzalloc ( derived_buf_len , GFP_KERNEL ) ;
2017-06-08 16:47:56 +03:00
if ( ! derived_buf )
2010-11-24 02:55:35 +03:00
return - ENOMEM ;
2017-06-08 16:47:56 +03:00
2010-11-24 02:55:35 +03:00
if ( key_type )
strcpy ( derived_buf , " AUTH_KEY " ) ;
else
strcpy ( derived_buf , " ENC_KEY " ) ;
memcpy ( derived_buf + strlen ( derived_buf ) + 1 , master_key ,
master_keylen ) ;
2020-05-02 08:31:21 +03:00
ret = crypto_shash_tfm_digest ( hash_tfm , derived_buf , derived_buf_len ,
derived_key ) ;
2020-08-07 09:18:13 +03:00
kfree_sensitive ( derived_buf ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
2016-01-24 16:18:19 +03:00
static struct skcipher_request * init_skcipher_req ( const u8 * key ,
unsigned int key_len )
2010-11-24 02:55:35 +03:00
{
2016-01-24 16:18:19 +03:00
struct skcipher_request * req ;
struct crypto_skcipher * tfm ;
2010-11-24 02:55:35 +03:00
int ret ;
2016-01-24 16:18:19 +03:00
tfm = crypto_alloc_skcipher ( blkcipher_alg , 0 , CRYPTO_ALG_ASYNC ) ;
if ( IS_ERR ( tfm ) ) {
2010-11-24 02:55:35 +03:00
pr_err ( " encrypted_key: failed to load %s transform (%ld) \n " ,
2016-01-24 16:18:19 +03:00
blkcipher_alg , PTR_ERR ( tfm ) ) ;
return ERR_CAST ( tfm ) ;
2010-11-24 02:55:35 +03:00
}
2016-01-24 16:18:19 +03:00
ret = crypto_skcipher_setkey ( tfm , key , key_len ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 ) {
pr_err ( " encrypted_key: failed to setkey (%d) \n " , ret ) ;
2016-01-24 16:18:19 +03:00
crypto_free_skcipher ( tfm ) ;
return ERR_PTR ( ret ) ;
2010-11-24 02:55:35 +03:00
}
2016-01-24 16:18:19 +03:00
req = skcipher_request_alloc ( tfm , GFP_KERNEL ) ;
if ( ! req ) {
pr_err ( " encrypted_key: failed to allocate request for %s \n " ,
blkcipher_alg ) ;
crypto_free_skcipher ( tfm ) ;
return ERR_PTR ( - ENOMEM ) ;
}
skcipher_request_set_callback ( req , 0 , NULL , NULL ) ;
return req ;
2010-11-24 02:55:35 +03:00
}
static struct key * request_master_key ( struct encrypted_key_payload * epayload ,
2015-10-21 16:04:48 +03:00
const u8 * * master_key , size_t * master_keylen )
2010-11-24 02:55:35 +03:00
{
2017-02-09 20:17:52 +03:00
struct key * mkey = ERR_PTR ( - EINVAL ) ;
2010-11-24 02:55:35 +03:00
if ( ! strncmp ( epayload - > master_desc , KEY_TRUSTED_PREFIX ,
KEY_TRUSTED_PREFIX_LEN ) ) {
mkey = request_trusted_key ( epayload - > master_desc +
KEY_TRUSTED_PREFIX_LEN ,
master_key , master_keylen ) ;
} else if ( ! strncmp ( epayload - > master_desc , KEY_USER_PREFIX ,
KEY_USER_PREFIX_LEN ) ) {
mkey = request_user_key ( epayload - > master_desc +
KEY_USER_PREFIX_LEN ,
master_key , master_keylen ) ;
} else
goto out ;
2011-06-27 15:45:39 +04:00
if ( IS_ERR ( mkey ) ) {
2011-10-24 16:17:42 +04:00
int ret = PTR_ERR ( mkey ) ;
2011-08-28 06:21:26 +04:00
if ( ret = = - ENOTSUPP )
pr_info ( " encrypted_key: key %s not supported " ,
epayload - > master_desc ) ;
else
pr_info ( " encrypted_key: key %s not found " ,
epayload - > master_desc ) ;
2011-06-27 15:45:39 +04:00
goto out ;
}
dump_master_key ( * master_key , * master_keylen ) ;
2010-11-24 02:55:35 +03:00
out :
return mkey ;
}
/* Before returning data to userspace, encrypt decrypted data. */
static int derived_key_encrypt ( struct encrypted_key_payload * epayload ,
const u8 * derived_key ,
2010-12-14 00:53:13 +03:00
unsigned int derived_keylen )
2010-11-24 02:55:35 +03:00
{
struct scatterlist sg_in [ 2 ] ;
struct scatterlist sg_out [ 1 ] ;
2016-01-24 16:18:19 +03:00
struct crypto_skcipher * tfm ;
struct skcipher_request * req ;
2010-11-24 02:55:35 +03:00
unsigned int encrypted_datalen ;
2016-09-20 15:35:55 +03:00
u8 iv [ AES_BLOCK_SIZE ] ;
2010-11-24 02:55:35 +03:00
int ret ;
encrypted_datalen = roundup ( epayload - > decrypted_datalen , blksize ) ;
2016-01-24 16:18:19 +03:00
req = init_skcipher_req ( derived_key , derived_keylen ) ;
ret = PTR_ERR ( req ) ;
if ( IS_ERR ( req ) )
2010-11-24 02:55:35 +03:00
goto out ;
dump_decrypted_data ( epayload ) ;
sg_init_table ( sg_in , 2 ) ;
sg_set_buf ( & sg_in [ 0 ] , epayload - > decrypted_data ,
epayload - > decrypted_datalen ) ;
2017-06-08 16:48:10 +03:00
sg_set_page ( & sg_in [ 1 ] , ZERO_PAGE ( 0 ) , AES_BLOCK_SIZE , 0 ) ;
2010-11-24 02:55:35 +03:00
sg_init_table ( sg_out , 1 ) ;
sg_set_buf ( sg_out , epayload - > encrypted_data , encrypted_datalen ) ;
2016-09-20 15:35:55 +03:00
memcpy ( iv , epayload - > iv , sizeof ( iv ) ) ;
skcipher_request_set_crypt ( req , sg_in , sg_out , encrypted_datalen , iv ) ;
2016-01-24 16:18:19 +03:00
ret = crypto_skcipher_encrypt ( req ) ;
tfm = crypto_skcipher_reqtfm ( req ) ;
skcipher_request_free ( req ) ;
crypto_free_skcipher ( tfm ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 )
pr_err ( " encrypted_key: failed to encrypt (%d) \n " , ret ) ;
else
dump_encrypted_data ( epayload , encrypted_datalen ) ;
out :
return ret ;
}
static int datablob_hmac_append ( struct encrypted_key_payload * epayload ,
2010-12-14 00:53:13 +03:00
const u8 * master_key , size_t master_keylen )
2010-11-24 02:55:35 +03:00
{
u8 derived_key [ HASH_SIZE ] ;
u8 * digest ;
int ret ;
ret = get_derived_key ( derived_key , AUTH_KEY , master_key , master_keylen ) ;
if ( ret < 0 )
goto out ;
2011-06-27 15:45:42 +04:00
digest = epayload - > format + epayload - > datablob_len ;
2010-11-24 02:55:35 +03:00
ret = calc_hmac ( digest , derived_key , sizeof derived_key ,
2011-06-27 15:45:42 +04:00
epayload - > format , epayload - > datablob_len ) ;
2010-11-24 02:55:35 +03:00
if ( ! ret )
dump_hmac ( NULL , digest , HASH_SIZE ) ;
out :
2017-06-08 16:49:11 +03:00
memzero_explicit ( derived_key , sizeof ( derived_key ) ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
/* verify HMAC before decrypting encrypted key */
static int datablob_hmac_verify ( struct encrypted_key_payload * epayload ,
2011-06-27 15:45:42 +04:00
const u8 * format , const u8 * master_key ,
size_t master_keylen )
2010-11-24 02:55:35 +03:00
{
u8 derived_key [ HASH_SIZE ] ;
u8 digest [ HASH_SIZE ] ;
int ret ;
2011-06-27 15:45:42 +04:00
char * p ;
unsigned short len ;
2010-11-24 02:55:35 +03:00
ret = get_derived_key ( derived_key , AUTH_KEY , master_key , master_keylen ) ;
if ( ret < 0 )
goto out ;
2011-06-27 15:45:42 +04:00
len = epayload - > datablob_len ;
if ( ! format ) {
p = epayload - > master_desc ;
len - = strlen ( epayload - > format ) + 1 ;
} else
p = epayload - > format ;
ret = calc_hmac ( digest , derived_key , sizeof derived_key , p , len ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 )
goto out ;
2017-06-08 16:48:32 +03:00
ret = crypto_memneq ( digest , epayload - > format + epayload - > datablob_len ,
sizeof ( digest ) ) ;
2010-11-24 02:55:35 +03:00
if ( ret ) {
ret = - EINVAL ;
dump_hmac ( " datablob " ,
2011-06-27 15:45:42 +04:00
epayload - > format + epayload - > datablob_len ,
2010-11-24 02:55:35 +03:00
HASH_SIZE ) ;
dump_hmac ( " calc " , digest , HASH_SIZE ) ;
}
out :
2017-06-08 16:49:11 +03:00
memzero_explicit ( derived_key , sizeof ( derived_key ) ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
static int derived_key_decrypt ( struct encrypted_key_payload * epayload ,
const u8 * derived_key ,
2010-12-14 00:53:13 +03:00
unsigned int derived_keylen )
2010-11-24 02:55:35 +03:00
{
struct scatterlist sg_in [ 1 ] ;
struct scatterlist sg_out [ 2 ] ;
2016-01-24 16:18:19 +03:00
struct crypto_skcipher * tfm ;
struct skcipher_request * req ;
2010-11-24 02:55:35 +03:00
unsigned int encrypted_datalen ;
2016-09-20 15:35:55 +03:00
u8 iv [ AES_BLOCK_SIZE ] ;
2017-06-08 16:48:10 +03:00
u8 * pad ;
2010-11-24 02:55:35 +03:00
int ret ;
2017-06-08 16:48:10 +03:00
/* Throwaway buffer to hold the unused zero padding at the end */
pad = kmalloc ( AES_BLOCK_SIZE , GFP_KERNEL ) ;
if ( ! pad )
return - ENOMEM ;
2010-11-24 02:55:35 +03:00
encrypted_datalen = roundup ( epayload - > decrypted_datalen , blksize ) ;
2016-01-24 16:18:19 +03:00
req = init_skcipher_req ( derived_key , derived_keylen ) ;
ret = PTR_ERR ( req ) ;
if ( IS_ERR ( req ) )
2010-11-24 02:55:35 +03:00
goto out ;
dump_encrypted_data ( epayload , encrypted_datalen ) ;
sg_init_table ( sg_in , 1 ) ;
sg_init_table ( sg_out , 2 ) ;
sg_set_buf ( sg_in , epayload - > encrypted_data , encrypted_datalen ) ;
sg_set_buf ( & sg_out [ 0 ] , epayload - > decrypted_data ,
2010-12-14 00:53:13 +03:00
epayload - > decrypted_datalen ) ;
2017-06-08 16:48:10 +03:00
sg_set_buf ( & sg_out [ 1 ] , pad , AES_BLOCK_SIZE ) ;
2010-11-24 02:55:35 +03:00
2016-09-20 15:35:55 +03:00
memcpy ( iv , epayload - > iv , sizeof ( iv ) ) ;
skcipher_request_set_crypt ( req , sg_in , sg_out , encrypted_datalen , iv ) ;
2016-01-24 16:18:19 +03:00
ret = crypto_skcipher_decrypt ( req ) ;
tfm = crypto_skcipher_reqtfm ( req ) ;
skcipher_request_free ( req ) ;
crypto_free_skcipher ( tfm ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 )
goto out ;
dump_decrypted_data ( epayload ) ;
out :
2017-06-08 16:48:10 +03:00
kfree ( pad ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
/* Allocate memory for decrypted key and datablob. */
static struct encrypted_key_payload * encrypted_key_alloc ( struct key * key ,
2011-06-27 15:45:42 +04:00
const char * format ,
2010-11-24 02:55:35 +03:00
const char * master_desc ,
2022-02-15 17:19:53 +03:00
const char * datalen ,
const char * decrypted_data )
2010-11-24 02:55:35 +03:00
{
struct encrypted_key_payload * epayload = NULL ;
unsigned short datablob_len ;
unsigned short decrypted_datalen ;
2011-06-27 15:45:42 +04:00
unsigned short payload_datalen ;
2010-11-24 02:55:35 +03:00
unsigned int encrypted_datalen ;
2011-06-27 15:45:42 +04:00
unsigned int format_len ;
2010-11-24 02:55:35 +03:00
long dlen ;
2022-02-15 17:19:53 +03:00
int i ;
2010-11-24 02:55:35 +03:00
int ret ;
2014-02-05 10:13:14 +04:00
ret = kstrtol ( datalen , 10 , & dlen ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 | | dlen < MIN_DATA_SIZE | | dlen > MAX_DATA_SIZE )
return ERR_PTR ( - EINVAL ) ;
2011-06-27 15:45:42 +04:00
format_len = ( ! format ) ? strlen ( key_format_default ) : strlen ( format ) ;
2010-11-24 02:55:35 +03:00
decrypted_datalen = dlen ;
2011-06-27 15:45:42 +04:00
payload_datalen = decrypted_datalen ;
2022-02-15 17:19:53 +03:00
if ( decrypted_data ) {
if ( ! user_decrypted_data ) {
pr_err ( " encrypted key: instantiation of keys using provided decrypted data is disabled since CONFIG_USER_DECRYPTED_DATA is set to false \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
if ( strlen ( decrypted_data ) ! = decrypted_datalen ) {
pr_err ( " encrypted key: decrypted data provided does not match decrypted data length provided \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
for ( i = 0 ; i < strlen ( decrypted_data ) ; i + + ) {
if ( ! isxdigit ( decrypted_data [ i ] ) ) {
pr_err ( " encrypted key: decrypted data provided must contain only hexadecimal characters \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
}
}
2018-12-04 21:31:33 +03:00
if ( format ) {
if ( ! strcmp ( format , key_format_ecryptfs ) ) {
if ( dlen ! = ECRYPTFS_MAX_KEY_BYTES ) {
pr_err ( " encrypted_key: keylen for the ecryptfs format must be equal to %d bytes \n " ,
ECRYPTFS_MAX_KEY_BYTES ) ;
return ERR_PTR ( - EINVAL ) ;
}
decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES ;
payload_datalen = sizeof ( struct ecryptfs_auth_tok ) ;
} else if ( ! strcmp ( format , key_format_enc32 ) ) {
if ( decrypted_datalen ! = KEY_ENC32_PAYLOAD_LEN ) {
pr_err ( " encrypted_key: enc32 key payload incorrect length: %d \n " ,
decrypted_datalen ) ;
return ERR_PTR ( - EINVAL ) ;
}
2011-06-27 15:45:44 +04:00
}
}
2010-11-24 02:55:35 +03:00
encrypted_datalen = roundup ( decrypted_datalen , blksize ) ;
2011-06-27 15:45:42 +04:00
datablob_len = format_len + 1 + strlen ( master_desc ) + 1
+ strlen ( datalen ) + 1 + ivsize + 1 + encrypted_datalen ;
2010-11-24 02:55:35 +03:00
2011-06-27 15:45:42 +04:00
ret = key_payload_reserve ( key , payload_datalen + datablob_len
2010-11-24 02:55:35 +03:00
+ HASH_SIZE + 1 ) ;
if ( ret < 0 )
return ERR_PTR ( ret ) ;
2011-06-27 15:45:42 +04:00
epayload = kzalloc ( sizeof ( * epayload ) + payload_datalen +
2010-11-24 02:55:35 +03:00
datablob_len + HASH_SIZE + 1 , GFP_KERNEL ) ;
if ( ! epayload )
return ERR_PTR ( - ENOMEM ) ;
2011-06-27 15:45:42 +04:00
epayload - > payload_datalen = payload_datalen ;
2010-11-24 02:55:35 +03:00
epayload - > decrypted_datalen = decrypted_datalen ;
epayload - > datablob_len = datablob_len ;
return epayload ;
}
static int encrypted_key_decrypt ( struct encrypted_key_payload * epayload ,
2011-06-27 15:45:42 +04:00
const char * format , const char * hex_encoded_iv )
2010-11-24 02:55:35 +03:00
{
struct key * mkey ;
u8 derived_key [ HASH_SIZE ] ;
2015-10-21 16:04:48 +03:00
const u8 * master_key ;
2010-11-24 02:55:35 +03:00
u8 * hmac ;
2010-12-14 00:53:12 +03:00
const char * hex_encoded_data ;
2010-11-24 02:55:35 +03:00
unsigned int encrypted_datalen ;
2010-12-14 00:53:13 +03:00
size_t master_keylen ;
2010-12-14 00:53:12 +03:00
size_t asciilen ;
2010-11-24 02:55:35 +03:00
int ret ;
encrypted_datalen = roundup ( epayload - > decrypted_datalen , blksize ) ;
2010-12-14 00:53:12 +03:00
asciilen = ( ivsize + 1 + encrypted_datalen + HASH_SIZE ) * 2 ;
if ( strlen ( hex_encoded_iv ) ! = asciilen )
return - EINVAL ;
hex_encoded_data = hex_encoded_iv + ( 2 * ivsize ) + 2 ;
2011-09-20 19:23:55 +04:00
ret = hex2bin ( epayload - > iv , hex_encoded_iv , ivsize ) ;
if ( ret < 0 )
return - EINVAL ;
ret = hex2bin ( epayload - > encrypted_data , hex_encoded_data ,
encrypted_datalen ) ;
if ( ret < 0 )
return - EINVAL ;
2010-11-24 02:55:35 +03:00
2011-06-27 15:45:42 +04:00
hmac = epayload - > format + epayload - > datablob_len ;
2011-09-20 19:23:55 +04:00
ret = hex2bin ( hmac , hex_encoded_data + ( encrypted_datalen * 2 ) ,
HASH_SIZE ) ;
if ( ret < 0 )
return - EINVAL ;
2010-11-24 02:55:35 +03:00
mkey = request_master_key ( epayload , & master_key , & master_keylen ) ;
if ( IS_ERR ( mkey ) )
return PTR_ERR ( mkey ) ;
2011-06-27 15:45:42 +04:00
ret = datablob_hmac_verify ( epayload , format , master_key , master_keylen ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 ) {
pr_err ( " encrypted_key: bad hmac (%d) \n " , ret ) ;
goto out ;
}
ret = get_derived_key ( derived_key , ENC_KEY , master_key , master_keylen ) ;
if ( ret < 0 )
goto out ;
ret = derived_key_decrypt ( epayload , derived_key , sizeof derived_key ) ;
if ( ret < 0 )
pr_err ( " encrypted_key: failed to decrypt key (%d) \n " , ret ) ;
out :
up_read ( & mkey - > sem ) ;
key_put ( mkey ) ;
2017-06-08 16:49:11 +03:00
memzero_explicit ( derived_key , sizeof ( derived_key ) ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
static void __ekey_init ( struct encrypted_key_payload * epayload ,
2011-06-27 15:45:42 +04:00
const char * format , const char * master_desc ,
const char * datalen )
2010-11-24 02:55:35 +03:00
{
2011-06-27 15:45:42 +04:00
unsigned int format_len ;
format_len = ( ! format ) ? strlen ( key_format_default ) : strlen ( format ) ;
epayload - > format = epayload - > payload_data + epayload - > payload_datalen ;
epayload - > master_desc = epayload - > format + format_len + 1 ;
2010-11-24 02:55:35 +03:00
epayload - > datalen = epayload - > master_desc + strlen ( master_desc ) + 1 ;
epayload - > iv = epayload - > datalen + strlen ( datalen ) + 1 ;
epayload - > encrypted_data = epayload - > iv + ivsize + 1 ;
2011-06-27 15:45:42 +04:00
epayload - > decrypted_data = epayload - > payload_data ;
2010-11-24 02:55:35 +03:00
2011-06-27 15:45:42 +04:00
if ( ! format )
memcpy ( epayload - > format , key_format_default , format_len ) ;
2011-06-27 15:45:44 +04:00
else {
if ( ! strcmp ( format , key_format_ecryptfs ) )
epayload - > decrypted_data =
ecryptfs_get_auth_tok_key ( ( struct ecryptfs_auth_tok * ) epayload - > payload_data ) ;
2011-06-27 15:45:42 +04:00
memcpy ( epayload - > format , format , format_len ) ;
2011-06-27 15:45:44 +04:00
}
2010-11-24 02:55:35 +03:00
memcpy ( epayload - > master_desc , master_desc , strlen ( master_desc ) ) ;
memcpy ( epayload - > datalen , datalen , strlen ( datalen ) ) ;
}
/*
* encrypted_init - initialize an encrypted key
*
2022-02-15 17:19:53 +03:00
* For a new key , use either a random number or user - provided decrypted data in
* case it is provided . A random number is used for the iv in both cases . For
* an old key , decrypt the hex encoded data .
2010-11-24 02:55:35 +03:00
*/
static int encrypted_init ( struct encrypted_key_payload * epayload ,
2011-06-27 15:45:44 +04:00
const char * key_desc , const char * format ,
const char * master_desc , const char * datalen ,
2022-02-15 17:19:53 +03:00
const char * hex_encoded_iv , const char * decrypted_data )
2010-11-24 02:55:35 +03:00
{
int ret = 0 ;
2011-06-27 15:45:44 +04:00
if ( format & & ! strcmp ( format , key_format_ecryptfs ) ) {
ret = valid_ecryptfs_desc ( key_desc ) ;
if ( ret < 0 )
return ret ;
ecryptfs_fill_auth_tok ( ( struct ecryptfs_auth_tok * ) epayload - > payload_data ,
key_desc ) ;
}
2011-06-27 15:45:42 +04:00
__ekey_init ( epayload , format , master_desc , datalen ) ;
2022-02-15 17:19:53 +03:00
if ( hex_encoded_iv ) {
2011-06-27 15:45:42 +04:00
ret = encrypted_key_decrypt ( epayload , format , hex_encoded_iv ) ;
2022-02-15 17:19:53 +03:00
} else if ( decrypted_data ) {
get_random_bytes ( epayload - > iv , ivsize ) ;
memcpy ( epayload - > decrypted_data , decrypted_data ,
epayload - > decrypted_datalen ) ;
} else {
get_random_bytes ( epayload - > iv , ivsize ) ;
get_random_bytes ( epayload - > decrypted_data , epayload - > decrypted_datalen ) ;
}
2010-11-24 02:55:35 +03:00
return ret ;
}
/*
* encrypted_instantiate - instantiate an encrypted key
*
2022-02-15 17:19:53 +03:00
* Instantiates the key :
* - by decrypting an existing encrypted datablob , or
* - by creating a new encrypted key based on a kernel random number , or
* - using provided decrypted data .
2010-11-24 02:55:35 +03:00
*
* On success , return 0. Otherwise return errno .
*/
2012-09-13 16:06:29 +04:00
static int encrypted_instantiate ( struct key * key ,
struct key_preparsed_payload * prep )
2010-11-24 02:55:35 +03:00
{
struct encrypted_key_payload * epayload = NULL ;
char * datablob = NULL ;
2011-06-27 15:45:42 +04:00
const char * format = NULL ;
2010-11-24 02:55:35 +03:00
char * master_desc = NULL ;
char * decrypted_datalen = NULL ;
char * hex_encoded_iv = NULL ;
2022-02-15 17:19:53 +03:00
char * decrypted_data = NULL ;
2012-09-13 16:06:29 +04:00
size_t datalen = prep - > datalen ;
2010-11-24 02:55:35 +03:00
int ret ;
2012-09-13 16:06:29 +04:00
if ( datalen < = 0 | | datalen > 32767 | | ! prep - > data )
2010-11-24 02:55:35 +03:00
return - EINVAL ;
datablob = kmalloc ( datalen + 1 , GFP_KERNEL ) ;
if ( ! datablob )
return - ENOMEM ;
datablob [ datalen ] = 0 ;
2012-09-13 16:06:29 +04:00
memcpy ( datablob , prep - > data , datalen ) ;
2011-06-27 15:45:42 +04:00
ret = datablob_parse ( datablob , & format , & master_desc ,
2022-02-15 17:19:53 +03:00
& decrypted_datalen , & hex_encoded_iv , & decrypted_data ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 )
goto out ;
2011-06-27 15:45:42 +04:00
epayload = encrypted_key_alloc ( key , format , master_desc ,
2022-02-15 17:19:53 +03:00
decrypted_datalen , decrypted_data ) ;
2010-11-24 02:55:35 +03:00
if ( IS_ERR ( epayload ) ) {
ret = PTR_ERR ( epayload ) ;
goto out ;
}
2011-06-27 15:45:44 +04:00
ret = encrypted_init ( epayload , key - > description , format , master_desc ,
2022-02-15 17:19:53 +03:00
decrypted_datalen , hex_encoded_iv , decrypted_data ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 ) {
2020-08-07 09:18:13 +03:00
kfree_sensitive ( epayload ) ;
2010-11-24 02:55:35 +03:00
goto out ;
}
2014-07-27 07:21:02 +04:00
rcu_assign_keypointer ( key , epayload ) ;
2010-11-24 02:55:35 +03:00
out :
2020-08-07 09:18:13 +03:00
kfree_sensitive ( datablob ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
static void encrypted_rcu_free ( struct rcu_head * rcu )
{
struct encrypted_key_payload * epayload ;
epayload = container_of ( rcu , struct encrypted_key_payload , rcu ) ;
2020-08-07 09:18:13 +03:00
kfree_sensitive ( epayload ) ;
2010-11-24 02:55:35 +03:00
}
/*
* encrypted_update - update the master key description
*
* Change the master key description for an existing encrypted key .
* The next read will return an encrypted datablob using the new
* master key description .
*
* On success , return 0. Otherwise return errno .
*/
2012-09-13 16:06:29 +04:00
static int encrypted_update ( struct key * key , struct key_preparsed_payload * prep )
2010-11-24 02:55:35 +03:00
{
2015-10-21 16:04:48 +03:00
struct encrypted_key_payload * epayload = key - > payload . data [ 0 ] ;
2010-11-24 02:55:35 +03:00
struct encrypted_key_payload * new_epayload ;
char * buf ;
char * new_master_desc = NULL ;
2011-06-27 15:45:42 +04:00
const char * format = NULL ;
2012-09-13 16:06:29 +04:00
size_t datalen = prep - > datalen ;
2010-11-24 02:55:35 +03:00
int ret = 0 ;
2017-10-04 18:43:25 +03:00
if ( key_is_negative ( key ) )
2015-11-25 00:36:31 +03:00
return - ENOKEY ;
2012-09-13 16:06:29 +04:00
if ( datalen < = 0 | | datalen > 32767 | | ! prep - > data )
2010-11-24 02:55:35 +03:00
return - EINVAL ;
buf = kmalloc ( datalen + 1 , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
buf [ datalen ] = 0 ;
2012-09-13 16:06:29 +04:00
memcpy ( buf , prep - > data , datalen ) ;
2022-02-15 17:19:53 +03:00
ret = datablob_parse ( buf , & format , & new_master_desc , NULL , NULL , NULL ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 )
goto out ;
ret = valid_master_desc ( new_master_desc , epayload - > master_desc ) ;
if ( ret < 0 )
goto out ;
2011-06-27 15:45:42 +04:00
new_epayload = encrypted_key_alloc ( key , epayload - > format ,
2022-02-15 17:19:53 +03:00
new_master_desc , epayload - > datalen , NULL ) ;
2010-11-24 02:55:35 +03:00
if ( IS_ERR ( new_epayload ) ) {
ret = PTR_ERR ( new_epayload ) ;
goto out ;
}
2011-06-27 15:45:42 +04:00
__ekey_init ( new_epayload , epayload - > format , new_master_desc ,
epayload - > datalen ) ;
2010-11-24 02:55:35 +03:00
memcpy ( new_epayload - > iv , epayload - > iv , ivsize ) ;
2011-06-27 15:45:42 +04:00
memcpy ( new_epayload - > payload_data , epayload - > payload_data ,
epayload - > payload_datalen ) ;
2010-11-24 02:55:35 +03:00
2012-01-18 00:39:51 +04:00
rcu_assign_keypointer ( key , new_epayload ) ;
2010-11-24 02:55:35 +03:00
call_rcu ( & epayload - > rcu , encrypted_rcu_free ) ;
out :
2020-08-07 09:18:13 +03:00
kfree_sensitive ( buf ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
/*
2020-03-22 04:11:24 +03:00
* encrypted_read - format and copy out the encrypted data
2010-11-24 02:55:35 +03:00
*
* The resulting datablob format is :
* < master - key name > < decrypted data length > < encrypted iv > < encrypted data >
*
* On success , return to userspace the encrypted key datablob size .
*/
2020-03-22 04:11:24 +03:00
static long encrypted_read ( const struct key * key , char * buffer ,
2010-11-24 02:55:35 +03:00
size_t buflen )
{
struct encrypted_key_payload * epayload ;
struct key * mkey ;
2015-10-21 16:04:48 +03:00
const u8 * master_key ;
2010-12-14 00:53:13 +03:00
size_t master_keylen ;
2010-11-24 02:55:35 +03:00
char derived_key [ HASH_SIZE ] ;
char * ascii_buf ;
size_t asciiblob_len ;
int ret ;
2017-03-01 18:11:23 +03:00
epayload = dereference_key_locked ( key ) ;
2010-11-24 02:55:35 +03:00
/* returns the hex encoded iv, encrypted-data, and hmac as ascii */
asciiblob_len = epayload - > datablob_len + ivsize + 1
+ roundup ( epayload - > decrypted_datalen , blksize )
+ ( HASH_SIZE * 2 ) ;
if ( ! buffer | | buflen < asciiblob_len )
return asciiblob_len ;
mkey = request_master_key ( epayload , & master_key , & master_keylen ) ;
if ( IS_ERR ( mkey ) )
return PTR_ERR ( mkey ) ;
ret = get_derived_key ( derived_key , ENC_KEY , master_key , master_keylen ) ;
if ( ret < 0 )
goto out ;
ret = derived_key_encrypt ( epayload , derived_key , sizeof derived_key ) ;
if ( ret < 0 )
goto out ;
ret = datablob_hmac_append ( epayload , master_key , master_keylen ) ;
if ( ret < 0 )
goto out ;
ascii_buf = datablob_format ( epayload , asciiblob_len ) ;
if ( ! ascii_buf ) {
ret = - ENOMEM ;
goto out ;
}
up_read ( & mkey - > sem ) ;
key_put ( mkey ) ;
2017-06-08 16:49:11 +03:00
memzero_explicit ( derived_key , sizeof ( derived_key ) ) ;
2010-11-24 02:55:35 +03:00
2020-03-22 04:11:24 +03:00
memcpy ( buffer , ascii_buf , asciiblob_len ) ;
2020-08-07 09:18:13 +03:00
kfree_sensitive ( ascii_buf ) ;
2010-11-24 02:55:35 +03:00
return asciiblob_len ;
out :
up_read ( & mkey - > sem ) ;
key_put ( mkey ) ;
2017-06-08 16:49:11 +03:00
memzero_explicit ( derived_key , sizeof ( derived_key ) ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
/*
2017-06-08 16:49:11 +03:00
* encrypted_destroy - clear and free the key ' s payload
2010-11-24 02:55:35 +03:00
*/
static void encrypted_destroy ( struct key * key )
{
2020-08-07 09:18:13 +03:00
kfree_sensitive ( key - > payload . data [ 0 ] ) ;
2010-11-24 02:55:35 +03:00
}
struct key_type key_type_encrypted = {
. name = " encrypted " ,
. instantiate = encrypted_instantiate ,
. update = encrypted_update ,
. destroy = encrypted_destroy ,
. describe = user_describe ,
. read = encrypted_read ,
} ;
EXPORT_SYMBOL_GPL ( key_type_encrypted ) ;
2017-06-08 16:48:25 +03:00
static int __init init_encrypted ( void )
2010-11-24 02:55:35 +03:00
{
int ret ;
2018-11-14 23:21:11 +03:00
hash_tfm = crypto_alloc_shash ( hash_alg , 0 , 0 ) ;
2017-06-08 16:48:25 +03:00
if ( IS_ERR ( hash_tfm ) ) {
pr_err ( " encrypted_key: can't allocate %s transform: %ld \n " ,
hash_alg , PTR_ERR ( hash_tfm ) ) ;
return PTR_ERR ( hash_tfm ) ;
2010-11-24 02:55:35 +03:00
}
2014-12-04 20:25:19 +03:00
ret = aes_get_sizes ( ) ;
if ( ret < 0 )
goto out ;
2010-11-24 02:55:35 +03:00
ret = register_key_type ( & key_type_encrypted ) ;
if ( ret < 0 )
goto out ;
2014-12-04 20:25:19 +03:00
return 0 ;
2010-11-24 02:55:35 +03:00
out :
2017-06-08 16:48:25 +03:00
crypto_free_shash ( hash_tfm ) ;
2010-11-24 02:55:35 +03:00
return ret ;
2011-01-18 17:07:12 +03:00
2010-11-24 02:55:35 +03:00
}
static void __exit cleanup_encrypted ( void )
{
2017-06-08 16:48:25 +03:00
crypto_free_shash ( hash_tfm ) ;
2010-11-24 02:55:35 +03:00
unregister_key_type ( & key_type_encrypted ) ;
}
late_initcall ( init_encrypted ) ;
module_exit ( cleanup_encrypted ) ;
MODULE_LICENSE ( " GPL " ) ;