Provided by: golang-github-containers-image_5.34.2-1_all 

NAME
container-signature - Container signature format
DESCRIPTION
This document describes the format of container signatures, as implemented by the
github.com/containers/image/signature package.
Most users should be able to consume these signatures by using the github.com/containers/image/signature
package (preferably through the higher-level signature.PolicyContext interface) without having to care
about the details of the format described below. This documentation exists primarily for maintainers of
the package and to allow independent reimplementations.
High-level overview
The signature provides an end-to-end authenticated claim that a container image has been approved by a
specific party (e.g. the creator of the image as their work, an automated build system as a result of an
automated build, a company IT department approving the image for production) under a specified identity
(e.g. an OS base image / specific application, with a specific version).
A container signature consists of a cryptographic signature which identifies and authenticates who signed
the image, and carries as a signed payload a JSON document. The JSON document identifies the image being
signed, claims a specific identity of the image and if applicable, contains other information about the
image.
The signatures do not modify the container image (the layers, configuration, manifest, …); e.g. their
presence does not change the manifest digest used to identify the image in docker/distribution servers;
rather, the signatures are associated with an immutable image. An image can have any number of
signatures so signature distribution systems SHOULD support associating more than one signature with an
image.
The cryptographic signature
As distributed, the container signature is a blob which contains a cryptographic signature in an
industry-standard format, carrying a signed JSON payload (i.e. the blob contains both the JSON document
and a signature of the JSON document; it is not a “detached signature” with independent blobs containing
the JSON document and a cryptographic signature).
Currently the only defined cryptographic signature format is an OpenPGP signature (RFC 4880), but others
may be added in the future. (The blob does not contain metadata identifying the cryptographic signature
format. It is expected that most formats are sufficiently self-describing that this is not necessary and
the configured expected public key provides another indication of the expected cryptographic signature
format. Such metadata may be added in the future for newly added cryptographic signature formats, if
necessary.)
Consumers of container signatures SHOULD verify the cryptographic signature against one or more trusted
public keys (e.g. defined in a policy.json signature verification policy file
⟨containers-policy.json.5.md⟩) before parsing or processing the JSON payload in any way, in particular
they SHOULD stop processing the container signature if the cryptographic signature verification fails,
without even starting to process the JSON payload.
(Consumers MAY extract identification of the signing key and other metadata from the cryptographic
signature, and the JSON payload, without verifying the signature, if the purpose is to allow managing the
signature blobs, e.g. to list the authors and image identities of signatures associated with a single
container image; if so, they SHOULD design the output of such processing to minimize the risk of users
considering the output trusted or in any way usable for making policy decisions about the image.)
OpenPGP signature verification
When verifying a cryptographic signature in the OpenPGP format, the consumer MUST verify at least the
following aspects of the signature (like the github.com/containers/image/signature package does):
• The blob MUST be a “Signed Message” as defined RFC 4880 section 11.3. (e.g. it MUST NOT be an
unsigned “Literal Message”, a “Cleartext Signature” as defined in RFC 4880 section 7, or any
other non-signature format).
• The signature MUST have been made by an expected key trusted for the purpose (and the specific
container image).
• The signature MUST be correctly formed and pass the cryptographic validation.
• The signature MUST correctly authenticate the included JSON payload (in particular, the parsing
of the JSON payload MUST NOT start before the complete payload has been cryptographically
authenticated).
• The signature MUST NOT be expired.
The consumer SHOULD have tests for its verification code which verify that signatures failing any of the
above are rejected.
JSON processing and forward compatibility
The payload of the cryptographic signature is a JSON document (RFC 7159). Consumers SHOULD parse it very
strictly, refusing any signature which violates the expected format (e.g. missing members, incorrect
member types) or can be interpreted ambiguously (e.g. a duplicated member in a JSON object).
Any violations of the JSON format or of other requirements in this document MAY be accepted if the JSON
document can be recognized to have been created by a known-incorrect implementation (see
⟨#optionalcreator⟩ below) and if the semantics of the invalid document, as created by such an
implementation, is clear.
The top-level value of the JSON document MUST be a JSON object with exactly two members, critical and
optional, each a JSON object.
The critical object MUST contain a type member identifying the document as a container signature (as
defined below ⟨#criticaltype⟩) and signature consumers MUST reject signatures which do not have this
member or in which this member does not have the expected value.
To ensure forward compatibility (allowing older signature consumers to correctly accept or reject
signatures created at a later date, with possible extensions to this format), consumers MUST reject the
signature if the critical object, or any of its subobjects, contain any member or data value which is
unrecognized, unsupported, invalid, or in any other way unexpected. At a minimum, this includes
unrecognized members in a JSON object, or incorrect types of expected members.
For the same reason, consumers SHOULD accept any members with unrecognized names in the optional object,
and MAY accept signatures where the object member is recognized but unsupported, or the value of the
member is unsupported. Consumers still SHOULD reject signatures where a member of an optional object is
supported but the value is recognized as invalid.
JSON data format
An example of the full format follows, with detailed description below. To reiterate, consumers of the
signature SHOULD perform successful cryptographic verification, and MUST reject unexpected data in the
critical object, or in the top-level object, as described above.
{
"critical": {
"type": "atomic container signature",
"image": {
"docker-manifest-digest": "sha256:817a12c32a39bbe394944ba49de563e085f1d3c5266eb8e9723256bc4448680e"
},
"identity": {
"docker-reference": "docker.io/library/busybox:latest"
}
},
"optional": {
"creator": "some software package v1.0.1-35",
"timestamp": 1483228800,
}
}
critical
This MUST be a JSON object which contains data critical to correctly evaluating the validity of a
signature.
Consumers MUST reject any signature where the critical object contains any unrecognized, unsupported,
invalid or in any other way unexpected member or data.
critical.type
This MUST be a string with a string value exactly equal to atomic container signature (three words,
including the spaces).
Signature consumers MUST reject signatures which do not have this member or this member does not have
exactly the expected value.
(The consumers MAY support signatures with a different value of the type member, if any is defined in the
future; if so, the rest of the JSON document is interpreted according to rules defining that value of
critical.type, not by this document.)
critical.image
This MUST be a JSON object which identifies the container image this signature applies to.
Consumers MUST reject any signature where the critical.image object contains any unrecognized,
unsupported, invalid or in any other way unexpected member or data.
(Currently only the docker-manifest-digest way of identifying a container image is defined; alternatives
to this may be defined in the future, but existing consumers are required to reject signatures which use
formats they do not support.)
critical.image.docker-manifest-digest
This MUST be a JSON string, in the github.com/opencontainers/go-digest.Digest string format.
The value of this member MUST match the manifest of the signed container image, as implemented in the
docker/distribution manifest addressing system.
The consumer of the signature SHOULD verify the manifest digest against a fully verified signature before
processing the contents of the image manifest in any other way (e.g. parsing the manifest further or
downloading layers of the image).
Implementation notes: * A single container image manifest may have several valid manifest digest values,
using different algorithms. * For “signed” docker/distribution schema 1
⟨https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-1.md⟩ manifests, the manifest
digest applies to the payload of the JSON web signature, not to the raw manifest blob.
critical.identity
This MUST be a JSON object which identifies the claimed identity of the image (usually the purpose of the
image, or the application, along with a version information), as asserted by the author of the signature.
Consumers MUST reject any signature where the critical.identity object contains any unrecognized,
unsupported, invalid or in any other way unexpected member or data.
(Currently only the docker-reference way of claiming an image identity/purpose is defined; alternatives
to this may be defined in the future, but existing consumers are required to reject signatures which use
formats they do not support.)
critical.identity.docker-reference
This MUST be a JSON string, in the github.com/docker/distribution/reference string format, and using the
same normalization semantics (where e.g. busybox:latest is equivalent to
docker.io/library/busybox:latest). If the normalization semantics allows multiple string representations
of the claimed identity with equivalent meaning, the critical.identity.docker-reference member SHOULD use
the fully explicit form (including the full host name and namespaces).
The value of this member MUST match the image identity/purpose expected by the consumer of the image
signature and the image (again, accounting for the docker/distribution/reference normalization
semantics).
In the most common case, this means that the critical.identity.docker-reference value must be equal to
the docker/distribution reference used to refer to or download the image. However, depending on the
specific application, users or system administrators may accept less specific matches (e.g. ignoring the
tag value in the signature when pulling the :latest tag or when referencing an image by digest), or they
may require critical.identity.docker-reference values with a completely different namespace to the
reference used to refer to/download the image (e.g. requiring a critical.identity.docker-reference value
which identifies the image as coming from a supplier when fetching it from a company-internal mirror of
approved images). The software performing this verification SHOULD allow the users to define such a
policy using the policy.json signature verification policy file format ⟨containers-policy.json.5.md⟩.
The critical.identity.docker-reference value SHOULD contain either a tag or digest; in most cases, it
SHOULD use a tag rather than a digest. (See also the default ⟨containers-policy.json.5.md#signedby⟩.)
optional
This MUST be a JSON object.
Consumers SHOULD accept any members with unrecognized names in the optional object, and MAY accept a
signature where the object member is recognized but unsupported, or the value of the member is valid but
unsupported. Consumers still SHOULD reject any signature where a member of an optional object is
supported but the value is recognized as invalid.
optional.creator
If present, this MUST be a JSON string, identifying the name and version of the software which has
created the signature (identifying the low-level software implementation; not the top-level caller).
The contents of this string is not defined in detail; however each implementation creating container
signatures:
• SHOULD define the contents to unambiguously define the software in practice (e.g. it SHOULD
contain the name of the software, not only the version number)
• SHOULD use a build and versioning process which ensures that the contents of this string (e.g.
an included version number) changes whenever the format or semantics of the generated signature
changes in any way; it SHOULD not be possible for two implementations which use a different
format or semantics to have the same optional.creator value
• SHOULD use a format which is reasonably easy to parse in software (perhaps using a regexp), and
which makes it easy enough to recognize a range of versions of a specific implementation (e.g.
the version of the implementation SHOULD NOT be only a git hash, because they don’t have an
easily defined ordering; the string should contain a version number, or at least a date of the
commit).
Consumers of container signatures MAY recognize specific values or sets of values of optional.creator
(perhaps augmented with optional.timestamp), and MAY change their processing of the signature based on
these values (usually to accommodate violations of this specification in past versions of the signing
software which cannot be fixed retroactively), as long as the semantics of the invalid document, as
created by such an implementation, is clear.
If consumers of signatures do change their behavior based on the optional.creator value, they SHOULD take
care that the way they process the signatures is not inconsistent with strictly validating signature
consumers. (I.e. it is acceptable for a consumer to accept a signature based on a specific
optional.creator value if other implementations would completely reject the signature, but it would be
very undesirable for the two kinds of implementations to accept the signature in different and
inconsistent situations.)
optional.timestamp
If present, this MUST be a JSON number, which is representable as a 64-bit integer, and identifies the
time when the signature was created as the number of seconds since the UNIX epoch (Jan 1 1970 00:00 UTC).
signature Container container-signature(5)