Skip to content

Commit

Permalink
PM / hibernate: create snapshot keys handler and using EFI key
Browse files Browse the repository at this point in the history
This patch adds a snapshot keys handler as a helper to use the
key retention service api to create the session key for snapshot
image encryption and authentication.

The handler uses EFI key as the snapshot key, and the encription
key and authentication key are derived from the snapshot key. The
encrypted key can also be a snapshot key, the logic will be added
to handler later.

The sanpshot key is a session key for one time usage. Either EFI
key or encrypted key can encrypt the key data to be a encrypted
blob. Kernel stores the encrypted blob to the snapshot image header
for hibernation resume.
  • Loading branch information
joeyli committed Jul 30, 2018
1 parent 4953ea3 commit 6311e97
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 11 deletions.
1 change: 1 addition & 0 deletions kernel/power/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ obj-$(CONFIG_FREEZER) += process.o
obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o
obj-$(CONFIG_HIBERNATE_VERIFICATION) += snapshot_key.o
obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o
obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o

Expand Down
10 changes: 9 additions & 1 deletion kernel/power/hibernate.c
Original file line number Diff line number Diff line change
Expand Up @@ -713,17 +713,24 @@ int hibernate(void)
}
efi_skey_stop_regen();

error = snapshot_create_trampoline();
error = init_snapshot_key();
if (error)
return error;

error = snapshot_create_trampoline();
if (error) {
clean_snapshot_key();
return error;
}

/* using EFI secret key to encrypt hidden area */
secret_key = get_efi_secret_key();
if (secret_key) {
error = encrypt_backup_hidden_area(secret_key, SECRET_KEY_SIZE);
if (error) {
pr_err("Encrypt hidden area failed: %d\n", error);
snapshot_free_trampoline();
clean_snapshot_key();
return error;
}
}
Expand Down Expand Up @@ -807,6 +814,7 @@ int hibernate(void)
atomic_inc(&snapshot_device_available);
Unlock:
unlock_system_sleep();
clean_snapshot_key();
pr_info("hibernation exit\n");

return error;
Expand Down
21 changes: 21 additions & 0 deletions kernel/power/power.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@
#include <linux/freezer.h>
#include <linux/compiler.h>
#include <crypto/aes.h>
#include <crypto/sha.h>

/* HMAC algorithm for hibernate snapshot signature */
#define SNAPSHOT_HMAC "hmac(sha512)"
#define SNAPSHOT_DIGEST_SIZE 64

/* The max size of encrypted key blob */
#define KEY_BLOB_BUFF_LEN 512
#define SNAPSHOT_KEY_SIZE SHA512_DIGEST_SIZE
#define DERIVED_KEY_SIZE SHA512_DIGEST_SIZE

struct swsusp_info {
struct new_utsname uts;
u32 version_code;
Expand All @@ -21,6 +27,7 @@ struct swsusp_info {
unsigned long trampoline_pfn;
u8 iv[AES_BLOCK_SIZE];
u8 signature[SNAPSHOT_DIGEST_SIZE];
u8 encrypted_key_blob[KEY_BLOB_BUFF_LEN];
} __aligned(PAGE_SIZE);

#ifdef CONFIG_HIBERNATION
Expand Down Expand Up @@ -175,6 +182,13 @@ extern int swsusp_prepare_crypto(bool may_sleep, bool create_iv);
extern void swsusp_finish_crypto(void);
extern void snapshot_set_enforce_verify(void);
extern int snapshot_is_enforce_verify(void);
extern int init_snapshot_key(void);
extern int init_snapshot_key_by_blob(u8 *encrypted_key_blob);
extern int get_snapshot_key(void);
extern int get_snapshot_auth_key(u8 *auth_key, bool may_sleep);
extern int get_snapshot_enc_key(u8 *enc_key, bool may_sleep);
extern int get_encrypted_snapshot_key_blob(u8 *buffer);
extern void clean_snapshot_key(void);
#else
static inline int snapshot_image_verify(void) { return 0; }
static inline int swsusp_prepare_hash(bool may_sleep) { return 0; }
Expand All @@ -183,6 +197,13 @@ static inline int swsusp_prepare_crypto(bool may_sleep, bool create_iv) { return
static inline void swsusp_finish_crypto(void) {}
static inline void snapshot_set_enforce_verify(void) {}
static inline int snapshot_is_enforce_verify(void) {return 0;}
extern int init_snapshot_key(void) { return 0; }
extern int init_snapshot_key_by_blob(u8 *encrypted_key_blob) { return 0; }
extern int get_snapshot_key(void) { return 0; }
extern int get_snapshot_auth_key(u8 *auth_key, bool may_sleep) { return 0; }
extern int get_snapshot_enc_key(u8 *enc_key, bool may_sleep) { return 0; }
extern int get_encrypted_snapshot_key_blob(u8 *buffer) { return 0; }
extern void clean_snapshot_key(void) {}
#endif

/* If unset, the snapshot device cannot be open. */
Expand Down
37 changes: 27 additions & 10 deletions kernel/power/snapshot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,9 @@ static void **h_buf;
*/
static u8 signature[SNAPSHOT_DIGEST_SIZE];

/* the data blob of encrypted snapshot key */
static u8 encrypted_key_blob[KEY_BLOB_BUFF_LEN];

/* Keep the signature verification result for trampoline */
static int sig_verify_ret;

Expand Down Expand Up @@ -1467,11 +1470,11 @@ static void *c_buffer;
int swsusp_prepare_crypto(bool may_sleep, bool create_iv)
{
struct crypto_skcipher *tfm;
u8 *key;
char enc_key[DERIVED_KEY_SIZE];
int ret = 0;

key = get_efi_secret_key();
if (!key) {
ret = get_snapshot_enc_key(enc_key, may_sleep);
if (ret) {
pr_warn_once("secret key is invalid\n");
return (sig_enforce) ? -EINVAL : 0;
}
Expand All @@ -1489,7 +1492,7 @@ int swsusp_prepare_crypto(bool may_sleep, bool create_iv)
goto alloc_fail;
}

ret = crypto_skcipher_setkey(tfm, key, 32);
ret = crypto_skcipher_setkey(tfm, enc_key, AES_MAX_KEY_SIZE);
if (ret) {
pr_err("failed to setkey (%d)\n", ret);
goto set_fail;
Expand Down Expand Up @@ -1533,14 +1536,14 @@ static struct shash_desc *s4_verify_desc;

int swsusp_prepare_hash(bool may_sleep)
{
char auth_key[DERIVED_KEY_SIZE];
struct crypto_shash *tfm;
u8 *key;
size_t digest_size, desc_size;
int ret;

key = get_efi_secret_key();
if (!key) {
pr_warn_once("secret key is invalid\n");
ret = get_snapshot_auth_key(auth_key, may_sleep);
if (ret) {
pr_warn_once("auth key is invalid\n");
return (sig_enforce) ? -EINVAL : 0;
}

Expand All @@ -1550,15 +1553,15 @@ int swsusp_prepare_hash(bool may_sleep)
return PTR_ERR(tfm);
}

ret = crypto_shash_setkey(tfm, key, SNAPSHOT_DIGEST_SIZE);
ret = crypto_shash_setkey(tfm, auth_key, DERIVED_KEY_SIZE);
if (ret) {
pr_err("Set HMAC key failed\n");
goto error;
}

desc_size = crypto_shash_descsize(tfm) + sizeof(*s4_verify_desc);
digest_size = crypto_shash_digestsize(tfm);
s4_verify_digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
s4_verify_digest = kzalloc(digest_size + desc_size, GFP_KERNEL); //TODO: check may_sleep ATOMIC
if (!s4_verify_digest) {
pr_err("Allocate digest failed\n");
ret = -ENOMEM;
Expand Down Expand Up @@ -1644,6 +1647,10 @@ int snapshot_image_verify(void)
goto error_prep;
}

ret = init_snapshot_key_by_blob(encrypted_key_blob);
if (ret)
goto error_prep;

ret = swsusp_prepare_hash(true);
if (ret || !s4_verify_desc)
goto error_prep;
Expand Down Expand Up @@ -1677,6 +1684,7 @@ int snapshot_image_verify(void)
error_shash_crypto:
swsusp_finish_crypto();
swsusp_finish_hash();
clean_snapshot_key();

error_prep:
vfree(h_buf);
Expand Down Expand Up @@ -1761,6 +1769,12 @@ static void load_signature(struct swsusp_info *info)
memcpy(signature, info->signature, SNAPSHOT_DIGEST_SIZE);
}

static void load_snapshot_key_blob(struct swsusp_info *info)
{
memset(encrypted_key_blob, 0, KEY_BLOB_BUFF_LEN);
memcpy(encrypted_key_blob, info->encrypted_key_blob, KEY_BLOB_BUFF_LEN);
}

static void init_sig_verify(struct trampoline *t)
{
t->sig_enforce = sig_enforce;
Expand Down Expand Up @@ -1809,6 +1823,7 @@ __copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
static inline void alloc_h_buf(void) {}
static void init_signature(struct swsusp_info *info) {}
static void load_signature(struct swsusp_info *info) {}
static void load_snapshot_key_blob(struct swsusp_info *info) {}
static void init_sig_verify(struct trampoline *t) {}
static void handle_sig_verify(struct trampoline *t) {}
#endif /* CONFIG_HIBERNATE_VERIFICATION */
Expand Down Expand Up @@ -2457,6 +2472,7 @@ static int init_header(struct swsusp_info *info)
info->trampoline_pfn = page_to_pfn(virt_to_page(trampoline_virt));
memcpy(info->iv, iv, AES_BLOCK_SIZE);
init_signature(info);
get_encrypted_snapshot_key_blob(info->encrypted_key_blob);
return init_header_complete(info);
}

Expand Down Expand Up @@ -2713,6 +2729,7 @@ static int load_header(struct swsusp_info *info)
trampoline_pfn = info->trampoline_pfn;
memcpy(iv, info->iv, AES_BLOCK_SIZE);
load_signature(info);
load_snapshot_key_blob(info);
}
return error;
}
Expand Down
Loading

0 comments on commit 6311e97

Please sign in to comment.