Skip to content

Commit 009663b

Browse files
committed
spdm: Multicast received signatures via netlink
WIP When authenticating a device with CMA-SPDM, the kernel verifies the challenge-response received from the device, but otherwise keeps it to itself. James Bottomley contends that's not good enough because user space or a remote attestation service may want to re-verify the challenge-response: Either because it mistrusts the kernel or because the kernel is unaware of policy constraints that user space or the remote attestation service want to apply. Facilitate such use cases by exposing a log in sysfs which consists of several files for each challenge-response event. The files are prefixed with a monotonically increasing number, starting at 0: /sys/devices/.../signatures/0_signature /sys/devices/.../signatures/0_transcript /sys/devices/.../signatures/0_requester_nonce /sys/devices/.../signatures/0_responder_nonce /sys/devices/.../signatures/0_hash_algorithm /sys/devices/.../signatures/0_combined_spdm_prefix /sys/devices/.../signatures/0_certificate_chain /sys/devices/.../signatures/0_type The 0_signature is computed over the 0_transcript (a concatenation of all SPDM messages exchanged with the device). To verify the signature, 0_transcript is hashed with 0_hash_algorithm (e.g. "sha384") and prefixed by 0_combined_spdm_prefix. The public key to verify the signature against is the leaf certificate contained in 0_certificate_chain. The nonces chosen by requester and responder are exposed as separate attributes to ease verification of their freshness. They're already contained in the transcript but their offsets within the transcript are variable, so user space would otherwise have to parse the SPDM messages in the transcript to find the nonces. The type attribute contains the event type: Currently it is always "responder-challenge_auth signing". In the future it may also contain "responder-measurements signing". This custom log format was chosen for lack of a better alternative. Although the TCG PFP Specification defines DEVICE_SECURITY_EVENT_DATA structures, those structures do not store the transcript (which can be a few kBytes or up to several MBytes in size). They do store nonces, hence at least allow for verification of nonce freshness. But without the transcript, user space cannot verify the signature: https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/ Exposing the transcript as an attribute of its own has the benefit that it can directly be fed into a protocol dissector for debugging purposes (think Wireshark). Signed-off-by: Lukas Wunner <lukas@wunner.de> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Cc: Jérôme Glisse <jglisse@google.com> Cc: Jason Gunthorpe <jgg@nvidia.com>
1 parent af9b939 commit 009663b

File tree

10 files changed

+591
-1
lines changed

10 files changed

+591
-1
lines changed

Documentation/ABI/testing/sysfs-devices-spdm

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,98 @@ Description:
7777
SPDM does not specify how to notify the kernel of such events,
7878
so unless reauthentication is manually initiated to update the
7979
kernel's cache, the "slot[0-7]" files may contain stale data.
80+
81+
82+
What: /sys/devices/.../signatures/
83+
What: /sys/devices/.../signatures/[0-9]*_signature
84+
What: /sys/devices/.../signatures/[0-9]*_transcript
85+
What: /sys/devices/.../signatures/[0-9]*_hash_algorithm
86+
What: /sys/devices/.../signatures/[0-9]*_combined_spdm_prefix
87+
What: /sys/devices/.../signatures/[0-9]*_certificate_chain
88+
Date: June 2024
89+
Contact: Lukas Wunner <lukas@wunner.de>
90+
Description:
91+
In bash syntax, the signature is verified as follows::
92+
93+
# number of signature to verify
94+
num=0
95+
96+
# split certificate chain into individual certificates
97+
openssl storeutl -text ${num}_certificate_chain | \
98+
csplit -z -f /tmp/cert - '/^[0-9]*: Certificate$/' '{*}'
99+
100+
# extract public key from leaf certificate
101+
leaf_cert=$(\ls /tmp/cert?? | tail -1)
102+
openssl x509 -pubkey -in ${leaf_cert} -out ${leaf_cert}.pub
103+
104+
# verify signature
105+
if [ \! -s ${num}_combined_spdm_prefix ] ; then
106+
# SPDM 1.0 and 1.1
107+
openssl dgst -$(cat ${num}_hash_algorithm) \
108+
-signature ${num}_signature -verify ${leaf_cert}.pub \
109+
${num}_transcript
110+
else
111+
# SPDM 1.2 and newer
112+
openssl dgst -$(cat ${num}_hash_algorithm) \
113+
-binary -out /tmp/transcript_hashed ${num}_transcript
114+
openssl dgst -$(cat ${num}_hash_algorithm) \
115+
-signature ${num}_signature -verify ${leaf_cert}.pub \
116+
${num}_combined_spdm_prefix /tmp/transcript_hashed
117+
fi
118+
119+
Note: The above works for RSA signatures, but not for ECDSA.
120+
SPDM encodes ECDSA signatures in P1363 format (concatenation of
121+
two raw integers), whereas openssl only supports X9.62 format
122+
(ASN.1 DER sequence of two integers). There is no command line
123+
utility to convert between the two formats, but most popular
124+
crypto libraries offer conversion routines:
125+
126+
| https://github.com/java-crypto/cross_platform_crypto/blob/main/docs/ecdsa_signature_conversion.md
127+
128+
The "transcript" file can be fed to a protocol dissector to
129+
examine the SPDM messages it contains:
130+
131+
| https://github.com/th-duvanel/spdm-wid
132+
| https://github.com/jyao1/wireshark-spdm
133+
| https://github.com/DMTF/spdm-dump
134+
135+
Note: To ease signature verification, the "transcript" file
136+
does not contain the trailing signature. However the signature
137+
is part of the final CHALLENGE_AUTH message, so the protocol
138+
dissector needs to be fed the concatenation of "transcript"
139+
and "signature".
140+
141+
142+
What: /sys/devices/.../signatures/[0-9]*_type
143+
Date: June 2024
144+
Contact: Lukas Wunner <lukas@wunner.de>
145+
Description:
146+
This file contains the type of event that led to signature
147+
generation. It is one of (sans quotes):
148+
149+
"responder-challenge_auth signing"
150+
151+
152+
What: /sys/devices/.../signatures/[0-9]*_requester_nonce
153+
What: /sys/devices/.../signatures/[0-9]*_responder_nonce
154+
Date: June 2024
155+
Contact: Lukas Wunner <lukas@wunner.de>
156+
Description:
157+
These files contain the 32 byte nonce chosen by requester and
158+
responder. They allow remote attestation services to verify
159+
freshness (uniqueness) of the nonces. Nonces used more than
160+
once can be identified with::
161+
162+
# hexdump -e '32/1 "%02x" "\n"' [0-9]*_nonce | sort | \
163+
uniq -c | grep -v '^ 1'
164+
165+
Remote attestation services may also want to verify that the
166+
entropy of the nonces is acceptable::
167+
168+
# ent 0_requester_nonce
169+
170+
Note: The nonces are also contained in the "transcript", but
171+
their offsets within the transcript are variable. It would be
172+
necessary to parse the SPDM messages in the transcript to find
173+
and extract the nonces, which is cumbersome. That's why they
174+
are exposed as separate files.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
2+
---
3+
name: spdm
4+
5+
doc: |
6+
DMTF Security Protocol and Data Model (SPDM)
7+
https://www.dmtf.org/dsp/DSP0274
8+
9+
protocol: genetlink
10+
11+
uapi-header: linux/spdm_netlink.h
12+
13+
definitions:
14+
-
15+
type: enum
16+
name: spdm-reqrsp-code
17+
doc: SPDM request or response code of a signed message (SPDM 1.0.0 table 4)
18+
entries:
19+
-
20+
name: spdm-challenge-auth
21+
value: 0x03
22+
-
23+
name: spdm-endpoint-info
24+
value: 0x07
25+
-
26+
name: spdm-measurements
27+
value: 0x60
28+
-
29+
name: spdm-key-exchange-rsp
30+
value: 0x64
31+
-
32+
name: spdm-finish
33+
value: 0xe5
34+
header: uapi/linux/spdm.h
35+
-
36+
type: enum
37+
name: hash-algo
38+
doc: SPDM-supported hash algorithm (SPDM 1.0.0 table 13)
39+
entries:
40+
-
41+
name: hash-algo-sha256
42+
value: 4
43+
-
44+
name: hash-algo-sha384
45+
value: 5
46+
-
47+
name: hash-algo-sha512
48+
value: 6
49+
-
50+
name: hash-algo-sha3-256
51+
value: 20
52+
-
53+
name: hash-algo-sha3-384
54+
value: 21
55+
-
56+
name: hash-algo-sha3-512
57+
value: 22
58+
header: uapi/linux/hash_info.h
59+
60+
attribute-sets:
61+
-
62+
name: sig
63+
doc: |
64+
Signature received from a device, together with all ancillary data
65+
needed for re-verification.
66+
67+
Meant for remote attestation services which do not trust the kernel
68+
to have verified the signature correctly or which want to apply
69+
policy constraints of their own.
70+
71+
The signature is computed over the %transcript attribute, which is
72+
a concatenation of all SPDM messages exchanged with the device.
73+
The transcript may occupy multiple megabytes, exceeding the maximum
74+
size of a netlink attribute. It may therefore be split across several
75+
netlink messages. The first netlink message contains a first portion
76+
of the transcript as well as all other attributes. Any subsequent
77+
netlink message contains only a single %transcript attribute which
78+
continues the already transmitted portions of the transcript.
79+
80+
SPDM 1.2 and newer hash the transcript with %hash-algo and prepend
81+
%combined-spdm-prefix before computing the signature (SPDM 1.2.0
82+
sec 15). For SPDM 1.0 and 1.1, that step is omitted and the
83+
%combined-spdm-prefix attribute is not included in the message.
84+
85+
The signature is verified against the leaf certificate in %slot.
86+
To save memory, only the slot number is included in the message,
87+
not the full certificate chain. Note that if the slot has since
88+
been provisioned with a different certificate chain, re-verification
89+
of the signature will fail.
90+
attributes:
91+
-
92+
name: device
93+
doc: |
94+
Device generating the signature, uniquely identified by its
95+
path under sysfs.
96+
type: string
97+
-
98+
name: rsp-code
99+
doc: |
100+
SPDM response code of the message containing the signature,
101+
to determine what kind of event caused signature generation.
102+
Equivalent to the "context" string of SPDM 1.2.0 sec 15,
103+
but represented numerically for easier parsing.
104+
type: u8
105+
enum: spdm-reqrsp-code
106+
-
107+
name: slot
108+
doc: |
109+
Certificate slot used for signature generation.
110+
type: u8
111+
-
112+
name: hash-algo
113+
doc: |
114+
Hash algorithm used for signature generation.
115+
type: u16
116+
enum: hash-algo
117+
-
118+
name: sig-offset
119+
doc: |
120+
Offset of signature in @transcript. The signature is located
121+
at the end of @transcript, hence its size equals @transcript
122+
size minus this offset.
123+
type: u32
124+
-
125+
name: req-nonce-offset
126+
doc: |
127+
Offset of 32 byte nonce chosen by requester in @transcript.
128+
Allows remote attestation services to verify freshness
129+
(uniqueness) and entropy adequacy of the nonce.
130+
type: u32
131+
-
132+
name: rsp-nonce-offset
133+
doc: |
134+
Offset of 32 byte nonce chosen by responder in @transcript.
135+
Allows remote attestation services to verify freshness
136+
(uniqueness) and entropy adequacy of the nonce.
137+
type: u32
138+
-
139+
name: combined-spdm-prefix
140+
doc: |
141+
Combined SPDM prefix used for signature generation (SPDM 1.2.0
142+
sec 15). Only included in the message with SPDM version 1.2.0
143+
or newer.
144+
type: binary
145+
checks:
146+
exact-len: 100
147+
-
148+
name: transcript
149+
doc: |
150+
SPDM transcript used for signature generation. The signature
151+
itself is located at the end of the transcript.
152+
type: binary
153+
multi-attr: true
154+
155+
operations:
156+
list:
157+
-
158+
name: sig
159+
doc: Signature event
160+
attribute-set: sig
161+
event:
162+
attributes:
163+
- sig
164+
mcgrp: sig
165+
166+
mcast-groups:
167+
list:
168+
-
169+
name: sig
170+
171+
kernel-family:
172+
headers: ["netlink-autogen.h"]

include/uapi/linux/spdm_netlink.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2+
/* Do not edit directly, auto-generated from: */
3+
/* Documentation/netlink/specs/spdm.yaml */
4+
/* YNL-GEN uapi header */
5+
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
6+
7+
#ifndef _UAPI_LINUX_SPDM_NETLINK_H
8+
#define _UAPI_LINUX_SPDM_NETLINK_H
9+
10+
#define SPDM_FAMILY_NAME "spdm"
11+
#define SPDM_FAMILY_VERSION 1
12+
13+
enum {
14+
SPDM_A_SIG_DEVICE = 1,
15+
SPDM_A_SIG_RSP_CODE,
16+
SPDM_A_SIG_SLOT,
17+
SPDM_A_SIG_HASH_ALGO,
18+
SPDM_A_SIG_SIG_OFFSET,
19+
SPDM_A_SIG_REQ_NONCE_OFFSET,
20+
SPDM_A_SIG_RSP_NONCE_OFFSET,
21+
SPDM_A_SIG_COMBINED_SPDM_PREFIX,
22+
SPDM_A_SIG_TRANSCRIPT,
23+
24+
__SPDM_A_SIG_MAX,
25+
SPDM_A_SIG_MAX = (__SPDM_A_SIG_MAX - 1)
26+
};
27+
28+
enum {
29+
SPDM_CMD_SIG = 1,
30+
31+
__SPDM_CMD_MAX,
32+
SPDM_CMD_MAX = (__SPDM_CMD_MAX - 1)
33+
};
34+
35+
#define SPDM_MCGRP_SIG "sig"
36+
37+
#endif /* _UAPI_LINUX_SPDM_NETLINK_H */

lib/spdm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
obj-$(CONFIG_SPDM) += spdm.o
99

1010
spdm-y := core.o req-authenticate.o
11+
spdm-$(CONFIG_NET) += req-netlink.o netlink-autogen.o
1112
spdm-$(CONFIG_SYSFS) += req-sysfs.o

lib/spdm/netlink-autogen.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
2+
/* Do not edit directly, auto-generated from: */
3+
/* Documentation/netlink/specs/spdm.yaml */
4+
/* YNL-GEN kernel source */
5+
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
6+
7+
#include <net/netlink.h>
8+
#include <net/genetlink.h>
9+
10+
#include <uapi/linux/spdm_netlink.h>
11+
#include <netlink-autogen.h>
12+
#include <uapi/linux/spdm.h>
13+
#include <uapi/linux/hash_info.h>
14+
15+
/* Ops table for spdm */
16+
static const struct genl_split_ops spdm_nl_ops[] = {
17+
};
18+
19+
static const struct genl_multicast_group spdm_nl_mcgrps[] = {
20+
[SPDM_NLGRP_SIG] = { "sig", },
21+
};
22+
23+
struct genl_family spdm_nl_family __ro_after_init = {
24+
.name = SPDM_FAMILY_NAME,
25+
.version = SPDM_FAMILY_VERSION,
26+
.netnsok = true,
27+
.parallel_ops = true,
28+
.module = THIS_MODULE,
29+
.split_ops = spdm_nl_ops,
30+
.n_split_ops = ARRAY_SIZE(spdm_nl_ops),
31+
.mcgrps = spdm_nl_mcgrps,
32+
.n_mcgrps = ARRAY_SIZE(spdm_nl_mcgrps),
33+
};

lib/spdm/netlink-autogen.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
2+
/* Do not edit directly, auto-generated from: */
3+
/* Documentation/netlink/specs/spdm.yaml */
4+
/* YNL-GEN kernel header */
5+
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
6+
7+
#ifndef _LINUX_SPDM_GEN_H
8+
#define _LINUX_SPDM_GEN_H
9+
10+
#include <net/netlink.h>
11+
#include <net/genetlink.h>
12+
13+
#include <uapi/linux/spdm_netlink.h>
14+
#include <netlink-autogen.h>
15+
#include <uapi/linux/spdm.h>
16+
#include <uapi/linux/hash_info.h>
17+
18+
enum {
19+
SPDM_NLGRP_SIG,
20+
};
21+
22+
extern struct genl_family spdm_nl_family;
23+
24+
#endif /* _LINUX_SPDM_GEN_H */

0 commit comments

Comments
 (0)