# Notary v2 Signature Formats
###### tags: `notary`
Notary v2 can sign any content within an OCI Distribution based registry. This document provides an iterative collaboration on what the signature content would look like, when persisted as a referenceType to content within a registry:
## Target Image
For the purposes of this discussion, we'll focus on signing the Notary v2 prototypical `net-monitor:v1` image.
- **repository**: `net-monitor`
- **media type**: `application/vnd.oci.image.manifest.v1+json`
- **digest**: `sha256:9aab35483ad0ee2e56fc1cf8205d5b7ca2fe029dccfc70988eb067e6b2f38663`
- **size**: `809`
- **tag**: `:v1`
:::info
:information_source: **NOTE:** There is no change to the existing image-spec 1.0 format. This example highlights what already exists.
:::
```json
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:e752324f6804d5d0b2c098f84507d095a8fd0031cf06cdb3c7ad1625dcd1b399",
"size": 7097
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:83c5cfdaa5385ea6fc4d31e724fd4dc5d74de847a7bdd968555b8f2c558dac0e",
"size": 25851449
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:7445693bd43e8246a8c166233392b33143f7f5e396c480f74538e5738fb6bd6e",
"size": 226
}
],
"annotations": {
"org.wabbit-networks.important-stuff": "important value",
"org.wabbit-networks.more-important-stuff": "more important value"
}
}
```
## A Notary v2 artifact manifest of the `net-monitor:v1` signature
- **repository**: `net-monitor`
- **media type**: `application/vnd.oci.artifact.manifest.v1+json`
- **digest**: `sha256:218e9533924a24d64f2cc6c7db8e5120e415d441a7529919c8d30472341038e7`
- **size**: `720`
- **tag**: _-none-_
```json
{
"schemaVersion": 3,
"mediaType": "application/vnd.oci.artifact.manifest.v1+json",
"artifactType": "cncf.notary.v2-rc1",
"blobs": [
{
"mediaType": "application/tar",
"digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0",
"size": 32654
}
],
"subjectManifest": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:9aab35483ad0ee2e56fc1cf8205d5b7ca2fe029dccfc70988eb067e6b2f38663",
"size": 809,
"annotations": {
"org.acme-rockets.importDate": "2021-04-23T18:25:43.511Z"
}
},
"annotations": {
"org.cncf.notary.v2.signature.subject": "acme-rockets.io"
}
}
```
The above artifact manifest signs the `subjectManifest`. Any content within the above net-monitor image is secured with the content in the `blob`
Justin Cormack: What I think you're suggesting is the following annotation would become part of the signed content stored in the blob?
```json
"annotations": {
"org.acme-rockets.importDate": "2021-04-23T18:25:43.511Z"
}
```
## Signature Payload
```json
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"size": 809,
"digest": "sha256:9aab35483ad0ee2e56fc1cf8205d5b7ca2fe029dccfc70988eb067e6b2f38663",
"annotations": {
"notary.v2.identity": "acme-rockets.io/net-monitor:v1"
}
}
```
## Signature Examples
### JWS JSON Serialization
**Payload:** aka claims
```json
{
"notary.v2": {
"subjectManifest": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:9aab35483ad0ee2e56fc1cf8205d5b7ca2fe029dccfc70988eb067e6b2f38663",
"size": 809,
"annotations": {
"org.acme-rockets.importDate": "2021-04-23T18:25:43.511Z"
}
},
"signedAttrs": {
"reserved": {
"arl": "http://registry.wabbit.net/arl",
"identity": "acme-rockets.io/net-monitor:v1"
},
"custom" : {
"buildId": "0001",
"imageScanned": "true"
}
}
},
"iat": 1627880148,
"exp": 1627883748
}
```
Payload contain the subject manifest and other attributes that has to be integrity protected.
* `notary.v2`: Top level node and private claim, encapsulating the notary v2 data. This claim MUST be present.
* `subjectManifest`: The image manifest that needs to be integrity protected.
* `signedAttrs`: Contains additional attributes that needs to be integrity protected.
* `reserved`: Collection of attributes reserved for notary v2 use such as artifact revocation list(arl),identity, etc.
* `custom`: Collection of user defined attributes such as buildId, imageScanned, etc. Use of this field is OPTIONAL.
* `iat`: Issued at identifies the time at which the JWT was issued. This claim MUST be present.
* `exp`: Expiration time identifies the expiration time on or after which the JWT must not be accepted for processing. This claim MUST be present.
* In order to leverage JWS claims validation functionality already provided by libraries we have defined `iat`, `exp` as top-level nodes.
**ProtectedHeader:**
```json
{
"alg": "RS256",
"cty": "application/<TBD>",
"crit":["cty"]
}
```
* `alg`: JWS needs algorithm(alg) to be present in header so we have added it as protected header. This header MUST be present.
* `cty`: Content type(cty) used to declare the media type of the secured content(the payload). This header MUST be present.
* `crit`: Indicates the list of headers that implementation MUST understood and process. This header MUST be present.
**SignatureEnvelope:**
```json
{
"payload": "<Base64Url(Payload)>",
"protected": "<Base64Url(ProtectedHeader)>"
"header": {
"timestamp": "<Base64(TimeStampToken)>",
"kid": "906ade40b96cff95e5b60f7e96f2cda7979c8ad5",
"x5c": ["<Base64(DER(leafCert))>", "<Base64(DER(intermediateCACert))>", "<Base64(DER(rootCert))>"]
},
"signature": "Base64Url( sign( ASCII( <Base64Url(Payload)>.<Base64Url(ProtectedHeader)> )))"
}
```
* `protected`: Base64Url encoded JSON object that contains the header parameters that are integrity protected by the JWS Signature digital signature
* `header`: JOSE Header containing the parameters describing the cryptographic operations and parameters employed. header is not integrity protected by signature. To start with we will only support reserved set of headers.
* `timestamp`: Base64 encoded [timestamp token](https://datatracker.ietf.org/doc/html/rfc3161#section-2.4.2) generated by TSA. Use of this is OPTIONAL.
* `kid` Hint indicating which key was used to generate the signature. Use of this is OPTIONAL.
* `x5c` Contains the X.509 public key certificate or certificate chain corresponding to the key used to generate the signature. Use of this is OPTIONAL. If signature was generated by x509 certificate signature envelop MUST contain x5c.
* The `header` node MUST contain either `kid` or `x5c` but not both.
* In case of `x5c`, the leaf certificate's public key algorithm(with some additional conventions) will be used for signature generation and this algorithm must match with `alg` header value. The verifier will make sure that the value of `alg` header is same as that of leaf certificate's signing algorithm.
* Additional convention for algorithm: If the x509 certificate does not indicate the hash algorithm (as is the case of ECDSA), then the implementation will use hard-code a mapping similar to that of [JWS](https://datatracker.ietf.org/doc/html/rfc7518#section-3.1).
* Implementation should only support predefined set of asymmetric signing algorithms, which means value of `alg` will always be from a predefined set of values.
### Dead Simple Signature Envelop (DSSE)
:::warning
:construction: Working in progress...
:::
### Extended DSSE
**Payload:**
```json
{
"subjectManifest": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:9aab35483ad0ee2e56fc1cf8205d5b7ca2fe029dccfc70988eb067e6b2f38663",
"size": 809,
"annotations": {
"org.acme-rockets.importDate": "2021-04-23T18:25:43.511Z"
}
},
"signedAttrs": {
"reserved": {
"iat": "2021-06-22T16:02:40.3375379Z",
"exp": "2021-09-20T16:02:40.3375379Z",
"arl": "http://registry.wabbit.net/arl",
"identity": "acme-rockets.io/net-monitor:v1"
},
"custom" : {
"BuildId": "0001",
"imageScanned": "true"
}
}
}
```
**SignatureEnvelope:**
```json
{
"payload": "<Base64(Payload)>",
"payloadType": "application/<TBD>",
"signatures": [
{
"keyid": "906ade40b96cff95e5b60f7e96f2cda7979c8ad5",
"x5c": ["<Base64(DER(leafCert))>", "<Base64(DER(intermediateCACert))>", "<Base64(DER(rootCert))>"],
"timestamp": "<Base64(TimeStampToken)>",
"sig": "Base64( sign( <Base64(Payload)> ))"
}
]
}
```
In SignatureEnvelope's `signatures` node, MUST contain either keyid or x5c but not both. Also, currently DSSE doesn't support [timestamp](https://hackmd.io/0GKGd0-1QQirbe1yty5vPg?both) and [x5c](https://github.com/secure-systems-lab/dsse/issues/42) fields.
### Open Questions
1. In Payload do we need `subjectManifest#annotations`? We have already defined `signedAttrs#custom` collection for user defined attributes?
2. Should signature verification fail if signature envelop contains unsupported/additional fields?