Skip to content

Commit acb2497

Browse files
committed
Propose an RFC for version negotiation in Cerberus
1 parent d9c9cc3 commit acb2497

File tree

1 file changed

+205
-0
lines changed

1 file changed

+205
-0
lines changed

0003-Version_Detection.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
* Name: Version_Detection
2+
* Date: 2021-09-20
3+
* Pull Request: [#NNNN](https://github.com/opencomputeproject/Security/pull/NNNN)
4+
5+
# Objective
6+
7+
Cerberus does not currently expose a particularly precise interface for
8+
discovering the version of a remote device being challenged or otherwise
9+
interacted with. However, Cerberus does make reference to these versions as part
10+
of the `CHALLENGE` message.
11+
12+
Cerberus also has significant "optional" components, though there is no way to
13+
discover whether a remote device supports them. In theory this would be provided
14+
to a PA-RoT via a manifest, but it some cases it may be useful to query this
15+
information dynamically.
16+
17+
This RFC describes:
18+
- A formal versioning scheme for the overall protocol, as well as its optional
19+
subcomponents.
20+
- A protocol command for querying this version information.
21+
- A way for vendors to allow for unambiguous querying of their vendor
22+
extensions.
23+
- A story for deprecation of commands.
24+
25+
# Proposal
26+
27+
Although Cerberus has some minor prior art around version numbers, we will be
28+
starting over from a clean slate.
29+
30+
## Protocol Version Numbers
31+
32+
A Cerberus version is a sixteen-bit opaque value, mapped to a commit hash of
33+
this repository. Protocol version N is described by the repository at that
34+
commit.
35+
36+
Versions are recorded as Git tags with the name `protocol-v{#}`, where
37+
`{#}` is replaced with the version number. There will also be a file,
38+
`PROTOCOL_VERSIONS.md`, which contains a list of all versions, their dates,
39+
and a changelog, in the following format:
40+
```
41+
# `protocol-v{#}`
42+
Date: YYYY-MM-DD
43+
<changelog>
44+
```
45+
46+
To create a new version:
47+
1. Create a commit that adds the new version to `PROTOCOL_VERSIONS.md`.
48+
2. The pull request created from that commit acts as an opportunity to discuss
49+
the new version and changelog.
50+
3. Once approved, the author must ensure the date on the new version matches.
51+
4. A maintainer will merge the PR, and then create a lightweight tag with the
52+
correct name pointing to the merged commit. This can be done via
53+
`git tag protocol-v{#} && git push origin --tags`. This must be a push to
54+
the upstream repository.
55+
56+
This proposal does not stipulate guidelines under which creating a new version
57+
is recommended; maintainers should create new versions as they deem necessary.
58+
59+
After this RFC is merged and implemented, a new version, version 0, must be
60+
created immediately.
61+
62+
## Subcomponents
63+
64+
A subcomponent is a set of optional Cerberus commands that need to be provided
65+
together, such as the PFM-related commands. Each subcomponent has a byte
66+
associated with it.
67+
68+
The subcomponents, their identifying bytes, and the list of commands in each
69+
should be listed in a table, just past the list of all commands. All optional
70+
commands must be part of a subcomponent, and a command may be part of multiple
71+
components.
72+
73+
## The `Protocol Version` Command
74+
75+
We define a new command, `Protocol Version`, using command byte `0x05`, and
76+
marked as *required*. Its purpose is to negotiate a shared version for the
77+
devices to communicate over.
78+
79+
A request has the following structure:
80+
81+
```c
82+
struct ProtocolVersionRequest {
83+
uint8_t reserved; // Must be zero.
84+
85+
uint16_t min_version;
86+
uint16_t max_version;
87+
88+
uint8_t bad_versions_len;
89+
uint16_t bad_versions[bad_versions_len];
90+
91+
uint8_t extns_len;
92+
struct {
93+
uint8_t len;
94+
uint8_t name[len];
95+
} extns[extns_len];
96+
}
97+
```
98+
99+
The requester provides the minimum and maximum versions (inclusive) it
100+
understands, as well as a list of versions it refuses to use (for security
101+
or other reasons). It also provides a list of vendor-defined extensions it
102+
knows how to speak.
103+
104+
Vendor-defined extensions are defined by strings, to
105+
avoid running into the usual "private use area" problems in code-point
106+
allocation. Vendors should choose strings that incorporate their name into them
107+
to avoid chances of collision. Period-separated names are ideal:
108+
- `widgetsinc.unsealing-with-chacha20`
109+
- `acmeco.fancy-pcie-update-scheme`
110+
111+
The response looks like this:
112+
113+
```c
114+
struct ProtocolVersionResponse {
115+
uint16_t version;
116+
117+
uint8_t extns_len;
118+
uint16_t extn_versions[extns_len];
119+
};
120+
```
121+
122+
This provides the responder-chosen version, and the versions of the requested
123+
vendor-defined extensions. A version of `0xffff` is used as a sentinel to
124+
indicate that the extension was unrecognized.
125+
126+
All messages that follow must use the chosen version number. This number not
127+
only specifies which messages are supported, but also which format to use for
128+
parsing commands, since that may vary across versions. The `Protocol Version`
129+
command, however, is unversioned. A reserved byte is included at the top of
130+
the command in case we ever need to change it.
131+
132+
A new error code, "Unnegotiated Version" (code `0x05`), should be returned by
133+
devices if no version has been negotiated yet with the requesting device.
134+
Requesters which had previously negotiated a version, but which recieve this
135+
message, should re-negotiate a version.
136+
137+
## Updates to `CHALLENGE`
138+
139+
Because only a single protocol version is negotiated, we can replace the version
140+
range in the `CHALLENGE` with the single negotiated version. This doesn't change
141+
the layout of the `CHALLENGE` in a meaningful way, since we are replacing two
142+
eight-bit fields with one sixteen-bit field.
143+
144+
## Evolution and Deprecation Process
145+
146+
This versioning scheme gives us a way to freely evolve the protocol without
147+
fear of subtle incompatibility: because one version is chosen, there is no
148+
ambiguity about different layouts of commands.
149+
150+
We also get deprecation for free: if we remove a message, devices can, given
151+
sufficiently wide range of advertised versions, select a version both are
152+
can work with. We can even re-use command bytes across versions, if that ever
153+
becomes a problem.
154+
155+
There is no particular reason to mark messages as deprecated in the spec itself,
156+
although it may be worthwhile to do so to indicate that they will eventually be
157+
removed. Whether to leave messages deprecated for a version or two, or to remove
158+
them immediately, is up to the maintainers.
159+
160+
This introduces the risk that two devices may refuse to interoperate due to
161+
incompatible versions. It is up to implementers to chose a sufficiently large
162+
range of versions to interoperate with other vendors' devices.
163+
164+
# Specification Changelist
165+
166+
The following changes are required:
167+
- The creation of `PROTOCOL_VERSIONS.md` as described above.
168+
- Prose in a section immediately before the `RoT Commands` section that
169+
describes the Cerberus Protocol versioning scheme, including protocol
170+
subcomponents and vendor-defined extensions.
171+
- A table immediately after the table of all commands, which defines the
172+
protocol subcomponents.
173+
- Add the new error code to the error codes table.
174+
- A new message definition, after `Device Information`, for the new `Protocol
175+
Version` command. This shall include prose of the negotiation process.
176+
- The min/max version fields in the `CHALLENGE` should be replaced with the
177+
single negotiated version.
178+
179+
# Implementation Guidance
180+
181+
Implementers which support a range of Cerberus versions will need to maintain a
182+
"currently negotiated version" for each bus they can service requests from.
183+
This should not be a significant cost, given they already need to maintain
184+
similar information for sessions.
185+
186+
Because requesters must know how to re-establish a negotiated version, an
187+
implementer can choose to record only a single version at a time.
188+
189+
# Alternatives Considered
190+
191+
An alternative is to have requester-chosen, rather than responder-chosen,
192+
versions. This doesn't have any specific benefits for us, but it does have the
193+
downside that we need to deal with different versions having different layouts
194+
for commands, meaning that the requester still needs to inform the responder
195+
about which protocol version it wishes to use.
196+
197+
This could be worked around by being careful about how commands are evolved, but
198+
it's likely to be rare enough that command formats change that the complexity
199+
would be worth it.
200+
201+
# Future Work
202+
203+
This RFC does not describe norms and practices around when to mint versions nor
204+
when to make the actual decision of deprecation; these are left up to the
205+
maintainers or a potential future RFC.

0 commit comments

Comments
 (0)