This currently very much a PoC. Currently the SPDM library only provides a single function to allow a challenge / authentication of the PCI EP. SPDM exchanges must occur in one of a small set of valid squences over which the message digest used in authentication is built up. Placing that complexity in the SPDM library seems like a good way to enforce that logic, without having to do it for each transport. Signed-off-by: Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx> --- drivers/pci/Kconfig | 9 ++++ drivers/pci/Makefile | 2 + drivers/pci/cma.c | 105 ++++++++++++++++++++++++++++++++++++++++ include/linux/pci-cma.h | 19 ++++++++ 4 files changed, 135 insertions(+) diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8b9b3341b553..3a6c4affe81f 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -128,6 +128,15 @@ config PCI_DOE_DRIVER number of different protocols. DOE is defined in the Data Object Exchange ECN to the PCIe r5.0 spec. +config PCI_CMA + tristate "PCI Component Measurement and Authentication" + select PCI_DOE + select ASN1_ENCODER + select SPDM + help + This enables library support for the PCI Component Measurement and + Authentication ECN. This uses DMTF SPDM 1.1 + config PCI_ATS bool diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 0a15f36e97f4..991d4186a01b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -30,9 +30,11 @@ obj-$(CONFIG_PCI_PF_STUB) += pci-pf-stub.o obj-$(CONFIG_PCI_ECAM) += ecam.o obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o obj-$(CONFIG_PCI_DOE_DRIVER) += pci-doe.o +obj-$(CONFIG_PCI_CMA) += pci-cma.o obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o pci-doe-y := doe.o +pci-cma-y := cma.o # Endpoint library must be initialized before its users obj-$(CONFIG_PCI_ENDPOINT) += endpoint/ diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c new file mode 100644 index 000000000000..7a14a3365300 --- /dev/null +++ b/drivers/pci/cma.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Component Measurement and Authentication was added as an ECN to the + * PCIe r5.0 spec. + * + * Copyright (C) 2021 Huawei + * Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx> + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/pci-cma.h> +#include <linux/pci-doe.h> +#include <linux/spdm.h> + +#define PCI_DOE_PROTOCOL_CMA 1 +/* Keyring that userspace can poke certs into */ +static struct key *cma_keyring; + +static int cma_spdm_ex(void *priv, struct spdm_exchange *spdm_ex) +{ + size_t request_padded_sz, response_padded_sz; + struct pci_doe_exchange ex = { + .prot = { + .vid = PCI_VENDOR_ID_PCI_SIG, + .type = PCI_DOE_PROTOCOL_CMA, + }, + }; + struct pci_doe_dev *doe_dev = priv; + int rc; + + /* DOE requires that response and request are padded to a multiple of 4 bytes */ + request_padded_sz = ALIGN(spdm_ex->request_pl_sz, sizeof(u32)); + if (request_padded_sz != spdm_ex->request_pl_sz) { + ex.request_pl = kzalloc(request_padded_sz, GFP_KERNEL); + if (!ex.request_pl) + return -ENOMEM; + memcpy(ex.request_pl, spdm_ex->request_pl, spdm_ex->request_pl_sz); + ex.request_pl_sz = request_padded_sz; + } else { + ex.request_pl = (u32 *)spdm_ex->request_pl; + ex.request_pl_sz = spdm_ex->request_pl_sz; + } + + response_padded_sz = ALIGN(spdm_ex->response_pl_sz, sizeof(u32)); + if (response_padded_sz != spdm_ex->response_pl_sz) { + ex.response_pl = kzalloc(response_padded_sz, GFP_KERNEL); + if (!ex.response_pl) { + rc = -ENOMEM; + goto err_free_req; + } + ex.response_pl_sz = response_padded_sz; + } else { + ex.response_pl = (u32 *)spdm_ex->response_pl; + ex.response_pl_sz = spdm_ex->response_pl_sz; + } + + rc = pci_doe_exchange_sync(doe_dev, &ex); + if (rc < 0) + goto err_free_rsp; + + if (response_padded_sz != spdm_ex->response_pl_sz) + memcpy(spdm_ex->response_pl, ex.response_pl, spdm_ex->response_pl_sz); + +err_free_rsp: + if (response_padded_sz != spdm_ex->response_pl_sz) + kfree(ex.response_pl); +err_free_req: + if (request_padded_sz != spdm_ex->request_pl_sz) + kfree(ex.request_pl); + + return rc; +} + +void pci_cma_init(struct pci_doe_dev *doe_dev, struct spdm_state *spdm_state) +{ + memset(spdm_state, 0, sizeof(*spdm_state)); + spdm_state->transport_ex = cma_spdm_ex; + spdm_state->transport_priv = doe_dev; + spdm_state->dev = &doe_dev->pdev->dev; + spdm_state->root_keyring = cma_keyring; +} +EXPORT_SYMBOL_GPL(pci_cma_init); + +int pci_cma_authenticate(struct spdm_state *spdm_state) +{ + return spdm_authenticate(spdm_state); +} +EXPORT_SYMBOL_GPL(pci_cma_authenticate); + +__init static int cma_keyring_init(void) +{ + cma_keyring = keyring_alloc("_cma", + KUIDT_INIT(0), KGIDT_INIT(0), + current_cred(), + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ | KEY_USR_WRITE | KEY_USR_SEARCH, + KEY_ALLOC_NOT_IN_QUOTA | KEY_ALLOC_SET_KEEP, NULL, NULL); + if (IS_ERR(cma_keyring)) + pr_err("Could not allocate cma keyring\n"); + + return 0; +} +device_initcall(cma_keyring_init); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/pci-cma.h b/include/linux/pci-cma.h new file mode 100644 index 000000000000..3790e532cd38 --- /dev/null +++ b/include/linux/pci-cma.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Component Measurement and Authentication was added as an ECN to the + * PCIe r5.0 spec. + * + * Copyright (C) 2021 Huawei + * Jonathan Cameron <Jonathan.Cameron@xxxxxxxxxx> + */ + +#ifndef _PCI_CMA_H_ +#define _PCI_CMA_H_ +struct pci_doe_dev; +struct spdm_state; + +void pci_cma_init(struct pci_doe_dev *doe_dev, struct spdm_state *spdm_state); + +int pci_cma_authenticate(struct spdm_state *spdm_state); + +#endif -- 2.32.0