linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
@ 2013-08-22 11:01 Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 01/18] asymmetric keys: add interface and skeleton for implement signature generation Lee, Chun-Yi
                   ` (18 more replies)
  0 siblings, 19 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Hi experts,

This patchset is the implementation for signature verification of hibernate
snapshot image. The origin idea is from Jiri Kosina: Let EFI bootloader
generate key-pair in UEFI secure boot environment, then pass it to kernel
for sign/verify S4 image.

Due to there have potential threat from the S4 image hacked, it may causes
kernel lost the trust in UEFI secure boot. Hacker attack the S4 snapshot
image in swap partition through whatever exploit from another trusted OS,
and the exploit may don't need physical access machine.

So, this patchset give the ability to kernel for parsing the RSA private key
from EFI bootloader, then using the private key to generate the signature
of S4 snapshot image. Kernel put the signature to snapshot header, and
verify the signature when kernel try to recover snapshot image to memory.

==============
How To Enable
==============

Set enable the CONFIG_SNAPSHOT_VERIFICATION kernel config. And you can also
choice which hash algorithm should snapshot be signed with. Then rebuild
kernel.

Please note this function need UEFI bootloader's support to generate key-pair
in UEFI secure boot environment, e.g. shim. Current shim implementation by
Gary Lin:

Git:
     https://github.com/lcp/shim/tree/s4-key-upstream
RPM:
     https://build.opensuse.org/package/show/home:gary_lin:UEFI/shim

Please use the shim from above URL if you want to try. Please remember add
the hash of shim to db in UEFI BIOS because it didn't sign by Microsoft or
any OSV key.

=========
Behavior
=========

The RSA key-pair are generated by EFI bootloader(e.g. shim) in UEFI secure
boot environment, so this function binding with EFI secure boot enabled.
The kernel behavior is:

 + UEFI Secure Boot ON. Kernel found private key from shim:
   Kernel will run the signature check when S4.

 + UEFI Secure Boot ON. Kernel didn't find key from shim:
   Kernel will lock down S4 function.

 + UEFI Secure Boot OFF
   Kernel will disable S4 signature check, and ignore any keys
   from EFI bootloader. Unconditional allow hibernate launch.

On EFI bootloader side, the behavior as following:

 + First, kernel will check the following 2 EFI variable:
   S4SignKey-fe141863-c070-478e-b8a3-878a5dc9ef21    [BootService]
   S4WakeKey-fe141863-c070-478e-b8a3-878a5dc9ef21    [Runtime][Volatile]

   S4SignKey and S4WakeKey is a RSA key-pair:
    - S4SignKey is a private key that's used to generate signature of S4
      snapshot.
      The blob format of S4SignKey is PKCS#8 uncompressed format, it should
      packaged a RSA private key that's followed PKCS#1.

    - S4WakeKey is a public key that's used to verify signature of S4
      snapshot.
      The blob format of S4WakeKey is X.509 format, it should packaged a RSA
      public key that's followed PKCS#1.

 + EFI bootloader must generate RSA key-pair when system boot:
   - Bootloader store the public key to EFI boottime variable by itself
   - Bootloader put The private key to S4SignKey EFI variable for forward to
     kernel.

 + EFI stub kernel will load the S4SignKey blob to RAM before ExitBootServices,
   then copy to a memory page to maintain by hibernate_key.c. This private key
   will used to sign snapshot when S4.

 + When machine resume from hibernate:
   - EFI bootloader should copy the public key from boottime variable to
     S4WakeKey EFI variable.
   - Bootloader need generates a new key-pair for next round S4 usage.
     It should put new private key to S4SignKey variable.

 + EFI bootlaoder need check the following EFI runtime variable for regenerate
   new key-pair:
   GenS4Key-fe141863-c070-478e-b8a3-878a5dc9ef21

   The size of GenS4Key is 1 byte, OS(kernel or userland tool) will set it to
   "1" for notify efi bootloader regenerate key-pair.

==============
Implementation
==============

Whole implementation including 3 parts: shim, asymmetric keys and hibernate:

 + shim:
   Current solution implemented by Gary Lin:
     https://github.com/lcp/shim/tree/s4-key-upstream

   Please use shim from the above URL if you want to try. Please remember add
   this shim to db because it didn't sign by Microsoft or any OSV key.

 + Asymmetric keys:
   This patchset implemented uncompressed PKCS#8 and RSA private key parser,
   it also implement the signature generation operation of RSASSA-PKCS1-v_5
   in PKCS#1 spec. [RFC3447 sec 8.2.2]
   Set CONFIG_PKCS8_PRIVATE_KEY_INFO_PARSER=y will give kernel the abilities
   to parsing private key in uncompressed PKCS#8 blob and generate signature.

 + Hibernate:
   Set CONFIG_SNAPSHOT_VERIFICATION=y will enable the function of snapshot
   signature generation and verification. I reserved 512 byes size in snapshot
   header for store the signature that's generated from the digest with SHA
   algorithms.

For adapt S4 signature check to secure boot, I have porting 3 patches from
Fedora kernel, authors are Josh Boyer and Matthew Garrett. I also add Cc. to
them.

Please help review this RFC patchset! Appreciate for any comments!


v3:
 - Load S4 sign key before ExitBootServices in efi stub.
 - In Makefile, moved hibernate_keys.o before hibernate.o for load S4 sign
   key before check hibernate image. It makes sure the new sign key will be
   transfer to resume target kernel.
 - Set "depends on EFI_STUB" in Kconfig. 

v2:
 - Moved SNAPSHOT_VERIFICATION kernel config to earlier patch.
 - Add dummy functions to simplify the ifdef check. 
 - Sent to opensuse-kernel@opensuse.org for review:
   http://lists.opensuse.org/opensuse-kernel/2013-08/msg00025.html

v1:
 - Internal review
 - github:
   https://github.com/joeyli/linux-s4sign/commits/devel-s4sign


Josh Boyer (1):
  Secure boot: Add a dummy kernel parameter that will switch on Secure
    Boot mode

Lee, Chun-Yi (15):
  asymmetric keys: add interface and skeleton for implement signature
    generation
  asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa
  asymmetric keys: separate the length checking of octet string from
    RSA_I2OSP
  asymmetric keys: implement OS2IP in rsa
  asymmetric keys: implement RSASP1
  asymmetric keys: support parsing PKCS #8 private key information
  asymmetric keys: explicitly add the leading zero byte to encoded
    message
  Hibernate: introduced RSA key-pair to verify signature of snapshot
  Hibernate: generate and verify signature of snapshot
  Hibernate: Avoid S4 sign key data included in snapshot image
  Hibernate: applied SNAPSHOT_VERIFICATION config to switch signature
    check
  Hibernate: adapt to UEFI secure boot with signature check
  Hibernate: show the verification time for monitor performance
  Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash
    algorithm
  Hibernate: notify bootloader regenerate key-pair for snapshot
    verification

Matthew Garrett (2):
  Secure boot: Add new capability
  efi: Enable secure boot lockdown automatically when enabled in
    firmware

 Documentation/kernel-parameters.txt        |    7 +
 Documentation/x86/zero-page.txt            |    2 +
 arch/x86/boot/compressed/eboot.c           |  121 ++++++++++
 arch/x86/include/asm/bootparam_utils.h     |    8 +-
 arch/x86/include/asm/efi.h                 |    9 +
 arch/x86/include/uapi/asm/bootparam.h      |    4 +-
 arch/x86/kernel/setup.c                    |    7 +
 arch/x86/platform/efi/efi.c                |   68 ++++++
 crypto/asymmetric_keys/Kconfig             |   11 +
 crypto/asymmetric_keys/Makefile            |   16 ++
 crypto/asymmetric_keys/pkcs8.asn1          |   19 ++
 crypto/asymmetric_keys/pkcs8_info_parser.c |  152 ++++++++++++
 crypto/asymmetric_keys/pkcs8_parser.h      |   23 ++
 crypto/asymmetric_keys/pkcs8_private_key.c |  148 ++++++++++++
 crypto/asymmetric_keys/pkcs8_rsakey.asn1   |   29 +++
 crypto/asymmetric_keys/private_key.h       |   29 +++
 crypto/asymmetric_keys/public_key.c        |   32 +++
 crypto/asymmetric_keys/rsa.c               |  283 ++++++++++++++++++++++-
 crypto/asymmetric_keys/signature.c         |   28 +++
 include/crypto/public_key.h                |   28 +++
 include/keys/asymmetric-subtype.h          |    6 +
 include/linux/cred.h                       |    2 +
 include/linux/efi.h                        |   18 ++
 include/uapi/linux/capability.h            |    6 +-
 kernel/cred.c                              |   17 ++
 kernel/power/Kconfig                       |   77 ++++++-
 kernel/power/Makefile                      |    1 +
 kernel/power/hibernate.c                   |   37 +++
 kernel/power/hibernate_keys.c              |  329 ++++++++++++++++++++++++++
 kernel/power/main.c                        |   11 +-
 kernel/power/power.h                       |   35 +++
 kernel/power/snapshot.c                    |  345 +++++++++++++++++++++++++++-
 kernel/power/swap.c                        |   22 ++
 kernel/power/user.c                        |   22 ++
 34 files changed, 1925 insertions(+), 27 deletions(-)
 create mode 100644 crypto/asymmetric_keys/pkcs8.asn1
 create mode 100644 crypto/asymmetric_keys/pkcs8_info_parser.c
 create mode 100644 crypto/asymmetric_keys/pkcs8_parser.h
 create mode 100644 crypto/asymmetric_keys/pkcs8_private_key.c
 create mode 100644 crypto/asymmetric_keys/pkcs8_rsakey.asn1
 create mode 100644 crypto/asymmetric_keys/private_key.h
 create mode 100644 kernel/power/hibernate_keys.c


^ permalink raw reply	[flat|nested] 61+ messages in thread

* [PATCH 01/18] asymmetric keys: add interface and skeleton for implement signature generation
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa Lee, Chun-Yi
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Add generate_signature interface on signature.c, asymmetric-subtype and
rsa.c for prepare to implement signature generation.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/private_key.h |   29 +++++++++++++++++++++++++++++
 crypto/asymmetric_keys/public_key.c  |   31 +++++++++++++++++++++++++++++++
 crypto/asymmetric_keys/rsa.c         |   22 ++++++++++++++++++++++
 crypto/asymmetric_keys/signature.c   |   28 ++++++++++++++++++++++++++++
 include/crypto/public_key.h          |   25 +++++++++++++++++++++++++
 include/keys/asymmetric-subtype.h    |    6 ++++++
 6 files changed, 141 insertions(+), 0 deletions(-)
 create mode 100644 crypto/asymmetric_keys/private_key.h

diff --git a/crypto/asymmetric_keys/private_key.h b/crypto/asymmetric_keys/private_key.h
new file mode 100644
index 0000000..c022eee
--- /dev/null
+++ b/crypto/asymmetric_keys/private_key.h
@@ -0,0 +1,29 @@
+/* Private key algorithm internals
+ *
+ * Copyright (C) 2013 SUSE Linux Products GmbH. All rights reserved.
+ * Written by Chun-Yi Lee (jlee@suse.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <crypto/public_key.h>
+
+extern struct asymmetric_key_subtype private_key_subtype;
+
+/*
+ * Private key algorithm definition.
+ */
+struct private_key_algorithm {
+	const char	*name;
+	u8		n_pub_mpi;	/* Number of MPIs in public key */
+	u8		n_sec_mpi;	/* Number of MPIs in secret key */
+	u8		n_sig_mpi;	/* Number of MPIs in a signature */
+	struct public_key_signature* (*generate_signature)(
+		const struct private_key *key, u8 *M,
+		enum pkey_hash_algo hash_algo, const bool hash);
+};
+
+extern const struct private_key_algorithm RSA_private_key_algorithm;
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index cb2e291..97ff932 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -19,6 +19,7 @@
 #include <linux/seq_file.h>
 #include <keys/asymmetric-subtype.h>
 #include "public_key.h"
+#include "private_key.h"
 
 MODULE_LICENSE("GPL");
 
@@ -96,6 +97,24 @@ static int public_key_verify_signature(const struct key *key,
 }
 
 /*
+ * Generate a signature using a private key.
+ */
+static struct public_key_signature *private_key_generate_signature(
+		const struct key *key, u8 *M, enum pkey_hash_algo hash_algo,
+		const bool hash)
+{
+	const struct private_key *pk = key->payload.data;
+
+	pr_info("private_key_generate_signature start");
+
+	if (!pk->algo->generate_signature)
+		return ERR_PTR(-ENOTSUPP);
+
+	return pk->algo->generate_signature(pk, M, hash_algo, hash);
+
+}
+
+/*
  * Public key algorithm asymmetric key subtype
  */
 struct asymmetric_key_subtype public_key_subtype = {
@@ -106,3 +125,15 @@ struct asymmetric_key_subtype public_key_subtype = {
 	.verify_signature	= public_key_verify_signature,
 };
 EXPORT_SYMBOL_GPL(public_key_subtype);
+
+/*
+ * Private key algorithm asymmetric key subtype
+ */
+struct asymmetric_key_subtype private_key_subtype = {
+	.owner                  = THIS_MODULE,
+	.name                   = "private_key",
+	.describe               = public_key_describe,
+	.destroy                = public_key_destroy,
+	.generate_signature     = private_key_generate_signature,
+};
+EXPORT_SYMBOL_GPL(private_key_subtype);
diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index 4a6a069..95aab83 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include "public_key.h"
+#include "private_key.h"
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("RSA Public Key Algorithm");
@@ -267,6 +268,18 @@ error:
 	return ret;
 }
 
+/*
+ * Perform the generation step [RFC3447 sec 8.2.1].
+ */
+static struct public_key_signature *RSA_generate_signature(
+		const struct private_key *key, u8 *M,
+		enum pkey_hash_algo hash_algo, const bool hash)
+{
+	pr_info("RSA_generate_signature start");
+
+	return 0;
+}
+
 const struct public_key_algorithm RSA_public_key_algorithm = {
 	.name		= "RSA",
 	.n_pub_mpi	= 2,
@@ -275,3 +288,12 @@ const struct public_key_algorithm RSA_public_key_algorithm = {
 	.verify_signature = RSA_verify_signature,
 };
 EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
+
+const struct private_key_algorithm RSA_private_key_algorithm = {
+	.name           = "RSA",
+	.n_pub_mpi      = 2,
+	.n_sec_mpi      = 3,
+	.n_sig_mpi      = 1,
+	.generate_signature = RSA_generate_signature,
+};
+EXPORT_SYMBOL_GPL(RSA_private_key_algorithm);
diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c
index 50b3f88..a1bf6be 100644
--- a/crypto/asymmetric_keys/signature.c
+++ b/crypto/asymmetric_keys/signature.c
@@ -47,3 +47,31 @@ int verify_signature(const struct key *key,
 	return ret;
 }
 EXPORT_SYMBOL_GPL(verify_signature);
+
+/**
+ * generate_signature - Initiate the use of an asymmetric key to generate a signature
+ * @key: The asymmetric key to generate against
+ * @M: The message to be signed, or a hash result. Dependent on the hash parameter
+ * @hash_algo: The hash algorithm to generate digest
+ * @hash: true means M is a original mesagse, false means M is a hash result
+ *
+ * Returns public_key-signature if successful or else an error.
+ */
+struct public_key_signature *generate_signature(const struct key *key, u8 *M,
+		enum pkey_hash_algo hash_algo, const bool hash)
+{
+	const struct asymmetric_key_subtype *subtype;
+
+	pr_info("==>%s()\n", __func__);
+
+	if (key->type != &key_type_asymmetric)
+		return ERR_PTR(-EINVAL);
+	subtype = asymmetric_key_subtype(key);
+	if (!subtype || !key->payload.data)
+		return ERR_PTR(-EINVAL);
+	if (!subtype->generate_signature)
+		return ERR_PTR(-ENOTSUPP);
+
+	return subtype->generate_signature(key, M, hash_algo, hash);
+}
+EXPORT_SYMBOL_GPL(generate_signature);
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index f5b0224..d44b29f 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -79,6 +79,29 @@ struct public_key {
 	};
 };
 
+struct private_key {
+	const struct private_key_algorithm *algo;
+	u8      capabilities;
+	enum pkey_id_type id_type:8;
+	union {
+		MPI     mpi[5];
+		struct {
+			MPI     p;      /* DSA prime */
+			MPI     q;      /* DSA group order */
+			MPI     g;      /* DSA group generator */
+			MPI     y;      /* DSA public-key value = g^x mod p */
+			MPI     x;      /* DSA secret exponent (if present) */
+		} dsa;
+		struct {
+			MPI     n;      /* RSA public modulus */
+			MPI     e;      /* RSA public encryption exponent */
+			MPI     d;      /* RSA secret encryption exponent (if present) */
+			MPI     p;      /* RSA secret prime (if present) */
+			MPI     q;      /* RSA secret prime (if present) */
+		} rsa;
+	};
+};
+
 extern void public_key_destroy(void *payload);
 
 /*
@@ -104,5 +127,7 @@ struct public_key_signature {
 struct key;
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
+extern struct public_key_signature *generate_signature(const struct key *key,
+			u8 *M, enum pkey_hash_algo hash_algo, const bool hash);
 
 #endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h
index 4b840e8..af79939 100644
--- a/include/keys/asymmetric-subtype.h
+++ b/include/keys/asymmetric-subtype.h
@@ -18,6 +18,7 @@
 #include <keys/asymmetric-type.h>
 
 struct public_key_signature;
+enum pkey_hash_algo;
 
 /*
  * Keys of this type declare a subtype that indicates the handlers and
@@ -37,6 +38,11 @@ struct asymmetric_key_subtype {
 	/* Verify the signature on a key of this subtype (optional) */
 	int (*verify_signature)(const struct key *key,
 				const struct public_key_signature *sig);
+
+	/* Generate the signature by key of this subtype (optional) */
+	struct public_key_signature* (*generate_signature)
+		(const struct key *key, u8 *M, enum pkey_hash_algo hash_algo,
+		 const bool hash);
 };
 
 /**
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 01/18] asymmetric keys: add interface and skeleton for implement signature generation Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 15:53   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP Lee, Chun-Yi
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Implement EMSA_PKCS1-v1_5-ENCODE [RFC3447 sec 9.2] in rsa.c. It's the
first step of signature generation operation (RSASSA-PKCS1-v1_5-SIGN).

This patch is temporary set emLen to pks->k, and temporary set EM to
pks->S for debugging. We will replace the above values to real signature
after implement RSASP1.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/rsa.c |  158 +++++++++++++++++++++++++++++++++++++++++-
 include/crypto/public_key.h  |    2 +
 2 files changed, 158 insertions(+), 2 deletions(-)

diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index 95aab83..6996ff7 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
+#include <crypto/hash.h>
 #include "public_key.h"
 #include "private_key.h"
 
@@ -152,6 +153,125 @@ static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
 }
 
 /*
+ * EMSA_PKCS1-v1_5-ENCODE [RFC3447 sec 9.2]
+ * @M: message to be signed, and octet string
+ * @emLen: intended length in octets of the encoded message
+ * @hash_algo: hash function (option)
+ * @hash: true means hash M, otherwise M is digest
+ * @EM: encoded message, an octet string of length emLen
+ */
+static int EMSA_PKCS1_v1_5_ENCODE(const u8 *M, size_t emLen,
+		enum pkey_hash_algo hash_algo, const bool hash,
+		u8 **_EM, struct public_key_signature *pks)
+{
+	u8 *digest;
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	size_t digest_size, desc_size;
+	size_t tLen;
+	u8 *T, *PS, *EM;
+	int i, ret;
+
+	pr_info("EMSA_PKCS1_v1_5_ENCODE start\n");
+
+	if (!RSA_ASN1_templates[hash_algo].data)
+		ret = -ENOTSUPP;
+	else
+		pks->pkey_hash_algo = hash_algo;
+
+	/* 1) Apply the hash function to the message M to produce a hash value H */
+	tfm = crypto_alloc_shash(pkey_hash_algo[hash_algo], 0, 0);
+	if (IS_ERR(tfm))
+		return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	digest_size = crypto_shash_digestsize(tfm);
+
+	ret = -ENOMEM;
+
+	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+	if (!digest)
+		goto error_digest;
+	pks->digest = digest;
+	pks->digest_size = digest_size;
+
+	if (hash) {
+		desc = (void *) digest + digest_size;
+		desc->tfm = tfm;
+		desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+		ret = crypto_shash_init(desc);
+		if (ret < 0)
+			goto error_shash;
+		ret = crypto_shash_finup(desc, M, sizeof(M), pks->digest);
+		if (ret < 0)
+			goto error_shash;
+	} else {
+		memcpy(pks->digest, M, pks->digest_size);
+		pks->digest_size = digest_size;
+	}
+	crypto_free_shash(tfm);
+
+	/* 2) Encode the algorithm ID for the hash function and the hash value into
+	 * an ASN.1 value of type DigestInfo with the DER. Let T be the DER encoding of
+	 * the DigestInfo value and let tLen be the length in octets of T.
+	 */
+	tLen = RSA_ASN1_templates[hash_algo].size + pks->digest_size;
+	T = kmalloc(tLen, GFP_KERNEL);
+	if (!T)
+		goto error_T;
+
+	memcpy(T, RSA_ASN1_templates[hash_algo].data, RSA_ASN1_templates[hash_algo].size);
+	memcpy(T + RSA_ASN1_templates[hash_algo].size, pks->digest, pks->digest_size);
+
+	/* 3) check If emLen < tLen + 11, output "intended encoded message length too short" */
+	if (emLen < tLen + 11) {
+		ret = EINVAL;
+		goto error_emLen;
+	}
+
+	/* 4) Generate an octet string PS consisting of emLen - tLen - 3 octets with 0xff. */
+	PS = kmalloc(emLen - tLen - 3, GFP_KERNEL);
+	if (!PS)
+		goto error_P;
+
+	for (i = 0; i < (emLen - tLen - 3); i++)
+		PS[i] = 0xff;
+
+	/* 5) Concatenate PS, the DER encoding T, and other padding to form the encoded
+	 * message EM as EM = 0x00 || 0x01 || PS || 0x00 || T
+	 */
+	EM = kmalloc(3 + emLen - tLen - 3 + tLen, GFP_KERNEL);
+	if (!EM)
+		goto error_EM;
+
+	EM[0] = 0x00;
+	EM[1] = 0x01;
+	memcpy(EM + 2, PS, emLen - tLen - 3);
+	EM[2 + emLen - tLen - 3] = 0x00;
+	memcpy(EM + 2 + emLen - tLen - 3 + 1, T, tLen);
+
+	*_EM = EM;
+
+	kfree(PS);
+	kfree(T);
+
+	return 0;
+
+error_EM:
+	kfree(PS);
+error_P:
+error_emLen:
+	kfree(T);
+error_T:
+error_shash:
+	kfree(digest);
+error_digest:
+	crypto_free_shash(tfm);
+	return ret;
+}
+
+/*
  * Perform the RSA signature verification.
  * @H: Value of hash of data and metadata
  * @EM: The computed signature value
@@ -275,9 +395,43 @@ static struct public_key_signature *RSA_generate_signature(
 		const struct private_key *key, u8 *M,
 		enum pkey_hash_algo hash_algo, const bool hash)
 {
-	pr_info("RSA_generate_signature start");
+	struct public_key_signature *pks;
+	u8 *EM = NULL;
+	size_t emLen;
+	int ret;
 
-	return 0;
+	pr_info("RSA_generate_signature start\n");
+
+	ret = -ENOMEM;
+	pks = kzalloc(sizeof(*pks), GFP_KERNEL);
+	if (!pks)
+		goto error_no_pks;
+
+	/* 1): EMSA-PKCS1-v1_5 encoding: */
+	/* Use the private key modulus size to be EM length */
+	emLen = mpi_get_nbits(key->rsa.n);
+	emLen = (emLen + 7) / 8;
+
+	ret = EMSA_PKCS1_v1_5_ENCODE(M, emLen, hash_algo, hash, &EM, pks);
+	if (ret < 0)
+		goto error_v1_5_encode;
+
+	/* TODO 2): m = OS2IP (EM) */
+
+	/* TODO 3): s = RSASP1 (K, m) */
+
+	/* TODO 4): S = I2OSP (s, k) */
+
+	/* TODO: signature S to a u8* S or set to sig->rsa.s? */
+	pks->S = EM;		/* TODO: temporary set S to EM */
+
+	return pks;
+
+error_v1_5_encode:
+	kfree(pks);
+error_no_pks:
+	pr_info("<==%s() = %d\n", __func__, ret);
+	return ERR_PTR(ret);
 }
 
 const struct public_key_algorithm RSA_public_key_algorithm = {
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index d44b29f..1cdf457 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -110,6 +110,8 @@ extern void public_key_destroy(void *payload);
 struct public_key_signature {
 	u8 *digest;
 	u8 digest_size;			/* Number of bytes in digest */
+	u8 *S;				/* signature S of length k octets */
+	size_t k;			/* length k of signature S */
 	u8 nr_mpi;			/* Occupancy of mpi[] */
 	enum pkey_hash_algo pkey_hash_algo : 8;
 	union {
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 01/18] asymmetric keys: add interface and skeleton for implement signature generation Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:01   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 04/18] asymmetric keys: implement OS2IP in rsa Lee, Chun-Yi
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Due to RSA_I2OSP is not only used by signature verification path but also used
in signature generation path. So, separate the length checking of octet string
because it's not for generate 0x00 0x01 leading string when used in signature
generation.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/rsa.c |   33 ++++++++++++++++++++++++---------
 1 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index 6996ff7..c26ae77 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -121,12 +121,30 @@ static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
 /*
  * Integer to Octet String conversion [RFC3447 sec 4.1]
  */
-static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
+static int _RSA_I2OSP(MPI x, unsigned *X_size, u8 **_X)
 {
-	unsigned X_size, x_size;
 	int X_sign;
 	u8 *X;
 
+	X = mpi_get_buffer(x, X_size, &X_sign);
+	if (!X)
+		return -ENOMEM;
+	if (X_sign < 0) {
+		kfree(X);
+		return -EBADMSG;
+	}
+
+	*_X = X;
+	return 0;
+}
+
+static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
+{
+	unsigned x_size;
+	unsigned X_size;
+	u8 *X = NULL;
+	int ret;
+
 	/* Make sure the string is the right length.  The number should begin
 	 * with { 0x00, 0x01, ... } so we have to account for 15 leading zero
 	 * bits not being reported by MPI.
@@ -136,13 +154,10 @@ static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
 	if (x_size != xLen * 8 - 15)
 		return -ERANGE;
 
-	X = mpi_get_buffer(x, &X_size, &X_sign);
-	if (!X)
-		return -ENOMEM;
-	if (X_sign < 0) {
-		kfree(X);
-		return -EBADMSG;
-	}
+	ret = _RSA_I2OSP(x, &X_size, &X);
+	if (ret < 0)
+		return ret;
+
 	if (X_size != xLen - 1) {
 		kfree(X);
 		return -EBADMSG;
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 04/18] asymmetric keys: implement OS2IP in rsa
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (2 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 05/18] asymmetric keys: implement RSASP1 Lee, Chun-Yi
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Implement Octet String to Integer conversion [RFC3447 sec 4.2] in rsa.c. It's
the second step of signature generation operation.

This patch is temporary set non-RSASP1 message to pks->S for debugging.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/rsa.c |   29 ++++++++++++++++++++++++-----
 1 files changed, 24 insertions(+), 5 deletions(-)

diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index c26ae77..0862018 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -168,6 +168,20 @@ static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
 }
 
 /*
+ * Octet String to Integer conversion [RFC3447 sec 4.2]
+ */
+static int RSA_OS2IP(u8 *X, size_t XLen, MPI *_x)
+{
+	MPI x;
+
+	x = mpi_alloc((XLen + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB);
+	mpi_set_buffer(x, X, XLen, 0);
+
+	*_x = x;
+	return 0;
+}
+
+/*
  * EMSA_PKCS1-v1_5-ENCODE [RFC3447 sec 9.2]
  * @M: message to be signed, and octet string
  * @emLen: intended length in octets of the encoded message
@@ -412,6 +426,9 @@ static struct public_key_signature *RSA_generate_signature(
 {
 	struct public_key_signature *pks;
 	u8 *EM = NULL;
+	MPI m = NULL;
+	MPI s = NULL;
+	unsigned X_size;
 	size_t emLen;
 	int ret;
 
@@ -431,14 +448,16 @@ static struct public_key_signature *RSA_generate_signature(
 	if (ret < 0)
 		goto error_v1_5_encode;
 
-	/* TODO 2): m = OS2IP (EM) */
+	/* 2): m = OS2IP (EM) */
+	ret = RSA_OS2IP(EM, emLen, &m);
+	if (ret < 0)
+		goto error_v1_5_encode;
 
 	/* TODO 3): s = RSASP1 (K, m) */
+	s = m;
 
-	/* TODO 4): S = I2OSP (s, k) */
-
-	/* TODO: signature S to a u8* S or set to sig->rsa.s? */
-	pks->S = EM;		/* TODO: temporary set S to EM */
+	/* 4): S = I2OSP (s, k) */
+	_RSA_I2OSP(s, &X_size, &pks->S);
 
 	return pks;
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 05/18] asymmetric keys: implement RSASP1
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (3 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 04/18] asymmetric keys: implement OS2IP in rsa Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 06/18] asymmetric keys: support parsing PKCS #8 private key information Lee, Chun-Yi
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Implement RSASP1 and fill-in the following data to public key signature
structure: signature length (pkcs->k), signature octet
strings (pks->S) and MPI of signature (pks->rsa.s).

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/rsa.c |   47 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 44 insertions(+), 3 deletions(-)

diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index 0862018..e60defe 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -86,6 +86,39 @@ static const struct {
 };
 
 /*
+ * RSASP1() function [RFC3447 sec 5.2.1]
+ */
+static int RSASP1(const struct private_key *key, MPI m, MPI *_s)
+{
+	MPI s;
+	int ret;
+
+	/* (1) Validate 0 <= m < n */
+	if (mpi_cmp_ui(m, 0) < 0) {
+		kleave(" = -EBADMSG [m < 0]");
+		return -EBADMSG;
+	}
+	if (mpi_cmp(m, key->rsa.n) >= 0) {
+		kleave(" = -EBADMSG [m >= n]");
+		return -EBADMSG;
+	}
+
+	s = mpi_alloc(0);
+	if (!s)
+		return -ENOMEM;
+
+	/* (2) s = m^d mod n */
+	ret = mpi_powm(s, m, key->rsa.d, key->rsa.n);
+	if (ret < 0) {
+		mpi_free(s);
+		return ret;
+	}
+
+	*_s = s;
+	return 0;
+}
+
+/*
  * RSAVP1() function [RFC3447 sec 5.2.2]
  */
 static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
@@ -173,9 +206,12 @@ static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
 static int RSA_OS2IP(u8 *X, size_t XLen, MPI *_x)
 {
 	MPI x;
+	int ret;
 
 	x = mpi_alloc((XLen + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB);
-	mpi_set_buffer(x, X, XLen, 0);
+	ret = mpi_set_buffer(x, X, XLen, 0);
+	if (ret < 0)
+		return ret;
 
 	*_x = x;
 	return 0;
@@ -453,8 +489,13 @@ static struct public_key_signature *RSA_generate_signature(
 	if (ret < 0)
 		goto error_v1_5_encode;
 
-	/* TODO 3): s = RSASP1 (K, m) */
-	s = m;
+	/* 3): s = RSASP1 (K, m) */
+	RSASP1(key, m, &s);
+
+	pks->rsa.s = s;
+	pks->nr_mpi = 1;
+	pks->k = mpi_get_nbits(s);
+	pks->k = (pks->k + 7) / 8;
 
 	/* 4): S = I2OSP (s, k) */
 	_RSA_I2OSP(s, &X_size, &pks->S);
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 06/18] asymmetric keys: support parsing PKCS #8 private key information
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (4 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 05/18] asymmetric keys: implement RSASP1 Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:10   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 07/18] asymmetric keys: explicitly add the leading zero byte to encoded message Lee, Chun-Yi
                   ` (12 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Add ASN.1 files and parser to support parsing PKCS #8 noncompressed private
key information. It's better than direct parsing pure private key because
PKCS #8 has a privateKeyAlgorithm to indicate the algorithm of private
key, e.g. RSA from PKCS #1

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/Kconfig             |   11 ++
 crypto/asymmetric_keys/Makefile            |   16 +++
 crypto/asymmetric_keys/pkcs8.asn1          |   19 ++++
 crypto/asymmetric_keys/pkcs8_info_parser.c |  152 ++++++++++++++++++++++++++++
 crypto/asymmetric_keys/pkcs8_parser.h      |   23 ++++
 crypto/asymmetric_keys/pkcs8_private_key.c |  148 +++++++++++++++++++++++++++
 crypto/asymmetric_keys/pkcs8_rsakey.asn1   |   29 ++++++
 crypto/asymmetric_keys/public_key.c        |    1 +
 include/crypto/public_key.h                |    1 +
 9 files changed, 400 insertions(+), 0 deletions(-)
 create mode 100644 crypto/asymmetric_keys/pkcs8.asn1
 create mode 100644 crypto/asymmetric_keys/pkcs8_info_parser.c
 create mode 100644 crypto/asymmetric_keys/pkcs8_parser.h
 create mode 100644 crypto/asymmetric_keys/pkcs8_private_key.c
 create mode 100644 crypto/asymmetric_keys/pkcs8_rsakey.asn1

diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 6d2c2ea..c0ebd57 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -35,4 +35,15 @@ config X509_CERTIFICATE_PARSER
 	  data and provides the ability to instantiate a crypto key from a
 	  public key packet found inside the certificate.
 
+config PKCS8_PRIVATE_KEY_INFO_PARSER
+	tristate "PKCS #8 private key info parser"
+	depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
+	select ASN1
+	select OID_REGISTRY
+	select CRYPTO_SHA256
+	help
+	  This option provides support for parsing PKCS #8 RSA private key info
+	  format blobs for key data and provides the ability to instantiate a
+	  crypto key from a private key packet.
+
 endif # ASYMMETRIC_KEY_TYPE
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index 0727204..65fbc45 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -23,5 +23,21 @@ $(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h
 $(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
 $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h
 
+#
+# PKCS8 Private Key handling
+#
+obj-$(CONFIG_PKCS8_PRIVATE_KEY_INFO_PARSER) += pkcs8_key_parser.o
+pkcs8_key_parser-y := \
+       pkcs8-asn1.o \
+       pkcs8_rsakey-asn1.o \
+       pkcs8_info_parser.o \
+       pkcs8_private_key.o
+
+$(obj)/pkcs8_info_parser.o: $(obj)/pkcs8-asn1.c $(obj)/pkcs8_rsakey-asn1.h
+$(obj)/pkcs8-asn1.o: $(obj)/pkcs8-asn1.c $(obj)/pkcs8-asn1.h
+$(obj)/pkcs8_rsakey-asn1.o: $(obj)/pkcs8_rsakey-asn1.c $(obj)/pkcs8_rsakey-asn1.h
+
 clean-files	+= x509-asn1.c x509-asn1.h
 clean-files	+= x509_rsakey-asn1.c x509_rsakey-asn1.h
+clean-files	+= pkcs8-asn1.c pkcs8-asn1.h
+clean-files	+= pkcs8_rsakey-asn1.c pkcs8_rsakey-asn1.h
diff --git a/crypto/asymmetric_keys/pkcs8.asn1 b/crypto/asymmetric_keys/pkcs8.asn1
new file mode 100644
index 0000000..89e845d
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8.asn1
@@ -0,0 +1,19 @@
+--
+-- Representation of RSA PKCS#8 private key information.
+--
+
+PrivateKeyInfo ::= SEQUENCE {
+	version			Version,
+        privateKeyAlgorithm	AlgorithmIdentifier,
+	privateKey	        OCTET STRING ({ pkcs8_extract_key_data })
+	-- Does not support attributes
+	-- attributes		[ 0 ] Attributes OPTIONAL
+	}
+
+-- Version ::= INTEGER { two-prime(0), multi(1) }
+Version ::= INTEGER
+
+AlgorithmIdentifier ::= SEQUENCE {
+        algorithm               OBJECT IDENTIFIER ({ pkcs8_note_OID }),
+        parameters              ANY OPTIONAL
+	}
diff --git a/crypto/asymmetric_keys/pkcs8_info_parser.c b/crypto/asymmetric_keys/pkcs8_info_parser.c
new file mode 100644
index 0000000..2da19b9
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8_info_parser.c
@@ -0,0 +1,152 @@
+/* X.509 certificate parser
+ *
+ * Copyright (C) 2013 SUSE Linux Products GmbH. All rights reserved.
+ * Written by Lee, Chun-Yi (jlee@suse.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "PKCS8: "fmt
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/oid_registry.h>
+#include "public_key.h"
+#include "pkcs8_parser.h"
+#include "pkcs8-asn1.h"
+#include "pkcs8_rsakey-asn1.h"
+
+struct pkcs8_parse_context {
+	struct pkcs8_info *info;		/* Certificate being constructed */
+	unsigned long   data;			/* Start of data */
+	const void      *key;                   /* Key data */
+	size_t          key_size;               /* Size of key data */
+	enum OID	algo_oid;		/* Algorithm OID */
+	unsigned char   nr_mpi;		/* Number of MPIs stored */
+};
+
+/*
+ * Free an PKCS #8 private key info
+ */
+void pkcs8_free_info(struct pkcs8_info *info)
+{
+	if (info) {
+		public_key_destroy(info->priv);
+		kfree(info);
+	}
+}
+
+/*
+ * Parse an PKCS #8 Private Key Info
+ */
+struct pkcs8_info *pkcs8_info_parse(const void *data, size_t datalen)
+{
+	struct pkcs8_info *info;
+	struct pkcs8_parse_context *ctx;
+	long ret;
+
+	ret = -ENOMEM;
+	info = kzalloc(sizeof(struct pkcs8_info), GFP_KERNEL);
+	if (!info)
+		goto error_no_info;
+	info->priv = kzalloc(sizeof(struct private_key), GFP_KERNEL);
+	if (!info->priv)
+		goto error_no_ctx;
+	ctx = kzalloc(sizeof(struct pkcs8_parse_context), GFP_KERNEL);
+	if (!ctx)
+		goto error_no_ctx;
+
+	ctx->info = info;
+	ctx->data = (unsigned long)data;
+
+	/* Attempt to decode the private key info */
+	ret = asn1_ber_decoder(&pkcs8_decoder, ctx, data, datalen);
+	if (ret < 0)
+		goto error_decode;
+
+	/* Decode the private key */
+	ret = asn1_ber_decoder(&pkcs8_rsakey_decoder, ctx,
+			       ctx->key, ctx->key_size);
+	if (ret < 0)
+		goto error_decode;
+
+	kfree(ctx);
+	return info;
+
+error_decode:
+	kfree(ctx);
+error_no_ctx:
+	pkcs8_free_info(info);
+error_no_info:
+	return ERR_PTR(ret);
+}
+
+/*
+ * Note an OID when we find one for later processing when we know how
+ * to interpret it.
+ */
+int pkcs8_note_OID(void *context, size_t hdrlen,
+	     unsigned char tag,
+	     const void *value, size_t vlen)
+{
+	struct pkcs8_parse_context *ctx = context;
+
+	ctx->algo_oid = look_up_OID(value, vlen);
+	if (ctx->algo_oid == OID__NR) {
+		char buffer[50];
+		sprint_oid(value, vlen, buffer, sizeof(buffer));
+		pr_debug("Unknown OID: [%lu] %s\n",
+			 (unsigned long)value - ctx->data, buffer);
+	}
+	return 0;
+}
+
+/*
+ * Extract the data for the private key algorithm
+ */
+int pkcs8_extract_key_data(void *context, size_t hdrlen,
+		unsigned char tag,
+		const void *value, size_t vlen)
+{
+	struct pkcs8_parse_context *ctx = context;
+
+	if (ctx->algo_oid != OID_rsaEncryption)
+		return -ENOPKG;
+
+	ctx->info->privkey_algo = PKEY_ALGO_RSA;
+	ctx->key = value;
+	ctx->key_size = vlen;
+	return 0;
+}
+
+/*
+ * Extract a RSA private key value
+ */
+int rsa_priv_extract_mpi(void *context, size_t hdrlen,
+		    unsigned char tag,
+		    const void *value, size_t vlen)
+{
+	struct pkcs8_parse_context *ctx = context;
+	MPI mpi;
+
+	if (ctx->nr_mpi >= ARRAY_SIZE(ctx->info->priv->mpi)) {
+		/* does not grab exponent1, exponent2 and coefficient */
+		if (ctx->nr_mpi > 8) {
+			pr_err("Too many public key MPIs in pkcs1 private key\n");
+			return -EBADMSG;
+		} else {
+			ctx->nr_mpi++;
+			return 0;
+		}
+	}
+
+	mpi = mpi_read_raw_data(value, vlen);
+	if (!mpi)
+		return -ENOMEM;
+
+	ctx->info->priv->mpi[ctx->nr_mpi++] = mpi;
+	return 0;
+}
diff --git a/crypto/asymmetric_keys/pkcs8_parser.h b/crypto/asymmetric_keys/pkcs8_parser.h
new file mode 100644
index 0000000..7f5d801
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8_parser.h
@@ -0,0 +1,23 @@
+/* PKCS #8 parser internal definitions
+ *
+ * Copyright (C) 2013 SUSE Linux Products GmbH. All rights reserved.
+ * Written by Lee, Chun-Yi (jlee@suse.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <crypto/public_key.h>
+
+struct pkcs8_info {
+	enum pkey_algo privkey_algo:8;		/* Private key algorithm */
+	struct private_key *priv;		/* Private key */
+};
+
+/*
+ * pkcs8_parser.c
+ */
+extern void pkcs8_free_info(struct pkcs8_info *info);
+extern struct pkcs8_info *pkcs8_info_parse(const void *data, size_t datalen);
diff --git a/crypto/asymmetric_keys/pkcs8_private_key.c b/crypto/asymmetric_keys/pkcs8_private_key.c
new file mode 100644
index 0000000..cf2545b
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8_private_key.c
@@ -0,0 +1,148 @@
+/* Instantiate a private key crypto key
+ *
+ * Copyright (C) 2013 SUSE Linux Products GmbH. All rights reserved.
+ * Written by Chun-Yi Lee (jlee@suse.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "PKCS8: "fmt
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#include <crypto/hash.h>
+#include "private_key.h"
+#include "pkcs8-asn1.h"
+#include "pkcs8_parser.h"
+
+#define KEY_PREFIX "Private Key: "
+#define FINGERPRINT_HASH "sha256"
+
+static const
+struct private_key_algorithm *pkcs8_private_key_algorithms[PKEY_ALGO__LAST] = {
+	[PKEY_ALGO_DSA]         = NULL,
+#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
+	defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
+	[PKEY_ALGO_RSA]         = &RSA_private_key_algorithm,
+#endif
+};
+
+/*
+ * Attempt to parse a data blob for a private key.
+ */
+static int pkcs8_key_preparse(struct key_preparsed_payload *prep)
+{
+	struct pkcs8_info *info;
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	u8 *digest;
+	size_t digest_size, desc_size;
+	char *fingerprint, *description;
+	int i, ret;
+
+	pr_info("pkcs8_key_preparse start\n");
+
+	info = pkcs8_info_parse(prep->data, prep->datalen);
+	if (IS_ERR(info))
+		return PTR_ERR(info);
+
+	info->priv->algo = pkcs8_private_key_algorithms[info->privkey_algo];
+	info->priv->id_type = PKEY_ID_PKCS8;
+
+	/* Hash the pkcs #8 blob to generate fingerprint */
+	tfm = crypto_alloc_shash(FINGERPRINT_HASH, 0, 0);
+	if (IS_ERR(tfm)) {
+		ret = PTR_ERR(tfm);
+		goto error_shash;
+	}
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	digest_size = crypto_shash_digestsize(tfm);
+
+	ret = -ENOMEM;
+
+	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+	if (!digest)
+		goto error_digest;
+	desc = (void *) digest + digest_size;
+	desc->tfm = tfm;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	ret = crypto_shash_init(desc);
+	if (ret < 0)
+		goto error_shash_init;
+	ret = crypto_shash_finup(desc, prep->data, prep->datalen, digest);
+	if (ret < 0)
+		goto error_shash_finup;
+
+	fingerprint = kzalloc(digest_size * 2 + 1, GFP_KERNEL);
+	if (!fingerprint)
+		goto error_fingerprint;
+	for (i = 0; i < digest_size; i++)
+		sprintf(fingerprint + i * 2, "%02x", digest[i]);
+
+	/* Propose a description */
+	description = kzalloc(strlen(KEY_PREFIX) + strlen(fingerprint) + 1, GFP_KERNEL);
+	if (!description)
+		goto error_description;
+	sprintf(description, "%s", KEY_PREFIX);
+	memcpy(description + strlen(KEY_PREFIX), fingerprint, strlen(fingerprint));
+
+	/* We're pinning the module by being linked against it */
+	__module_get(private_key_subtype.owner);
+	prep->type_data[0] = &private_key_subtype;
+	prep->type_data[1] = fingerprint;
+	prep->payload = info->priv;
+	prep->description = description;
+
+	/* size of 4096 bits private key file is 2.3K */
+	prep->quotalen = 700;
+
+	pr_info("pkcs8_key_preparse done\n");
+
+	/* We've finished with the information */
+	kfree(digest);
+	crypto_free_shash(tfm);
+	info->priv = NULL;
+	pkcs8_free_info(info);
+
+	return 0;
+
+error_description:
+	kfree(fingerprint);
+error_fingerprint:
+error_shash_finup:
+error_shash_init:
+	kfree(digest);
+error_digest:
+	crypto_free_shash(tfm);
+error_shash:
+	info->priv = NULL;
+	pkcs8_free_info(info);
+	return ret;
+}
+
+static struct asymmetric_key_parser pkcs8_private_key_parser = {
+	.owner	= THIS_MODULE,
+	.name	= "pkcs8",
+	.parse	= pkcs8_key_preparse,
+};
+
+/*
+ * Module stuff
+ */
+static int __init pkcs8_private_key_init(void)
+{
+	return register_asymmetric_key_parser(&pkcs8_private_key_parser);
+}
+
+static void __exit pkcs8_private_key_exit(void)
+{
+	unregister_asymmetric_key_parser(&pkcs8_private_key_parser);
+}
+
+module_init(pkcs8_private_key_init);
+module_exit(pkcs8_private_key_exit);
diff --git a/crypto/asymmetric_keys/pkcs8_rsakey.asn1 b/crypto/asymmetric_keys/pkcs8_rsakey.asn1
new file mode 100644
index 0000000..d997c5e
--- /dev/null
+++ b/crypto/asymmetric_keys/pkcs8_rsakey.asn1
@@ -0,0 +1,29 @@
+--
+-- Representation of RSA private key with information.
+--
+
+RSAPrivateKey ::= SEQUENCE {
+	version			Version,
+	modulus                 INTEGER ({ rsa_priv_extract_mpi }),	-- n
+	publicExponent          INTEGER ({ rsa_priv_extract_mpi }),	-- e
+	privateExponent         INTEGER ({ rsa_priv_extract_mpi }),	-- d
+	prime1                  INTEGER ({ rsa_priv_extract_mpi }),	-- p
+	prime2                  INTEGER ({ rsa_priv_extract_mpi }),	-- q
+	exponent1               INTEGER ({ rsa_priv_extract_mpi }),	-- d mod (p-1)
+	exponent2               INTEGER ({ rsa_priv_extract_mpi }),	-- d mod (q-1)
+	coefficient             INTEGER ({ rsa_priv_extract_mpi })	-- (inverse of q) mod p
+	-- Doesn't support multi-prime
+	-- otherPrimeInfos         [ 0 ] OtherPrimeInfos OPTIONAL
+	}
+
+-- Version ::= INTEGER { two-prime(0), multi(1) }
+Version ::= INTEGER
+
+-- OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
+OtherPrimeInfos ::= SEQUENCE OF OtherPrimeInfo
+
+OtherPrimeInfo ::= SEQUENCE {
+    prime             INTEGER,  -- ri
+    exponent          INTEGER,  -- di
+    coefficient       INTEGER   -- ti
+}
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 97ff932..1636c4c 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -44,6 +44,7 @@ EXPORT_SYMBOL_GPL(pkey_hash_algo);
 const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
 	[PKEY_ID_PGP]		= "PGP",
 	[PKEY_ID_X509]		= "X509",
+	[PKEY_ID_PKCS8]         = "PKCS8",
 };
 EXPORT_SYMBOL_GPL(pkey_id_type);
 
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index 1cdf457..e51f294 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -41,6 +41,7 @@ extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
 enum pkey_id_type {
 	PKEY_ID_PGP,		/* OpenPGP generated key ID */
 	PKEY_ID_X509,		/* X.509 arbitrary subjectKeyIdentifier */
+	PKEY_ID_PKCS8,		/* PKCS #8 Private Key */
 	PKEY_ID_TYPE__LAST
 };
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 07/18] asymmetric keys: explicitly add the leading zero byte to encoded message
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (5 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 06/18] asymmetric keys: support parsing PKCS #8 private key information Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:13   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 08/18] Secure boot: Add new capability Lee, Chun-Yi
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Per PKCS1 spec, the EMSA-PKCS1-v1_5 encoded message is leading by 0x00 0x01 in
its first 2 bytes. The leading zero byte is suppressed by MPI so we pass a
pointer to the _preceding_ byte to RSA_verify() in original code, but it has
risk for the byte is not zero because it's not in EM buffer's scope, neither
RSA_verify() nor mpi_get_buffer() didn't take care the leading byte.

To avoid the risk, that's better we explicitly add the leading zero byte to EM
for pass to RSA_verify(). This patch allocate a _EM buffer to capture the
result from RSA_I2OSP(), then set the first byte to zero in EM and copy the
remaining bytes from _EM.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 crypto/asymmetric_keys/rsa.c |   14 ++++++++++----
 1 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c
index e60defe..1fadc7f 100644
--- a/crypto/asymmetric_keys/rsa.c
+++ b/crypto/asymmetric_keys/rsa.c
@@ -401,6 +401,7 @@ static int RSA_verify_signature(const struct public_key *key,
 	/* Variables as per RFC3447 sec 8.2.2 */
 	const u8 *H = sig->digest;
 	u8 *EM = NULL;
+	u8 *_EM = NULL;
 	MPI m = NULL;
 	size_t k;
 
@@ -435,14 +436,19 @@ static int RSA_verify_signature(const struct public_key *key,
 	/* (2c) Convert the message representative (m) to an encoded message
 	 *      (EM) of length k octets.
 	 *
-	 *      NOTE!  The leading zero byte is suppressed by MPI, so we pass a
-	 *      pointer to the _preceding_ byte to RSA_verify()!
+	 *      NOTE!  The leading zero byte is suppressed by MPI, so we add it
+	 *      back to EM before input to RSA_verify()!
 	 */
-	ret = RSA_I2OSP(m, k, &EM);
+	ret = RSA_I2OSP(m, k, &_EM);
 	if (ret < 0)
 		goto error;
 
-	ret = RSA_verify(H, EM - 1, k, sig->digest_size,
+	EM = kmalloc(k, GFP_KERNEL);
+	memset(EM, 0, 1);
+	memcpy(EM + 1, _EM, k-1);
+	kfree(_EM);
+
+	ret = RSA_verify(H, EM, k, sig->digest_size,
 			 RSA_ASN1_templates[sig->pkey_hash_algo].data,
 			 RSA_ASN1_templates[sig->pkey_hash_algo].size);
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 08/18] Secure boot: Add new capability
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (6 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 07/18] asymmetric keys: explicitly add the leading zero byte to encoded message Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:14   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 09/18] Secure boot: Add a dummy kernel parameter that will switch on Secure Boot mode Lee, Chun-Yi
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Matthew Garrett, Lee,
	Chun-Yi

From: Matthew Garrett <mjg@redhat.com>

Secure boot adds certain policy requirements, including that root must not
be able to do anything that could cause the kernel to execute arbitrary code.
The simplest way to handle this would seem to be to add a new capability
and gate various functionality on that. We'll then strip it from the initial
capability set if required.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Acked-by: Lee, Chun-Yi <jlee@suse.com>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 include/uapi/linux/capability.h |    6 +++++-
 1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
index ba478fa..7109e65 100644
--- a/include/uapi/linux/capability.h
+++ b/include/uapi/linux/capability.h
@@ -343,7 +343,11 @@ struct vfs_cap_data {
 
 #define CAP_BLOCK_SUSPEND    36
 
-#define CAP_LAST_CAP         CAP_BLOCK_SUSPEND
+/* Allow things that trivially permit root to modify the running kernel */
+
+#define CAP_COMPROMISE_KERNEL  37
+
+#define CAP_LAST_CAP         CAP_COMPROMISE_KERNEL
 
 #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 09/18] Secure boot: Add a dummy kernel parameter that will switch on Secure Boot mode
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (7 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 08/18] Secure boot: Add new capability Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:16   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware Lee, Chun-Yi
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

From: Josh Boyer <jwboyer@redhat.com>

This forcibly drops CAP_COMPROMISE_KERNEL from both cap_permitted and cap_bset
in the init_cred struct, which everything else inherits from.  This works on
any machine and can be used to develop even if the box doesn't have UEFI.

Signed-off-by: Josh Boyer <jwboyer@redhat.com>
Acked-by: Lee, Chun-Yi <jlee@suse.com>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 Documentation/kernel-parameters.txt |    7 +++++++
 kernel/cred.c                       |   17 +++++++++++++++++
 2 files changed, 24 insertions(+), 0 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 15356ac..6ad8292 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2784,6 +2784,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 			Note: increases power consumption, thus should only be
 			enabled if running jitter sensitive (HPC/RT) workloads.
 
+	secureboot_enable=
+			[KNL] Enables an emulated UEFI Secure Boot mode.  This
+			locks down various aspects of the kernel guarded by the
+			CAP_COMPROMISE_KERNEL capability.  This includes things
+			like /dev/mem, IO port access, and other areas.  It can
+			be used on non-UEFI machines for testing purposes.
+
 	security=	[SECURITY] Choose a security module to enable at boot.
 			If this boot parameter is not specified, only the first
 			security module asking for security registration will be
diff --git a/kernel/cred.c b/kernel/cred.c
index e0573a4..c3f4e3e 100644
--- a/kernel/cred.c
+++ b/kernel/cred.c
@@ -565,6 +565,23 @@ void __init cred_init(void)
 				     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 }
 
+void __init secureboot_enable()
+{
+	pr_info("Secure boot enabled\n");
+	cap_lower((&init_cred)->cap_bset, CAP_COMPROMISE_KERNEL);
+	cap_lower((&init_cred)->cap_permitted, CAP_COMPROMISE_KERNEL);
+}
+
+/* Dummy Secure Boot enable option to fake out UEFI SB=1 */
+static int __init secureboot_enable_opt(char *str)
+{
+	int sb_enable = !!simple_strtol(str, NULL, 0);
+	if (sb_enable)
+		secureboot_enable();
+	return 1;
+}
+__setup("secureboot_enable=", secureboot_enable_opt);
+
 /**
  * prepare_kernel_cred - Prepare a set of credentials for a kernel service
  * @daemon: A userspace daemon to be used as a reference
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (8 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 09/18] Secure boot: Add a dummy kernel parameter that will switch on Secure Boot mode Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:22   ` Pavel Machek
  2013-09-03 10:49   ` Matt Fleming
  2013-08-22 11:01 ` [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot Lee, Chun-Yi
                   ` (8 subsequent siblings)
  18 siblings, 2 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Matthew Garrett, Lee,
	Chun-Yi

From: Matthew Garrett <mjg@redhat.com>

The firmware has a set of flags that indicate whether secure boot is enabled
and enforcing. Use them to indicate whether the kernel should lock itself
down.  We also indicate the machine is in secure boot mode by adding the
EFI_SECURE_BOOT bit for use with efi_enabled.

Signed-off-by: Matthew Garrett <mjg@redhat.com>
Signed-off-by: Josh Boyer <jwboyer@redhat.com>
Acked-by: Lee, Chun-Yi <jlee@suse.com>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 Documentation/x86/zero-page.txt        |    2 ++
 arch/x86/boot/compressed/eboot.c       |   32 ++++++++++++++++++++++++++++++++
 arch/x86/include/asm/bootparam_utils.h |    8 ++++++--
 arch/x86/include/uapi/asm/bootparam.h  |    3 ++-
 arch/x86/kernel/setup.c                |    7 +++++++
 include/linux/cred.h                   |    2 ++
 include/linux/efi.h                    |    1 +
 7 files changed, 52 insertions(+), 3 deletions(-)

diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt
index 199f453..ff651d3 100644
--- a/Documentation/x86/zero-page.txt
+++ b/Documentation/x86/zero-page.txt
@@ -30,6 +30,8 @@ Offset	Proto	Name		Meaning
 1E9/001	ALL	eddbuf_entries	Number of entries in eddbuf (below)
 1EA/001	ALL	edd_mbr_sig_buf_entries	Number of entries in edd_mbr_sig_buffer
 				(below)
+1EB/001	ALL	kbd_status	Numlock is enabled
+1EC/001	ALL	secure_boot	Kernel should enable secure boot lockdowns
 1EF/001	ALL	sentinel	Used to detect broken bootloaders
 290/040	ALL	edd_mbr_sig_buffer EDD MBR signatures
 2D0/A00	ALL	e820_map	E820 memory map table
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index d606463..9baee3e 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -861,6 +861,36 @@ fail:
 	return status;
 }
 
+static int get_secure_boot(efi_system_table_t *_table)
+{
+	u8 sb, setup;
+	unsigned long datasize = sizeof(sb);
+	efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
+	efi_status_t status;
+
+	status = efi_call_phys5(sys_table->runtime->get_variable,
+				L"SecureBoot", &var_guid, NULL, &datasize, &sb);
+
+	if (status != EFI_SUCCESS)
+		return 0;
+
+	if (sb == 0)
+		return 0;
+
+
+	status = efi_call_phys5(sys_table->runtime->get_variable,
+				L"SetupMode", &var_guid, NULL, &datasize,
+				&setup);
+
+	if (status != EFI_SUCCESS)
+		return 0;
+
+	if (setup == 1)
+		return 0;
+
+	return 1;
+}
+
 /*
  * Because the x86 boot code expects to be passed a boot_params we
  * need to create one ourselves (usually the bootloader would create
@@ -1169,6 +1199,8 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
 	if (sys_table->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE)
 		goto fail;
 
+	boot_params->secure_boot = get_secure_boot(sys_table);
+
 	setup_graphics(boot_params);
 
 	setup_efi_pci(boot_params);
diff --git a/arch/x86/include/asm/bootparam_utils.h b/arch/x86/include/asm/bootparam_utils.h
index 653668d..69a6c08 100644
--- a/arch/x86/include/asm/bootparam_utils.h
+++ b/arch/x86/include/asm/bootparam_utils.h
@@ -38,9 +38,13 @@ static void sanitize_boot_params(struct boot_params *boot_params)
 		memset(&boot_params->olpc_ofw_header, 0,
 		       (char *)&boot_params->efi_info -
 			(char *)&boot_params->olpc_ofw_header);
-		memset(&boot_params->kbd_status, 0,
+		memset(&boot_params->kbd_status, 0, sizeof(boot_params->kbd_status));
+		/* don't clear boot_params->secure_boot.  we set that ourselves
+		 * earlier.
+		 */
+		memset(&boot_params->_pad5[0], 0,
 		       (char *)&boot_params->hdr -
-		       (char *)&boot_params->kbd_status);
+		       (char *)&boot_params->_pad5[0]);
 		memset(&boot_params->_pad7[0], 0,
 		       (char *)&boot_params->edd_mbr_sig_buffer[0] -
 			(char *)&boot_params->_pad7[0]);
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index c15ddaf..85d7685 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -131,7 +131,8 @@ struct boot_params {
 	__u8  eddbuf_entries;				/* 0x1e9 */
 	__u8  edd_mbr_sig_buf_entries;			/* 0x1ea */
 	__u8  kbd_status;				/* 0x1eb */
-	__u8  _pad5[3];					/* 0x1ec */
+	__u8  secure_boot;				/* 0x1ec */
+	__u8  _pad5[2];					/* 0x1ed */
 	/*
 	 * The sentinel is set to a nonzero value (0xff) in header.S.
 	 *
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f8ec578..2a8168a 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1129,6 +1129,13 @@ void __init setup_arch(char **cmdline_p)
 
 	io_delay_init();
 
+	if (boot_params.secure_boot) {
+#ifdef CONFIG_EFI
+		set_bit(EFI_SECURE_BOOT, &x86_efi_facility);
+#endif
+		secureboot_enable();
+	}
+
 	/*
 	 * Parse the ACPI tables for possible boot-time SMP configuration.
 	 */
diff --git a/include/linux/cred.h b/include/linux/cred.h
index 04421e8..9e69542 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -156,6 +156,8 @@ extern int set_security_override_from_ctx(struct cred *, const char *);
 extern int set_create_files_as(struct cred *, struct inode *);
 extern void __init cred_init(void);
 
+extern void secureboot_enable(void);
+
 /*
  * check for validity of credentials
  */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 5f8f176..febce85 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -634,6 +634,7 @@ extern int __init efi_setup_pcdp_console(char *);
 #define EFI_RUNTIME_SERVICES	3	/* Can we use runtime services? */
 #define EFI_MEMMAP		4	/* Can we use EFI memory map? */
 #define EFI_64BIT		5	/* Is the firmware 64-bit? */
+#define EFI_SECURE_BOOT	6	/* Are we in Secure Boot mode? */
 
 #ifdef CONFIG_EFI
 # ifdef CONFIG_X86
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (9 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:25   ` Pavel Machek
  2013-09-05  8:53   ` Matt Fleming
  2013-08-22 11:01 ` [PATCH 12/18] Hibernate: generate and " Lee, Chun-Yi
                   ` (7 subsequent siblings)
  18 siblings, 2 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi, Takashi Iwai

Introduced a hibernate_key.c file to query the key pair from EFI variables
and maintain key pair for check signature of S4 snapshot image. We
loaded the private key when snapshot image stored success.

This patch introduced 2 EFI variables for store the key to sign S4 image and
verify signature when S4 wake up. The names and GUID are:
  S4SignKey-fe141863-c070-478e-b8a3-878a5dc9ef21
  S4WakeKey-fe141863-c070-478e-b8a3-878a5dc9ef21

S4SignKey is used by EFI bootloader to pass the RSA private key that packaged
by PKCS#8 format, kernel will read and parser it when system boot and reload
it when S4 resume. EFI bootloader need gnerate a new private key when every
time system boot.

S4WakeKey is used to pass the RSA public key that packaged by X.509
certificate, kernel will read and parser it for check the signature of
S4 snapshot image when S4 resume.

The follow-up patch will remove S4SignKey and S4WakeKey after load them
to kernel for avoid anyone can access it through efivarfs.

v3:
- Load S4 sign key before ExitBootServices.
  Load private key before ExitBootServices() then bootloader doesn't need
  generate key-pair for each booting:
   + Add setup_s4_keys() to eboot.c to load S4 sign key before ExitBootServices.
   + Reserve the memory block of sign key data blob in efi.c
- In Makefile, moved hibernate_keys.o before hibernate.o for load S4 sign
  key before check hibernate image. It makes sure the new sign key will be
  transfer to resume target kernel.
- Set "depends on EFI_STUB" in Kconfig

v2:
Add CONFIG_SNAPSHOT_VERIFICATION for build of hibernate_keys.c depend on
Kconfig.

Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 arch/x86/boot/compressed/eboot.c      |   89 ++++++++++
 arch/x86/include/asm/efi.h            |    9 +
 arch/x86/include/uapi/asm/bootparam.h |    1 +
 arch/x86/platform/efi/efi.c           |   68 ++++++++
 include/linux/efi.h                   |   17 ++
 kernel/power/Kconfig                  |   16 ++-
 kernel/power/Makefile                 |    1 +
 kernel/power/hibernate.c              |    3 +
 kernel/power/hibernate_keys.c         |  290 +++++++++++++++++++++++++++++++++
 kernel/power/power.h                  |   27 +++
 10 files changed, 519 insertions(+), 2 deletions(-)
 create mode 100644 kernel/power/hibernate_keys.c

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 9baee3e..855bda4 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -368,6 +368,91 @@ free_handle:
 	return status;
 }
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+static efi_status_t setup_s4_keys(struct boot_params *params)
+{
+	struct setup_data *data;
+	unsigned long datasize;
+	u32 attr;
+	struct efi_s4_key *s4key;
+	efi_status_t status;
+
+	data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
+
+	while (data && data->next)
+		data = (struct setup_data *)(unsigned long)data->next;
+
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA, sizeof(*s4key), &s4key);
+	if (status != EFI_SUCCESS) {
+		efi_printk("Failed to alloc memory for efi_s4_key\n");
+		goto error_setup;
+	}
+
+	s4key->data.type = SETUP_S4_KEY;
+	s4key->data.len = sizeof(struct efi_s4_key) -
+		sizeof(struct setup_data);
+	s4key->data.next = 0;
+	s4key->skey_dsize = 0;
+	s4key->err_status = 0;
+
+	if (data)
+		data->next = (unsigned long)s4key;
+	else
+		params->hdr.setup_data = (unsigned long)s4key;
+
+	/* obtain the size of key data */
+	datasize = 0;
+	status = efi_call_phys5(sys_table->runtime->get_variable,
+				EFI_S4_SIGN_KEY_NAME, &EFI_HIBERNATE_GUID,
+				NULL, &datasize, NULL);
+	if (status != EFI_BUFFER_TOO_SMALL) {
+		efi_printk("Couldn't get S4 key data size\n");
+		goto error_size;
+	}
+	if (datasize > PAGE_SIZE - sizeof(datasize)) {
+		efi_printk("The size of S4 sign key is too large\n");
+		status = EFI_UNSUPPORTED;
+		goto error_size;
+	}
+
+	s4key->skey_dsize = datasize;
+	status = efi_call_phys3(sys_table->boottime->allocate_pool,
+				EFI_LOADER_DATA, s4key->skey_dsize,
+				&s4key->skey_data_addr);
+	if (status != EFI_SUCCESS) {
+		efi_printk("Failed to alloc page for S4 key data\n");
+		goto error_s4key;
+	}
+
+	attr = 0;
+	memset((void *)s4key->skey_data_addr, 0, s4key->skey_dsize);
+	status = efi_call_phys5(sys_table->runtime->get_variable,
+				EFI_S4_SIGN_KEY_NAME, &EFI_HIBERNATE_GUID, &attr,
+				&(s4key->skey_dsize), s4key->skey_data_addr);
+	if (status) {
+		efi_printk("Couldn't get S4 key data\n");
+		goto error_gets4key;
+	}
+	if (attr & EFI_VARIABLE_RUNTIME_ACCESS) {
+		efi_printk("S4 sign key can not be a runtime variable\n");
+		memset((void *)s4key->skey_data_addr, 0, s4key->skey_dsize);
+		status = EFI_UNSUPPORTED;
+		goto error_gets4key;
+	}
+
+	return 0;
+
+error_gets4key:
+	efi_call_phys1(sys_table->boottime->free_pool, s4key->skey_data_addr);
+error_s4key:
+error_size:
+	s4key->err_status = status;
+error_setup:
+	return status;
+}
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
+
 /*
  * See if we have Graphics Output Protocol
  */
@@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
 
 	setup_efi_pci(boot_params);
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	setup_s4_keys(boot_params);
+#endif
+
 	status = efi_call_phys3(sys_table->boottime->allocate_pool,
 				EFI_LOADER_DATA, sizeof(*gdt),
 				(void **)&gdt);
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 0062a01..56ececa 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -102,6 +102,15 @@ extern void efi_call_phys_epilog(void);
 extern void efi_unmap_memmap(void);
 extern void efi_memory_uc(u64 addr, unsigned long size);
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+struct efi_s4_key {
+	struct setup_data data;
+	unsigned long err_status;
+	unsigned long skey_dsize;
+	void *skey_data_addr;
+};
+#endif
+
 #ifdef CONFIG_EFI
 
 static inline bool efi_is_native(void)
diff --git a/arch/x86/include/uapi/asm/bootparam.h b/arch/x86/include/uapi/asm/bootparam.h
index 85d7685..79398ff 100644
--- a/arch/x86/include/uapi/asm/bootparam.h
+++ b/arch/x86/include/uapi/asm/bootparam.h
@@ -6,6 +6,7 @@
 #define SETUP_E820_EXT			1
 #define SETUP_DTB			2
 #define SETUP_PCI			3
+#define SETUP_S4_KEY			4
 
 /* ram_size flags */
 #define RAMDISK_IMAGE_START_MASK	0x07FF
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 90f6ed1..c8a4fca 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -704,6 +704,69 @@ static int __init efi_memmap_init(void)
 	return 0;
 }
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+static unsigned long skey_dsize;
+static u64 skey_data_addr;
+static unsigned long skey_err_status;
+
+bool efi_s4_key_available(void)
+{
+	return skey_dsize && skey_data_addr && !skey_err_status;
+}
+
+unsigned long __init efi_copy_skey_data(void *page_addr)
+{
+	void *key_addr;
+
+	if (efi_s4_key_available()) {
+		key_addr = early_ioremap(skey_data_addr, skey_dsize);
+		memcpy(page_addr, key_addr, skey_dsize);
+		early_iounmap(key_addr, skey_dsize);
+	}
+
+	return skey_dsize;
+}
+
+void __init efi_erase_s4_skey_data(void)
+{
+	void *key_addr;
+
+	key_addr = early_ioremap(skey_data_addr, skey_dsize);
+	memset(key_addr, 0, skey_dsize);
+	early_iounmap(key_addr, skey_dsize);
+	memblock_free(skey_data_addr, skey_dsize);
+	skey_data_addr = 0;
+	skey_dsize = 0;
+}
+
+static void __init efi_reserve_s4_skey_data(void)
+{
+	u64 pa_data;
+	struct setup_data *data;
+	struct efi_s4_key *s4key;
+
+	skey_err_status = 0;
+	pa_data = boot_params.hdr.setup_data;
+	while (pa_data) {
+		data = early_ioremap(pa_data, sizeof(*s4key));
+		if (data->type == SETUP_S4_KEY) {
+			s4key = (struct efi_s4_key *)data;
+			if (!s4key->err_status) {
+				skey_dsize = s4key->skey_dsize;
+				skey_data_addr = (u64) s4key->skey_data_addr;
+				memblock_reserve(skey_data_addr, skey_dsize);
+			} else {
+				skey_err_status = s4key->err_status;
+				pr_err("Get S4 sign key from EFI fail: 0x%lx\n",
+					skey_err_status);
+			}
+		}
+		pa_data = data->next;
+		early_iounmap(data, sizeof(*s4key));
+	}
+}
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
+
 void __init efi_init(void)
 {
 	efi_char16_t *c16;
@@ -729,6 +792,11 @@ void __init efi_init(void)
 
 	set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	/* keep s4 key from setup_data */
+	efi_reserve_s4_skey_data();
+#endif
+
 	/*
 	 * Show what we know for posterity
 	 */
diff --git a/include/linux/efi.h b/include/linux/efi.h
index febce85..55f80be 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -389,6 +389,18 @@ typedef efi_status_t efi_query_variable_store_t(u32 attributes, unsigned long si
 #define EFI_FILE_SYSTEM_GUID \
     EFI_GUID(  0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+#define EFI_HIBERNATE_GUID \
+    EFI_GUID(0xfe141863, 0xc070, 0x478e, 0xb8, 0xa3, 0x87, 0x8a, 0x5d, 0xc9, 0xef, 0x21)
+/*
+ * The UEFI variable names of the key-pair to verify S4 snapshot image:
+ * S4SignKey-EFI_HIBERNATE_GUID: The private key is used to sign snapshot
+ * S4WakeKey-EFI_HIBERNATE_GUID: The public key is used to verify snapshot
+ */
+#define EFI_S4_SIGN_KEY_NAME    ((efi_char16_t [10]) { 'S', '4', 'S', 'i', 'g', 'n', 'K', 'e', 'y', 0 })
+#define EFI_S4_WAKE_KEY_NAME    ((efi_char16_t [10]) { 'S', '4', 'W', 'a', 'k', 'e', 'K', 'e', 'y', 0 })
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
+
 typedef struct {
 	efi_guid_t guid;
 	u64 table;
@@ -577,6 +589,11 @@ extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if pos
 extern void efi_late_init(void);
 extern void efi_free_boot_services(void);
 extern efi_status_t efi_query_variable_store(u32 attributes, unsigned long size);
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+extern bool efi_s4_key_available(void);
+extern unsigned long efi_copy_skey_data(void *page_addr);
+extern void efi_erase_s4_skey_data(void);
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
 #else
 static inline void efi_late_init(void) {}
 static inline void efi_free_boot_services(void) {}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index d444c4e..b592d88 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -66,8 +66,17 @@ config HIBERNATION
 
 	  For more information take a look at <file:Documentation/power/swsusp.txt>.
 
-config ARCH_SAVE_PAGE_KEYS
-	bool
+config SNAPSHOT_VERIFICATION
+	bool "Hibernate snapshot verification"
+	depends on HIBERNATION
+	depends on EFI_STUB
+	depends on X86
+	select PKCS8_PRIVATE_KEY_INFO_PARSER
+	help
+	  This option provides support for generate anad verify the signautre by
+	  RSA key-pair against hibernate snapshot image. Current mechanism
+	  dependent on UEFI environment. EFI bootloader should generate the
+	  key-pair.
 
 config PM_STD_PARTITION
 	string "Default resume partition"
@@ -91,6 +100,9 @@ config PM_STD_PARTITION
 	  suspended image to. It will simply pick the first available swap 
 	  device.
 
+config ARCH_SAVE_PAGE_KEYS
+	bool
+
 config PM_SLEEP
 	def_bool y
 	depends on SUSPEND || HIBERNATE_CALLBACKS
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 29472bf..46b6422 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_VT_CONSOLE_SLEEP)	+= console.o
 obj-$(CONFIG_FREEZER)		+= process.o
 obj-$(CONFIG_SUSPEND)		+= suspend.o
 obj-$(CONFIG_PM_TEST_SUSPEND)	+= suspend_test.o
+obj-$(CONFIG_SNAPSHOT_VERIFICATION)    += hibernate_keys.o
 obj-$(CONFIG_HIBERNATION)	+= hibernate.o snapshot.o swap.o user.o \
 				   block_io.o
 obj-$(CONFIG_PM_AUTOSLEEP)	+= autosleep.o
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index b26f5f1..c545b15 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -28,6 +28,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/ctype.h>
 #include <linux/genhd.h>
+#include <linux/key.h>
 
 #include "power.h"
 
@@ -631,6 +632,7 @@ static void power_down(void)
 int hibernate(void)
 {
 	int error;
+	int skey_error;
 
 	lock_system_sleep();
 	/* The snapshot device should not be opened while we're running */
@@ -680,6 +682,7 @@ int hibernate(void)
 		pm_restore_gfp_mask();
 	} else {
 		pr_debug("PM: Image restored successfully.\n");
+		restore_sign_key_data();
 	}
 
  Thaw:
diff --git a/kernel/power/hibernate_keys.c b/kernel/power/hibernate_keys.c
new file mode 100644
index 0000000..1bc5976
--- /dev/null
+++ b/kernel/power/hibernate_keys.c
@@ -0,0 +1,290 @@
+#include <linux/sched.h>
+#include <linux/efi.h>
+#include <linux/mpi.h>
+#include <linux/asn1.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
+
+#include "power.h"
+
+static void *skey_data;
+static void *skey_data_buf;
+static unsigned long skey_dsize;
+
+static int efi_status_to_err(efi_status_t status)
+{
+	int err;
+
+	switch (status) {
+	case EFI_INVALID_PARAMETER:
+		err = -EINVAL;
+		break;
+	case EFI_OUT_OF_RESOURCES:
+		err = -ENOSPC;
+		break;
+	case EFI_DEVICE_ERROR:
+		err = -EIO;
+		break;
+	case EFI_WRITE_PROTECTED:
+		err = -EROFS;
+		break;
+	case EFI_SECURITY_VIOLATION:
+		err = -EACCES;
+		break;
+	case EFI_NOT_FOUND:
+		err = -ENODATA;
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	return err;
+}
+
+bool swsusp_page_is_sign_key(struct page *page)
+{
+	unsigned long skey_data_pfn;
+	bool ret;
+
+	if (!skey_data || IS_ERR(skey_data))
+		return false;
+
+	skey_data_pfn = page_to_pfn(virt_to_page(skey_data));
+	ret = (page_to_pfn(page) == skey_data_pfn) ? true : false;
+	if (ret)
+		pr_info("PM: Avoid snapshot the page of S4 sign key.\n");
+
+	return ret;
+}
+
+unsigned long get_skey_data_buf_pfn(void)
+{
+	if (!skey_data_buf || IS_ERR(skey_data_buf))
+		return 0;
+
+	return page_to_pfn(virt_to_page(skey_data_buf));
+}
+
+void clone_skey_data(void *page)
+{
+	if (!page)
+		return;
+
+	if (skey_data && !IS_ERR(skey_data)) {
+		memcpy(page, &skey_dsize, sizeof(skey_dsize));
+		memcpy(page + sizeof(skey_dsize), skey_data, PAGE_SIZE - sizeof(skey_dsize));
+	}
+}
+
+void restore_sign_key_data(void)
+{
+	memset(skey_data, 0, PAGE_SIZE);
+	if (skey_data_buf && !IS_ERR(skey_data_buf)) {
+		/* restore sign key size and data from buffer */
+		memcpy(&skey_dsize, skey_data_buf, sizeof(skey_dsize));
+		memcpy(skey_data, skey_data_buf + sizeof(skey_dsize),
+				PAGE_SIZE - sizeof(skey_dsize));
+		/* reset skey page buffer */
+		memset(skey_data_buf, 0, PAGE_SIZE);
+		pr_info("PM: Restore S4 sign key from buffer\n");
+	} else
+		pr_err("PM: Restore S4 sign key fail\n");
+}
+
+bool skey_data_available(void)
+{
+	static unsigned char const_seq = (ASN1_SEQ | (ASN1_CONS << 5));
+	bool ret = false;
+
+	/* Sign key is PKCS#8 format that must be a Constructed SEQUENCE */
+	ret = skey_data && !IS_ERR(skey_data) &&
+		(skey_dsize != 0) &&
+		((unsigned char *)skey_data)[0] == const_seq;
+
+	return ret;
+}
+
+struct key *get_sign_key(void)
+{
+	const struct cred *cred = current_cred();
+	struct key *skey;
+	int err;
+
+	if (!skey_data || IS_ERR(skey_data))
+		return ERR_PTR(-EBADMSG);
+
+	skey = key_alloc(&key_type_asymmetric, "s4_sign_key",
+			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+			cred, 0, KEY_ALLOC_NOT_IN_QUOTA);
+	if (IS_ERR(skey)) {
+		pr_err("PM: Allocate s4 sign key error: %ld\n", PTR_ERR(skey));
+		goto error_keyalloc;
+	}
+
+	err = key_instantiate_and_link(skey, skey_data, skey_dsize, NULL, NULL);
+	if (err < 0) {
+		pr_err("PM: S4 sign key instantiate error: %d\n", err);
+		if (skey)
+			key_put(skey);
+		skey = ERR_PTR(err);
+		goto error_keyinit;
+	}
+
+	return skey;
+
+error_keyinit:
+error_keyalloc:
+	return skey;
+}
+
+void erase_skey_data(void)
+{
+	if (!skey_data || IS_ERR(skey_data))
+		return;
+
+	memset(skey_data, 0, PAGE_SIZE);
+}
+
+void destroy_sign_key(struct key *skey)
+{
+	erase_skey_data();
+	if (skey)
+		key_put(skey);
+}
+
+static void *load_wake_key_data(unsigned long *datasize)
+{
+	u32 attr;
+	void *wkey_data;
+	efi_status_t status;
+
+	if (!efi_enabled(EFI_RUNTIME_SERVICES))
+		return ERR_PTR(-EPERM);
+
+	/* obtain the size */
+	*datasize = 0;
+	status = efi.get_variable(EFI_S4_WAKE_KEY_NAME, &EFI_HIBERNATE_GUID,
+				  NULL, datasize, NULL);
+	if (status != EFI_BUFFER_TOO_SMALL) {
+		wkey_data = ERR_PTR(efi_status_to_err(status));
+		pr_err("PM: Couldn't get wake key data size: 0x%lx\n", status);
+		goto error;
+	}
+
+	/* check attributes */
+	wkey_data = kzalloc(*datasize, GFP_KERNEL);
+	if (!wkey_data) {
+		wkey_data = ERR_PTR(-ENOMEM);
+		goto error;
+	}
+
+	status = efi.get_variable(EFI_S4_WAKE_KEY_NAME, &EFI_HIBERNATE_GUID,
+				&attr, datasize, wkey_data);
+	if (status) {
+		kfree(wkey_data);
+		*datasize = 0;
+		wkey_data = ERR_PTR(efi_status_to_err(status));
+		pr_err("PM: Get wake key data error: 0x%lx\n", status);
+		goto error;
+	}
+	if (attr & EFI_VARIABLE_NON_VOLATILE) {
+		memset(wkey_data, 0, *datasize);
+		kfree(wkey_data);
+		*datasize = 0;
+		wkey_data = ERR_PTR(-EBADMSG);
+		pr_err("PM: Wake key has wrong attributes: 0x%x\n", attr);
+		goto error;
+	}
+
+error:
+	return wkey_data;
+}
+
+bool wkey_data_available(void)
+{
+	static int ret = 1;
+	unsigned long datasize;
+	void *wkey_data;
+
+	if (ret > 0) {
+		wkey_data = load_wake_key_data(&datasize);
+		if (wkey_data && IS_ERR(wkey_data)) {
+			ret = PTR_ERR(wkey_data);
+			goto error;
+		} else {
+			if (wkey_data) {
+				memset(wkey_data, 0, datasize);
+				kfree(wkey_data);
+			}
+			ret = 0;
+		}
+	}
+
+error:
+	return !ret;
+}
+
+struct key *get_wake_key(void)
+{
+	const struct cred *cred = current_cred();
+	void *wkey_data;
+	unsigned long datasize = 0;
+	struct key *wkey;
+	int err;
+
+	wkey_data = load_wake_key_data(&datasize);
+	if (IS_ERR(wkey_data)) {
+		wkey = (struct key *)wkey_data;
+		goto error_data;
+	}
+
+	wkey = key_alloc(&key_type_asymmetric, "s4_wake_key",
+			GLOBAL_ROOT_UID, GLOBAL_ROOT_GID,
+			cred, 0, KEY_ALLOC_NOT_IN_QUOTA);
+	if (IS_ERR(wkey)) {
+		pr_err("PM: Allocate s4 wake key error: %ld\n", PTR_ERR(wkey));
+		goto error_keyalloc;
+	}
+	err = key_instantiate_and_link(wkey, wkey_data, datasize, NULL, NULL);
+	if (err < 0) {
+		pr_err("PM: S4 wake key instantiate error: %d\n", err);
+		if (wkey)
+			key_put(wkey);
+		wkey = ERR_PTR(err);
+	}
+
+error_keyalloc:
+	if (wkey_data && !IS_ERR(wkey_data))
+		kfree(wkey_data);
+error_data:
+	return wkey;
+}
+
+size_t get_key_length(const struct key *key)
+{
+	const struct public_key *pk = key->payload.data;
+	size_t len;
+
+	/* TODO: better check the RSA type */
+
+	len = mpi_get_nbits(pk->rsa.n);
+	len = (len + 7) / 8;
+
+	return len;
+}
+
+static int __init init_sign_key_data(void)
+{
+	skey_data = (void *)get_zeroed_page(GFP_KERNEL);
+	skey_data_buf = (void *)get_zeroed_page(GFP_KERNEL);
+
+	if (skey_data && efi_s4_key_available()) {
+		skey_dsize = efi_copy_skey_data(skey_data);
+		efi_erase_s4_skey_data();
+		pr_info("PM: Load s4 sign key from EFI\n");
+	}
+
+	return 0;
+}
+
+late_initcall(init_sign_key_data);
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 7d4b7ff..69a81d8 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -160,6 +160,33 @@ extern void swsusp_close(fmode_t);
 extern int swsusp_unmark(void);
 #endif
 
+/* kernel/power/hibernate_key.c */
+extern bool skey_data_available(void);
+extern struct key *get_sign_key(void);
+extern void erase_skey_data(void);
+extern void snapshot_fill_s4_skey(void);
+extern void destroy_sign_key(struct key *key);
+extern bool wkey_data_available(void);
+extern struct key *get_wake_key(void);
+extern size_t get_key_length(const struct key *key);
+
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+extern void restore_sign_key_data(void);
+extern bool swsusp_page_is_sign_key(struct page *page);
+extern unsigned long get_skey_data_buf_pfn(void);
+extern void clone_skey_data(void *page_addr);
+#else /* !CONFIG_SUSPEND */
+static inline void restore_sign_key_data(void) {}
+static inline bool swsusp_page_is_sign_key(struct page *page)
+{
+	return false;
+}
+static inline unsigned long get_skey_data_buf_pfn(void)
+{
+	return 0;
+}
+#endif /* !CONFIG_SNAPSHOT_VERIFICATION */
+
 /* kernel/power/block_io.c */
 extern struct block_device *hib_resume_bdev;
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 12/18] Hibernate: generate and verify signature of snapshot
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (10 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:36   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image Lee, Chun-Yi
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

This patch add the code for generate/verify signature of snapshot, it
put the signature to snapshot header. This approach can support both
on userspace hibernate and in-kernel hibernate.

v2:
- Due to loaded S4 sign key before ExitBootServices, we need forward key from
  boot kernel to resume target kernel. So this patch add a empty page in
  snapshot image, then we keep the pfn of this empty page in snapshot header.
  When system resume from hibernate, we fill new sign key to this empty page
  space after snapshot image checked pass. This mechanism let boot kernel can
  forward new sign key to resume target kernel but don't need write new private
  key to any other storage, e.g. swap.

Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/power.h    |    6 +
 kernel/power/snapshot.c |  280 +++++++++++++++++++++++++++++++++++++++++++++-
 kernel/power/swap.c     |   14 +++
 kernel/power/user.c     |    9 ++
 4 files changed, 302 insertions(+), 7 deletions(-)

diff --git a/kernel/power/power.h b/kernel/power/power.h
index 69a81d8..84e0b06 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -3,6 +3,9 @@
 #include <linux/utsname.h>
 #include <linux/freezer.h>
 
+/* The maximum length of snapshot signature */
+#define SIG_LENG 512
+
 struct swsusp_info {
 	struct new_utsname	uts;
 	u32			version_code;
@@ -11,6 +14,8 @@ struct swsusp_info {
 	unsigned long		image_pages;
 	unsigned long		pages;
 	unsigned long		size;
+	unsigned long           skey_data_buf_pfn;
+	u8			signature[SIG_LENG];
 } __attribute__((aligned(PAGE_SIZE)));
 
 #ifdef CONFIG_HIBERNATION
@@ -134,6 +139,7 @@ extern int snapshot_read_next(struct snapshot_handle *handle);
 extern int snapshot_write_next(struct snapshot_handle *handle);
 extern void snapshot_write_finalize(struct snapshot_handle *handle);
 extern int snapshot_image_loaded(struct snapshot_handle *handle);
+extern int snapshot_image_verify(void);
 
 /* If unset, the snapshot device cannot be open. */
 extern atomic_t snapshot_device_available;
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 349587b..72e2911 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -27,6 +27,9 @@
 #include <linux/highmem.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <crypto/hash.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1031,11 +1034,49 @@ static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
 }
 #endif /* CONFIG_HIGHMEM */
 
-static void
+#define SNAPSHOT_HASH "sha256"
+
+/*
+ * Signature of snapshot for check.
+ */
+static u8 signature[SIG_LENG];
+
+static int
 copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 {
 	struct zone *zone;
-	unsigned long pfn;
+	unsigned long pfn, dst_pfn;
+	struct page *d_page;
+	void *hash_buffer = NULL;
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	u8 *digest;
+	size_t digest_size, desc_size;
+	struct key *s4_sign_key;
+	struct public_key_signature *pks;
+	int ret;
+
+	ret = -ENOMEM;
+	tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
+	if (IS_ERR(tfm)) {
+		pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	digest_size = crypto_shash_digestsize(tfm);
+	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+	if (!digest) {
+		pr_err("digest allocate fail");
+		ret = -ENOMEM;
+		goto error_digest;
+	}
+	desc = (void *) digest + digest_size;
+	desc->tfm = tfm;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	ret = crypto_shash_init(desc);
+	if (ret < 0)
+		goto error_shash;
 
 	for_each_populated_zone(zone) {
 		unsigned long max_zone_pfn;
@@ -1052,8 +1093,65 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 		pfn = memory_bm_next_pfn(orig_bm);
 		if (unlikely(pfn == BM_END_OF_MAP))
 			break;
-		copy_data_page(memory_bm_next_pfn(copy_bm), pfn);
+		dst_pfn = memory_bm_next_pfn(copy_bm);
+		copy_data_page(dst_pfn, pfn);
+
+		/* Generate digest */
+		d_page = pfn_to_page(dst_pfn);
+		if (PageHighMem(d_page)) {
+			void *kaddr;
+			kaddr = kmap_atomic(d_page);
+			copy_page(buffer, kaddr);
+			kunmap_atomic(kaddr);
+			hash_buffer = buffer;
+		} else {
+			hash_buffer = page_address(d_page);
+		}
+		ret = crypto_shash_update(desc, hash_buffer, PAGE_SIZE);
+		if (ret)
+			goto error_shash;
+	}
+
+	crypto_shash_final(desc, digest);
+	if (ret)
+		goto error_shash;
+
+	/* Generate signature by private key */
+	s4_sign_key = get_sign_key();
+	if (!s4_sign_key || IS_ERR(s4_sign_key)) {
+		pr_err("Get S4 sign key fail: %ld\n", PTR_ERR(s4_sign_key));
+		ret = PTR_ERR(s4_sign_key);
+		goto error_key;
 	}
+
+	pks = generate_signature(s4_sign_key, digest, PKEY_HASH_SHA256, false);
+	if (IS_ERR(pks)) {
+		pr_err("Generate signature fail: %lx", PTR_ERR(pks));
+		ret = PTR_ERR(pks);
+		goto error_sign;
+	} else
+		memcpy(signature, pks->S, pks->k);
+
+	destroy_sign_key(s4_sign_key);
+
+	if (pks && pks->digest)
+		kfree(pks->digest);
+	if (pks && pks->rsa.s)
+		mpi_free(pks->rsa.s);
+	kfree(pks);
+	kfree(digest);
+	crypto_free_shash(tfm);
+
+	return 0;
+
+error_sign:
+	destroy_sign_key(s4_sign_key);
+error_key:
+error_shash:
+	kfree(digest);
+error_digest:
+	crypto_free_shash(tfm);
+	return ret;
 }
 
 /* Total number of image pages */
@@ -1080,6 +1178,14 @@ static struct memory_bitmap orig_bm;
  */
 static struct memory_bitmap copy_bm;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+/*
+ * Keep the pfn of S4 sign key buffer from resume target. We write the next time
+ * sign key to this page in snapshot image before restore.
+ */
+unsigned long skey_data_buf_pfn;
+#endif
+
 /**
  *	swsusp_free - free pages allocated for the suspend.
  *
@@ -1580,6 +1686,7 @@ swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
 asmlinkage int swsusp_save(void)
 {
 	unsigned int nr_pages, nr_highmem;
+	int ret;
 
 	printk(KERN_INFO "PM: Creating hibernation image:\n");
 
@@ -1602,7 +1709,9 @@ asmlinkage int swsusp_save(void)
 	 * Kill them.
 	 */
 	drain_local_pages(NULL);
-	copy_data_pages(&copy_bm, &orig_bm);
+	ret = copy_data_pages(&copy_bm, &orig_bm);
+	if (ret)
+		return ret;
 
 	/*
 	 * End of critical section. From now on, we can write to memory,
@@ -1657,6 +1766,10 @@ static int init_header(struct swsusp_info *info)
 	info->pages = snapshot_get_image_size();
 	info->size = info->pages;
 	info->size <<= PAGE_SHIFT;
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	info->skey_data_buf_pfn = get_skey_data_buf_pfn();
+	memcpy(info->signature, signature, SIG_LENG);
+#endif
 	return init_header_complete(info);
 }
 
@@ -1819,6 +1932,10 @@ load_header(struct swsusp_info *info)
 	if (!error) {
 		nr_copy_pages = info->image_pages;
 		nr_meta_pages = info->pages - info->image_pages - 1;
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+		skey_data_buf_pfn = info->skey_data_buf_pfn;
+		memcpy(signature, info->signature, SIG_LENG);
+#endif
 	}
 	return error;
 }
@@ -2159,7 +2276,8 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
  *	set for its caller to write to.
  */
 
-static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
+static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca,
+		unsigned long *_pfn)
 {
 	struct pbe *pbe;
 	struct page *page;
@@ -2168,6 +2286,9 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
 	if (pfn == BM_END_OF_MAP)
 		return ERR_PTR(-EFAULT);
 
+	if (_pfn)
+		*_pfn = pfn;
+
 	page = pfn_to_page(pfn);
 	if (PageHighMem(page))
 		return get_highmem_page_buffer(page, ca);
@@ -2194,6 +2315,9 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
 	return pbe->address;
 }
 
+void **h_buf;
+void *skey_snapshot_buf;
+
 /**
  *	snapshot_write_next - used for writing the system memory snapshot.
  *
@@ -2214,6 +2338,7 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
 int snapshot_write_next(struct snapshot_handle *handle)
 {
 	static struct chain_allocator ca;
+	unsigned long pfn;
 	int error = 0;
 
 	/* Check if we have already loaded the entire image */
@@ -2236,6 +2361,13 @@ int snapshot_write_next(struct snapshot_handle *handle)
 		if (error)
 			return error;
 
+		/* Allocate void * array to keep buffer point for generate hash,
+		 * h_buf will freed in snapshot_image_verify().
+		 */
+		h_buf = kmalloc(sizeof(void *) * nr_copy_pages, GFP_KERNEL);
+		if (!h_buf)
+			pr_err("Allocate hash buffer fail!");
+
 		error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
 		if (error)
 			return error;
@@ -2258,20 +2390,27 @@ int snapshot_write_next(struct snapshot_handle *handle)
 			chain_init(&ca, GFP_ATOMIC, PG_SAFE);
 			memory_bm_position_reset(&orig_bm);
 			restore_pblist = NULL;
-			handle->buffer = get_buffer(&orig_bm, &ca);
+			handle->buffer = get_buffer(&orig_bm, &ca, &pfn);
 			handle->sync_read = 0;
 			if (IS_ERR(handle->buffer))
 				return PTR_ERR(handle->buffer);
+			if (h_buf)
+				*h_buf = handle->buffer;
 		}
 	} else {
 		copy_last_highmem_page();
 		/* Restore page key for data page (s390 only). */
 		page_key_write(handle->buffer);
-		handle->buffer = get_buffer(&orig_bm, &ca);
+		handle->buffer = get_buffer(&orig_bm, &ca, &pfn);
 		if (IS_ERR(handle->buffer))
 			return PTR_ERR(handle->buffer);
 		if (handle->buffer != buffer)
 			handle->sync_read = 0;
+		if (h_buf)
+			*(h_buf + (handle->cur - nr_meta_pages - 1)) = handle->buffer;
+		/* Keep the buffer of sign key in snapshot */
+		if (pfn == skey_data_buf_pfn)
+			skey_snapshot_buf = handle->buffer;
 	}
 	handle->cur++;
 	return PAGE_SIZE;
@@ -2304,6 +2443,133 @@ int snapshot_image_loaded(struct snapshot_handle *handle)
 			handle->cur <= nr_meta_pages + nr_copy_pages);
 }
 
+int snapshot_verify_signature(u8 *digest, size_t digest_size)
+{
+	struct key *s4_wake_key;
+	struct public_key_signature *pks;
+	int ret;
+	MPI mpi;
+
+	/* load public key */
+	s4_wake_key = get_wake_key();
+	if (!s4_wake_key || IS_ERR(s4_wake_key)) {
+		pr_err("PM: Get S4 wake key fail: %ld\n", PTR_ERR(s4_wake_key));
+		return PTR_ERR(s4_wake_key);
+	}
+
+	pks = kzalloc(digest_size + sizeof(*pks), GFP_KERNEL);
+	if (!pks) {
+		pr_err("PM: Allocate public key signature fail!");
+		return -ENOMEM;
+	}
+	pks->pkey_hash_algo = PKEY_HASH_SHA256;
+	pks->digest = digest;
+	pks->digest_size = digest_size;
+
+	mpi = mpi_read_raw_data(signature, get_key_length(s4_wake_key));
+	if (!mpi) {
+		pr_err("PM: mpi_read_raw_data fail!\n");
+		ret = -ENOMEM;
+		goto error_mpi;
+	}
+	pks->mpi[0] = mpi;
+	pks->nr_mpi = 1;
+
+	/* RSA signature check */
+	ret = verify_signature(s4_wake_key, pks);
+	if (ret) {
+		pr_err("snapshot S4 signature verification fail: %d\n", ret);
+		goto error_verify;
+	} else
+		pr_info("snapshot S4 signature verification pass!\n");
+
+	if (pks->rsa.s)
+		mpi_free(pks->rsa.s);
+	kfree(pks);
+
+	return 0;
+
+error_verify:
+	if (pks->rsa.s)
+		mpi_free(pks->rsa.s);
+error_mpi:
+	kfree(pks);
+	return ret;
+}
+
+int snapshot_image_verify(void)
+{
+	struct crypto_shash *tfm;
+	struct shash_desc *desc;
+	u8 *digest;
+	size_t digest_size, desc_size;
+	int ret, i;
+
+	if (!h_buf)
+		return 0;
+
+	tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
+	if (IS_ERR(tfm)) {
+		pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
+		return PTR_ERR(tfm);
+	}
+
+	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+	digest_size = crypto_shash_digestsize(tfm);
+	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+	if (!digest) {
+		pr_err("digest allocate fail");
+		ret = -ENOMEM;
+		goto error_digest;
+	}
+	desc = (void *) digest + digest_size;
+	desc->tfm = tfm;
+	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	ret = crypto_shash_init(desc);
+	if (ret < 0)
+		goto error_shash;
+
+	for (i = 0; i < nr_copy_pages; i++) {
+		ret = crypto_shash_update(desc, *(h_buf + i), PAGE_SIZE);
+		if (ret)
+			goto error_shash;
+	}
+
+	ret = crypto_shash_final(desc, digest);
+	if (ret)
+		goto error_shash;
+
+	ret = snapshot_verify_signature(digest, digest_size);
+	if (ret)
+		goto error_verify;
+
+	kfree(h_buf);
+	kfree(digest);
+	crypto_free_shash(tfm);
+	return 0;
+
+error_verify:
+error_shash:
+	kfree(h_buf);
+	kfree(digest);
+error_digest:
+	crypto_free_shash(tfm);
+	return ret;
+}
+
+void snapshot_fill_s4_skey(void)
+{
+	if (!skey_snapshot_buf)
+		return;
+
+	/* Fill new s4 sign key to snapshot in memory */
+	clone_skey_data(skey_snapshot_buf);
+	/* clean skey page data */
+	erase_skey_data();
+	pr_info("PM: Fill new s4 key to snapshot");
+}
+
 #ifdef CONFIG_HIGHMEM
 /* Assumes that @buf is ready and points to a "safe" page */
 static inline void
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 7c33ed2..f6eaf6e 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -1004,6 +1004,13 @@ static int load_image(struct swap_map_handle *handle,
 		snapshot_write_finalize(snapshot);
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
+		ret = snapshot_image_verify();
+		if (ret)
+			pr_info("PM: snapshot signature check FAIL: %d\n", ret);
+		else {
+			pr_info("PM: snapshot signature check SUCCESS!\n");
+			snapshot_fill_s4_skey();
+		}
 	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 	return ret;
@@ -1358,6 +1365,13 @@ out_finish:
 				}
 			}
 		}
+		ret = snapshot_image_verify();
+		if (ret)
+			pr_info("PM: snapshot signature check FAIL: %d\n", ret);
+		else {
+			pr_info("PM: snapshot signature check SUCCESS!\n");
+			snapshot_fill_s4_skey();
+		}
 	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 out_clean:
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 4ed81e7..c092e81 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -228,6 +228,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 		if (!data->frozen || data->ready)
 			break;
 		pm_restore_gfp_mask();
+		restore_sign_key_data();
 		thaw_processes();
 		data->frozen = 0;
 		break;
@@ -253,6 +254,14 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			error = -EPERM;
 			break;
 		}
+		if (!snapshot_image_verify()) {
+			pr_info("PM: snapshot signature check SUCCESS!\n");
+			snapshot_fill_s4_skey();
+		} else {
+			pr_info("PM: snapshot signature check FAIL!\n");
+			error = -EPERM;
+			break;
+		}
 		error = hibernation_restore(data->platform_support);
 		break;
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (11 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 12/18] Hibernate: generate and " Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:39   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 14/18] Hibernate: applied SNAPSHOT_VERIFICATION config to switch signature check Lee, Chun-Yi
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

This patch add swsusp_page_is_sign_key() method to hibernate_key.c and
check the page is S4 sign key data when collect saveable page in
snapshot.c to avoid sign key data included in snapshot image.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/snapshot.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 72e2911..9e4c94b 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -860,6 +860,9 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
 
 	BUG_ON(!PageHighMem(page));
 
+	if (swsusp_page_is_sign_key(page))
+		return NULL;
+
 	if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page) ||
 	    PageReserved(page))
 		return NULL;
@@ -922,6 +925,9 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
 
 	BUG_ON(PageHighMem(page));
 
+	if (swsusp_page_is_sign_key(page))
+		return NULL;
+
 	if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
 		return NULL;
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 14/18] Hibernate: applied SNAPSHOT_VERIFICATION config to switch signature check
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (12 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 15/18] Hibernate: adapt to UEFI secure boot with " Lee, Chun-Yi
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

This patch applied SNAPSHOT_VERIFICATION kernel config for switching
signature check of hibernate snapshot image.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/snapshot.c |   19 +++++++++++++++++++
 kernel/power/swap.c     |   30 +++++++++++++++++++-----------
 kernel/power/user.c     |    2 ++
 3 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 9e4c94b..cf3d69c 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1052,6 +1052,8 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 {
 	struct zone *zone;
 	unsigned long pfn, dst_pfn;
+
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 	struct page *d_page;
 	void *hash_buffer = NULL;
 	struct crypto_shash *tfm;
@@ -1083,6 +1085,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 	ret = crypto_shash_init(desc);
 	if (ret < 0)
 		goto error_shash;
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
 
 	for_each_populated_zone(zone) {
 		unsigned long max_zone_pfn;
@@ -1102,6 +1105,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 		dst_pfn = memory_bm_next_pfn(copy_bm);
 		copy_data_page(dst_pfn, pfn);
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 		/* Generate digest */
 		d_page = pfn_to_page(dst_pfn);
 		if (PageHighMem(d_page)) {
@@ -1116,8 +1120,10 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 		ret = crypto_shash_update(desc, hash_buffer, PAGE_SIZE);
 		if (ret)
 			goto error_shash;
+#endif
 	}
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 	crypto_shash_final(desc, digest);
 	if (ret)
 		goto error_shash;
@@ -1147,9 +1153,11 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 	kfree(pks);
 	kfree(digest);
 	crypto_free_shash(tfm);
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
 
 	return 0;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 error_sign:
 	destroy_sign_key(s4_sign_key);
 error_key:
@@ -1158,6 +1166,7 @@ error_shash:
 error_digest:
 	crypto_free_shash(tfm);
 	return ret;
+#endif
 }
 
 /* Total number of image pages */
@@ -2321,8 +2330,10 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca,
 	return pbe->address;
 }
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 void **h_buf;
 void *skey_snapshot_buf;
+#endif
 
 /**
  *	snapshot_write_next - used for writing the system memory snapshot.
@@ -2367,12 +2378,14 @@ int snapshot_write_next(struct snapshot_handle *handle)
 		if (error)
 			return error;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 		/* Allocate void * array to keep buffer point for generate hash,
 		 * h_buf will freed in snapshot_image_verify().
 		 */
 		h_buf = kmalloc(sizeof(void *) * nr_copy_pages, GFP_KERNEL);
 		if (!h_buf)
 			pr_err("Allocate hash buffer fail!");
+#endif
 
 		error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
 		if (error)
@@ -2400,8 +2413,10 @@ int snapshot_write_next(struct snapshot_handle *handle)
 			handle->sync_read = 0;
 			if (IS_ERR(handle->buffer))
 				return PTR_ERR(handle->buffer);
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 			if (h_buf)
 				*h_buf = handle->buffer;
+#endif
 		}
 	} else {
 		copy_last_highmem_page();
@@ -2412,11 +2427,13 @@ int snapshot_write_next(struct snapshot_handle *handle)
 			return PTR_ERR(handle->buffer);
 		if (handle->buffer != buffer)
 			handle->sync_read = 0;
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 		if (h_buf)
 			*(h_buf + (handle->cur - nr_meta_pages - 1)) = handle->buffer;
 		/* Keep the buffer of sign key in snapshot */
 		if (pfn == skey_data_buf_pfn)
 			skey_snapshot_buf = handle->buffer;
+#endif
 	}
 	handle->cur++;
 	return PAGE_SIZE;
@@ -2449,6 +2466,7 @@ int snapshot_image_loaded(struct snapshot_handle *handle)
 			handle->cur <= nr_meta_pages + nr_copy_pages);
 }
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 int snapshot_verify_signature(u8 *digest, size_t digest_size)
 {
 	struct key *s4_wake_key;
@@ -2575,6 +2593,7 @@ void snapshot_fill_s4_skey(void)
 	erase_skey_data();
 	pr_info("PM: Fill new s4 key to snapshot");
 }
+#endif /* CONFIG_SNAPSHOT_VERIFICATION */
 
 #ifdef CONFIG_HIGHMEM
 /* Assumes that @buf is ready and points to a "safe" page */
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index f6eaf6e..b5f8ce1 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -1004,13 +1004,17 @@ static int load_image(struct swap_map_handle *handle,
 		snapshot_write_finalize(snapshot);
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
-		ret = snapshot_image_verify();
-		if (ret)
-			pr_info("PM: snapshot signature check FAIL: %d\n", ret);
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 		else {
-			pr_info("PM: snapshot signature check SUCCESS!\n");
-			snapshot_fill_s4_skey();
+			ret = snapshot_image_verify();
+			if (ret)
+				pr_info("PM: snapshot signature check FAIL: %d\n", ret);
+			else {
+				pr_info("PM: snapshot signature check SUCCESS!\n");
+				snapshot_fill_s4_skey();
+			}
 		}
+#endif
 	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 	return ret;
@@ -1365,13 +1369,17 @@ out_finish:
 				}
 			}
 		}
-		ret = snapshot_image_verify();
-		if (ret)
-			pr_info("PM: snapshot signature check FAIL: %d\n", ret);
-		else {
-			pr_info("PM: snapshot signature check SUCCESS!\n");
-			snapshot_fill_s4_skey();
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+		if (!ret) {
+			ret = snapshot_image_verify();
+			if (ret)
+				pr_info("PM: snapshot signature check FAIL: %d\n", ret);
+			else {
+				pr_info("PM: snapshot signature check SUCCESS!\n");
+				snapshot_fill_s4_skey();
+			}
 		}
+#endif
 	}
 	swsusp_show_speed(&start, &stop, nr_to_read, "Read");
 out_clean:
diff --git a/kernel/power/user.c b/kernel/power/user.c
index c092e81..27b21ee 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -254,6 +254,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			error = -EPERM;
 			break;
 		}
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
 		if (!snapshot_image_verify()) {
 			pr_info("PM: snapshot signature check SUCCESS!\n");
 			snapshot_fill_s4_skey();
@@ -262,6 +263,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			error = -EPERM;
 			break;
 		}
+#endif
 		error = hibernation_restore(data->platform_support);
 		break;
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 15/18] Hibernate: adapt to UEFI secure boot with signature check
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (13 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 14/18] Hibernate: applied SNAPSHOT_VERIFICATION config to switch signature check Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:42   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 16/18] Hibernate: show the verification time for monitor performance Lee, Chun-Yi
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

In current solution, the snapshot signature check used the RSA key-pair
that are generated by bootloader(e.g. shim) and pass the key-pair to
kernel through EFI variables. I choice to binding the snapshot
signature check mechanism with UEFI secure boot for provide stronger
protection of hibernate. Current behavior is following:

 + UEFI Secure Boot ON, Kernel found key-pair from shim:
   Will do the S4 signature check.

 + UEFI Secure Boot ON, Kernel didn't find key-pair from shim:
   Will lock down S4 function.

 + UEFI Secure Boot OFF
   Will NOT do the S4 signature check.
   Ignore any keys from bootloader.

v2:
Replace sign_key_data_loaded() by skey_data_available() to check sign key data
is available for hibernate.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/hibernate.c |   36 +++++++++++++++++-
 kernel/power/main.c      |   11 +++++-
 kernel/power/snapshot.c  |   95 ++++++++++++++++++++++++++--------------------
 kernel/power/swap.c      |    4 +-
 kernel/power/user.c      |   11 +++++
 5 files changed, 112 insertions(+), 45 deletions(-)

diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index c545b15..0f19f3d 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -29,6 +29,7 @@
 #include <linux/ctype.h>
 #include <linux/genhd.h>
 #include <linux/key.h>
+#include <linux/efi.h>
 
 #include "power.h"
 
@@ -632,7 +633,14 @@ static void power_down(void)
 int hibernate(void)
 {
 	int error;
-	int skey_error;
+
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	if (!capable(CAP_COMPROMISE_KERNEL) && !skey_data_available()) {
+#else
+	if (!capable(CAP_COMPROMISE_KERNEL)) {
+#endif
+		return -EPERM;
+	}
 
 	lock_system_sleep();
 	/* The snapshot device should not be opened while we're running */
@@ -799,6 +807,15 @@ static int software_resume(void)
 	if (error)
 		goto Unlock;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	if (!capable(CAP_COMPROMISE_KERNEL) && !wkey_data_available()) {
+#else
+	if (!capable(CAP_COMPROMISE_KERNEL)) {
+#endif
+		mutex_unlock(&pm_mutex);
+		return -EPERM;
+	}
+
 	/* The snapshot device should not be opened while we're running */
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
 		error = -EBUSY;
@@ -892,6 +909,15 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
 	int i;
 	char *start = buf;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	if (efi_enabled(EFI_SECURE_BOOT) && !skey_data_available()) {
+#else
+	if (efi_enabled(EFI_SECURE_BOOT)) {
+#endif
+		buf += sprintf(buf, "[%s]\n", "disabled");
+		return buf-start;
+	}
+
 	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
 		if (!hibernation_modes[i])
 			continue;
@@ -926,6 +952,14 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
 	char *p;
 	int mode = HIBERNATION_INVALID;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	if (!capable(CAP_COMPROMISE_KERNEL) && !skey_data_available()) {
+#else
+	if (!capable(CAP_COMPROMISE_KERNEL)) {
+#endif
+		return -EPERM;
+	}
+
 	p = memchr(buf, '\n', n);
 	len = p ? p - buf : n;
 
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 1d1bf63..47bf300 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -15,6 +15,7 @@
 #include <linux/workqueue.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <linux/efi.h>
 
 #include "power.h"
 
@@ -301,7 +302,15 @@ static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
 	}
 #endif
 #ifdef CONFIG_HIBERNATION
-	s += sprintf(s, "%s\n", "disk");
+	if (!efi_enabled(EFI_SECURE_BOOT)) {
+		s += sprintf(s, "%s\n", "disk");
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	} else if (skey_data_available()) {
+		s += sprintf(s, "%s\n", "disk");
+#endif
+	} else {
+		s += sprintf(s, "\n");
+	}
 #else
 	if (s != buf)
 		/* convert the last space to a newline */
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index cf3d69c..36c7157 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -860,7 +860,8 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
 
 	BUG_ON(!PageHighMem(page));
 
-	if (swsusp_page_is_sign_key(page))
+	if (!capable(CAP_COMPROMISE_KERNEL) &&
+	    swsusp_page_is_sign_key(page))
 		return NULL;
 
 	if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page) ||
@@ -925,7 +926,8 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn)
 
 	BUG_ON(PageHighMem(page));
 
-	if (swsusp_page_is_sign_key(page))
+	if (!capable(CAP_COMPROMISE_KERNEL) &&
+	    swsusp_page_is_sign_key(page))
 		return NULL;
 
 	if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
@@ -1056,35 +1058,37 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
 	struct page *d_page;
 	void *hash_buffer = NULL;
-	struct crypto_shash *tfm;
-	struct shash_desc *desc;
-	u8 *digest;
+	struct crypto_shash *tfm = NULL;
+	struct shash_desc *desc = NULL;
+	u8 *digest = NULL;
 	size_t digest_size, desc_size;
 	struct key *s4_sign_key;
 	struct public_key_signature *pks;
 	int ret;
 
 	ret = -ENOMEM;
-	tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
-	if (IS_ERR(tfm)) {
-		pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
-		return PTR_ERR(tfm);
-	}
+	if (!capable(CAP_COMPROMISE_KERNEL)) {
+		tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
+		if (IS_ERR(tfm)) {
+			pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
+			return PTR_ERR(tfm);
+		}
 
-	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-	digest_size = crypto_shash_digestsize(tfm);
-	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
-	if (!digest) {
-		pr_err("digest allocate fail");
-		ret = -ENOMEM;
-		goto error_digest;
+		desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
+		digest_size = crypto_shash_digestsize(tfm);
+		digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
+		if (!digest) {
+			pr_err("digest allocate fail");
+			ret = -ENOMEM;
+			goto error_digest;
+		}
+		desc = (void *) digest + digest_size;
+		desc->tfm = tfm;
+		desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+		ret = crypto_shash_init(desc);
+		if (ret < 0)
+			goto error_shash;
 	}
-	desc = (void *) digest + digest_size;
-	desc->tfm = tfm;
-	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
-	ret = crypto_shash_init(desc);
-	if (ret < 0)
-		goto error_shash;
 #endif /* CONFIG_SNAPSHOT_VERIFICATION */
 
 	for_each_populated_zone(zone) {
@@ -1106,24 +1110,29 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 		copy_data_page(dst_pfn, pfn);
 
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
-		/* Generate digest */
-		d_page = pfn_to_page(dst_pfn);
-		if (PageHighMem(d_page)) {
-			void *kaddr;
-			kaddr = kmap_atomic(d_page);
-			copy_page(buffer, kaddr);
-			kunmap_atomic(kaddr);
-			hash_buffer = buffer;
-		} else {
-			hash_buffer = page_address(d_page);
+		if (!capable(CAP_COMPROMISE_KERNEL)) {
+			/* Generate digest */
+			d_page = pfn_to_page(dst_pfn);
+			if (PageHighMem(d_page)) {
+				void *kaddr;
+				kaddr = kmap_atomic(d_page);
+				copy_page(buffer, kaddr);
+				kunmap_atomic(kaddr);
+				hash_buffer = buffer;
+			} else {
+				hash_buffer = page_address(d_page);
+			}
+			ret = crypto_shash_update(desc, hash_buffer, PAGE_SIZE);
+			if (ret)
+				goto error_shash;
 		}
-		ret = crypto_shash_update(desc, hash_buffer, PAGE_SIZE);
-		if (ret)
-			goto error_shash;
 #endif
 	}
 
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
+	if (capable(CAP_COMPROMISE_KERNEL))
+		goto skip_sign;
+
 	crypto_shash_final(desc, digest);
 	if (ret)
 		goto error_shash;
@@ -1153,6 +1162,8 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 	kfree(pks);
 	kfree(digest);
 	crypto_free_shash(tfm);
+
+skip_sign:
 #endif /* CONFIG_SNAPSHOT_VERIFICATION */
 
 	return 0;
@@ -2382,9 +2393,11 @@ int snapshot_write_next(struct snapshot_handle *handle)
 		/* Allocate void * array to keep buffer point for generate hash,
 		 * h_buf will freed in snapshot_image_verify().
 		 */
-		h_buf = kmalloc(sizeof(void *) * nr_copy_pages, GFP_KERNEL);
-		if (!h_buf)
-			pr_err("Allocate hash buffer fail!");
+		if (!capable(CAP_COMPROMISE_KERNEL)) {
+			h_buf = kmalloc(sizeof(void *) * nr_copy_pages, GFP_KERNEL);
+			if (!h_buf)
+				pr_err("Allocate hash buffer fail!");
+		}
 #endif
 
 		error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
@@ -2414,7 +2427,7 @@ int snapshot_write_next(struct snapshot_handle *handle)
 			if (IS_ERR(handle->buffer))
 				return PTR_ERR(handle->buffer);
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
-			if (h_buf)
+			if (!capable(CAP_COMPROMISE_KERNEL) && h_buf)
 				*h_buf = handle->buffer;
 #endif
 		}
@@ -2428,7 +2441,7 @@ int snapshot_write_next(struct snapshot_handle *handle)
 		if (handle->buffer != buffer)
 			handle->sync_read = 0;
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
-		if (h_buf)
+		if (!capable(CAP_COMPROMISE_KERNEL) && h_buf)
 			*(h_buf + (handle->cur - nr_meta_pages - 1)) = handle->buffer;
 		/* Keep the buffer of sign key in snapshot */
 		if (pfn == skey_data_buf_pfn)
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index b5f8ce1..40225d7 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -1005,7 +1005,7 @@ static int load_image(struct swap_map_handle *handle,
 		if (!snapshot_image_loaded(snapshot))
 			ret = -ENODATA;
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
-		else {
+		else if (!capable(CAP_COMPROMISE_KERNEL)) {
 			ret = snapshot_image_verify();
 			if (ret)
 				pr_info("PM: snapshot signature check FAIL: %d\n", ret);
@@ -1370,7 +1370,7 @@ out_finish:
 			}
 		}
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
-		if (!ret) {
+		if (!ret && !capable(CAP_COMPROMISE_KERNEL)) {
 			ret = snapshot_image_verify();
 			if (ret)
 				pr_info("PM: snapshot signature check FAIL: %d\n", ret);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 27b21ee..690f148 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -48,6 +48,14 @@ static int snapshot_open(struct inode *inode, struct file *filp)
 	struct snapshot_data *data;
 	int error;
 
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+	if (!capable(CAP_COMPROMISE_KERNEL) && !wkey_data_available()) {
+#else
+	if (!capable(CAP_COMPROMISE_KERNEL)) {
+#endif
+		return -EPERM;
+	}
+
 	lock_system_sleep();
 
 	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
@@ -255,6 +263,8 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			break;
 		}
 #ifdef CONFIG_SNAPSHOT_VERIFICATION
+		if (capable(CAP_COMPROMISE_KERNEL))
+			goto skip_verify;
 		if (!snapshot_image_verify()) {
 			pr_info("PM: snapshot signature check SUCCESS!\n");
 			snapshot_fill_s4_skey();
@@ -263,6 +273,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 			error = -EPERM;
 			break;
 		}
+skip_verify:
 #endif
 		error = hibernation_restore(data->platform_support);
 		break;
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 16/18] Hibernate: show the verification time for monitor performance
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (14 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 15/18] Hibernate: adapt to UEFI secure boot with " Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-22 11:01 ` [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm Lee, Chun-Yi
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

Show the verification time for monitor the performance of SHA256 and RSA
verification.

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/snapshot.c |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 36c7157..b9c6a8a 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -2536,6 +2536,8 @@ error_mpi:
 
 int snapshot_image_verify(void)
 {
+	struct timeval start;
+	struct timeval stop;
 	struct crypto_shash *tfm;
 	struct shash_desc *desc;
 	u8 *digest;
@@ -2563,6 +2565,8 @@ int snapshot_image_verify(void)
 	desc->tfm = tfm;
 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
+	do_gettimeofday(&start);
+
 	ret = crypto_shash_init(desc);
 	if (ret < 0)
 		goto error_shash;
@@ -2581,6 +2585,9 @@ int snapshot_image_verify(void)
 	if (ret)
 		goto error_verify;
 
+	do_gettimeofday(&stop);
+	swsusp_show_speed(&start, &stop, nr_copy_pages, "Verified");
+
 	kfree(h_buf);
 	kfree(digest);
 	crypto_free_shash(tfm);
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (15 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 16/18] Hibernate: show the verification time for monitor performance Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-25 16:43   ` Pavel Machek
  2013-08-22 11:01 ` [PATCH 18/18] Hibernate: notify bootloader regenerate key-pair for snapshot verification Lee, Chun-Yi
  2013-08-28 21:01 ` [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Florian Weimer
  18 siblings, 1 reply; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

This patch introduced SNAPSHOT_SIG_HASH config for user to select which
hash algorithm will be used during signature generation of snapshot.

v2:
Add define check of oCONFIG_SNAPSHOT_VERIFICATION in snapshot.c before
declare pkey_hash().

Reviewed-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/Kconfig    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 kernel/power/snapshot.c |   27 ++++++++++++++++++++++-----
 2 files changed, 68 insertions(+), 5 deletions(-)

diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index b592d88..79b34fa 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -78,6 +78,52 @@ config SNAPSHOT_VERIFICATION
 	  dependent on UEFI environment. EFI bootloader should generate the
 	  key-pair.
 
+choice
+	prompt "Which hash algorithm should snapshot be signed with?"
+        depends on SNAPSHOT_VERIFICATION
+        help
+          This determines which sort of hashing algorithm will be used during
+          signature generation of snapshot. This algorithm _must_ be built into
+	  the kernel directly so that signature verification can take place.
+	  It is not possible to load a signed snapshot containing the algorithm
+	  to check the signature on that module.
+
+config SNAPSHOT_SIG_SHA1
+        bool "Sign modules with SHA-1"
+        select CRYPTO_SHA1
+	select CRYPTO_SHA1_SSSE3 if X86_64
+
+config SNAPSHOT_SIG_SHA224
+        bool "Sign modules with SHA-224"
+        select CRYPTO_SHA256
+	select CRYPTO_SHA256_SSSE3 if X86_64
+
+config SNAPSHOT_SIG_SHA256
+        bool "Sign modules with SHA-256"
+        select CRYPTO_SHA256
+	select CRYPTO_SHA256_SSSE3 if X86_64
+
+config SNAPSHOT_SIG_SHA384
+        bool "Sign modules with SHA-384"
+        select CRYPTO_SHA512
+	select CRYPTO_SHA512_SSSE3 if X86_64
+
+config SNAPSHOT_SIG_SHA512
+        bool "Sign modules with SHA-512"
+        select CRYPTO_SHA512
+	select CRYPTO_SHA512_SSSE3 if X86_64
+
+endchoice
+
+config SNAPSHOT_SIG_HASH
+        string
+        depends on SNAPSHOT_VERIFICATION
+        default "sha1" if SNAPSHOT_SIG_SHA1
+        default "sha224" if SNAPSHOT_SIG_SHA224
+        default "sha256" if SNAPSHOT_SIG_SHA256
+        default "sha384" if SNAPSHOT_SIG_SHA384
+        default "sha512" if SNAPSHOT_SIG_SHA512
+
 config PM_STD_PARTITION
 	string "Default resume partition"
 	depends on HIBERNATION
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index b9c6a8a..f02e351 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1042,12 +1042,29 @@ static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
 }
 #endif /* CONFIG_HIGHMEM */
 
-#define SNAPSHOT_HASH "sha256"
+#ifdef CONFIG_SNAPSHOT_VERIFICATION
+static const char *snapshot_hash = CONFIG_SNAPSHOT_SIG_HASH;
+
+static int pkey_hash(void)
+{
+	int i, ret;
+
+	ret = -1;
+	for (i = 0; i < PKEY_HASH__LAST; i++) {
+		if (!strcmp(pkey_hash_algo[i], snapshot_hash)) {
+			ret = i;
+			break;
+		}
+	}
+
+	return ret;
+}
 
 /*
  * Signature of snapshot for check.
  */
 static u8 signature[SIG_LENG];
+#endif
 
 static int
 copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
@@ -1068,7 +1085,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 
 	ret = -ENOMEM;
 	if (!capable(CAP_COMPROMISE_KERNEL)) {
-		tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
+		tfm = crypto_alloc_shash(snapshot_hash, 0, 0);
 		if (IS_ERR(tfm)) {
 			pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
 			return PTR_ERR(tfm);
@@ -1145,7 +1162,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
 		goto error_key;
 	}
 
-	pks = generate_signature(s4_sign_key, digest, PKEY_HASH_SHA256, false);
+	pks = generate_signature(s4_sign_key, digest, pkey_hash(), false);
 	if (IS_ERR(pks)) {
 		pr_err("Generate signature fail: %lx", PTR_ERR(pks));
 		ret = PTR_ERR(pks);
@@ -2499,7 +2516,7 @@ int snapshot_verify_signature(u8 *digest, size_t digest_size)
 		pr_err("PM: Allocate public key signature fail!");
 		return -ENOMEM;
 	}
-	pks->pkey_hash_algo = PKEY_HASH_SHA256;
+	pks->pkey_hash_algo = pkey_hash();
 	pks->digest = digest;
 	pks->digest_size = digest_size;
 
@@ -2547,7 +2564,7 @@ int snapshot_image_verify(void)
 	if (!h_buf)
 		return 0;
 
-	tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
+	tfm = crypto_alloc_shash(snapshot_hash, 0, 0);
 	if (IS_ERR(tfm)) {
 		pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
 		return PTR_ERR(tfm);
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* [PATCH 18/18] Hibernate: notify bootloader regenerate key-pair for snapshot verification
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (16 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm Lee, Chun-Yi
@ 2013-08-22 11:01 ` Lee, Chun-Yi
  2013-08-28 21:01 ` [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Florian Weimer
  18 siblings, 0 replies; 61+ messages in thread
From: Lee, Chun-Yi @ 2013-08-22 11:01 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-security-module, linux-efi, linux-pm, linux-crypto,
	opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

This patch introduced SNAPSHOT_REGEN_KEYS kernel config, enable this
option let kernel notify booloader (e.g. shim) to regenerate key-pair of
snapshot verification for each hibernate.

Kernel loaded S4 sign key in efi stub, so the private key forward from
efi bootloader to kernel in UEFI secure environment. Regenerate key-pair
for each hibernate will gain more security but it hurt the lifetime of
EFI flash memory.

Kernel write an non-volatile runtime efi variable, the name is
GenS4Key-fe141863-c070-478e-b8a3-878a5dc9ef21, to notify efi bootloader
regenerate key-pair for next hibernate cycle.

Userland hibernate tool can write GenS4Key at runtime, kernel will
respect the value but not overwrite it when S4. This mechanism let
userland tool can also notify bootloader to regenerate key-pair through
GenS4Key flag.

Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
---
 kernel/power/Kconfig          |   15 +++++++++++++++
 kernel/power/hibernate_keys.c |   39 +++++++++++++++++++++++++++++++++++++++
 kernel/power/power.h          |    2 ++
 kernel/power/snapshot.c       |    3 +++
 4 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 79b34fa..63bda98 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -78,6 +78,21 @@ config SNAPSHOT_VERIFICATION
 	  dependent on UEFI environment. EFI bootloader should generate the
 	  key-pair.
 
+config SNAPSHOT_REGEN_KEYS
+	bool "Regenerate key-pair for each snapshot verification"
+        depends on SNAPSHOT_VERIFICATION
+	help
+	  Enabled this option let kernel notify booloader (e.g. shim) to
+	  regenerate key-pair of snapshot verification for each hibernate.
+	  Linux kernel write an non-volatile runtime EFI variable, the name
+	  is GenS4Key-fe141863-c070-478e-b8a3-878a5dc9ef21, to notify EFI
+	  bootloader regenerate key-pair for next hibernate cycle.
+
+	  Userland hibernate tool can write GenS4Key at runtime then kernel
+	  will respect the value but not overwrite it when S4. This mechanism
+	  let userland tool can also notify bootloader to regenerate key-pair
+	  through GenS4Key flag.
+
 choice
 	prompt "Which hash algorithm should snapshot be signed with?"
         depends on SNAPSHOT_VERIFICATION
diff --git a/kernel/power/hibernate_keys.c b/kernel/power/hibernate_keys.c
index 1bc5976..60d3e73 100644
--- a/kernel/power/hibernate_keys.c
+++ b/kernel/power/hibernate_keys.c
@@ -7,6 +7,8 @@
 
 #include "power.h"
 
+static efi_char16_t efi_gens4key_name[9] = { 'G', 'e', 'n', 'S', '4', 'K', 'e', 'y', 0 };
+
 static void *skey_data;
 static void *skey_data_buf;
 static unsigned long skey_dsize;
@@ -273,6 +275,42 @@ size_t get_key_length(const struct key *key)
 	return len;
 }
 
+void set_key_regen_flag(void)
+{
+#ifdef CONFIG_SNAPSHOT_REGEN_KEYS
+	unsigned long datasize;
+	u8 gens4key;
+	efi_status_t status;
+
+	/* existing flag may set by userland, respect but not overwrite it */
+	datasize = 0;
+	status = efi.get_variable(efi_gens4key_name, &EFI_HIBERNATE_GUID,
+				  NULL, &datasize, NULL);
+	if (status == EFI_BUFFER_TOO_SMALL)
+		return;
+
+	/* set flag of key-pair regeneration */
+	gens4key = 1;
+	status = efi.set_variable(efi_gens4key_name, &EFI_HIBERNATE_GUID,
+				  EFI_VARIABLE_NON_VOLATILE |
+				  EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				  EFI_VARIABLE_RUNTIME_ACCESS,
+				  1, (void *)&gens4key);
+	if (status)
+		pr_err("PM: Set GenS4Key flag fail: 0x%lx\n", status);
+#endif
+}
+
+static void clean_key_regen_flag(void)
+{
+	/* clean flag of key-pair regeneration */
+	efi.set_variable(efi_gens4key_name, &EFI_HIBERNATE_GUID,
+			 EFI_VARIABLE_NON_VOLATILE |
+			 EFI_VARIABLE_BOOTSERVICE_ACCESS |
+			 EFI_VARIABLE_RUNTIME_ACCESS,
+			 0, NULL);
+}
+
 static int __init init_sign_key_data(void)
 {
 	skey_data = (void *)get_zeroed_page(GFP_KERNEL);
@@ -283,6 +321,7 @@ static int __init init_sign_key_data(void)
 		efi_erase_s4_skey_data();
 		pr_info("PM: Load s4 sign key from EFI\n");
 	}
+	clean_key_regen_flag();
 
 	return 0;
 }
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 84e0b06..3fcde36 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -181,6 +181,7 @@ extern void restore_sign_key_data(void);
 extern bool swsusp_page_is_sign_key(struct page *page);
 extern unsigned long get_skey_data_buf_pfn(void);
 extern void clone_skey_data(void *page_addr);
+extern void set_key_regen_flag(void);
 #else /* !CONFIG_SUSPEND */
 static inline void restore_sign_key_data(void) {}
 static inline bool swsusp_page_is_sign_key(struct page *page)
@@ -191,6 +192,7 @@ static inline unsigned long get_skey_data_buf_pfn(void)
 {
 	return 0;
 }
+static inline void set_key_regen_flag(void) {}
 #endif /* !CONFIG_SNAPSHOT_VERIFICATION */
 
 /* kernel/power/block_io.c */
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index f02e351..12174ff 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -1769,6 +1769,9 @@ asmlinkage int swsusp_save(void)
 	printk(KERN_INFO "PM: Hibernation image created (%d pages copied)\n",
 		nr_pages);
 
+	/* set regenerate key flag */
+	set_key_regen_flag();
+
 	return 0;
 }
 
-- 
1.6.4.2


^ permalink raw reply related	[flat|nested] 61+ messages in thread

* Re: [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa
  2013-08-22 11:01 ` [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa Lee, Chun-Yi
@ 2013-08-25 15:53   ` Pavel Machek
  2013-08-26 10:17     ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 15:53 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:41, Lee, Chun-Yi wrote:
> Implement EMSA_PKCS1-v1_5-ENCODE [RFC3447 sec 9.2] in rsa.c. It's the
> first step of signature generation operation
> (RSASSA-PKCS1-v1_5-SIGN).

Is this your own code, or did you copy it from somewhere?

> +	if (!T)
> +		goto error_T;
> +
> +	memcpy(T, RSA_ASN1_templates[hash_algo].data, RSA_ASN1_templates[hash_algo].size);
> +	memcpy(T + RSA_ASN1_templates[hash_algo].size, pks->digest, pks->digest_size);
> +
> +	/* 3) check If emLen < tLen + 11, output "intended encoded message length too short" */
> +	if (emLen < tLen + 11) {
> +		ret = EINVAL;
> +		goto error_emLen;
> +	}

Normal kernel calling convention is 0 / -EINVAL.

> +	memcpy(EM + 2, PS, emLen - tLen - 3);
> +	EM[2 + emLen - tLen - 3] = 0x00;
> +	memcpy(EM + 2 + emLen - tLen - 3 + 1, T, tLen);

ThisDoesNotLookLikeKernelCode, NoCamelCase, please.

> +	*_EM = EM;

And we don't usually use _ prefix like this.


> --- a/include/crypto/public_key.h
> +++ b/include/crypto/public_key.h
> @@ -110,6 +110,8 @@ extern void public_key_destroy(void *payload);
>  struct public_key_signature {
>  	u8 *digest;
>  	u8 digest_size;			/* Number of bytes in digest */
> +	u8 *S;				/* signature S of length k octets */

u8 *signature?

> +	size_t k;			/* length k of signature S */

u8 *signature_length.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP
  2013-08-22 11:01 ` [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP Lee, Chun-Yi
@ 2013-08-25 16:01   ` Pavel Machek
  2013-08-26 10:25     ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:01 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:42, Lee, Chun-Yi wrote:
> Due to RSA_I2OSP is not only used by signature verification path but also used
> in signature generation path. So, separate the length checking of octet string
> because it's not for generate 0x00 0x01 leading string when used in signature
> generation.
> 
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>

> +static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
> +{
> +	unsigned x_size;
> +	unsigned X_size;
> +	u8 *X = NULL;

Is this kernel code or entry into obfuscated C code contest? This is not funny.

									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 06/18] asymmetric keys: support parsing PKCS #8 private key information
  2013-08-22 11:01 ` [PATCH 06/18] asymmetric keys: support parsing PKCS #8 private key information Lee, Chun-Yi
@ 2013-08-25 16:10   ` Pavel Machek
  0 siblings, 0 replies; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:10 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:45, Lee, Chun-Yi wrote:
> Add ASN.1 files and parser to support parsing PKCS #8 noncompressed private
> key information. It's better than direct parsing pure private key because
> PKCS #8 has a privateKeyAlgorithm to indicate the algorithm of private
> key, e.g. RSA from PKCS #1
> 
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>


> +#include <crypto/public_key.h>
> +
> +struct pkcs8_info {
> +	enum pkey_algo privkey_algo:8;		/* Private key algorithm */

Are you sure this is well-defined?

> +struct private_key_algorithm *pkcs8_private_key_algorithms[PKEY_ALGO__LAST] = {
> +	[PKEY_ALGO_DSA]         = NULL,
> +#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
> +	defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
> +	[PKEY_ALGO_RSA]         = &RSA_private_key_algorithm,
> +#endif
> +};

  pkey_algo
  privkey_algo
  private_key_algorithm

...you use all variants.

Having symbols with "__" inside them is "interesting". I'd not do it.
										Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 07/18] asymmetric keys: explicitly add the leading zero byte to encoded message
  2013-08-22 11:01 ` [PATCH 07/18] asymmetric keys: explicitly add the leading zero byte to encoded message Lee, Chun-Yi
@ 2013-08-25 16:13   ` Pavel Machek
  0 siblings, 0 replies; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:13 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:46, Lee, Chun-Yi wrote:
> Per PKCS1 spec, the EMSA-PKCS1-v1_5 encoded message is leading by 0x00 0x01 in
> its first 2 bytes. The leading zero byte is suppressed by MPI so we pass a
> pointer to the _preceding_ byte to RSA_verify() in original code, but it has
> risk for the byte is not zero because it's not in EM buffer's scope, neither
> RSA_verify() nor mpi_get_buffer() didn't take care the leading byte.
> 
> To avoid the risk, that's better we explicitly add the leading zero byte to EM
> for pass to RSA_verify(). This patch allocate a _EM buffer to capture the
> result from RSA_I2OSP(), then set the first byte to zero in EM and copy the
> remaining bytes from _EM.
> 
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>

> -	ret = RSA_verify(H, EM - 1, k, sig->digest_size,
> +	EM = kmalloc(k, GFP_KERNEL);
> +	memset(EM, 0, 1);
> +	memcpy(EM + 1, _EM, k-1);
> +	kfree(_EM);

Spot a crash waiting to happen.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 08/18] Secure boot: Add new capability
  2013-08-22 11:01 ` [PATCH 08/18] Secure boot: Add new capability Lee, Chun-Yi
@ 2013-08-25 16:14   ` Pavel Machek
  0 siblings, 0 replies; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:14 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Matthew Garrett, Lee, Chun-Yi

On Thu 2013-08-22 19:01:47, Lee, Chun-Yi wrote:
> From: Matthew Garrett <mjg@redhat.com>
> 
> Secure boot adds certain policy requirements, including that root must not
> be able to do anything that could cause the kernel to execute arbitrary code.
> The simplest way to handle this would seem to be to add a new capability
> and gate various functionality on that. We'll then strip it from the initial
> capability set if required.

There was some discussion about this before, right? And I don't think
conclusion was it was acceptable...?

> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> Acked-by: Lee, Chun-Yi <jlee@suse.com>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> ---
>  include/uapi/linux/capability.h |    6 +++++-
>  1 files changed, 5 insertions(+), 1 deletions(-)
> 
> diff --git a/include/uapi/linux/capability.h b/include/uapi/linux/capability.h
> index ba478fa..7109e65 100644
> --- a/include/uapi/linux/capability.h
> +++ b/include/uapi/linux/capability.h
> @@ -343,7 +343,11 @@ struct vfs_cap_data {
>  
>  #define CAP_BLOCK_SUSPEND    36
>  
> -#define CAP_LAST_CAP         CAP_BLOCK_SUSPEND
> +/* Allow things that trivially permit root to modify the running kernel */
> +
> +#define CAP_COMPROMISE_KERNEL  37
> +
> +#define CAP_LAST_CAP         CAP_COMPROMISE_KERNEL
>  
>  #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
>  

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 09/18] Secure boot: Add a dummy kernel parameter that will switch on Secure Boot mode
  2013-08-22 11:01 ` [PATCH 09/18] Secure boot: Add a dummy kernel parameter that will switch on Secure Boot mode Lee, Chun-Yi
@ 2013-08-25 16:16   ` Pavel Machek
  0 siblings, 0 replies; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:16 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

You may want to check subject. If it does something, it is not dummy.

> --- a/Documentation/kernel-parameters.txt
> +++ b/Documentation/kernel-parameters.txt
> @@ -2784,6 +2784,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
>  			Note: increases power consumption, thus should only be
>  			enabled if running jitter sensitive (HPC/RT) workloads.
>  
> +	secureboot_enable=
> +			[KNL] Enables an emulated UEFI Secure Boot mode.  This
> +			locks down various aspects of the kernel guarded by the
> +			CAP_COMPROMISE_KERNEL capability.  This includes things
> +			like /dev/mem, IO port access, and other areas.  It can
> +			be used on non-UEFI machines for testing purposes.
> +
>  	security=	[SECURITY] Choose a security module to enable at boot.
>  			If this boot parameter is not specified, only the first
>  			security module asking for security registration will be
> diff --git a/kernel/cred.c b/kernel/cred.c
> index e0573a4..c3f4e3e 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -565,6 +565,23 @@ void __init cred_init(void)
>  				     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
>  }
>  
> +void __init secureboot_enable()
> +{
> +	pr_info("Secure boot enabled\n");
> +	cap_lower((&init_cred)->cap_bset, CAP_COMPROMISE_KERNEL);
> +	cap_lower((&init_cred)->cap_permitted, CAP_COMPROMISE_KERNEL);
> +}

OTOH you don't implement CAP_COMPROMISE_KERNEL, so it is dummy after
all. But CAP_COMPROMISE_KERNEL is infeasible to implement, right?
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware
  2013-08-22 11:01 ` [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware Lee, Chun-Yi
@ 2013-08-25 16:22   ` Pavel Machek
  2013-08-25 16:26     ` Matthew Garrett
  2013-09-03 10:49   ` Matt Fleming
  1 sibling, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:22 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Matthew Garrett, Lee, Chun-Yi

On Thu 2013-08-22 19:01:49, Lee, Chun-Yi wrote:
> From: Matthew Garrett <mjg@redhat.com>
> 
> The firmware has a set of flags that indicate whether secure boot is enabled
> and enforcing. Use them to indicate whether the kernel should lock itself
> down.  We also indicate the machine is in secure boot mode by adding the
> EFI_SECURE_BOOT bit for use with efi_enabled.

> +	status = efi_call_phys5(sys_table->runtime->get_variable,
> +				L"SecureBoot", &var_guid, NULL, &datasize, &sb);

What is this L"..." thing?
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-22 11:01 ` [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot Lee, Chun-Yi
@ 2013-08-25 16:25   ` Pavel Machek
  2013-08-27  9:04     ` joeyli
  2013-09-05  8:53   ` Matt Fleming
  1 sibling, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:25 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi, Takashi Iwai

On Thu 2013-08-22 19:01:50, Lee, Chun-Yi wrote:
> Introduced a hibernate_key.c file to query the key pair from EFI variables
> and maintain key pair for check signature of S4 snapshot image. We
> loaded the private key when snapshot image stored success.
> 
> This patch introduced 2 EFI variables for store the key to sign S4 image and
> verify signature when S4 wake up. The names and GUID are:
>   S4SignKey-fe141863-c070-478e-b8a3-878a5dc9ef21
>   S4WakeKey-fe141863-c070-478e-b8a3-878a5dc9ef21
> 
> S4SignKey is used by EFI bootloader to pass the RSA private key that packaged
> by PKCS#8 format, kernel will read and parser it when system boot and reload
> it when S4 resume. EFI bootloader need gnerate a new private key when every
> time system boot.
> 
> S4WakeKey is used to pass the RSA public key that packaged by X.509
> certificate, kernel will read and parser it for check the signature of
> S4 snapshot image when S4 resume.
> 
> The follow-up patch will remove S4SignKey and S4WakeKey after load them
> to kernel for avoid anyone can access it through efivarfs.
> 
> v3:
> - Load S4 sign key before ExitBootServices.
>   Load private key before ExitBootServices() then bootloader doesn't need
>   generate key-pair for each booting:
>    + Add setup_s4_keys() to eboot.c to load S4 sign key before ExitBootServices.
>    + Reserve the memory block of sign key data blob in efi.c
> - In Makefile, moved hibernate_keys.o before hibernate.o for load S4 sign
>   key before check hibernate image. It makes sure the new sign key will be
>   transfer to resume target kernel.
> - Set "depends on EFI_STUB" in Kconfig
> 
> v2:
> Add CONFIG_SNAPSHOT_VERIFICATION for build of hibernate_keys.c depend on
> Kconfig.
> 
> Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> Cc: Takashi Iwai <tiwai@suse.de>
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>


> --- a/arch/x86/boot/compressed/eboot.c
> +++ b/arch/x86/boot/compressed/eboot.c
> @@ -368,6 +368,91 @@ free_handle:
>  	return status;
>  }
>  
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +static efi_status_t setup_s4_keys(struct boot_params *params)
> +{
> +	struct setup_data *data;
> +	unsigned long datasize;
> +	u32 attr;
> +	struct efi_s4_key *s4key;
> +	efi_status_t status;
> +
> +	data = (struct setup_data *)(unsigned long)params->hdr.setup_data;

A bit too many casts.

> @@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
>  
>  	setup_efi_pci(boot_params);
>  
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +	setup_s4_keys(boot_params);
> +#endif
> +

Move ifdef inside the function?

> @@ -729,6 +792,11 @@ void __init efi_init(void)
>  
>  	set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
>  
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +	/* keep s4 key from setup_data */
> +	efi_reserve_s4_skey_data();
> +#endif
> +

Here too.

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware
  2013-08-25 16:22   ` Pavel Machek
@ 2013-08-25 16:26     ` Matthew Garrett
  0 siblings, 0 replies; 61+ messages in thread
From: Matthew Garrett @ 2013-08-25 16:26 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Lee, Chun-Yi, linux-kernel, linux-security-module, linux-efi,
	linux-pm, linux-crypto, opensuse-kernel, David Howells,
	Rafael J. Wysocki, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Matthew Garrett, Lee, Chun-Yi

On Sun, Aug 25, 2013 at 06:22:43PM +0200, Pavel Machek wrote:
> On Thu 2013-08-22 19:01:49, Lee, Chun-Yi wrote:
> > From: Matthew Garrett <mjg@redhat.com>
> > 
> > The firmware has a set of flags that indicate whether secure boot is enabled
> > and enforcing. Use them to indicate whether the kernel should lock itself
> > down.  We also indicate the machine is in secure boot mode by adding the
> > EFI_SECURE_BOOT bit for use with efi_enabled.
> 
> > +	status = efi_call_phys5(sys_table->runtime->get_variable,
> > +				L"SecureBoot", &var_guid, NULL, &datasize, &sb);
> 
> What is this L"..." thing?

http://en.wikipedia.org/wiki/C_syntax#Wide_character_strings
-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 12/18] Hibernate: generate and verify signature of snapshot
  2013-08-22 11:01 ` [PATCH 12/18] Hibernate: generate and " Lee, Chun-Yi
@ 2013-08-25 16:36   ` Pavel Machek
  2013-08-27  3:22     ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:36 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:51, Lee, Chun-Yi wrote:
> This patch add the code for generate/verify signature of snapshot, it
> put the signature to snapshot header. This approach can support both
> on userspace hibernate and in-kernel hibernate.
> 
> v2:
> - Due to loaded S4 sign key before ExitBootServices, we need forward key from
>   boot kernel to resume target kernel. So this patch add a empty page in
>   snapshot image, then we keep the pfn of this empty page in snapshot header.
>   When system resume from hibernate, we fill new sign key to this empty page
>   space after snapshot image checked pass. This mechanism let boot kernel can
>   forward new sign key to resume target kernel but don't need write new private
>   key to any other storage, e.g. swap.
> 
> Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> ---
>  kernel/power/power.h    |    6 +
>  kernel/power/snapshot.c |  280 +++++++++++++++++++++++++++++++++++++++++++++-
>  kernel/power/swap.c     |   14 +++
>  kernel/power/user.c     |    9 ++
>  4 files changed, 302 insertions(+), 7 deletions(-)
> 
> diff --git a/kernel/power/power.h b/kernel/power/power.h
> index 69a81d8..84e0b06 100644
> --- a/kernel/power/power.h
> +++ b/kernel/power/power.h
> @@ -3,6 +3,9 @@
>  #include <linux/utsname.h>
>  #include <linux/freezer.h>
>  
> +/* The maximum length of snapshot signature */
> +#define SIG_LENG 512
> +
>  struct swsusp_info {
>  	struct new_utsname	uts;
>  	u32			version_code;
> @@ -11,6 +14,8 @@ struct swsusp_info {
>  	unsigned long		image_pages;
>  	unsigned long		pages;
>  	unsigned long		size;
> +	unsigned long           skey_data_buf_pfn;
> +	u8			signature[SIG_LENG];
>  } __attribute__((aligned(PAGE_SIZE)));

SIG_LEN or SIG_LENGTH. Select one.


> +static int
>  copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
>  {
>  	struct zone *zone;
> -	unsigned long pfn;
> +	unsigned long pfn, dst_pfn;
...
> +	tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
> +	if (IS_ERR(tfm)) {
> +		pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
> +		return PTR_ERR(tfm);
> +	}
> +
> +	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> +	digest_size = crypto_shash_digestsize(tfm);
> +	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);

Are you sure GFP_KERNEL allocation is okay at this phase of
hibernation?

Could the hashing be done at later phase, when writing the image to
disk?

>  
> +void **h_buf;

helpfully named.

> +	ret = verify_signature(s4_wake_key, pks);
> +	if (ret) {
> +		pr_err("snapshot S4 signature verification fail: %d\n", ret);
> +		goto error_verify;
> +	} else
> +		pr_info("snapshot S4 signature verification pass!\n");
> +
> +	if (pks->rsa.s)
> +		mpi_free(pks->rsa.s);
> +	kfree(pks);

ret = 0 and fall through?

> +	return 0;
> +
> +error_verify:
> +	if (pks->rsa.s)
> +		mpi_free(pks->rsa.s);
> +error_mpi:
> +	kfree(pks);
> +	return ret;
> +}


> +	ret = crypto_shash_final(desc, digest);
> +	if (ret)
> +		goto error_shash;
> +
> +	ret = snapshot_verify_signature(digest, digest_size);
> +	if (ret)
> +		goto error_verify;
> +
> +	kfree(h_buf);
> +	kfree(digest);
> +	crypto_free_shash(tfm);
> +	return 0;

These four lines can be deleted.

> +
> +error_verify:
> +error_shash:
> +	kfree(h_buf);
> +	kfree(digest);
> +error_digest:
> +	crypto_free_shash(tfm);
> +	return ret;
> +}
> +
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image
  2013-08-22 11:01 ` [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image Lee, Chun-Yi
@ 2013-08-25 16:39   ` Pavel Machek
  2013-08-27  8:33     ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:39 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:52, Lee, Chun-Yi wrote:
> This patch add swsusp_page_is_sign_key() method to hibernate_key.c and
> check the page is S4 sign key data when collect saveable page in
> snapshot.c to avoid sign key data included in snapshot image.
> 
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> ---
>  kernel/power/snapshot.c |    6 ++++++
>  1 files changed, 6 insertions(+), 0 deletions(-)
> 
> diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
> index 72e2911..9e4c94b 100644
> --- a/kernel/power/snapshot.c
> +++ b/kernel/power/snapshot.c
> @@ -860,6 +860,9 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
>  
>  	BUG_ON(!PageHighMem(page));
>  
> +	if (swsusp_page_is_sign_key(page))
> +		return NULL;
> +
>  	if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page) ||
>  	    PageReserved(page))
>  		return NULL;

Just do set_page_forbidden() on your page?
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 15/18] Hibernate: adapt to UEFI secure boot with signature check
  2013-08-22 11:01 ` [PATCH 15/18] Hibernate: adapt to UEFI secure boot with " Lee, Chun-Yi
@ 2013-08-25 16:42   ` Pavel Machek
  2013-08-27 10:14     ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:42 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:54, Lee, Chun-Yi wrote:
> In current solution, the snapshot signature check used the RSA key-pair
> that are generated by bootloader(e.g. shim) and pass the key-pair to
> kernel through EFI variables. I choice to binding the snapshot
> signature check mechanism with UEFI secure boot for provide stronger
> protection of hibernate. Current behavior is following:
> 
>  + UEFI Secure Boot ON, Kernel found key-pair from shim:
>    Will do the S4 signature check.
> 
>  + UEFI Secure Boot ON, Kernel didn't find key-pair from shim:
>    Will lock down S4 function.
> 
>  + UEFI Secure Boot OFF
>    Will NOT do the S4 signature check.
>    Ignore any keys from bootloader.
> 
> v2:
> Replace sign_key_data_loaded() by skey_data_available() to check sign key data
> is available for hibernate.
> 
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> ---
>  kernel/power/hibernate.c |   36 +++++++++++++++++-
>  kernel/power/main.c      |   11 +++++-
>  kernel/power/snapshot.c  |   95 ++++++++++++++++++++++++++--------------------
>  kernel/power/swap.c      |    4 +-
>  kernel/power/user.c      |   11 +++++
>  5 files changed, 112 insertions(+), 45 deletions(-)
> 
> diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
> index c545b15..0f19f3d 100644
> --- a/kernel/power/hibernate.c
> +++ b/kernel/power/hibernate.c
> @@ -29,6 +29,7 @@
>  #include <linux/ctype.h>
>  #include <linux/genhd.h>
>  #include <linux/key.h>
> +#include <linux/efi.h>
>  
>  #include "power.h"
>  
> @@ -632,7 +633,14 @@ static void power_down(void)
>  int hibernate(void)
>  {
>  	int error;
> -	int skey_error;
> +
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +	if (!capable(CAP_COMPROMISE_KERNEL) && !skey_data_available()) {
> +#else
> +	if (!capable(CAP_COMPROMISE_KERNEL)) {
> +#endif
> +		return -EPERM;
> +	}
>  
>  	lock_system_sleep();
>  	/* The snapshot device should not be opened while we're running */
> @@ -799,6 +807,15 @@ static int software_resume(void)
>  	if (error)
>  		goto Unlock;
>  
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +	if (!capable(CAP_COMPROMISE_KERNEL) && !wkey_data_available()) {
> +#else
> +	if (!capable(CAP_COMPROMISE_KERNEL)) {
> +#endif
> +		mutex_unlock(&pm_mutex);
> +		return -EPERM;
> +	}
> +
>  	/* The snapshot device should not be opened while we're running */
>  	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
>  		error = -EBUSY;
> @@ -892,6 +909,15 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
>  	int i;
>  	char *start = buf;
>  
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +	if (efi_enabled(EFI_SECURE_BOOT) && !skey_data_available()) {
> +#else
> +	if (efi_enabled(EFI_SECURE_BOOT)) {
> +#endif
> +		buf += sprintf(buf, "[%s]\n", "disabled");
> +		return buf-start;
> +	}
> +
>  	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
>  		if (!hibernation_modes[i])
>  			continue;
> @@ -926,6 +952,14 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
>  	char *p;
>  	int mode = HIBERNATION_INVALID;
>  
> +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> +	if (!capable(CAP_COMPROMISE_KERNEL) && !skey_data_available()) {
> +#else
> +	if (!capable(CAP_COMPROMISE_KERNEL)) {
> +#endif
> +		return -EPERM;
> +	}
> +
>  	p = memchr(buf, '\n', n);
>  	len = p ? p - buf : n;
>  

You clearly need some helper function.
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm
  2013-08-22 11:01 ` [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm Lee, Chun-Yi
@ 2013-08-25 16:43   ` Pavel Machek
  2013-08-27 10:22     ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-25 16:43 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Lee, Chun-Yi

On Thu 2013-08-22 19:01:56, Lee, Chun-Yi wrote:
> This patch introduced SNAPSHOT_SIG_HASH config for user to select which
> hash algorithm will be used during signature generation of snapshot.
> 
> v2:
> Add define check of oCONFIG_SNAPSHOT_VERIFICATION in snapshot.c before
> declare pkey_hash().
> 
> Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> ---
>  kernel/power/Kconfig    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
>  kernel/power/snapshot.c |   27 ++++++++++++++++++++++-----
>  2 files changed, 68 insertions(+), 5 deletions(-)
> 
> diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> index b592d88..79b34fa 100644
> --- a/kernel/power/Kconfig
> +++ b/kernel/power/Kconfig
> @@ -78,6 +78,52 @@ config SNAPSHOT_VERIFICATION
>  	  dependent on UEFI environment. EFI bootloader should generate the
>  	  key-pair.
>  
> +choice
> +	prompt "Which hash algorithm should snapshot be signed with?"
> +        depends on SNAPSHOT_VERIFICATION
> +        help
> +          This determines which sort of hashing algorithm will be used during
> +          signature generation of snapshot. This algorithm _must_ be built into
> +	  the kernel directly so that signature verification can take place.
> +	  It is not possible to load a signed snapshot containing the algorithm
> +	  to check the signature on that module.

Like if 1000 ifdefs you already added to the code are not enough, you
make some new ones?
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa
  2013-08-25 15:53   ` Pavel Machek
@ 2013-08-26 10:17     ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-26 10:17 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

Hi Pavel, 

First, thanks for your review!

於 日,2013-08-25 於 17:53 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:41, Lee, Chun-Yi wrote:
> > Implement EMSA_PKCS1-v1_5-ENCODE [RFC3447 sec 9.2] in rsa.c. It's the
> > first step of signature generation operation
> > (RSASSA-PKCS1-v1_5-SIGN).
> 
> Is this your own code, or did you copy it from somewhere?
> 

It's my own code, development base on RSA PKCS#1 spec. So the naming of
variables are match with PKCS#1 spec.

> > +	if (!T)
> > +		goto error_T;
> > +
> > +	memcpy(T, RSA_ASN1_templates[hash_algo].data, RSA_ASN1_templates[hash_algo].size);
> > +	memcpy(T + RSA_ASN1_templates[hash_algo].size, pks->digest, pks->digest_size);
> > +
> > +	/* 3) check If emLen < tLen + 11, output "intended encoded message length too short" */
> > +	if (emLen < tLen + 11) {
> > +		ret = EINVAL;
> > +		goto error_emLen;
> > +	}
> 
> Normal kernel calling convention is 0 / -EINVAL.

Yes, here is my mistake, I will modify it.

> 
> > +	memcpy(EM + 2, PS, emLen - tLen - 3);
> > +	EM[2 + emLen - tLen - 3] = 0x00;
> > +	memcpy(EM + 2 + emLen - tLen - 3 + 1, T, tLen);
> 
> ThisDoesNotLookLikeKernelCode, NoCamelCase, please.
> 

Thanks for you point out, I will change it.

> > +	*_EM = EM;
> 
> And we don't usually use _ prefix like this.
> 

Thanks! I will change it.

> 
> > --- a/include/crypto/public_key.h
> > +++ b/include/crypto/public_key.h
> > @@ -110,6 +110,8 @@ extern void public_key_destroy(void *payload);
> >  struct public_key_signature {
> >  	u8 *digest;
> >  	u8 digest_size;			/* Number of bytes in digest */
> > +	u8 *S;				/* signature S of length k octets */
> 
> u8 *signature?

Yes, this 'S' is signature. I put the naming full match with spec for
development, I will change it to match kernel rule. e.g. signature_S

> 
> > +	size_t k;			/* length k of signature S */
> 
> u8 *signature_length.
> 

I will use signature_leng_k to also match with PKCS#1 spec, I think it's
better for review source code with the spec for debugging.


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP
  2013-08-25 16:01   ` Pavel Machek
@ 2013-08-26 10:25     ` joeyli
  2013-08-26 11:27       ` Pavel Machek
  0 siblings, 1 reply; 61+ messages in thread
From: joeyli @ 2013-08-26 10:25 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

於 日,2013-08-25 於 18:01 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:42, Lee, Chun-Yi wrote:
> > Due to RSA_I2OSP is not only used by signature verification path but also used
> > in signature generation path. So, separate the length checking of octet string
> > because it's not for generate 0x00 0x01 leading string when used in signature
> > generation.
> > 
> > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> 
> > +static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
> > +{
> > +	unsigned x_size;
> > +	unsigned X_size;
> > +	u8 *X = NULL;
> 
> Is this kernel code or entry into obfuscated C code contest? This is not funny.
> 
> 									Pavel

The small "x" is the input integer that will transfer to big "X" that is
a octet sting. 

Sorry for I direct give variable name to match with spec, maybe I need
use big_X or....

Do you have good suggest for the naming?


Thanks a lot!
Joey Lee



^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP
  2013-08-26 10:25     ` joeyli
@ 2013-08-26 11:27       ` Pavel Machek
  2013-08-27  8:36         ` Jiri Kosina
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-26 11:27 UTC (permalink / raw)
  To: joeyli
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

Hi!

> > > Due to RSA_I2OSP is not only used by signature verification path but also used
> > > in signature generation path. So, separate the length checking of octet string
> > > because it's not for generate 0x00 0x01 leading string when used in signature
> > > generation.
> > > 
> > > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > 
> > > +static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
> > > +{
> > > +	unsigned x_size;
> > > +	unsigned X_size;
> > > +	u8 *X = NULL;
> > 
> > Is this kernel code or entry into obfuscated C code contest? This is not funny.
> > 
> The small "x" is the input integer that will transfer to big "X" that is
> a octet sting. 
> 
> Sorry for I direct give variable name to match with spec, maybe I need
> use big_X or....

Having variables that differ only in case is confusing. Actually
RSA_I2OSP is not a good name for function, either.

If it converts x into X, perhaps you can name one input and second output?

> Do you have good suggest for the naming?

Not really, sorry.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 12/18] Hibernate: generate and verify signature of snapshot
  2013-08-25 16:36   ` Pavel Machek
@ 2013-08-27  3:22     ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-27  3:22 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

Hi Pavel, 

Thanks for your time to review my patches.

於 日,2013-08-25 於 18:36 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:51, Lee, Chun-Yi wrote:
> > This patch add the code for generate/verify signature of snapshot, it
> > put the signature to snapshot header. This approach can support both
> > on userspace hibernate and in-kernel hibernate.
> > 
> > v2:
> > - Due to loaded S4 sign key before ExitBootServices, we need forward key from
> >   boot kernel to resume target kernel. So this patch add a empty page in
> >   snapshot image, then we keep the pfn of this empty page in snapshot header.
> >   When system resume from hibernate, we fill new sign key to this empty page
> >   space after snapshot image checked pass. This mechanism let boot kernel can
> >   forward new sign key to resume target kernel but don't need write new private
> >   key to any other storage, e.g. swap.
> > 
> > Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > ---
> >  kernel/power/power.h    |    6 +
> >  kernel/power/snapshot.c |  280 +++++++++++++++++++++++++++++++++++++++++++++-
> >  kernel/power/swap.c     |   14 +++
> >  kernel/power/user.c     |    9 ++
> >  4 files changed, 302 insertions(+), 7 deletions(-)
> > 
> > diff --git a/kernel/power/power.h b/kernel/power/power.h
> > index 69a81d8..84e0b06 100644
> > --- a/kernel/power/power.h
> > +++ b/kernel/power/power.h
> > @@ -3,6 +3,9 @@
> >  #include <linux/utsname.h>
> >  #include <linux/freezer.h>
> >  
> > +/* The maximum length of snapshot signature */
> > +#define SIG_LENG 512
> > +
> >  struct swsusp_info {
> >  	struct new_utsname	uts;
> >  	u32			version_code;
> > @@ -11,6 +14,8 @@ struct swsusp_info {
> >  	unsigned long		image_pages;
> >  	unsigned long		pages;
> >  	unsigned long		size;
> > +	unsigned long           skey_data_buf_pfn;
> > +	u8			signature[SIG_LENG];
> >  } __attribute__((aligned(PAGE_SIZE)));
> 
> SIG_LEN or SIG_LENGTH. Select one.
> 

I will use SIG_LEN at next version, thanks!

> 
> > +static int
> >  copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
> >  {
> >  	struct zone *zone;
> > -	unsigned long pfn;
> > +	unsigned long pfn, dst_pfn;
> ...
> > +	tfm = crypto_alloc_shash(SNAPSHOT_HASH, 0, 0);
> > +	if (IS_ERR(tfm)) {
> > +		pr_err("IS_ERR(tfm): %ld", PTR_ERR(tfm));
> > +		return PTR_ERR(tfm);
> > +	}
> > +
> > +	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
> > +	digest_size = crypto_shash_digestsize(tfm);
> > +	digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
> 
> Are you sure GFP_KERNEL allocation is okay at this phase of
> hibernation?
> 
> Could the hashing be done at later phase, when writing the image to
> disk?
> 

Thanks for you point out!

Yes, call memory allocate here is not a good design due to it causes
garbage in snapshot that will not released by resumed kernel.

I just finished another implementation, the respin patch extracts the
signature generation code to another function then call the function in
swsusp_save() after copy_data_pages() finished. We can write to memory
at that stage.

> >  
> > +void **h_buf;
> 
> helpfully named.
> 

I will change the name to handle_buffers;

> > +	ret = verify_signature(s4_wake_key, pks);
> > +	if (ret) {
> > +		pr_err("snapshot S4 signature verification fail: %d\n", ret);
> > +		goto error_verify;
> > +	} else
> > +		pr_info("snapshot S4 signature verification pass!\n");
> > +
> > +	if (pks->rsa.s)
> > +		mpi_free(pks->rsa.s);
> > +	kfree(pks);
> 
> ret = 0 and fall through?
> 

When verification success, verify_signature() will return 0.

Yes, here have duplicate code, I will clear up it.

> > +	return 0;
> > +
> > +error_verify:
> > +	if (pks->rsa.s)
> > +		mpi_free(pks->rsa.s);
> > +error_mpi:
> > +	kfree(pks);
> > +	return ret;
> > +}
> 
> 
> > +	ret = crypto_shash_final(desc, digest);
> > +	if (ret)
> > +		goto error_shash;
> > +
> > +	ret = snapshot_verify_signature(digest, digest_size);
> > +	if (ret)
> > +		goto error_verify;
> > +
> > +	kfree(h_buf);
> > +	kfree(digest);
> > +	crypto_free_shash(tfm);
> > +	return 0;
> 
> These four lines can be deleted.
> 

Yes, here also duplicate, I will remove.

> > +
> > +error_verify:
> > +error_shash:
> > +	kfree(h_buf);
> > +	kfree(digest);
> > +error_digest:
> > +	crypto_free_shash(tfm);
> > +	return ret;
> > +}
> > +
> 									Pavel


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image
  2013-08-25 16:39   ` Pavel Machek
@ 2013-08-27  8:33     ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-27  8:33 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

於 日,2013-08-25 於 18:39 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:52, Lee, Chun-Yi wrote:
> > This patch add swsusp_page_is_sign_key() method to hibernate_key.c and
> > check the page is S4 sign key data when collect saveable page in
> > snapshot.c to avoid sign key data included in snapshot image.
> > 
> > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > ---
> >  kernel/power/snapshot.c |    6 ++++++
> >  1 files changed, 6 insertions(+), 0 deletions(-)
> > 
> > diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
> > index 72e2911..9e4c94b 100644
> > --- a/kernel/power/snapshot.c
> > +++ b/kernel/power/snapshot.c
> > @@ -860,6 +860,9 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
> >  
> >  	BUG_ON(!PageHighMem(page));
> >  
> > +	if (swsusp_page_is_sign_key(page))
> > +		return NULL;
> > +
> >  	if (swsusp_page_is_forbidden(page) ||  swsusp_page_is_free(page) ||
> >  	    PageReserved(page))
> >  		return NULL;
> 
> Just do set_page_forbidden() on your page?

Before call swsusp_unset_page_forbidden(), we need make sure the
create_basic_memory_bitmaps() function already called to initial
forbidden_pages_map. That means need careful the timing, otherwise the
page of private key will not register to forbidden pages map.

So, I choice to refuse the page of private key when snapshot finding
which page is saveable. It has clearer code and we don't need worry the
future change of hibernate.c or user.c for when they call
create_basic_memory_bitmaps() and when the code clear forbidden pages
map.


Thanks a lot!
Joey Lee



^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP
  2013-08-26 11:27       ` Pavel Machek
@ 2013-08-27  8:36         ` Jiri Kosina
  0 siblings, 0 replies; 61+ messages in thread
From: Jiri Kosina @ 2013-08-27  8:36 UTC (permalink / raw)
  To: Pavel Machek
  Cc: joeyli, linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

On Mon, 26 Aug 2013, Pavel Machek wrote:

> > > > Due to RSA_I2OSP is not only used by signature verification path but also used
> > > > in signature generation path. So, separate the length checking of octet string
> > > > because it's not for generate 0x00 0x01 leading string when used in signature
> > > > generation.
> > > > 
> > > > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > > > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > > 
> > > > +static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
> > > > +{
> > > > +	unsigned x_size;
> > > > +	unsigned X_size;
> > > > +	u8 *X = NULL;
> > > 
> > > Is this kernel code or entry into obfuscated C code contest? This is not funny.
> > > 
> > The small "x" is the input integer that will transfer to big "X" that is
> > a octet sting. 
> > 
> > Sorry for I direct give variable name to match with spec, maybe I need
> > use big_X or....
> 
> Having variables that differ only in case is confusing. Actually
> RSA_I2OSP is not a good name for function, either.
> 
> If it converts x into X, perhaps you can name one input and second output?

The variable naming is according to spec, and I believe it makes sense to 
keep it so, no matter how stupid the naming in the spec might be.

Otherwise you have to do mental remapping when looking at the code and the 
spec at the same time, which is very inconvenient.

Would a comment next to the variable declaration, that would point this 
fact out, be satisfactory for you?

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-25 16:25   ` Pavel Machek
@ 2013-08-27  9:04     ` joeyli
  2013-08-27 11:29       ` Pavel Machek
  0 siblings, 1 reply; 61+ messages in thread
From: joeyli @ 2013-08-27  9:04 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Takashi Iwai

Hi Pavel, 

於 日,2013-08-25 於 18:25 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:50, Lee, Chun-Yi wrote:
> > Introduced a hibernate_key.c file to query the key pair from EFI variables
> > and maintain key pair for check signature of S4 snapshot image. We
> > loaded the private key when snapshot image stored success.
> > 
> > This patch introduced 2 EFI variables for store the key to sign S4 image and
> > verify signature when S4 wake up. The names and GUID are:
> >   S4SignKey-fe141863-c070-478e-b8a3-878a5dc9ef21
> >   S4WakeKey-fe141863-c070-478e-b8a3-878a5dc9ef21
> > 
> > S4SignKey is used by EFI bootloader to pass the RSA private key that packaged
> > by PKCS#8 format, kernel will read and parser it when system boot and reload
> > it when S4 resume. EFI bootloader need gnerate a new private key when every
> > time system boot.
> > 
> > S4WakeKey is used to pass the RSA public key that packaged by X.509
> > certificate, kernel will read and parser it for check the signature of
> > S4 snapshot image when S4 resume.
> > 
> > The follow-up patch will remove S4SignKey and S4WakeKey after load them
> > to kernel for avoid anyone can access it through efivarfs.
> > 
> > v3:
> > - Load S4 sign key before ExitBootServices.
> >   Load private key before ExitBootServices() then bootloader doesn't need
> >   generate key-pair for each booting:
> >    + Add setup_s4_keys() to eboot.c to load S4 sign key before ExitBootServices.
> >    + Reserve the memory block of sign key data blob in efi.c
> > - In Makefile, moved hibernate_keys.o before hibernate.o for load S4 sign
> >   key before check hibernate image. It makes sure the new sign key will be
> >   transfer to resume target kernel.
> > - Set "depends on EFI_STUB" in Kconfig
> > 
> > v2:
> > Add CONFIG_SNAPSHOT_VERIFICATION for build of hibernate_keys.c depend on
> > Kconfig.
> > 
> > Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> > Cc: Takashi Iwai <tiwai@suse.de>
> > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> 
> 
> > --- a/arch/x86/boot/compressed/eboot.c
> > +++ b/arch/x86/boot/compressed/eboot.c
> > @@ -368,6 +368,91 @@ free_handle:
> >  	return status;
> >  }
> >  
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +static efi_status_t setup_s4_keys(struct boot_params *params)
> > +{
> > +	struct setup_data *data;
> > +	unsigned long datasize;
> > +	u32 attr;
> > +	struct efi_s4_key *s4key;
> > +	efi_status_t status;
> > +
> > +	data = (struct setup_data *)(unsigned long)params->hdr.setup_data;
> 
> A bit too many casts.

Thanks.
Yes, here is my mistake, I will remove "unsigned long" cast.

> 
> > @@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> >  
> >  	setup_efi_pci(boot_params);
> >  
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +	setup_s4_keys(boot_params);
> > +#endif
> > +
> 
> Move ifdef inside the function?

OK, I will define a dummy function for non-verification situation.

> 
> > @@ -729,6 +792,11 @@ void __init efi_init(void)
> >  
> >  	set_bit(EFI_SYSTEM_TABLES, &x86_efi_facility);
> >  
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +	/* keep s4 key from setup_data */
> > +	efi_reserve_s4_skey_data();
> > +#endif
> > +
> 
> Here too.
> 

I will also use dummy function here. 


Thanks
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 15/18] Hibernate: adapt to UEFI secure boot with signature check
  2013-08-25 16:42   ` Pavel Machek
@ 2013-08-27 10:14     ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-27 10:14 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

於 日,2013-08-25 於 18:42 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:54, Lee, Chun-Yi wrote:
> > In current solution, the snapshot signature check used the RSA key-pair
> > that are generated by bootloader(e.g. shim) and pass the key-pair to
> > kernel through EFI variables. I choice to binding the snapshot
> > signature check mechanism with UEFI secure boot for provide stronger
> > protection of hibernate. Current behavior is following:
> > 
> >  + UEFI Secure Boot ON, Kernel found key-pair from shim:
> >    Will do the S4 signature check.
> > 
> >  + UEFI Secure Boot ON, Kernel didn't find key-pair from shim:
> >    Will lock down S4 function.
> > 
> >  + UEFI Secure Boot OFF
> >    Will NOT do the S4 signature check.
> >    Ignore any keys from bootloader.
> > 
> > v2:
> > Replace sign_key_data_loaded() by skey_data_available() to check sign key data
> > is available for hibernate.
> > 
> > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > ---
> >  kernel/power/hibernate.c |   36 +++++++++++++++++-
> >  kernel/power/main.c      |   11 +++++-
> >  kernel/power/snapshot.c  |   95 ++++++++++++++++++++++++++--------------------
> >  kernel/power/swap.c      |    4 +-
> >  kernel/power/user.c      |   11 +++++
> >  5 files changed, 112 insertions(+), 45 deletions(-)
> > 
> > diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
> > index c545b15..0f19f3d 100644
> > --- a/kernel/power/hibernate.c
> > +++ b/kernel/power/hibernate.c
> > @@ -29,6 +29,7 @@
> >  #include <linux/ctype.h>
> >  #include <linux/genhd.h>
> >  #include <linux/key.h>
> > +#include <linux/efi.h>
> >  
> >  #include "power.h"
> >  
> > @@ -632,7 +633,14 @@ static void power_down(void)
> >  int hibernate(void)
> >  {
> >  	int error;
> > -	int skey_error;
> > +
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +	if (!capable(CAP_COMPROMISE_KERNEL) && !skey_data_available()) {
> > +#else
> > +	if (!capable(CAP_COMPROMISE_KERNEL)) {
> > +#endif
> > +		return -EPERM;
> > +	}
> >  
> >  	lock_system_sleep();
> >  	/* The snapshot device should not be opened while we're running */
> > @@ -799,6 +807,15 @@ static int software_resume(void)
> >  	if (error)
> >  		goto Unlock;
> >  
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +	if (!capable(CAP_COMPROMISE_KERNEL) && !wkey_data_available()) {
> > +#else
> > +	if (!capable(CAP_COMPROMISE_KERNEL)) {
> > +#endif
> > +		mutex_unlock(&pm_mutex);
> > +		return -EPERM;
> > +	}
> > +
> >  	/* The snapshot device should not be opened while we're running */
> >  	if (!atomic_add_unless(&snapshot_device_available, -1, 0)) {
> >  		error = -EBUSY;
> > @@ -892,6 +909,15 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
> >  	int i;
> >  	char *start = buf;
> >  
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +	if (efi_enabled(EFI_SECURE_BOOT) && !skey_data_available()) {
> > +#else
> > +	if (efi_enabled(EFI_SECURE_BOOT)) {
> > +#endif
> > +		buf += sprintf(buf, "[%s]\n", "disabled");
> > +		return buf-start;
> > +	}
> > +
> >  	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
> >  		if (!hibernation_modes[i])
> >  			continue;
> > @@ -926,6 +952,14 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
> >  	char *p;
> >  	int mode = HIBERNATION_INVALID;
> >  
> > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > +	if (!capable(CAP_COMPROMISE_KERNEL) && !skey_data_available()) {
> > +#else
> > +	if (!capable(CAP_COMPROMISE_KERNEL)) {
> > +#endif
> > +		return -EPERM;
> > +	}
> > +
> >  	p = memchr(buf, '\n', n);
> >  	len = p ? p - buf : n;
> >  
> 
> You clearly need some helper function.
> 									Pavel
> 

I will use a help function to replace those ifdef block.

Thanks for your suggestion!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm
  2013-08-25 16:43   ` Pavel Machek
@ 2013-08-27 10:22     ` joeyli
  2013-08-27 11:30       ` Pavel Machek
  0 siblings, 1 reply; 61+ messages in thread
From: joeyli @ 2013-08-27 10:22 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

於 日,2013-08-25 於 18:43 +0200,Pavel Machek 提到:
> On Thu 2013-08-22 19:01:56, Lee, Chun-Yi wrote:
> > This patch introduced SNAPSHOT_SIG_HASH config for user to select which
> > hash algorithm will be used during signature generation of snapshot.
> > 
> > v2:
> > Add define check of oCONFIG_SNAPSHOT_VERIFICATION in snapshot.c before
> > declare pkey_hash().
> > 
> > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > ---
> >  kernel/power/Kconfig    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
> >  kernel/power/snapshot.c |   27 ++++++++++++++++++++++-----
> >  2 files changed, 68 insertions(+), 5 deletions(-)
> > 
> > diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> > index b592d88..79b34fa 100644
> > --- a/kernel/power/Kconfig
> > +++ b/kernel/power/Kconfig
> > @@ -78,6 +78,52 @@ config SNAPSHOT_VERIFICATION
> >  	  dependent on UEFI environment. EFI bootloader should generate the
> >  	  key-pair.
> >  
> > +choice
> > +	prompt "Which hash algorithm should snapshot be signed with?"
> > +        depends on SNAPSHOT_VERIFICATION
> > +        help
> > +          This determines which sort of hashing algorithm will be used during
> > +          signature generation of snapshot. This algorithm _must_ be built into
> > +	  the kernel directly so that signature verification can take place.
> > +	  It is not possible to load a signed snapshot containing the algorithm
> > +	  to check the signature on that module.
> 
> Like if 1000 ifdefs you already added to the code are not enough, you
> make some new ones?
> 									Pavel
> 

This SNAPSHOT_SIG_HASH kernel config is to select which SHA algorithms
used for generate digest of snapshot. The configuration will captured by
a const char* in code:

+static const char *snapshot_hash = CONFIG_SNAPSHOT_SIG_HASH;
+
+static int pkey_hash(void)

So, there doesn't have any ifdef block derived from this new config.


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-27  9:04     ` joeyli
@ 2013-08-27 11:29       ` Pavel Machek
  2013-08-27 12:01         ` Manfred Hollstein
  2013-08-27 13:12         ` joeyli
  0 siblings, 2 replies; 61+ messages in thread
From: Pavel Machek @ 2013-08-27 11:29 UTC (permalink / raw)
  To: joeyli
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Takashi Iwai


> > > @@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> > >  
> > >  	setup_efi_pci(boot_params);
> > >  
> > > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > > +	setup_s4_keys(boot_params);
> > > +#endif
> > > +
> > 
> > Move ifdef inside the function?
> 
> OK, I will define a dummy function for non-verification situation.

IIRC you can just put the #ifdef inside the function body. 
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm
  2013-08-27 10:22     ` joeyli
@ 2013-08-27 11:30       ` Pavel Machek
  2013-08-27 12:54         ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-27 11:30 UTC (permalink / raw)
  To: joeyli
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

On Tue 2013-08-27 18:22:17, joeyli wrote:
> 於 日,2013-08-25 於 18:43 +0200,Pavel Machek 提到:
> > On Thu 2013-08-22 19:01:56, Lee, Chun-Yi wrote:
> > > This patch introduced SNAPSHOT_SIG_HASH config for user to select which
> > > hash algorithm will be used during signature generation of snapshot.
> > > 
> > > v2:
> > > Add define check of oCONFIG_SNAPSHOT_VERIFICATION in snapshot.c before
> > > declare pkey_hash().
> > > 
> > > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > > ---
> > >  kernel/power/Kconfig    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  kernel/power/snapshot.c |   27 ++++++++++++++++++++++-----
> > >  2 files changed, 68 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> > > index b592d88..79b34fa 100644
> > > --- a/kernel/power/Kconfig
> > > +++ b/kernel/power/Kconfig
> > > @@ -78,6 +78,52 @@ config SNAPSHOT_VERIFICATION
> > >  	  dependent on UEFI environment. EFI bootloader should generate the
> > >  	  key-pair.
> > >  
> > > +choice
> > > +	prompt "Which hash algorithm should snapshot be signed with?"
> > > +        depends on SNAPSHOT_VERIFICATION
> > > +        help
> > > +          This determines which sort of hashing algorithm will be used during
> > > +          signature generation of snapshot. This algorithm _must_ be built into
> > > +	  the kernel directly so that signature verification can take place.
> > > +	  It is not possible to load a signed snapshot containing the algorithm
> > > +	  to check the signature on that module.
> > 
> > Like if 1000 ifdefs you already added to the code are not enough, you
> > make some new ones?
> > 									Pavel
> > 
> 
> This SNAPSHOT_SIG_HASH kernel config is to select which SHA algorithms
> used for generate digest of snapshot. The configuration will captured by
> a const char* in code:
> 
> +static const char *snapshot_hash = CONFIG_SNAPSHOT_SIG_HASH;
> +
> +static int pkey_hash(void)
> 
> So, there doesn't have any ifdef block derived from this new config.

I'd say select one hash function, and use it. There's no need to make
it configurable.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-27 11:29       ` Pavel Machek
@ 2013-08-27 12:01         ` Manfred Hollstein
  2013-08-27 14:17           ` Pavel Machek
  2013-08-27 13:12         ` joeyli
  1 sibling, 1 reply; 61+ messages in thread
From: Manfred Hollstein @ 2013-08-27 12:01 UTC (permalink / raw)
  To: Pavel Machek
  Cc: joeyli, linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Takashi Iwai

On Tue, 27 Aug 2013, 13:29:43 +0200, Pavel Machek wrote:
> > > > @@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> > > >  
> > > >  	setup_efi_pci(boot_params);
> > > >  
> > > > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > > > +	setup_s4_keys(boot_params);
> > > > +#endif
> > > > +
> > > 
> > > Move ifdef inside the function?
> > 
> > OK, I will define a dummy function for non-verification situation.
> 
> IIRC you can just put the #ifdef inside the function body. 

This is certainly not to be invoked on a frequent basis (and therefore
not on a hot path), but from a more general angle, wouldn't this leave
a(nother) plain "jsr... rts" sequence without any effect other than
burning a few cycles? If the whole function call can be disabled
(ignored) in a certain configuration, it shouldn't call at all, should
it?

Cheers.

l8er
manfred

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm
  2013-08-27 11:30       ` Pavel Machek
@ 2013-08-27 12:54         ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-27 12:54 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

於 二,2013-08-27 於 13:30 +0200,Pavel Machek 提到:
> On Tue 2013-08-27 18:22:17, joeyli wrote:
> > 於 日,2013-08-25 於 18:43 +0200,Pavel Machek 提到:
> > > On Thu 2013-08-22 19:01:56, Lee, Chun-Yi wrote:
> > > > This patch introduced SNAPSHOT_SIG_HASH config for user to select which
> > > > hash algorithm will be used during signature generation of snapshot.
> > > > 
> > > > v2:
> > > > Add define check of oCONFIG_SNAPSHOT_VERIFICATION in snapshot.c before
> > > > declare pkey_hash().
> > > > 
> > > > Reviewed-by: Jiri Kosina <jkosina@suse.cz>
> > > > Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> > > > ---
> > > >  kernel/power/Kconfig    |   46 ++++++++++++++++++++++++++++++++++++++++++++++
> > > >  kernel/power/snapshot.c |   27 ++++++++++++++++++++++-----
> > > >  2 files changed, 68 insertions(+), 5 deletions(-)
> > > > 
> > > > diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
> > > > index b592d88..79b34fa 100644
> > > > --- a/kernel/power/Kconfig
> > > > +++ b/kernel/power/Kconfig
> > > > @@ -78,6 +78,52 @@ config SNAPSHOT_VERIFICATION
> > > >  	  dependent on UEFI environment. EFI bootloader should generate the
> > > >  	  key-pair.
> > > >  
> > > > +choice
> > > > +	prompt "Which hash algorithm should snapshot be signed with?"
> > > > +        depends on SNAPSHOT_VERIFICATION
> > > > +        help
> > > > +          This determines which sort of hashing algorithm will be used during
> > > > +          signature generation of snapshot. This algorithm _must_ be built into
> > > > +	  the kernel directly so that signature verification can take place.
> > > > +	  It is not possible to load a signed snapshot containing the algorithm
> > > > +	  to check the signature on that module.
> > > 
> > > Like if 1000 ifdefs you already added to the code are not enough, you
> > > make some new ones?
> > > 									Pavel
> > > 
> > 
> > This SNAPSHOT_SIG_HASH kernel config is to select which SHA algorithms
> > used for generate digest of snapshot. The configuration will captured by
> > a const char* in code:
> > 
> > +static const char *snapshot_hash = CONFIG_SNAPSHOT_SIG_HASH;
> > +
> > +static int pkey_hash(void)
> > 
> > So, there doesn't have any ifdef block derived from this new config.
> 
> I'd say select one hash function, and use it. There's no need to make
> it configurable.
> 									Pavel

There have better performance when SHA algorithm output shorter hash
result. On the other hand, longer hash result provide better security.

And, on 64-bits system, the SHA512 has better performance then SHA256.

Due to user have different use case and different hardware, why not give
them this option to make decision?


Thanks a lot!
Joey LEe


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-27 11:29       ` Pavel Machek
  2013-08-27 12:01         ` Manfred Hollstein
@ 2013-08-27 13:12         ` joeyli
  1 sibling, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-27 13:12 UTC (permalink / raw)
  To: Pavel Machek
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal, Takashi Iwai

於 二,2013-08-27 於 13:29 +0200,Pavel Machek 提到:
> > > > @@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> > > >  
> > > >  	setup_efi_pci(boot_params);
> > > >  
> > > > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > > > +	setup_s4_keys(boot_params);
> > > > +#endif
> > > > +
> > > 
> > > Move ifdef inside the function?
> > 
> > OK, I will define a dummy function for non-verification situation.
> 
> IIRC you can just put the #ifdef inside the function body. 
> 									Pavel

I want use inline dummy function like saveable_highmem_page() in
snapshot.c, maybe it's	 better then additional function call?


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-27 12:01         ` Manfred Hollstein
@ 2013-08-27 14:17           ` Pavel Machek
  0 siblings, 0 replies; 61+ messages in thread
From: Pavel Machek @ 2013-08-27 14:17 UTC (permalink / raw)
  To: Manfred Hollstein, joeyli, linux-kernel, linux-security-module,
	linux-efi, linux-pm, linux-crypto, opensuse-kernel,
	David Howells, Rafael J. Wysocki, Matthew Garrett, Len Brown,
	Josh Boyer, Vojtech Pavlik, Matt Fleming, James Bottomley,
	Greg KH, JKosina, Rusty Russell, Herbert Xu, David S. Miller,
	H. Peter Anvin, Michal Marek, Gary Lin, Vivek Goyal,
	Takashi Iwai

On Tue 2013-08-27 14:01:42, Manfred Hollstein wrote:
> On Tue, 27 Aug 2013, 13:29:43 +0200, Pavel Machek wrote:
> > > > > @@ -1205,6 +1290,10 @@ struct boot_params *efi_main(void *handle, efi_system_table_t *_table,
> > > > >  
> > > > >  	setup_efi_pci(boot_params);
> > > > >  
> > > > > +#ifdef CONFIG_SNAPSHOT_VERIFICATION
> > > > > +	setup_s4_keys(boot_params);
> > > > > +#endif
> > > > > +
> > > > 
> > > > Move ifdef inside the function?
> > > 
> > > OK, I will define a dummy function for non-verification situation.
> > 
> > IIRC you can just put the #ifdef inside the function body. 
> 
> This is certainly not to be invoked on a frequent basis (and therefore
> not on a hot path), but from a more general angle, wouldn't this leave
> a(nother) plain "jsr... rts" sequence without any effect other than
> burning a few cycles? If the whole function call can be disabled
> (ignored) in a certain configuration, it shouldn't call at all, should
> it?

gcc should be able to deal with optimizing that out.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
                   ` (17 preceding siblings ...)
  2013-08-22 11:01 ` [PATCH 18/18] Hibernate: notify bootloader regenerate key-pair for snapshot verification Lee, Chun-Yi
@ 2013-08-28 21:01 ` Florian Weimer
  2013-08-29  0:01   ` joeyli
  18 siblings, 1 reply; 61+ messages in thread
From: Florian Weimer @ 2013-08-28 21:01 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi

* Chun-Yi Lee:

>  + EFI bootloader must generate RSA key-pair when system boot:
>    - Bootloader store the public key to EFI boottime variable by itself
>    - Bootloader put The private key to S4SignKey EFI variable for forward to
>      kernel.

Is the UEFI NVRAM really suited for such regular updates?

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-08-28 21:01 ` [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Florian Weimer
@ 2013-08-29  0:01   ` joeyli
  2013-08-29 21:32     ` Pavel Machek
  2013-09-01 10:41     ` Florian Weimer
  0 siblings, 2 replies; 61+ messages in thread
From: joeyli @ 2013-08-29  0:01 UTC (permalink / raw)
  To: Florian Weimer
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal

Hi Florian, 

Thanks for your response.

於 三,2013-08-28 於 23:01 +0200,Florian Weimer 提到:
> * Chun-Yi Lee:
> 
> >  + EFI bootloader must generate RSA key-pair when system boot:

I should add more information on this sentence for mention need GenS4Key
runtime variable then re-generate key-pair.

Thanks!

> >    - Bootloader store the public key to EFI boottime variable by itself
> >    - Bootloader put The private key to S4SignKey EFI variable for forward to
> >      kernel.
> 
> Is the UEFI NVRAM really suited for such regular updates?
> 

Yes, Matthew raised this concern at before. I modified patch to load
private key in efi stub kernel, before ExitBootServices(), that means we
don't need generate key-pair at every system boot. So, the above
procedure of efi bootloader will only run one time. 

User can enable SNAPSHOT_REGEN_KEYS kernel config to notify efi
booloader regenerate key-pair for every S4 to improve security if he
want. So, the key-pair re-generate procedure will only launched when S4
resume, not every system boot.


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-08-29  0:01   ` joeyli
@ 2013-08-29 21:32     ` Pavel Machek
  2013-08-29 22:30       ` joeyli
  2013-09-01 10:41     ` Florian Weimer
  1 sibling, 1 reply; 61+ messages in thread
From: Pavel Machek @ 2013-08-29 21:32 UTC (permalink / raw)
  To: joeyli
  Cc: Florian Weimer, linux-kernel, linux-security-module, linux-efi,
	linux-pm, linux-crypto, opensuse-kernel, David Howells,
	Rafael J. Wysocki, Matthew Garrett, Len Brown, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal

Hi!

> > >    - Bootloader store the public key to EFI boottime variable by itself
> > >    - Bootloader put The private key to S4SignKey EFI variable for forward to
> > >      kernel.
> > 
> > Is the UEFI NVRAM really suited for such regular updates?
> > 
> 
> Yes, Matthew raised this concern at before. I modified patch to load
> private key in efi stub kernel, before ExitBootServices(), that means we
> don't need generate key-pair at every system boot. So, the above
> procedure of efi bootloader will only run one time. 
> 
> User can enable SNAPSHOT_REGEN_KEYS kernel config to notify efi
> booloader regenerate key-pair for every S4 to improve security if he
> want. So, the key-pair re-generate procedure will only launched when S4
> resume, not every system boot.

How many writes can UEFI NVRAM survive? (Is it NOR?)

"every S4 resume" may be approximately "every boot" for some users...
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-08-29 21:32     ` Pavel Machek
@ 2013-08-29 22:30       ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-08-29 22:30 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Florian Weimer, linux-kernel, linux-security-module, linux-efi,
	linux-pm, linux-crypto, opensuse-kernel, David Howells,
	Rafael J. Wysocki, Matthew Garrett, Len Brown, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal

於 四,2013-08-29 於 23:32 +0200,Pavel Machek 提到:
> Hi!
> 
> > > >    - Bootloader store the public key to EFI boottime variable by itself
> > > >    - Bootloader put The private key to S4SignKey EFI variable for forward to
> > > >      kernel.
> > > 
> > > Is the UEFI NVRAM really suited for such regular updates?
> > > 
> > 
> > Yes, Matthew raised this concern at before. I modified patch to load
> > private key in efi stub kernel, before ExitBootServices(), that means we
> > don't need generate key-pair at every system boot. So, the above
> > procedure of efi bootloader will only run one time. 
> > 
> > User can enable SNAPSHOT_REGEN_KEYS kernel config to notify efi
> > booloader regenerate key-pair for every S4 to improve security if he
> > want. So, the key-pair re-generate procedure will only launched when S4
> > resume, not every system boot.
> 
> How many writes can UEFI NVRAM survive? (Is it NOR?)

Currently doesn't have enough information for normal. Yes, I don't know.

> 
> "every S4 resume" may be approximately "every boot" for some users...
> 									Pavel

Yes, it's possible.

So, this option will be disabled by default. Default will only generate
one key-pair for every hibernate.
If "re-generate key-pair for every S4" is still hurt lift of UEFI NVRAM
too much, then another thinking for re-generate key-pair are:
 
 + Re-generate key-pair after a number of hibernates.
   e.g. after 5, 10, 20... times
or
 + Random re-generate key-pair?


On the other hand...
In current design, GenS4Key EFI variable could be write by userland
hibernate tool, kernel will respect GenS4Key value from userland when
hibernate launch. So, userland can tell bootloader to lunch the key-pair
regeneration procedure.


Thanks a lot!
Joey LEe


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-08-29  0:01   ` joeyli
  2013-08-29 21:32     ` Pavel Machek
@ 2013-09-01 10:41     ` Florian Weimer
  2013-09-01 16:04       ` Matthew Garrett
  1 sibling, 1 reply; 61+ messages in thread
From: Florian Weimer @ 2013-09-01 10:41 UTC (permalink / raw)
  To: joeyli
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal

* joeyli:

> Yes, Matthew raised this concern at before. I modified patch to load
> private key in efi stub kernel, before ExitBootServices(), that means we
> don't need generate key-pair at every system boot. So, the above
> procedure of efi bootloader will only run one time. 

But if you don't generate fresh keys on every boot, the persistent
keys are mor exposed to other UEFI applications.  Correct me if I'm
wrong, but I don't think UEFI variables are segregated between
different UEFI applications, so if anyone gets a generic UEFI variable
dumper (or setter) signed by the trusted key, this cryptographic
validation of hibernate snapshots is bypassable.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-09-01 10:41     ` Florian Weimer
@ 2013-09-01 16:04       ` Matthew Garrett
  2013-09-01 16:40         ` Florian Weimer
  0 siblings, 1 reply; 61+ messages in thread
From: Matthew Garrett @ 2013-09-01 16:04 UTC (permalink / raw)
  To: Florian Weimer
  Cc: joeyli, linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Len Brown, Pavel Machek, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

On Sun, Sep 01, 2013 at 12:41:22PM +0200, Florian Weimer wrote:

> But if you don't generate fresh keys on every boot, the persistent
> keys are mor exposed to other UEFI applications.  Correct me if I'm
> wrong, but I don't think UEFI variables are segregated between
> different UEFI applications, so if anyone gets a generic UEFI variable
> dumper (or setter) signed by the trusted key, this cryptographic
> validation of hibernate snapshots is bypassable.

If anyone can execute arbitrary code in your UEFI environment then 
you've already lost.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-09-01 16:04       ` Matthew Garrett
@ 2013-09-01 16:40         ` Florian Weimer
  2013-09-01 16:46           ` Matthew Garrett
  2013-09-02  2:12           ` joeyli
  0 siblings, 2 replies; 61+ messages in thread
From: Florian Weimer @ 2013-09-01 16:40 UTC (permalink / raw)
  To: Matthew Garrett
  Cc: joeyli, linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Len Brown, Pavel Machek, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

* Matthew Garrett:

> On Sun, Sep 01, 2013 at 12:41:22PM +0200, Florian Weimer wrote:
>
>> But if you don't generate fresh keys on every boot, the persistent
>> keys are mor exposed to other UEFI applications.  Correct me if I'm
>> wrong, but I don't think UEFI variables are segregated between
>> different UEFI applications, so if anyone gets a generic UEFI variable
>> dumper (or setter) signed by the trusted key, this cryptographic
>> validation of hibernate snapshots is bypassable.
>
> If anyone can execute arbitrary code in your UEFI environment then 
> you've already lost.

This is not about arbitrary code execution.  The problematic
applications which conflict with this proposed functionality are not
necessarily malicious by themselves and even potentially useful.

For example, if you want to provision a bunch of machines and you have
to set certain UEFI variables, it might be helpful to do so in an
unattended fashion, just by booting from a USB stick with a suitable
UEFI application.  Is this evil?  I don't think so.

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-09-01 16:40         ` Florian Weimer
@ 2013-09-01 16:46           ` Matthew Garrett
  2013-09-02  2:12           ` joeyli
  1 sibling, 0 replies; 61+ messages in thread
From: Matthew Garrett @ 2013-09-01 16:46 UTC (permalink / raw)
  To: Florian Weimer
  Cc: joeyli, linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Len Brown, Pavel Machek, Josh Boyer, Vojtech Pavlik,
	Matt Fleming, James Bottomley, Greg KH, JKosina, Rusty Russell,
	Herbert Xu, David S. Miller, H. Peter Anvin, Michal Marek,
	Gary Lin, Vivek Goyal

On Sun, Sep 01, 2013 at 06:40:41PM +0200, Florian Weimer wrote:
> * Matthew Garrett:
> 
> > On Sun, Sep 01, 2013 at 12:41:22PM +0200, Florian Weimer wrote:
> >
> >> But if you don't generate fresh keys on every boot, the persistent
> >> keys are mor exposed to other UEFI applications.  Correct me if I'm
> >> wrong, but I don't think UEFI variables are segregated between
> >> different UEFI applications, so if anyone gets a generic UEFI variable
> >> dumper (or setter) signed by the trusted key, this cryptographic
> >> validation of hibernate snapshots is bypassable.
> >
> > If anyone can execute arbitrary code in your UEFI environment then 
> > you've already lost.
> 
> This is not about arbitrary code execution.  The problematic
> applications which conflict with this proposed functionality are not
> necessarily malicious by themselves and even potentially useful.
 
A signed application that permits the modification of arbitrary boot 
services variables *is* malicious. No implementation is designed to be 
safe in that scenario. Why bother with modifying encryption keys when 
you can just modify MOK instead?

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot
  2013-09-01 16:40         ` Florian Weimer
  2013-09-01 16:46           ` Matthew Garrett
@ 2013-09-02  2:12           ` joeyli
  1 sibling, 0 replies; 61+ messages in thread
From: joeyli @ 2013-09-02  2:12 UTC (permalink / raw)
  To: Florian Weimer
  Cc: Matthew Garrett, linux-kernel, linux-security-module, linux-efi,
	linux-pm, linux-crypto, opensuse-kernel, David Howells,
	Rafael J. Wysocki, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal

於 日,2013-09-01 於 18:40 +0200,Florian Weimer 提到:
> * Matthew Garrett:
> 
> > On Sun, Sep 01, 2013 at 12:41:22PM +0200, Florian Weimer wrote:
> >
> >> But if you don't generate fresh keys on every boot, the persistent
> >> keys are mor exposed to other UEFI applications.  Correct me if I'm
> >> wrong, but I don't think UEFI variables are segregated between
> >> different UEFI applications, so if anyone gets a generic UEFI variable
> >> dumper (or setter) signed by the trusted key, this cryptographic
> >> validation of hibernate snapshots is bypassable.
> >
> > If anyone can execute arbitrary code in your UEFI environment then 
> > you've already lost.
> 
> This is not about arbitrary code execution.  The problematic
> applications which conflict with this proposed functionality are not
> necessarily malicious by themselves and even potentially useful.
> 
> For example, if you want to provision a bunch of machines and you have
> to set certain UEFI variables, it might be helpful to do so in an
> unattended fashion, just by booting from a USB stick with a suitable
> UEFI application.  Is this evil?  I don't think so.
> --

Yes, if there have the kind of UEFI tools like you said, and it leak to
attacker, then we lost.

Even we re-generate key-pair for every S4, the tool, if it can set
variable, means it can replace the public key that was stored by efi
bootloader in bootservices variable. Then we still lost.

When the tool can only dump variable but not set, then re-generate
key-pair to every S4 can prevent it. If the tool can also set variable,
then I don't think there have any way to protect key-pair in UEFI
variables.

Using TPM is a way to protect key-pair, but user need key-in password
when generate and use key to sign stuff. It noises to user, but the best
way to keep the password is in brain.


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware
  2013-08-22 11:01 ` [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware Lee, Chun-Yi
  2013-08-25 16:22   ` Pavel Machek
@ 2013-09-03 10:49   ` Matt Fleming
  1 sibling, 0 replies; 61+ messages in thread
From: Matt Fleming @ 2013-09-03 10:49 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Matthew Garrett, Lee,
	Chun-Yi

On Thu, 22 Aug, at 07:01:49PM, Lee, Chun-Yi wrote:
> From: Matthew Garrett <mjg@redhat.com>
> 
> The firmware has a set of flags that indicate whether secure boot is enabled
> and enforcing. Use them to indicate whether the kernel should lock itself
> down.  We also indicate the machine is in secure boot mode by adding the
> EFI_SECURE_BOOT bit for use with efi_enabled.
> 
> Signed-off-by: Matthew Garrett <mjg@redhat.com>
> Signed-off-by: Josh Boyer <jwboyer@redhat.com>
> Acked-by: Lee, Chun-Yi <jlee@suse.com>
> Signed-off-by: Lee, Chun-Yi <jlee@suse.com>
> ---
>  Documentation/x86/zero-page.txt        |    2 ++
>  arch/x86/boot/compressed/eboot.c       |   32 ++++++++++++++++++++++++++++++++
>  arch/x86/include/asm/bootparam_utils.h |    8 ++++++--
>  arch/x86/include/uapi/asm/bootparam.h  |    3 ++-
>  arch/x86/kernel/setup.c                |    7 +++++++
>  include/linux/cred.h                   |    2 ++
>  include/linux/efi.h                    |    1 +
>  7 files changed, 52 insertions(+), 3 deletions(-)

[...]

> +static int get_secure_boot(efi_system_table_t *_table)
> +{
> +	u8 sb, setup;
> +	unsigned long datasize = sizeof(sb);
> +	efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID;
> +	efi_status_t status;
> +
> +	status = efi_call_phys5(sys_table->runtime->get_variable,
> +				L"SecureBoot", &var_guid, NULL, &datasize, &sb);
> +

The _table argument isn't needed because it's never used.

[...]

>  	io_delay_init();
>  
> +	if (boot_params.secure_boot) {
> +#ifdef CONFIG_EFI
> +		set_bit(EFI_SECURE_BOOT, &x86_efi_facility);
> +#endif
> +		secureboot_enable();
> +	}
> +

efi_enabled(EFI_BOOT) should be checked also, instead of assuming that
secure_boot contains a sensible value.

-- 
Matt Fleming, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-08-22 11:01 ` [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot Lee, Chun-Yi
  2013-08-25 16:25   ` Pavel Machek
@ 2013-09-05  8:53   ` Matt Fleming
  2013-09-05 10:13     ` joeyli
  1 sibling, 1 reply; 61+ messages in thread
From: Matt Fleming @ 2013-09-05  8:53 UTC (permalink / raw)
  To: Lee, Chun-Yi
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Lee, Chun-Yi, Takashi Iwai

On Thu, 22 Aug, at 07:01:50PM, Lee, Chun-Yi wrote:
> +static int efi_status_to_err(efi_status_t status)
> +{
> +	int err;
> +
> +	switch (status) {
> +	case EFI_INVALID_PARAMETER:
> +		err = -EINVAL;
> +		break;
> +	case EFI_OUT_OF_RESOURCES:
> +		err = -ENOSPC;
> +		break;
> +	case EFI_DEVICE_ERROR:
> +		err = -EIO;
> +		break;
> +	case EFI_WRITE_PROTECTED:
> +		err = -EROFS;
> +		break;
> +	case EFI_SECURITY_VIOLATION:
> +		err = -EACCES;
> +		break;
> +	case EFI_NOT_FOUND:
> +		err = -ENODATA;
> +		break;
> +	default:
> +		err = -EINVAL;
> +	}
> +
> +	return err;
> +}

Please don't reimplement this. Instead make the existing function
global.

[...]

> +static void *load_wake_key_data(unsigned long *datasize)
> +{
> +	u32 attr;
> +	void *wkey_data;
> +	efi_status_t status;
> +
> +	if (!efi_enabled(EFI_RUNTIME_SERVICES))
> +		return ERR_PTR(-EPERM);
> +
> +	/* obtain the size */
> +	*datasize = 0;
> +	status = efi.get_variable(EFI_S4_WAKE_KEY_NAME, &EFI_HIBERNATE_GUID,
> +				  NULL, datasize, NULL);
> +	if (status != EFI_BUFFER_TOO_SMALL) {
> +		wkey_data = ERR_PTR(efi_status_to_err(status));
> +		pr_err("PM: Couldn't get wake key data size: 0x%lx\n", status);
> +		goto error;
> +	}

Is it safe to completely bypass the efivars interface and access
efi.get_variable() directly? I wouldn't have thought so, unless you can
guarantee that the kernel isn't going to access any of the EFI runtime
services while you execute this function.

-- 
Matt Fleming, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-09-05  8:53   ` Matt Fleming
@ 2013-09-05 10:13     ` joeyli
  2013-09-05 10:31       ` Matt Fleming
  0 siblings, 1 reply; 61+ messages in thread
From: joeyli @ 2013-09-05 10:13 UTC (permalink / raw)
  To: Matt Fleming
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Takashi Iwai

Hi Matt, 

First, thanks for your review!

於 四,2013-09-05 於 09:53 +0100,Matt Fleming 提到:
> On Thu, 22 Aug, at 07:01:50PM, Lee, Chun-Yi wrote:
> > +static int efi_status_to_err(efi_status_t status)
> > +{
> > +	int err;
> > +
> > +	switch (status) {
> > +	case EFI_INVALID_PARAMETER:
> > +		err = -EINVAL;
> > +		break;
> > +	case EFI_OUT_OF_RESOURCES:
> > +		err = -ENOSPC;
> > +		break;
> > +	case EFI_DEVICE_ERROR:
> > +		err = -EIO;
> > +		break;
> > +	case EFI_WRITE_PROTECTED:
> > +		err = -EROFS;
> > +		break;
> > +	case EFI_SECURITY_VIOLATION:
> > +		err = -EACCES;
> > +		break;
> > +	case EFI_NOT_FOUND:
> > +		err = -ENODATA;
> > +		break;
> > +	default:
> > +		err = -EINVAL;
> > +	}
> > +
> > +	return err;
> > +}
> 
> Please don't reimplement this. Instead make the existing function
> global.
> 

OK, I will make the function to global.

> [...]
> 
> > +static void *load_wake_key_data(unsigned long *datasize)
> > +{
> > +	u32 attr;
> > +	void *wkey_data;
> > +	efi_status_t status;
> > +
> > +	if (!efi_enabled(EFI_RUNTIME_SERVICES))
> > +		return ERR_PTR(-EPERM);
> > +
> > +	/* obtain the size */
> > +	*datasize = 0;
> > +	status = efi.get_variable(EFI_S4_WAKE_KEY_NAME, &EFI_HIBERNATE_GUID,
> > +				  NULL, datasize, NULL);
> > +	if (status != EFI_BUFFER_TOO_SMALL) {
> > +		wkey_data = ERR_PTR(efi_status_to_err(status));
> > +		pr_err("PM: Couldn't get wake key data size: 0x%lx\n", status);
> > +		goto error;
> > +	}
> 
> Is it safe to completely bypass the efivars interface and access
> efi.get_variable() directly? I wouldn't have thought so, unless you can
> guarantee that the kernel isn't going to access any of the EFI runtime
> services while you execute this function.
> 

This S4WakeKey is a VOLATILE variable that could not modify by
SetVariable() at runtime. So, it's read only even through efivars. 

Does it what your concern?


Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-09-05 10:13     ` joeyli
@ 2013-09-05 10:31       ` Matt Fleming
  2013-09-05 13:28         ` joeyli
  0 siblings, 1 reply; 61+ messages in thread
From: Matt Fleming @ 2013-09-05 10:31 UTC (permalink / raw)
  To: joeyli
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Takashi Iwai

On Thu, 05 Sep, at 06:13:36PM, joeyli wrote:
> This S4WakeKey is a VOLATILE variable that could not modify by
> SetVariable() at runtime. So, it's read only even through efivars. 
> 
> Does it what your concern?
 
No, the UEFI spec probibits certain runtime functions from being
executed concurrently on separate cpus and the spinlock used in the
efivars code ensures that we adhere to that restriction. See table 31 in
section 7.1 of the UEFI 2.4 spec for the list of services that are
non-reentrant.

The problem isn't that we want to avoid simultaneous access to
S4WakeKey, it's that we can't invoke any of the variable runtime service
functions concurrently.

-- 
Matt Fleming, Intel Open Source Technology Center

^ permalink raw reply	[flat|nested] 61+ messages in thread

* Re: [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot
  2013-09-05 10:31       ` Matt Fleming
@ 2013-09-05 13:28         ` joeyli
  0 siblings, 0 replies; 61+ messages in thread
From: joeyli @ 2013-09-05 13:28 UTC (permalink / raw)
  To: Matt Fleming
  Cc: linux-kernel, linux-security-module, linux-efi, linux-pm,
	linux-crypto, opensuse-kernel, David Howells, Rafael J. Wysocki,
	Matthew Garrett, Len Brown, Pavel Machek, Josh Boyer,
	Vojtech Pavlik, Matt Fleming, James Bottomley, Greg KH, JKosina,
	Rusty Russell, Herbert Xu, David S. Miller, H. Peter Anvin,
	Michal Marek, Gary Lin, Vivek Goyal, Takashi Iwai

於 四,2013-09-05 於 11:31 +0100,Matt Fleming 提到:
> On Thu, 05 Sep, at 06:13:36PM, joeyli wrote:
> > This S4WakeKey is a VOLATILE variable that could not modify by
> > SetVariable() at runtime. So, it's read only even through efivars. 
> > 
> > Does it what your concern?
>  
> No, the UEFI spec probibits certain runtime functions from being
> executed concurrently on separate cpus and the spinlock used in the
> efivars code ensures that we adhere to that restriction. See table 31 in
> section 7.1 of the UEFI 2.4 spec for the list of services that are
> non-reentrant.
> 
> The problem isn't that we want to avoid simultaneous access to
> S4WakeKey, it's that we can't invoke any of the variable runtime service
> functions concurrently.
> 

I see! I will use efivar api to access EFI variable.

Thanks a lot!
Joey Lee


^ permalink raw reply	[flat|nested] 61+ messages in thread

end of thread, other threads:[~2013-09-05 13:28 UTC | newest]

Thread overview: 61+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-22 11:01 [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Lee, Chun-Yi
2013-08-22 11:01 ` [PATCH 01/18] asymmetric keys: add interface and skeleton for implement signature generation Lee, Chun-Yi
2013-08-22 11:01 ` [PATCH 02/18] asymmetric keys: implement EMSA_PKCS1-v1_5-ENCODE in rsa Lee, Chun-Yi
2013-08-25 15:53   ` Pavel Machek
2013-08-26 10:17     ` joeyli
2013-08-22 11:01 ` [PATCH 03/18] asymmetric keys: separate the length checking of octet string from RSA_I2OSP Lee, Chun-Yi
2013-08-25 16:01   ` Pavel Machek
2013-08-26 10:25     ` joeyli
2013-08-26 11:27       ` Pavel Machek
2013-08-27  8:36         ` Jiri Kosina
2013-08-22 11:01 ` [PATCH 04/18] asymmetric keys: implement OS2IP in rsa Lee, Chun-Yi
2013-08-22 11:01 ` [PATCH 05/18] asymmetric keys: implement RSASP1 Lee, Chun-Yi
2013-08-22 11:01 ` [PATCH 06/18] asymmetric keys: support parsing PKCS #8 private key information Lee, Chun-Yi
2013-08-25 16:10   ` Pavel Machek
2013-08-22 11:01 ` [PATCH 07/18] asymmetric keys: explicitly add the leading zero byte to encoded message Lee, Chun-Yi
2013-08-25 16:13   ` Pavel Machek
2013-08-22 11:01 ` [PATCH 08/18] Secure boot: Add new capability Lee, Chun-Yi
2013-08-25 16:14   ` Pavel Machek
2013-08-22 11:01 ` [PATCH 09/18] Secure boot: Add a dummy kernel parameter that will switch on Secure Boot mode Lee, Chun-Yi
2013-08-25 16:16   ` Pavel Machek
2013-08-22 11:01 ` [PATCH 10/18] efi: Enable secure boot lockdown automatically when enabled in firmware Lee, Chun-Yi
2013-08-25 16:22   ` Pavel Machek
2013-08-25 16:26     ` Matthew Garrett
2013-09-03 10:49   ` Matt Fleming
2013-08-22 11:01 ` [PATCH 11/18] Hibernate: introduced RSA key-pair to verify signature of snapshot Lee, Chun-Yi
2013-08-25 16:25   ` Pavel Machek
2013-08-27  9:04     ` joeyli
2013-08-27 11:29       ` Pavel Machek
2013-08-27 12:01         ` Manfred Hollstein
2013-08-27 14:17           ` Pavel Machek
2013-08-27 13:12         ` joeyli
2013-09-05  8:53   ` Matt Fleming
2013-09-05 10:13     ` joeyli
2013-09-05 10:31       ` Matt Fleming
2013-09-05 13:28         ` joeyli
2013-08-22 11:01 ` [PATCH 12/18] Hibernate: generate and " Lee, Chun-Yi
2013-08-25 16:36   ` Pavel Machek
2013-08-27  3:22     ` joeyli
2013-08-22 11:01 ` [PATCH 13/18] Hibernate: Avoid S4 sign key data included in snapshot image Lee, Chun-Yi
2013-08-25 16:39   ` Pavel Machek
2013-08-27  8:33     ` joeyli
2013-08-22 11:01 ` [PATCH 14/18] Hibernate: applied SNAPSHOT_VERIFICATION config to switch signature check Lee, Chun-Yi
2013-08-22 11:01 ` [PATCH 15/18] Hibernate: adapt to UEFI secure boot with " Lee, Chun-Yi
2013-08-25 16:42   ` Pavel Machek
2013-08-27 10:14     ` joeyli
2013-08-22 11:01 ` [PATCH 16/18] Hibernate: show the verification time for monitor performance Lee, Chun-Yi
2013-08-22 11:01 ` [PATCH 17/18] Hibernate: introduced SNAPSHOT_SIG_HASH config for select hash algorithm Lee, Chun-Yi
2013-08-25 16:43   ` Pavel Machek
2013-08-27 10:22     ` joeyli
2013-08-27 11:30       ` Pavel Machek
2013-08-27 12:54         ` joeyli
2013-08-22 11:01 ` [PATCH 18/18] Hibernate: notify bootloader regenerate key-pair for snapshot verification Lee, Chun-Yi
2013-08-28 21:01 ` [RFC PATCH 00/18 v3] Signature verification of hibernate snapshot Florian Weimer
2013-08-29  0:01   ` joeyli
2013-08-29 21:32     ` Pavel Machek
2013-08-29 22:30       ` joeyli
2013-09-01 10:41     ` Florian Weimer
2013-09-01 16:04       ` Matthew Garrett
2013-09-01 16:40         ` Florian Weimer
2013-09-01 16:46           ` Matthew Garrett
2013-09-02  2:12           ` joeyli

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).