diff mbox series

[3/3] integrity: Load keys from TPM NV onto IMA keyring

Message ID 20210225203229.363302-4-patrick@puiterwijk.org (mailing list archive)
State New, archived
Headers show
Series Load keys from TPM2 NV Index on IMA keyring | expand

Commit Message

Patrick Uiterwijk Feb. 25, 2021, 8:32 p.m. UTC
Allows users to enroll their own public key stored in a specific TPM2
NV Index, requiring the absence of the Platform Create and Platform
Write attributes on the NV Index, to be loaded on the IMA keyring.

Provides a method for users to load keys without the need to recompile
the kernel or change the kernel binary, which would require a resign of
the kernel image.

Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
---
 security/integrity/ima/Kconfig    | 22 +++++++++++++
 security/integrity/ima/ima_init.c | 53 +++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

Comments

Stefan Berger Feb. 26, 2021, 9:47 p.m. UTC | #1
On 2/25/21 3:32 PM, Patrick Uiterwijk wrote:
> Allows users to enroll their own public key stored in a specific TPM2
> NV Index, requiring the absence of the Platform Create and Platform
> Write attributes on the NV Index, to be loaded on the IMA keyring.
>
> Provides a method for users to load keys without the need to recompile
> the kernel or change the kernel binary, which would require a resign of
> the kernel image.
>
> Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
> ---
>   security/integrity/ima/Kconfig    | 22 +++++++++++++
>   security/integrity/ima/ima_init.c | 53 +++++++++++++++++++++++++++++++
>   2 files changed, 75 insertions(+)
>
> diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
> index 12e9250c1bec..28424b930c81 100644
> --- a/security/integrity/ima/Kconfig
> +++ b/security/integrity/ima/Kconfig
> @@ -291,6 +291,28 @@ config IMA_BLACKLIST_KEYRING
>   	   the search is successful the requested operation is rejected and
>   	   an error is returned to the caller.
>   
> +config IMA_LOAD_CERT_NVINDEX
> +	bool "Load certificate from TPM nvindex into '.ima' trusted keyring"
> +	depends on IMA_TRUSTED_KEYRING && TCG_TPM
> +	default n
> +	help
> +	   File signature verification is based on the public keys
> +	   loaded on the .ima trusted keyring. These public keys are
> +	   X509 certificates signed by a trusted key on the
> +	   .system keyring.  This option enables X509 certificate
> +	   loading by the kernel onto the '.ima' trusted keyring
> +	   from a TPM nvindex, bypassing the builtin keyring check.
> +
> +config IMA_LOAD_CERT_NVINDEX_INDEX
> +	hex "The TPM NV Index to load into the '.ima' trusted keyring"
> +	depends on IMA_LOAD_CERT_NVINDEX
> +	default 0x184b520
> +	help
> +	   Defines the index of the NV Index that gets loaded into the
> +	   '.ima' keyring.
> +	   The default is the "0x18" prefix for a non-TCG specified NV Index,
> +	   suffixed with ASCII for "KR" (keyring) and then 0
> +
>   config IMA_LOAD_X509
>   	bool "Load X509 certificate onto the '.ima' trusted keyring"
>   	depends on IMA_TRUSTED_KEYRING
> diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
> index 6e8742916d1d..ea0949e8df12 100644
> --- a/security/integrity/ima/ima_init.c
> +++ b/security/integrity/ima/ima_init.c
> @@ -112,6 +112,55 @@ void __init ima_load_x509(void)
>   }
>   #endif
>   
> +#ifndef CONFIG_IMA_LOAD_CERT_NVINDEX
> +int __init ima_load_key_nvindex(void)
> +{
> +	return 0;
> +}
> +#else
> +int __init ima_load_key_nvindex(void)
> +{
> +	void *cert_buffer;
> +	int rc;
> +	key_perm_t perm;
> +	u32 nvindex_attributes = 0;
> +
> +	rc = tpm_nv_read(tpm_default_chip(),


You should do chip = tpm_default_chip() so that later on you can do 
put_device(&chip->dev).


> +				CONFIG_IMA_LOAD_CERT_NVINDEX_INDEX,
> +				&nvindex_attributes, &cert_buffer);
> +	if (rc < 0) {
> +		if (rc == -ENODEV)  /* No TPM2 */
> +			rc = 0;
> +		if (rc == -ENOENT)  /* No certificate in NV Index */
> +			rc = 0;
> +		goto out;
> +	}
> +
> +	pr_info("Loading IMA key from TPM NV Index 0x%x", CONFIG_IMA_LOAD_CERT_NVINDEX_INDEX);
> +
> +	if (nvindex_attributes & TPM2_ATTR_NV_PLATFORMCREATE) {
> +		pr_err("NV Index has the Platform Create attribute");
> +		rc = -EACCES;
> +		goto out_free;
> +	}
> +	if (nvindex_attributes & TPM2_ATTR_NV_PPWRITE) {
> +		pr_err("NV Index has the Platform Write attribute");
> +		rc = -EACCES;
> +		goto out_free;
> +	}
> +
> +	perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ;
> +	rc = integrity_load_cert(INTEGRITY_KEYRING_IMA, "TPM NV Index",
> +				 cert_buffer, rc, perm,
> +				 KEY_ALLOC_BYPASS_RESTRICTION);
> +
> +out_free:
> +	kvfree(cert_buffer);


kfree?


> +out:
> +	return rc;
> +}
> +#endif
> +
>   int __init ima_init(void)
>   {
>   	int rc;
> @@ -124,6 +173,10 @@ int __init ima_init(void)
>   	if (rc)
>   		return rc;
>   
> +	rc = ima_load_key_nvindex();
> +	if (rc)
> +		pr_info("Failed to load IMA key from TPM NV Index (%d)", rc);
> +
>   	rc = ima_init_crypto();
>   	if (rc)
>   		return rc;
Stefan Berger Feb. 26, 2021, 9:51 p.m. UTC | #2
On 2/26/21 4:47 PM, Stefan Berger wrote:
> On 2/25/21 3:32 PM, Patrick Uiterwijk wrote:
>> Allows users to enroll their own public key stored in a specific TPM2
>> NV Index, requiring the absence of the Platform Create and Platform
>> Write attributes on the NV Index, to be loaded on the IMA keyring.
>>
>> Provides a method for users to load keys without the need to recompile
>> the kernel or change the kernel binary, which would require a resign of
>> the kernel image.
>>
>> Signed-off-by: Patrick Uiterwijk <patrick@puiterwijk.org>
>> ---
>>   security/integrity/ima/Kconfig    | 22 +++++++++++++
>>   security/integrity/ima/ima_init.c | 53 +++++++++++++++++++++++++++++++
>>   2 files changed, 75 insertions(+)
>>
>> diff --git a/security/integrity/ima/Kconfig 
>> b/security/integrity/ima/Kconfig
>> index 12e9250c1bec..28424b930c81 100644
>> --- a/security/integrity/ima/Kconfig
>> +++ b/security/integrity/ima/Kconfig
>> @@ -291,6 +291,28 @@ config IMA_BLACKLIST_KEYRING
>>          the search is successful the requested operation is rejected 
>> and
>>          an error is returned to the caller.
>>   +config IMA_LOAD_CERT_NVINDEX
>> +    bool "Load certificate from TPM nvindex into '.ima' trusted 
>> keyring"
>> +    depends on IMA_TRUSTED_KEYRING && TCG_TPM
>> +    default n
>> +    help
>> +       File signature verification is based on the public keys
>> +       loaded on the .ima trusted keyring. These public keys are
>> +       X509 certificates signed by a trusted key on the
>> +       .system keyring.  This option enables X509 certificate
>> +       loading by the kernel onto the '.ima' trusted keyring
>> +       from a TPM nvindex, bypassing the builtin keyring check.
>> +
>> +config IMA_LOAD_CERT_NVINDEX_INDEX
>> +    hex "The TPM NV Index to load into the '.ima' trusted keyring"
>> +    depends on IMA_LOAD_CERT_NVINDEX
>> +    default 0x184b520
>> +    help
>> +       Defines the index of the NV Index that gets loaded into the
>> +       '.ima' keyring.
>> +       The default is the "0x18" prefix for a non-TCG specified NV 
>> Index,
>> +       suffixed with ASCII for "KR" (keyring) and then 0
>> +
>>   config IMA_LOAD_X509
>>       bool "Load X509 certificate onto the '.ima' trusted keyring"
>>       depends on IMA_TRUSTED_KEYRING
>> diff --git a/security/integrity/ima/ima_init.c 
>> b/security/integrity/ima/ima_init.c
>> index 6e8742916d1d..ea0949e8df12 100644
>> --- a/security/integrity/ima/ima_init.c
>> +++ b/security/integrity/ima/ima_init.c
>> @@ -112,6 +112,55 @@ void __init ima_load_x509(void)
>>   }
>>   #endif
>>   +#ifndef CONFIG_IMA_LOAD_CERT_NVINDEX
>> +int __init ima_load_key_nvindex(void)
>> +{
>> +    return 0;
>> +}
>> +#else
>> +int __init ima_load_key_nvindex(void)
>> +{
>> +    void *cert_buffer;
>> +    int rc;
>> +    key_perm_t perm;
>> +    u32 nvindex_attributes = 0;
>> +
>> +    rc = tpm_nv_read(tpm_default_chip(),
>
>
> You should do chip = tpm_default_chip() so that later on you can do 
> put_device(&chip->dev).


... or just use ima_tpm_chip if != NULL: 
https://elixir.bootlin.com/linux/latest/source/security/integrity/ima/ima_init.c#L23



>
>
>> + CONFIG_IMA_LOAD_CERT_NVINDEX_INDEX,
>> +                &nvindex_attributes, &cert_buffer);
>> +    if (rc < 0) {
>> +        if (rc == -ENODEV)  /* No TPM2 */
>> +            rc = 0;
>> +        if (rc == -ENOENT)  /* No certificate in NV Index */
>> +            rc = 0;
>> +        goto out;
>> +    }
>> +
>> +    pr_info("Loading IMA key from TPM NV Index 0x%x", 
>> CONFIG_IMA_LOAD_CERT_NVINDEX_INDEX);
>> +
>> +    if (nvindex_attributes & TPM2_ATTR_NV_PLATFORMCREATE) {
>> +        pr_err("NV Index has the Platform Create attribute");
>> +        rc = -EACCES;
>> +        goto out_free;
>> +    }
>> +    if (nvindex_attributes & TPM2_ATTR_NV_PPWRITE) {
>> +        pr_err("NV Index has the Platform Write attribute");
>> +        rc = -EACCES;
>> +        goto out_free;
>> +    }
>> +
>> +    perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | 
>> KEY_USR_READ;
>> +    rc = integrity_load_cert(INTEGRITY_KEYRING_IMA, "TPM NV Index",
>> +                 cert_buffer, rc, perm,
>> +                 KEY_ALLOC_BYPASS_RESTRICTION);
>> +
>> +out_free:
>> +    kvfree(cert_buffer);
>
>
> kfree?
>
>
>> +out:
>> +    return rc;
>> +}
>> +#endif
>> +
>>   int __init ima_init(void)
>>   {
>>       int rc;
>> @@ -124,6 +173,10 @@ int __init ima_init(void)
>>       if (rc)
>>           return rc;
>>   +    rc = ima_load_key_nvindex();
>> +    if (rc)
>> +        pr_info("Failed to load IMA key from TPM NV Index (%d)", rc);
>> +
>>       rc = ima_init_crypto();
>>       if (rc)
>>           return rc;
diff mbox series

Patch

diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig
index 12e9250c1bec..28424b930c81 100644
--- a/security/integrity/ima/Kconfig
+++ b/security/integrity/ima/Kconfig
@@ -291,6 +291,28 @@  config IMA_BLACKLIST_KEYRING
 	   the search is successful the requested operation is rejected and
 	   an error is returned to the caller.
 
+config IMA_LOAD_CERT_NVINDEX
+	bool "Load certificate from TPM nvindex into '.ima' trusted keyring"
+	depends on IMA_TRUSTED_KEYRING && TCG_TPM
+	default n
+	help
+	   File signature verification is based on the public keys
+	   loaded on the .ima trusted keyring. These public keys are
+	   X509 certificates signed by a trusted key on the
+	   .system keyring.  This option enables X509 certificate
+	   loading by the kernel onto the '.ima' trusted keyring
+	   from a TPM nvindex, bypassing the builtin keyring check.
+
+config IMA_LOAD_CERT_NVINDEX_INDEX
+	hex "The TPM NV Index to load into the '.ima' trusted keyring"
+	depends on IMA_LOAD_CERT_NVINDEX
+	default 0x184b520
+	help
+	   Defines the index of the NV Index that gets loaded into the
+	   '.ima' keyring.
+	   The default is the "0x18" prefix for a non-TCG specified NV Index,
+	   suffixed with ASCII for "KR" (keyring) and then 0
+
 config IMA_LOAD_X509
 	bool "Load X509 certificate onto the '.ima' trusted keyring"
 	depends on IMA_TRUSTED_KEYRING
diff --git a/security/integrity/ima/ima_init.c b/security/integrity/ima/ima_init.c
index 6e8742916d1d..ea0949e8df12 100644
--- a/security/integrity/ima/ima_init.c
+++ b/security/integrity/ima/ima_init.c
@@ -112,6 +112,55 @@  void __init ima_load_x509(void)
 }
 #endif
 
+#ifndef CONFIG_IMA_LOAD_CERT_NVINDEX
+int __init ima_load_key_nvindex(void)
+{
+	return 0;
+}
+#else
+int __init ima_load_key_nvindex(void)
+{
+	void *cert_buffer;
+	int rc;
+	key_perm_t perm;
+	u32 nvindex_attributes = 0;
+
+	rc = tpm_nv_read(tpm_default_chip(),
+				CONFIG_IMA_LOAD_CERT_NVINDEX_INDEX,
+				&nvindex_attributes, &cert_buffer);
+	if (rc < 0) {
+		if (rc == -ENODEV)  /* No TPM2 */
+			rc = 0;
+		if (rc == -ENOENT)  /* No certificate in NV Index */
+			rc = 0;
+		goto out;
+	}
+
+	pr_info("Loading IMA key from TPM NV Index 0x%x", CONFIG_IMA_LOAD_CERT_NVINDEX_INDEX);
+
+	if (nvindex_attributes & TPM2_ATTR_NV_PLATFORMCREATE) {
+		pr_err("NV Index has the Platform Create attribute");
+		rc = -EACCES;
+		goto out_free;
+	}
+	if (nvindex_attributes & TPM2_ATTR_NV_PPWRITE) {
+		pr_err("NV Index has the Platform Write attribute");
+		rc = -EACCES;
+		goto out_free;
+	}
+
+	perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ;
+	rc = integrity_load_cert(INTEGRITY_KEYRING_IMA, "TPM NV Index",
+				 cert_buffer, rc, perm,
+				 KEY_ALLOC_BYPASS_RESTRICTION);
+
+out_free:
+	kvfree(cert_buffer);
+out:
+	return rc;
+}
+#endif
+
 int __init ima_init(void)
 {
 	int rc;
@@ -124,6 +173,10 @@  int __init ima_init(void)
 	if (rc)
 		return rc;
 
+	rc = ima_load_key_nvindex();
+	if (rc)
+		pr_info("Failed to load IMA key from TPM NV Index (%d)", rc);
+
 	rc = ima_init_crypto();
 	if (rc)
 		return rc;