aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-09-26 05:11:06 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-10-10 05:36:33 -0400
commit80d65e58e93ffdabf58202653a0435bd3cf2d82e (patch)
tree966d24554f7ca69bd10a0ccf791e805d442a2238
parent85ecac79457e30b19802bbfaeba1856ad00945b0 (diff)
MODSIGN: Sign modules during the build process
If CONFIG_MODULE_SIG is set, then this patch will cause all modules files to to have signatures added. The following steps will occur: (1) The module will be linked to foo.ko.unsigned instead of foo.ko (2) The module will be stripped using both "strip -x -g" and "eu-strip" to ensure minimal size for inclusion in an initramfs. (3) The signature will be generated on the stripped module. (4) The signature will be appended to the module, along with some information about the signature and a magic string that indicates the presence of the signature. Step (3) requires private and public keys to be available. By default these are expected to be found in files: signing_key.priv signing_key.x509 in the base directory of the build. The first is the private key in PEM form and the second is the X.509 certificate in DER form as can be generated from openssl: openssl req \ -new -x509 -outform PEM -out signing_key.x509 \ -keyout signing_key.priv -nodes \ -subj "/CN=H2G2/O=Magrathea/CN=Slartibartfast" If the secret key is not found then signing will be skipped and the unsigned module from (1) will just be copied to foo.ko. If signing occurs, lines like the following will be seen: LD [M] fs/foo/foo.ko.unsigned STRIP [M] fs/foo/foo.ko.stripped SIGN [M] fs/foo/foo.ko will appear in the build log. If the signature step will be skipped and the following will be seen: LD [M] fs/foo/foo.ko.unsigned STRIP [M] fs/foo/foo.ko.stripped NO SIGN [M] fs/foo/foo.ko NOTE! After the signature step, the signed module _must_not_ be passed through strip. The unstripped, unsigned module is still available at the name on the LD [M] line. This restriction may affect packaging tools (such as rpmbuild) and initramfs composition tools. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--scripts/Makefile.modpost77
-rw-r--r--scripts/sign-file115
2 files changed, 191 insertions, 1 deletions
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 08dce14f2dc8..2a4d1a176526 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -14,7 +14,8 @@
14# 3) create one <module>.mod.c file pr. module 14# 3) create one <module>.mod.c file pr. module
15# 4) create one Module.symvers file with CRC for all exported symbols 15# 4) create one Module.symvers file with CRC for all exported symbols
16# 5) compile all <module>.mod.c files 16# 5) compile all <module>.mod.c files
17# 6) final link of the module to a <module.ko> file 17# 6) final link of the module to a <module.ko> (or <module.unsigned>) file
18# 7) signs the modules to a <module.ko> file
18 19
19# Step 3 is used to place certain information in the module's ELF 20# Step 3 is used to place certain information in the module's ELF
20# section, including information such as: 21# section, including information such as:
@@ -32,6 +33,8 @@
32# Step 4 is solely used to allow module versioning in external modules, 33# Step 4 is solely used to allow module versioning in external modules,
33# where the CRC of each module is retrieved from the Module.symvers file. 34# where the CRC of each module is retrieved from the Module.symvers file.
34 35
36# Step 7 is dependent on CONFIG_MODULE_SIG being enabled.
37
35# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined 38# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
36# symbols in the final module linking stage 39# symbols in the final module linking stage
37# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. 40# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
@@ -116,6 +119,7 @@ $(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
116targets += $(modules:.ko=.mod.o) 119targets += $(modules:.ko=.mod.o)
117 120
118# Step 6), final link of the modules 121# Step 6), final link of the modules
122ifneq ($(CONFIG_MODULE_SIG),y)
119quiet_cmd_ld_ko_o = LD [M] $@ 123quiet_cmd_ld_ko_o = LD [M] $@
120 cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \ 124 cmd_ld_ko_o = $(LD) -r $(LDFLAGS) \
121 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ 125 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
@@ -125,7 +129,78 @@ $(modules): %.ko :%.o %.mod.o FORCE
125 $(call if_changed,ld_ko_o) 129 $(call if_changed,ld_ko_o)
126 130
127targets += $(modules) 131targets += $(modules)
132else
133quiet_cmd_ld_ko_unsigned_o = LD [M] $@
134 cmd_ld_ko_unsigned_o = \
135 $(LD) -r $(LDFLAGS) \
136 $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \
137 -o $@ $(filter-out FORCE,$^) \
138 $(if $(AFTER_LINK),; $(AFTER_LINK))
139
140$(modules:.ko=.ko.unsigned): %.ko.unsigned :%.o %.mod.o FORCE
141 $(call if_changed,ld_ko_unsigned_o)
142
143targets += $(modules:.ko=.ko.unsigned)
144
145# Step 7), sign the modules
146MODSECKEY = ./signing_key.priv
147MODPUBKEY = ./signing_key.x509
148
149ifeq ($(wildcard $(MODSECKEY))+$(wildcard $(MODPUBKEY)),$(MODSECKEY)+$(MODPUBKEY))
150ifeq ($(KBUILD_SRC),)
151 # no O= is being used
152 SCRIPTS_DIR := scripts
153else
154 SCRIPTS_DIR := $(KBUILD_SRC)/scripts
155endif
156SIGN_MODULES := 1
157else
158SIGN_MODULES := 0
159endif
160
161# only sign if it's an in-tree module
162ifneq ($(KBUILD_EXTMOD),)
163SIGN_MODULES := 0
164endif
128 165
166# We strip the module as best we can - note that using both strip and eu-strip
167# results in a smaller module than using either alone.
168EU_STRIP = $(shell which eu-strip || echo true)
169
170quiet_cmd_sign_ko_stripped_ko_unsigned = STRIP [M] $@
171 cmd_sign_ko_stripped_ko_unsigned = \
172 cp $< $@ && \
173 strip -x -g $@ && \
174 $(EU_STRIP) $@
175
176ifeq ($(SIGN_MODULES),1)
177
178quiet_cmd_genkeyid = GENKEYID $@
179 cmd_genkeyid = \
180 perl $(SCRIPTS_DIR)/x509keyid $< $<.signer $<.keyid
181
182%.signer %.keyid: %
183 $(call if_changed,genkeyid)
184
185KEYRING_DEP := $(MODSECKEY) $(MODPUBKEY) $(MODPUBKEY).signer $(MODPUBKEY).keyid
186quiet_cmd_sign_ko_ko_stripped = SIGN [M] $@
187 cmd_sign_ko_ko_stripped = \
188 sh $(SCRIPTS_DIR)/sign-file $(MODSECKEY) $(MODPUBKEY) $< $@
189else
190KEYRING_DEP :=
191quiet_cmd_sign_ko_ko_unsigned = NO SIGN [M] $@
192 cmd_sign_ko_ko_unsigned = \
193 cp $< $@
194endif
195
196$(modules): %.ko :%.ko.stripped $(KEYRING_DEP) FORCE
197 $(call if_changed,sign_ko_ko_stripped)
198
199$(patsubst %.ko,%.ko.stripped,$(modules)): %.ko.stripped :%.ko.unsigned FORCE
200 $(call if_changed,sign_ko_stripped_ko_unsigned)
201
202targets += $(modules)
203endif
129 204
130# Add FORCE to the prequisites of a target to force it to be always rebuilt. 205# Add FORCE to the prequisites of a target to force it to be always rebuilt.
131# --------------------------------------------------------------------------- 206# ---------------------------------------------------------------------------
diff --git a/scripts/sign-file b/scripts/sign-file
new file mode 100644
index 000000000000..e58e34e50ac5
--- /dev/null
+++ b/scripts/sign-file
@@ -0,0 +1,115 @@
1#!/bin/sh
2#
3# Sign a module file using the given key.
4#
5# Format: sign-file <key> <x509> <src-file> <dst-file>
6#
7
8scripts=`dirname $0`
9
10CONFIG_MODULE_SIG_SHA512=y
11if [ -r .config ]
12then
13 . ./.config
14fi
15
16key="$1"
17x509="$2"
18src="$3"
19dst="$4"
20
21if [ ! -r "$key" ]
22then
23 echo "Can't read private key" >&2
24 exit 2
25fi
26
27if [ ! -r "$x509" ]
28then
29 echo "Can't read X.509 certificate" >&2
30 exit 2
31fi
32if [ ! -r "$x509.signer" ]
33then
34 echo "Can't read Signer name" >&2
35 exit 2;
36fi
37if [ ! -r "$x509.keyid" ]
38then
39 echo "Can't read Key identifier" >&2
40 exit 2;
41fi
42
43#
44# Signature parameters
45#
46algo=1 # Public-key crypto algorithm: RSA
47hash= # Digest algorithm
48id_type=1 # Identifier type: X.509
49
50#
51# Digest the data
52#
53dgst=
54if [ "$CONFIG_MODULE_SIG_SHA1" = "y" ]
55then
56 prologue="0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14"
57 dgst=-sha1
58 hash=2
59elif [ "$CONFIG_MODULE_SIG_SHA224" = "y" ]
60then
61 prologue="0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1C"
62 dgst=-sha224
63 hash=7
64elif [ "$CONFIG_MODULE_SIG_SHA256" = "y" ]
65then
66 prologue="0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20"
67 dgst=-sha256
68 hash=4
69elif [ "$CONFIG_MODULE_SIG_SHA384" = "y" ]
70then
71 prologue="0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30"
72 dgst=-sha384
73 hash=5
74elif [ "$CONFIG_MODULE_SIG_SHA512" = "y" ]
75then
76 prologue="0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40"
77 dgst=-sha512
78 hash=6
79else
80 echo "$0: Can't determine hash algorithm" >&2
81 exit 2
82fi
83
84(
85perl -e "binmode STDOUT; print pack(\"C*\", $prologue)" || exit $?
86openssl dgst $dgst -binary $src || exit $?
87) >$src.dig || exit $?
88
89#
90# Generate the binary signature, which will be just the integer that comprises
91# the signature with no metadata attached.
92#
93openssl rsautl -sign -inkey $key -keyform PEM -in $src.dig -out $src.sig || exit $?
94signerlen=`stat -c %s $x509.signer`
95keyidlen=`stat -c %s $x509.keyid`
96siglen=`stat -c %s $src.sig`
97
98#
99# Build the signed binary
100#
101(
102 cat $src || exit $?
103 echo '~Module signature appended~' || exit $?
104 cat $x509.signer $x509.keyid || exit $?
105
106 # Preface each signature integer with a 2-byte BE length
107 perl -e "binmode STDOUT; print pack(\"n\", $siglen)" || exit $?
108 cat $src.sig || exit $?
109
110 # Generate the information block
111 perl -e "binmode STDOUT; print pack(\"CCCCCxxxN\", $algo, $hash, $id_type, $signerlen, $keyidlen, $siglen + 2)" || exit $?
112) >$dst~ || exit $?
113
114# Permit in-place signing
115mv $dst~ $dst || exit $?