PFK: fixed issue where key in TZ was not set properly

When key is set in ICE via TZ, HLOS should send two parts, SALT and
the KEY itself according to AES standards. KEY was used for both parts.

Change-Id: I453dea289b01bdf49352d5209255966052f5dc1b
Signed-off-by: Andrey Markovytch <andreym@codeaurora.org>
This commit is contained in:
Andrey Markovytch 2015-07-08 11:24:29 +03:00 committed by David Keitel
parent 584531e72e
commit 8928f8683b
12 changed files with 485 additions and 66 deletions

View file

@ -351,9 +351,9 @@ static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
|| !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED));
if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "Key size [%zd]; key:\n",
crypt_stat->key_size);
ecryptfs_get_key_size_to_enc_data(crypt_stat));
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
ecryptfs_get_key_size_to_enc_data(crypt_stat));
}
init_completion(&ecr.completion);
@ -372,7 +372,7 @@ static int crypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
/* Consider doing this once, when the file is opened */
if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) {
rc = crypto_ablkcipher_setkey(crypt_stat->tfm, crypt_stat->key,
crypt_stat->key_size);
ecryptfs_get_key_size_to_enc_data(crypt_stat));
if (rc) {
ecryptfs_printk(KERN_ERR,
"Error setting key; rc = [%d]\n",
@ -693,7 +693,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
"Initializing cipher [%s]; strlen = [%d]; "
"key_size_bits = [%zd]\n",
crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
crypt_stat->key_size << 3);
ecryptfs_get_key_size_to_enc_data(crypt_stat) << 3);
mutex_lock(&crypt_stat->cs_tfm_mutex);
if (crypt_stat->tfm) {
rc = 0;
@ -775,7 +775,7 @@ int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)
goto out;
}
rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,
crypt_stat->key_size);
ecryptfs_get_key_size_to_enc_data(crypt_stat));
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
"MD5 while generating root IV\n");
@ -802,6 +802,33 @@ static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
}
}
static int ecryptfs_generate_new_salt(struct ecryptfs_crypt_stat *crypt_stat)
{
size_t salt_size = 0;
salt_size = ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode));
if (0 == salt_size)
return 0;
if (!ecryptfs_check_space_for_salt(crypt_stat->key_size, salt_size)) {
ecryptfs_printk(KERN_WARNING, "not enough space for salt\n");
crypt_stat->flags |= ECRYPTFS_SECURITY_WARNING;
return -EINVAL;
}
get_random_bytes(crypt_stat->key + crypt_stat->key_size, salt_size);
if (unlikely(ecryptfs_verbosity > 0)) {
ecryptfs_printk(KERN_DEBUG, "Generated new session salt:\n");
ecryptfs_dump_hex(crypt_stat->key + crypt_stat->key_size,
salt_size);
}
return 0;
}
/**
* ecryptfs_copy_mount_wide_flags_to_inode_flags
* @crypt_stat: The inode's cryptographic context
@ -928,6 +955,8 @@ int ecryptfs_new_file_context(struct inode *ecryptfs_inode)
crypt_stat->key_size =
mount_crypt_stat->global_default_cipher_key_size;
ecryptfs_generate_new_key(crypt_stat);
ecryptfs_generate_new_salt(crypt_stat);
rc = ecryptfs_init_crypt_ctx(crypt_stat);
if (rc)
ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "

View file

@ -119,3 +119,16 @@ void ecryptfs_dump_hex(char *data, int bytes)
printk("\n");
}
void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher)
{
size_t salt_size = ecryptfs_get_salt_size_for_cipher(cipher);
if (0 == salt_size)
return;
if (!ecryptfs_check_space_for_salt(key_size, salt_size))
return;
ecryptfs_printk(KERN_DEBUG, "Decrypted session salt key:\n");
ecryptfs_dump_hex(data + key_size, salt_size);
}

View file

@ -623,6 +623,7 @@ int ecryptfs_encrypt_and_encode_filename(
const char *name, size_t name_size);
struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
void ecryptfs_dump_hex(char *data, int bytes);
void ecryptfs_dump_salt_hex(char *data, int key_size, char *cipher);
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
int sg_size);
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
@ -777,4 +778,18 @@ void ecryptfs_freepage(struct page *page);
struct ecryptfs_events *get_events(void);
size_t ecryptfs_get_salt_size_for_cipher(const char *cipher);
size_t ecryptfs_get_key_size_to_enc_data(
struct ecryptfs_crypt_stat *crypt_stat);
size_t ecryptfs_get_key_size_to_store_key(
struct ecryptfs_crypt_stat *crypt_stat);
size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
const char *cipher);
bool ecryptfs_check_space_for_salt(const size_t key_size,
const size_t salt_size);
#endif /* #ifndef ECRYPTFS_KERNEL_H */

View file

@ -73,6 +73,7 @@ int ecryptfs_register_to_events(struct ecryptfs_events *ops)
events_ptr->is_cipher_supported_cb =
ops->is_cipher_supported_cb;
events_ptr->is_hw_crypt_cb = ops->is_hw_crypt_cb;
events_ptr->get_salt_key_size_cb = ops->get_salt_key_size_cb;
get_random_bytes(&handle, sizeof(handle));
ret_value = handle;
@ -166,6 +167,29 @@ size_t ecryptfs_get_key_size(void *data)
return stat->key_size;
}
/**
* Given ecryptfs data, the function
* returns appropriate salt size.
*
* !!! crypt_stat cipher name and mode must be initialized
*/
size_t ecryptfs_get_salt_size(void *data)
{
struct ecryptfs_crypt_stat *stat = NULL;
if (!data) {
ecryptfs_printk(KERN_ERR,
"ecryptfs_get_salt_size: invalid data parameter\n");
return 0;
}
stat = (struct ecryptfs_crypt_stat *)data;
return ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(stat->cipher,
stat->cipher_mode));
}
/**
* Given ecryptfs data, the function
* returns appropriate cipher.
@ -202,6 +226,23 @@ const unsigned char *ecryptfs_get_key(void *data)
return stat->key;
}
/**
* Given ecryptfs data, the function
* returns file encryption salt.
*/
const unsigned char *ecryptfs_get_salt(void *data)
{
struct ecryptfs_crypt_stat *stat = NULL;
if (!data) {
ecryptfs_printk(KERN_ERR,
"ecryptfs_get_salt: invalid data parameter\n");
return NULL;
}
stat = (struct ecryptfs_crypt_stat *)data;
return stat->key + ecryptfs_get_salt_size(data);
}
/**
* Returns ecryptfs events pointer
*/
@ -210,3 +251,108 @@ inline struct ecryptfs_events *get_events(void)
return events_ptr;
}
/**
* If external crypto module requires salt in addition to key,
* we store it as part of key array (if there is enough space)
* Checks whether a salt key can fit into array allocated for
* regular key
*/
bool ecryptfs_check_space_for_salt(const size_t key_size,
const size_t salt_size)
{
if ((salt_size + key_size) > ECRYPTFS_MAX_KEY_BYTES)
return false;
return true;
}
/*
* If there is salt that is used by external crypto module, it is stored
* in the same array where regular key is. Salt is going to be used by
* external crypto module only, so for all internal crypto operations salt
* should be ignored.
*
* Get key size in cases where it is going to be used for data encryption
* or for all other general purposes
*/
size_t ecryptfs_get_key_size_to_enc_data(
struct ecryptfs_crypt_stat *crypt_stat)
{
if (!crypt_stat)
return 0;
return crypt_stat->key_size;
}
/*
* If there is salt that is used by external crypto module, it is stored
* in the same array where regular key is. Salt is going to be used by
* external crypto module only, but we still need to save and restore it
* (in encrypted form) as part of ecryptfs header along with the regular
* key.
*
* Get key size in cases where it is going to be stored persistently
*
* !!! crypt_stat cipher name and mode must be initialized
*/
size_t ecryptfs_get_key_size_to_store_key(
struct ecryptfs_crypt_stat *crypt_stat)
{
size_t salt_size = 0;
if (!crypt_stat)
return 0;
salt_size = ecryptfs_get_salt_size(crypt_stat);
if (!ecryptfs_check_space_for_salt(crypt_stat->key_size, salt_size)) {
ecryptfs_printk(KERN_WARNING,
"ecryptfs_get_key_size_to_store_key: not enough space for salt\n");
return crypt_stat->key_size;
}
return crypt_stat->key_size + salt_size;
}
/*
* If there is salt that is used by external crypto module, it is stored
* in the same array where regular key is. Salt is going to be used by
* external crypto module only, but we still need to save and restore it
* (in encrypted form) as part of ecryptfs header along with the regular
* key.
*
* Get key size in cases where it is going to be restored from storage
*
* !!! crypt_stat cipher name and mode must be initialized
*/
size_t ecryptfs_get_key_size_to_restore_key(size_t stored_key_size,
const char *cipher)
{
size_t salt_size = 0;
if (!cipher)
return 0;
salt_size = ecryptfs_get_salt_size_for_cipher(cipher);
if (salt_size >= stored_key_size) {
ecryptfs_printk(KERN_WARNING,
"ecryptfs_get_key_size_to_restore_key: salt %zu >= stred size %zu\n",
salt_size, stored_key_size);
return stored_key_size;
}
return stored_key_size - salt_size;
}
/**
* Given cipher, the function returns appropriate salt size.
*/
size_t ecryptfs_get_salt_size_for_cipher(const char *cipher)
{
if (!get_events() || !(get_events()->get_salt_key_size_cb))
return 0;
return get_events()->get_salt_key_size_cb(cipher);
}

View file

@ -315,7 +315,8 @@ write_tag_66_packet(char *signature, u8 cipher_code,
* | File Encryption Key Size | 1 or 2 bytes |
* | File Encryption Key | arbitrary |
*/
data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size);
data_len = (5 + ECRYPTFS_SIG_SIZE_HEX +
ecryptfs_get_key_size_to_store_key(crypt_stat));
*packet = kmalloc(data_len, GFP_KERNEL);
message = *packet;
if (!message) {
@ -335,8 +336,9 @@ write_tag_66_packet(char *signature, u8 cipher_code,
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX;
/* The encrypted key includes 1 byte cipher code and 2 byte checksum */
rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3,
&packet_size_len);
rc = ecryptfs_write_packet_length(&message[i],
ecryptfs_get_key_size_to_store_key(crypt_stat) + 3,
&packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
"header; cannot generate packet length\n");
@ -344,9 +346,10 @@ write_tag_66_packet(char *signature, u8 cipher_code,
}
i += packet_size_len;
message[i++] = cipher_code;
memcpy(&message[i], crypt_stat->key, crypt_stat->key_size);
i += crypt_stat->key_size;
for (j = 0; j < crypt_stat->key_size; j++)
memcpy(&message[i], crypt_stat->key,
ecryptfs_get_key_size_to_store_key(crypt_stat));
i += ecryptfs_get_key_size_to_store_key(crypt_stat);
for (j = 0; j < ecryptfs_get_key_size_to_store_key(crypt_stat); j++)
checksum += crypt_stat->key[j];
message[i++] = (checksum / 256) % 256;
message[i++] = (checksum % 256);
@ -1187,16 +1190,20 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
rc);
goto out;
}
auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
auth_tok->session_key.decrypted_key_size);
crypt_stat->key_size = auth_tok->session_key.decrypted_key_size;
rc = ecryptfs_cipher_code_to_string(full_cipher, cipher_code);
if (rc) {
ecryptfs_printk(KERN_ERR, "Cipher code [%d] is invalid\n",
cipher_code)
goto out;
goto out;
}
auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
auth_tok->session_key.decrypted_key_size);
crypt_stat->key_size = ecryptfs_get_key_size_to_restore_key(
auth_tok->session_key.decrypted_key_size, full_cipher);
ecryptfs_parse_full_cipher(full_cipher,
crypt_stat->cipher, crypt_stat->cipher_mode);
@ -1205,6 +1212,9 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
ecryptfs_dump_salt_hex(crypt_stat->key, crypt_stat->key_size,
full_cipher);
}
out:
kfree(msg);
@ -1475,7 +1485,10 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
break;
default:
crypt_stat->key_size =
(*new_auth_tok)->session_key.encrypted_key_size;
ecryptfs_get_key_size_to_restore_key(
(*new_auth_tok)->session_key.encrypted_key_size,
full_cipher);
}
rc = ecryptfs_init_crypt_ctx(crypt_stat);
if (rc)
@ -1723,7 +1736,7 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
mutex_lock(tfm_mutex);
rc = crypto_blkcipher_setkey(
desc.tfm, auth_tok->token.password.session_key_encryption_key,
crypt_stat->key_size);
auth_tok->token.password.session_key_encryption_key_bytes);
if (unlikely(rc < 0)) {
mutex_unlock(tfm_mutex);
printk(KERN_ERR "Error setting key for crypto context\n");
@ -1746,6 +1759,9 @@ decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
crypt_stat->key_size);
ecryptfs_dump_hex(crypt_stat->key,
crypt_stat->key_size);
ecryptfs_dump_salt_hex(crypt_stat->key, crypt_stat->key_size,
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode));
}
out:
return rc;
@ -1984,12 +2000,13 @@ pki_encrypt_session_key(struct key *auth_tok_key,
int rc;
rc = write_tag_66_packet(auth_tok->token.private_key.signature,
ecryptfs_code_for_cipher_string(
ecryptfs_code_for_cipher_string(
ecryptfs_get_full_cipher(
crypt_stat->cipher,
crypt_stat->cipher_mode),
crypt_stat->key_size),
crypt_stat, &payload, &payload_len);
ecryptfs_get_key_size_to_enc_data(
crypt_stat)),
crypt_stat, &payload, &payload_len);
up_write(&(auth_tok_key->sem));
key_put(auth_tok_key);
if (rc) {
@ -2047,7 +2064,7 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
ecryptfs_from_hex(key_rec->sig, auth_tok->token.private_key.signature,
ECRYPTFS_SIG_SIZE);
encrypted_session_key_valid = 0;
for (i = 0; i < crypt_stat->key_size; i++)
for (i = 0; i < ecryptfs_get_key_size_to_store_key(crypt_stat); i++)
encrypted_session_key_valid |=
auth_tok->session_key.encrypted_key[i];
if (encrypted_session_key_valid) {
@ -2233,13 +2250,14 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
mount_crypt_stat->global_default_cipher_key_size;
if (auth_tok->session_key.encrypted_key_size == 0)
auth_tok->session_key.encrypted_key_size =
crypt_stat->key_size;
ecryptfs_get_key_size_to_store_key(crypt_stat);
if (crypt_stat->key_size == 24
&& strcmp("aes", crypt_stat->cipher) == 0) {
memset((crypt_stat->key + 24), 0, 8);
auth_tok->session_key.encrypted_key_size = 32;
} else
auth_tok->session_key.encrypted_key_size = crypt_stat->key_size;
auth_tok->session_key.encrypted_key_size =
ecryptfs_get_key_size_to_store_key(crypt_stat);
key_rec->enc_key_size =
auth_tok->session_key.encrypted_key_size;
encrypted_session_key_valid = 0;
@ -2263,8 +2281,8 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
auth_tok->token.password.
session_key_encryption_key_bytes);
memcpy(session_key_encryption_key,
auth_tok->token.password.session_key_encryption_key,
crypt_stat->key_size);
auth_tok->token.password.session_key_encryption_key,
auth_tok->token.password.session_key_encryption_key_bytes);
ecryptfs_printk(KERN_DEBUG,
"Cached session key encryption key:\n");
if (ecryptfs_verbosity > 0)
@ -2297,7 +2315,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
}
mutex_lock(tfm_mutex);
rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key,
crypt_stat->key_size);
auth_tok->token.password.session_key_encryption_key_bytes);
if (rc < 0) {
mutex_unlock(tfm_mutex);
ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
@ -2306,7 +2324,11 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes,
}
rc = 0;
ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the key\n",
crypt_stat->key_size);
crypt_stat->key_size);
ecryptfs_printk(KERN_DEBUG, "Encrypting [%zd] bytes of the salt key\n",
ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(crypt_stat->cipher,
crypt_stat->cipher_mode)));
rc = crypto_blkcipher_encrypt(&desc, dst_sg, src_sg,
(*key_rec).enc_key_size);
mutex_unlock(tfm_mutex);

View file

@ -266,6 +266,7 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
int cipher_key_bytes_set = 0;
int fn_cipher_key_bytes;
int fn_cipher_key_bytes_set = 0;
size_t salt_size = 0;
struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
&sbi->mount_crypt_stat;
substring_t args[MAX_OPT_ARGS];
@ -418,8 +419,24 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options,
&& !fn_cipher_name_set)
strcpy(mount_crypt_stat->global_default_fn_cipher_name,
mount_crypt_stat->global_default_cipher_name);
if (!cipher_key_bytes_set)
if (cipher_key_bytes_set) {
salt_size = ecryptfs_get_salt_size_for_cipher(
ecryptfs_get_full_cipher(
mount_crypt_stat->global_default_cipher_name,
mount_crypt_stat->global_default_cipher_mode));
if (!ecryptfs_check_space_for_salt(
mount_crypt_stat->global_default_cipher_key_size,
salt_size)) {
ecryptfs_printk(
KERN_WARNING,
"eCryptfs internal error: no space for salt");
}
} else
mount_crypt_stat->global_default_cipher_key_size = 0;
if ((mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)
&& !fn_cipher_key_bytes_set)
mount_crypt_stat->global_default_fn_cipher_key_bytes =

View file

@ -119,7 +119,7 @@ struct ecryptfs_auth_tok {
* such as ecryptfs_get_key_size(), ecryptfs_get_cipher() etc.
*/
struct ecryptfs_events {
bool (*is_cipher_supported_cb)(char *cipher);
bool (*is_cipher_supported_cb)(const char *cipher);
void (*open_cb)(struct inode *inode, void *ecrytpfs_data);
void (*release_cb)(struct inode *inode);
int (*encrypt_cb)(struct page *in_page, struct page *out_page,
@ -127,6 +127,7 @@ struct ecryptfs_events {
int (*decrypt_cb)(struct page *in_page, struct page *out_page,
struct inode *inode, unsigned long extent_offset);
bool (*is_hw_crypt_cb)(void);
size_t (*get_salt_key_size_cb)(const char *cipher);
};
@ -138,6 +139,10 @@ const unsigned char *ecryptfs_get_key(void *ecrytpfs_data);
size_t ecryptfs_get_key_size(void *ecrytpfs_data);
const unsigned char *ecryptfs_get_salt(void *ecrytpfs_data);
size_t ecryptfs_get_salt_size(void *ecrytpfs_data);
const unsigned char *ecryptfs_get_cipher(void *ecrytpfs_data);
bool ecryptfs_is_page_in_metadata(void *ecrytpfs_data, pgoff_t offset);

View file

@ -65,6 +65,7 @@ static int g_events_handle;
/* might be replaced by a table when more than one cipher is supported */
#define PFK_SUPPORTED_CIPHER "aes_xts"
#define PFK_SUPPORTED_KEY_SIZE 32
#define PFK_SUPPORTED_SALT_SIZE 32
static int pfk_inode_alloc_security(struct inode *inode)
{
@ -326,12 +327,14 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
struct inode *inode = NULL;
int ret = 0;
const unsigned char *key = NULL;
const unsigned char *salt = NULL;
const unsigned char *cipher = NULL;
void *ecryptfs_data = NULL;
u32 key_index = 0;
enum ice_cryto_algo_mode algo_mode = 0;
enum ice_crpto_key_size key_size_type = 0;
size_t key_size = 0;
size_t salt_size = 0;
pgoff_t offset;
bool is_metadata = false;
@ -386,6 +389,20 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
goto end;
}
salt = ecryptfs_get_salt(ecryptfs_data);
if (!salt) {
pr_err("could not parse salt from ecryptfs\n");
ret = -EINVAL;
goto end;
}
salt_size = ecryptfs_get_salt_size(ecryptfs_data);
if (!salt_size) {
pr_err("could not parse salt size from ecryptfs\n");
ret = -EINVAL;
goto end;
}
cipher = ecryptfs_get_cipher(ecryptfs_data);
if (!key) {
pr_err("could not parse key from ecryptfs\n");
@ -401,7 +418,7 @@ int pfk_load_key(const struct bio *bio, struct ice_crypto_setting *ice_setting)
if (ret != 0)
return ret;
ret = pfk_kc_load_key(key, key_size, &key_index);
ret = pfk_kc_load_key(key, key_size, salt, salt_size, &key_index);
if (ret != 0) {
pr_err("could not load key into pfk key cache, error %d\n",
ret);
@ -503,7 +520,6 @@ bool pfk_allow_merge_bio(struct bio *bio1, struct bio *bio2)
goto end;
}
/*
* at this point both bio's are in the same file which is probably
* encrypted, last thing to check is header vs data
@ -587,7 +603,9 @@ static void pfk_open_cb(struct inode *inode, void *ecryptfs_data)
static void pfk_release_cb(struct inode *inode)
{
const unsigned char *key = NULL;
size_t key_size;
const unsigned char *salt = NULL;
size_t key_size = 0;
size_t salt_size = 0;
void *data = NULL;
if (!pfk_is_ready())
@ -616,14 +634,26 @@ static void pfk_release_cb(struct inode *inode)
return;
}
pfk_kc_remove_key(key, key_size);
salt = ecryptfs_get_salt(data);
if (!salt) {
pr_err("could not parse salt from ecryptfs\n");
return;
}
salt_size = ecryptfs_get_salt_size(data);
if (!salt_size) {
pr_err("could not parse salt size from ecryptfs\n");
return;
}
pfk_kc_remove_key_with_salt(key, key_size, salt, salt_size);
mutex_lock(&pfk_lock);
pfk_set_ecryptfs_data(inode, NULL);
mutex_unlock(&pfk_lock);
}
static bool pfk_is_cipher_supported_cb(char *cipher)
static bool pfk_is_cipher_supported_cb(const char *cipher)
{
if (!pfk_is_ready())
return false;
@ -642,6 +672,17 @@ static bool pfk_is_hw_crypt_cb(void)
return true;
}
static size_t pfk_get_salt_key_size_cb(const char *cipher)
{
if (!pfk_is_ready())
return 0;
if (!pfk_is_cipher_supported_cb(cipher))
return 0;
return PFK_SUPPORTED_SALT_SIZE;
}
static void __exit pfk_exit(void)
{
@ -660,6 +701,7 @@ static int __init pfk_init(void)
events.release_cb = pfk_release_cb;
events.is_cipher_supported_cb = pfk_is_cipher_supported_cb;
events.is_hw_crypt_cb = pfk_is_hw_crypt_cb;
events.get_salt_key_size_cb = pfk_get_salt_key_size_cb;
g_events_handle = ecryptfs_register_to_events(&events);
if (0 == g_events_handle) {

View file

@ -48,46 +48,60 @@
#define TZ_ES_SET_ICE_KEY_PARAM_ID \
TZ_SYSCALL_CREATE_PARAM_ID_3( \
TZ_SYSCALL_PARAM_TYPE_VAL, \
TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
TZ_SYSCALL_CREATE_PARAM_ID_5( \
TZ_SYSCALL_PARAM_TYPE_VAL, \
TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL, \
TZ_SYSCALL_PARAM_TYPE_BUF_RW, TZ_SYSCALL_PARAM_TYPE_VAL)
#define TZ_ES_INVALIDATE_ICE_KEY_PARAM_ID \
TZ_SYSCALL_CREATE_PARAM_ID_1( \
TZ_SYSCALL_PARAM_TYPE_VAL)
#define ICE_KEY_SIZE 32
#define ICE_SALT_SIZE 32
uint8_t ice_key[ICE_KEY_SIZE];
uint8_t ice_salt[ICE_KEY_SIZE];
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key)
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt)
{
struct scm_desc desc = {0};
int ret;
char *tzbuf = (char *)ice_key;
char *tzbuf_key = (char *)ice_key;
char *tzbuf_salt = (char *)ice_salt;
uint32_t smc_id = 0;
u32 tzbuflen = sizeof(ice_key);
u32 tzbuflen_key = sizeof(ice_key);
u32 tzbuflen_salt = sizeof(ice_salt);
if (index < MIN_ICE_KEY_INDEX || index > MAX_ICE_KEY_INDEX)
return -EINVAL;
if (!tzbuf)
if (!key || !salt)
return -EINVAL;
if (!tzbuf_key || !tzbuf_salt)
return -ENOMEM;
memset(tzbuf, 0, tzbuflen);
memcpy(ice_key, key, ICE_KEY_SIZE);
memset(tzbuf_key, 0, tzbuflen_key);
memset(tzbuf_salt, 0, tzbuflen_salt);
dmac_flush_range(tzbuf, tzbuf + tzbuflen);
memcpy(ice_key, key, tzbuflen_key);
memcpy(ice_salt, salt, tzbuflen_salt);
dmac_flush_range(tzbuf_key, tzbuf_key + tzbuflen_key);
dmac_flush_range(tzbuf_salt, tzbuf_salt + tzbuflen_salt);
smc_id = TZ_ES_SET_ICE_KEY_ID;
pr_debug(" %s , smc_id = 0x%x\n", __func__, smc_id);
desc.arginfo = TZ_ES_SET_ICE_KEY_PARAM_ID;
desc.args[0] = index;
desc.args[1] = virt_to_phys(tzbuf);
desc.args[2] = tzbuflen;
desc.args[1] = virt_to_phys(tzbuf_key);
desc.args[2] = tzbuflen_key;
desc.args[3] = virt_to_phys(tzbuf_salt);
desc.args[4] = tzbuflen_salt;
ret = scm_call2_atomic(smc_id, &desc);
pr_debug(" %s , ret = %d\n", __func__, ret);

View file

@ -26,7 +26,7 @@
int pfk_ice_init(void);
int pfk_ice_deinit(void);
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key);
int qti_pfk_ice_set_key(uint32_t index, uint8_t *key, uint8_t *salt);
int qti_pfk_ice_invalidate_key(uint32_t index);

View file

@ -41,15 +41,17 @@
/** the first available index in ice engine */
#define PFK_KC_STARTING_INDEX 2
/** currently the only supported key size */
/** currently the only supported key and salt sizes */
#define PFK_KC_KEY_SIZE 32
#define PFK_KC_SALT_SIZE 32
/** Table size */
/* TODO replace by some constant from ice.h */
#define PFK_KC_TABLE_SIZE ((32) - (PFK_KC_STARTING_INDEX))
/** The maximum key size */
/** The maximum key and salt size */
#define PFK_MAX_KEY_SIZE PFK_KC_KEY_SIZE
#define PFK_MAX_SALT_SIZE PFK_KC_SALT_SIZE
static DEFINE_SPINLOCK(kc_lock);
static bool kc_ready;
@ -57,11 +59,15 @@ static bool kc_ready;
struct kc_entry {
unsigned char key[PFK_MAX_KEY_SIZE];
size_t key_size;
unsigned char salt[PFK_MAX_SALT_SIZE];
size_t salt_size;
u64 time_stamp;
u32 key_index;
};
static struct kc_entry kc_table[PFK_KC_TABLE_SIZE] = {{{0} , 0, 0, 0} };
static struct kc_entry kc_table[PFK_KC_TABLE_SIZE] = {{{0}, 0, {0}, 0, 0, 0} };
/**
* pfk_min_time_entry() - update min time and update min entry
@ -96,30 +102,65 @@ static inline bool kc_is_ready(void)
}
/**
* kc_find_key() - find kc entry
* kc_find_key_at_index() - find kc entry starting at specific index
* @key: key to look for
* @key_size: the key size
* @salt: salt to look for
* @salt_size: the salt size
* @sarting_index: index to start search with, if entry found, updated with
* index of that entry
*
* Return entry or NULL in case of error
* Should be invoked under lock
*/
static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size)
static struct kc_entry *kc_find_key_at_index(const unsigned char *key,
size_t key_size, const unsigned char *salt, size_t salt_size,
int *starting_index)
{
struct kc_entry *entry = NULL;
int i = 0;
for (i = 0; i < PFK_KC_TABLE_SIZE; i++) {
for (i = *starting_index; i < PFK_KC_TABLE_SIZE; i++) {
entry = &(kc_table[i]);
if (NULL != salt) {
if (entry->salt_size != salt_size)
continue;
if (0 != memcmp(entry->salt, salt, salt_size))
continue;
}
if (entry->key_size != key_size)
continue;
if (0 == memcmp(entry->key, key, key_size))
if (0 == memcmp(entry->key, key, key_size)) {
*starting_index = i;
return entry;
}
}
return NULL;
}
/**
* kc_find_key() - find kc entry
* @key: key to look for
* @key_size: the key size
* @salt: salt to look for
* @salt_size: the salt size
*
* Return entry or NULL in case of error
* Should be invoked under lock
*/
static struct kc_entry *kc_find_key(const unsigned char *key, size_t key_size,
const unsigned char *salt, size_t salt_size)
{
int index = 0;
return kc_find_key_at_index(key, key_size, salt, salt_size, &index);
}
/**
* kc_find_oldest_entry() - finds the entry with minimal timestamp
*
@ -183,6 +224,7 @@ static void kc_clear_entry(struct kc_entry *entry, bool clear_qscee)
qti_pfk_ice_invalidate_key(entry->key_index);
memset(entry->key, 0, entry->key_size);
memset(entry->salt, 0, entry->salt_size);
entry->time_stamp = 0;
}
@ -194,13 +236,15 @@ static void kc_clear_entry(struct kc_entry *entry, bool clear_qscee)
* @entry: entry to replace key in
* @key: key
* @key_size: key_size
* @salt: salt
* @salt_size: salt_size
*
* The previous key is securely released and wiped, the new one is loaded
* to ICE.
* Should be invoked under lock
*/
static int kc_replace_entry(struct kc_entry *entry, const unsigned char *key,
size_t key_size)
size_t key_size, const unsigned char *salt, size_t salt_size)
{
int ret = 0;
@ -209,7 +253,11 @@ static int kc_replace_entry(struct kc_entry *entry, const unsigned char *key,
memcpy(entry->key, key, key_size);
entry->key_size = key_size;
ret = qti_pfk_ice_set_key(entry->key_index, (uint8_t *) key);
memcpy(entry->salt, salt, salt_size);
entry->salt_size = salt_size;
ret = qti_pfk_ice_set_key(entry->key_index, (uint8_t *) key,
(uint8_t *) salt);
if (ret != 0) {
ret = -EINVAL;
goto err;
@ -265,7 +313,9 @@ int pfk_kc_deinit(void)
* pfk_kc_load_key() - retrieve the key from cache or add it if it's not there
* return the ICE hw key index
* @key: pointer to the key
* @key_size: the size of the key, assumed to be not bigger than
* @key_size: the size of the key
* @salt: pointer to the salt
* @salt_size: the size of the salt
* @key_index: the pointer to key_index where the output will be stored
*
* If key is present in cache, than the key_index will be retrieved from cache.
@ -275,7 +325,8 @@ int pfk_kc_deinit(void)
*
* Return 0 in case of success, error otherwise
*/
int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
int pfk_kc_load_key(const unsigned char *key, size_t key_size,
const unsigned char *salt, size_t salt_size, u32 *key_index)
{
int ret = 0;
struct kc_entry *entry = NULL;
@ -283,14 +334,17 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
if (!kc_is_ready())
return -ENODEV;
if (!key || !key_index)
if (!key || !salt || !key_index)
return -EPERM;
if (key_size != PFK_KC_KEY_SIZE)
return -EPERM;
if (salt_size != PFK_KC_SALT_SIZE)
return -EPERM;
spin_lock(&kc_lock);
entry = kc_find_key(key, key_size);
entry = kc_find_key(key, key_size, salt, salt_size);
if (!entry) {
entry = kc_find_oldest_entry();
if (!entry) {
@ -302,7 +356,7 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
pr_debug("didn't found key in cache, replacing entry with index %d\n",
entry->key_index);
ret = kc_replace_entry(entry, key, key_size);
ret = kc_replace_entry(entry, key, key_size, salt, salt_size);
if (ret) {
spin_unlock(&kc_lock);
return -EINVAL;
@ -322,7 +376,54 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
/**
* pfk_kc_remove_key() - remove the key from cache and from ICE engine
* @key: pointer to the key
* @key_size: the size of the key, assumed to be not bigger than
* @key_size: the size of the key
* @salt: pointer to the key
* @salt_size: the size of the key
*
* Return 0 in case of success, error otherwise (also in case of non
* (existing key)
*/
int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
const unsigned char *salt, size_t salt_size)
{
struct kc_entry *entry = NULL;
if (!kc_is_ready())
return -ENODEV;
if (!key)
return -EPERM;
if (!salt)
return -EPERM;
if (key_size != PFK_KC_KEY_SIZE)
return -EPERM;
if (salt_size != PFK_KC_SALT_SIZE)
return -EPERM;
spin_lock(&kc_lock);
entry = kc_find_key(key, key_size, salt, salt_size);
if (!entry) {
pr_err("key does not exist\n");
spin_unlock(&kc_lock);
return -EINVAL;
}
kc_clear_entry(entry, true);
spin_unlock(&kc_lock);
return 0;
}
/**
* pfk_kc_remove_key() - remove the key from cache and from ICE engine
* when no salt is available. Will only search key part, if there are several,
* all will be removed
*
* @key: pointer to the key
* @key_size: the size of the key
*
* Return 0 in case of success, error otherwise (also in case of non
* (existing key)
@ -330,6 +431,7 @@ int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index)
int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
{
struct kc_entry *entry = NULL;
int index = 0;
if (!kc_is_ready())
return -ENODEV;
@ -341,7 +443,8 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
return -EPERM;
spin_lock(&kc_lock);
entry = kc_find_key(key, key_size);
entry = kc_find_key_at_index(key, key_size, NULL, 0, &index);
if (!entry) {
pr_err("key does not exist\n");
spin_unlock(&kc_lock);
@ -349,6 +452,16 @@ int pfk_kc_remove_key(const unsigned char *key, size_t key_size)
}
kc_clear_entry(entry, true);
/* let's clean additional entries with the same key if there are any */
do {
entry = kc_find_key_at_index(key, key_size, NULL, 0, &index);
if (!entry)
break;
kc_clear_entry(entry, true);
} while (true);
spin_unlock(&kc_lock);
return 0;

View file

@ -17,7 +17,10 @@
int pfk_kc_init(void);
int pfk_kc_deinit(void);
int pfk_kc_load_key(const unsigned char *key, size_t key_size, u32 *key_index);
int pfk_kc_load_key(const unsigned char *key, size_t key_size,
const unsigned char *salt, size_t salt_size, u32 *key_index);
int pfk_kc_remove_key_with_salt(const unsigned char *key, size_t key_size,
const unsigned char *salt, size_t salt_size);
int pfk_kc_remove_key(const unsigned char *key, size_t key_size);
void pfk_kc_clear(void);