Contents:
 
 - Restrict linking of keys to .ima and .evm keyrings based on
   digitalSignature attribute in the certificate.
 - PowerVM: load machine owner keys into the .machine [1] keyring.
 - PowerVM: load module signing keys into the secondary trusted keyring
   (keys blessed by the vendor).
 - tpm_tis_spi: half-duplex transfer mode
 - tpm_tis: retry corrupted transfers
 - Apply revocation list (.mokx) to an all system keyrings (e.g. .machine
   keyring).
 
 [1] https://blogs.oracle.com/linux/post/the-machine-keyring
 
 BR, Jarkko
 -----BEGIN PGP SIGNATURE-----
 
 iIgEABYIADAWIQRE6pSOnaBC00OEHEIaerohdGur0gUCZN5/qBIcamFya2tvQGtl
 cm5lbC5vcmcACgkQGnq6IXRrq9J4GQEAstTtQfGGrx5KInOTMWOvaq/Cum5iW4AD
 NefVfbUtCCQBANvFtxoPYQS5u6+rIdxzIwFiNUlOyt2uR2bkk4UUiPML
 =Vvs8
 -----END PGP SIGNATURE-----

Merge tag 'tpmdd-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd

Pull tpm updates from Jarkko Sakkinen:

 - Restrict linking of keys to .ima and .evm keyrings based on
   digitalSignature attribute in the certificate

 - PowerVM: load machine owner keys into the .machine [1] keyring

 - PowerVM: load module signing keys into the secondary trusted keyring
   (keys blessed by the vendor)

 - tpm_tis_spi: half-duplex transfer mode

 - tpm_tis: retry corrupted transfers

 - Apply revocation list (.mokx) to an all system keyrings (e.g.
   .machine keyring)

Link: https://blogs.oracle.com/linux/post/the-machine-keyring [1]

* tag 'tpmdd-v6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/jarkko/linux-tpmdd:
  certs: Reference revocation list for all keyrings
  tpm/tpm_tis_synquacer: Use module_platform_driver macro to simplify the code
  tpm: remove redundant variable len
  tpm_tis: Resend command to recover from data transfer errors
  tpm_tis: Use responseRetry to recover from data transfer errors
  tpm_tis: Move CRC check to generic send routine
  tpm_tis_spi: Add hardware wait polling
  KEYS: Replace all non-returning strlcpy with strscpy
  integrity: PowerVM support for loading third party code signing keys
  integrity: PowerVM machine keyring enablement
  integrity: check whether imputed trust is enabled
  integrity: remove global variable from machine_keyring.c
  integrity: ignore keys failing CA restrictions on non-UEFI platform
  integrity: PowerVM support for loading CA keys on machine keyring
  integrity: Enforce digitalSignature usage in the ima and evm keyrings
  KEYS: DigitalSignature link restriction
  tpm_tis: Revert "tpm_tis: Disable interrupts on ThinkPad T490s"
This commit is contained in:
Linus Torvalds 2023-08-29 08:05:18 -07:00
commit f2586d921c
21 changed files with 394 additions and 148 deletions

View File

@ -6394,6 +6394,13 @@
This will guarantee that all the other pcrs
are saved.
tpm_tis.interrupts= [HW,TPM]
Enable interrupts for the MMIO based physical layer
for the FIFO interface. By default it is set to false
(0). For more information about TPM hardware interfaces
defined by Trusted Computing Group (TCG) see
https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/
tp_printk [FTRACE]
Have the tracepoints sent to printk as well as the
tracing ring buffer. This is useful for early boot up

View File

@ -51,6 +51,26 @@ int restrict_link_by_builtin_trusted(struct key *dest_keyring,
builtin_trusted_keys);
}
/**
* restrict_link_by_digsig_builtin - Restrict digitalSignature key additions by the built-in keyring
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @restriction_key: A ring of keys that can be used to vouch for the new cert.
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in the built in system keyring. The new key
* must have the digitalSignature usage field set.
*/
int restrict_link_by_digsig_builtin(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key)
{
return restrict_link_by_digsig(dest_keyring, type, payload,
builtin_trusted_keys);
}
#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
/**
* restrict_link_by_builtin_and_secondary_trusted - Restrict keyring
@ -83,6 +103,35 @@ int restrict_link_by_builtin_and_secondary_trusted(
secondary_trusted_keys);
}
/**
* restrict_link_by_digsig_builtin_and_secondary - Restrict by digitalSignature.
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @restrict_key: A ring of keys that can be used to vouch for the new cert.
*
* Restrict the addition of keys into a keyring based on the key-to-be-added
* being vouched for by a key in either the built-in or the secondary system
* keyrings. The new key must have the digitalSignature usage field set.
*/
int restrict_link_by_digsig_builtin_and_secondary(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *restrict_key)
{
/* If we have a secondary trusted keyring, then that contains a link
* through to the builtin keyring and the search will follow that link.
*/
if (type == &key_type_keyring &&
dest_keyring == secondary_trusted_keys &&
payload == &builtin_trusted_keys->payload)
/* Allow the builtin keyring to be added to the secondary */
return 0;
return restrict_link_by_digsig(dest_keyring, type, payload,
secondary_trusted_keys);
}
/*
* Allocate a struct key_restriction for the "builtin and secondary trust"
* keyring. Only for use in system_trusted_keyring_init().
@ -103,6 +152,36 @@ static __init struct key_restriction *get_builtin_and_secondary_restriction(void
return restriction;
}
/**
* add_to_secondary_keyring - Add to secondary keyring.
* @source: Source of key
* @data: The blob holding the key
* @len: The length of the data blob
*
* Add a key to the secondary keyring. The key must be vouched for by a key in the builtin,
* machine or secondary keyring itself.
*/
void __init add_to_secondary_keyring(const char *source, const void *data, size_t len)
{
key_ref_t key;
key_perm_t perm;
perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW;
key = key_create_or_update(make_key_ref(secondary_trusted_keys, 1),
"asymmetric",
NULL, data, len, perm,
KEY_ALLOC_NOT_IN_QUOTA);
if (IS_ERR(key)) {
pr_err("Problem loading X.509 certificate from %s to secondary keyring %ld\n",
source, PTR_ERR(key));
return;
}
pr_notice("Loaded X.509 cert '%s'\n", key_ref_to_ptr(key)->description);
key_ref_put(key);
}
#endif
#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
void __init set_machine_trusted_keys(struct key *keyring)
@ -251,6 +330,12 @@ int verify_pkcs7_message_sig(const void *data, size_t len,
if (ret < 0)
goto error;
ret = is_key_on_revocation_list(pkcs7);
if (ret != -ENOKEY) {
pr_devel("PKCS#7 key is on revocation list\n");
goto error;
}
if (!trusted_keys) {
trusted_keys = builtin_trusted_keys;
} else if (trusted_keys == VERIFY_USE_SECONDARY_KEYRING) {
@ -270,12 +355,6 @@ int verify_pkcs7_message_sig(const void *data, size_t len,
pr_devel("PKCS#7 platform keyring is not available\n");
goto error;
}
ret = is_key_on_revocation_list(pkcs7);
if (ret != -ENOKEY) {
pr_devel("PKCS#7 platform key is on revocation list\n");
goto error;
}
}
ret = pkcs7_validate_trust(pkcs7, trusted_keys);
if (ret < 0) {

View File

@ -148,6 +148,50 @@ int restrict_link_by_ca(struct key *dest_keyring,
return 0;
}
/**
* restrict_link_by_digsig - Restrict additions to a ring of digsig keys
* @dest_keyring: Keyring being linked to.
* @type: The type of key being added.
* @payload: The payload of the new key.
* @trust_keyring: A ring of keys that can be used to vouch for the new cert.
*
* Check if the new certificate has digitalSignature usage set. If it is,
* then mark the new certificate as being ok to link. Afterwards verify
* the new certificate against the ones in the trust_keyring.
*
* Returns 0 if the new certificate was accepted, -ENOKEY if the
* certificate is not a digsig. -ENOPKG if the signature uses unsupported
* crypto, or some other error if there is a matching certificate but
* the signature check cannot be performed.
*/
int restrict_link_by_digsig(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring)
{
const struct public_key *pkey;
if (type != &key_type_asymmetric)
return -EOPNOTSUPP;
pkey = payload->data[asym_crypto];
if (!pkey)
return -ENOPKG;
if (!test_bit(KEY_EFLAG_DIGITALSIG, &pkey->key_eflags))
return -ENOKEY;
if (test_bit(KEY_EFLAG_CA, &pkey->key_eflags))
return -ENOKEY;
if (test_bit(KEY_EFLAG_KEYCERTSIGN, &pkey->key_eflags))
return -ENOKEY;
return restrict_link_by_signature(dest_keyring, type, payload,
trust_keyring);
}
static bool match_either_id(const struct asymmetric_key_id **pair,
const struct asymmetric_key_id *single)
{

View File

@ -251,7 +251,6 @@ static int tpm1_binary_bios_measurements_show(struct seq_file *m, void *v)
static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
{
int len = 0;
char *eventname;
struct tcpa_event *event = v;
unsigned char *event_entry =
@ -273,7 +272,7 @@ static int tpm1_ascii_bios_measurements_show(struct seq_file *m, void *v)
/* 3rd: event type identifier */
seq_printf(m, " %02x", do_endian_conversion(event->event_type));
len += get_event_name(eventname, event, event_entry);
get_event_name(eventname, event, event_entry);
/* 4th: eventname <= max + \'0' delimiter */
seq_printf(m, " %s\n", eventname);

View File

@ -27,7 +27,6 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/kernel.h>
#include <linux/dmi.h>
#include "tpm.h"
#include "tpm_tis_core.h"
@ -89,8 +88,8 @@ static inline void tpm_tis_iowrite32(u32 b, void __iomem *iobase, u32 addr)
tpm_tis_flush(iobase);
}
static int interrupts;
module_param(interrupts, int, 0444);
static bool interrupts;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
static bool itpm;
@ -103,92 +102,6 @@ module_param(force, bool, 0444);
MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
#endif
static int tpm_tis_disable_irq(const struct dmi_system_id *d)
{
if (interrupts == -1) {
pr_notice("tpm_tis: %s detected: disabling interrupts.\n", d->ident);
interrupts = 0;
}
return 0;
}
static const struct dmi_system_id tpm_tis_dmi_table[] = {
{
.callback = tpm_tis_disable_irq,
.ident = "Framework Laptop (12th Gen Intel Core)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (12th Gen Intel Core)"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "Framework Laptop (13th Gen Intel Core)",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop (13th Gen Intel Core)"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkPad T490s",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T490s"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkStation P360 Tiny",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P360 Tiny"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkPad L490",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L490"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkPad L590",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L590"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "ThinkStation P620",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkStation P620"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "TUXEDO InfinityBook S 15/17 Gen7",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_PRODUCT_NAME, "TUXEDO InfinityBook S 15/17 Gen7"),
},
},
{
.callback = tpm_tis_disable_irq,
.ident = "UPX-TGL",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "AAEON"),
DMI_MATCH(DMI_PRODUCT_NAME, "UPX-TGL01"),
},
},
{}
};
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
static int has_hid(struct acpi_device *dev, const char *hid)
{
@ -312,8 +225,6 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info)
int irq = -1;
int rc;
dmi_check_system(tpm_tis_dmi_table);
rc = check_acpi_tpm2(dev);
if (rc)
return rc;

View File

@ -340,7 +340,7 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
return size;
}
static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
static int tpm_tis_try_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
int size = 0;
@ -348,11 +348,6 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
u32 expected;
int rc;
if (count < TPM_HEADER_SIZE) {
size = -EIO;
goto out;
}
size = recv_data(chip, buf, TPM_HEADER_SIZE);
/* read first 10 bytes, including tag, paramsize, and result */
if (size < TPM_HEADER_SIZE) {
@ -385,7 +380,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
goto out;
}
status = tpm_tis_status(chip);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
if (status & TPM_STS_DATA_AVAIL) {
dev_err(&chip->dev, "Error left over data\n");
size = -EIO;
goto out;
@ -399,10 +394,36 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}
out:
tpm_tis_ready(chip);
return size;
}
static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev);
unsigned int try;
int rc = 0;
if (count < TPM_HEADER_SIZE)
return -EIO;
for (try = 0; try < TPM_RETRY; try++) {
rc = tpm_tis_try_recv(chip, buf, count);
if (rc == -EIO)
/* Data transfer errors, indicated by EIO, can be
* recovered by rereading the response.
*/
tpm_tis_write8(priv, TPM_STS(priv->locality),
TPM_STS_RESPONSE_RETRY);
else
break;
}
tpm_tis_ready(chip);
return rc;
}
/*
* If interrupts are used (signaled by an irq set in the vendor structure)
* tpm.c can skip polling for the data to be available as the interrupt is
@ -469,6 +490,12 @@ static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len)
goto out_err;
}
rc = tpm_tis_verify_crc(priv, len, buf);
if (rc < 0) {
dev_err(&chip->dev, "CRC mismatch for command.\n");
goto out_err;
}
return 0;
out_err:
@ -512,15 +539,16 @@ static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len)
int rc;
u32 ordinal;
unsigned long dur;
unsigned int try;
rc = tpm_tis_send_data(chip, buf, len);
if (rc < 0)
return rc;
rc = tpm_tis_verify_crc(priv, len, buf);
if (rc < 0) {
dev_err(&chip->dev, "CRC mismatch for command.\n");
return rc;
for (try = 0; try < TPM_RETRY; try++) {
rc = tpm_tis_send_data(chip, buf, len);
if (rc >= 0)
/* Data transfer done successfully */
break;
else if (rc != -EIO)
/* Data transfer failed, not recoverable */
return rc;
}
/* go and do it */

View File

@ -34,6 +34,7 @@ enum tis_status {
TPM_STS_GO = 0x20,
TPM_STS_DATA_AVAIL = 0x10,
TPM_STS_DATA_EXPECT = 0x08,
TPM_STS_RESPONSE_RETRY = 0x02,
TPM_STS_READ_ZERO = 0x23, /* bits that must be zero on read */
};

View File

@ -71,8 +71,74 @@ static int tpm_tis_spi_flow_control(struct tpm_tis_spi_phy *phy,
return 0;
}
int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
u8 *in, const u8 *out)
/*
* Half duplex controller with support for TPM wait state detection like
* Tegra QSPI need CMD, ADDR & DATA sent in single message to manage HW flow
* control. Each phase sent in different transfer for controller to idenity
* phase.
*/
static int tpm_tis_spi_transfer_half(struct tpm_tis_data *data, u32 addr,
u16 len, u8 *in, const u8 *out)
{
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
struct spi_transfer spi_xfer[3];
struct spi_message m;
u8 transfer_len;
int ret;
while (len) {
transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE);
spi_message_init(&m);
phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1);
phy->iobuf[1] = 0xd4;
phy->iobuf[2] = addr >> 8;
phy->iobuf[3] = addr;
memset(&spi_xfer, 0, sizeof(spi_xfer));
spi_xfer[0].tx_buf = phy->iobuf;
spi_xfer[0].len = 1;
spi_message_add_tail(&spi_xfer[0], &m);
spi_xfer[1].tx_buf = phy->iobuf + 1;
spi_xfer[1].len = 3;
spi_message_add_tail(&spi_xfer[1], &m);
if (out) {
spi_xfer[2].tx_buf = &phy->iobuf[4];
spi_xfer[2].rx_buf = NULL;
memcpy(&phy->iobuf[4], out, transfer_len);
out += transfer_len;
}
if (in) {
spi_xfer[2].tx_buf = NULL;
spi_xfer[2].rx_buf = &phy->iobuf[4];
}
spi_xfer[2].len = transfer_len;
spi_message_add_tail(&spi_xfer[2], &m);
reinit_completion(&phy->ready);
ret = spi_sync(phy->spi_device, &m);
if (ret < 0)
return ret;
if (in) {
memcpy(in, &phy->iobuf[4], transfer_len);
in += transfer_len;
}
len -= transfer_len;
}
return ret;
}
static int tpm_tis_spi_transfer_full(struct tpm_tis_data *data, u32 addr,
u16 len, u8 *in, const u8 *out)
{
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
int ret = 0;
@ -148,6 +214,24 @@ int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
return ret;
}
int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len,
u8 *in, const u8 *out)
{
struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data);
struct spi_controller *ctlr = phy->spi_device->controller;
/*
* TPM flow control over SPI requires full duplex support.
* Send entire message to a half duplex controller to handle
* wait polling in controller.
* Set TPM HW flow control flag..
*/
if (ctlr->flags & SPI_CONTROLLER_HALF_DUPLEX)
return tpm_tis_spi_transfer_half(data, addr, len, in, out);
else
return tpm_tis_spi_transfer_full(data, addr, len, in, out);
}
static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr,
u16 len, u8 *result, enum tpm_tis_io_mode io_mode)
{
@ -189,6 +273,9 @@ static int tpm_tis_spi_probe(struct spi_device *dev)
phy->flow_control = tpm_tis_spi_flow_control;
if (dev->controller->flags & SPI_CONTROLLER_HALF_DUPLEX)
dev->mode |= SPI_TPM_HW_FLOW;
/* If the SPI device has an IRQ then use that */
if (dev->irq > 0)
irq = dev->irq;

View File

@ -162,23 +162,7 @@ static struct platform_driver tis_synquacer_drv = {
},
};
static int __init tpm_tis_synquacer_module_init(void)
{
int rc;
module_platform_driver(tis_synquacer_drv);
rc = platform_driver_register(&tis_synquacer_drv);
if (rc)
return rc;
return 0;
}
static void __exit tpm_tis_synquacer_module_exit(void)
{
platform_driver_unregister(&tis_synquacer_drv);
}
module_init(tpm_tis_synquacer_module_init);
module_exit(tpm_tis_synquacer_module_exit);
MODULE_DESCRIPTION("TPM MMIO Driver for Socionext SynQuacer platform");
MODULE_LICENSE("GPL");

View File

@ -78,6 +78,10 @@ extern int restrict_link_by_ca(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring);
int restrict_link_by_digsig(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring);
#else
static inline int restrict_link_by_ca(struct key *dest_keyring,
const struct key_type *type,
@ -86,6 +90,14 @@ static inline int restrict_link_by_ca(struct key *dest_keyring,
{
return 0;
}
static inline int restrict_link_by_digsig(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *trust_keyring)
{
return 0;
}
#endif
extern int query_asymmetric_key(const struct kernel_pkey_params *,

View File

@ -23,10 +23,15 @@ extern int restrict_link_by_builtin_trusted(struct key *keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key);
int restrict_link_by_digsig_builtin(struct key *dest_keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key);
extern __init int load_module_cert(struct key *keyring);
#else
#define restrict_link_by_builtin_trusted restrict_link_reject
#define restrict_link_by_digsig_builtin restrict_link_reject
static inline __init int load_module_cert(struct key *keyring)
{
@ -41,8 +46,17 @@ extern int restrict_link_by_builtin_and_secondary_trusted(
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key);
int restrict_link_by_digsig_builtin_and_secondary(struct key *keyring,
const struct key_type *type,
const union key_payload *payload,
struct key *restriction_key);
void __init add_to_secondary_keyring(const char *source, const void *data, size_t len);
#else
#define restrict_link_by_builtin_and_secondary_trusted restrict_link_by_builtin_trusted
#define restrict_link_by_digsig_builtin_and_secondary restrict_link_by_digsig_builtin
static inline void __init add_to_secondary_keyring(const char *source, const void *data, size_t len)
{
}
#endif
#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING

View File

@ -67,7 +67,9 @@ config INTEGRITY_MACHINE_KEYRING
depends on SECONDARY_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
depends on SYSTEM_BLACKLIST_KEYRING
depends on LOAD_UEFI_KEYS
depends on LOAD_UEFI_KEYS || LOAD_PPC_KEYS
select INTEGRITY_CA_MACHINE_KEYRING if LOAD_PPC_KEYS
select INTEGRITY_CA_MACHINE_KEYRING_MAX if LOAD_PPC_KEYS
help
If set, provide a keyring to which Machine Owner Keys (MOK) may
be added. This keyring shall contain just MOK keys. Unlike keys

View File

@ -34,9 +34,9 @@ static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = {
};
#ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
#define restrict_link_to_ima restrict_link_by_builtin_and_secondary_trusted
#define restrict_link_to_ima restrict_link_by_digsig_builtin_and_secondary
#else
#define restrict_link_to_ima restrict_link_by_builtin_trusted
#define restrict_link_to_ima restrict_link_by_digsig_builtin
#endif
static struct key *integrity_keyring_from_id(const unsigned int id)
@ -113,7 +113,7 @@ static int __init __integrity_init_keyring(const unsigned int id,
} else {
if (id == INTEGRITY_KEYRING_PLATFORM)
set_platform_trusted_keys(keyring[id]);
if (id == INTEGRITY_KEYRING_MACHINE && trust_moklist())
if (id == INTEGRITY_KEYRING_MACHINE && imputed_trust_enabled())
set_machine_trusted_keys(keyring[id]);
if (id == INTEGRITY_KEYRING_IMA)
load_module_cert(keyring[id]);

View File

@ -64,7 +64,8 @@ config EVM_LOAD_X509
This option enables X509 certificate loading from the kernel
onto the '.evm' trusted keyring. A public key can be used to
verify EVM integrity starting from the 'init' process.
verify EVM integrity starting from the 'init' process. The
key must have digitalSignature usage set.
config EVM_X509_PATH
string "EVM X509 certificate path"

View File

@ -270,7 +270,8 @@ config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY
help
Keys may be added to the IMA or IMA blacklist keyrings, if the
key is validly signed by a CA cert in the system built-in or
secondary trusted keyrings.
secondary trusted keyrings. The key must also have the
digitalSignature usage set.
Intermediate keys between those the kernel has compiled in and the
IMA keys to be added may be added to the system secondary keyring,

View File

@ -320,13 +320,14 @@ static inline void __init add_to_platform_keyring(const char *source,
#ifdef CONFIG_INTEGRITY_MACHINE_KEYRING
void __init add_to_machine_keyring(const char *source, const void *data, size_t len);
bool __init trust_moklist(void);
bool __init imputed_trust_enabled(void);
#else
static inline void __init add_to_machine_keyring(const char *source,
const void *data, size_t len)
{
}
static inline bool __init trust_moklist(void)
static inline bool __init imputed_trust_enabled(void)
{
return false;
}

View File

@ -61,7 +61,8 @@ __init efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type)
__init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type)
{
if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0) {
if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) && trust_moklist())
if (IS_ENABLED(CONFIG_INTEGRITY_MACHINE_KEYRING) &&
imputed_trust_enabled())
return add_to_machine_keyring;
else
return add_to_platform_keyring;
@ -69,6 +70,22 @@ __init efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type)
return NULL;
}
__init efi_element_handler_t get_handler_for_ca_keys(const efi_guid_t *sig_type)
{
if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
return add_to_machine_keyring;
return NULL;
}
__init efi_element_handler_t get_handler_for_code_signing_keys(const efi_guid_t *sig_type)
{
if (efi_guidcmp(*sig_type, efi_cert_x509_guid) == 0)
return add_to_secondary_keyring;
return NULL;
}
/*
* Return the appropriate handler for particular signature list types found in
* the UEFI dbx and MokListXRT tables.

View File

@ -29,6 +29,16 @@ efi_element_handler_t get_handler_for_db(const efi_guid_t *sig_type);
*/
efi_element_handler_t get_handler_for_mok(const efi_guid_t *sig_type);
/*
* Return the handler for particular signature list types for CA keys.
*/
efi_element_handler_t get_handler_for_ca_keys(const efi_guid_t *sig_type);
/*
* Return the handler for particular signature list types for code signing keys.
*/
efi_element_handler_t get_handler_for_code_signing_keys(const efi_guid_t *sig_type);
/*
* Return the handler for particular signature list types found in the dbx.
*/

View File

@ -59,6 +59,8 @@ static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
static int __init load_powerpc_certs(void)
{
void *db = NULL, *dbx = NULL, *data = NULL;
void *trustedca;
void *moduledb;
u64 dsize = 0;
u64 offset = 0;
int rc = 0;
@ -120,6 +122,38 @@ static int __init load_powerpc_certs(void)
kfree(data);
}
data = get_cert_list("trustedcadb", 12, &dsize);
if (!data) {
pr_info("Couldn't get trustedcadb list from firmware\n");
} else if (IS_ERR(data)) {
rc = PTR_ERR(data);
pr_err("Error reading trustedcadb from firmware: %d\n", rc);
} else {
extract_esl(trustedca, data, dsize, offset);
rc = parse_efi_signature_list("powerpc:trustedca", trustedca, dsize,
get_handler_for_ca_keys);
if (rc)
pr_err("Couldn't parse trustedcadb signatures: %d\n", rc);
kfree(data);
}
data = get_cert_list("moduledb", 9, &dsize);
if (!data) {
pr_info("Couldn't get moduledb list from firmware\n");
} else if (IS_ERR(data)) {
rc = PTR_ERR(data);
pr_err("Error reading moduledb from firmware: %d\n", rc);
} else {
extract_esl(moduledb, data, dsize, offset);
rc = parse_efi_signature_list("powerpc:moduledb", moduledb, dsize,
get_handler_for_code_signing_keys);
if (rc)
pr_err("Couldn't parse moduledb signatures: %d\n", rc);
kfree(data);
}
return rc;
}
late_initcall(load_powerpc_certs);

View File

@ -8,8 +8,6 @@
#include <linux/efi.h>
#include "../integrity.h"
static bool trust_mok;
static __init int machine_keyring_init(void)
{
int rc;
@ -36,7 +34,8 @@ void __init add_to_machine_keyring(const char *source, const void *data, size_t
* If the restriction check does not pass and the platform keyring
* is configured, try to add it into that keyring instead.
*/
if (rc && IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING))
if (rc && efi_enabled(EFI_BOOT) &&
IS_ENABLED(CONFIG_INTEGRITY_PLATFORM_KEYRING))
rc = integrity_load_cert(INTEGRITY_KEYRING_PLATFORM, source,
data, len, perm);
@ -62,12 +61,14 @@ static __init bool uefi_check_trust_mok_keys(void)
return false;
}
bool __init trust_moklist(void)
static bool __init trust_moklist(void)
{
static bool initialized;
static bool trust_mok;
if (!initialized) {
initialized = true;
trust_mok = false;
if (uefi_check_trust_mok_keys())
trust_mok = true;
@ -75,3 +76,16 @@ bool __init trust_moklist(void)
return trust_mok;
}
/*
* Provides platform specific check for trusting imputed keys before loading
* on .machine keyring. UEFI systems enable this trust based on a variable,
* and for other platforms, it is always enabled.
*/
bool __init imputed_trust_enabled(void)
{
if (efi_enabled(EFI_BOOT))
return trust_moklist();
return true;
}

View File

@ -178,7 +178,7 @@ struct key *request_key_auth_new(struct key *target, const char *op,
if (!rka->callout_info)
goto error_free_rka;
rka->callout_len = callout_len;
strlcpy(rka->op, op, sizeof(rka->op));
strscpy(rka->op, op, sizeof(rka->op));
/* see if the calling process is already servicing the key request of
* another process */