[opensuse-kernel] [RFC V4 PATCH 00/15] 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 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 CONFIG_SNAPSHOT_VERIFICATION kernel config to enable. And you can also choice which hash algorithm should snapshot be signed with. Then rebuild kernel. This function depends on EFI_STUB. 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. The default behavior is taint kernel when signature check fail. If you want direct fail whole hibernate snapshot restore procedure when signature check does not pass, please use snapshot_sig_enforce kernel parameter or CONFIG_EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE config. If you want binding UEF secure boot with sig_enforce flag, then you can use CONFIG_EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE config. The sig_enforce flag will auto enabled when UEFI secure boot enabled. Behavior ========= The RSA key-pair are generated by EFI bootloader(e.g. shim) in UEFI secure boot environment, then put private key to S4SignKey, public key to S4WakeKey EFI variable. Kernel's behavior as following: + First, EFI stub 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 stub kernel will load the S4SignKey blob to RAM before ExitBootServices, then copy to a memory page that's maintained by hibernate_key.c. This private key will be used to sign snapshot when hibernate launched. + When sig_enforce flag set to TRUE, means force check verification pass: - If kernel didn't find S4 key-pair, then kernel will block hibernate functions including kernel space and userspace hibernate. - If snapshot signature check fail when hibernate resume, the snapshot restore procedure will fail and running normal boot process. + When sig_enforce flag set to FALSE, means not force the verification pass: - If kernel didn't find S4 key-pair, then the hibernate function still available. But kernel will be tainted after hibernate resume. - If snapshot signature check fail when hibernate resume, the snapshot restore procedure will allow continue. But kernel will be tainted. On EFI bootloader side, the behavior as following: + EFI bootloader must generate RSA key-pair when: - First time boot, bootloader generate key-pair when didn't find it. - Bootloader need re-generate after found GenS4Key efi variable from OS: GenS4Key-fe141863-c070-478e-b8a3-878a5dc9ef21 [Runtime][Non-Volatile] The size of GenS4Key is 1 byte, OS(kernel or userland tool) will set it to "1" for notify efi bootloader regenerate key-pair. - If re-generate key-pair, bootloader need store the new public key to EFI bootservices variable by itself, e.g. store to NextWakeKey variable When system resumed from hibernate, bootloader need copy public key from NextWakeKey to S4WakeKey, then kernel will use it to verify snapshot image. 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, It Base on Matthew Garrett's 2 patches in "[PATCH] Add additional security checks when module loading is restricted" series: https://lkml.org/lkml/2013/8/19/331 [PATCH 01/10] Add secure_modules() call [PATCH V3 11/11] Add option to automatically enforce module signatures when in Secure Boot mode Please help review this RFC patchset! Appreciate for any comments! V4: - Cleaned source code, use helper functions to reduce #ifdef chunk. - Introduced sig_enforce flag, taint kernel when signature check fail. - Use forward_info structure to maintain the empty of forward information and new sign key from boot kernel to resume target kernel. - Use efivar API to access S4WakeKey variable. - Call set_key_regen_flag() to set key-pair regeneration flag in hibernate.c and user.c 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 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: taint kernel when signature check fail 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 Hibernate: adapt to UEFI secure boot with signature check Documentation/kernel-parameters.txt | 7 + arch/x86/Kconfig | 11 + arch/x86/boot/compressed/eboot.c | 92 +++++++ arch/x86/include/asm/efi.h | 9 + arch/x86/include/uapi/asm/bootparam.h | 1 + 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 | 296 +++++++++++++++++++- crypto/asymmetric_keys/signature.c | 28 ++ include/crypto/public_key.h | 28 ++ include/keys/asymmetric-subtype.h | 6 + include/linux/efi.h | 25 ++ include/linux/kernel.h | 1 + include/linux/suspend.h | 7 + kernel/panic.c | 2 + kernel/power/Kconfig | 77 +++++- kernel/power/Makefile | 1 + kernel/power/hibernate.c | 23 ++- kernel/power/hibernate_keys.c | 410 ++++++++++++++++++++++++++++ kernel/power/main.c | 7 +- kernel/power/power.h | 62 +++++ kernel/power/snapshot.c | 323 ++++++++++++++++++++++- kernel/power/swap.c | 4 + kernel/power/user.c | 14 +- 33 files changed, 1946 insertions(+), 22 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
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.
The naming of EMSA_PKCS1_v1_5_ENCODE and the variables used in this function
accord PKCS#1 spec but not follow kernel naming convention, it useful when look
at them with spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt
Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
V2:
- Clean up naming of variable: replace _EM by EM, replace EM by EM_tmp.
- Add comment to EMSA_PKCS1-v1_5-ENCODE function.
Cc: Pavel Machek
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.
The naming of _RSA_I2OSP and the variables used in this function accord PKCS#1
spec but not follow kernel naming convention, it useful when look at them with
spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt
Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
Cc: Pavel Machek
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.
The naming of RSA_OS2IP and the variables used in this function accord PKCS#1
spec but not follow kernel naming convention, it useful when look at them with
spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt
Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
Cc: Pavel Machek
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).
The naming of RSASP1 and the variables used in this function accord PKCS#1
spec but not follow kernel naming convention, it useful when look at them with
spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt
Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
Cc: Pavel Machek
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
v2:
- Removed bitfield declare of privkey_algo in struct pkcs8_info because it does
not help on reduce memory space.
- Replace privkey_algo by pkey_algo in struct pkcs8_info to simplify naming.
Cc: Pavel Machek
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.
V2:
- Check the memory allocate result of EM to avoid use it when allocate fail.
Cc: Pavel Machek
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 [BOOT SERVICES][NV]
S4WakeKey-fe141863-c070-478e-b8a3-878a5dc9ef21 [RUNTIME SERVICES][V]
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 parse the RSA public key that packaged by X.509
certificate, kernel will read and parse 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.
V4:
- Removed duplicate cast of params->hdr.setup_data
- Declare dummy function of setup_s4_keys() and efi_reserve_s4_skey_data() to
avoid ifdef.
- Use forward_info structure to maintain the empty of forward information and
new sign key from boot kernel to resume target kernel.
- Use efivar API to access S4WakeKey variable.
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
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.
v3:
- Change the naming of SIG_LENG to SIG_LEN
- Extracts the code of signature generation code from copy_data_pages() to
swsusp_generate_signature(), call it in swsusp_save() after copy_data_pages()
finished.
- Change the naming of h_buf to handle_buffers.
- Removed duplicate code in snapshot_verify_signature() and
snapshot_image_verify().
- Merged [PATCH 14/18]
Hibernate: applied SNAPSHOT_VERIFICATION config to switch signature check
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
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
We will not direct fail the hibernate snapshot restore when the
signature check fail, instead kernel will complain by warning
message and taint kernel.
This patch also introduced a sig_enforce flag to indicate if we want
direct fail the snapshot restore when signature check fail. User can
enable it through snapshot_sig_enforce parameter or
EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE.
Signed-off-by: Lee, Chun-Yi
Show the verification time for monitor the performance of SHA256 and RSA
verification.
Reviewed-by: Jiri Kosina
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
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.
V4:
- Use efivar API to access GenS4Key variable.
- Call set_key_regen_flag() in hibernate.c and user.c
Cc: Matthew Garrett
Base on Matthew Garrett's 2 patches in
"[PATCH] Add additional security checks when module loading is restricted" series
[PATCH 01/10] Add secure_modules() call
[PATCH V3 11/11] Add option to automatically enforce module signatures when in Secure Boot mode
This patch introduced EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE kernel config, it's
provide user to binding UEFI secure boot with SIG_ENFORCE flag of hibernate.
In current solution, the snapshot signature check used the RSA key-pair
that are generated by bootloader(e.g. shim) then pass the key-pair to
kernel through EFI variables. Simply say: The root of trust is base on
UEFI secure boot enabled. So, that makes sense to binding the snapshot
signature check mechanism with UEFI secure boot for provide stronger
protection of hibernate. The behavior when enabled
EFI_SECURE_BOOT_SNAPSHOT_SIG_ENFORCE as following:
+ UEFI Secure Boot ON (means SIG_ENFORCE on),
and Kernel found key-pair from bootloader:
Will do the S4 signature check.
+ UEFI Secure Boot ON, (SIG_ENFORCE on)
but Kernel didn't find key-pair from shim:
Will lock down S4 function.
+ UEFI Secure Boot OFF (means SIG_ENFORCE off)
taint kernel when signature check fail or didn't find key-pair.
V3:
Use helper function secure_hibernate() to reduce ifdef block.
V2:
Replace sign_key_data_loaded() by skey_data_available() to check sign key data
is available for hibernate.
Reviewed-by: Jiri Kosina
Hello,
On Sat, Sep 14, 2013 at 7:56 PM, 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.
The naming of EMSA_PKCS1_v1_5_ENCODE and the variables used in this function accord PKCS#1 spec but not follow kernel naming convention, it useful when look at them with spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
V2: - Clean up naming of variable: replace _EM by EM, replace EM by EM_tmp. - Add comment to EMSA_PKCS1-v1_5-ENCODE function.
Cc: Pavel Machek
Reviewed-by: Jiri Kosina Signed-off-by: Lee, Chun-Yi --- crypto/asymmetric_keys/rsa.c | 163 +++++++++++++++++++++++++++++++++++++++++- include/crypto/public_key.h | 2 + 2 files changed, 164 insertions(+), 1 deletions(-) diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c index 47f3be4..352ba45 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -13,6 +13,7 @@ #include
#include #include +#include #include "public_key.h" #include "private_key.h" @@ -152,6 +153,132 @@ 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, an octet string + * @emLen: intended length in octets of the encoded message + * @hash_algo: hash function (option) + * @hash: true means hash M, otherwise M is already a digest + * @EM: encoded message, an octet string of length emLen + * + * This function is a implementation of the EMSA-PKCS1-v1_5 encoding operation + * in RSA PKCS#1 spec. It used by the signautre generation operation of + * RSASSA-PKCS1-v1_5 to encode message M to encoded message EM. + * + * The variables used in this function accord PKCS#1 spec but not follow kernel + * naming convention, it useful when look at them with spec. + */ +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_tmp; + int i, ret; + + pr_info("EMSA_PKCS1_v1_5_ENCODE start\n"); + + if (!RSA_ASN1_templates[hash_algo].data)
What about checking hash_algo against PKEY_HASH__LAST, or it relies on the caller?
+ 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; +
Ok. You allocated tfm to get hash size, right? But why do you allocate descriptor even it might not be needed?
+ 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);
This is I completely fail to understand... You expect sizeof(M) to be the message length????? Have you ever tested it?
+ if (ret < 0) + goto error_shash; + } else { + memcpy(pks->digest, M, pks->digest_size); + pks->digest_size = digest_size; + }
Does caller use pks->digest and pks->digest_size after return? I think it needs encoded value, not the hash... So why do you pass pks?
+ 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; +
Why do you need T and PS memory allocations at all? You need only EM_tmp allocation and copy directly to the destination...
+ 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; +
ditto
+ 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_tmp = kmalloc(3 + emLen - tLen - 3 + tLen, GFP_KERNEL); + if (!EM_tmp) + goto error_EM; + + EM_tmp[0] = 0x00; + EM_tmp[1] = 0x01; + memcpy(EM_tmp + 2, PS, emLen - tLen - 3); + EM_tmp[2 + emLen - tLen - 3] = 0x00; + memcpy(EM_tmp + 2 + emLen - tLen - 3 + 1, T, tLen); + + *EM = EM_tmp; + + kfree(PS); + kfree(T);
get rid of it... - Dmitry
+ + 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 +402,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) { + struct public_key_signature *pks; + u8 *EM = NULL; + size_t emLen; + int ret; + pr_info("RSA_generate_signature start\n");
- return 0; + 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.0.2
-- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- Thanks, Dmitry -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Sat, Sep 14, 2013 at 7:56 PM, 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.
The naming of EMSA_PKCS1_v1_5_ENCODE and the variables used in this function accord PKCS#1 spec but not follow kernel naming convention, it useful when look at them with spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
V2: - Clean up naming of variable: replace _EM by EM, replace EM by EM_tmp. - Add comment to EMSA_PKCS1-v1_5-ENCODE function.
Cc: Pavel Machek
Reviewed-by: Jiri Kosina Signed-off-by: Lee, Chun-Yi --- crypto/asymmetric_keys/rsa.c | 163 +++++++++++++++++++++++++++++++++++++++++- include/crypto/public_key.h | 2 + 2 files changed, 164 insertions(+), 1 deletions(-) diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c index 47f3be4..352ba45 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -13,6 +13,7 @@ #include
#include #include +#include #include "public_key.h" #include "private_key.h" @@ -152,6 +153,132 @@ 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, an octet string + * @emLen: intended length in octets of the encoded message + * @hash_algo: hash function (option) + * @hash: true means hash M, otherwise M is already a digest + * @EM: encoded message, an octet string of length emLen + * + * This function is a implementation of the EMSA-PKCS1-v1_5 encoding operation + * in RSA PKCS#1 spec. It used by the signautre generation operation of + * RSASSA-PKCS1-v1_5 to encode message M to encoded message EM. + * + * The variables used in this function accord PKCS#1 spec but not follow kernel + * naming convention, it useful when look at them with spec. + */ +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_tmp; + 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; +
as I said, remove it... see bellow....
+ 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; + as I said remove it... see bellow..
+ for (i = 0; i < (emLen - tLen - 3); i++) + PS[i] = 0xff; +
memset() does not work here?
+ /* 5) Concatenate PS, the DER encoding T, and other padding to form the encoded + * message EM as EM = 0x00 || 0x01 || PS || 0x00 || T + */ + EM_tmp = kmalloc(3 + emLen - tLen - 3 + tLen, GFP_KERNEL); + if (!EM_tmp) + goto error_EM; + + EM_tmp[0] = 0x00; + EM_tmp[1] = 0x01;
+ memcpy(EM_tmp + 2, PS, emLen - tLen - 3); + EM_tmp[2 + emLen - tLen - 3] = 0x00;
above 2 lines can be replaced by: PS = &EM_tmp[2]; PS_len = emLen - tLen - 3 memset(PS, 0xff, PS_len); EM_tmp[2 + PS_len] = 0x00;
+ memcpy(EM_tmp + 2 + emLen - tLen - 3 + 1, T, tLen); + This can be replaced by:
T = &EM_tmp[2+ PS_Len + 1]; 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);
+ *EM = EM_tmp; + + kfree(PS); + kfree(T); +
Right? So please remove unneeded allocations... Dmitry
+ 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 +402,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) { + struct public_key_signature *pks; + u8 *EM = NULL; + size_t emLen; + int ret; + pr_info("RSA_generate_signature start\n");
- return 0; + 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.0.2
-- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
-- Thanks, Dmitry -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Hi Dmitry, First, thanks for your time to review my patches! 於 二,2013-09-17 於 16:51 -0500,Dmitry Kasatkin 提到:
Hello,
On Sat, Sep 14, 2013 at 7:56 PM, 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).
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.
The naming of EMSA_PKCS1_v1_5_ENCODE and the variables used in this function accord PKCS#1 spec but not follow kernel naming convention, it useful when look at them with spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
V2: - Clean up naming of variable: replace _EM by EM, replace EM by EM_tmp. - Add comment to EMSA_PKCS1-v1_5-ENCODE function.
Cc: Pavel Machek
Reviewed-by: Jiri Kosina Signed-off-by: Lee, Chun-Yi --- crypto/asymmetric_keys/rsa.c | 163 +++++++++++++++++++++++++++++++++++++++++- include/crypto/public_key.h | 2 + 2 files changed, 164 insertions(+), 1 deletions(-) diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c index 47f3be4..352ba45 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -13,6 +13,7 @@ #include
#include #include +#include #include "public_key.h" #include "private_key.h" @@ -152,6 +153,132 @@ 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, an octet string + * @emLen: intended length in octets of the encoded message + * @hash_algo: hash function (option) + * @hash: true means hash M, otherwise M is already a digest + * @EM: encoded message, an octet string of length emLen + * + * This function is a implementation of the EMSA-PKCS1-v1_5 encoding operation + * in RSA PKCS#1 spec. It used by the signautre generation operation of + * RSASSA-PKCS1-v1_5 to encode message M to encoded message EM. + * + * The variables used in this function accord PKCS#1 spec but not follow kernel + * naming convention, it useful when look at them with spec. + */ +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_tmp; + int i, ret; + + pr_info("EMSA_PKCS1_v1_5_ENCODE start\n"); + + if (!RSA_ASN1_templates[hash_algo].data)
What about checking hash_algo against PKEY_HASH__LAST, or it relies on the caller?
Yes, check PKEY_HASH__LAST is more easy and clear, I will change it. Thanks!
+ 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; +
Ok. You allocated tfm to get hash size, right?
But why do you allocate descriptor even it might not be needed?
You are right, I should skip the code of allocate descriptor when the hash is supported. I will modified it. Thanks!
+ 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);
This is I completely fail to understand... You expect sizeof(M) to be the message length????? Have you ever tested it?
Sigh! I just checked my test program for this code path, this stupid problem causes by my test program doesn't feed the right hash result that should used to verify signature. So, I didn't capture this bug. And, the hibernate signature check mechanism doesn't run into this code path because the hash generation is done by hibernate code but not in here. So, I also didn't find this problem when running hibernate check. Appreciate for your point out! I just fix it in next patch version.
+ if (ret < 0) + goto error_shash; + } else { + memcpy(pks->digest, M, pks->digest_size); + pks->digest_size = digest_size; + }
Does caller use pks->digest and pks->digest_size after return? I think it needs encoded value, not the hash... So why do you pass pks?
I put the signature MPI to pks->rsa.s, and put the encoded signature to pks->S. So caller can grab encoded signature. I also pass the pks->digest and pks->digest_size to caller for reference. Then caller can simply feed this pks to RSA_verify_signature() for verify the signature result, don't need generate hash again.
+ 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; +
Why do you need T and PS memory allocations at all? You need only EM_tmp allocation and copy directly to the destination...
OK, I will change the code to allocate T and PS size in EM_tmp.
+ 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; +
ditto
OK, I will allocate PS with EM_tmp. Thanks!
+ 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_tmp = kmalloc(3 + emLen - tLen - 3 + tLen, GFP_KERNEL); + if (!EM_tmp) + goto error_EM; + + EM_tmp[0] = 0x00; + EM_tmp[1] = 0x01; + memcpy(EM_tmp + 2, PS, emLen - tLen - 3); + EM_tmp[2 + emLen - tLen - 3] = 0x00; + memcpy(EM_tmp + 2 + emLen - tLen - 3 + 1, T, tLen); + + *EM = EM_tmp; + + kfree(PS); + kfree(T);
get rid of it...
OK!
- Dmitry
+ + 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 +402,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) { + struct public_key_signature *pks; + u8 *EM = NULL; + size_t emLen; + int ret; + pr_info("RSA_generate_signature start\n");
- return 0; + 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.0.2
-- To unsubscribe from this list: send the line "unsubscribe linux-crypto" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Sun 2013-09-15 08:56:59, 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.
This series is big enough already... and who is going to test it? There's no need to make hash configurable. Just select one that works. Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Sun, Sep 15, 2013 at 08:56:48AM +0800, 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).
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.
The naming of EMSA_PKCS1_v1_5_ENCODE and the variables used in this function accord PKCS#1 spec but not follow kernel naming convention, it useful when look at them with spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
V2:
You're now at V4.
- Clean up naming of variable: replace _EM by EM, replace EM by EM_tmp. - Add comment to EMSA_PKCS1-v1_5-ENCODE function.
Cc: Pavel Machek
Reviewed-by: Jiri Kosina Signed-off-by: Lee, Chun-Yi --- crypto/asymmetric_keys/rsa.c | 163 +++++++++++++++++++++++++++++++++++++++++- include/crypto/public_key.h | 2 + 2 files changed, 164 insertions(+), 1 deletions(-) diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c index 47f3be4..352ba45 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -13,6 +13,7 @@ #include
#include #include +#include #include "public_key.h" #include "private_key.h" @@ -152,6 +153,132 @@ 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, an octet string + * @emLen: intended length in octets of the encoded message + * @hash_algo: hash function (option) + * @hash: true means hash M, otherwise M is already a digest + * @EM: encoded message, an octet string of length emLen + * + * This function is a implementation of the EMSA-PKCS1-v1_5 encoding operation + * in RSA PKCS#1 spec. It used by the signautre generation operation of + * RSASSA-PKCS1-v1_5 to encode message M to encoded message EM. + * + * The variables used in this function accord PKCS#1 spec but not follow kernel + * naming convention, it useful when look at them with spec. + */ +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_tmp; + 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;
The earlier "ret = -ENOTSUPP;" is either unused because you return at the IS_ERR, or unused because you overwrite it here. I'm a little disappointed that the compiler didn't recognise that something was assigned to a value that is never used. Phil
+ + 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_tmp = kmalloc(3 + emLen - tLen - 3 + tLen, GFP_KERNEL); + if (!EM_tmp) + goto error_EM; + + EM_tmp[0] = 0x00; + EM_tmp[1] = 0x01; + memcpy(EM_tmp + 2, PS, emLen - tLen - 3); + EM_tmp[2 + emLen - tLen - 3] = 0x00; + memcpy(EM_tmp + 2 + emLen - tLen - 3 + 1, T, tLen); + + *EM = EM_tmp; + + 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 +402,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) { + struct public_key_signature *pks; + u8 *EM = NULL; + size_t emLen; + int ret; + pr_info("RSA_generate_signature start\n");
- return 0; + 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.0.2
-- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
-- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
I have pushed some keyrings patches that will likely affect this to: http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key... I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them. It'd be helpful if you could see if you need to make any updates. David -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference: Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations. Alan Stern -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Wed, 2013-09-25 at 17:25 -0400, Alan Stern wrote:
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
The reason is the desire to validate that the previous kernel created something which it passed on to the current kernel (in this case, the hibernation image) untampered with. To do that, something must be passed to the prior kernel that can be validated but *not* recreated by the current kernel. The scheme for doing this is a public/private key pair generated for each boot incarnation N as a pair P_N (public key) and K_N (private key). Then the Nth boot incarnation gets P_{N-1} and K_N (the boot environment holds P_N in inaccessible BS variables for passing into the next kernel) so the Nth kernel can validate information from the N-1th kernel using P_{N-1} and create information for passing on in a validated fashion to the next kernel using K_N. This scheme doesn't work with symmetric keys unless you have a modification I haven't seen? James -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Wed 2013-09-25 15:16:54, James Bottomley wrote:
On Wed, 2013-09-25 at 17:25 -0400, Alan Stern wrote:
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
The reason is the desire to validate that the previous kernel created something which it passed on to the current kernel (in this case, the hibernation image) untampered with. To do that, something must be passed to the prior kernel that can be validated but *not* recreated by the current kernel.
I don't get this. Why is it important that current kernel can't recreate the signature? Current kernel is not considered malicious (if it were, you have worse problems). Pavel PS: And yes, it would be nice to have Documentation/power/swsusp-uefi.txt (or something) explaining the design. -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Wed, 25 Sep 2013, James Bottomley wrote:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
The reason is the desire to validate that the previous kernel created something which it passed on to the current kernel (in this case, the hibernation image) untampered with. To do that, something must be passed to the prior kernel that can be validated but *not* recreated by the current kernel.
As Pavel pointed out, this seems like a futile approach. If the current kernel is going to do the validating, then of course it can create something that it will validate. Or to put it another way, how come you don't trust the current kernel not to modify the image but you do trust it to validate the image?
The scheme for doing this is a public/private key pair generated for each boot incarnation N as a pair P_N (public key) and K_N (private key). Then the Nth boot incarnation gets P_{N-1} and K_N (the boot
Where does it get them from? Some place in the firmware, presumably.
environment holds P_N in inaccessible BS variables for passing into the next kernel) so the Nth kernel can validate information from the N-1th kernel using P_{N-1} and create information for passing on in a validated fashion to the next kernel using K_N.
So kernel N gets P_{N-1} and an image that has been signed by K_{N-1}. What's to prevent kernel N from creating a bogus pair of keys (K',P') and a bogus image, signing that image with K', and then pretending it got P' from the firmware instead of P_{N-1}? However... Let's assume that you _do_ trust kernel N. Then consider this alternative approach: A symmetric key S_N is created for boot incarnation N. Kernel N receives S_{N-1} from the firmware and uses it to verify the signature attached to the hibernation image. When kernel N wants to create the next hibernation image, it signs the image with S_N (also obtained from the firmware).
This scheme doesn't work with symmetric keys unless you have a modification I haven't seen?
Obviously these two schemes are different. Do these differences have any security implications? Alan Stern -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 三,2013-09-25 於 22:04 +0100,David Howells 提到:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
Thanks for your point out, I will respin my asymmetric keys patch base on this tree.
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
It'd be helpful if you could see if you need to make any updates.
David
In LPC, Alan and Vojtech raised another thinking is using symmetric key to protect the hash of snapshot. It's simpler then using RSA private key to sign it. Even finally we use the symmetric key solution, I will still respin and resent the patch for add the leading zero byte: [PATCH V4 07/15] asymmetric keys: explicitly add the leading zero byte to encoded message I think keys-devel tree need it. Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 三,2013-09-18 於 15:45 +0200,Pavel Machek 提到:
On Sun 2013-09-15 08:56:59, 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.
This series is big enough already... and who is going to test it?
The hash config not just for testing, it's relate to the performance and secure between different hash algorithms. There have person raised in LPC say he don't like SHA algorithm.
There's no need to make hash configurable. Just select one that works.
Pavel
SHA1 has good performance, and SHA512 has better security, which one you like it? Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 三,2013-09-25 於 17:25 -0400,Alan Stern 提到:
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
Alan Stern
Per my understood, it's like add salt to snapshot when generate signature, then remove the salt when store the snapshot to swap. (or pass snapshot to userland). Let me explain the symmetric key solution base on my understand: + EFI stub kernel generate a hash value from a random seed, then store it to EFi boot varaible. It should protected by UEFI secure boot environment. + When hibernate launched: - Kernel create the snapshot image of memory. It's included the random hash value(salt) that generated in EFI stub stage. - Then kernel hash the snapshot image, put the hash to snapshot header, just like current asymmetric keys solution. - Kernel erase the salt in snapshot image before it go to swap or pass to userspace tool. + When hibernate resume: - Kernel or userspace tool load the snapshot(without salt) from swap to temporary memory space. - Kernel fill the salt back to snapshot image in memory, hash it. - Kernel compare the hash with the hash that put in snapshot header. - Verification done! The follow-up action as current solution. Please current me if I missed anything. Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Thu, 2013-09-26 at 02:27 +0200, Pavel Machek wrote:
On Wed 2013-09-25 15:16:54, James Bottomley wrote:
On Wed, 2013-09-25 at 17:25 -0400, Alan Stern wrote:
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
The reason is the desire to validate that the previous kernel created something which it passed on to the current kernel (in this case, the hibernation image) untampered with. To do that, something must be passed to the prior kernel that can be validated but *not* recreated by the current kernel.
I don't get this. Why is it important that current kernel can't recreate the signature?
The thread model is an attack on the saved information (i.e. the suspend image) between it being saved by the old kernel and used by the new one. The important point isn't that the new kernel doesn't have access to K_{N-1} it's that no-one does: the key is destroyed as soon as the old kernel terminates however the verification public part P_{N-1} survives. James
Current kernel is not considered malicious (if it were, you have worse problems).
Pavel
PS: And yes, it would be nice to have Documentation/power/swsusp-uefi.txt (or something) explaining the design.
-- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 四,2013-09-26 於 02:27 +0200,Pavel Machek 提到:
On Wed 2013-09-25 15:16:54, James Bottomley wrote:
On Wed, 2013-09-25 at 17:25 -0400, Alan Stern wrote:
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
The reason is the desire to validate that the previous kernel created something which it passed on to the current kernel (in this case, the hibernation image) untampered with. To do that, something must be passed to the prior kernel that can be validated but *not* recreated by the current kernel.
I don't get this. Why is it important that current kernel can't recreate the signature?
Current kernel is not considered malicious (if it were, you have worse problems).
Current boot kernel should not malicious especially when UEFI secure boot enabled.
Pavel
PS: And yes, it would be nice to have Documentation/power/swsusp-uefi.txt (or something) explaining the design.
Thanks for your suggestion, I will write the swsusp-uefi.txt to explaining the design in next version. Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Wed, 25 Sep 2013, James Bottomley wrote:
I don't get this. Why is it important that current kernel can't recreate the signature?
The thread model is an attack on the saved information (i.e. the suspend image) between it being saved by the old kernel and used by the new one. The important point isn't that the new kernel doesn't have access to K_{N-1} it's that no-one does: the key is destroyed as soon as the old kernel terminates however the verification public part P_{N-1} survives.
James, could you please describe the exact scenario you think that the symmetric keys aproach doesn't protect against, while the assymetric key aproach does? The crucial points, which I believe make the symmetric key aproach work (and I feel quite embarassed by the fact that I haven't realized this initially when coming up with the assymetric keys aproach) are: - the kernel that is performing the actual resumption is trusted in the secure boot model, i.e. you trust it to perform proper verification - potentially malicious userspace (which is what we are protecting against -- malicious root creating fake hibernation image and issuing reboot) doesn't have access to the symmetric key -- Jiri Kosina SUSE Labs -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Hi Phil, First! Thanks for your time to review my patch! 於 一,2013-09-23 於 19:49 +0300,Phil Carmody 提到:
On Sun, Sep 15, 2013 at 08:56:48AM +0800, 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).
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.
The naming of EMSA_PKCS1_v1_5_ENCODE and the variables used in this function accord PKCS#1 spec but not follow kernel naming convention, it useful when look at them with spec.
Reference: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1v2/pkcs1ietffinal.txt Reference: http://www.emc.com/collateral/white-papers/h11300-pkcs-1v2-2-rsa-cryptograph...
V2:
You're now at V4.
The V4 is for whole patchset, I didn't do any modify in this patch in this version. The version define maybe confuse between separate and whole patchset, I will avoid it.
- Clean up naming of variable: replace _EM by EM, replace EM by EM_tmp. - Add comment to EMSA_PKCS1-v1_5-ENCODE function.
Cc: Pavel Machek
Reviewed-by: Jiri Kosina Signed-off-by: Lee, Chun-Yi --- crypto/asymmetric_keys/rsa.c | 163 +++++++++++++++++++++++++++++++++++++++++- include/crypto/public_key.h | 2 + 2 files changed, 164 insertions(+), 1 deletions(-) diff --git a/crypto/asymmetric_keys/rsa.c b/crypto/asymmetric_keys/rsa.c index 47f3be4..352ba45 100644 --- a/crypto/asymmetric_keys/rsa.c +++ b/crypto/asymmetric_keys/rsa.c @@ -13,6 +13,7 @@ #include
#include #include +#include #include "public_key.h" #include "private_key.h" @@ -152,6 +153,132 @@ 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, an octet string + * @emLen: intended length in octets of the encoded message + * @hash_algo: hash function (option) + * @hash: true means hash M, otherwise M is already a digest + * @EM: encoded message, an octet string of length emLen + * + * This function is a implementation of the EMSA-PKCS1-v1_5 encoding operation + * in RSA PKCS#1 spec. It used by the signautre generation operation of + * RSASSA-PKCS1-v1_5 to encode message M to encoded message EM. + * + * The variables used in this function accord PKCS#1 spec but not follow kernel + * naming convention, it useful when look at them with spec. + */ +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_tmp; + 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;
The earlier "ret = -ENOTSUPP;" is either unused because you return at the IS_ERR, or unused because you overwrite it here. I'm a little disappointed that the compiler didn't recognise that something was assigned to a value that is never used.
Phil
Yes, Dmitry also pointed out this issue, I should not go on the hash process if the hash algorithm didn't support. I will change fix this problem in next version. Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Hi!
On Sun 2013-09-15 08:56:59, 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.
This series is big enough already... and who is going to test it?
The hash config not just for testing, it's relate to the performance and secure between different hash algorithms.
I'm not saying it is for testing. I'm saying that selection makes testing harder.
There have person raised in LPC say he don't like SHA algorithm.
Well, I don't like the config option.
There's no need to make hash configurable. Just select one that works.
SHA1 has good performance, and SHA512 has better security, which one you like it?
Use SHA1. It is completely adequate for what you are trying to do. Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 四,2013-09-26 於 10:19 +0800,joeyli 提到:
於 三,2013-09-25 於 17:25 -0400,Alan Stern 提到:
On Wed, 25 Sep 2013, David Howells wrote:
I have pushed some keyrings patches that will likely affect this to:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=key...
I intend to ask James to pull these into his next branch. If he's happy to do so, I can look at pulling at least your asymmetric keys patch on top of them.
This suggests a point that I raised at the Linux Plumbers conference:
Why are asymmetric keys used for verifying the hibernation image? It seems that a symmetric key would work just as well. And it would be a lot quicker to generate, because it wouldn't need any high-precision integer computations.
Alan Stern
Per my understood, it's like add salt to snapshot when generate signature, then remove the salt when store the snapshot to swap. (or pass snapshot to userland).
Let me explain the symmetric key solution base on my understand:
+ EFI stub kernel generate a hash value from a random seed, then store it to EFi boot varaible. It should protected by UEFI secure boot environment.
+ When hibernate launched: - Kernel create the snapshot image of memory. It's included the random hash value(salt) that generated in EFI stub stage. - Then kernel hash the snapshot image, put the hash to snapshot header, just like current asymmetric keys solution. - Kernel erase the salt in snapshot image before it go to swap or pass to userspace tool.
+ When hibernate resume: - Kernel or userspace tool load the snapshot(without salt) from swap to temporary memory space. - Kernel fill the salt back to snapshot image in memory, hash it. - Kernel compare the hash with the hash that put in snapshot header. - Verification done! The follow-up action as current solution.
Please current me if I missed anything.
Thanks a lot! Joey Lee
For the symmetric key solution, I will try HMAC (Hash Message Authentication Code). It's already used in networking, hope the performance is not too bad to a big image. Thanks Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
Hi!
For the symmetric key solution, I will try HMAC (Hash Message Authentication Code). It's already used in networking, hope the performance is not too bad to a big image.
Kernel already supports crc32 of the hibernation image, you may want to take a look how that is done. Maybe you want to replace crc32 with cryptographics hash (sha1?) and then use only hash for more crypto? That way speed of whatever crypto you do should not be an issue. Actually... Is not it as simple as storing hash of hibernation image into NVRAM and then verifying the hash matches the value in NVRAM on next startup? No encryption needed. And that may even be useful for non-secure-boot people, as it ensures you boot right image after resume, boot it just once, etc... Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On 26.9.2013 14:06, Pavel Machek wrote:
Actually...
Is not it as simple as storing hash of hibernation image into NVRAM and then verifying the hash matches the value in NVRAM on next startup? No encryption needed.
I think that part of the exercise is to minimize the number of writes to the NVRAM. The hash changes with every hibernation, obviously. Michal -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Thu, Sep 26, 2013 at 02:06:21PM +0200, Pavel Machek wrote:
For the symmetric key solution, I will try HMAC (Hash Message Authentication Code). It's already used in networking, hope the performance is not too bad to a big image.
Kernel already supports crc32 of the hibernation image, you may want to take a look how that is done.
Maybe you want to replace crc32 with cryptographics hash (sha1?) and then use only hash for more crypto? That way speed of whatever crypto you do should not be an issue.
Well, yes, one could skip the CRC when the signing is enabled to gain a little speedup.
Actually...
Is not it as simple as storing hash of hibernation image into NVRAM and then verifying the hash matches the value in NVRAM on next startup? No encryption needed.
First, there is no encryption going on. Only doing a HMAC (digest (hash) using a key) of the image. Second, since NVRAM is accessible through efivarsfs, storing the hash in NVRAM wouldn't prevent an attacker from modifying the hash to match a modified image. There is a reason why the key for the HMAC is stored in the NVRAM in a BootServices variable that isn't accessible from the OS and is write-protected on hardware level from the OS.
And that may even be useful for non-secure-boot people, as it ensures you boot right image after resume, boot it just once, etc...
The HMAC approach isn't much more complicated, and it gives you all these benefits even with secure boot disabled. -- Vojtech Pavlik Director SUSE Labs -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Thu, Sep 26, 2013 at 02:21:23PM +0200, Michal Marek wrote:
Is not it as simple as storing hash of hibernation image into NVRAM and then verifying the hash matches the value in NVRAM on next startup? No encryption needed.
I think that part of the exercise is to minimize the number of writes to the NVRAM. The hash changes with every hibernation, obviously.
The key should, too. -- Vojtech Pavlik Director SUSE Labs -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 四,2013-09-26 於 14:06 +0200,Pavel Machek 提到:
Hi!
For the symmetric key solution, I will try HMAC (Hash Message Authentication Code). It's already used in networking, hope the performance is not too bad to a big image.
Kernel already supports crc32 of the hibernation image, you may want to take a look how that is done.
In current kernel design, The crc32 is only for the LZO in-kernel hibernate, doesn't apply to non-compress hibernate and userspace hibernate. Put signature to snapshot header can support any kind of caller that's trigger hibernate. Any userspace hibernate tool will take the snapshot image from kernel, so, we need put the signature(or hash result) to snapshot header before userspace write it to anywhere.
Maybe you want to replace crc32 with cryptographics hash (sha1?) and then use only hash for more crypto? That way speed of whatever crypto you do should not be an issue.
That speed of hash is calculated from non-compress snapshot image, does not overlap with crc32.
Actually...
Is not it as simple as storing hash of hibernation image into NVRAM and then verifying the hash matches the value in NVRAM on next startup? No encryption needed.
And that may even be useful for non-secure-boot people, as it ensures you boot right image after resume, boot it just once, etc...
Pavel
The HMAC approach will not encrypt, just put the key of HMAC to boottime variable. If user doesn't enable UEFI secure boot, that's fine, the key of HMAC still cannot access in OS runtime. If user enable UEFI secure boot, then that's better! Because all EFI file will signed by the manufacturers or OSVs to make sure the code is secure, will not pass the key to runtime. Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
於 四,2013-09-26 於 14:22 +0200,Vojtech Pavlik 提到:
On Thu, Sep 26, 2013 at 02:06:21PM +0200, Pavel Machek wrote:
For the symmetric key solution, I will try HMAC (Hash Message Authentication Code). It's already used in networking, hope the performance is not too bad to a big image.
Kernel already supports crc32 of the hibernation image, you may want to take a look how that is done.
Maybe you want to replace crc32 with cryptographics hash (sha1?) and then use only hash for more crypto? That way speed of whatever crypto you do should not be an issue.
Well, yes, one could skip the CRC when the signing is enabled to gain a little speedup.
In current kernel, CRC is for check the integrity of LZO compressed image, the purpose is different to check the integrity of snapshot image. So, CRC will not in non-compress hibernate or userspace hibernate code path On the other hand, attacker can easily change the CRC code in the header of LZO hibernate image. Thanks a lot! Joey Lee -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Thu, 2013-09-26 at 08:24 +0200, Jiri Kosina wrote:
On Wed, 25 Sep 2013, James Bottomley wrote:
I don't get this. Why is it important that current kernel can't recreate the signature?
The thread model is an attack on the saved information (i.e. the suspend image) between it being saved by the old kernel and used by the new one. The important point isn't that the new kernel doesn't have access to K_{N-1} it's that no-one does: the key is destroyed as soon as the old kernel terminates however the verification public part P_{N-1} survives.
James,
could you please describe the exact scenario you think that the symmetric keys aproach doesn't protect against, while the assymetric key aproach does?
The crucial points, which I believe make the symmetric key aproach work (and I feel quite embarassed by the fact that I haven't realized this initially when coming up with the assymetric keys aproach) are:
- the kernel that is performing the actual resumption is trusted in the secure boot model, i.e. you trust it to perform proper verification
- potentially malicious userspace (which is what we are protecting against -- malicious root creating fake hibernation image and issuing reboot) doesn't have access to the symmetric key
OK, so the scheme is to keep a symmetric key in BS that is passed into the kernel each time (effectively a secret key) for signing and validation? The only two problems I see are 1. The key isn't generational (any compromise obtains it). This can be fixed by using a set of keys generated on each boot and passing in both K_{N-1} and K_N 2. No external agency other than the next kernel can do the validation since the validating key has to be secret The importance of 2 is just tripwire like detection ... perhaps it doesn't really matter in a personal computer situation. It would matter in an enterprise where images are stored and re-used but until servers have UEFI secure boot, that's not going to be an issue. James -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Thu, 26 Sep 2013, James Bottomley wrote:
could you please describe the exact scenario you think that the symmetric keys aproach doesn't protect against, while the assymetric key aproach does?
The crucial points, which I believe make the symmetric key aproach work (and I feel quite embarassed by the fact that I haven't realized this initially when coming up with the assymetric keys aproach) are:
- the kernel that is performing the actual resumption is trusted in the secure boot model, i.e. you trust it to perform proper verification
- potentially malicious userspace (which is what we are protecting against -- malicious root creating fake hibernation image and issuing reboot) doesn't have access to the symmetric key
OK, so the scheme is to keep a symmetric key in BS that is passed into the kernel each time (effectively a secret key) for signing and validation?
Exactly.
The only two problems I see are
1. The key isn't generational (any compromise obtains it). This can be fixed by using a set of keys generated on each boot and passing in both K_{N-1} and K_N
I think this could be easily made optional, leaving the user with choice of faster or "safer" boot.
2. No external agency other than the next kernel can do the validation since the validating key has to be secret
This is true, but as you said, the relevance of this seems to be rather questionable. -- Jiri Kosina SUSE Labs -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Thu, Sep 26, 2013 at 04:48:00PM +0200, Jiri Kosina wrote:
The only two problems I see are
1. The key isn't generational (any compromise obtains it). This can be fixed by using a set of keys generated on each boot and passing in both K_{N-1} and K_N
I think this could be easily made optional, leaving the user with choice of faster or "safer" boot.
Ideally, the key should be regenerated on each true reboot and kept the same if it is just a resume. Unfortunately, I don't see a way to distinguish those before we call ExitBootServices(). The reasoning behind that is that in the case of a kernel compromise, a suspended-and-resumed kernel will still be compromised, so there is no value in passing it a new key. A freshly booted kernel, though, should get a new key, exactly because the attacker could have obtained a key from the previous, compromised one. This speeds up the ususal suspend-and-resume cycle, but provides full security once the user performs a full reboot. The question that remains is how to tell in advance.
2. No external agency other than the next kernel can do the validation since the validating key has to be secret
This is true, but as you said, the relevance of this seems to be rather questionable.
Indeed, it's hard to imagine a scenario that is also valid within the secure boot threat model. -- Vojtech Pavlik Director SUSE Labs -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
On Sunday, September 15, 2013 08:56:46 AM Lee, Chun-Yi wrote:
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 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.
I wonder what the status of this work is? Is it considered ready for inclusion or are you still going to work on it and resubmit? Rafael -- To unsubscribe, e-mail: opensuse-kernel+unsubscribe@opensuse.org To contact the owner, e-mail: opensuse-kernel+owner@opensuse.org
participants (12)
-
Alan Stern
-
David Howells
-
Dmitry Kasatkin
-
James Bottomley
-
Jiri Kosina
-
joeyli
-
Lee, Chun-Yi
-
Michal Marek
-
Pavel Machek
-
Phil Carmody
-
Rafael J. Wysocki
-
Vojtech Pavlik