转自:http://blog.chinaunix.net/uid-27717694-id-3999307.html

sign-file在kernel源代码目录找

一、前言
linux内核从3.7 开始加入模块签名检查机制,如果内核选项CONFIG_MODULE_SIG和CONFIG_MODULE_SIG_FORCE打开的话,当加载模块时内核会检查模块的签名,如果签名不存在或者签名内容不一致,会强制退出模块的加载。所以为模块签名就尤为重要。如果是内核选项CONFIG_MODULE_SIG_ALL打开,内核编译模块时会自动为模块签名。否则就要自己对模块签名。

首先我们就要想到用什么签名工具,因为签名机制从3.7 内核才加入,所以为模块签名的资料少之又少,我找了很长时间也没有头绪,网上说的最多的都是openssl来做签名。所以理所当然的我也使用openssl来做签名,但是它是linux内核之外的工具,就算生成签名,你还要手动添加到模块.ko文件最后,还要设置一些内核要检查的固定结构体(例如:signature_module结构),很是麻烦,并且内核的key你拿不到,用的不是内核的可以签名肯定通不过检查。所以这种方法至少我认为不可行。

后来又开始找别的签名工具,但是都不成功,实验了很长时间。但是偶尔查找资料看到一篇外文资料,关于内核签名的。讲的很详细,原来内核签名工具就在linux内核之中,折腾了半天原来解决方法就在旁边,既兴奋又坑爹。给我的教训就是,查资料的时候尽可能的查英文资料,不得不说确实比国内的资料多而且质量要高。

二、下边就奉上这篇英文资料:

Signed kernel module support

From Gentoo Wiki
Jump to:  navigationsearch

Since Linux kernel version 3.7 onwards, support has been added for signed kernel modules. When enabled, the Linux kernel will only load kernel modules that are digitally signed with the proper key. This allows further hardening of the system by disallowing unsigned kernel modules, or kernel modules signed with the wrong key, to be loaded. Malicious kernel modules are a common method for loading rootkits on a Linux system.

Contents

 [hide

Enabling module signature verification

Enabling support is a matter of toggling a few settings in the Linux kernel configuration. Unless you want to use your own keypair, this is all that has to be done to enable kernel module support.

Configuring module signature verification

Module signature verification is a kernel feature, so has to be enabled through the Linux kernel configuration. You can find the necessary options under Enable loadable module support.

 [Collapse
Kernel configuration Enable module signature verification

--- Enable loadable module support
[*]   Module signature verification
[*]     Require modules to be validly signed
[*]     Automatically sign all modules
      Which hash algorithm should modules be signed with? (Sign modules with SHA-512) --->

The option Module signature verification (CONFIG_MODULE_SIG) enables the module signature verification in the Linux kernel. It supports two approaches on signed module support: a rather permissive one and a strict one. By default, the permissive approach is used, which means that the Linux kernel module either has to have a valid signature, or no signature. With the strict approach, a valid signature must be present. In the above example, the strict approach is used by selecting Require modules to be validly signed (CONFIG_MODULE_SIG_FORCE). Another way of enabling this strict approach is to set the kernel boot option enforcemodulesig=1.

When building the Linux kernel, the kernel modules will not be signed automatically unless you selectAutomatically sign all modules (CONFIG_MODULE_SIG_ALL).

Finally, we need to select the hash algorithm to use with the cryptographic signature. In the above example, we use SHA-512.

Building the kernel with proper keys

When the Linux kernel is building with module signature verification support enabled, then you can use your own keys or have the Linux kernel build infrastructure create a set for you. If you want the Linux kernel build infrastructure to create it for you, just continue as you always do with a make and make modules_install. At the end of the build process, you will notice that signing_key.priv and signing_key.x509 will be available on the root of the Linux kernel sources.

If we want to use our own keys, you can use openssl to create a key pair (private key and public key). The following command, taken from kernel/Makefile, creates such a key pair.

 [Collapse
File x509.genkey Key generation configuration file

[ req ]
default_bits = 4096
distinguished_name = req_distinguished_name
prompt = no
string_mask = utf8only
x509_extensions = myexts
  
[ req_distinguished_name ]
O = GenFic
CN = Kernel Signing Key
emailAddress = server.support@genfic.com
  
[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
user $  openssl req -new -nodes -utf8 -sha512 -days 36500 -batch -x509 -config x509.genkey -outform DER -out signing_key.x509 -keyout signing_key.priv

The resulting files need to be stored as signing_key.x509 and signing_key.priv in the root of the Linux kernel source tree.

The public key part will be build inside the Linux kernel. If you configured the kernel to sign modules, this signing will take place during the make modules_install part.

Validating module signature support

Reboot with the newly configured kernel. In the output of dmesg you should be able to confirm that the proper certificate is loaded:

user $  dmesg | grep MODSIGN
[    2.450021] MODSIGN: Loaded cert 'GenFic: Kernel Signing Key: b923a5f44eae25bbad52c8bf2742e7b7e6fb0c0e'

The kernel modules have the digital signature appended at the end. A simple hexdump can confirm if a signature is present or not:

user $  hexdump -C vxlan.ko | tail
00008880  cf 0e e7 cb 10 9e 98 5f  4b 21 d4 03 ba 3d 7e e7  |......._K!...=~.|
00008890  68 db f9 e3 5f 62 3c c7  d6 6c 84 c7 d6 68 c1 73  |h..._b<..l...h.s|
000088a0  3d d7 5a 38 66 99 12 b8  84 c9 84 45 dd 68 6d 17  |=.Z8f......E.hm.|
000088b0  03 24 dc 9c 6f 6d 11 01  e9 74 82 ea b5 5b 46 07  |.$..om...t...[F.|
000088c0  fe dd 66 97 1a 33 58 3d  6e d0 ac 03 08 16 73 06  |..f..3X=n.....s.|
000088d0  9f 90 c4 eb b3 82 1d 9f  48 8c 5b 51 01 06 01 1e  |........H.[Q....|
000088e0  14 00 00 00 00 00 02 02  7e 4d 6f 64 75 6c 65 20  |........~Module |
000088f0  73 69 67 6e 61 74 75 72  65 20 61 70 70 65 6e 64  |signature append|
00008900  65 64 7e 0a                                       |ed~.|
00008904

The string ~Module signature appended~ at the end confirms that a signature is present. Of course, it does not confirm that the signature is valid or not.

To remove the signature, we can use the strip command:

root #  strip --strip-debug vxlan.ko 
root #  hexdump -C vxlan.ko | tail
00097330  6c 5f 67 65 74 5f 73 74  61 74 73 36 34 00 72 63  |l_get_stats64.rc|
00097340  75 5f 62 61 72 72 69 65  72 00 5f 72 61 77 5f 73  |u_barrier._raw_s|
00097350  70 69 6e 5f 75 6e 6c 6f  63 6b 00 72 65 67 69 73  |pin_unlock.regis|
00097360  74 65 72 5f 70 65 72 6e  65 74 5f 64 65 76 69 63  |ter_pernet_devic|
00097370  65 00 6b 6d 61 6c 6c 6f  63 5f 63 61 63 68 65 73  |e.kmalloc_caches|
00097380  00 6e 65 74 64 65 76 5f  69 6e 66 6f 00 6e 65 69  |.netdev_info.nei|
00097390  67 68 5f 6c 6f 6f 6b 75  70 00 72 65 6c 65 61 73  |gh_lookup.releas|
000973a0  65 5f 73 6f 63 6b 00 72  65 67 69 73 74 65 72 5f  |e_sock.register_|
000973b0  6e 65 74 64 65 76 69 63  65 00                    |netdevice.|
000973ba

If we try to load this module now, we get a failure:

root #  modprobe vxlan
modprobe: ERROR: could not insert 'vxlan': Required key not available

This confirms that modules without a signature are not loaded.

Administering kernel module signatures

Once the kernel boots and we have validated that the signed kernel module support works, it is important to correctly handle the keys themselves.

Protecting the private key

The private key, stored as signing_key.priv, needs to be moved to a secure location (unless you will be creating new keys for new kernels, in which case the file can be removed). Do not keep it at /usr/src/linux on production systems as malware can then easily use this key to sign the malicious kernel modules (such as rootkits) and compromise the system further.

Manually signing modules

If you ever need to manually sign a kernel module, you can use the scripts/sign-file script available in the Linux kernel source tree. It requires four arguments:

  1. The hash algorithm to use, such as sha512
  2. The private key location
  3. The certificate (which includes the public key) location
  4. The kernel module to sign

In this case, the key pair does not need to be named signing_file.priv and such, nor do they need to be in the root of the Linux kernel source tree location.

user $  perl /usr/src/linux/scripts/sign-file sha512 /mnt/sdcard/kernel-signkey.priv /mnt/sdcard/kernel-signkey.x509 vxlan.ko

Distributing the kernel and modules

If we create a kernel package through make tarbz2-pkg, the modules in it will be signed already so we do not need to manually sign them afterwards. The signing keys themselves are not distributed with it.

More resources

In Booting a self-signed Linux kernel Greg Kroah-Hartman describes how to boot a self-signed Linux kernel from EFI. As having signed kernel module support is only secure if the Linux kernel is trusted, this is an important (and related) feature to work with.

The kernel loads these keys at boot time.

Finally, by signing the kenel module files of virtual box with my private key, I can launch VirtualBox on my EFI system.

1. List currently loaded keys:

$ sudo keyctl list %:.system_keyring
5 keys in keyring:
87094    8     9: ---lswrv  0 0 asymmetric: Fedora kernel signing key: 9a0182fa6694d373f36bde1c99594e0e42ac8f9f
10640     6     48: ---lswrv 0 0 asymmetric: Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42
23     9    543: ---lswrv 0 0 asymmetric: Acer: c4f0474ae6b5e67a509d99132f49a4ec13f7ac68
3152    52    312: ---lswrv 0 0 asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4
43107    9    814: ---lswrv 0 0 asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53

These were loaded at kernel boot time:

$ dmesg | grep 'EFI: Loaded cert'
[    0.719111] EFI: Loaded cert 'Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53' linked to '.system_keyring'
[    0.719120] EFI: Loaded cert 'Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4' linked to '.system_keyring'
[    0.719149] EFI: Loaded cert 'Acer: c4f0474ae6b5e67a509d99132f49a4ec13f7ac68' linked to '.system_keyring'
[    0.730021] EFI: Loaded cert 'Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42' linked to '.system_keyring'

2. Create private/public key pair from a configuration file:

a. Create the folder where to put the keys (can be anywhere).

mkdir ~/x509; cd ~/x509

b. Create the configuration file (don't forget to personalize):

$ cat << EOF > configuration_file.config
[ req ]
days = 36500
default_bits = 4096
#specify the section defining the requested distinguished name
distinguished_name = maarten
prompt = no
string_mask = utf8only
#Specify the section that defines extensions to add to a self-signed certificate.
x509_extensions = myexts
encrypt_key = no

[ maarten ]
countryName = be
organizationName = Maarten Inc
commonName = Maarten
emailAddress = maarten@xxx.com

[ myexts ]
basicConstraints=critical,CA:FALSE
keyUsage=digitalSignature
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid
EOF

c. Generate the private/public key (store them somewhere safely !!!):

$ openssl req -x509 -new -utf8 -sha256 -batch -config configuration_file.config -outform DER -out public_key.der -keyout private_key.priv

3. In the previous step, you have generated your private/public key pair. We will now add them to the mok list. You will be asked a password. Remember it, as it will be used to confirm the MOK request.

$ sudo mokutil --import my_signing_key_pub.der

4. Reboot the machine

 $ sudo shutdown -r now

5. At boot time, shim.efi will notice the newly added key and will launch MokManager.efi.

MokManager.efi will request to enter your previously entered password.

6. Once booted, your key pair has been succesfully added to the key ring of the kernel.

$ sudo keyctl list %:.system_keyring

6 keys in keyring:
870942879: ---lswrv     0     0 asymmetric: Fedora kernel signing key: 9a0182fa6694d373f36bde1c99594e0e42ac8f9f
1064026748: ---lswrv     0     0 asymmetric: Fedora Secure Boot CA: fde32599c2d61db1bf5807335d7b20e4cd963b42
6557317: ---lswrv     0     0 asymmetric: maarten: Organization signing key: e121670995ff9ea405426aa201e651eee7242316
2399543: ---lswrv     0     0 asymmetric: Acer: c4f0474ae6b5e67a509d99132f49a4ec13f7ac68
315252312: ---lswrv     0     0 asymmetric: Microsoft Corporation UEFI CA 2011: 13adbf4309bd82709c8cd54f316ed522988a1bd4
431079814: ---lswrv     0     0 asymmetric: Microsoft Windows Production PCA 2011: a92902398e16c49778cd90f99e4f9ae17c55af53

7. I ended up signing the kernel modules of VirtualBox with the following for loop:

for i in /usr/lib/modules/$(uname -r)/extra/VirtualBox/*ko; do
  sudo /usr/src/kernels/$(uname -r)/scripts/sign-file sha256 private_key.priv  public_key.der "$i";
done

8. VirtualBox will happily run virtual machines. ==> Done!

I expect VirtualBox to break everytime an update for VirtualBox is released. In that case, you will have to repeat step 7. I am not sure what the effect of a shim update will be.

Sources:

[0] https://access.redhat.com/documentati...

[1] http://www-01.ibm.com/support/knowled...

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐