2015-04-21 16:23:47 -07:00
/*
2015-05-15 16:26:10 -07:00
* key management facility for FS encryption support .
2015-04-21 16:23:47 -07:00
*
* Copyright ( C ) 2015 , Google , Inc .
*
2015-05-15 16:26:10 -07:00
* This contains encryption key functions .
2015-04-21 16:23:47 -07:00
*
* Written by Michael Halcrow , Ildar Muslukhov , and Uday Savagaonkar , 2015.
*/
2015-05-15 16:26:10 -07:00
2015-04-21 16:23:47 -07:00
# include <keys/encrypted-type.h>
# include <keys/user-type.h>
# include <linux/random.h>
# include <linux/scatterlist.h>
# include <uapi/linux/keyctl.h>
2015-05-15 16:26:10 -07:00
# include <linux/fscrypto.h>
2015-04-21 16:23:47 -07:00
static void derive_crypt_complete ( struct crypto_async_request * req , int rc )
{
2015-05-15 16:26:10 -07:00
struct fscrypt_completion_result * ecr = req - > data ;
2015-04-21 16:23:47 -07:00
if ( rc = = - EINPROGRESS )
return ;
ecr - > res = rc ;
complete ( & ecr - > completion ) ;
}
/**
2015-05-15 16:26:10 -07:00
* derive_key_aes ( ) - Derive a key using AES - 128 - ECB
2016-02-05 19:21:41 -08:00
* @ deriving_key : Encryption key used for derivation .
2015-04-21 16:23:47 -07:00
* @ source_key : Source key to which to apply derivation .
* @ derived_key : Derived key .
*
* Return : Zero on success ; non - zero otherwise .
*/
2015-05-15 16:26:10 -07:00
static int derive_key_aes ( u8 deriving_key [ FS_AES_128_ECB_KEY_SIZE ] ,
u8 source_key [ FS_AES_256_XTS_KEY_SIZE ] ,
u8 derived_key [ FS_AES_256_XTS_KEY_SIZE ] )
2015-04-21 16:23:47 -07:00
{
int res = 0 ;
2016-03-21 11:03:02 -07:00
struct skcipher_request * req = NULL ;
2015-05-15 16:26:10 -07:00
DECLARE_FS_COMPLETION_RESULT ( ecr ) ;
2015-04-21 16:23:47 -07:00
struct scatterlist src_sg , dst_sg ;
2016-03-21 11:03:02 -07:00
struct crypto_skcipher * tfm = crypto_alloc_skcipher ( " ecb(aes) " , 0 , 0 ) ;
2015-04-21 16:23:47 -07:00
if ( IS_ERR ( tfm ) ) {
res = PTR_ERR ( tfm ) ;
tfm = NULL ;
goto out ;
}
2016-03-21 11:03:02 -07:00
crypto_skcipher_set_flags ( tfm , CRYPTO_TFM_REQ_WEAK_KEY ) ;
req = skcipher_request_alloc ( tfm , GFP_NOFS ) ;
2015-04-21 16:23:47 -07:00
if ( ! req ) {
res = - ENOMEM ;
goto out ;
}
2016-03-21 11:03:02 -07:00
skcipher_request_set_callback ( req ,
2015-04-21 16:23:47 -07:00
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP ,
derive_crypt_complete , & ecr ) ;
2016-03-21 11:03:02 -07:00
res = crypto_skcipher_setkey ( tfm , deriving_key ,
2015-05-15 16:26:10 -07:00
FS_AES_128_ECB_KEY_SIZE ) ;
2015-04-21 16:23:47 -07:00
if ( res < 0 )
goto out ;
2015-05-15 16:26:10 -07:00
sg_init_one ( & src_sg , source_key , FS_AES_256_XTS_KEY_SIZE ) ;
sg_init_one ( & dst_sg , derived_key , FS_AES_256_XTS_KEY_SIZE ) ;
2016-03-21 11:03:02 -07:00
skcipher_request_set_crypt ( req , & src_sg , & dst_sg ,
2015-05-15 16:26:10 -07:00
FS_AES_256_XTS_KEY_SIZE , NULL ) ;
2016-03-21 11:03:02 -07:00
res = crypto_skcipher_encrypt ( req ) ;
2015-04-21 16:23:47 -07:00
if ( res = = - EINPROGRESS | | res = = - EBUSY ) {
wait_for_completion ( & ecr . completion ) ;
res = ecr . res ;
}
out :
2016-03-21 11:03:02 -07:00
skcipher_request_free ( req ) ;
crypto_free_skcipher ( tfm ) ;
2015-04-21 16:23:47 -07:00
return res ;
}
2015-05-15 16:26:10 -07:00
static void put_crypt_info ( struct fscrypt_info * ci )
2015-04-21 16:23:47 -07:00
{
if ( ! ci )
return ;
2016-03-21 11:03:02 -07:00
key_put ( ci - > ci_keyring_key ) ;
crypto_free_skcipher ( ci - > ci_ctfm ) ;
2015-05-15 16:26:10 -07:00
kmem_cache_free ( fscrypt_info_cachep , ci ) ;
2015-04-21 16:23:47 -07:00
}
2015-05-15 16:26:10 -07:00
int get_crypt_info ( struct inode * inode )
2015-04-21 16:23:47 -07:00
{
2015-05-15 16:26:10 -07:00
struct fscrypt_info * crypt_info ;
u8 full_key_descriptor [ FS_KEY_DESC_PREFIX_SIZE +
( FS_KEY_DESCRIPTOR_SIZE * 2 ) + 1 ] ;
2015-04-21 16:23:47 -07:00
struct key * keyring_key = NULL ;
2015-05-15 16:26:10 -07:00
struct fscrypt_key * master_key ;
struct fscrypt_context ctx ;
2015-10-21 14:04:48 +01:00
const struct user_key_payload * ukp ;
2016-03-21 11:03:02 -07:00
struct crypto_skcipher * ctfm ;
2015-05-19 22:26:54 -07:00
const char * cipher_str ;
2015-05-15 16:26:10 -07:00
u8 raw_key [ FS_MAX_KEY_SIZE ] ;
u8 mode ;
2015-04-21 16:23:47 -07:00
int res ;
2015-05-15 16:26:10 -07:00
res = fscrypt_initialize ( ) ;
2015-05-15 15:37:24 -07:00
if ( res )
return res ;
2015-05-15 16:26:10 -07:00
if ( ! inode - > i_sb - > s_cop - > get_context )
return - EOPNOTSUPP ;
2015-05-19 22:26:54 -07:00
retry :
2015-05-15 16:26:10 -07:00
crypt_info = ACCESS_ONCE ( inode - > i_crypt_info ) ;
2015-05-19 22:26:54 -07:00
if ( crypt_info ) {
if ( ! crypt_info - > ci_keyring_key | |
key_validate ( crypt_info - > ci_keyring_key ) = = 0 )
2015-04-21 16:23:47 -07:00
return 0 ;
2015-05-15 16:26:10 -07:00
fscrypt_put_encryption_info ( inode , crypt_info ) ;
2015-05-19 22:26:54 -07:00
goto retry ;
2015-04-21 16:23:47 -07:00
}
2015-05-15 16:26:10 -07:00
res = inode - > i_sb - > s_cop - > get_context ( inode , & ctx , sizeof ( ctx ) ) ;
if ( res < 0 ) {
if ( ! fscrypt_dummy_context_enabled ( inode ) )
return res ;
ctx . contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS ;
ctx . filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS ;
ctx . flags = 0 ;
} else if ( res ! = sizeof ( ctx ) ) {
2015-04-21 16:23:47 -07:00
return - EINVAL ;
2015-05-15 16:26:10 -07:00
}
2015-04-21 16:23:47 -07:00
res = 0 ;
2015-05-15 16:26:10 -07:00
crypt_info = kmem_cache_alloc ( fscrypt_info_cachep , GFP_NOFS ) ;
2015-04-21 16:23:47 -07:00
if ( ! crypt_info )
return - ENOMEM ;
crypt_info - > ci_flags = ctx . flags ;
crypt_info - > ci_data_mode = ctx . contents_encryption_mode ;
crypt_info - > ci_filename_mode = ctx . filenames_encryption_mode ;
crypt_info - > ci_ctfm = NULL ;
2015-05-19 22:26:54 -07:00
crypt_info - > ci_keyring_key = NULL ;
2015-04-21 16:23:47 -07:00
memcpy ( crypt_info - > ci_master_key , ctx . master_key_descriptor ,
sizeof ( crypt_info - > ci_master_key ) ) ;
if ( S_ISREG ( inode - > i_mode ) )
2015-05-19 22:26:54 -07:00
mode = crypt_info - > ci_data_mode ;
2015-04-21 16:23:47 -07:00
else if ( S_ISDIR ( inode - > i_mode ) | | S_ISLNK ( inode - > i_mode ) )
2015-05-19 22:26:54 -07:00
mode = crypt_info - > ci_filename_mode ;
2015-05-12 13:33:00 -07:00
else
2015-04-21 16:23:47 -07:00
BUG ( ) ;
2015-05-12 13:33:00 -07:00
2015-05-19 22:26:54 -07:00
switch ( mode ) {
2015-05-15 16:26:10 -07:00
case FS_ENCRYPTION_MODE_AES_256_XTS :
2015-05-19 22:26:54 -07:00
cipher_str = " xts(aes) " ;
break ;
2015-05-15 16:26:10 -07:00
case FS_ENCRYPTION_MODE_AES_256_CTS :
2015-05-19 22:26:54 -07:00
cipher_str = " cts(cbc(aes)) " ;
break ;
default :
printk_once ( KERN_WARNING
2015-05-15 16:26:10 -07:00
" %s: unsupported key mode %d (ino %u) \n " ,
__func__ , mode , ( unsigned ) inode - > i_ino ) ;
2015-05-19 22:26:54 -07:00
res = - ENOKEY ;
goto out ;
}
2015-05-15 16:26:10 -07:00
if ( fscrypt_dummy_context_enabled ( inode ) ) {
memset ( raw_key , 0x42 , FS_AES_256_XTS_KEY_SIZE ) ;
goto got_key ;
}
memcpy ( full_key_descriptor , FS_KEY_DESC_PREFIX ,
FS_KEY_DESC_PREFIX_SIZE ) ;
sprintf ( full_key_descriptor + FS_KEY_DESC_PREFIX_SIZE ,
" %*phN " , FS_KEY_DESCRIPTOR_SIZE ,
2015-04-21 16:23:47 -07:00
ctx . master_key_descriptor ) ;
2015-05-15 16:26:10 -07:00
full_key_descriptor [ FS_KEY_DESC_PREFIX_SIZE +
( 2 * FS_KEY_DESCRIPTOR_SIZE ) ] = ' \0 ' ;
2015-04-21 16:23:47 -07:00
keyring_key = request_key ( & key_type_logon , full_key_descriptor , NULL ) ;
if ( IS_ERR ( keyring_key ) ) {
res = PTR_ERR ( keyring_key ) ;
keyring_key = NULL ;
goto out ;
}
2015-05-19 22:26:54 -07:00
crypt_info - > ci_keyring_key = keyring_key ;
2016-02-05 19:19:01 -08:00
if ( keyring_key - > type ! = & key_type_logon ) {
2015-05-15 16:26:10 -07:00
printk_once ( KERN_WARNING
" %s: key type must be logon \n " , __func__ ) ;
2016-02-05 19:19:01 -08:00
res = - ENOKEY ;
goto out ;
}
2016-02-05 19:38:42 -08:00
down_read ( & keyring_key - > sem ) ;
2015-10-21 14:04:48 +01:00
ukp = user_key_payload ( keyring_key ) ;
2015-05-15 16:26:10 -07:00
if ( ukp - > datalen ! = sizeof ( struct fscrypt_key ) ) {
2015-04-21 16:23:47 -07:00
res = - EINVAL ;
2016-02-05 19:38:42 -08:00
up_read ( & keyring_key - > sem ) ;
2015-04-21 16:23:47 -07:00
goto out ;
}
2015-05-15 16:26:10 -07:00
master_key = ( struct fscrypt_key * ) ukp - > data ;
BUILD_BUG_ON ( FS_AES_128_ECB_KEY_SIZE ! = FS_KEY_DERIVATION_NONCE_SIZE ) ;
if ( master_key - > size ! = FS_AES_256_XTS_KEY_SIZE ) {
2016-02-05 19:19:01 -08:00
printk_once ( KERN_WARNING
2015-05-15 16:26:10 -07:00
" %s: key size incorrect: %d \n " ,
__func__ , master_key - > size ) ;
2016-02-05 19:19:01 -08:00
res = - ENOKEY ;
2016-02-05 19:38:42 -08:00
up_read ( & keyring_key - > sem ) ;
2016-02-05 19:19:01 -08:00
goto out ;
}
2015-05-15 16:26:10 -07:00
res = derive_key_aes ( ctx . nonce , master_key - > raw , raw_key ) ;
2016-02-05 19:38:42 -08:00
up_read ( & keyring_key - > sem ) ;
2015-05-19 22:26:54 -07:00
if ( res )
goto out ;
2015-05-15 16:26:10 -07:00
got_key :
2016-03-21 11:03:02 -07:00
ctfm = crypto_alloc_skcipher ( cipher_str , 0 , 0 ) ;
2015-05-19 22:26:54 -07:00
if ( ! ctfm | | IS_ERR ( ctfm ) ) {
res = ctfm ? PTR_ERR ( ctfm ) : - ENOMEM ;
printk ( KERN_DEBUG
" %s: error %d (inode %u) allocating crypto tfm \n " ,
__func__ , res , ( unsigned ) inode - > i_ino ) ;
goto out ;
2015-04-21 16:23:47 -07:00
}
2015-05-19 22:26:54 -07:00
crypt_info - > ci_ctfm = ctfm ;
2016-03-21 11:03:02 -07:00
crypto_skcipher_clear_flags ( ctfm , ~ 0 ) ;
crypto_skcipher_set_flags ( ctfm , CRYPTO_TFM_REQ_WEAK_KEY ) ;
res = crypto_skcipher_setkey ( ctfm , raw_key , fscrypt_key_size ( mode ) ) ;
2015-05-19 22:26:54 -07:00
if ( res )
goto out ;
memzero_explicit ( raw_key , sizeof ( raw_key ) ) ;
2015-05-15 16:26:10 -07:00
if ( cmpxchg ( & inode - > i_crypt_info , NULL , crypt_info ) ! = NULL ) {
put_crypt_info ( crypt_info ) ;
2015-05-19 22:26:54 -07:00
goto retry ;
}
return 0 ;
out :
2015-05-15 16:26:10 -07:00
if ( res = = - ENOKEY )
2015-05-19 22:26:54 -07:00
res = 0 ;
2015-05-15 16:26:10 -07:00
put_crypt_info ( crypt_info ) ;
2015-05-19 22:26:54 -07:00
memzero_explicit ( raw_key , sizeof ( raw_key ) ) ;
2015-04-21 16:23:47 -07:00
return res ;
}
2015-05-15 16:26:10 -07:00
void fscrypt_put_encryption_info ( struct inode * inode , struct fscrypt_info * ci )
2015-04-21 16:23:47 -07:00
{
2015-05-15 16:26:10 -07:00
struct fscrypt_info * prev ;
if ( ci = = NULL )
ci = ACCESS_ONCE ( inode - > i_crypt_info ) ;
if ( ci = = NULL )
return ;
2015-04-21 16:23:47 -07:00
2015-05-15 16:26:10 -07:00
prev = cmpxchg ( & inode - > i_crypt_info , ci , NULL ) ;
if ( prev ! = ci )
return ;
put_crypt_info ( ci ) ;
}
EXPORT_SYMBOL ( fscrypt_put_encryption_info ) ;
int fscrypt_get_encryption_info ( struct inode * inode )
{
struct fscrypt_info * ci = inode - > i_crypt_info ;
if ( ! ci | |
( ci - > ci_keyring_key & &
( ci - > ci_keyring_key - > flags & ( ( 1 < < KEY_FLAG_INVALIDATED ) |
( 1 < < KEY_FLAG_REVOKED ) |
( 1 < < KEY_FLAG_DEAD ) ) ) ) )
return get_crypt_info ( inode ) ;
return 0 ;
2015-04-21 16:23:47 -07:00
}
2015-05-15 16:26:10 -07:00
EXPORT_SYMBOL ( fscrypt_get_encryption_info ) ;