1container-signature(5) format container-signature(5)
2
3
4
5Miloslav Trmač March 2017
6
7
9 container-signature - Container signature format
10
11
12
14 This document describes the format of container signatures, as imple‐
15 mented by the github.com/containers/image/signature package.
16
17
18 Most users should be able to consume these signatures by using the
19 github.com/containers/image/signature package (preferably through the
20 higher-level signature.PolicyContext interface) without having to care
21 about the details of the format described below. This documentation
22 exists primarily for maintainers of the package and to allow indepen‐
23 dent reimplementations.
24
25
27 The signature provides an end-to-end authenticated claim that a con‐
28 tainer image has been approved by a specific party (e.g. the creator of
29 the image as their work, an automated build system as a result of an
30 automated build, a company IT department approving the image for pro‐
31 duction) under a specified identity (e.g. an OS base image / specific
32 application, with a specific version).
33
34
35 A container signature consists of a cryptographic signature which iden‐
36 tifies and authenticates who signed the image, and carries as a signed
37 payload a JSON document. The JSON document identifies the image being
38 signed, claims a specific identity of the image and if applicable, con‐
39 tains other information about the image.
40
41
42 The signatures do not modify the container image (the layers, configu‐
43 ration, manifest, …); e.g. their presence does not change the manifest
44 digest used to identify the image in docker/distribution servers;
45 rather, the signatures are associated with an immutable image. An im‐
46 age can have any number of signatures so signature distribution systems
47 SHOULD support associating more than one signature with an image.
48
49
51 As distributed, the container signature is a blob which contains a
52 cryptographic signature in an industry-standard format, carrying a
53 signed JSON payload (i.e. the blob contains both the JSON document and
54 a signature of the JSON document; it is not a “detached signature” with
55 independent blobs containing the JSON document and a cryptographic sig‐
56 nature).
57
58
59 Currently the only defined cryptographic signature format is an OpenPGP
60 signature (RFC 4880), but others may be added in the future. (The blob
61 does not contain metadata identifying the cryptographic signature for‐
62 mat. It is expected that most formats are sufficiently self-describing
63 that this is not necessary and the configured expected public key pro‐
64 vides another indication of the expected cryptographic signature for‐
65 mat. Such metadata may be added in the future for newly added crypto‐
66 graphic signature formats, if necessary.)
67
68
69 Consumers of container signatures SHOULD verify the cryptographic sig‐
70 nature against one or more trusted public keys (e.g. defined in a pol‐
71 icy.json signature verification policy file ⟨containers-pol‐
72 icy.json.5.md⟩) before parsing or processing the JSON payload in any
73 way, in particular they SHOULD stop processing the container signature
74 if the cryptographic signature verification fails, without even start‐
75 ing to process the JSON payload.
76
77
78 (Consumers MAY extract identification of the signing key and other
79 metadata from the cryptographic signature, and the JSON payload, with‐
80 out verifying the signature, if the purpose is to allow managing the
81 signature blobs, e.g. to list the authors and image identities of sig‐
82 natures associated with a single container image; if so, they SHOULD
83 design the output of such processing to minimize the risk of users con‐
84 sidering the output trusted or in any way usable for making policy de‐
85 cisions about the image.)
86
87
88 OpenPGP signature verification
89 When verifying a cryptographic signature in the OpenPGP format, the
90 consumer MUST verify at least the following aspects of the signature
91 (like the github.com/containers/image/signature package does):
92
93
94 • The blob MUST be a “Signed Message” as defined RFC 4880 sec‐
95 tion 11.3. (e.g. it MUST NOT be an unsigned “Literal Mes‐
96 sage”, a “Cleartext Signature” as defined in RFC 4880 section
97 7, or any other non-signature format).
98
99 • The signature MUST have been made by an expected key trusted
100 for the purpose (and the specific container image).
101
102 • The signature MUST be correctly formed and pass the crypto‐
103 graphic validation.
104
105 • The signature MUST correctly authenticate the included JSON
106 payload (in particular, the parsing of the JSON payload MUST
107 NOT start before the complete payload has been cryptographi‐
108 cally authenticated).
109
110 • The signature MUST NOT be expired.
111
112
113
114 The consumer SHOULD have tests for its verification code which verify
115 that signatures failing any of the above are rejected.
116
117
119 The payload of the cryptographic signature is a JSON document (RFC
120 7159). Consumers SHOULD parse it very strictly, refusing any signature
121 which violates the expected format (e.g. missing members, incorrect
122 member types) or can be interpreted ambiguously (e.g. a duplicated mem‐
123 ber in a JSON object).
124
125
126 Any violations of the JSON format or of other requirements in this doc‐
127 ument MAY be accepted if the JSON document can be recognized to have
128 been created by a known-incorrect implementation (see optional.creator
129 ⟨#optionalcreator⟩ below) and if the semantics of the invalid document,
130 as created by such an implementation, is clear.
131
132
133 The top-level value of the JSON document MUST be a JSON object with ex‐
134 actly two members, critical and optional, each a JSON object.
135
136
137 The critical object MUST contain a type member identifying the document
138 as a container signature (as defined below ⟨#criticaltype⟩) and signa‐
139 ture consumers MUST reject signatures which do not have this member or
140 in which this member does not have the expected value.
141
142
143 To ensure forward compatibility (allowing older signature consumers to
144 correctly accept or reject signatures created at a later date, with
145 possible extensions to this format), consumers MUST reject the signa‐
146 ture if the critical object, or any of its subobjects, contain any mem‐
147 ber or data value which is unrecognized, unsupported, invalid, or in
148 any other way unexpected. At a minimum, this includes unrecognized
149 members in a JSON object, or incorrect types of expected members.
150
151
152 For the same reason, consumers SHOULD accept any members with unrecog‐
153 nized names in the optional object, and MAY accept signatures where the
154 object member is recognized but unsupported, or the value of the member
155 is unsupported. Consumers still SHOULD reject signatures where a mem‐
156 ber of an optional object is supported but the value is recognized as
157 invalid.
158
159
161 An example of the full format follows, with detailed description below.
162 To reiterate, consumers of the signature SHOULD perform successful
163 cryptographic verification, and MUST reject unexpected data in the
164 critical object, or in the top-level object, as described above.
165
166
167 {
168 "critical": {
169 "type": "atomic container signature",
170 "image": {
171 "docker-manifest-digest": "sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e"
172 },
173 "identity": {
174 "docker-reference": "docker.io/library/busybox:latest"
175 }
176 },
177 "optional": {
178 "creator": "some software package v1.0.1-35",
179 "timestamp": 1483228800,
180 }
181 }
182
183
184
185 critical
186 This MUST be a JSON object which contains data critical to correctly
187 evaluating the validity of a signature.
188
189
190 Consumers MUST reject any signature where the critical object contains
191 any unrecognized, unsupported, invalid or in any other way unexpected
192 member or data.
193
194
195 critical.type
196 This MUST be a string with a string value exactly equal to atomic con‐
197 tainer signature (three words, including the spaces).
198
199
200 Signature consumers MUST reject signatures which do not have this mem‐
201 ber or this member does not have exactly the expected value.
202
203
204 (The consumers MAY support signatures with a different value of the
205 type member, if any is defined in the future; if so, the rest of the
206 JSON document is interpreted according to rules defining that value of
207 critical.type, not by this document.)
208
209
210 critical.image
211 This MUST be a JSON object which identifies the container image this
212 signature applies to.
213
214
215 Consumers MUST reject any signature where the critical.image object
216 contains any unrecognized, unsupported, invalid or in any other way un‐
217 expected member or data.
218
219
220 (Currently only the docker-manifest-digest way of identifying a con‐
221 tainer image is defined; alternatives to this may be defined in the fu‐
222 ture, but existing consumers are required to reject signatures which
223 use formats they do not support.)
224
225
226 critical.image.docker-manifest-digest
227 This MUST be a JSON string, in the github.com/opencontainers/go-di‐
228 gest.Digest string format.
229
230
231 The value of this member MUST match the manifest of the signed con‐
232 tainer image, as implemented in the docker/distribution manifest ad‐
233 dressing system.
234
235
236 The consumer of the signature SHOULD verify the manifest digest against
237 a fully verified signature before processing the contents of the image
238 manifest in any other way (e.g. parsing the manifest further or down‐
239 loading layers of the image).
240
241
242 Implementation notes: * A single container image manifest may have sev‐
243 eral valid manifest digest values, using different algorithms. * For
244 “signed” docker/distribution schema 1 ⟨https://github.com/docker/dis‐
245 tribution/blob/master/docs/spec/manifest-v2-1.md⟩ manifests, the mani‐
246 fest digest applies to the payload of the JSON web signature, not to
247 the raw manifest blob.
248
249
250 critical.identity
251 This MUST be a JSON object which identifies the claimed identity of the
252 image (usually the purpose of the image, or the application, along with
253 a version information), as asserted by the author of the signature.
254
255
256 Consumers MUST reject any signature where the critical.identity object
257 contains any unrecognized, unsupported, invalid or in any other way un‐
258 expected member or data.
259
260
261 (Currently only the docker-reference way of claiming an image iden‐
262 tity/purpose is defined; alternatives to this may be defined in the fu‐
263 ture, but existing consumers are required to reject signatures which
264 use formats they do not support.)
265
266
267 critical.identity.docker-reference
268 This MUST be a JSON string, in the github.com/docker/distribution/ref‐
269 erence string format, and using the same normalization semantics (where
270 e.g. busybox:latest is equivalent to docker.io/library/busybox:latest).
271 If the normalization semantics allows multiple string representations
272 of the claimed identity with equivalent meaning, the critical.iden‐
273 tity.docker-reference member SHOULD use the fully explicit form (in‐
274 cluding the full host name and namespaces).
275
276
277 The value of this member MUST match the image identity/purpose expected
278 by the consumer of the image signature and the image (again, accounting
279 for the docker/distribution/reference normalization semantics).
280
281
282 In the most common case, this means that the critical.identity.docker-
283 reference value must be equal to the docker/distribution reference used
284 to refer to or download the image. However, depending on the specific
285 application, users or system administrators may accept less specific
286 matches (e.g. ignoring the tag value in the signature when pulling the
287 :latest tag or when referencing an image by digest), or they may re‐
288 quire critical.identity.docker-reference values with a completely dif‐
289 ferent namespace to the reference used to refer to/download the image
290 (e.g. requiring a critical.identity.docker-reference value which iden‐
291 tifies the image as coming from a supplier when fetching it from a com‐
292 pany-internal mirror of approved images). The software performing this
293 verification SHOULD allow the users to define such a policy using the
294 policy.json signature verification policy file format ⟨containers-pol‐
295 icy.json.5.md⟩.
296
297
298 The critical.identity.docker-reference value SHOULD contain either a
299 tag or digest; in most cases, it SHOULD use a tag rather than a digest.
300 (See also the default matchRepoDigestOrExact matching semantics in pol‐
301 icy.json ⟨containers-policy.json.5.md#signedby⟩.)
302
303
304 optional
305 This MUST be a JSON object.
306
307
308 Consumers SHOULD accept any members with unrecognized names in the op‐
309 tional object, and MAY accept a signature where the object member is
310 recognized but unsupported, or the value of the member is valid but un‐
311 supported. Consumers still SHOULD reject any signature where a member
312 of an optional object is supported but the value is recognized as in‐
313 valid.
314
315
316 optional.creator
317 If present, this MUST be a JSON string, identifying the name and ver‐
318 sion of the software which has created the signature (identifying the
319 low-level software implementation; not the top-level caller).
320
321
322 The contents of this string is not defined in detail; however each im‐
323 plementation creating container signatures:
324
325
326 • SHOULD define the contents to unambiguously define the soft‐
327 ware in practice (e.g. it SHOULD contain the name of the soft‐
328 ware, not only the version number)
329
330 • SHOULD use a build and versioning process which ensures that
331 the contents of this string (e.g. an included version number)
332 changes whenever the format or semantics of the generated sig‐
333 nature changes in any way; it SHOULD not be possible for two
334 implementations which use a different format or semantics to
335 have the same optional.creator value
336
337 • SHOULD use a format which is reasonably easy to parse in soft‐
338 ware (perhaps using a regexp), and which makes it easy enough
339 to recognize a range of versions of a specific implementation
340 (e.g. the version of the implementation SHOULD NOT be only a
341 git hash, because they don’t have an easily defined ordering;
342 the string should contain a version number, or at least a date
343 of the commit).
344
345
346
347 Consumers of container signatures MAY recognize specific values or sets
348 of values of optional.creator (perhaps augmented with optional.time‐
349 stamp), and MAY change their processing of the signature based on these
350 values (usually to accommodate violations of this specification in past
351 versions of the signing software which cannot be fixed retroactively),
352 as long as the semantics of the invalid document, as created by such an
353 implementation, is clear.
354
355
356 If consumers of signatures do change their behavior based on the op‐
357 tional.creator value, they SHOULD take care that the way they process
358 the signatures is not inconsistent with strictly validating signature
359 consumers. (I.e. it is acceptable for a consumer to accept a signature
360 based on a specific optional.creator value if other implementations
361 would completely reject the signature, but it would be very undesirable
362 for the two kinds of implementations to accept the signature in differ‐
363 ent and inconsistent situations.)
364
365
366 optional.timestamp
367 If present, this MUST be a JSON number, which is representable as a
368 64-bit integer, and identifies the time when the signature was created
369 as the number of seconds since the UNIX epoch (Jan 1 1970 00:00 UTC).
370
371
372
373signature Container container-signature(5)