Skip to content

Commit 3513369

Browse files
committed
Document required client changes for Rekor v2
Fixes #108 Signed-off-by: Hayden B <8418760+haydentherapper@users.noreply.github.com>
1 parent ec16bc7 commit 3513369

File tree

1 file changed

+324
-0
lines changed

1 file changed

+324
-0
lines changed

CLIENTS.md

Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
# Client Changes for Rekor v2
2+
3+
This document outlines the changes clients need to make to support
4+
Rekor v2.
5+
6+
## Rekor v2 API
7+
8+
Rekor v2 supports HTTP or gRPC, like Fulcio. For Go, we have implemented a client
9+
already. For other languages, they can either use the
10+
[OpenAPI docs](https://github.com/sigstore/rekor-tiles/tree/main/docs/openapi),
11+
[gRPC service proto](https://github.com/sigstore/rekor-tiles/tree/main/api/proto),
12+
or create their own client.
13+
14+
The service implements one write API, `/api/v2/log/entries`. Example JSON request bodies
15+
below:
16+
17+
```jsonc
18+
// Request with a Fulcio certificate
19+
{
20+
"hashedRekordRequestV0_0_2": {
21+
// Must use hash algorithm from key_details
22+
"digest": "<base64 digest of artifact>",
23+
"signature": {
24+
"content": "<base64 signature>",
25+
"verifier": {
26+
"x509Certificate": "<base64 DER-encoded certificate>",
27+
// Must match signing algorithm
28+
"keyDetails": "PKIX_ECDSA_P256_SHA_256"
29+
}
30+
}
31+
}
32+
}
33+
34+
// Request with a self-managed key
35+
{
36+
"hashedRekordRequestV0_0_2": {
37+
"digest": "<base64 digest of artifact>",
38+
"signature": {
39+
"content": "<base64 signature>",
40+
"verifier": {
41+
"publicKey": {
42+
"rawBytes": "<base64 DER-encoded public key>"
43+
},
44+
"keyDetails": "PKIX_ECDSA_P256_SHA_256"
45+
}
46+
}
47+
}
48+
}
49+
50+
// Request with an attestation
51+
{
52+
"dsseRequestV0_0_2": {
53+
"envelope": {
54+
"payload": "<base64-encoded message>",
55+
"payloadType": "<type, e.g. application/vnd.in-toto+json>",
56+
"signatures": [
57+
{
58+
"sig": "<base64-encoded signature>",
59+
"keyid": ""
60+
}
61+
]
62+
},
63+
"verifier": {
64+
"x509Certificate": "<base64 DER-encoded certificate>",
65+
// Must match signing algorithm
66+
"keyDetails": "PKIX_ECDSA_P256_SHA_256"
67+
}
68+
}
69+
}
70+
71+
// Request with an attestation with a self-managed key
72+
{
73+
"dsseRequestV0_0_2": {
74+
"envelope": {
75+
"payload": "<base64-encoded message>",
76+
"payloadType": "<type, e.g. application/vnd.in-toto+json>",
77+
"signatures": [
78+
{
79+
"sig": "<base64-encoded signature>",
80+
"keyid": ""
81+
}
82+
]
83+
},
84+
"verifier": {
85+
"publicKey": {
86+
"rawBytes": "<base64 DER-encoded public key>"
87+
},
88+
// Must match signing algorithm
89+
"keyDetails": "PKIX_ECDSA_P256_SHA_256"
90+
}
91+
}
92+
}
93+
```
94+
95+
The response will be a
96+
[`TransparencyLogEntry` message](https://github.com/sigstore/protobuf-specs/blob/5296f13d62e7fad428581d969f664c30cc52f549/protos/sigstore_rekor.proto#L94),
97+
which should be persisted in a bundle. Clients no longer need to transform the
98+
Rekor response into a `TLE` message to store in the bundle.
99+
100+
### Two Entry Types
101+
102+
Rekor v2 only supports `hashedrekord` (`HashedRekordRequestV0_0_2`) and
103+
`dsse` (`DSSERequestV0_0_2`) entry types, dropping a number of unused types
104+
such as `jar`, `alpine`, `rpm`, and the older types `rekord` and `intoto`.
105+
Additional types may be added in the future if there is demand, but this
106+
will require updating the client specification so that all clients implement
107+
support for these types.
108+
109+
### Certificate and Public Key Verifiers
110+
111+
Rekor v2 only supports signature verification using a certificate or a
112+
public key, dropping support for PGP, minisign, pkcs7, SSH and TUF.
113+
Additional verifiers may be added in the future, but this will also require
114+
updating the client specification.
115+
116+
## Handling Longer Requests
117+
118+
Clients need to increase request timeouts to at least 10 seconds.
119+
120+
Rekor now batches uploads so that checkpoints are published less frequently.
121+
Additionally, we plan to support synchronous witnessing, where third-party
122+
witnesses independently verify the consistency of the log and Rekor provides
123+
co-signed checkpoints with each upload response.
124+
125+
## Signed RFC 3161 Timestamps
126+
127+
Rekor will no longer return SignedEntryTimestamps or include integrated time
128+
in the response. Clients must fetch an RFC 3161 signed timestamp from a trusted
129+
timestamp authority and include the signed timestamp in the bundle.
130+
131+
Sigstore now operates a timestamp authority at `timestamp.sigstore.dev` and
132+
`timestamp.sigstage.dev` for staging, and the roots for these services will
133+
be included in the TrustedRoot distributed via TUF. Clients may request timestamps
134+
from other trusted timestamp authorities as well. As with other services,
135+
users should specify the verification material for the additional timestamp
136+
authorities in the TrustedRoot.
137+
138+
## SigningConfig support
139+
140+
Clients must implement support for the SigningConfig message, which specifies
141+
the list of URLs that clients should use during signing. Since Rekor shards
142+
will now have unique URLs, we will use the SigningConfig to distribute
143+
the URLs for new shards.
144+
145+
We have published a v2 SigningConfig message to support handling log
146+
sharding, with validity windows (which will prevent a client from writing to a
147+
log before the TrustedRoot is fully distributed) and services with different API
148+
versions (for the transition between Rekor v1 and v2).
149+
150+
A more detailed description of how clients must, should and may handle
151+
the SigningConfig message is in the
152+
[protobuf-specs repo](https://github.com/sigstore/protobuf-specs/blob/dda47952957722e943829af6fe531c005a9fbed6/protos/sigstore_trustroot.proto#L147).
153+
154+
An example SigningConfig with annotations is below:
155+
156+
```jsonc
157+
{
158+
// Clients do not need to support v0.1
159+
"mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json",
160+
161+
// Fulcio service URLs.
162+
// Clients must select the first service from the list whose validity window
163+
// is active and the API version is supported by the client. Clients must
164+
// select the highest supported API version.
165+
// Clients can assume that this list is sorted from most recent to oldest.
166+
"caUrls": {
167+
"url": "https://fulcio.sigstore.dev",
168+
"majorApiVersion": 1,
169+
"validFor": {
170+
// When clients should start using this service
171+
"start": "<UTC timestamp>",
172+
// Optional, when a service is turned down and clients should
173+
// treat the service as offline
174+
"end": "<UTC timestamp>"
175+
},
176+
},
177+
178+
// OIDC service URLs
179+
"oidcUrls": {
180+
"url": "https://oauth2.sigstore.dev/auth",
181+
"majorApiVersion": 1,
182+
"validFor": {
183+
"start": "<UTC timestamp>"
184+
},
185+
},
186+
187+
188+
"rekorTlogUrls": {
189+
"url": "https://oauth2.sigstore.dev/auth",
190+
"majorApiVersion": 1,
191+
"validFor": {
192+
"start": "<UTC timestamp>"
193+
},
194+
},
195+
196+
// Rekor service selection
197+
// "Valid" is defined above to mean the service's validity window is
198+
// active and the API version is supported by the client.
199+
"rekorTlogConfig": {
200+
// EXACT specifies that a client must upload entries to exactly
201+
// "count" number of valid logs. Clients must throw an error
202+
// if less than "count" logs are valid. Clients should select
203+
// logs from the highest available API version, even if "count"
204+
// logs are not available.
205+
// May also be ANY, meaning the client should select exactly
206+
// one valid log. The client can decide how to select it, e.g. random
207+
// or round-robin if the client tracks state.
208+
// May also be ALL, which should be all valid logs.
209+
"selector": "EXACT",
210+
// Optional, only when EXACT is specified
211+
"count": 2
212+
},
213+
214+
// Timestamp authority URLs
215+
// Like Rekor, clients should use the TSA config which dictates
216+
// how many TSAs should be used to request timestamps from.
217+
"tsaUrls": {
218+
"url": "https://oauth2.sigstore.dev/auth",
219+
"majorApiVersion": 1,
220+
"validFor": {
221+
"start": "<UTC timestamp>"
222+
},
223+
},
224+
225+
// Timestamp authority service selection
226+
"tsaConfig": {
227+
"selector": "ANY"
228+
}
229+
}
230+
```
231+
232+
## Removing Online Verification and Search
233+
234+
Rekor no longer provides an API for online verification and search. This includes
235+
the APIs for requesting inclusion proofs by index, by leaf hash and by entry,
236+
and searching for an entry by artifact hash or identity. In the near future,
237+
we will spin up a separate service to support search.
238+
239+
Clients must be given the inclusion proof and checkpoint for an entry,
240+
which must be stored in a bundle.
241+
242+
This should have no impact on clients as inclusion proofs were already
243+
required in bundles. This will only impact monitors, and the read API
244+
changes are detailed below.
245+
246+
## No Attestation Storage
247+
248+
Rekor v1's `intoto` type persisted attestations. Rekor v1's `dsse` type
249+
removed attestation storage as Rekor was not designed to be used as storage
250+
for verification metadata.
251+
252+
In Rekor v2, the `DSSERequestV0_0_2` type will also not support attestation
253+
storage. Attestations should be persisted alongside an artifact, e.g. in
254+
OCI or a package registry, or in a dedicated attestation storage service.
255+
256+
## C2SP Checkpoints
257+
258+
The checkpoints the log provides will conform to the
259+
[C2SP checkpoint spec](https://github.com/C2SP/C2SP/blob/main/tlog-checkpoint.md).
260+
Clients must check that their checkpoint verification implementation properly
261+
handles these checkpoints, which could include:
262+
263+
* Multiple signatures
264+
* Optional extension lines
265+
* Updated key names, which will match the shard URL
266+
* Key IDs calculated per the [signed note spec](https://github.com/C2SP/C2SP/blob/main/signed-note.md#signatures)
267+
* ECDSA and Ed25519 key IDs are based on the spec
268+
* For RSA, the signature type is `0xFF` and we append `PKIX-RSA-PKCS#1v1.5`,
269+
`key ID = SHA-256(key name || 0x0A || 0xFF || PKIX-RSA-PKCS#1v1.5 || public key)[:4]`
270+
271+
## TrustedRoot With Multiple Logs
272+
273+
Clients must verify that verification works with a TrustedRoot
274+
with multiple logs with overlapping validity windows. Confirm that
275+
the client will fetch the correct verification key from the TrustedRoot
276+
by using the log ID (which is the hash of the log's public key).
277+
278+
## Monitoring/Auditing
279+
280+
One of the more significant changes in a tile-backed log is the changes
281+
to the read API. Inclusion and consistency proofs are not served via an
282+
API, rather the client requests the set of tiles necessary to compute
283+
the inclusion or consistency proof.
284+
285+
When monitoring the log searching for entries, the monitor will not request
286+
entries by index, but by tile. Monitors can choose to only fetch complete
287+
tiles or request [partial tiles](https://github.com/C2SP/C2SP/blob/main/tlog-tiles.md#partial-tiles),
288+
which are the rightmost tiles in a tree that may contain somewhere between 1 and 255 hashes.
289+
It is recommended to request partial tiles, or else the monitor might lag behind
290+
if tiles are not filled frequently.
291+
292+
The APIs to request checkpoints, tiles, and entry bundles are defined
293+
in the
294+
[tlog-tiles spec](https://github.com/C2SP/C2SP/blob/main/tlog-tiles.md#apis).
295+
For Go, [trillian-tessera](https://github.com/transparency-dev/trillian-tessera/tree/main/client)
296+
provides a client to compute proofs and fetch tiles.
297+
298+
## Future: Witnessing
299+
300+
Witnessing provides independent verification that the log
301+
remains consistent (append-only). Witnessing can either be
302+
asynchronous, where a client requests witnesses verify consistency
303+
proofs, or synchronous, where the log requests witnesses
304+
verify proofs for every checkpoint issued. This results in a
305+
longer request times and a dependency on third-party witnesses,
306+
but results in a strong offline proof of log inclusion. We
307+
will publish a doc later on with more details.
308+
309+
In the initial launch of Rekor v2, checkpoints will not be
310+
witnessed, while we wait for the launch of a public witness
311+
network. Clients do not need to implement verification of
312+
witness signatures initially, but clients should increase
313+
request timeouts to account for the additional time to
314+
sign checkpoints, which we estimate to be <10s.
315+
316+
To verify cosignatures, see the
317+
[spec](https://github.com/C2SP/C2SP/blob/main/tlog-cosignature.md).
318+
319+
The log will determine which set of witnesses is trusted and the
320+
M-of-N witnesses to fetch signatures from, and this policy will
321+
be distributed by Sigstore's TUF root.
322+
323+
Co-signed checkpoints will also be timestamped, so they can serve
324+
as an independent signed timestamp instead of an RFC 3161 timestamp.

0 commit comments

Comments
 (0)