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
* TORSEC group - - http : //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>
# include <crypto/sha.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 }
} ;
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 :
2011-06-27 15:45:42 +04:00
* new [ < format > ] < master - key name > < decrypted data length >
* 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 ,
char * * hex_encoded_iv )
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
}
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 ;
keys: Replace uid/gid/perm permissions checking with an ACL
Replace the uid/gid/perm permissions checking on a key with an ACL to allow
the SETATTR and SEARCH permissions to be split. This will also allow a
greater range of subjects to represented.
============
WHY DO THIS?
============
The problem is that SETATTR and SEARCH cover a slew of actions, not all of
which should be grouped together.
For SETATTR, this includes actions that are about controlling access to a
key:
(1) Changing a key's ownership.
(2) Changing a key's security information.
(3) Setting a keyring's restriction.
And actions that are about managing a key's lifetime:
(4) Setting an expiry time.
(5) Revoking a key.
and (proposed) managing a key as part of a cache:
(6) Invalidating a key.
Managing a key's lifetime doesn't really have anything to do with
controlling access to that key.
Expiry time is awkward since it's more about the lifetime of the content
and so, in some ways goes better with WRITE permission. It can, however,
be set unconditionally by a process with an appropriate authorisation token
for instantiating a key, and can also be set by the key type driver when a
key is instantiated, so lumping it with the access-controlling actions is
probably okay.
As for SEARCH permission, that currently covers:
(1) Finding keys in a keyring tree during a search.
(2) Permitting keyrings to be joined.
(3) Invalidation.
But these don't really belong together either, since these actions really
need to be controlled separately.
Finally, there are number of special cases to do with granting the
administrator special rights to invalidate or clear keys that I would like
to handle with the ACL rather than key flags and special checks.
===============
WHAT IS CHANGED
===============
The SETATTR permission is split to create two new permissions:
(1) SET_SECURITY - which allows the key's owner, group and ACL to be
changed and a restriction to be placed on a keyring.
(2) REVOKE - which allows a key to be revoked.
The SEARCH permission is split to create:
(1) SEARCH - which allows a keyring to be search and a key to be found.
(2) JOIN - which allows a keyring to be joined as a session keyring.
(3) INVAL - which allows a key to be invalidated.
The WRITE permission is also split to create:
(1) WRITE - which allows a key's content to be altered and links to be
added, removed and replaced in a keyring.
(2) CLEAR - which allows a keyring to be cleared completely. This is
split out to make it possible to give just this to an administrator.
(3) REVOKE - see above.
Keys acquire ACLs which consist of a series of ACEs, and all that apply are
unioned together. An ACE specifies a subject, such as:
(*) Possessor - permitted to anyone who 'possesses' a key
(*) Owner - permitted to the key owner
(*) Group - permitted to the key group
(*) Everyone - permitted to everyone
Note that 'Other' has been replaced with 'Everyone' on the assumption that
you wouldn't grant a permit to 'Other' that you wouldn't also grant to
everyone else.
Further subjects may be made available by later patches.
The ACE also specifies a permissions mask. The set of permissions is now:
VIEW Can view the key metadata
READ Can read the key content
WRITE Can update/modify the key content
SEARCH Can find the key by searching/requesting
LINK Can make a link to the key
SET_SECURITY Can change owner, ACL, expiry
INVAL Can invalidate
REVOKE Can revoke
JOIN Can join this keyring
CLEAR Can clear this keyring
The KEYCTL_SETPERM function is then deprecated.
The KEYCTL_SET_TIMEOUT function then is permitted if SET_SECURITY is set,
or if the caller has a valid instantiation auth token.
The KEYCTL_INVALIDATE function then requires INVAL.
The KEYCTL_REVOKE function then requires REVOKE.
The KEYCTL_JOIN_SESSION_KEYRING function then requires JOIN to join an
existing keyring.
The JOIN permission is enabled by default for session keyrings and manually
created keyrings only.
======================
BACKWARD COMPATIBILITY
======================
To maintain backward compatibility, KEYCTL_SETPERM will translate the
permissions mask it is given into a new ACL for a key - unless
KEYCTL_SET_ACL has been called on that key, in which case an error will be
returned.
It will convert possessor, owner, group and other permissions into separate
ACEs, if each portion of the mask is non-zero.
SETATTR permission turns on all of INVAL, REVOKE and SET_SECURITY. WRITE
permission turns on WRITE, REVOKE and, if a keyring, CLEAR. JOIN is turned
on if a keyring is being altered.
The KEYCTL_DESCRIBE function translates the ACL back into a permissions
mask to return depending on possessor, owner, group and everyone ACEs.
It will make the following mappings:
(1) INVAL, JOIN -> SEARCH
(2) SET_SECURITY -> SETATTR
(3) REVOKE -> WRITE if SETATTR isn't already set
(4) CLEAR -> WRITE
Note that the value subsequently returned by KEYCTL_DESCRIBE may not match
the value set with KEYCTL_SETATTR.
=======
TESTING
=======
This passes the keyutils testsuite for all but a couple of tests:
(1) tests/keyctl/dh_compute/badargs: The first wrong-key-type test now
returns EOPNOTSUPP rather than ENOKEY as READ permission isn't removed
if the type doesn't have ->read(). You still can't actually read the
key.
(2) tests/keyctl/permitting/valid: The view-other-permissions test doesn't
work as Other has been replaced with Everyone in the ACL.
Signed-off-by: David Howells <dhowells@redhat.com>
2019-06-28 01:03:07 +03:00
ukey = request_key ( & key_type_user , master_desc , NULL , 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_hash ( struct crypto_shash * tfm , u8 * digest ,
2010-12-14 00:53:13 +03:00
const u8 * buf , unsigned int buflen )
2010-11-24 02:55:35 +03:00
{
2017-06-08 16:48:25 +03:00
SHASH_DESC_ON_STACK ( desc , tfm ) ;
int err ;
2010-11-24 02:55:35 +03:00
2017-06-08 16:48:25 +03:00
desc - > tfm = tfm ;
2010-11-24 02:55:35 +03:00
2017-06-08 16:48:25 +03:00
err = crypto_shash_digest ( desc , buf , buflen , digest ) ;
shash_desc_zero ( desc ) ;
return err ;
2010-11-24 02:55:35 +03:00
}
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 )
err = calc_hash ( tfm , digest , buf , buflen ) ;
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 ) ;
2017-06-08 16:48:25 +03:00
ret = calc_hash ( hash_tfm , derived_key , derived_buf , derived_buf_len ) ;
2017-06-08 16:49:11 +03:00
kzfree ( 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 ,
const char * datalen )
{
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 ;
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 ;
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
*
* For a new key , use a random number for both the iv and data
* itself . For an old key , decrypt the hex encoded data .
*/
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 ,
const char * hex_encoded_iv )
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 ) ;
2010-12-14 00:53:12 +03:00
if ( ! hex_encoded_iv ) {
2010-11-24 02:55:35 +03:00
get_random_bytes ( epayload - > iv , ivsize ) ;
get_random_bytes ( epayload - > decrypted_data ,
epayload - > decrypted_datalen ) ;
} else
2011-06-27 15:45:42 +04:00
ret = encrypted_key_decrypt ( epayload , format , hex_encoded_iv ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
/*
* encrypted_instantiate - instantiate an encrypted key
*
* Decrypt an existing encrypted datablob or create a new encrypted key
* based on a kernel random number .
*
* 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 ;
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 ,
& decrypted_datalen , & hex_encoded_iv ) ;
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 ,
decrypted_datalen ) ;
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 ,
decrypted_datalen , hex_encoded_iv ) ;
2010-11-24 02:55:35 +03:00
if ( ret < 0 ) {
2017-06-08 16:49:11 +03:00
kzfree ( 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 :
2017-06-08 16:49:11 +03:00
kzfree ( 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 ) ;
2017-06-08 16:49:11 +03:00
kzfree ( 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 ) ;
2011-06-27 15:45:42 +04:00
ret = datablob_parse ( buf , & format , & new_master_desc , 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 ,
new_master_desc , epayload - > datalen ) ;
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 :
2017-06-08 16:49:11 +03:00
kzfree ( buf ) ;
2010-11-24 02:55:35 +03:00
return ret ;
}
/*
* encrypted_read - format and copy the encrypted data to userspace
*
* 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 .
*/
static long encrypted_read ( const struct key * key , char __user * buffer ,
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
if ( copy_to_user ( buffer , ascii_buf , asciiblob_len ) ! = 0 )
ret = - EFAULT ;
2017-06-08 16:49:11 +03:00
kzfree ( 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 )
{
2017-06-08 16:49:11 +03:00
kzfree ( 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 " ) ;