COSE Sign1 Signature Envelope
May 16, 2025 ยท View on GitHub
This specification implements the Notary Project signature specification using CBOR Object Signing and Encryption (COSE). COSE (RFC8152) is a CBOR based envelope format for digital signatures over any type of payload (e.g. CBOR, JSON, binary). Notary Project specifically supports COSE_Sign1_Tagged as a signature envelope.
OCI Signature Storage
A COSE signature envelope will be stored in an OCI registry as a blob, and referenced in the signature manifest as a layer blob with mediaType of "application/cose".
Signature Manifest Examples
{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"artifactType": "application/vnd.cncf.notary.signature",
"config": {
"mediaType": "application/vnd.oci.empty.v1+json",
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"size": 2,
"data": "e30="
},
"layers": [
{
"mediaType": "application/cose",
"digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0",
"size": 32654
}
],
"subject": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333",
"size": 16724
},
"annotations": {
"io.cncf.notary.x509chain.thumbprint#S256":
"[\"B7A69A70992AE4F9FF103EBE04A2C3BA6C777E439253CE36562E6E98375068C3\",\"932EB6F5598435D4EF23F97B0B5ACB515FAE2B8D8FAC046AB813DDC419DD5E89\"]"
}
}
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"config": {
"mediaType": "application/vnd.cncf.notary.signature",
"size": 2,
"digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a"
},
"layers": [
{
"mediaType": "application/cose",
"digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0",
"size": 32654
}
],
"subject": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333",
"size": 16724
},
"annotations": {
"io.cncf.notary.x509chain.thumbprint#S256":
"[\"B7A69A70992AE4F9FF103EBE04A2C3BA6C777E439253CE36562E6E98375068C3\",\"932EB6F5598435D4EF23F97B0B5ACB515FAE2B8D8FAC046AB813DDC419DD5E89\"]"
}
}
Blob Signature Storage
For detached signatures associated with arbitrary blobs, a COSE signature envelope will be stored on the file system as a binary file with cose as the file extension.
COSE Payload
The COSE envelope contains the Notary Project signature Payload.
Example of the Notary Project OCI signature payload:
{
"targetArtifact": {
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333",
"size": 16724,
"annotations": {
"io.wabbit-networks.buildId": "123" // user defined metadata
}
}
}
Example of the Notary Project blob signature payload:
{
"targetArtifact": {
"mediaType": "application/octet-stream",
"digest": "sha256:2f3a23b6373afb134ddcd864be8e037e34a662d090d33ee849471ff73c873345",
"size": 1024,
"annotations": {
"io.wabbit-networks.buildId": "123" // user defined metadata
}
}
}
Protected Header
The COSE envelope for the Notary Project signature uses the following header parameters:
- Common parameters
- Label
1:alg - Label
2:crit - Label
3:content type
- Label
- Additional parameters with collision resistant names.
io.cncf.notary.signingSchemeio.cncf.notary.signingTimeio.cncf.notary.authenticSigningTimeio.cncf.notary.expiry
Example with Signing Scheme notary.x509
{
/ alg / 1: / PS384 / -38,
/ crit / 2: [
'io.cncf.notary.signingScheme',
'io.cncf.notary.expiry'
],
/ cty / 3: 'application/vnd.cncf.notary.payload.v1+json',
'io.cncf.notary.signingScheme': 'notary.x509',
'io.cncf.notary.signingTime': 1(1667411812),
'io.cncf.notary.expiry': 1(1667415412)
}
Example with Signing Scheme notary.x509.signingAuthority
{
/ alg / 1: / PS384 / -38,
/ crit / 2: [
'io.cncf.notary.signingScheme',
'io.cncf.notary.authenticSigningTime',
'io.cncf.notary.expiry'
],
/ cty / 3: 'application/vnd.cncf.notary.payload.v1+json',
'io.cncf.notary.signingScheme': 'notary.x509.signingAuthority',
'io.cncf.notary.authenticSigningTime': 1(1667411812),
'io.cncf.notary.expiry': 1(1667415412)
}
Note: The above examples are represented using the extended CBOR diagnostic notation.
alg(int): This REQUIRED parameter (label1) defines which signing algorithm was used to generate the signature. The signature algorithm of the signing key (first certificate inx5chain) is the source of truth, and during signing the value ofalgMUST be set corresponding to signature algorithm of the signing key using this mapping that lists the Notary Project signature allowed subset ofalgvalues supported by COSE. Similarly verifier of the signature MUST matchalgwith signature algorithm of the signing key to mitigate algorithm substitution attacks.crit(array of int/tstr): This REQUIRED parameter (label2) lists the header parameters that implementations MUST understand and process. It MUST only contain parameters apart from integer labels in the range of 0 to 8. This header MUST containio.cncf.notary.signingSchemewhich is a required critical header, and optionally containio.cncf.notary.authenticSigningTimeandio.cncf.notary.expiryif these critical headers are present in the signature.content type(tstr): The REQUIRED parameter content type (label3) is used to declare the media type of the secured content (the payload). The supported value isapplication/vnd.cncf.notary.payload.v1+json.io.cncf.notary.signingScheme(tstr, critical): This REQUIRED header specifies the Notary Project signing scheme used by the signature. Supported values arenotary.x509andnotary.x509.signingAuthority.io.cncf.notary.signingTime(date/time): This header specifies the time at which the signature was generated. This is an untrusted date/time, and therefore not used in trust decisions. Its value is an Epoch-Based Date/Time defined in RFC 8949. The optional fractional seconds SHOULD NOT be used. This claim is REQUIRED and only valid when signing scheme isnotary.x509.io.cncf.notary.authenticSigningTime(date/time, critical): This header specifies the authenticated time at which the signature was generated. Its value is an Epoch-Based Date/Time defined in RFC 8949. The optional fractional seconds SHOULD NOT be used. This claim is REQUIRED and only valid when signing scheme isnotary.x509.signingAuthority.io.cncf.notary.expiry(date/time, critical): This OPTIONAL header provides a "best by use" time for the artifact, as defined by the signer. Its value is an Epoch-Based Date/Time defined in RFC 8949. The optional fractional seconds SHOULD NOT be used.
Unprotected Headers
The Notary Project signature supports the following unprotected header parameters:
io.cncf.notary.timestampSignature- Label
33:x5chain io.cncf.notary.signingAgent
{
/ x5chain / 33: [
<< DER(leafCert) >>,
<< DER(intermediate CACert) >>,
<< DER(rootCert) >>
],
'io.cncf.notary.timestampSignature': << TimeStampToken >>,
'io.cncf.notary.signingAgent': 'notation/1.0.0'
}
Note: << and >> are used to notate the CBOR byte string resulting from encoding the data item.
x5chain(array of bstr): This REQUIRED parameter (label33by IANA) contains the ordered list of X.509 certificate or certificate chain (RFC5280) corresponding to the key used to digitally sign the COSE. The certificate chain is represented as an array of certificate, each certificate in the array is DER encoded and then wrapped in a CBOR byte string. The certificate containing the public key corresponding to the key used to digitally sign the COSE MUST be the first certificate, followed by the intermediate and root certificates in the correct order. Refer Certificate Chain unsigned attribute for more details. Optionally, this header can be presented in the protected header.io.cncf.notary.timestampSignature(bstr): This OPTIONAL header is used to store a countersignature that proves the signature was generated before the timestamp. Only RFC 3161 compliantTimeStampTokenare supported. If present, this header is validated and used solely under thenotary.x509signing scheme. Refer Timestamp Signature unsigned attribute for more details.io.cncf.notary.signingAgent(tstr): This OPTIONAL header provides the identifier of a client (e.g. Notation) that produced the signature. E.g.notation/1.0.0. Refer Signing Agent unsigned attribute for more details.
Signature
In COSE, signature is calculated by constructing the Sig_structure for COSE_Sign1.
The process is described below:
- Encode the protected header into a CBOR object as a byte string named
body_protected. - Construct the
Sig_structureforCOSE_Sign1. The fieldcontextis set toSignature1forCOSE_Sign1as specified by RFC9052.Sig_structure = [ / context / 'Signature1', / body_protected / << ProtectedHeaders >>, / external_aad / h'', / payload / << Payload >>, ] - Encode
Sig_structureinto a CBOR object as a byte string namedToBeSigned. - Compute the signature on the
ToBeSignedconstructed in the previous step by using the signature algorithm of the signing key, which MUST match the corresponding protected header elementalg. This is the value of the signature property used in the signature envelope.
Signature Envelope
The final signature envelope is a COSE_Sign1_Tagged object, consisting of Payload, ProtectedHeaders, UnprotectedHeaders, and Signature.
18(
[
/ protected / << {
/ alg / 1: / PS384 / -38,
/ crit / 2: [
'io.cncf.notary.signingScheme',
'io.cncf.notary.authenticSigningTime',
'io.cncf.notary.expiry'
],
/ cty / 3: 'application/vnd.cncf.notary.payload.v1+json',
'io.cncf.notary.signingScheme': 'notary.x509.signingAuthority',
'io.cncf.notary.authenticSigningTime': 1(1667411812),
'io.cncf.notary.expiry': 1(1667415412)
} >>,
/ unprotected / {
/ x5chain / 33: [
<< DER(leafCert) >>,
<< DER(intermediate CACert) >>,
<< DER(rootCert) >>
],
'io.cncf.notary.timestampSignature': << TimeStampToken >>,
'io.cncf.notary.signingAgent': 'notation/1.0.0'
},
/ payload / << descriptor >>,
/ signature / << sign( << Sig_structure >> ) >>
]
)
Implementation Constraints
Supported alg header values
Implementations of the Notary Project signature specification MUST enforce the following constraints on signature generation and verification:
algparameter value MUST NOT be a symmetric-key algorithm such asHMAC.algparameter value MUST be same as that of signature algorithm identified using signing certificate's public key algorithm and size.algparameter values for various signature algorithms is a subset of values supported by COSE.
Mapping of the Notary Project signature approved algorithms to COSE alg header parameter values
| Signature Algorithm | alg Label |
|---|---|
| RSASSA-PSS with SHA-256 | -37 |
| RSASSA-PSS with SHA-384 | -38 |
| RSASSA-PSS with SHA-512 | -39 |
| ECDSA on secp256r1 with SHA-256 | -7 |
| ECDSA on secp384r1 with SHA-384 | -35 |
| ECDSA on secp521r1 with SHA-512 | -36 |