...

Text file src/github.com/sigstore/cosign/v2/specs/SIGNATURE_SPEC.md

Documentation: github.com/sigstore/cosign/v2/specs

     1# Cosign Signature Specifications
     2
     3This document aims to describe how `cosign` signs containers.
     4The goal is to specify the behavior well enough to promote other implementations and enable interoperability.
     5Container signatures generated with `cosign` should be verifiable in other tools, and vice-versa.
     6
     7This document is broken up into a few parts:
     8* [Properties](#properties) details the individual components that are used to create and verify signatures.
     9* [Storage](#storage) details how signatures are stored and discovered in an OCI registry.
    10* [Payload](#payload) details the format of to-be-signed payloads.
    11* [Signature](#signature) details the signature schemes supported.
    12
    13## Properties
    14
    15This section describes the REQUIRED and OPTIONAL properties used to sign and verify an image.
    16Their layout in an OCI object is described below.
    17
    18* `payload` bytes
    19
    20  This REQUIRED property contains the contents of signed data in byte-form.
    21  Because signatures are __detached__, the payload MUST contain the digest of the image it references, in a well-known location.
    22  This location is dependent on the [payload format](#payloads).
    23
    24* `mediaType` string
    25
    26  This REQUIRED property contains the media type of the payload.
    27
    28* `signature` string
    29
    30  This REQUIRED property contains the base64-encoded signature.
    31  This signature MUST be generated by a supported scheme.
    32  For more details on supported schemes, see the [`Signature`](#signature) section below.
    33
    34  Example `signature`:
    35    `MEYCIQDXmXWj59naoPFlLnCADIPLKgLG3LyFtKrbjpnkYiGNGgIhAJ/eNx5zr/l1MJKSFpFMjPKKr4fjh5RHEtT2DhMamZuT`
    36
    37* `certificate` string
    38
    39  This OPTIONAL property contains a [PEM-encoded](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail) x509 certificate.
    40  If present, this certificate MUST embed the public key that can be used to verify the signature.
    41
    42  Example `certificate`:
    43
    44```
    45-----BEGIN CERTIFICATE-----
    46MIICrjCCAjSgAwIBAgIUAM4mURWUSkg06fmHmFfTmerYKaUwCgYIKoZIzj0EAwMw
    47KjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y
    48MTA0MDExNTU5MDZaFw0yMTA0MDExNjE4NTlaMDoxGzAZBgNVBAoMEmRsb3JlbmNA
    49Z29vZ2xlLmNvbTEbMBkGA1UEAwwSZGxvcmVuY0Bnb29nbGUuY29tMFkwEwYHKoZI
    50zj0CAQYIKoZIzj0DAQcDQgAE3R0ZtpfBd3Y8DaXuB1gM8JPlhsDIEfXO/WsMJEN1
    514hEn8wajX2HklqL7igZPFICv6tBUGylIHp2mTH2Nhv38mqOCASYwggEiMA4GA1Ud
    52DwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAMBgNVHRMBAf8EAjAAMB0G
    53A1UdDgQWBBTy3UWIop0bNrdNgSrVHHD10qSASTAfBgNVHSMEGDAWgBTIxR0AQZok
    54KTJRJOsNrkrtSgbT7DCBjQYIKwYBBQUHAQEEgYAwfjB8BggrBgEFBQcwAoZwaHR0
    55cDovL3ByaXZhdGVjYS1jb250ZW50LTYwM2ZlN2U3LTAwMDAtMjIyNy1iZjc1LWY0
    56ZjVlODBkMjk1NC5zdG9yYWdlLmdvb2dsZWFwaXMuY29tL2NhMzZhMWU5NjI0MmI5
    57ZmNiMTQ2L2NhLmNydDAdBgNVHREEFjAUgRJkbG9yZW5jQGdvb2dsZS5jb20wCgYI
    58KoZIzj0EAwMDaAAwZQIwC15Gtd9F6W9lmJuoXMym9DfWlBpK5HEPak38WPXqowRp
    596p+2/3jSLkFT5Nn5fuISAjEAouVlX4zH2rlkfg45HnDJax7o6ZV+E0/6BdAms44D
    60Ej6T/GLK6XJSB28haSPRWB7k
    61-----END CERTIFICATE-----
    62```
    63
    64* `chain` string
    65  This OPTIONAL property contains a PEM-encoded, DER-formatted, ASN.1 x509 certificate chain.
    66  The `certificate` property MUST be present if this property is present.
    67  This chain MAY be used by implementations to verify the `certificate` property.
    68  Clients MUST validate that any certificates in the chain that are self-signed
    69  or are expected to be trust anchors with an out-of-band mechanism.
    70
    71  Example `chain`:
    72
    73```
    74----BEGIN CERTIFICATE-----
    75MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq
    76MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx
    77MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu
    78ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy
    79A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas
    80taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm
    81MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
    82FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u
    83Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx
    84Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup
    85Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
    86-----END CERTIFICATE-----
    87-----BEGIN CERTIFICATE-----
    88MIICVTCCAT2gAwIBAgIQAUrAOaxMcCVQ6AwcDagmRzANBgkqhkiG9w0BAQsFADAh
    89MR8wHQYDVQQDDBZZdWJpY28gUElWIEF0dGVzdGF0aW9uMCAXDTE2MDMxNDAwMDAw
    90MFoYDzIwNTIwNDE3MDAwMDAwWjAlMSMwIQYDVQQDDBpZdWJpS2V5IFBJViBBdHRl
    91c3RhdGlvbiA5YzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFfnSOVAZLOTOYRs
    92n4BeD3cMYHFvtwBsK8X0yJ21NKUwJ3fvnqdq0qGeIT92zstNLEWCqP3qMkhs9sh4
    93wP1tHTGjTjBMMBEGCisGAQQBgsQKAwMEAwUCBjAUBgorBgEEAYLECgMHBAYCBADH
    94kP4wEAYKKwYBBAGCxAoDCAQCAwIwDwYKKwYBBAGCxAoDCQQBAzANBgkqhkiG9w0B
    95AQsFAAOCAQEAVRtRFpmgFD+rQqBG92HArMQ+j1FMX23QL9Z76IhaSElmN6cjgsv3
    968pJM8GL+ih6vVyCHeU6GoE9Bgj2XB02ZgkmWihnaJX2WG4VOm2dN3SqDmWFp4KLJ
    97vuzVXEHWuGevwMAOsvMkmXP8HI2npaCPBmprirExbv6bxSyng4ZNHmgdzqmjYyt+
    98d+ELe3xEeYYqQYx+IswHPRE5mGk/PO4hysk79mhwRNuvmygDbI8Emwvp3Pgzlgr1
    99Gyp4apdU7AXEwysEQIb034aPrTlpmxh90SnTZFs2DHOvCjCPPAmoWfuQUwPhSPRb
   10092pXqODWYqpW8+IRED5e42Ncu9XtDgS5Pw==
   101-----END CERTIFICATE-----
   102```
   103
   104* `bundle` string
   105
   106  This OPTIONAL property contains a JSON formatted `bundle` type, which can be used for offline verification.
   107  Example `bundle`:
   108
   109```json
   110{
   111  "SignedEntryTimestamp": "MEUCIQDHiGUesxPpn+qRONLmKlNIVPhl9gBMnwNeIQmRkRmZVQIgRxPpuYQDZR/8lYKcEfiQn5b+7VDoJIC72ZWHO9ZCp1A=",
   112  "Payload": {
   113    "body": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJzcGVjIjp7ImRhdGEiOnsiaGFzaCI6eyJhbGdvcml0aG0iOiJzaGEyNTYiLCJ2YWx1ZSI6ImE0NDkyYjBlYWJkZDIzMTJmMDYzMjkwYWJkNzk3ZDlkNzFhM2FiMjhiZDY1YTJjMTg5YjBkZjBkMzliOGMzYjkifX0sInNpZ25hdHVyZSI6eyJjb250ZW50IjoiTUVRQ0lDTmRYeTNiWHAxRE1PTDZOUGZYMzVnSjI3YnpsZHdTdkNBTnd5ZE9RVWlqQWlCQWg5WlJwQ3AzYlg5eE9UbEhTR2w0cFVGd0ZtUFJJWGZpY09pRTBHM1Vzdz09IiwiZm9ybWF0IjoieDUwOSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTmxla05EUVdkRFowRjNTVUpCWjBsVVZISk9aa013YkZSSmRWSXZWR0UyWm14MWFtdFFOWHBaTDFSQlMwSm5aM0ZvYTJwUFVGRlJSRUY2UVhFS1RWSlZkMFYzV1VSV1VWRkxSWGQ0ZW1GWFpIcGtSemw1V2xNMWExcFlXWGhGVkVGUVFtZE9Wa0pCVFZSRFNFNXdXak5PTUdJelNteE5RalJZUkZSSmVBcE5SRmw1VFdwSmVFMUVaM2RPUm05WVJGUkplRTFFV1hsTmFrbDRUV3BuZDAweGIzZEJSRUphVFVKTlIwSjVjVWRUVFRRNVFXZEZSME5EY1VkVFRUUTVDa0YzUlVoQk1FbEJRazFGV1M4ck4yRktjRmRLVFhjNWVrTmljMDFrT0hOQlRUTmxSbk5OTjBSbFpFZGlXRzlNUjJ4YUwyZHBNR2h5WTBaU1NWVTRiM2NLUzBKeU1ISkVTRE5QVkZaSWJVdFVZMkV2SzIweGQxQjNTVzlZTTFGUVYycG5aMFYwVFVsSlFrdFVRVTlDWjA1V1NGRTRRa0ZtT0VWQ1FVMURRalJCZHdwRmQxbEVWbEl3YkVKQmQzZERaMWxKUzNkWlFrSlJWVWhCZDAxM1JFRlpSRlpTTUZSQlVVZ3ZRa0ZKZDBGRVFXUkNaMDVXU0ZFMFJVWm5VVlZ5WVRoTENuSnJaMjAzVGtsNFRrNXBVMkpZVG00eFdFVkxhRzFyZDBoM1dVUldVakJxUWtKbmQwWnZRVlY1VFZWa1FVVkhZVXBEYTNsVlUxUnlSR0UxU3pkVmIwY0tNQ3QzZDJkWk1FZERRM05IUVZGVlJrSjNSVUpDU1VkQlRVZzBkMlpCV1VsTGQxbENRbEZWU0UxQlMwZGpSMmd3WkVoQk5reDVPWGRqYld3eVdWaFNiQXBaTWtWMFdUSTVkV1JIVm5Wa1F6QXlUVVJPYlZwVVpHeE9lVEIzVFVSQmQweFVTWGxOYW1OMFdXMVpNMDVUTVcxT1Ixa3hXbFJuZDFwRVNUVk9WRkYxQ21NelVuWmpiVVp1V2xNMWJtSXlPVzVpUjFab1kwZHNla3h0VG5aaVV6bHFXVlJOTWxsVVJteFBWRmw1VGtSS2FVOVhXbXBaYWtVd1RtazVhbGxUTldvS1kyNVJkMHBCV1VSV1VqQlNRVkZJTDBKQ2IzZEhTVVZYWTBoS2NHVlhSak5aVjFKdlpESkdRVm95T1haYU1uaHNURzFPZG1KVVFVdENaMmR4YUd0cVR3cFFVVkZFUVhkT2NFRkVRbTFCYWtWQk1UQlVSR015Wm1oUFZrRlVNWFJzZFM4MmMzWnhSbEZ1YkRaWU9YZGhNbXRUU2t0RGJqUkZZbFJFYTNwYVJYb3lDblppUWtwb2FFZ3ZjbWRXUjFKMU5tWkJha1ZCYkhsb05uUmhZelJZVFRaS2IzVlZlRWtyTjFnelFtUTFXVXR5WlRGS1dFOWhia0ZaYW1adldHNTVUSFFLZDNCSVFWb3paVzFhY0VWa00yeHFTVEF3Vm04S0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX0sImtpbmQiOiJyZWtvcmQifQ==",
   114    "integratedTime": 1624396085,
   115    "logIndex": 5179,
   116    "logID": "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"
   117  }
   118}
   119```
   120
   121  The following are REQUIRED properties of the bundle:
   122
   123  - The `SignedEntryTimestamp` is a rekor-signed signature over the logIndex, body and integratedTime of the Rekor Log Entry
   124  - The `Payload` consists of all fields required to verify the SET:
   125    - The `body` is the body of the Rekor Log Entry
   126    - The `integratedTime` is the UNIX timestamp the log entry was integrated into the transparency log
   127    - The `logIndex` is the index of the log entry in the transparency log
   128    - The `logID` is the SHA256 hash of the DER-encoded public key for the log at the time the entry was included in the log
   129
   130For instructions on using the `bundle` for verification, see [USAGE.md](../USAGE.md#verify-a-signature-was-added-to-the-transparency-log).
   131
   132* `rfc3161timestamp` string
   133
   134  This OPTIONAL property contains a JSON formatted `RFC3161Timestamp` containing the timestamp response from a
   135  timestamp authority.
   136
   137## Storage
   138
   139`cosign` image signatures are stored in an OCI registry and are designed to make use of the existing specifications.
   140The full specifications for the OCI formats and specifications used are available [here](https://github.com/opencontainers).
   141
   142### Discovery
   143
   144Signature object are placed in specific location in an OCI registry to enable consistent, interoperable discovery.
   145
   146Multiple discovery mechanisms MAY be used.
   147Implementations MUST support at least the following mechanisms:
   148
   149* Tag-based Discovery
   150
   151#### Tag-based Discovery
   152
   153In this scheme, signatures are stored in an OCI registry in a predictable location, addressable by tag.
   154The location of signatures corresponding to a specific object can be computed using the digest of the object.
   155
   156If the object is referenced by tag, the tag must first be resolved to a digest.
   157Then the digest of the object (of the form `sha256:abcdef...`) is encoded into a tag name using the following rules:
   158
   159* Replace the `:` character with a `-`
   160* Append the `.sig` suffix
   161
   162Example digest->tag mapping:
   163
   1641. Start with `gcr.io/dlorenc-vmtest2/demo:latest`
   1652. Resolve this to a digest: `sha256:97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36`
   1663. Follow the encoding rules: `sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig`
   1674. Signature can be found at `gcr.io/dlorenc-vmtest2/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig`
   168
   169Implementations MAY store signatures objects in the same OCI repository as the target image or a different one.
   170
   171### Object Types
   172
   173This section describes the way the properties from above are embedded into OCI objects that can be stored in a registry.
   174Implementations MUST support storing signatures in at least the following object types:
   175
   176* [OCI Image Manifest V1](#oci-image-manifest-v1)
   177
   178#### OCI Image Manifest V1
   179
   180This section describes the way the mandatory and optional signature properties are embedded into an
   181[OCI Image Manifest V1](https://github.com/opencontainers/image-spec/blob/master/manifest.md) object.
   182
   183Only one image manifest is created for every signed object.
   184Multiple signatures can be embedded in one image manifest.
   185
   186##### Payload and mediaType
   187
   188The `payload` bytes are uploaded to an OCI registry as a `blob`, and are referenced by `digest`, `size` and `mediaType.`
   189The digest is embedded into the `Image` manifest as a `layer`, via a [`Descriptor`](https://github.com/opencontainers/image-spec/blob/master/descriptor.md).
   190
   191The `mediaType` property for the `payload` is included in the same descriptor.
   192
   193Example `payload`:
   194
   195```json
   196{
   197  "schemaVersion": 2,
   198  "config": {
   199    "mediaType": "application/vnd.oci.image.config.v1+json",
   200    <omitted for brevity>
   201  },
   202  "layers": [
   203    {
   204      "mediaType": "application/vnd.dev.cosign.simplesigning.v1+json",
   205      "size": 210,
   206      "digest": "sha256:1119abab63e605dcc281019bad0424744178b6f61ba57378701fe7391994c999",
   207    },
   208    <other layers here>
   209  ]
   210}
   211```
   212
   213##### Signature
   214
   215The `signature` is base64-encoded and stored as an `annotation` on the layer, in the same descriptor.
   216The `annotation` key is `dev.cosignproject.cosign/signature`.
   217
   218Example `signature`:
   219
   220```json
   221"annotations": {
   222    "dev.cosignproject.cosign/signature": "MEUCIBKI9FIC+YD3m/lWViyPxsJsbnIHj86sSbb7L3qvpEFoAiEA2ZChO/67CuAPQKJLBVsAc7bs9hBK8RpsdfjBsByGKJM="
   223}
   224```
   225
   226##### Certificate
   227
   228The `certificate` is stored as an `annotation` on the layer, in the same descriptor.
   229The `annotation` key is `dev.cosignproject.cosign/certificate`.
   230
   231Example `certificate`:
   232
   233```json
   234"annotations": {
   235     "dev.sigstore.cosign/certificate": "-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIUAM4mURWUSkg06fmHmFfTmerYKaUwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTA0MDExNTU5MDZaFw0yMTA0MDExNjE4NTlaMDoxGzAZBgNVBAoMEmRsb3JlbmNA\nZ29vZ2xlLmNvbTEbMBkGA1UEAwwSZGxvcmVuY0Bnb29nbGUuY29tMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAE3R0ZtpfBd3Y8DaXuB1gM8JPlhsDIEfXO/WsMJEN1\n4hEn8wajX2HklqL7igZPFICv6tBUGylIHp2mTH2Nhv38mqOCASYwggEiMA4GA1Ud\nDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAMBgNVHRMBAf8EAjAAMB0G\nA1UdDgQWBBTy3UWIop0bNrdNgSrVHHD10qSASTAfBgNVHSMEGDAWgBTIxR0AQZok\nKTJRJOsNrkrtSgbT7DCBjQYIKwYBBQUHAQEEgYAwfjB8BggrBgEFBQcwAoZwaHR0\ncDovL3ByaXZhdGVjYS1jb250ZW50LTYwM2ZlN2U3LTAwMDAtMjIyNy1iZjc1LWY0\nZjVlODBkMjk1NC5zdG9yYWdlLmdvb2dsZWFwaXMuY29tL2NhMzZhMWU5NjI0MmI5\nZmNiMTQ2L2NhLmNydDAdBgNVHREEFjAUgRJkbG9yZW5jQGdvb2dsZS5jb20wCgYI\nKoZIzj0EAwMDaAAwZQIwC15Gtd9F6W9lmJuoXMym9DfWlBpK5HEPak38WPXqowRp\n6p+2/3jSLkFT5Nn5fuISAjEAouVlX4zH2rlkfg45HnDJax7o6ZV+E0/6BdAms44D\nEj6T/GLK6XJSB28haSPRWB7k\n-----END CERTIFICATE-----\n",
   236}
   237```
   238
   239##### Chain
   240
   241The `chain` is stored as an `annotation` on the layer, in the same descriptor.
   242The `annotation` key is `dev.cosignproject.cosign/chain`.
   243
   244Example `chain`:
   245
   246```json
   247"annotations": {
   248      "dev.sigstore.cosign/chain": "-----BEGIN CERTIFICATE-----\nMIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq\nMRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx\nMDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu\nZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy\nA7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas\ntaRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm\nMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE\nFMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u\nSu1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx\nVe/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup\nHr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==\n-----END CERTIFICATE-----"
   249}
   250```
   251
   252## Payloads
   253
   254Implementations MUST support at least the following payload types:
   255
   256  * Simple Signing
   257
   258### Simple Signing
   259
   260The Simple Signing payload format is [specified here](https://github.com/containers/image/blob/a5061e5a5f00333ea3a92e7103effd11c6e2f51d/docs/containers-signature.5.md#json-data-format)
   261
   262The following additional semantics are applied:
   263
   264* The `mediaType` used to identify this payload format is: `application/vnd.dev.cosign.simplesigning.v1+json`.
   265* The `critical.type` value used to identify `cosign` signatures is: `cosign container image signature`.
   266* The `critical.identity.docker-reference` field is ignored.
   267* Optional user-specified claims may be included in the `Optional` section.
   268
   269For example:
   270```json
   271{
   272    "critical": {
   273           "identity": {
   274               "docker-reference": "testing/manifest"
   275           },
   276           "image": {
   277               "Docker-manifest-digest": "sha256:20be...fe55"
   278           },
   279           "type": "cosign container image signature"
   280    },
   281    "optional": {
   282           "creator": "atomic",
   283           "timestamp": 1458239713
   284    }
   285}
   286```
   287
   288## Signature Schemes
   289
   290Implementations must support at least the following schemes:
   291
   292* ECDSA-P256
   293
   294No information about the signature scheme is included in the object.
   295Clients must determine the signature scheme out-of-band during the verification process.
   296
   297### Hashing Algorithms
   298
   299Signers and verifiers must know the hash algorithm used in addition to the signature scheme.
   300In an attempt to avoid specifying a particular hashing algorithm, we require that digest be calculated using the SAME algorithm as the OCI registry.
   301In practice, this means [sha256](https://github.com/opencontainers/image-spec/blob/master/descriptor.md#digests).
   302
   303When the payload is stored as a `blob` in the OCI registry, it is exposed and referenced via a [Content Addressable](https://en.wikipedia.org/wiki/Content-addressable_storage) API.
   304
   305Example referenced payload:
   306
   307```json
   308{
   309  "mediaType": "application/vnd.dev.cosign.simplesigning.v1+json",
   310  "size": 210,
   311  "digest": "sha256:1119abab63e605dcc281019bad0424744178b6f61ba57378701fe7391994c999",
   312}
   313```
   314
   315Here, `1119abab63e605dcc281019bad0424744178b6f61ba57378701fe7391994c999` is the hex-encoded digest, and the `sha256:` prefix specifies the algorithm.
   316This value is already calculated and verified by both the registry and client-tooling.
   317
   318This means that our signatures is "linked" to a "container image" happens via two hops:
   319
   320`Sign(sha256(SimpleSigningPayload(sha256(Image Manifest))))`
   321
   322Allowing flexibility in hashing algorithms of the digital signature would only allow manipulation of the "outer" one - the image manifest
   323itself is always referenced by `sha256` today.
   324This means using a different hashing algorithm as part of the final signature, even one perceived as "stronger", would result in limited cryptographic benefits.
   325
   326Put simply: implementations MUST use the same hash algorithm used by the underlying registry to reference the payload.
   327Any future algorithmic-agility will come from the storage layer as part of the OCI specification.
   328
   329# Rationales and Commentary
   330
   331This document, while labeled a `Specification`, aims to specify as few things as possible.
   332Instead, we prescribe the usage of other specifications.
   333
   334This section contains a rationale for each choice, as well as comparisons to alternatives considered.
   335
   336## Payload/Attestation Format: Simple Signing
   337
   338We chose Simple Signing because it has the most existing usage and meets our requirements:
   339
   340* Critical/Optional sections
   341* Extensible with more attestations
   342* Cross-language serialization support
   343
   344### Alternatives
   345
   346* OCI Descriptor.
   347
   348  This has the fields we need, with a few problems.
   349  * The annotations section is limiting with map[string]string.
   350  * The `URLs` field is not meant for this use-case.
   351  * No real benefit, since it's stored as a `blob` (not parsed by the registry).
   352
   353* Plain digest
   354
   355  This doesn't have any attestation/annotation support.
   356
   357* Something new
   358
   359  See above, we've tried to avoid making any new types where possible.
   360
   361## OCI Type - Docker Manifest/OCI Manifest
   362
   363We're currently using Docker but will switch to OCI.
   364The format support across registries is a toss-up, but likely to improve for OCI.
   365OCI supports custom media-types and has other "correctness" benefits.
   366
   367## Discovery - Tag Based
   368
   369We use the tag based mechanism because it's the only option we can think of.
   370It meets the two hard requirements: works **everywhere** today and requires no extra services.
   371It also does not mutate the signed object (like an attached signature or index might).
   372
   373Support for multiple signatures works but is racy.
   374
   375### Alternatives Considered
   376
   377Notary v1/Grafeas both require another database.
   378A few other proprietary APIs exist, but they're not cross-registry.
   379
   380## Hash Algorithm - None!
   381
   382Most common signature schemes support customizable hash algorithms.
   383These are typically stored with the signature for convenience, presenting a possible attack/confusion vector.
   384
   385We decided to pin to the registry hash algorithm.
   386This removes an entire moving part without sacrificing agility.
   387
   388The registry/client-tooling already perform hash validation as part of the CAS.
   389While their spec does not completely pin to specific algorithm, SHA256 is ubiquitous in practice.
   390This means that our signed payload object references the actual image "target" by a sha-256 digest - the entire signature already relies on the strength of this algorithm.
   391
   392Trading off this perceived agility for the reduction in attack surface is a win.
   393
   394** Note **: This is only possible if we store the `payload` in a blob by itself.
   395Serializing the payload and signature together in something like a JWT for storage would mean the payload is no longer directly hashed into the CAS.
   396There is also a performance benefit: we can validate the signature (stored in the manifest) against the payload (stored as a blob) without fetching the blob, because the blob's digest is also present in the manifest.
   397
   398## Algorithms
   399
   400We only require ECDSA-P256 (with the SHA256 hash algorithm, see above), but will allow for other schemes.
   401We will bias toward algorithms well-supported in the Go ecosystem, but will accept others.
   402We will bias toward support for algorithms with wide industry adoption, API support, and hardware availability.
   403
   404## Compatibility
   405
   406We are compatible with the In-Toto [Metablock](https://in-toto.readthedocs.io/en/latest/model.html) and JWS [rfc7515](https://tools.ietf.org/html/rfc7515) formats.
   407This means we can convert to these formats during verification, and from these formats during upload/signature.
   408You can think of this spec as an "on-registry serialization format" for either of these specified formats.

View as plain text