Skip to content

Commit

Permalink
PCI/CMA: Authenticate devices on enumeration
Browse files Browse the repository at this point in the history
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@huawei.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
  • Loading branch information
jic23 authored and l1k committed Dec 17, 2022
1 parent 3c557a9 commit 7949b9e
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 0 deletions.
9 changes: 9 additions & 0 deletions drivers/pci/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,15 @@ config XEN_PCIDEV_FRONTEND
config PCI_ATS
bool

config PCI_CMA
bool "Component Measurement and Authentication (CMA/SPDM)"
select PCI_DOE
select SPDM
help
Authenticate devices on enumeration per PCIe r6.0 sec 6.31.
A PCI DOE mailbox is used as transport for DMTF SPDM based
attestation, measurement and secure channel establishment.

config PCI_DOE
bool

Expand Down
1 change: 1 addition & 0 deletions drivers/pci/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ obj-$(CONFIG_PCI_P2PDMA) += p2pdma.o
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
obj-$(CONFIG_VGA_ARB) += vgaarb.o
obj-$(CONFIG_PCI_DOE) += doe.o
obj-$(CONFIG_PCI_CMA) += cma.o

# Endpoint library must be initialized before its users
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
Expand Down
97 changes: 97 additions & 0 deletions drivers/pci/cma.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Component Measurement and Authentication (CMA/SPDM, PCIe r6.0 sec 6.31)
*
* Copyright (C) 2021 Huawei
* Jonathan Cameron <Jonathan.Cameron@huawei.com>
*
* Copyright (C) 2022 Intel Corporation
*/

#define dev_fmt(fmt) "CMA: " fmt

#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pci-doe.h>
#include <linux/pm_runtime.h>
#include <linux/spdm.h>

#include "pci.h"

#define PCI_DOE_PROTOCOL_CMA 1

/* Keyring that userspace can poke certs into */
static struct key *cma_keyring;

static int spdm_doe_transport(void *priv, struct device *dev,
void *request, size_t request_sz,
void *response, size_t response_sz)
{
struct pci_doe_mb *doe = priv;
int rc;

/*
* CMA/SPDM operation in non-D0 states is optional (PCIe r6.0
* sec 6.31.3). The spec does not define a way to determine
* if it's supported, so resume to D0.
*/
rc = pm_runtime_resume_and_get(dev);
if (rc)
return rc;

rc = pci_doe(doe, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_PROTOCOL_CMA,
request, request_sz, response, response_sz);

pm_runtime_put(dev);

return rc;
}

void pci_cma_init(struct pci_dev *pdev)
{
struct spdm_state *spdm_state;
struct pci_doe_mb *doe;
int rc;

if (!pci_is_pcie(pdev))
return;

/* CMA/SPDM does not apply to Root Ports (PCIe r6.0 sec 6.31.3) */
if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)
return;

doe = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
PCI_DOE_PROTOCOL_CMA);
if (!doe)
return;

spdm_state = spdm_create(spdm_doe_transport, doe, &pdev->dev,
cma_keyring);
if (!spdm_state)
return;

rc = spdm_authenticate(spdm_state);
if (rc)
pci_info(pdev, "No CMA support\n");
else
pci_info(pdev, "Attestation passed\n");

kfree(spdm_state);
}

__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");
6 changes: 6 additions & 0 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,12 @@ static inline void pci_doe_stop(struct pci_dev *pdev) { }
static inline void pci_doe_destroy(struct pci_dev *pdev) { }
#endif

#ifdef CONFIG_PCI_CMA
void pci_cma_init(struct pci_dev *pdev);
#else
static inline void pci_cma_init(struct pci_dev *pdev) { }
#endif

/*
* Config Address for PCI Configuration Mechanism #1
*
Expand Down
1 change: 1 addition & 0 deletions drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -2477,6 +2477,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_dpc_init(dev); /* Downstream Port Containment */
pci_rcec_init(dev); /* Root Complex Event Collector */
pci_doe_init(dev); /* Data Object Exchange */
pci_cma_init(dev); /* Component Measurement & Auth */

pcie_report_downtraining(dev);
pci_init_reset_methods(dev);
Expand Down

0 comments on commit 7949b9e

Please sign in to comment.