2021-02-18 22:04:42

by Nayna Jain

[permalink] [raw]
Subject: [PATCH v2 0/5] ima: kernel build support for loading the kernel module signing key

Kernel modules are currently only signed when CONFIG_MODULE_SIG is enabled.
The kernel module signing key is a self-signed CA only loaded onto the
.builtin_trusted_key keyring. On secure boot enabled systems with an arch
specific IMA policy enabled, but without MODULE_SIG enabled, kernel modules
are not signed, nor is the kernel module signing public key loaded onto the
IMA keyring.

In order to load the the kernel module signing key onto the IMA trusted
keyring ('.ima'), the certificate needs to be signed by a CA key either on
the builtin or secondary keyrings. This series of patches enables IMA
verification of signed kernel modules by:

* Defining a kernel CA key. The CA key signs the kernel module signing key
and is loaded onto the .builtin_trusted_key keyring, only when the kernel
module signing key is loaded onto the .ima keyring.

* Enable module signing at build time for IMA_APPRAISE_MODSIG as well

v2:

* Include feedback from Stefan - corrected the Fixes commit id in Patch 1
and cleaned Patch 5/5.
* Fix the issue reported by kernel test bot.
* Include Jarkko's feedback on patch description.

Nayna Jain (5):
keys: cleanup build time module signing keys
keys: generate self-signed module signing key using CSR
ima: update kernel module signing process during build
keys: define build time generated ephemeral kernel CA key
ima: enable loading of build time generated key on .ima keyring

Makefile | 9 ++--
certs/Kconfig | 2 +-
certs/Makefile | 77 ++++++++++++++++++++++++++++++++---
certs/system_certificates.S | 16 +++++++-
certs/system_keyring.c | 55 +++++++++++++++++++------
include/keys/system_keyring.h | 9 +++-
init/Kconfig | 6 +--
security/integrity/digsig.c | 4 ++
8 files changed, 150 insertions(+), 28 deletions(-)

--
2.29.2


2021-02-18 22:04:57

by Nayna Jain

[permalink] [raw]
Subject: [PATCH v2 4/5] keys: define build time generated ephemeral kernel CA key

Certificates being loaded onto the IMA trusted keyring must be signed by
a key on either the builtin or secondary trusted keyring. Create and
include in the kernel image an ephemeral CA key at build time when
IMA_APPRAISE_MODSIG is enabled.

Reported-by: kernel test robot <[email protected]> (redirect openssl stderr)
Signed-off-by: Nayna Jain <[email protected]>
---
Makefile | 2 ++
certs/Makefile | 68 ++++++++++++++++++++++++++++++++++---
certs/system_certificates.S | 16 ++++++++-
3 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
index a971d4ae40bd..15e8344836b1 100644
--- a/Makefile
+++ b/Makefile
@@ -1475,6 +1475,8 @@ MRPROPER_FILES += include/config include/generated \
certs/signing_key.pem certs/signing_key.x509 \
certs/x509.genkey certs/signing_key.key \
certs/signing_key.crt certs/signing_key.csr \
+ certs/ca_signing_key.pem certs/ca_signing_key.x509 \
+ certs/ca_signing_key.srl \
vmlinux-gdb.py \
*.spec

diff --git a/certs/Makefile b/certs/Makefile
index b2be7eb413d3..3fe6b73786fa 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -32,6 +32,14 @@ endif # CONFIG_SYSTEM_TRUSTED_KEYRING
clean-files := x509_certificate_list .x509.list

ifeq ($(CONFIG_MODULE_SIG),y)
+SIGN_KEY = y
+endif
+
+ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
+SIGN_KEY = y
+endif
+
+ifdef SIGN_KEY
###############################################################################
#
# If module signing is requested, say by allyesconfig, but a key has not been
@@ -51,6 +59,16 @@ silent_redirect_openssl = 2>/dev/null
# external private key, because 'make randconfig' might enable such a
# boolean option and we unfortunately can't make it depend on !RANDCONFIG.
ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
+
+ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
+# openssl arguments for CA Signed certificate.
+CA_KEY = certs/ca_signing_key.pem
+SIGNER = -CA $(CA_KEY) -CAkey $(CA_KEY) -CAcreateserial
+else
+# openssl arguments for Self Signed certificate.
+SIGNER = -signkey $(obj)/signing_key.key
+endif # CONFIG_IMA_APPRAISE_MODSIG
+
$(obj)/signing_key.pem: $(obj)/x509.genkey
@$(kecho) "###"
@$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
@@ -60,14 +78,23 @@ $(obj)/signing_key.pem: $(obj)/x509.genkey
@$(kecho) "### needs to be run as root, and uses a hardware random"
@$(kecho) "### number generator if one is available."
@$(kecho) "###"
+ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
+ # Generate kernel build time CA Certificate.
+ @$(Q)openssl req -new -nodes -utf8 \
+ -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
+ -subj "/CN=Build time autogenerated kernel CA key" \
+ -batch -x509 -config $(obj)/x509.genkey \
+ -outform PEM -out $(CA_KEY) \
+ -keyout $(CA_KEY) -extensions ca_ext \
+ $($(quiet)redirect_openssl)
+endif # CONFIG_IMA_APPRAISE_MODSIG
$(Q)openssl req -new -nodes -utf8 \
-batch -config $(obj)/x509.genkey \
-outform PEM -out $(obj)/signing_key.csr \
-keyout $(obj)/signing_key.key -extensions myexts \
$($(quiet)redirect_openssl)
$(Q)openssl x509 -req -days 36500 -in $(obj)/signing_key.csr \
- -outform PEM -out $(obj)/signing_key.crt \
- -signkey $(obj)/signing_key.key \
+ -outform PEM -out $(obj)/signing_key.crt $(SIGNER) \
-$(CONFIG_MODULE_SIG_HASH) -extensions myexts \
-extfile $(obj)/x509.genkey \
$($(quiet)redirect_openssl)
@@ -95,19 +122,50 @@ $(obj)/x509.genkey:
@echo >>$@ "keyUsage=digitalSignature"
@echo >>$@ "subjectKeyIdentifier=hash"
@echo >>$@ "authorityKeyIdentifier=keyid"
+ @echo >>$@
+ @echo >>$@ "[ ca_ext ]"
+ @echo >>$@ "keyUsage=critical,keyCertSign"
+ @echo >>$@ "basicConstraints=critical,CA:TRUE,pathlen:0"
+ @echo >>$@ "subjectKeyIdentifier=hash"
+ @echo >>$@ "authorityKeyIdentifier=keyid"
endif # CONFIG_MODULE_SIG_KEY

$(eval $(call config_filename,MODULE_SIG_KEY))
+SUBJECT=CN = Build time autogenerated kernel key
+ISSUER=$(shell openssl x509 -in certs/signing_key.crt -noout -issuer $($(quiet)redirect_openssl))

# If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it
+
+# GCC PR#66871 again.
+ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
+
+# Remove existing keys if it is self-signed.
+$(if $(findstring $(SUBJECT),$(ISSUER)),$(shell rm -f certs/signing_key.* certs/x509.genkey))
+CA_KEY = certs/ca_signing_key.pem
+
+$(obj)/system_certificates.o: $(obj)/ca_signing_key.x509 $(obj)/signing_key.x509
+
+targets += ca_signing_key.x509
+$(obj)/ca_signing_key.x509: $(obj)/signing_key.x509 scripts/extract-cert FORCE
+ $(call if_changed,extract_certs,$(CA_KEY))
+
+targets += signing_key.x509
+$(obj)/signing_key.x509: $(obj)/signing_key.pem scripts/extract-cert FORCE
+ $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
+else
+
+# Remove existing keys if it is CA signed.
+$(if $(findstring $(SUBJECT),$(ISSUER)),,$(shell rm -f certs/ca_signing_key.* certs/signing_key.* certs/x509.genkey))
+
ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME)))
X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME)
endif

-# GCC PR#66871 again.
$(obj)/system_certificates.o: $(obj)/signing_key.x509

targets += signing_key.x509
-$(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE
+$(obj)/signing_key.x509: certs/signing_key.pem scripts/extract-cert $(X509_DEP) FORCE
$(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
-endif # CONFIG_MODULE_SIG
+
+endif # CONFIG_IMA_APPRAISE_MODSIG
+endif # SIGN_KEY
diff --git a/certs/system_certificates.S b/certs/system_certificates.S
index 8f29058adf93..e10043800a7e 100644
--- a/certs/system_certificates.S
+++ b/certs/system_certificates.S
@@ -8,8 +8,13 @@
.globl system_certificate_list
system_certificate_list:
__cert_list_start:
-#ifdef CONFIG_MODULE_SIG
+__module_cert_start:
+#if defined(CONFIG_MODULE_SIG) || defined(CONFIG_IMA_APPRAISE_MODSIG)
.incbin "certs/signing_key.x509"
+#endif
+__module_cert_end:
+#ifdef CONFIG_IMA_APPRAISE_MODSIG
+ .incbin "certs/ca_signing_key.x509"
#endif
.incbin "certs/x509_certificate_list"
__cert_list_end:
@@ -35,3 +40,12 @@ system_certificate_list_size:
#else
.long __cert_list_end - __cert_list_start
#endif
+
+ .align 8
+ .globl module_cert_size
+ module_cert_size:
+#ifdef CONFIG_64BIT
+ .quad __module_cert_end - __module_cert_start
+#else
+ .long __module_cert_end - __module_cert_start
+#endif
--
2.29.2

2021-02-19 15:29:30

by Stefan Berger

[permalink] [raw]
Subject: Re: [PATCH v2 4/5] keys: define build time generated ephemeral kernel CA key

On 2/18/21 5:00 PM, Nayna Jain wrote:
> Certificates being loaded onto the IMA trusted keyring must be signed by
> a key on either the builtin or secondary trusted keyring. Create and
> include in the kernel image an ephemeral CA key at build time when
> IMA_APPRAISE_MODSIG is enabled.
>
> Reported-by: kernel test robot <[email protected]> (redirect openssl stderr)
> Signed-off-by: Nayna Jain <[email protected]>
> ---
> Makefile | 2 ++
> certs/Makefile | 68 ++++++++++++++++++++++++++++++++++---
> certs/system_certificates.S | 16 ++++++++-
> 3 files changed, 80 insertions(+), 6 deletions(-)
>
> diff --git a/Makefile b/Makefile
> index a971d4ae40bd..15e8344836b1 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -1475,6 +1475,8 @@ MRPROPER_FILES += include/config include/generated \
> certs/signing_key.pem certs/signing_key.x509 \
> certs/x509.genkey certs/signing_key.key \
> certs/signing_key.crt certs/signing_key.csr \
> + certs/ca_signing_key.pem certs/ca_signing_key.x509 \
> + certs/ca_signing_key.srl \
> vmlinux-gdb.py \
> *.spec
>
> diff --git a/certs/Makefile b/certs/Makefile
> index b2be7eb413d3..3fe6b73786fa 100644
> --- a/certs/Makefile
> +++ b/certs/Makefile
> @@ -32,6 +32,14 @@ endif # CONFIG_SYSTEM_TRUSTED_KEYRING
> clean-files := x509_certificate_list .x509.list
>
> ifeq ($(CONFIG_MODULE_SIG),y)
> +SIGN_KEY = y
> +endif
> +
> +ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
> +SIGN_KEY = y
> +endif
> +
> +ifdef SIGN_KEY
> ###############################################################################
> #
> # If module signing is requested, say by allyesconfig, but a key has not been
> @@ -51,6 +59,16 @@ silent_redirect_openssl = 2>/dev/null
> # external private key, because 'make randconfig' might enable such a
> # boolean option and we unfortunately can't make it depend on !RANDCONFIG.
> ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem")
> +
> +ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
> +# openssl arguments for CA Signed certificate.
> +CA_KEY = certs/ca_signing_key.pem
> +SIGNER = -CA $(CA_KEY) -CAkey $(CA_KEY) -CAcreateserial
> +else
> +# openssl arguments for Self Signed certificate.
> +SIGNER = -signkey $(obj)/signing_key.key
> +endif # CONFIG_IMA_APPRAISE_MODSIG
> +
> $(obj)/signing_key.pem: $(obj)/x509.genkey
> @$(kecho) "###"
> @$(kecho) "### Now generating an X.509 key pair to be used for signing modules."
> @@ -60,14 +78,23 @@ $(obj)/signing_key.pem: $(obj)/x509.genkey
> @$(kecho) "### needs to be run as root, and uses a hardware random"
> @$(kecho) "### number generator if one is available."
> @$(kecho) "###"
> +ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
> + # Generate kernel build time CA Certificate.
> + @$(Q)openssl req -new -nodes -utf8 \
> + -$(CONFIG_MODULE_SIG_HASH) -days 36500 \
> + -subj "/CN=Build time autogenerated kernel CA key" \
> + -batch -x509 -config $(obj)/x509.genkey \
> + -outform PEM -out $(CA_KEY) \
> + -keyout $(CA_KEY) -extensions ca_ext \
> + $($(quiet)redirect_openssl)
> +endif # CONFIG_IMA_APPRAISE_MODSIG
> $(Q)openssl req -new -nodes -utf8 \
> -batch -config $(obj)/x509.genkey \
> -outform PEM -out $(obj)/signing_key.csr \
> -keyout $(obj)/signing_key.key -extensions myexts \
> $($(quiet)redirect_openssl)
> $(Q)openssl x509 -req -days 36500 -in $(obj)/signing_key.csr \
> - -outform PEM -out $(obj)/signing_key.crt \
> - -signkey $(obj)/signing_key.key \
> + -outform PEM -out $(obj)/signing_key.crt $(SIGNER) \
> -$(CONFIG_MODULE_SIG_HASH) -extensions myexts \
> -extfile $(obj)/x509.genkey \
> $($(quiet)redirect_openssl)
> @@ -95,19 +122,50 @@ $(obj)/x509.genkey:
> @echo >>$@ "keyUsage=digitalSignature"
> @echo >>$@ "subjectKeyIdentifier=hash"
> @echo >>$@ "authorityKeyIdentifier=keyid"
> + @echo >>$@
> + @echo >>$@ "[ ca_ext ]"
> + @echo >>$@ "keyUsage=critical,keyCertSign"
> + @echo >>$@ "basicConstraints=critical,CA:TRUE,pathlen:0"
> + @echo >>$@ "subjectKeyIdentifier=hash"
> + @echo >>$@ "authorityKeyIdentifier=keyid"
> endif # CONFIG_MODULE_SIG_KEY
>
> $(eval $(call config_filename,MODULE_SIG_KEY))
> +SUBJECT=CN = Build time autogenerated kernel key
> +ISSUER=$(shell openssl x509 -in certs/signing_key.crt -noout -issuer $($(quiet)redirect_openssl))
>
> # If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it
> +
> +# GCC PR#66871 again.
> +ifeq ($(CONFIG_IMA_APPRAISE_MODSIG),y)
> +
> +# Remove existing keys if it is self-signed.
> +$(if $(findstring $(SUBJECT),$(ISSUER)),$(shell rm -f certs/signing_key.* certs/x509.genkey))
> +CA_KEY = certs/ca_signing_key.pem
> +
> +$(obj)/system_certificates.o: $(obj)/ca_signing_key.x509 $(obj)/signing_key.x509
> +
> +targets += ca_signing_key.x509
> +$(obj)/ca_signing_key.x509: $(obj)/signing_key.x509 scripts/extract-cert FORCE
> + $(call if_changed,extract_certs,$(CA_KEY))
> +
> +targets += signing_key.x509
> +$(obj)/signing_key.x509: $(obj)/signing_key.pem scripts/extract-cert FORCE
> + $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
> +else
> +
> +# Remove existing keys if it is CA signed.
> +$(if $(findstring $(SUBJECT),$(ISSUER)),,$(shell rm -f certs/ca_signing_key.* certs/signing_key.* certs/x509.genkey))
> +
> ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME)))
> X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME)
> endif
>
> -# GCC PR#66871 again.

I think you should keep this comment at this place here.


> $(obj)/system_certificates.o: $(obj)/signing_key.x509
>
> targets += signing_key.x509
> -$(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE
> +$(obj)/signing_key.x509: certs/signing_key.pem scripts/extract-cert $(X509_DEP) FORCE
> $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY))
> -endif # CONFIG_MODULE_SIG
> +
> +endif # CONFIG_IMA_APPRAISE_MODSIG
> +endif # SIGN_KEY
> diff --git a/certs/system_certificates.S b/certs/system_certificates.S
> index 8f29058adf93..e10043800a7e 100644
> --- a/certs/system_certificates.S
> +++ b/certs/system_certificates.S
> @@ -8,8 +8,13 @@
> .globl system_certificate_list
> system_certificate_list:
> __cert_list_start:
> -#ifdef CONFIG_MODULE_SIG
> +__module_cert_start:
> +#if defined(CONFIG_MODULE_SIG) || defined(CONFIG_IMA_APPRAISE_MODSIG)
> .incbin "certs/signing_key.x509"
> +#endif
> +__module_cert_end:
> +#ifdef CONFIG_IMA_APPRAISE_MODSIG
> + .incbin "certs/ca_signing_key.x509"
> #endif
> .incbin "certs/x509_certificate_list"
> __cert_list_end:
> @@ -35,3 +40,12 @@ system_certificate_list_size:
> #else
> .long __cert_list_end - __cert_list_start
> #endif
> +
> + .align 8
> + .globl module_cert_size
> + module_cert_size:
> +#ifdef CONFIG_64BIT
> + .quad __module_cert_end - __module_cert_start
> +#else
> + .long __module_cert_end - __module_cert_start
> +#endif