[opensuse-kernel] [PATCH 00/18 v3] Signature verification of hibernate snapshot
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 -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
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 -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
participants (1)
-
Lee, Chun-Yi