All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/4] PCI/CMA and SPDM library
@ 2021-08-04 16:18 Jonathan Cameron
  2021-08-04 16:18 ` [RFC PATCH 1/4] lib/asn1_encoder: Add a function to encode many byte integer values Jonathan Cameron
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-04 16:18 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr, Jonathan Cameron

This is an RFC to start discussions about how we support the Component
Measurement and Authentication (CMA) ECN (pcisig.com)

CMA provides an adaptation of the data objects and underlying protocol
defined in the DMTF SPDM specification to be used to authenticate and
conduct run-time measurements of the state of PCI devices (kind of like
IMA for devices / firmware). This is done using a Data Object Exchange (DOE)
protocol described in the ECN.

The CMA ECN is available from the PCI SIG and SPDM can be found at
https://www.dmtf.org/sites/default/files/standards/documents/DSP0274_1.1.1.pdf

CMA/SPDM is focused on establishing trust of the device by:
1) Negotiate algorithms supported.
2) Retrieve and check the certificate chain from the device against
   a suitable signing certificate on the host.
3) Issue a challenge to the device to verify it can sign with the private
   key associated with the leaf certificate.
4) (Request a measurement of device state)
5) (Establish a secure channel for further measurements or other uses)
6) (Mutual authentication)

This RFC only does steps 1-3

Testing of this patch set has been conducted against QEMU emulation of
the device backed by openSPDM emulation of the SPDM protocol.

https://lore.kernel.org/qemu-devel/1624665723-5169-1-git-send-email-cbrowy@avery-design.com/

Open questions are called out in the individual patches but the big ones are
probably:

1) Certificate management.
   Current code uses a _cma keyring created by the kernel, into which a
   suitable root certificate can be inserted from userspace.

   A=$(keyctl search %:_cma  keyring _cma)
   evmctl import ecdsaca.cert.der $A

   Is this an acceptable way to load the root certificates for this purpose?

   The root of the device provided certificate chain is then checked against
   certificates on this keychain, but is itself (with the other certificates
   in the chain) loaded into an SPDM instance specific keychain.  Currently
   there is no safe cleanup of this which will need to be fixed.

   Using the keychain mechanism provides a very convenient way to manage these
   certificates and to allow userspace to read them for debug purpose etc, but
   is this the right use model?

   Finally the leaf certificate of this chain is used to check signatures of
   the rest of the communications with the device.

2) ASNL1 encoder for ECDSA signature
   It seems from the openSPDM implementation that for these signatures,
   the format is a simple pair of raw values.  The kernel implementation of
   ECDSA signature verification assumes ASN1 encoding as seems to be used
   in x509 certificates.  Currently I work around that by encoding the
   signatures so that the ECDSA code can un-encode them again and use them.
   This seems slightly silly, but it is minimum impact on current code.
   Other suggestions welcome.

3) Interface to present to drivers. Currently I'm providing just one exposed
   function that wraps up all the exhanges until a challenge authentication
   response from the device. This is done using one possible sequence.
   I don't think it makes sense to expose the low level components due to the
   underlying spdm_state updates and there only being a fixed set of valid
   orderings.

Future patches will raise questions around management of the measurements, but
I'll leave those until I have some sort of implementation to shoot at.
The 'on probe' use in the CXL driver is only one likely time when authentication
would be needed.

Note I'm new to a bunch of the areas of the kernel this touches, so have
probably done things that are totally wrong.

CC list is best effort to identify those who 'might' care.  Please share
with anyone I've missed.

Thanks,

Jonathan


Jonathan Cameron (4):
  lib/asn1_encoder: Add a function to encode many byte integer values.
  spdm: Introduce a library for DMTF SPDM
  PCI/CMA: Initial support for Component Measurement and Authentication
    ECN
  cxl/pci: Add really basic CMA authentication support.

 drivers/cxl/Kconfig          |    1 +
 drivers/cxl/mem.h            |    2 +
 drivers/cxl/pci.c            |   13 +-
 drivers/pci/Kconfig          |    9 +
 drivers/pci/Makefile         |    1 +
 drivers/pci/doe.c            |    2 -
 include/linux/asn1_encoder.h |    3 +
 include/linux/pci-doe.h      |    2 +
 lib/Kconfig                  |    3 +
 lib/Makefile                 |    2 +
 lib/asn1_encoder.c           |   54 ++
 lib/spdm.c                   | 1196 ++++++++++++++++++++++++++++++++++
 12 files changed, 1285 insertions(+), 3 deletions(-)
 create mode 100644 lib/spdm.c

-- 
2.19.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [RFC PATCH 1/4] lib/asn1_encoder: Add a function to encode many byte integer values.
  2021-08-04 16:18 [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
@ 2021-08-04 16:18 ` Jonathan Cameron
  2021-08-04 16:18 ` [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM Jonathan Cameron
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-04 16:18 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr, Jonathan Cameron

An example is the encoding of ECC signatures used by the ECDSA
signature verification code.  A user is the new SPDM support where
raw signatures are returned by the responder.  These can then
be encoded so that we can pass them to signature_verify()

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---

Needs considerably more testing with crafted examples to hit the corner
cases.  For now it's enough to show how this 'might' fit together.

 include/linux/asn1_encoder.h |  3 ++
 lib/asn1_encoder.c           | 54 ++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/include/linux/asn1_encoder.h b/include/linux/asn1_encoder.h
index 08cd0c2ad34f..30c3ebacd46c 100644
--- a/include/linux/asn1_encoder.h
+++ b/include/linux/asn1_encoder.h
@@ -19,6 +19,9 @@ unsigned char *
 asn1_encode_tag(unsigned char *data, const unsigned char *end_data,
 		u32 tag, const unsigned char *string, int len);
 unsigned char *
+asn1_encode_integer_large_positive(unsigned char *data, const unsigned char *end_data,
+			  u32 tag, const unsigned char *integer, int len);
+unsigned char *
 asn1_encode_octet_string(unsigned char *data,
 			 const unsigned char *end_data,
 			 const unsigned char *string, u32 len);
diff --git a/lib/asn1_encoder.c b/lib/asn1_encoder.c
index 41e71aae3ef6..135c5cf2d77e 100644
--- a/lib/asn1_encoder.c
+++ b/lib/asn1_encoder.c
@@ -317,6 +317,60 @@ asn1_encode_tag(unsigned char *data, const unsigned char *end_data,
 }
 EXPORT_SYMBOL_GPL(asn1_encode_tag);
 
+unsigned char *
+asn1_encode_integer_large_positive(unsigned char *data, const unsigned char *end_data,
+				   u32 tag, const unsigned char *integer, int len)
+{
+	int data_len = end_data - data;
+	unsigned char *d = &data[2];
+	bool found = false;
+	int i;
+
+	if (WARN(tag > 30, "ASN.1 tag can't be > 30"))
+		return ERR_PTR(-EINVAL);
+
+	if (!integer && WARN(len > 127,
+			    "BUG: recode tag is too big (>127)"))
+		return ERR_PTR(-EINVAL);
+
+	if (IS_ERR(data))
+		return data;
+
+	if (data_len < 3)
+		return ERR_PTR(-EINVAL);
+
+
+	data[0] = _tagn(UNIV, PRIM, tag);
+	/* Leave space for length */
+	data_len -= 2;
+
+	for (i = 0; i < len; i++) {
+		int byte = integer[i];
+
+		if (!found && byte == 0)
+			continue;
+
+		/*
+		 * as per encode_integer
+		 */
+		if (!found && (byte & 0x80)) {
+			*d++ = 0;
+			data_len--;
+		}
+		found = true;
+		if (data_len == 0)
+			return ERR_PTR(-EINVAL);
+
+		*d++ = byte;
+		data_len--;
+	}
+
+	data[1] = d - data - 2;
+
+	return d;
+}
+EXPORT_SYMBOL_GPL(asn1_encode_integer_large_positive);
+
 /**
  * asn1_encode_octet_string() - encode an ASN.1 OCTET STRING
  * @data:	pointer to encode at
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
  2021-08-04 16:18 [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
  2021-08-04 16:18 ` [RFC PATCH 1/4] lib/asn1_encoder: Add a function to encode many byte integer values Jonathan Cameron
@ 2021-08-04 16:18 ` Jonathan Cameron
  2022-02-18 22:05   ` Dan Williams
  2021-08-04 16:18 ` [RFC PATCH 3/4] PCI/CMA: Initial support for Component Measurement and Authentication ECN Jonathan Cameron
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-04 16:18 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr, Jonathan Cameron

The Security Protocol and Data Model (SPDM) defines messages,
data objects and sequences for performing message exchanges between
devices over various transports and physical media.

As the kernel supports several possible transports (mctp, PCI DOE)
introduce a library than can in turn be used with all those transports.

There are a large number of open questions around how we do this that
need to be resolved. These include:
*  Key chain management
   - Current approach is to use a keychain provide as part of per transport
     initialization for the root certificates which are assumed to be
     loaded into that keychain, perhaps in an initrd script.
   - Each SPDM instance then has its own keychain to manage its
     certificates. It may make sense to drop this, but that looks like it
     will make a lot of the standard infrastructure harder to use.
 *  ECC algorithms needing ASN1 encoded signatures.  I'm struggling to find
    any specification that actual 'requires' that choice vs raw data, so my
    guess is that this is a question of existing usecases (x509 certs seem
    to use this form, but CHALLENGE_AUTH SPDM seems to use raw data).
    I'm not sure whether we are better off just encoding the signature in
    ASN1 as currently done in this series, or if it is worth a tweaking
    things in the crypto layers.
 *  Lots of options in actual implementation to look at.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 lib/Kconfig  |    3 +
 lib/Makefile |    2 +
 lib/spdm.c   | 1196 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1201 insertions(+)

diff --git a/lib/Kconfig b/lib/Kconfig
index ac3b30697b2b..0aa2fef6a592 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -704,3 +704,6 @@ config PLDMFW
 
 config ASN1_ENCODER
        tristate
+
+config SPDM
+       tristate
diff --git a/lib/Makefile b/lib/Makefile
index 2cc359ec1fdd..566166d6936e 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -282,6 +282,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
 obj-$(CONFIG_ASN1) += asn1_decoder.o
 obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
 
+obj-$(CONFIG_SPDM) += spdm.o
+
 obj-$(CONFIG_FONT_SUPPORT) += fonts/
 
 hostprogs	:= gen_crc32table
diff --git a/lib/spdm.c b/lib/spdm.c
new file mode 100644
index 000000000000..3ce2341647f8
--- /dev/null
+++ b/lib/spdm.c
@@ -0,0 +1,1196 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DMTF Security Protocol and Data Model
+ *
+ * Copyright (C) 2021 Huawei
+ *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ */
+
+#include <linux/asn1_encoder.h>
+#include <linux/asn1_ber_bytecode.h>
+#include <linux/bitfield.h>
+#include <linux/cred.h>
+#include <linux/dev_printk.h>
+#include <linux/digsig.h>
+#include <linux/idr.h>
+#include <linux/key.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/spdm.h>
+
+#include <crypto/akcipher.h>
+#include <crypto/hash.h>
+#include <crypto/public_key.h>
+#include <keys/asymmetric-type.h>
+#include <keys/user-type.h>
+#include <asm/unaligned.h>
+
+/*
+ * Todo
+ * - Secure channel setup.
+ * - Multiple slot support.
+ * - Measurement support (over secure channel or within CHALLENGE_AUTH.
+ * - Support more core algorithms (not CMA does not require them, but may use
+ *   them if present.
+ * - Extended algorithm, support.
+ */
+/*
+ * Discussions points
+ * 1. Worth adding an SPDM layer around a transport layer?
+ * 2. Pad all SPDM request response to DWORD so we don't have to bounce for CMA /DOE.
+ * 3. Currently only implement one flow - so ignore whether we have certs cached.
+ *    Could implement the alternative flows, but at cost of complexity.
+ * 4. Keyring management. How to ensure we can easily check root key against
+ *    keys in appropriate keyring, but ensure we can't cross check keys
+ *    from different devices.  Current solution of one keyring per SPDM has issues
+ *    around cleanup when an error occurs.
+ * 5. Several corners of the SPDM specification were not totally clear to me, so
+ *    where unsure I verified options against openSPDM.
+ * Detailed stuff
+ * - SPDM spec doesn't define a header, but all requests and responses have same
+ *   first 4 bytes.  Either could define that as a header, or givem the better names
+ *   to reflect how param1 and param2 are actually used.
+ */
+
+static int spdm_append_buffer_a(struct spdm_state *spdm_state, void *data,
+				size_t data_size, bool reset)
+{
+	u8 *a_new;
+
+	if (reset) {
+		kfree(spdm_state->a);
+		spdm_state->a = NULL;
+		spdm_state->a_length = 0;
+	}
+
+	a_new = krealloc(spdm_state->a, spdm_state->a_length + data_size, GFP_KERNEL);
+	if (!a_new)
+		return -ENOMEM;
+
+	spdm_state->a = a_new;
+	memcpy(spdm_state->a + spdm_state->a_length, data, data_size);
+	spdm_state->a_length += data_size;
+
+	return 0;
+}
+
+#define SPDM_REQ 0x80
+#define SPDM_GET_VERSION 0x04
+
+struct spdm_get_version_req {
+	u8 version;
+	u8 code;
+	u8 param1;
+	u8 param2;
+};
+
+struct spdm_get_version_rsp {
+	u8 version;
+	u8 code;
+	u8 param1;
+	u8 param2;
+
+	u8 reserved;
+	u8 version_number_entry_count;
+	__le16 version_number_entries[];
+};
+
+#define SPDM_GET_CAPABILITIES 0x61
+
+/* For this exchange the request and response messages have the same form. */
+struct spdm_get_capabilities_reqrsp {
+	u8 version;
+	u8 code;
+	u8 param1;
+	u8 param2;
+
+	u8 reserved;
+	u8 ctexponent;
+	u16 reserved2;
+
+/* CACHE_CAP is only valid for response */
+#define SPDM_GET_CAP_FLAG_CACHE_CAP			BIT(0)
+#define SPDM_GET_CAP_FLAG_CERT_CAP			BIT(1)
+#define SPDM_GET_CAP_FLAG_CHAL_CAP			BIT(2)
+
+/* MEAS_CAP values other than 0 only for response */
+#define SPDM_GET_CAP_FLAG_MEAS_CAP_MSK			GENMASK(4, 3)
+#define   SPDM_GET_CAP_FLAG_MEAS_CAP_NO			0
+#define   SPDM_GET_CAP_FLAG_MEAS_CAP_MEAS		1
+#define   SPDM_GET_CAP_FLAG_MEAS_CAP_MEAS_SIG		2
+
+/* MEAS_FRESH_CAP == 0 for request */
+#define SPDM_GET_CAP_FLAG_MEAS_FRESH_CAP		BIT(5)
+#define SPDM_GET_CAP_FLAG_ENCRYPT_CAP			BIT(6)
+#define SPDM_GET_CAP_FLAG_MAC_CAP			BIT(7)
+#define SPDM_GET_CAP_FLAG_MUT_AUTH_CAP			BIT(8)
+#define SPDM_GET_CAP_FLAG_KEY_EX_CAP			BIT(9)
+
+#define SPDM_GET_CAP_FLAG_PSK_CAP_MSK			GENMASK(11, 10)
+#define   SPDM_GET_CAP_FLAG_PSK_CAP_NO_PRESHARE		0
+#define   SPDM_GET_CAP_FLAG_PSK_CAP_PRESHARE		1
+
+#define SPDM_GET_CAP_FLAG_ENCAP_CAP			BIT(12)
+#define SPDM_GET_CAP_FLAG_HBEAT_CAP			BIT(13)
+#define SPDM_GET_CAP_FLAG_KEY_UPD_CAP			BIT(14)
+#define SPDM_GET_CAP_FLAG_HANDSHAKE_ITC_CAP		BIT(15)
+#define SPDM_GET_CAP_FLAG_PUB_KEY_ID_CAP		BIT(16)
+	__le32 flags;
+};
+
+#define SPDM_NEGOTIATE_ALGS 0x63
+
+struct spdm_negotiate_algs_req {
+	u8 version;
+	u8 code;
+	u8 param1; /* Numer of algorithm structure tables */
+	u8 param2;
+
+	__le16 length; /* <= 128 bytes */
+	u8 measurement_specification;  /* Only one bit set, BIT 0 == DMTF */
+	u8 reserved;
+	__le32 base_asym_algo;
+
+	/* Bit mask, entries form spdm_base_hash_algo */
+	__le32 base_hash_algo;
+
+	u8 reserved2[12];
+	u8 ext_asm_count;
+	u8 ext_hash_count;
+	u8 reserved3[2];
+
+	/*
+	 * Additional fields at end of this structure
+	 * - ExtAsym 4 * ext_asm_count
+	 * - ExtHash 4 * ext_hash_count
+	 * - ReqAlgStruct size * param1
+	 */
+};
+
+struct spdm_negotiate_algs_rsp {
+	u8 version;
+	u8 code;
+	u8 param1; /* Numer of algorithm structure tables */
+	u8 param2;
+
+	__le16 length; /* <= 128 bytes */
+	u8 measurement_specification;  /* Only one bit set, BIT 0 == DMTF */
+	u8 reserved;
+
+	/* Exactly one bit must be set if GET_MEASUREMENTS is supported */
+	__le32 measurement_hash_algo;
+	/* At most one bit set to reflect negotiated alg */
+	__le32 base_asym_sel;
+	__le32 base_hash_sel;
+	u8 reserved2[12];
+	u8 ext_asym_sel_count; /* Either 0 or 1 */
+	u8 ext_hash_sel_count; /* Either 0 or 1 */
+	u8 reserved3[2];
+
+	/*
+	 * Additional fields at end of this structure
+	 * - ExtAsym 4 * ext_asm_count
+	 * - ExtHash 4 * ext_hash_count
+	 * - ReqAlgStruct size * param1
+	 */
+};
+
+#define SPDM_REQ_ALG_STRUCT_TYPE_DHE			0x2
+#define   SPDM_DHE_ALGO_FFDHE_2048			BIT(0)
+#define   SPDM_DHE_ALGO_FFDHE_3072			BIT(1)
+#define   SPDM_DHE_ALGO_FFDHE_4096			BIT(2)
+#define   SPDM_DHE_ALGO_SECP_256R1			BIT(3)
+#define   SPDM_DHE_ALGO_SECP_384R1			BIT(4)
+#define   SPDM_DHE_ALGO_SECP_521R1			BIT(5)
+
+#define SPDM_REQ_ALG_STRUCT_TYPE_AEAD_CIPHER_SUITE	0x3
+#define   SPDM_AEAD_ALGO_AES_128_GCM			BIT(0)
+#define   SPDM_AEAD_ALGO_AES_256_GCM			BIT(1)
+#define   SPDM_AEAD_ALGO_CHACHA20_POLY1305		BIT(2)
+#define SPDM_REQ_ALG_STRUCT_TYPE_REQ_BASE_ASYM_ALG	0x4
+/* As for base_asym_algo above */
+
+#define SPDM_REQ_ALG_STRUCT_TYPE_KEY_SCHEDULE		0x5
+#define   SPDM_KEY_SCHEDULE_SPDM			BIT(0)
+
+struct spdm_req_alg_struct {
+	u8 alg_type;
+	u8 alg_count; /* 0x2K where K is number of alg_external entries */
+	/* This field is sized based on alg_count[7:5] - currently always 2 */
+	__le16 alg_supported;
+	__le32 alg_external[];
+};
+
+#define SPDM_GET_DIGESTS 0x01
+struct spdm_digest_req {
+	u8 version;
+	u8 code;
+	u8 param1; /* Reserved */
+	u8 param2; /* Reserved */
+};
+
+struct spdm_cert_chain {
+	__le16 length;
+	u8 reserved[2];
+	/*
+	 * Additional fields:
+	 * - Hash of the root
+	 * - Certs: ASN.1 Der-encoded X.509 v3 - First cert signed by root or is the root.
+	 */
+};
+
+struct spdm_digest_rsp {
+	u8 version;
+	u8 code;
+	u8 param1; /* Reserved */
+	u8 param2; /* Slot mask */
+	/* Hash of spdm_cert_chain for each slot */
+	u8 digests[];
+};
+
+#define SPDM_GET_CERTIFICATE 0x02
+struct spdm_certificate_req {
+	u8 version;
+	u8 code;
+	u8 param1; /* Slot number 0..7 */
+	u8 param2; /* Reserved */
+	__le16 offset;
+	__le16 length; /* Note 0xFFFF and offset 0 is special value meaning whole chain */
+};
+
+struct spdm_certificate_rsp {
+	u8 version;
+	u8 code;
+	u8 param1; /* Slot number 0..7 */
+	u8 param2; /* Reserved */
+	__le16 portion_length;
+	__le16 remainder_length;
+	u8 cert_chain[]; /* Portion Length Long */
+};
+
+
+#define SPDM_CHALLENGE 0x03
+struct spdm_challenge_req {
+	u8 version;
+	u8 code;
+	u8 param1; /* Slot number 0..7 */
+	u8 param2; /* Measurement summary hash type */
+	u8 nonce[32];
+};
+
+struct spdm_challenge_rsp {
+	u8 version;
+	u8 code;
+	u8 param1; /* response attribute field, slot id from challenge, bit 7 is mutual auth */
+	u8 param2; /* slot mask */
+	/* Hash length cert chain */
+	/* Nonce, 32 bytes */
+	/* Measurement Summary Hash - if present */
+	/* 2 byte opaque length */
+	/* opaque data if length non 0 */
+	/* Signature */
+};
+
+static size_t spdm_challenge_rsp_signature_offset(struct spdm_state *spdm_state,
+						 struct spdm_challenge_req *req,
+						 struct spdm_challenge_rsp *rsp)
+{
+	u16 opaque_length;
+	size_t offset;
+
+	offset = sizeof(*rsp);		/* Header offset */
+	offset += spdm_state->h;	/* CertChain hash */
+	offset += 32;			/* Nonce */
+
+	/* Measurement summary hash */
+	if (req->param2 &&
+	    (spdm_state->responder_caps & SPDM_GET_CAP_FLAG_MAC_CAP))
+		offset += spdm_state->h;
+	/*
+	 * This is almost certainly aligned, but that's not obvious from nearby code
+	 * so play safe.
+	 */
+	opaque_length = get_unaligned_le16((u8 *)rsp + offset);
+	offset += sizeof(__le16);
+	offset += opaque_length;
+
+	return offset;
+}
+
+#define SPDM_ERROR 0x7f
+enum spdm_error_code {
+	spdm_invalid_request = 0x01,
+	spdm_invalid_session = 0x02,
+	spdm_busy = 0x03,
+	spdm_unexpected_request = 0x04,
+	spdm_unspecified = 0x05,
+	spdm_decrypt_error = 0x06,
+	spdm_unsupported_request = 0x07,
+	spdm_request_in_flight = 0x08,
+	spdm_invalid_response_code = 0x09,
+	spdm_session_limit_exceeded = 0x0a,
+	spdm_major_version_missmatch = 0x41,
+	spdm_response_not_ready = 0x42,
+	spdm_request_resync = 0x43,
+	spdm_vendor_defined_error = 0xff,
+};
+
+struct spdm_error_rsp {
+	u8 version;
+	u8 code;
+	u8 param1; /* Error code */
+	u8 param2; /* Error data */
+	u8 extended_error_data[];
+};
+#define SPDM_ERROR_MIN_SIZE sizeof(struct spdm_error_rsp)
+
+static void spdm_err(struct device *dev, enum spdm_error_code error_code,
+		     u8 error_data)
+{
+	switch (error_code) {
+	case spdm_invalid_request:
+		dev_err(dev, "Invalid Request\n");
+		break;
+	case spdm_invalid_session:
+		dev_err(dev, "Invalid Session %#x\n", error_data);
+		break;
+	case spdm_busy:
+		dev_err(dev, "Busy\n");
+		break;
+	case spdm_unexpected_request:
+		dev_err(dev, "Unexpected request\n");
+		break;
+	case spdm_unspecified:
+		dev_err(dev, "Unspecified\n");
+		break;
+	case spdm_decrypt_error:
+		dev_err(dev, "Decrypt Error\n");
+		break;
+	case spdm_unsupported_request:
+		dev_err(dev, "Unsupported Request %#x\n", error_data);
+		break;
+	case spdm_request_in_flight:
+		dev_err(dev, "Request in flight\n");
+		break;
+	case spdm_invalid_response_code:
+		dev_err(dev, "Invalid response code\n");
+		break;
+	case spdm_session_limit_exceeded:
+		dev_err(dev, "Session limit exceeded\n");
+		break;
+	case spdm_major_version_missmatch:
+		dev_err(dev, "Major version mismatch\n");
+		break;
+	case spdm_response_not_ready:
+		dev_err(dev, "Response not ready\n");
+		break;
+	case spdm_request_resync:
+		dev_err(dev, "Request resynchronization\n");
+		break;
+	case spdm_vendor_defined_error:
+		dev_err(dev, "Vendor defined error\n");
+		break;
+	}
+}
+
+static int __spdm_exchange(struct spdm_state *spdm_state, struct spdm_exchange *ex, u8 version)
+{
+	int length;
+	int rc;
+
+	if (ex->request_pl_sz < sizeof(*ex->request_pl) ||
+	    ex->response_pl_sz < sizeof(*ex->response_pl))
+		return -EINVAL;
+
+	ex->request_pl->version = version;
+	ex->request_pl->code = SPDM_REQ | ex->code;
+
+	/* Will become an op pointer if we have a second transport */
+	rc = spdm_state->transport_ex(spdm_state->transport_priv, ex);
+	if (rc < 0)
+		return rc;
+
+	length = rc;
+	if (length < SPDM_ERROR_MIN_SIZE)
+		return -EIO;
+
+	if (ex->response_pl->code == SPDM_ERROR) {
+		spdm_err(spdm_state->dev, ex->response_pl->param1,
+			 ex->response_pl->param2);
+		return -EIO;
+	}
+
+	if (ex->response_pl->code != ex->code) {
+		dev_err(spdm_state->dev,
+			"Invalid SPDM response received - does not match request code\n");
+		return -EIO;
+	}
+
+	return length;
+}
+
+static int spdm1p0_exchange(struct spdm_state *spdm_state, struct spdm_exchange *ex)
+{
+	return __spdm_exchange(spdm_state, ex, 0x10);
+}
+
+static int spdm1p1_exchange(struct spdm_state *spdm_state, struct spdm_exchange *ex)
+{
+	return __spdm_exchange(spdm_state, ex, 0x11);
+}
+
+static int spdm_get_version_1p1(struct spdm_state *spdm_state)
+{
+	struct spdm_get_version_req req = {};
+	struct spdm_get_version_rsp *rsp;
+	struct spdm_exchange spdm_ex;
+	ssize_t rc, rsp_sz, length;
+	int numversions = 2;
+
+retry:
+	rsp_sz = struct_size(rsp, version_number_entries, numversions);
+	rsp = kzalloc(rsp_sz, GFP_KERNEL);
+
+	spdm_ex = (struct spdm_exchange) {
+		.request_pl = (struct spdm_header *)&req,
+		.request_pl_sz = sizeof(req),
+		.response_pl = (struct spdm_header *)rsp,
+		.response_pl_sz = rsp_sz,
+		.code = SPDM_GET_VERSION,
+	};
+	rc = spdm1p0_exchange(spdm_state, &spdm_ex);
+	if (rc < 0)
+		goto err;
+
+	length = rc;
+
+	if (length < struct_size(rsp, version_number_entries, 1)) {
+		dev_err(spdm_state->dev, "SPDM must support at least one version\n");
+		rc = -EIO;
+		goto err;
+	}
+
+	/* If we didn't allocate enough space the first time, go around again */
+	if (rsp->version_number_entry_count > numversions) {
+		numversions = rsp->version_number_entry_count;
+		kfree(rsp);
+		goto retry;
+	}
+
+	/*
+	 * Cache the request and response to use later to compute a message digest,
+	 * as the algorithm to use is not yet known.
+	 *
+	 * Response may be padded, so we need to compute the length rather than relying
+	 * on the length returned by the transport.
+	 */
+	length = struct_size(rsp, version_number_entries, rsp->version_number_entry_count);
+	rc = spdm_append_buffer_a(spdm_state, &req, sizeof(req), true);
+	if (rc)
+		goto err;
+
+	rc = spdm_append_buffer_a(spdm_state, rsp, length, false);
+
+err:
+	kfree(rsp);
+
+	return rc;
+}
+
+
+static int spdm_negotiate_caps(struct spdm_state *spdm_state, u32 req_caps,
+			       u32 *rsp_caps)
+{
+	struct spdm_get_capabilities_reqrsp req = {
+		.ctexponent = 2, /* FIXME: Chose sensible value */
+		.flags = cpu_to_le32(req_caps),
+	};
+	struct spdm_get_capabilities_reqrsp rsp;
+	struct spdm_exchange spdm_ex = {
+		.request_pl = (struct spdm_header *)&req,
+		.request_pl_sz = sizeof(req),
+		.response_pl = (struct spdm_header *)&rsp,
+		.response_pl_sz = sizeof(rsp),
+		.code = SPDM_GET_CAPABILITIES,
+	};
+	int rc, length;
+
+	rc = spdm1p1_exchange(spdm_state, &spdm_ex);
+	if (rc < 0)
+		return rc;
+	length = rc;
+
+	if (length < sizeof(rsp)) {
+		dev_err(spdm_state->dev, "NEGOTIATE_CAPS response short\n");
+		return -EIO;
+	}
+	/* Cache capability as can affect data layout for other messages */
+	spdm_state->responder_caps = le32_to_cpu(rsp.flags);
+
+	if (rsp_caps)
+		*rsp_caps = spdm_state->responder_caps;
+
+	rc = spdm_append_buffer_a(spdm_state, &req, sizeof(req), false);
+	if (rc)
+		return rc;
+
+	return spdm_append_buffer_a(spdm_state, &rsp, sizeof(rsp), false);
+}
+
+static int spdm_start_digest(struct spdm_state *spdm_state,
+			     void *req, size_t req_sz, void *rsp, size_t rsp_sz)
+{
+	int rc;
+
+	/* Build first part of challenge hash */
+	switch (spdm_state->base_hash_alg) {
+	case spdm_base_hash_sha_384:
+		spdm_state->shash = crypto_alloc_shash("sha384", 0, CRYPTO_ALG_ASYNC);
+		break;
+	case spdm_base_hash_sha_256:
+		spdm_state->shash = crypto_alloc_shash("sha256", 0, CRYPTO_ALG_ASYNC);
+		break;
+	default:
+		/* Given device must support one of the above, lets stick to them for now */
+		return -EINVAL;
+	}
+
+	if (!spdm_state->shash)
+		return -ENOMEM;
+
+	/* Used frequently to compute offsets, so cache H */
+	spdm_state->h = crypto_shash_digestsize(spdm_state->shash);
+
+	spdm_state->desc = kzalloc(struct_size(spdm_state->desc, __ctx,
+					       crypto_shash_descsize(spdm_state->shash)),
+				   GFP_KERNEL);
+	if (!spdm_state->desc) {
+		rc = -ENOMEM;
+		goto err_free_shash;
+	}
+	spdm_state->desc->tfm = spdm_state->shash;
+
+	rc = crypto_shash_init(spdm_state->desc);
+	if (rc)
+		goto err_free_desc;
+
+	rc = crypto_shash_update(spdm_state->desc, spdm_state->a,
+				 spdm_state->a_length);
+	if (rc)
+		goto err_free_desc;
+
+	rc = crypto_shash_update(spdm_state->desc, (u8 *)req, req_sz);
+
+	if (rc)
+		goto err_free_desc;
+
+	rc = crypto_shash_update(spdm_state->desc, (u8 *)rsp, rsp_sz);
+	if (rc)
+		goto err_free_desc;
+
+	kfree(spdm_state->a);
+	spdm_state->a = NULL;
+	spdm_state->a_length = 0;
+
+	return 0;
+
+err_free_desc:
+	kfree(spdm_state->desc);
+err_free_shash:
+	crypto_free_shash(spdm_state->shash);
+	return rc;
+}
+
+static int spdm_negotiate_algs(struct spdm_state *spdm_state)
+{
+	struct spdm_req_alg_struct *req_alg_struct;
+	/*
+	 * Current support is focused on enabling PCI/CMA
+	 *
+	 * CMA requires that device must support
+	 * One or more of:
+	 *  - RSASSA_3072
+	 *  - ECDSA_ECC_NIST_P256
+	 *  - ECDSA_ECC_NIST_P384
+	 * One or more of:
+	 *  - SHA_256
+	 *  - SHA_384
+	 */
+	struct spdm_negotiate_algs_req *req;
+	struct spdm_negotiate_algs_rsp *rsp;
+	struct spdm_exchange spdm_ex;
+	/*
+	 * There are several variable length elements at the end of these structures.
+	 * Allow for 0 Ext Asym, 0 Ext Hash, 4 ReqAlgStructs
+	 */
+	size_t req_sz = sizeof(*req) + 16;
+	/*
+	 * Response length may be less than this if not all algorithm types supported,
+	 * resulting in fewer AlgStructure fields than in the request.
+	 */
+	size_t rsp_sz = sizeof(*rsp) + 16;
+	size_t length;
+	int rc;
+
+	req = kzalloc(req_sz, GFP_KERNEL);
+	if (!req)
+		return -ENOMEM;
+
+	req->param1 = 4;
+	req->code = SPDM_NEGOTIATE_ALGS | SPDM_REQ;
+	req->length = cpu_to_le16(req_sz);
+	req->measurement_specification = BIT(0);
+	req->base_asym_algo = cpu_to_le16(BIT(spdm_asym_rsassa_3072) |
+					  BIT(spdm_asym_ecdsa_ecc_nist_p256) |
+					  BIT(spdm_asym_ecdsa_ecc_nist_p384));
+	req->base_hash_algo = cpu_to_le16(BIT(spdm_base_hash_sha_256) |
+					  BIT(spdm_base_hash_sha_384));
+
+	req->ext_asm_count = 0;
+	req->ext_hash_count = 0;
+	req_alg_struct = (struct spdm_req_alg_struct *)(req + 1);
+	/*
+	 * For CMA only we don't need to support DHE, AEAD or Key Schedule - but the
+	 * responder may reply with them anyway.
+	 * TODO: Identify minimum set needed.
+	 */
+	req_alg_struct[0] = (struct spdm_req_alg_struct) {
+		.alg_type = SPDM_REQ_ALG_STRUCT_TYPE_DHE,
+		.alg_count = 0x20,
+		.alg_supported = cpu_to_le16(SPDM_DHE_ALGO_FFDHE_2048 |
+					     SPDM_DHE_ALGO_FFDHE_3072 |
+					     SPDM_DHE_ALGO_SECP_256R1 |
+					     SPDM_DHE_ALGO_SECP_384R1)
+					     };
+	req_alg_struct[1] = (struct spdm_req_alg_struct) {
+		.alg_type = SPDM_REQ_ALG_STRUCT_TYPE_AEAD_CIPHER_SUITE,
+		.alg_count = 0x20,
+		.alg_supported = cpu_to_le16(SPDM_AEAD_ALGO_AES_256_GCM |
+					     SPDM_AEAD_ALGO_CHACHA20_POLY1305)
+	};
+	req_alg_struct[2] = (struct spdm_req_alg_struct) {
+		.alg_type = SPDM_REQ_ALG_STRUCT_TYPE_REQ_BASE_ASYM_ALG,
+		.alg_count = 0x20,
+		.alg_supported = cpu_to_le16(BIT(spdm_asym_rsassa_3072) |
+					     BIT(spdm_asym_ecdsa_ecc_nist_p256) |
+					     BIT(spdm_asym_ecdsa_ecc_nist_p384)),
+	};
+	req_alg_struct[3] = (struct spdm_req_alg_struct) {
+		.alg_type = SPDM_REQ_ALG_STRUCT_TYPE_KEY_SCHEDULE,
+		.alg_count = 0x20,
+		.alg_supported = cpu_to_le16(SPDM_KEY_SCHEDULE_SPDM)
+	};
+
+	rsp = kzalloc(rsp_sz, GFP_KERNEL);
+	if (!rsp) {
+		rc = -ENOMEM;
+		goto err_free_req;
+	}
+
+	spdm_ex = (struct spdm_exchange) {
+		.request_pl = (struct spdm_header *)req,
+		.request_pl_sz = req_sz,
+		.response_pl = (struct spdm_header *)rsp,
+		.response_pl_sz = rsp_sz,
+		.code = SPDM_NEGOTIATE_ALGS,
+	};
+
+	rc = spdm1p1_exchange(spdm_state, &spdm_ex);
+	if (rc < 0)
+		goto err_free_rsp;
+	length = rc;
+
+	//TODO: Check this cannot return short.
+	if (length < rsp_sz) {
+		dev_err(spdm_state->dev, "Response too short\n");
+		rc = -EIO;
+		goto err_free_rsp;
+	}
+
+	spdm_state->measurement_hash_alg = __ffs(le16_to_cpu(rsp->measurement_hash_algo));
+	spdm_state->base_asym_alg = __ffs(le16_to_cpu(rsp->base_asym_sel));
+	spdm_state->base_hash_alg = __ffs(le16_to_cpu(rsp->base_hash_sel));
+
+	switch (spdm_state->base_asym_alg) {
+	case spdm_asym_rsassa_3072:
+		spdm_state->s = 384;
+		break;
+	case spdm_asym_ecdsa_ecc_nist_p256:
+		spdm_state->s = 64;
+		break;
+	case spdm_asym_ecdsa_ecc_nist_p384:
+		spdm_state->s = 96;
+		break;
+	default:
+		dev_err(spdm_state->dev, "Unknown async base algorithm\n");
+		rc = -EINVAL;
+		goto err_free_rsp;
+	}
+
+	rsp_sz = sizeof(*rsp) + rsp->param1 * sizeof(struct spdm_req_alg_struct);
+	rc = spdm_start_digest(spdm_state, req, req_sz, rsp, rsp_sz);
+
+err_free_rsp:
+	kfree(rsp);
+err_free_req:
+	kfree(req);
+
+	return rc;
+}
+
+static int spdm_get_digests(struct spdm_state *spdm_state)
+{
+	struct spdm_digest_req req = {};
+	struct spdm_digest_rsp *rsp;
+	struct spdm_exchange spdm_ex;
+	unsigned long slot_bm;
+	int rc;
+	/* Assume all slots may be present */
+	size_t rsp_sz;
+
+	rsp_sz = struct_size(rsp, digests, spdm_state->h * 8);
+	rsp = kzalloc(rsp_sz, GFP_KERNEL);
+	if (!rsp)
+		return -ENOMEM;
+
+	spdm_ex = (struct spdm_exchange) {
+		.request_pl = (struct spdm_header *)&req,
+		.request_pl_sz = sizeof(req),
+		.response_pl = (struct spdm_header *)rsp,
+		.response_pl_sz = rsp_sz,
+		.code = SPDM_GET_DIGESTS,
+	};
+
+	rc = spdm1p1_exchange(spdm_state, &spdm_ex);
+	if (rc < 0)
+		return rc;
+
+	rc = crypto_shash_update(spdm_state->desc, (u8 *)&req, sizeof(req));
+	if (rc)
+		goto err_free_rsp;
+
+	slot_bm = rsp->param2;
+	rsp_sz = struct_size(rsp, digests,
+			     spdm_state->h *
+			     bitmap_weight(&slot_bm, 8 * sizeof(rsp->param2)));
+
+	rc = crypto_shash_update(spdm_state->desc, (u8 *)rsp, rsp_sz);
+
+err_free_rsp:
+	kfree(rsp);
+
+	return rc;
+}
+
+/* Used to give a unique name for per device keychains */
+static DEFINE_IDA(spdm_ida);
+
+static int spdm_get_certificate(struct spdm_state *spdm_state)
+{
+	//TODO: Test this.
+	/* This should ensure the limitation is rarely at the requester */
+	u16 bufsize = 0x8000;
+	struct spdm_certificate_req req = {
+		.param1 = 0, /* Slot 0 */
+	};
+	struct spdm_certificate_rsp *rsp;
+	size_t rsp_sz;
+	struct spdm_exchange spdm_ex;
+	u16 remainder_length = bufsize;
+	u16 offset = 0;
+	char *keyring_name;
+	int keyring_id;
+	u8 *certs = NULL;
+	u16 certs_length = 0;
+	u16 next_cert;
+	int rc;
+
+	rsp_sz = struct_size(rsp, cert_chain, bufsize);
+	rsp = kzalloc(rsp_sz, GFP_KERNEL);
+	if (!rsp)
+		return -ENOMEM;
+
+	spdm_ex = (struct spdm_exchange) {
+		.request_pl = (struct spdm_header *)&req,
+		.request_pl_sz = sizeof(req),
+		.response_pl = (struct spdm_header *)rsp,
+		.response_pl_sz = rsp_sz,
+		.code = SPDM_GET_CERTIFICATE,
+	};
+
+	while (remainder_length > 0) {
+		u8 *newcerts;
+
+		req.length = min(remainder_length, bufsize);
+		req.offset = offset;
+
+		rc = spdm1p1_exchange(spdm_state, &spdm_ex);
+		if (rc < 0)
+			goto err_free_certs;
+
+		/*
+		 * Taking the hash of each message was established by looking at
+		 * what openSPDM does, rather than it being clear from the SPDM
+		 * specification.
+		 */
+		rc = crypto_shash_update(spdm_state->desc, (u8 *)&req, sizeof(req));
+		if (rc)
+			goto err_free_certs;
+
+		/* Care needed - each message might not be full length due to padding */
+		rc = crypto_shash_update(spdm_state->desc, (u8 *)rsp,
+					 sizeof(rsp) + rsp->portion_length);
+		if (rc)
+			goto err_free_certs;
+
+		certs_length += rsp->portion_length;
+		newcerts = krealloc(certs, certs_length, GFP_KERNEL);
+		if (!newcerts) {
+			rc = -ENOMEM;
+			goto err_free_certs;
+		}
+		certs = newcerts;
+		memcpy(certs + offset, rsp->cert_chain, rsp->portion_length);
+		offset += rsp->portion_length;
+		remainder_length = rsp->remainder_length;
+	}
+
+	keyring_id = ida_alloc(&spdm_ida, GFP_KERNEL);
+	if (keyring_id < 0) {
+		rc = keyring_id;
+		goto err_free_certs;
+
+	}
+
+	keyring_name = kasprintf(GFP_KERNEL, "_spdm%02d", keyring_id);
+	if (!keyring_name) {
+		rc = -ENOMEM;
+		goto err_free_ida;
+	}
+
+	/*
+	 * Create a spdm instance specific keyring to avoid mixing certs,
+	 * Not a child of _cma keyring, because the search below should
+	 * not find a self signed cert in here.
+	 *
+	 * Not sure how to release a keyring, so currently if this fails we leak.
+	 * That might be fine but an ida could get reused.
+	 */
+	spdm_state->keyring = keyring_alloc(keyring_name,
+					    KUIDT_INIT(0), KGIDT_INIT(0),
+					    current_cred(),
+					    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+					    KEY_USR_VIEW | KEY_USR_READ,
+					    KEY_ALLOC_NOT_IN_QUOTA |
+					    KEY_ALLOC_SET_KEEP,
+					    NULL, NULL);
+	kfree(keyring_name);
+	if (IS_ERR(spdm_state->keyring)) {
+		dev_err(spdm_state->dev,
+			"Failed to allocate per spdm keyring\n");
+		rc = PTR_ERR(spdm_state->keyring);
+		goto err_free_ida;
+	}
+
+	next_cert = sizeof(struct spdm_cert_chain) + spdm_state->h;
+
+	/*
+	 * Store the certificate chain on the per SPDM instance keyring.
+	 * Allow for up to 3 bytes padding as transport sends multiples of 4 bytes.
+	 */
+	while (next_cert < offset) {
+		struct key *key;
+		key_ref_t key2;
+
+		key2 = key_create_or_update(make_key_ref(spdm_state->keyring, 1),
+					    "asymmetric", NULL,
+					    certs + next_cert, offset - next_cert,
+					    (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+					    KEY_USR_VIEW | KEY_USR_READ,
+					    KEY_ALLOC_NOT_IN_QUOTA);
+
+		if (IS_ERR(key2)) {
+			/* FIXME: Any additional cleanup to do here? */
+			rc = PTR_ERR(key2);
+			goto err_free_ida;
+		}
+
+		if (!spdm_state->leaf_key) {
+			/* First key in chain, so check against keys on _cma keyring */
+			struct public_key_signature *sig =
+				key_ref_to_ptr(key2)->payload.data[asym_auth];
+
+			key = find_asymmetric_key(spdm_state->root_keyring, sig->auth_ids[0],
+						  sig->auth_ids[1], false);
+			if (IS_ERR(key)) {
+				dev_err(spdm_state->dev,
+					"Unable to retrieve signing certificate from _cma keyring\n");
+				rc = PTR_ERR(key);
+				goto err_free_ida;
+			}
+
+			rc = verify_signature(key, sig);
+			if (rc) {
+				dev_err(spdm_state->dev,
+					"Unable to check SPDM cert against _cma keyring\n");
+				goto err_free_ida;
+			}
+
+			spdm_state->leaf_key = key_ref_to_ptr(key2);
+		} else {
+			/* Not the first key in chain, so check it against previous one */
+			struct public_key_signature *sig =
+				key_ref_to_ptr(key2)->payload.data[asym_auth];
+
+			rc = verify_signature(spdm_state->leaf_key, sig);
+			if (rc) {
+				dev_err(spdm_state->dev,
+					"Unable to verify SPDM cert against previous cert in chain\n");
+				goto err_free_ida;
+			}
+			spdm_state->leaf_key = key_ref_to_ptr(key2);
+		}
+		/*
+		 * Horrible but need to pull this directly from the ASN1 stream as the cert
+		 * chain is a concatentation of multiple cerificates.
+		 */
+		next_cert += get_unaligned_be16(certs + next_cert + 2) + 4;
+	}
+
+	kfree(certs);
+	kfree(rsp);
+
+	return 0;
+
+err_free_ida:
+	ida_free(&spdm_ida, keyring_id);
+err_free_certs:
+	kfree(certs);
+	kfree(rsp);
+
+	return rc;
+}
+
+
+static int spdm_verify_signature(struct spdm_state *spdm_state, u8 *sig_ptr,
+				 u8 *digest, unsigned int digest_size)
+{
+	const struct asymmetric_key_ids *ids;
+	struct public_key_signature sig = {};
+	/* Large enough for an ASN1 enocding of supported ECC signatures */
+	unsigned char buffer2[128] = {};
+	int rc;
+
+	/*
+	 * The ecdsa signatures are raw concatentation of the two values.
+	 * In order to use verify_signature we need to reformat them into ASN1.
+	 */
+	switch (spdm_state->base_asym_alg) {
+	case spdm_asym_ecdsa_ecc_nist_p256:
+	case spdm_asym_ecdsa_ecc_nist_p384:
+	{
+		unsigned char buffer[128] = {};
+		unsigned char *p = buffer;
+		unsigned char *p2;
+
+		//TODO: test the ASN1 function rather more extensively.
+		/* First pack the two large integer values */
+		p = asn1_encode_integer_large_positive(p, buffer + sizeof(buffer),
+						       ASN1_INT, sig_ptr,
+						       spdm_state->s / 2);
+		p = asn1_encode_integer_large_positive(p, buffer + sizeof(buffer),
+						       ASN1_INT,
+						       sig_ptr + spdm_state->s  / 2,
+						       spdm_state->s / 2);
+
+		/* In turn pack those two large integer values into a sequence */
+		p2 = asn1_encode_sequence(buffer2, buffer2 + sizeof(buffer2),
+					  buffer, p - buffer);
+
+		sig.s = buffer2;
+		sig.s_size = p2 - buffer2;
+		sig.encoding = "raw";
+		break;
+	}
+
+	case spdm_asym_rsassa_3072:
+		sig.s = sig_ptr;
+		sig.s_size = spdm_state->s;
+		sig.encoding = "pkcs1";
+		break;
+	default:
+		dev_err(spdm_state->dev,
+			"Signature algorithm not yet supported\n");
+		return -EINVAL;
+	}
+	sig.digest = digest;
+	sig.digest_size = digest_size;
+	ids = asymmetric_key_ids(spdm_state->leaf_key);
+	sig.auth_ids[0] = ids->id[0];
+	sig.auth_ids[1] = ids->id[1];
+
+	switch (spdm_state->base_hash_alg) {
+	case spdm_base_hash_sha_384:
+		sig.hash_algo = "sha384";
+		break;
+	case spdm_base_hash_sha_256:
+		sig.hash_algo = "sha256";
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	rc = verify_signature(spdm_state->leaf_key, &sig);
+	if (rc) {
+		dev_err(spdm_state->dev,
+			"Failed to verify challenge_auth signature %d\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+static int spdm_challenge(struct spdm_state *spdm_state)
+{
+	struct spdm_challenge_req req = {
+		.param1 = 0, /* slot 0 for now */
+		.param2 = 0, /* no measurement summary hash */
+	};
+	struct spdm_challenge_rsp *rsp;
+	struct spdm_exchange spdm_ex;
+	size_t sig_offset, rsp_max_size;
+	int length, rc;
+	u8 *digest;
+
+	/*
+	 * The response length is up to:
+	 * 4 byte header
+	 * H byte CertChainHash
+	 * 32 byte nonce
+	 * (H byte Measurement Summary Hash - not currently requested)
+	 * 2 byte Opaque Length
+	 * <= 1024 bytes Opaque Data
+	 * S byte signature
+	 */
+	rsp_max_size = 4 + spdm_state->h + 32 + 2 + 1024 + spdm_state->s;
+	rsp = kzalloc(rsp_max_size, GFP_KERNEL);
+	if (!rsp)
+		return -ENOMEM;
+
+	get_random_bytes(&req.nonce, sizeof(req.nonce));
+
+	spdm_ex = (struct spdm_exchange) {
+		.request_pl = (struct spdm_header *)&req,
+		.request_pl_sz = sizeof(req),
+		.response_pl = (struct spdm_header *)rsp,
+		.response_pl_sz = rsp_max_size,
+		.code = SPDM_CHALLENGE,
+	};
+
+	rc = spdm1p1_exchange(spdm_state, &spdm_ex);
+	if (rc < 0)
+		goto err_free_rsp;
+	length = rc;
+
+	/* Last step of building the digest */
+	rc = crypto_shash_update(spdm_state->desc, (u8 *)&req, sizeof(req));
+	if (rc)
+		goto err_free_rsp;
+
+	/* The hash is complete + signature received; verify against leaf key */
+	sig_offset = spdm_challenge_rsp_signature_offset(spdm_state, &req, rsp);
+	if (sig_offset >= length) {
+		rc = -EIO;
+		goto err_free_rsp;
+	}
+
+	rc = crypto_shash_update(spdm_state->desc, (u8 *)rsp, sig_offset);
+	if (rc)
+		goto err_free_rsp;
+
+	digest = kmalloc(spdm_state->h, GFP_KERNEL);
+	if (!digest) {
+		rc = -ENOMEM;
+		goto err_free_rsp;
+	}
+
+	crypto_shash_final(spdm_state->desc, digest);
+
+	rc = spdm_verify_signature(spdm_state, (u8 *)rsp + sig_offset, digest,
+				   spdm_state->h);
+	if (rc) {
+		dev_err(spdm_state->dev, "Failed to verify SPDM challenge auth signature\n");
+		goto err_free_digest;
+	}
+
+	kfree(spdm_state->desc);
+
+	/* Clear to give a simple way to detect out of order */
+	spdm_state->desc = NULL;
+
+err_free_digest:
+	kfree(digest);
+
+err_free_rsp:
+	kfree(rsp);
+	return rc;
+}
+
+int spdm_authenticate(struct spdm_state *spdm_state)
+{
+	u32 req_caps, rsp_caps;
+	int rc;
+
+	rc = spdm_get_version_1p1(spdm_state);
+	if (rc)
+		return rc;
+
+	/* TODO: work out if a subset of these is fine for CMA */
+	req_caps = SPDM_GET_CAP_FLAG_CERT_CAP |
+		SPDM_GET_CAP_FLAG_CHAL_CAP |
+		SPDM_GET_CAP_FLAG_ENCRYPT_CAP |
+		SPDM_GET_CAP_FLAG_MAC_CAP |
+		SPDM_GET_CAP_FLAG_MUT_AUTH_CAP |
+		SPDM_GET_CAP_FLAG_KEY_EX_CAP |
+		FIELD_PREP(SPDM_GET_CAP_FLAG_PSK_CAP_MSK, SPDM_GET_CAP_FLAG_PSK_CAP_PRESHARE) |
+		SPDM_GET_CAP_FLAG_ENCAP_CAP |
+		SPDM_GET_CAP_FLAG_HBEAT_CAP |
+		SPDM_GET_CAP_FLAG_KEY_UPD_CAP |
+		SPDM_GET_CAP_FLAG_HANDSHAKE_ITC_CAP;
+
+	rc = spdm_negotiate_caps(spdm_state, req_caps, &rsp_caps);
+	if (rc)
+		return rc;
+
+	rc = spdm_negotiate_algs(spdm_state);
+	if (rc)
+		return rc;
+
+	/* At this point we know the hash so can start calculating it as we go */
+	rc = spdm_get_digests(spdm_state);
+	if (rc)
+		goto err_free_hash;
+
+	rc = spdm_get_certificate(spdm_state);
+	if (rc)
+		goto err_free_hash;
+
+	rc = spdm_challenge(spdm_state);
+	if (rc)
+		goto err_free_hash;
+
+	/*
+	 * If we get to here, we have successfully verified the device is one we are happy
+	 * with using.
+	 */
+	return 0;
+
+err_free_hash:
+	kfree(spdm_state->desc);
+	crypto_free_shash(spdm_state->shash);
+
+	return rc;
+}
+EXPORT_SYMBOL_GPL(spdm_authenticate);
+
+MODULE_LICENSE("GPL v2");
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC PATCH 3/4] PCI/CMA: Initial support for Component Measurement and Authentication ECN
  2021-08-04 16:18 [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
  2021-08-04 16:18 ` [RFC PATCH 1/4] lib/asn1_encoder: Add a function to encode many byte integer values Jonathan Cameron
  2021-08-04 16:18 ` [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM Jonathan Cameron
@ 2021-08-04 16:18 ` Jonathan Cameron
  2021-09-17 16:22   ` Jonathan Cameron
  2021-08-04 16:18 ` [RFC PATCH 4/4] cxl/pci: Add really basic CMA authentication support Jonathan Cameron
  2021-08-05 16:43 ` [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
  4 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-04 16:18 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr, Jonathan Cameron

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>
---
 drivers/pci/Kconfig     | 9 +++++++++
 drivers/pci/Makefile    | 1 +
 drivers/pci/doe.c       | 2 --
 include/linux/pci-doe.h | 2 ++
 4 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index a30c59cf5e27..43e3b0d5e8cd 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -198,6 +198,15 @@ config PCI_DOE
 	  used by a number of different protocols.
 	  DOE is defined in the Data Object Exchange ECN to the PCIe r5.0 spec.
 
+config PCI_CMA
+	tristate
+	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
+
 choice
 	prompt "PCI Express hierarchy optimization setting"
 	default PCIE_BUS_DEFAULT
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 1b61c1a1c232..3f6b3543d565 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -29,6 +29,7 @@ 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)		+= doe.o
+obj-$(CONFIG_PCI_CMA)		+= cma.o
 obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
 
 # Endpoint library must be initialized before its users
diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
index 2d20f59e42c6..f6aaeed01010 100644
--- a/drivers/pci/doe.c
+++ b/drivers/pci/doe.c
@@ -20,8 +20,6 @@
 /* Maximum number of DOE instances in the system */
 #define PCI_DOE_MAX_CNT 65536
 
-#define PCI_DOE_PROTOCOL_DISCOVERY 0
-
 #define PCI_DOE_BUSY_MAX_RETRIES 16
 #define PCI_DOE_POLL_INTERVAL (HZ / 128)
 
diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h
index bdc5f15f14ab..1347c124ed70 100644
--- a/include/linux/pci-doe.h
+++ b/include/linux/pci-doe.h
@@ -19,6 +19,8 @@ struct pci_doe_prot {
 	u8 type;
 };
 
+#define PCI_DOE_PROTOCOL_DISCOVERY 0
+#define PCI_DOE_PROTOCOL_CMA 1
 struct workqueue_struct;
 
 enum pci_doe_state {
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [RFC PATCH 4/4] cxl/pci: Add really basic CMA authentication support.
  2021-08-04 16:18 [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
                   ` (2 preceding siblings ...)
  2021-08-04 16:18 ` [RFC PATCH 3/4] PCI/CMA: Initial support for Component Measurement and Authentication ECN Jonathan Cameron
@ 2021-08-04 16:18 ` Jonathan Cameron
  2021-08-05 16:43 ` [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
  4 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-04 16:18 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr, Jonathan Cameron

This is just for purposes of poking the CMA / SPDM code.
What exactly the model in the driver looks like is still to
be worked out.

Note the PROBE_FORCE_SYNCHRONOUS is a workaround to avoid warnings
about trying to load an additional crypto module whilst doing an
asychronous probe.

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/cxl/Kconfig |  1 +
 drivers/cxl/mem.h   |  2 ++
 drivers/cxl/pci.c   | 13 ++++++++++++-
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index e2bca26eb879..c726cc9adddb 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -17,6 +17,7 @@ config CXL_MEM
 	tristate "CXL.mem: Memory Devices"
 	default CXL_BUS
 	select PCI_DOE
+	select PCI_CMA
 	help
 	  The CXL.mem protocol allows a device to act as a provider of
 	  "System RAM" and/or "Persistent Memory" that is fully coherent
diff --git a/drivers/cxl/mem.h b/drivers/cxl/mem.h
index f626aa7eb389..cb8c2dfda277 100644
--- a/drivers/cxl/mem.h
+++ b/drivers/cxl/mem.h
@@ -57,6 +57,7 @@ struct cxl_memdev {
  * @pdev: The PCI device associated with this CXL device.
  * @cxlmd: Logical memory device chardev / interface
  * @table_doe: Data exchange object mailbox used to read tables
+ * @cma_doe: Component measurement and authentication mailbox
  * @regs: Parsed register blocks
  * @payload_size: Size of space for payload
  *                (CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register)
@@ -73,6 +74,7 @@ struct cxl_mem {
 	struct cxl_memdev *cxlmd;
 
 	struct pci_doe *table_doe;
+	struct pci_doe *cma_doe;
 	struct cxl_regs regs;
 
 	size_t payload_size;
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 471bddc9d167..e6ca84cc6fff 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -2,10 +2,12 @@
 /* Copyright(c) 2020 Intel Corporation. All rights reserved. */
 #include <uapi/linux/cxl_mem.h>
 #include <linux/security.h>
+#include <linux/pci-cma.h>
 #include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/sizes.h>
 #include <linux/mutex.h>
+#include <linux/spdm.h>
 #include <linux/list.h>
 #include <linux/cdev.h>
 #include <linux/idr.h>
@@ -1723,6 +1725,7 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct cxl_memdev *cxlmd;
 	struct cxl_mem *cxlm;
+	struct spdm_state spdm_state;
 	int rc, irqs;
 
 	rc = pcim_enable_device(pdev);
@@ -1770,6 +1773,14 @@ static int cxl_mem_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	cxlm->table_doe = pci_doe_find(pdev, PCI_DVSEC_VENDOR_ID_CXL,
 				       CXL_DOE_PROTOCOL_TABLE_ACCESS);
 
+	cxlm->cma_doe = pci_doe_find(pdev, PCI_VENDOR_ID_PCI_SIG,
+				     PCI_DOE_PROTOCOL_CMA);
+
+	pci_cma_init(cxlm->cma_doe, &spdm_state);
+	rc = pci_cma_authenticate(&spdm_state);
+	if (rc)
+		return rc;
+
 	rc = cxl_mem_setup_regs(cxlm);
 	if (rc)
 		return rc;
@@ -1808,7 +1819,7 @@ static struct pci_driver cxl_mem_driver = {
 	.id_table		= cxl_mem_pci_tbl,
 	.probe			= cxl_mem_probe,
 	.driver	= {
-		.probe_type	= PROBE_PREFER_ASYNCHRONOUS,
+		.probe_type	= PROBE_FORCE_SYNCHRONOUS,
 	},
 };
 
-- 
2.19.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 0/4] PCI/CMA and SPDM library
  2021-08-04 16:18 [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
                   ` (3 preceding siblings ...)
  2021-08-04 16:18 ` [RFC PATCH 4/4] cxl/pci: Add really basic CMA authentication support Jonathan Cameron
@ 2021-08-05 16:43 ` Jonathan Cameron
  2021-08-31 12:55   ` Jonathan Cameron
  4 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-05 16:43 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr

On Thu, 5 Aug 2021 00:18:35 +0800
Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:

> This is an RFC to start discussions about how we support the Component
> Measurement and Authentication (CMA) ECN (pcisig.com)
> 
> CMA provides an adaptation of the data objects and underlying protocol
> defined in the DMTF SPDM specification to be used to authenticate and
> conduct run-time measurements of the state of PCI devices (kind of like
> IMA for devices / firmware). This is done using a Data Object Exchange (DOE)
> protocol described in the ECN.
> 
> The CMA ECN is available from the PCI SIG and SPDM can be found at
> https://www.dmtf.org/sites/default/files/standards/documents/DSP0274_1.1.1.pdf
> 
> CMA/SPDM is focused on establishing trust of the device by:
> 1) Negotiate algorithms supported.
> 2) Retrieve and check the certificate chain from the device against
>    a suitable signing certificate on the host.
> 3) Issue a challenge to the device to verify it can sign with the private
>    key associated with the leaf certificate.
> 4) (Request a measurement of device state)
> 5) (Establish a secure channel for further measurements or other uses)
> 6) (Mutual authentication)
> 
> This RFC only does steps 1-3
> 
> Testing of this patch set has been conducted against QEMU emulation of
> the device backed by openSPDM emulation of the SPDM protocol.

Note testing also works with libspdm and libspdm-emu from
https://github.com/DMTF/spdm-emu with no modifications.

The openSPDM modifications Chris and team made were all associated with the host
end and are not needed for this code (the QEMU part is still needed to provide
the DOE emulation and forward the traffic to spdm_responder_emu)

I should also have mentioned this series is on top of the recently posted
DOE series rebased onto the linux-cxl next git tree.  I'm not really expecting
anyone to test it at this stage, but if desired I can push a full tree out
somewhere with this in place.

Jonathan

> 
> https://lore.kernel.org/qemu-devel/1624665723-5169-1-git-send-email-cbrowy@avery-design.com/
> 
> Open questions are called out in the individual patches but the big ones are
> probably:
> 
> 1) Certificate management.
>    Current code uses a _cma keyring created by the kernel, into which a
>    suitable root certificate can be inserted from userspace.
> 
>    A=$(keyctl search %:_cma  keyring _cma)
>    evmctl import ecdsaca.cert.der $A
> 
>    Is this an acceptable way to load the root certificates for this purpose?
> 
>    The root of the device provided certificate chain is then checked against
>    certificates on this keychain, but is itself (with the other certificates
>    in the chain) loaded into an SPDM instance specific keychain.  Currently
>    there is no safe cleanup of this which will need to be fixed.
> 
>    Using the keychain mechanism provides a very convenient way to manage these
>    certificates and to allow userspace to read them for debug purpose etc, but
>    is this the right use model?
> 
>    Finally the leaf certificate of this chain is used to check signatures of
>    the rest of the communications with the device.
> 
> 2) ASNL1 encoder for ECDSA signature
>    It seems from the openSPDM implementation that for these signatures,
>    the format is a simple pair of raw values.  The kernel implementation of
>    ECDSA signature verification assumes ASN1 encoding as seems to be used
>    in x509 certificates.  Currently I work around that by encoding the
>    signatures so that the ECDSA code can un-encode them again and use them.
>    This seems slightly silly, but it is minimum impact on current code.
>    Other suggestions welcome.
> 
> 3) Interface to present to drivers. Currently I'm providing just one exposed
>    function that wraps up all the exhanges until a challenge authentication
>    response from the device. This is done using one possible sequence.
>    I don't think it makes sense to expose the low level components due to the
>    underlying spdm_state updates and there only being a fixed set of valid
>    orderings.
> 
> Future patches will raise questions around management of the measurements, but
> I'll leave those until I have some sort of implementation to shoot at.
> The 'on probe' use in the CXL driver is only one likely time when authentication
> would be needed.
> 
> Note I'm new to a bunch of the areas of the kernel this touches, so have
> probably done things that are totally wrong.
> 
> CC list is best effort to identify those who 'might' care.  Please share
> with anyone I've missed.
> 
> Thanks,
> 
> Jonathan
> 
> 
> Jonathan Cameron (4):
>   lib/asn1_encoder: Add a function to encode many byte integer values.
>   spdm: Introduce a library for DMTF SPDM
>   PCI/CMA: Initial support for Component Measurement and Authentication
>     ECN
>   cxl/pci: Add really basic CMA authentication support.
> 
>  drivers/cxl/Kconfig          |    1 +
>  drivers/cxl/mem.h            |    2 +
>  drivers/cxl/pci.c            |   13 +-
>  drivers/pci/Kconfig          |    9 +
>  drivers/pci/Makefile         |    1 +
>  drivers/pci/doe.c            |    2 -
>  include/linux/asn1_encoder.h |    3 +
>  include/linux/pci-doe.h      |    2 +
>  lib/Kconfig                  |    3 +
>  lib/Makefile                 |    2 +
>  lib/asn1_encoder.c           |   54 ++
>  lib/spdm.c                   | 1196 ++++++++++++++++++++++++++++++++++
>  12 files changed, 1285 insertions(+), 3 deletions(-)
>  create mode 100644 lib/spdm.c
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 0/4] PCI/CMA and SPDM library
  2021-08-05 16:43 ` [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
@ 2021-08-31 12:55   ` Jonathan Cameron
  2021-11-17 17:46     ` Chris Browy
  0 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2021-08-31 12:55 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr

On Thu, 5 Aug 2021 17:43:46 +0100
Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:

> On Thu, 5 Aug 2021 00:18:35 +0800
> Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:
> 
> > This is an RFC to start discussions about how we support the Component
> > Measurement and Authentication (CMA) ECN (pcisig.com)
> > 
> > CMA provides an adaptation of the data objects and underlying protocol
> > defined in the DMTF SPDM specification to be used to authenticate and
> > conduct run-time measurements of the state of PCI devices (kind of like
> > IMA for devices / firmware). This is done using a Data Object Exchange (DOE)
> > protocol described in the ECN.
> > 
> > The CMA ECN is available from the PCI SIG and SPDM can be found at
> > https://www.dmtf.org/sites/default/files/standards/documents/DSP0274_1.1.1.pdf
> > 
> > CMA/SPDM is focused on establishing trust of the device by:
> > 1) Negotiate algorithms supported.
> > 2) Retrieve and check the certificate chain from the device against
> >    a suitable signing certificate on the host.
> > 3) Issue a challenge to the device to verify it can sign with the private
> >    key associated with the leaf certificate.
> > 4) (Request a measurement of device state)
> > 5) (Establish a secure channel for further measurements or other uses)
> > 6) (Mutual authentication)
> > 
> > This RFC only does steps 1-3
> > 
> > Testing of this patch set has been conducted against QEMU emulation of
> > the device backed by openSPDM emulation of the SPDM protocol.  
> 
> Note testing also works with libspdm and libspdm-emu from
> https://github.com/DMTF/spdm-emu with no modifications.
> 
> The openSPDM modifications Chris and team made were all associated with the host
> end and are not needed for this code (the QEMU part is still needed to provide
> the DOE emulation and forward the traffic to spdm_responder_emu)
> 
> I should also have mentioned this series is on top of the recently posted
> DOE series rebased onto the linux-cxl next git tree.  I'm not really expecting
> anyone to test it at this stage, but if desired I can push a full tree out
> somewhere with this in place.

A couple of updates:

1. This topic is on the agenda for the linaro-open-discussions call tomorrow.
https://linaro.atlassian.net/wiki/spaces/LOD/overview
It's a public call and anyone interested is welcome to join in. Time is rather
unfriendly for US based people unfortunately. I'll throw together some sort of
overview / open questions slide deck which will be posted on that page. Note
related topics on plumbers microconf agenda later in the month - I'll share details
of that once known.

2. Related to that I had a request for trees as the base of the various series are not
obvious (involved a bunch of rebases of various other patch sets)

https://github.com/hisilicon/kernel-dev/tree/doe-spdm-v1 rebased to 5.14-rc7
https://github.com/hisilicon/qemu/tree/cxl-hacks rebased to qemu/master as of Friday

For qemu side of things you need to be running spdm_responder_emu --trans PCI_DOE 
from https://github.com/DMTF/spdm-emu first (that will act as server to qemu acting
as a client). Various parameters allow you to change the algorithms advertised and the
kernel code should work for all the ones CMA mandates (but nothing beyond that for now).

For the cxl device the snippet of qemu commandline needed is:
-device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-mem1, id=cxl-pmem0,size=2G,spdm=true

Otherwise much the same as https://people.kernel.org/jic23/ (instructions written to enable
testing of the DOE patches this built on).

Build at least the cxl_pci driver as a module as we need to poke the certificate into the keychain
before that (find the cert in spdm_emu tree).
Instructions to do that with keyctl and evmctl are in the cover letter of the patch series.

Hopefully I'll find some time soonish to update that blog post with instructions.

Thanks,

Jonathan

> 
> Jonathan
> 
> > 
> > https://lore.kernel.org/qemu-devel/1624665723-5169-1-git-send-email-cbrowy@avery-design.com/
> > 
> > Open questions are called out in the individual patches but the big ones are
> > probably:
> > 
> > 1) Certificate management.
> >    Current code uses a _cma keyring created by the kernel, into which a
> >    suitable root certificate can be inserted from userspace.
> > 
> >    A=$(keyctl search %:_cma  keyring _cma)
> >    evmctl import ecdsaca.cert.der $A
> > 
> >    Is this an acceptable way to load the root certificates for this purpose?
> > 
> >    The root of the device provided certificate chain is then checked against
> >    certificates on this keychain, but is itself (with the other certificates
> >    in the chain) loaded into an SPDM instance specific keychain.  Currently
> >    there is no safe cleanup of this which will need to be fixed.
> > 
> >    Using the keychain mechanism provides a very convenient way to manage these
> >    certificates and to allow userspace to read them for debug purpose etc, but
> >    is this the right use model?
> > 
> >    Finally the leaf certificate of this chain is used to check signatures of
> >    the rest of the communications with the device.
> > 
> > 2) ASNL1 encoder for ECDSA signature
> >    It seems from the openSPDM implementation that for these signatures,
> >    the format is a simple pair of raw values.  The kernel implementation of
> >    ECDSA signature verification assumes ASN1 encoding as seems to be used
> >    in x509 certificates.  Currently I work around that by encoding the
> >    signatures so that the ECDSA code can un-encode them again and use them.
> >    This seems slightly silly, but it is minimum impact on current code.
> >    Other suggestions welcome.
> > 
> > 3) Interface to present to drivers. Currently I'm providing just one exposed
> >    function that wraps up all the exhanges until a challenge authentication
> >    response from the device. This is done using one possible sequence.
> >    I don't think it makes sense to expose the low level components due to the
> >    underlying spdm_state updates and there only being a fixed set of valid
> >    orderings.
> > 
> > Future patches will raise questions around management of the measurements, but
> > I'll leave those until I have some sort of implementation to shoot at.
> > The 'on probe' use in the CXL driver is only one likely time when authentication
> > would be needed.
> > 
> > Note I'm new to a bunch of the areas of the kernel this touches, so have
> > probably done things that are totally wrong.
> > 
> > CC list is best effort to identify those who 'might' care.  Please share
> > with anyone I've missed.
> > 
> > Thanks,
> > 
> > Jonathan
> > 
> > 
> > Jonathan Cameron (4):
> >   lib/asn1_encoder: Add a function to encode many byte integer values.
> >   spdm: Introduce a library for DMTF SPDM
> >   PCI/CMA: Initial support for Component Measurement and Authentication
> >     ECN
> >   cxl/pci: Add really basic CMA authentication support.
> > 
> >  drivers/cxl/Kconfig          |    1 +
> >  drivers/cxl/mem.h            |    2 +
> >  drivers/cxl/pci.c            |   13 +-
> >  drivers/pci/Kconfig          |    9 +
> >  drivers/pci/Makefile         |    1 +
> >  drivers/pci/doe.c            |    2 -
> >  include/linux/asn1_encoder.h |    3 +
> >  include/linux/pci-doe.h      |    2 +
> >  lib/Kconfig                  |    3 +
> >  lib/Makefile                 |    2 +
> >  lib/asn1_encoder.c           |   54 ++
> >  lib/spdm.c                   | 1196 ++++++++++++++++++++++++++++++++++
> >  12 files changed, 1285 insertions(+), 3 deletions(-)
> >  create mode 100644 lib/spdm.c
> >   
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 3/4] PCI/CMA: Initial support for Component Measurement and Authentication ECN
  2021-08-04 16:18 ` [RFC PATCH 3/4] PCI/CMA: Initial support for Component Measurement and Authentication ECN Jonathan Cameron
@ 2021-09-17 16:22   ` Jonathan Cameron
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2021-09-17 16:22 UTC (permalink / raw)
  To: linux-cxl, linux-pci
  Cc: keyrings, dan.j.williams, Chris Browy, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr

On Thu, 5 Aug 2021 00:18:38 +0800
Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:

> 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>

This is far more likely to work if I actually include the missing drivers/pci/cma.c
I'll send a v2 next week, but in the meantime it should look like this.

From: Jonathan Cameron <Jonathan.Cameron@huawei.com>
To: <jonathan.cameron@huawei.com>
Subject: [PATCH] pci/cma: Missing file
Date: Sat, 18 Sep 2021 00:16:00 +0800
X-Mailer: git-send-email 2.19.1

Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
---
 drivers/pci/cma.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 102 insertions(+)

diff --git a/drivers/pci/cma.c b/drivers/pci/cma.c
new file mode 100644
index 000000000000..58fef73674fe
--- /dev/null
+++ b/drivers/pci/cma.c
@@ -0,0 +1,102 @@
+// 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@huawei.com>
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pci-cma.h>
+#include <linux/pci-doe.h>
+#include <linux/spdm.h>
+
+/* 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 = {
+		.vid = PCI_VENDOR_ID_PCI_SIG,
+		.protocol = PCI_DOE_PROTOCOL_CMA,
+	};
+	struct pci_doe *doe = 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, &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 *doe, struct spdm_state *spdm_state)
+{
+	memset(spdm_state, 0, sizeof(*spdm_state));
+	spdm_state->transport_ex = cma_spdm_ex;
+	spdm_state->transport_priv = doe;
+	spdm_state->dev = &doe->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");
-- 
2.19.1



> ---
>  drivers/pci/Kconfig     | 9 +++++++++
>  drivers/pci/Makefile    | 1 +
>  drivers/pci/doe.c       | 2 --
>  include/linux/pci-doe.h | 2 ++
>  4 files changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index a30c59cf5e27..43e3b0d5e8cd 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -198,6 +198,15 @@ config PCI_DOE
>  	  used by a number of different protocols.
>  	  DOE is defined in the Data Object Exchange ECN to the PCIe r5.0 spec.
>  
> +config PCI_CMA
> +	tristate
> +	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
> +
>  choice
>  	prompt "PCI Express hierarchy optimization setting"
>  	default PCIE_BUS_DEFAULT
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 1b61c1a1c232..3f6b3543d565 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -29,6 +29,7 @@ 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)		+= doe.o
> +obj-$(CONFIG_PCI_CMA)		+= cma.o
>  obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
>  
>  # Endpoint library must be initialized before its users
> diff --git a/drivers/pci/doe.c b/drivers/pci/doe.c
> index 2d20f59e42c6..f6aaeed01010 100644
> --- a/drivers/pci/doe.c
> +++ b/drivers/pci/doe.c
> @@ -20,8 +20,6 @@
>  /* Maximum number of DOE instances in the system */
>  #define PCI_DOE_MAX_CNT 65536
>  
> -#define PCI_DOE_PROTOCOL_DISCOVERY 0
> -
>  #define PCI_DOE_BUSY_MAX_RETRIES 16
>  #define PCI_DOE_POLL_INTERVAL (HZ / 128)
>  
> diff --git a/include/linux/pci-doe.h b/include/linux/pci-doe.h
> index bdc5f15f14ab..1347c124ed70 100644
> --- a/include/linux/pci-doe.h
> +++ b/include/linux/pci-doe.h
> @@ -19,6 +19,8 @@ struct pci_doe_prot {
>  	u8 type;
>  };
>  
> +#define PCI_DOE_PROTOCOL_DISCOVERY 0
> +#define PCI_DOE_PROTOCOL_CMA 1
>  struct workqueue_struct;
>  
>  enum pci_doe_state {


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 0/4] PCI/CMA and SPDM library
  2021-08-31 12:55   ` Jonathan Cameron
@ 2021-11-17 17:46     ` Chris Browy
  2021-11-18 11:54       ` Jonathan Cameron
  0 siblings, 1 reply; 14+ messages in thread
From: Chris Browy @ 2021-11-17 17:46 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-cxl, Linux PCI, keyrings, dan.j.williams, linuxarm,
	Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr



> On Aug 31, 2021, at 8:55 AM, Jonathan Cameron <jonathan.cameron@huawei.com> wrote:
> 
> On Thu, 5 Aug 2021 17:43:46 +0100
> Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:
> 
>> On Thu, 5 Aug 2021 00:18:35 +0800
>> Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:
>> 
>>> This is an RFC to start discussions about how we support the Component
>>> Measurement and Authentication (CMA) ECN (pcisig.com)
>>> 
>>> CMA provides an adaptation of the data objects and underlying protocol
>>> defined in the DMTF SPDM specification to be used to authenticate and
>>> conduct run-time measurements of the state of PCI devices (kind of like
>>> IMA for devices / firmware). This is done using a Data Object Exchange (DOE)
>>> protocol described in the ECN.
>>> 
>>> The CMA ECN is available from the PCI SIG and SPDM can be found at
>>> https://www.dmtf.org/sites/default/files/standards/documents/DSP0274_1.1.1.pdf
>>> 
>>> CMA/SPDM is focused on establishing trust of the device by:
>>> 1) Negotiate algorithms supported.
>>> 2) Retrieve and check the certificate chain from the device against
>>>   a suitable signing certificate on the host.
>>> 3) Issue a challenge to the device to verify it can sign with the private
>>>   key associated with the leaf certificate.
>>> 4) (Request a measurement of device state)
>>> 5) (Establish a secure channel for further measurements or other uses)
>>> 6) (Mutual authentication)
>>> 
>>> This RFC only does steps 1-3

Could you describe the additional software beyond step 3 that is required to complete 
the IDE Key Management protocol post SPDM secure session establishment (see PCIe 
base 6.0r0.9.pdf, Figure 6-59 IDE_KM Example) to reach IDE establishment and run 
regular applications using IDE streams.  The goal is to do more complete testing of 
some real CXL devices to the point of running user applications over IDE streams to 
access HDM memory.

>>> 
>>> Testing of this patch set has been conducted against QEMU emulation of
>>> the device backed by openSPDM emulation of the SPDM protocol.  
>> 
>> Note testing also works with libspdm and libspdm-emu from
>> https://github.com/DMTF/spdm-emu with no modifications.
>> 
>> The openSPDM modifications Chris and team made were all associated with the host
>> end and are not needed for this code (the QEMU part is still needed to provide
>> the DOE emulation and forward the traffic to spdm_responder_emu)
>> 
>> I should also have mentioned this series is on top of the recently posted
>> DOE series rebased onto the linux-cxl next git tree.  I'm not really expecting
>> anyone to test it at this stage, but if desired I can push a full tree out
>> somewhere with this in place.
> 
> A couple of updates:
> 
> 1. This topic is on the agenda for the linaro-open-discussions call tomorrow.
> https://linaro.atlassian.net/wiki/spaces/LOD/overview
> It's a public call and anyone interested is welcome to join in. Time is rather
> unfriendly for US based people unfortunately. I'll throw together some sort of
> overview / open questions slide deck which will be posted on that page. Note
> related topics on plumbers microconf agenda later in the month - I'll share details
> of that once known.
> 
> 2. Related to that I had a request for trees as the base of the various series are not
> obvious (involved a bunch of rebases of various other patch sets)
> 
> https://github.com/hisilicon/kernel-dev/tree/doe-spdm-v1 rebased to 5.14-rc7
> https://github.com/hisilicon/qemu/tree/cxl-hacks rebased to qemu/master as of Friday
> 
> For qemu side of things you need to be running spdm_responder_emu --trans PCI_DOE 
> from https://github.com/DMTF/spdm-emu first (that will act as server to qemu acting
> as a client). Various parameters allow you to change the algorithms advertised and the
> kernel code should work for all the ones CMA mandates (but nothing beyond that for now).
> 
> For the cxl device the snippet of qemu commandline needed is:
> -device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-mem1, id=cxl-pmem0,size=2G,spdm=true
> 
> Otherwise much the same as https://people.kernel.org/jic23/ (instructions written to enable
> testing of the DOE patches this built on).
> 
> Build at least the cxl_pci driver as a module as we need to poke the certificate into the keychain
> before that (find the cert in spdm_emu tree).
> Instructions to do that with keyctl and evmctl are in the cover letter of the patch series.
> 
> Hopefully I'll find some time soonish to update that blog post with instructions.
> 
> Thanks,
> 
> Jonathan
> 
>> 
>> Jonathan
>> 
>>> 
>>> https://lore.kernel.org/qemu-devel/1624665723-5169-1-git-send-email-cbrowy@avery-design.com/
>>> 
>>> Open questions are called out in the individual patches but the big ones are
>>> probably:
>>> 
>>> 1) Certificate management.
>>>   Current code uses a _cma keyring created by the kernel, into which a
>>>   suitable root certificate can be inserted from userspace.
>>> 
>>>   A=$(keyctl search %:_cma  keyring _cma)
>>>   evmctl import ecdsaca.cert.der $A
>>> 
>>>   Is this an acceptable way to load the root certificates for this purpose?
>>> 
>>>   The root of the device provided certificate chain is then checked against
>>>   certificates on this keychain, but is itself (with the other certificates
>>>   in the chain) loaded into an SPDM instance specific keychain.  Currently
>>>   there is no safe cleanup of this which will need to be fixed.
>>> 
>>>   Using the keychain mechanism provides a very convenient way to manage these
>>>   certificates and to allow userspace to read them for debug purpose etc, but
>>>   is this the right use model?
>>> 
>>>   Finally the leaf certificate of this chain is used to check signatures of
>>>   the rest of the communications with the device.
>>> 
>>> 2) ASNL1 encoder for ECDSA signature
>>>   It seems from the openSPDM implementation that for these signatures,
>>>   the format is a simple pair of raw values.  The kernel implementation of
>>>   ECDSA signature verification assumes ASN1 encoding as seems to be used
>>>   in x509 certificates.  Currently I work around that by encoding the
>>>   signatures so that the ECDSA code can un-encode them again and use them.
>>>   This seems slightly silly, but it is minimum impact on current code.
>>>   Other suggestions welcome.
>>> 
>>> 3) Interface to present to drivers. Currently I'm providing just one exposed
>>>   function that wraps up all the exhanges until a challenge authentication
>>>   response from the device. This is done using one possible sequence.
>>>   I don't think it makes sense to expose the low level components due to the
>>>   underlying spdm_state updates and there only being a fixed set of valid
>>>   orderings.
>>> 
>>> Future patches will raise questions around management of the measurements, but
>>> I'll leave those until I have some sort of implementation to shoot at.
>>> The 'on probe' use in the CXL driver is only one likely time when authentication
>>> would be needed.
>>> 
>>> Note I'm new to a bunch of the areas of the kernel this touches, so have
>>> probably done things that are totally wrong.
>>> 
>>> CC list is best effort to identify those who 'might' care.  Please share
>>> with anyone I've missed.
>>> 
>>> Thanks,
>>> 
>>> Jonathan
>>> 
>>> 
>>> Jonathan Cameron (4):
>>>  lib/asn1_encoder: Add a function to encode many byte integer values.
>>>  spdm: Introduce a library for DMTF SPDM
>>>  PCI/CMA: Initial support for Component Measurement and Authentication
>>>    ECN
>>>  cxl/pci: Add really basic CMA authentication support.
>>> 
>>> drivers/cxl/Kconfig          |    1 +
>>> drivers/cxl/mem.h            |    2 +
>>> drivers/cxl/pci.c            |   13 +-
>>> drivers/pci/Kconfig          |    9 +
>>> drivers/pci/Makefile         |    1 +
>>> drivers/pci/doe.c            |    2 -
>>> include/linux/asn1_encoder.h |    3 +
>>> include/linux/pci-doe.h      |    2 +
>>> lib/Kconfig                  |    3 +
>>> lib/Makefile                 |    2 +
>>> lib/asn1_encoder.c           |   54 ++
>>> lib/spdm.c                   | 1196 ++++++++++++++++++++++++++++++++++
>>> 12 files changed, 1285 insertions(+), 3 deletions(-)
>>> create mode 100644 lib/spdm.c
>>> 
>> 
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 0/4] PCI/CMA and SPDM library
  2021-11-17 17:46     ` Chris Browy
@ 2021-11-18 11:54       ` Jonathan Cameron
  0 siblings, 0 replies; 14+ messages in thread
From: Jonathan Cameron @ 2021-11-18 11:54 UTC (permalink / raw)
  To: Chris Browy
  Cc: 20210917172205.00000684, linux-cxl, Linux PCI, keyrings,
	dan.j.williams, linuxarm, Lorenzo Pieralisi, Bjorn Helgaas,
	Jeremy Kerr

On Wed, 17 Nov 2021 12:46:48 -0500
Chris Browy <cbrowy@avery-design.com> wrote:

> > On Aug 31, 2021, at 8:55 AM, Jonathan Cameron <jonathan.cameron@huawei.com> wrote:
> > 
> > On Thu, 5 Aug 2021 17:43:46 +0100
> > Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:
> >   
> >> On Thu, 5 Aug 2021 00:18:35 +0800
> >> Jonathan Cameron <Jonathan.Cameron@huawei.com> wrote:
> >>   
> >>> This is an RFC to start discussions about how we support the Component
> >>> Measurement and Authentication (CMA) ECN (pcisig.com)
> >>> 
> >>> CMA provides an adaptation of the data objects and underlying protocol
> >>> defined in the DMTF SPDM specification to be used to authenticate and
> >>> conduct run-time measurements of the state of PCI devices (kind of like
> >>> IMA for devices / firmware). This is done using a Data Object Exchange (DOE)
> >>> protocol described in the ECN.
> >>> 
> >>> The CMA ECN is available from the PCI SIG and SPDM can be found at
> >>> https://www.dmtf.org/sites/default/files/standards/documents/DSP0274_1.1.1.pdf
> >>> 
> >>> CMA/SPDM is focused on establishing trust of the device by:
> >>> 1) Negotiate algorithms supported.
> >>> 2) Retrieve and check the certificate chain from the device against
> >>>   a suitable signing certificate on the host.
> >>> 3) Issue a challenge to the device to verify it can sign with the private
> >>>   key associated with the leaf certificate.
> >>> 4) (Request a measurement of device state)
> >>> 5) (Establish a secure channel for further measurements or other uses)
> >>> 6) (Mutual authentication)
> >>> 
> >>> This RFC only does steps 1-3  
> 
> Could you describe the additional software beyond step 3 that is required to complete 
> the IDE Key Management protocol post SPDM secure session establishment (see PCIe 
> base 6.0r0.9.pdf, Figure 6-59 IDE_KM Example) to reach IDE establishment and run 

Stick to the ECN in references as that is published at least to SIG members.
We shouldn't be discussing draft specs on a public list (though in this case it's the
same material as the published ECN).

> regular applications using IDE streams.  The goal is to do more complete testing of 
> some real CXL devices to the point of running user applications over IDE streams to 
> access HDM memory.

Hi Chris,

This is off the top of my head rather than a considered answer as having a busy week.
Firstly a small thing but IDE requires a different DOE protocol - it is CMA with 
extra stuff but technically different protocol number.
3 a) Add the kernel side messages to actually request a secure channel.
  b) Hook into appropriate kernel subsystems to generate the keys.

After that is up and running (can test by doing some measurements over the now encrypted channel),
then we need to do the key setup as in the IDE spec.  So implement the IDE_KM protocol.
That will cover EPs.  If you have a switch in the path then you'll need to add emulation
support for a DOE on that as well.

Now the host is interesting.  You are allowed but not required to support IDE_KM on a DOE
in the root port (there are lots of other options) or in RCRB.  Also allowed impdef means
which I suspect is going to be more common as a secure channel between components both within
the SoC is a little odd.  That decision may depend on whether a given vendor sees
IDE establishment and maintenance as a firmware / BMC job or an OS one.

IDE_KM protocol has 6 messages and i think we would need to implement them all.

There is also the extended capability to be handled which brings more complexity.
So all the stuff in figure 7-16 IDE_KM Examples (might be the same as the one you refer to...)

We've only gotten as far as mid way down the second block of exchanges.
That diagram assumes host is using an impdef method, but I think we'd be better off
first implementing the RP DOE approach (which will be the same as switch to EP)
and that means negotiating a secure channel etc with the RP as well as the EP.
Then you can program appropriate keys and jump through the various IDE_KM_KSET_GO
as in the diagram.

There is quite a lot of work to be done to bring up the full flow, but, interestingly I think
there will be far fewer open questions in that part of enablement than we have for
earlier steps of SPDM setup, simply because it doesn't really interact with the
rest of Linux so sits almost entirely in the PCI subsystem.  A fun early question is
how we decide it needs to be enabled at all.

Whilst I'm planning to eventually get this all in place it may take a while.

If we were making a plan...
1) Finish of SPDM stuff - so secure channel setup and ideally flesh out measurements for which
   I have a prototype.
2) Qemu emulation RP with IDE support (building on your team's work on EP support).
3) Bring up basic flow against that emulation.
4) Figure out what to do about key refresh...
5) Qemu emulation of switch.
6) Bring flows up against switch etc.
7) Selective IDE.
8) P2P selective IDE...
9) Retire and let the youngsters actually use it ;)

Jonathan


> 
> >>> 
> >>> Testing of this patch set has been conducted against QEMU emulation of
> >>> the device backed by openSPDM emulation of the SPDM protocol.    
> >> 
> >> Note testing also works with libspdm and libspdm-emu from
> >> https://github.com/DMTF/spdm-emu with no modifications.
> >> 
> >> The openSPDM modifications Chris and team made were all associated with the host
> >> end and are not needed for this code (the QEMU part is still needed to provide
> >> the DOE emulation and forward the traffic to spdm_responder_emu)
> >> 
> >> I should also have mentioned this series is on top of the recently posted
> >> DOE series rebased onto the linux-cxl next git tree.  I'm not really expecting
> >> anyone to test it at this stage, but if desired I can push a full tree out
> >> somewhere with this in place.  
> > 
> > A couple of updates:
> > 
> > 1. This topic is on the agenda for the linaro-open-discussions call tomorrow.
> > https://linaro.atlassian.net/wiki/spaces/LOD/overview
> > It's a public call and anyone interested is welcome to join in. Time is rather
> > unfriendly for US based people unfortunately. I'll throw together some sort of
> > overview / open questions slide deck which will be posted on that page. Note
> > related topics on plumbers microconf agenda later in the month - I'll share details
> > of that once known.
> > 
> > 2. Related to that I had a request for trees as the base of the various series are not
> > obvious (involved a bunch of rebases of various other patch sets)
> > 
> > https://github.com/hisilicon/kernel-dev/tree/doe-spdm-v1 rebased to 5.14-rc7
> > https://github.com/hisilicon/qemu/tree/cxl-hacks rebased to qemu/master as of Friday
> > 
> > For qemu side of things you need to be running spdm_responder_emu --trans PCI_DOE 
> > from https://github.com/DMTF/spdm-emu first (that will act as server to qemu acting
> > as a client). Various parameters allow you to change the algorithms advertised and the
> > kernel code should work for all the ones CMA mandates (but nothing beyond that for now).
> > 
> > For the cxl device the snippet of qemu commandline needed is:
> > -device cxl-type3,bus=root_port13,memdev=cxl-mem1,lsa=cxl-mem1, id=cxl-pmem0,size=2G,spdm=true
> > 
> > Otherwise much the same as https://people.kernel.org/jic23/ (instructions written to enable
> > testing of the DOE patches this built on).
> > 
> > Build at least the cxl_pci driver as a module as we need to poke the certificate into the keychain
> > before that (find the cert in spdm_emu tree).
> > Instructions to do that with keyctl and evmctl are in the cover letter of the patch series.
> > 
> > Hopefully I'll find some time soonish to update that blog post with instructions.
> > 
> > Thanks,
> > 
> > Jonathan
> >   
> >> 
> >> Jonathan
> >>   
> >>> 
> >>> https://lore.kernel.org/qemu-devel/1624665723-5169-1-git-send-email-cbrowy@avery-design.com/
> >>> 
> >>> Open questions are called out in the individual patches but the big ones are
> >>> probably:
> >>> 
> >>> 1) Certificate management.
> >>>   Current code uses a _cma keyring created by the kernel, into which a
> >>>   suitable root certificate can be inserted from userspace.
> >>> 
> >>>   A=$(keyctl search %:_cma  keyring _cma)
> >>>   evmctl import ecdsaca.cert.der $A
> >>> 
> >>>   Is this an acceptable way to load the root certificates for this purpose?
> >>> 
> >>>   The root of the device provided certificate chain is then checked against
> >>>   certificates on this keychain, but is itself (with the other certificates
> >>>   in the chain) loaded into an SPDM instance specific keychain.  Currently
> >>>   there is no safe cleanup of this which will need to be fixed.
> >>> 
> >>>   Using the keychain mechanism provides a very convenient way to manage these
> >>>   certificates and to allow userspace to read them for debug purpose etc, but
> >>>   is this the right use model?
> >>> 
> >>>   Finally the leaf certificate of this chain is used to check signatures of
> >>>   the rest of the communications with the device.
> >>> 
> >>> 2) ASNL1 encoder for ECDSA signature
> >>>   It seems from the openSPDM implementation that for these signatures,
> >>>   the format is a simple pair of raw values.  The kernel implementation of
> >>>   ECDSA signature verification assumes ASN1 encoding as seems to be used
> >>>   in x509 certificates.  Currently I work around that by encoding the
> >>>   signatures so that the ECDSA code can un-encode them again and use them.
> >>>   This seems slightly silly, but it is minimum impact on current code.
> >>>   Other suggestions welcome.
> >>> 
> >>> 3) Interface to present to drivers. Currently I'm providing just one exposed
> >>>   function that wraps up all the exhanges until a challenge authentication
> >>>   response from the device. This is done using one possible sequence.
> >>>   I don't think it makes sense to expose the low level components due to the
> >>>   underlying spdm_state updates and there only being a fixed set of valid
> >>>   orderings.
> >>> 
> >>> Future patches will raise questions around management of the measurements, but
> >>> I'll leave those until I have some sort of implementation to shoot at.
> >>> The 'on probe' use in the CXL driver is only one likely time when authentication
> >>> would be needed.
> >>> 
> >>> Note I'm new to a bunch of the areas of the kernel this touches, so have
> >>> probably done things that are totally wrong.
> >>> 
> >>> CC list is best effort to identify those who 'might' care.  Please share
> >>> with anyone I've missed.
> >>> 
> >>> Thanks,
> >>> 
> >>> Jonathan
> >>> 
> >>> 
> >>> Jonathan Cameron (4):
> >>>  lib/asn1_encoder: Add a function to encode many byte integer values.
> >>>  spdm: Introduce a library for DMTF SPDM
> >>>  PCI/CMA: Initial support for Component Measurement and Authentication
> >>>    ECN
> >>>  cxl/pci: Add really basic CMA authentication support.
> >>> 
> >>> drivers/cxl/Kconfig          |    1 +
> >>> drivers/cxl/mem.h            |    2 +
> >>> drivers/cxl/pci.c            |   13 +-
> >>> drivers/pci/Kconfig          |    9 +
> >>> drivers/pci/Makefile         |    1 +
> >>> drivers/pci/doe.c            |    2 -
> >>> include/linux/asn1_encoder.h |    3 +
> >>> include/linux/pci-doe.h      |    2 +
> >>> lib/Kconfig                  |    3 +
> >>> lib/Makefile                 |    2 +
> >>> lib/asn1_encoder.c           |   54 ++
> >>> lib/spdm.c                   | 1196 ++++++++++++++++++++++++++++++++++
> >>> 12 files changed, 1285 insertions(+), 3 deletions(-)
> >>> create mode 100644 lib/spdm.c
> >>>   
> >>   
> >   
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
  2021-08-04 16:18 ` [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM Jonathan Cameron
@ 2022-02-18 22:05   ` Dan Williams
  2022-02-28 18:13     ` Box, David E
  0 siblings, 1 reply; 14+ messages in thread
From: Dan Williams @ 2022-02-18 22:05 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-cxl, Linux PCI, open list:KEYS-TRUSTED, Chris Browy,
	Linuxarm, Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr,
	David E Box

On Wed, Aug 4, 2021 at 9:23 AM Jonathan Cameron
<Jonathan.Cameron@huawei.com> wrote:
>
> The Security Protocol and Data Model (SPDM) defines messages,
> data objects and sequences for performing message exchanges between
> devices over various transports and physical media.
>
> As the kernel supports several possible transports (mctp, PCI DOE)
> introduce a library than can in turn be used with all those transports.
>
> There are a large number of open questions around how we do this that
> need to be resolved. These include:
> *  Key chain management
>    - Current approach is to use a keychain provide as part of per transport
>      initialization for the root certificates which are assumed to be
>      loaded into that keychain, perhaps in an initrd script.
>    - Each SPDM instance then has its own keychain to manage its
>      certificates. It may make sense to drop this, but that looks like it
>      will make a lot of the standard infrastructure harder to use.
>  *  ECC algorithms needing ASN1 encoded signatures.  I'm struggling to find
>     any specification that actual 'requires' that choice vs raw data, so my
>     guess is that this is a question of existing usecases (x509 certs seem
>     to use this form, but CHALLENGE_AUTH SPDM seems to use raw data).
>     I'm not sure whether we are better off just encoding the signature in
>     ASN1 as currently done in this series, or if it is worth a tweaking
>     things in the crypto layers.
>  *  Lots of options in actual implementation to look at.
>
> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> ---
>  lib/Kconfig  |    3 +
>  lib/Makefile |    2 +
>  lib/spdm.c   | 1196 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1201 insertions(+)
>
> diff --git a/lib/Kconfig b/lib/Kconfig
> index ac3b30697b2b..0aa2fef6a592 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -704,3 +704,6 @@ config PLDMFW
>
>  config ASN1_ENCODER
>         tristate
> +
> +config SPDM
> +       tristate
> diff --git a/lib/Makefile b/lib/Makefile
> index 2cc359ec1fdd..566166d6936e 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -282,6 +282,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
>  obj-$(CONFIG_ASN1) += asn1_decoder.o
>  obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
>
> +obj-$(CONFIG_SPDM) += spdm.o
> +
>  obj-$(CONFIG_FONT_SUPPORT) += fonts/
>
>  hostprogs      := gen_crc32table
> diff --git a/lib/spdm.c b/lib/spdm.c
> new file mode 100644
> index 000000000000..3ce2341647f8
> --- /dev/null
> +++ b/lib/spdm.c
> @@ -0,0 +1,1196 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * DMTF Security Protocol and Data Model
> + *
> + * Copyright (C) 2021 Huawei
> + *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
> + */
> +
> +#include <linux/asn1_encoder.h>
> +#include <linux/asn1_ber_bytecode.h>
> +#include <linux/bitfield.h>
> +#include <linux/cred.h>
> +#include <linux/dev_printk.h>
> +#include <linux/digsig.h>
> +#include <linux/idr.h>
> +#include <linux/key.h>
> +#include <linux/module.h>
> +#include <linux/random.h>
> +#include <linux/spdm.h>
> +
> +#include <crypto/akcipher.h>
> +#include <crypto/hash.h>
> +#include <crypto/public_key.h>
> +#include <keys/asymmetric-type.h>
> +#include <keys/user-type.h>
> +#include <asm/unaligned.h>
> +
> +/*
> + * Todo
> + * - Secure channel setup.
> + * - Multiple slot support.
> + * - Measurement support (over secure channel or within CHALLENGE_AUTH.
> + * - Support more core algorithms (not CMA does not require them, but may use
> + *   them if present.
> + * - Extended algorithm, support.
> + */
> +/*
> + * Discussions points
> + * 1. Worth adding an SPDM layer around a transport layer?

I came here to say yes to this question. I am seeing interest in SPDM
outside of a DOE transport.

Hope to find my way back to testing these bits out soon...

^ permalink raw reply	[flat|nested] 14+ messages in thread

* RE: [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
  2022-02-18 22:05   ` Dan Williams
@ 2022-02-28 18:13     ` Box, David E
  2022-03-01  9:59       ` Jonathan Cameron
  0 siblings, 1 reply; 14+ messages in thread
From: Box, David E @ 2022-02-28 18:13 UTC (permalink / raw)
  To: Williams, Dan J, Jonathan Cameron
  Cc: linux-cxl, Linux PCI, open list:KEYS-TRUSTED, Chris Browy,
	Linuxarm, Lorenzo Pieralisi, Bjorn Helgaas, Jeremy Kerr,
	'david.e.box@linux.intel.com'

Hi Jonathan,

I'd like to test this patch with a custom transport but there's a reference to spdm.h that isn't here. Also, have you looked at measurement support yet? Thanks.

David


> -----Original Message-----
> From: Dan Williams <dan.j.williams@intel.com>
> Sent: Friday, February 18, 2022 2:06 PM
> To: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> Cc: linux-cxl@vger.kernel.org; Linux PCI <linux-pci@vger.kernel.org>;
> open list:KEYS-TRUSTED <keyrings@vger.kernel.org>; Chris Browy
> <cbrowy@avery-design.com>; Linuxarm <linuxarm@huawei.com>; Lorenzo
> Pieralisi <lorenzo.pieralisi@arm.com>; Bjorn Helgaas
> <bjorn@helgaas.com>; Jeremy Kerr <jk@codeconstruct.com.au>; Box, David
> E <david.e.box@intel.com>
> Subject: Re: [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
> 
> On Wed, Aug 4, 2021 at 9:23 AM Jonathan Cameron
> <Jonathan.Cameron@huawei.com> wrote:
> >
> > The Security Protocol and Data Model (SPDM) defines messages, data
> > objects and sequences for performing message exchanges between
> devices
> > over various transports and physical media.
> >
> > As the kernel supports several possible transports (mctp, PCI DOE)
> > introduce a library than can in turn be used with all those
> transports.
> >
> > There are a large number of open questions around how we do this that
> > need to be resolved. These include:
> > *  Key chain management
> >    - Current approach is to use a keychain provide as part of per
> transport
> >      initialization for the root certificates which are assumed to be
> >      loaded into that keychain, perhaps in an initrd script.
> >    - Each SPDM instance then has its own keychain to manage its
> >      certificates. It may make sense to drop this, but that looks
> like it
> >      will make a lot of the standard infrastructure harder to use.
> >  *  ECC algorithms needing ASN1 encoded signatures.  I'm struggling
> to find
> >     any specification that actual 'requires' that choice vs raw data,
> so my
> >     guess is that this is a question of existing usecases (x509 certs
> seem
> >     to use this form, but CHALLENGE_AUTH SPDM seems to use raw data).
> >     I'm not sure whether we are better off just encoding the
> signature in
> >     ASN1 as currently done in this series, or if it is worth a
> tweaking
> >     things in the crypto layers.
> >  *  Lots of options in actual implementation to look at.
> >
> > Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > ---
> >  lib/Kconfig  |    3 +
> >  lib/Makefile |    2 +
> >  lib/spdm.c   | 1196
> ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 1201 insertions(+)
> >
> > diff --git a/lib/Kconfig b/lib/Kconfig index
> > ac3b30697b2b..0aa2fef6a592 100644
> > --- a/lib/Kconfig
> > +++ b/lib/Kconfig
> > @@ -704,3 +704,6 @@ config PLDMFW
> >
> >  config ASN1_ENCODER
> >         tristate
> > +
> > +config SPDM
> > +       tristate
> > diff --git a/lib/Makefile b/lib/Makefile index
> > 2cc359ec1fdd..566166d6936e 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -282,6 +282,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
> >  obj-$(CONFIG_ASN1) += asn1_decoder.o
> >  obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
> >
> > +obj-$(CONFIG_SPDM) += spdm.o
> > +
> >  obj-$(CONFIG_FONT_SUPPORT) += fonts/
> >
> >  hostprogs      := gen_crc32table
> > diff --git a/lib/spdm.c b/lib/spdm.c
> > new file mode 100644
> > index 000000000000..3ce2341647f8
> > --- /dev/null
> > +++ b/lib/spdm.c
> > @@ -0,0 +1,1196 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * DMTF Security Protocol and Data Model
> > + *
> > + * Copyright (C) 2021 Huawei
> > + *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > + */
> > +
> > +#include <linux/asn1_encoder.h>
> > +#include <linux/asn1_ber_bytecode.h>
> > +#include <linux/bitfield.h>
> > +#include <linux/cred.h>
> > +#include <linux/dev_printk.h>
> > +#include <linux/digsig.h>
> > +#include <linux/idr.h>
> > +#include <linux/key.h>
> > +#include <linux/module.h>
> > +#include <linux/random.h>
> > +#include <linux/spdm.h>
> > +
> > +#include <crypto/akcipher.h>
> > +#include <crypto/hash.h>
> > +#include <crypto/public_key.h>
> > +#include <keys/asymmetric-type.h>
> > +#include <keys/user-type.h>
> > +#include <asm/unaligned.h>
> > +
> > +/*
> > + * Todo
> > + * - Secure channel setup.
> > + * - Multiple slot support.
> > + * - Measurement support (over secure channel or within
> CHALLENGE_AUTH.
> > + * - Support more core algorithms (not CMA does not require them,
> but may use
> > + *   them if present.
> > + * - Extended algorithm, support.
> > + */
> > +/*
> > + * Discussions points
> > + * 1. Worth adding an SPDM layer around a transport layer?
> 
> I came here to say yes to this question. I am seeing interest in SPDM
> outside of a DOE transport.
> 
> Hope to find my way back to testing these bits out soon...

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
  2022-02-28 18:13     ` Box, David E
@ 2022-03-01  9:59       ` Jonathan Cameron
  2022-03-02 21:34         ` David E. Box
  0 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2022-03-01  9:59 UTC (permalink / raw)
  To: Box, David E
  Cc: Williams, Dan J, linux-cxl, Linux PCI, open list:KEYS-TRUSTED,
	Chris Browy, Linuxarm, Lorenzo Pieralisi, Bjorn Helgaas,
	Jeremy Kerr, 'david.e.box@linux.intel.com'

On Mon, 28 Feb 2022 18:13:27 +0000
"Box, David E" <david.e.box@intel.com> wrote:

> Hi Jonathan,
> 
> I'd like to test this patch with a custom transport but there's a reference to spdm.h that isn't here. Also, have you looked at measurement support yet? Thanks.
> 

Hi David,

I messed this up.

Some discussion of this took place on the linaro open discussions list
and I posted a version there to enable some testing which has the missing file.
Note I only did minimal testing against that tree and have had one verbal report
of a minor bug (without details...)

https://op-lists.linaro.org/archives/list/linaro-open-discussions@op-lists.linaro.org/thread/5QU65B6Q74B3B4ESR7W5HER5HQ6WF4EQ/

It's rather dated now so I'll do a rebase and post this hopefully later
this week given you are interested.

Note I haven't done any work on this for some time...

Curious though - what transport are people looking at?
I was planning to do MCTP over VDM at somepoint, but are we talking
something truely custom?  If so any plans to upstream as
I'd love a second transport to prove out the layering?

Thanks,

Jonathan



> David
> 
> 
> > -----Original Message-----
> > From: Dan Williams <dan.j.williams@intel.com>
> > Sent: Friday, February 18, 2022 2:06 PM
> > To: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > Cc: linux-cxl@vger.kernel.org; Linux PCI <linux-pci@vger.kernel.org>;
> > open list:KEYS-TRUSTED <keyrings@vger.kernel.org>; Chris Browy
> > <cbrowy@avery-design.com>; Linuxarm <linuxarm@huawei.com>; Lorenzo
> > Pieralisi <lorenzo.pieralisi@arm.com>; Bjorn Helgaas
> > <bjorn@helgaas.com>; Jeremy Kerr <jk@codeconstruct.com.au>; Box, David
> > E <david.e.box@intel.com>
> > Subject: Re: [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
> > 
> > On Wed, Aug 4, 2021 at 9:23 AM Jonathan Cameron
> > <Jonathan.Cameron@huawei.com> wrote:  
> > >
> > > The Security Protocol and Data Model (SPDM) defines messages, data
> > > objects and sequences for performing message exchanges between  
> > devices  
> > > over various transports and physical media.
> > >
> > > As the kernel supports several possible transports (mctp, PCI DOE)
> > > introduce a library than can in turn be used with all those  
> > transports.  
> > >
> > > There are a large number of open questions around how we do this that
> > > need to be resolved. These include:
> > > *  Key chain management
> > >    - Current approach is to use a keychain provide as part of per  
> > transport  
> > >      initialization for the root certificates which are assumed to be
> > >      loaded into that keychain, perhaps in an initrd script.
> > >    - Each SPDM instance then has its own keychain to manage its
> > >      certificates. It may make sense to drop this, but that looks  
> > like it  
> > >      will make a lot of the standard infrastructure harder to use.
> > >  *  ECC algorithms needing ASN1 encoded signatures.  I'm struggling  
> > to find  
> > >     any specification that actual 'requires' that choice vs raw data,  
> > so my  
> > >     guess is that this is a question of existing usecases (x509 certs  
> > seem  
> > >     to use this form, but CHALLENGE_AUTH SPDM seems to use raw data).
> > >     I'm not sure whether we are better off just encoding the  
> > signature in  
> > >     ASN1 as currently done in this series, or if it is worth a  
> > tweaking  
> > >     things in the crypto layers.
> > >  *  Lots of options in actual implementation to look at.
> > >
> > > Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > ---
> > >  lib/Kconfig  |    3 +
> > >  lib/Makefile |    2 +
> > >  lib/spdm.c   | 1196  
> > ++++++++++++++++++++++++++++++++++++++++++++++++++  
> > >  3 files changed, 1201 insertions(+)
> > >
> > > diff --git a/lib/Kconfig b/lib/Kconfig index
> > > ac3b30697b2b..0aa2fef6a592 100644
> > > --- a/lib/Kconfig
> > > +++ b/lib/Kconfig
> > > @@ -704,3 +704,6 @@ config PLDMFW
> > >
> > >  config ASN1_ENCODER
> > >         tristate
> > > +
> > > +config SPDM
> > > +       tristate
> > > diff --git a/lib/Makefile b/lib/Makefile index
> > > 2cc359ec1fdd..566166d6936e 100644
> > > --- a/lib/Makefile
> > > +++ b/lib/Makefile
> > > @@ -282,6 +282,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
> > >  obj-$(CONFIG_ASN1) += asn1_decoder.o
> > >  obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
> > >
> > > +obj-$(CONFIG_SPDM) += spdm.o
> > > +
> > >  obj-$(CONFIG_FONT_SUPPORT) += fonts/
> > >
> > >  hostprogs      := gen_crc32table
> > > diff --git a/lib/spdm.c b/lib/spdm.c
> > > new file mode 100644
> > > index 000000000000..3ce2341647f8
> > > --- /dev/null
> > > +++ b/lib/spdm.c
> > > @@ -0,0 +1,1196 @@
> > > +// SPDX-License-Identifier: GPL-2.0
> > > +/*
> > > + * DMTF Security Protocol and Data Model
> > > + *
> > > + * Copyright (C) 2021 Huawei
> > > + *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > + */
> > > +
> > > +#include <linux/asn1_encoder.h>
> > > +#include <linux/asn1_ber_bytecode.h>
> > > +#include <linux/bitfield.h>
> > > +#include <linux/cred.h>
> > > +#include <linux/dev_printk.h>
> > > +#include <linux/digsig.h>
> > > +#include <linux/idr.h>
> > > +#include <linux/key.h>
> > > +#include <linux/module.h>
> > > +#include <linux/random.h>
> > > +#include <linux/spdm.h>
> > > +
> > > +#include <crypto/akcipher.h>
> > > +#include <crypto/hash.h>
> > > +#include <crypto/public_key.h>
> > > +#include <keys/asymmetric-type.h>
> > > +#include <keys/user-type.h>
> > > +#include <asm/unaligned.h>
> > > +
> > > +/*
> > > + * Todo
> > > + * - Secure channel setup.
> > > + * - Multiple slot support.
> > > + * - Measurement support (over secure channel or within  
> > CHALLENGE_AUTH.  
> > > + * - Support more core algorithms (not CMA does not require them,  
> > but may use  
> > > + *   them if present.
> > > + * - Extended algorithm, support.
> > > + */
> > > +/*
> > > + * Discussions points
> > > + * 1. Worth adding an SPDM layer around a transport layer?  
> > 
> > I came here to say yes to this question. I am seeing interest in SPDM
> > outside of a DOE transport.
> > 
> > Hope to find my way back to testing these bits out soon...  


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM
  2022-03-01  9:59       ` Jonathan Cameron
@ 2022-03-02 21:34         ` David E. Box
  0 siblings, 0 replies; 14+ messages in thread
From: David E. Box @ 2022-03-02 21:34 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Williams, Dan J, linux-cxl, Linux PCI, open list:KEYS-TRUSTED,
	Chris Browy, Linuxarm, Lorenzo Pieralisi, Bjorn Helgaas,
	Jeremy Kerr

On Tue, 2022-03-01 at 09:59 +0000, Jonathan Cameron wrote:
> On Mon, 28 Feb 2022 18:13:27 +0000
> "Box, David E" <david.e.box@intel.com> wrote:
> 
> > Hi Jonathan,
> > 
> > I'd like to test this patch with a custom transport but there's a
> > reference to spdm.h that isn't here. Also, have you looked at
> > measurement support yet? Thanks.
> > 
> 
> Hi David,
> 
> I messed this up.
> 
> Some discussion of this took place on the linaro open discussions
> list
> and I posted a version there to enable some testing which has the
> missing file.
> Note I only did minimal testing against that tree and have had one
> verbal report
> of a minor bug (without details...)
> 
> https://op-lists.linaro.org/archives/list/linaro-open-discussions@op-lists.linaro.org/thread/5QU65B6Q74B3B4ESR7W5HER5HQ6WF4EQ/
> 
> It's rather dated now so I'll do a rebase and post this hopefully
> later
> this week given you are interested.
> Note I haven't done any work on this for some time...
> 
> Curious though - what transport are people looking at?
> I was planning to do MCTP over VDM at somepoint, but are we talking
> something truely custom?  If so any plans to upstream as
> I'd love a second transport to prove out the layering?

Thanks for the link. Definitely interested so please do cc me on future
patches. I'm particularly interested in the SPDM library since I'm
looking at this for use with a device specific transport. I'll let you
know if/when there's something to upstream. Thanks.

David

> 
> 
> Thanks,
> 
> Jonathan
> 
> 
> 
> > David
> > 
> > 
> > > -----Original Message-----
> > > From: Dan Williams <dan.j.williams@intel.com>
> > > Sent: Friday, February 18, 2022 2:06 PM
> > > To: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > Cc: linux-cxl@vger.kernel.org; Linux PCI <
> > > linux-pci@vger.kernel.org>;
> > > open list:KEYS-TRUSTED <keyrings@vger.kernel.org>; Chris Browy
> > > <cbrowy@avery-design.com>; Linuxarm <linuxarm@huawei.com>;
> > > Lorenzo
> > > Pieralisi <lorenzo.pieralisi@arm.com>; Bjorn Helgaas
> > > <bjorn@helgaas.com>; Jeremy Kerr <jk@codeconstruct.com.au>; Box,
> > > David
> > > E <david.e.box@intel.com>
> > > Subject: Re: [RFC PATCH 2/4] spdm: Introduce a library for DMTF
> > > SPDM
> > > 
> > > On Wed, Aug 4, 2021 at 9:23 AM Jonathan Cameron
> > > <Jonathan.Cameron@huawei.com> wrote:  
> > > > The Security Protocol and Data Model (SPDM) defines messages,
> > > > data
> > > > objects and sequences for performing message exchanges
> > > > between  
> > > devices  
> > > > over various transports and physical media.
> > > > 
> > > > As the kernel supports several possible transports (mctp, PCI
> > > > DOE)
> > > > introduce a library than can in turn be used with all those  
> > > transports.  
> > > > There are a large number of open questions around how we do
> > > > this that
> > > > need to be resolved. These include:
> > > > *  Key chain management
> > > >    - Current approach is to use a keychain provide as part of
> > > > per  
> > > transport  
> > > >      initialization for the root certificates which are assumed
> > > > to be
> > > >      loaded into that keychain, perhaps in an initrd script.
> > > >    - Each SPDM instance then has its own keychain to manage its
> > > >      certificates. It may make sense to drop this, but that
> > > > looks  
> > > like it  
> > > >      will make a lot of the standard infrastructure harder to
> > > > use.
> > > >  *  ECC algorithms needing ASN1 encoded signatures.  I'm
> > > > struggling  
> > > to find  
> > > >     any specification that actual 'requires' that choice vs raw
> > > > data,  
> > > so my  
> > > >     guess is that this is a question of existing usecases (x509
> > > > certs  
> > > seem  
> > > >     to use this form, but CHALLENGE_AUTH SPDM seems to use raw
> > > > data).
> > > >     I'm not sure whether we are better off just encoding the  
> > > signature in  
> > > >     ASN1 as currently done in this series, or if it is worth
> > > > a  
> > > tweaking  
> > > >     things in the crypto layers.
> > > >  *  Lots of options in actual implementation to look at.
> > > > 
> > > > Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > > ---
> > > >  lib/Kconfig  |    3 +
> > > >  lib/Makefile |    2 +
> > > >  lib/spdm.c   | 1196  
> > > ++++++++++++++++++++++++++++++++++++++++++++++++++  
> > > >  3 files changed, 1201 insertions(+)
> > > > 
> > > > diff --git a/lib/Kconfig b/lib/Kconfig index
> > > > ac3b30697b2b..0aa2fef6a592 100644
> > > > --- a/lib/Kconfig
> > > > +++ b/lib/Kconfig
> > > > @@ -704,3 +704,6 @@ config PLDMFW
> > > > 
> > > >  config ASN1_ENCODER
> > > >         tristate
> > > > +
> > > > +config SPDM
> > > > +       tristate
> > > > diff --git a/lib/Makefile b/lib/Makefile index
> > > > 2cc359ec1fdd..566166d6936e 100644
> > > > --- a/lib/Makefile
> > > > +++ b/lib/Makefile
> > > > @@ -282,6 +282,8 @@ obj-$(CONFIG_PERCPU_TEST) += percpu_test.o
> > > >  obj-$(CONFIG_ASN1) += asn1_decoder.o
> > > >  obj-$(CONFIG_ASN1_ENCODER) += asn1_encoder.o
> > > > 
> > > > +obj-$(CONFIG_SPDM) += spdm.o
> > > > +
> > > >  obj-$(CONFIG_FONT_SUPPORT) += fonts/
> > > > 
> > > >  hostprogs      := gen_crc32table
> > > > diff --git a/lib/spdm.c b/lib/spdm.c
> > > > new file mode 100644
> > > > index 000000000000..3ce2341647f8
> > > > --- /dev/null
> > > > +++ b/lib/spdm.c
> > > > @@ -0,0 +1,1196 @@
> > > > +// SPDX-License-Identifier: GPL-2.0
> > > > +/*
> > > > + * DMTF Security Protocol and Data Model
> > > > + *
> > > > + * Copyright (C) 2021 Huawei
> > > > + *     Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > > + */
> > > > +
> > > > +#include <linux/asn1_encoder.h>
> > > > +#include <linux/asn1_ber_bytecode.h>
> > > > +#include <linux/bitfield.h>
> > > > +#include <linux/cred.h>
> > > > +#include <linux/dev_printk.h>
> > > > +#include <linux/digsig.h>
> > > > +#include <linux/idr.h>
> > > > +#include <linux/key.h>
> > > > +#include <linux/module.h>
> > > > +#include <linux/random.h>
> > > > +#include <linux/spdm.h>
> > > > +
> > > > +#include <crypto/akcipher.h>
> > > > +#include <crypto/hash.h>
> > > > +#include <crypto/public_key.h>
> > > > +#include <keys/asymmetric-type.h>
> > > > +#include <keys/user-type.h>
> > > > +#include <asm/unaligned.h>
> > > > +
> > > > +/*
> > > > + * Todo
> > > > + * - Secure channel setup.
> > > > + * - Multiple slot support.
> > > > + * - Measurement support (over secure channel or within  
> > > CHALLENGE_AUTH.  
> > > > + * - Support more core algorithms (not CMA does not require
> > > > them,  
> > > but may use  
> > > > + *   them if present.
> > > > + * - Extended algorithm, support.
> > > > + */
> > > > +/*
> > > > + * Discussions points
> > > > + * 1. Worth adding an SPDM layer around a transport layer?  
> > > 
> > > I came here to say yes to this question. I am seeing interest in
> > > SPDM
> > > outside of a DOE transport.
> > > 
> > > Hope to find my way back to testing these bits out soon...  


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-03-02 21:34 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-04 16:18 [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
2021-08-04 16:18 ` [RFC PATCH 1/4] lib/asn1_encoder: Add a function to encode many byte integer values Jonathan Cameron
2021-08-04 16:18 ` [RFC PATCH 2/4] spdm: Introduce a library for DMTF SPDM Jonathan Cameron
2022-02-18 22:05   ` Dan Williams
2022-02-28 18:13     ` Box, David E
2022-03-01  9:59       ` Jonathan Cameron
2022-03-02 21:34         ` David E. Box
2021-08-04 16:18 ` [RFC PATCH 3/4] PCI/CMA: Initial support for Component Measurement and Authentication ECN Jonathan Cameron
2021-09-17 16:22   ` Jonathan Cameron
2021-08-04 16:18 ` [RFC PATCH 4/4] cxl/pci: Add really basic CMA authentication support Jonathan Cameron
2021-08-05 16:43 ` [RFC PATCH 0/4] PCI/CMA and SPDM library Jonathan Cameron
2021-08-31 12:55   ` Jonathan Cameron
2021-11-17 17:46     ` Chris Browy
2021-11-18 11:54       ` Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.