diff --git a/MAINTAINERS b/MAINTAINERS index 7d477d5..ac2af2c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2,13 +2,13 @@ # Pattern: [First Name] [Last Name] <[Email Address]> ([GitHub Handle]) Justin Cormack (@justincormack) Niaz Khan (@niazfk) +Pritesh Bandi (@priteshbandi) +Shiwei Zhang (@shizhMSFT) Steve Lasker (@stevelasker) +Toddy Mladenov (@toddysm) # Repo-Level Maintainers (in alphabetical order) # Note: This is for the notaryproject/notaryproject repo Milind Gokarn (@gokarnm) -Pritesh Bandi (@priteshbandi) -Shiwei Zhang (@shizhMSFT) -Toddy Mladenov (@toddysm) Vani Rao (@vaninrao10) Yi Zha (@yizha1) diff --git a/media/blob-signature-specification.svg b/media/blob-signature-specification.svg new file mode 100644 index 0000000..bb10d12 --- /dev/null +++ b/media/blob-signature-specification.svg @@ -0,0 +1,4 @@ + + + +
Payload
(Blob Descriptor)
Payload...
Signed Attributes
Signed Attributes
Unsigned Attributes
Unsigned Attributes
Signature
Signature
my-blob.bin
my-blob.bin
my-blob.bin.sig.jws
my-blob.bin.sig.jws
(Signature Envelope)
(Signature Envelope)
File System
File System
my-blob.bin.sig.cose
my-blob.bin.sig.cose
(JWS Signature)
(JWS Signature)
(Blob)
(Blob)
(COSE Signature)
(COSE Signature)
Text is not SVG - cannot display
\ No newline at end of file diff --git a/media/signature-specification.svg b/media/oci-signature-specification.svg similarity index 100% rename from media/signature-specification.svg rename to media/oci-signature-specification.svg diff --git a/specs/signature-envelope-cose.md b/specs/signature-envelope-cose.md index b23ed9f..c126a43 100644 --- a/specs/signature-envelope-cose.md +++ b/specs/signature-envelope-cose.md @@ -4,7 +4,7 @@ This specification implements the [Notary Project signature specification](signa CBOR Object Signing and Encryption (COSE). COSE ([RFC8152](https://datatracker.ietf.org/doc/html/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](https://datatracker.ietf.org/doc/html/rfc8152#section-4.2) as a signature envelope. -## Storage +## 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"`. @@ -36,12 +36,15 @@ Signature Manifest Example } } ``` +## 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](./signature-specification.md#payload). -Example of the Notary Project signature payload: +Example of the Notary Project OCI signature payload: ```jsonc { @@ -56,6 +59,21 @@ Example of the Notary Project signature payload: } ``` +Example of the Notary Project blob signature payload: + +```jsonc +{ + "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: diff --git a/specs/signature-envelope-jws.md b/specs/signature-envelope-jws.md index 1965930..dfb8756 100644 --- a/specs/signature-envelope-jws.md +++ b/specs/signature-envelope-jws.md @@ -2,7 +2,7 @@ This specification implements the [Notary Project signature specification](./signature-specification.md) using JSON Web Signature (JWS). JWS ([RFC7515](https://datatracker.ietf.org/doc/html/rfc7515)) is a JSON based envelope format for digital signatures over any type of payload (e.g. JSON, binary). JWS is the Notary Project supported signature format and specifically uses the *JWS JSON Serialization* representation. -## Storage +## OCI Signature Storage A JWS signature envelope will be stored in an OCI registry as a layer, and referenced in the signature manifest as a layer blob with `mediaType` of `"application/jose+json"`. @@ -35,11 +35,15 @@ Signature Manifest Example } ``` +## Blob Signature Storage + +For detached signatures associated with blobs, a JWS signature envelope will be stored on the file system with `jws` as the file extension. + ## JWS Payload The JWS envelope contains the [Notary Project signature payload](./signature-specification.md#payload). -Example of the Notary Project signature payload +Example of the Notary Project OCI signature payload ```jsonc { @@ -54,6 +58,21 @@ Example of the Notary Project signature payload } ``` +Example of the Notary Project blob signature payload: + +```jsonc +{ + "targetArtifact": { + "mediaType": "application/octet-stream", + "digest": "sha256:2f3a23b6373afb134ddcd864be8e037e34a662d090d33ee849471ff73c873345", + "size": 1024, + "annotations": { + "io.wabbit-networks.buildId": "123" // user defined metadata + } + } +} +``` + ## Protected Headers The JWS envelope for the Notary Project signature uses following headers diff --git a/specs/signature-specification.md b/specs/signature-specification.md index 1b7d29c..ce06c66 100644 --- a/specs/signature-specification.md +++ b/specs/signature-specification.md @@ -2,75 +2,9 @@ This document provides the following details for Notary Project signature: -- **[Storage](#storage)**: Describes how signatures are stored and retrieved from an OCI registry. - **[Signature Envelope](#signature-envelope)**: Describes the structure of the Notary Project signature. - -## Storage - -This section describes how a Notary Project signature is stored in an OCI Distribution conformant registry. -OCI image manifest is used to store signatures in the registry, see [OCI image spec v1.1.0-rc3][oci-image-manifest] for details. -The signature manifest has a configuration media type that specifies it's a Notary Project signature, a subject referencing the manifest of the artifact being signed, a layer referencing the signature, and a collection of annotations. - -![Signature storage inside registry](../media/signature-specification.svg) - -Signature manifest example per OCI image manifest: - -```jsonc -{ - "schemaVersion": 2, - "mediaType": "application/vnd.oci.image.manifest.v1+json", - "config": { - "mediaType": "application/vnd.cncf.notary.signature", - "size": 2, - "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" - }, - "layers": [ - { - "mediaType": "application/jose+json", - "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\"]" - } -} -``` - -Besides the [image manifest property requirements][image-manifest-property-descriptions], the properties have the following additional restrictions: - -- **`mediaType`** (*string*): This REQUIRED property MUST be `application/vnd.oci.image.manifest.v1+json`. -- **`config`** (*descriptor*): This property is REQUIRED to be compatible with [OCI image specification][oci-image-manifest]. The Notary Project signature specification doesn't require any configuration for a signature, and the configuration content is not consumed by implementations of the Notary Project signature specification. - - **`mediaType`** (*string*): This REQUIRED property MUST be `application/vnd.cncf.notary.signature`. - - **`digest`** (*string*): This REQUIRED property is the digest of the config content. - - **`size`** (*int64*): This REQUIRED property specifies the size, in bytes, of the raw config content. -- **`layers`** (*array of objects*): This REQUIRED property contains collection of only one [OCI descriptor][oci-descriptor] referencing the signature envelope. - - **`mediaType`** (*string*): This REQUIRED property contains media type of signature envelope blob. Following values are supported - - `application/jose+json` - - `application/cose` -- **`subject`** (*descriptor*): A REQUIRED artifact descriptor referencing the signed manifest. -- **`annotations`** (*string-string map*): This REQUIRED property contains metadata for the image manifest. - It is being used to store information about the signature. - Keys using the `io.cncf.notary` namespace are reserved for use in the Notary Project signature specification and MUST NOT be used by other specifications. - - **`io.cncf.notary.x509chain.thumbprint#S256`**: A REQUIRED annotation whose value contains the list of SHA-256 fingerprints of signing certificate and certificate chain (including root) used for signature generation. The list of fingerprints is present as a JSON array string, corresponding to ordered certificates in [*Certificate Chain* unsigned attribute](#unsigned-attributes) in the signature envelope. The annotation name contains the hash algorithm as a suffix (`#S256`) and can be extended to support other hashing algorithms in future. - -### Signature Discovery - -The client should be able to discover all the signatures belonging to an artifact (such as image manifest) by using [OCI Distribution Referrers API][oci-distribution-referrers]. -OCI Distribution Referrers API returns a paginated list of all artifacts belonging to a target artifact (such as container images, SBoMs). -The implementation can filter Notary Project signatures by either using OCI Distribution Referrers API or using custom logic on the client. -Each Notary Project signature refers to a signature envelope blob. - -### Signature Filtering - -An OCI artifact can have multiple signatures, implementations of the Notary Project signature specification uses annotations of the signature manifest to filter relevant signatures based on the applicable trust policy. -The Notary Project signature manifest's `io.cncf.notary.x509chain.thumbprint#S256` annotation key MUST contain the list of SHA-256 fingerprints of certificate and certificate chain used for signing. +- **[OCI Signatures](#oci-signatures)**: Describes how signatures for OCI artifacts are stored and retrieved from an OCI registry. +- **[Blob Signatures](#blob-signatures)**: Describes how signatures for signed Blobs are stored on file system. ## Signature Envelope @@ -84,9 +18,9 @@ A signature envelope consists of the following components: A signature envelope is `e = {m, v, u, s}` where `s` is signature. -This specification defines the set of signed and unsigned attributes that make up a valid Notary Project signature. This specification aims to be be agnostic of signature envelope format (e.g. COSE, JWS), details of encoding the envelope in a specific signature envelope format are covered in in separate specs. +This specification defines the set of signed and unsigned attributes that make up a valid Notary Project signature. This specification aims to be agnostic of signature envelope format (e.g. COSE, JWS), details of encoding the envelope in a specific signature envelope format are covered in separate specs. -The Notary Project signature supports the following envelope formats: +The Notary Project signature supports following envelope formats: - [JWS](./signature-envelope-jws.md) - [COSE](./signature-envelope-cose.md) @@ -95,13 +29,26 @@ The Notary Project signature supports the following envelope formats: The Notary Project signature payload is a JSON document with media type `application/vnd.cncf.notary.payload.v1+json` and has following properties. -- `targetArtifact` : Required property whose value is the descriptor of the target artifact manifest that is being signed. Only [OCI descriptor][oci-descriptor] is supported. +- `targetArtifact` : Required property whose value is the descriptor of the target artifact manifest that is being signed. +- For OCI artifacts, this MUST be a valid [OCI descriptor][oci-descriptor]. - Descriptor MUST contain `mediaType`, `digest`, and `size` fields. - - Descriptor MAY contain `annotations` and if present it MUST follow the [annotation rules][annotation-rules]. The Notary Project signature uses annotations for storing both Notary Project specific and user defined metadata. The prefix `io.cncf.notary` in annotation keys is reserved for use in Notary Project signature and MUST NOT be used outside this specification. + - Descriptor MAY contain `annotations` and if present it MUST follow the [annotation rules][annotation-rules]. - Descriptor MAY contain `artifactType` field for the `config.mediaType` of OCI image manifests. +- For Blob artifacts, the descriptor MUST describe the blob that is being signed + - Descriptor MUST contain `mediaType`, `digest`, and `size` fields. + - `digest` MUST be in the format of `:`. Example: `sha256:2f3a23b6373afb134ddcd864be8e037e34a662d090d33ee849471ff73c873345` + - `digest algorithm` MUST be deduced from signing certificate's public key. See [Algorithm Selection](#algorithm-selection) + - `mediaType` can be any arbitrary media type that the user provides to describe the blob. An example can be `application/octet-stream` + - `size` MUST be the raw size of the blob in bytes. + - Blob descriptors MAY optionally contain `annotations` and if present it MUST follow the [annotation rules][annotation-rules]. + +NOTE: The Notary Project signature uses annotations for storing both Notary Project specific and user defined metadata. The prefix `io.cncf.notary` in `annotations` key is reserved for use in Notary Project signature and MUST NOT be used outside this specification. + #### Examples +##### OCI Payload + ```jsonc { "targetArtifact": { @@ -111,6 +58,7 @@ The Notary Project signature payload is a JSON document with media type `applica } } ``` +##### OCI Payload with artifactType and annotations ```jsonc { @@ -125,6 +73,31 @@ The Notary Project signature payload is a JSON document with media type `applica } } ``` +##### Blob Payload + +```jsonc +{ + "targetArtifact": { + "mediaType": "application/octet-stream", + "digest": "sha256:2f3a23b6373afb134ddcd864be8e037e34a662d090d33ee849471ff73c873345", + "size": 1024 + } +} +``` +##### Blob Payload with annotations + +```jsonc +{ + "targetArtifact": { + "mediaType": "application/octet-stream", + "digest": "sha256:2f3a23b6373afb134ddcd864be8e037e34a662d090d33ee849471ff73c873345", + "size": 1024, + "annotations": { + "io.wabbit-networks.buildId": "123" // user defined metadata + } + } +} +``` ### Signed Attributes @@ -179,6 +152,84 @@ These attributes are considered unsigned with respect to the signing key that ge - **Timestamp signature** : An OPTIONAL counter signature which provides [authentic timestamp](#signing-time)e.g. Time Stamp Authority (TSA) generated timestamp signature. Only [RFC3161][ietf-rfc3161] compliant TimeStampToken are currently supported. - **Signing Agent**: An OPTIONAL claim that provides the identifier of the software (e.g. Notation) that produced the signature on behalf of the user. It is an opaque string set by the software that produces the signature. It's intended primarily for diagnostic and troubleshooting purposes, this attribute is unsigned, the verifier MUST NOT validate formatting, or fail validation based on the content of this claim. The suggested format is one or more tokens of the form `{id}/{version}` containing identifier and version of the software, separated by spaces. E.g. "notation/1.0.0", "notation/1.0.0 myplugin/0.8". +## OCI Signatures + +This section describes how a Notary Project signature is stored in an OCI Distribution conformant registry. +OCI image manifest is used to store signatures in the registry, see [OCI image spec v1.1.0-rc3][oci-image-manifest] for details. +The signature manifest has a configuration media type that specifies it's a Notary Project signature, a subject referencing the manifest of the artifact being signed, a layer referencing the signature, and a collection of annotations. + +![Signature storage inside registry](../media/oci-signature-specification.svg) + +Signature manifest example per OCI image manifest: + +```jsonc +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.cncf.notary.signature", + "size": 2, + "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a" + }, + "layers": [ + { + "mediaType": "application/jose+json", + "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\"]" + } +} +``` + +Besides the [image manifest property requirements][image-manifest-property-descriptions], the properties have the following additional restrictions: + +- **`mediaType`** (*string*): This REQUIRED property MUST be `application/vnd.oci.image.manifest.v1+json`. +- **`config`** (*descriptor*): This property is REQUIRED to be compatible with [OCI image specification][oci-image-manifest]. The Notary Project signature specification doesn't require any configuration for a signature, and the configuration content is not consumed by implementations of the Notary Project signature specification. + - **`mediaType`** (*string*): This REQUIRED property MUST be `application/vnd.cncf.notary.signature`. + - **`digest`** (*string*): This REQUIRED property is the digest of the config content. + - **`size`** (*int64*): This REQUIRED property specifies the size, in bytes, of the raw config content. +- **`layers`** (*array of objects*): This REQUIRED property contains collection of only one [OCI descriptor][oci-descriptor] referencing the signature envelope. + - **`mediaType`** (*string*): This REQUIRED property contains media type of signature envelope blob. Following values are supported + - `application/jose+json` + - `application/cose` +- **`subject`** (*descriptor*): A REQUIRED artifact descriptor referencing the signed manifest. +- **`annotations`** (*string-string map*): This REQUIRED property contains metadata for the image manifest. + It is being used to store information about the signature. + Keys using the `io.cncf.notary` namespace are reserved for use in the Notary Project signature specification and MUST NOT be used by other specifications. + - **`io.cncf.notary.x509chain.thumbprint#S256`**: A REQUIRED annotation whose value contains the list of SHA-256 fingerprints of signing certificate and certificate chain (including root) used for signature generation. The list of fingerprints is present as a JSON array string, corresponding to ordered certificates in [*Certificate Chain* unsigned attribute](#unsigned-attributes) in the signature envelope. The annotation name contains the hash algorithm as a suffix (`#S256`) and can be extended to support other hashing algorithms in future. + +### OCI Signature Discovery + +The client should be able to discover all the signatures belonging to an artifact (such as image manifest) by using [OCI Distribution Referrers API][oci-distribution-referrers]. +OCI Distribution Referrers API returns a paginated list of all artifacts belonging to a target artifact (such as container images, SBoMs). +The implementation can filter Notary Project signatures by either using OCI Distribution Referrers API or using custom logic on the client. +Each Notary Project signature refers to a signature envelope blob. + +### OCI Signature Filtering + +An OCI artifact can have multiple signatures, implementations of the Notary Project signature specification uses annotations of the signature manifest to filter relevant signatures based on the applicable trust policy. +The Notary Project signature manifest's `io.cncf.notary.x509chain.thumbprint#S256` annotation key MUST contain the list of SHA-256 fingerprints of certificate and certificate chain used for signing. + +## Blob Signatures + +The Notary Project facilitates signing arbitrary blobs using detached signatures. These detached signatures can be transported via any preferred medium and verified on the receiving end. A detached signature refers to a signature that is not embedded within (and therefore does not modify) the original blob, instead it consists of a detached signature envelope with a signature over the unique representation of the blob (i.e. blob's digest). The file extension can either be 'jws' or 'cose', indicating the signature envelope format. + +![Signature storage inside file system](../media/blob-signature-specification.svg) + +### Differences between OCI and blob signatures + +1. Apart from the `payload` field, all other fields of a signature envelope are identical between OCI and blob signatures. +1. OCI signatures have signature manifest files, containing the mediaType of the signature envelope (application/jose+json or application/cose). However, blob signatures lack such manifest file and this mediaType information is instead found in the signature file extension. + ## Signature Algorithm Requirements The implementation MUST support the following set of algorithms: @@ -194,7 +245,7 @@ For ECDSA equivalent NIST curves and ANSI curves can be found at [RFC4492 Append ### Algorithm Selection -The signing certificate's public key algorithm and size MUST be used to determine the signature algorithm. +The signing certificate's public key algorithm and size MUST be used to determine the signature algorithm. Notary Project supports the following Signature Algorithms. | Public Key Algorithm | Key Size (bits) | Signature Algorithm | | -------------------- | --------------- | ------------------------------- | @@ -269,10 +320,10 @@ The signing time denotes the time at which the signature was generated. A X509 c This is an optional feature that provides a "best by use" time for the artifact, as defined by the signer. The Notary Project signature specification allows users to include an optional expiry time when they generate a signature. The expiry time is not set by default and requires explicit configuration by users at the time of signature generation. The artifact is considered expired when the current time is greater than or equal to expiry time, users performing verification can either configure their trust policies to fail the verification or even accept the artifact with expiry date in the past using policy. This is an advanced feature that allows implementing controls for user defined semantics like deprecation for older artifacts, or block older artifacts in a production environment. Users should only include an expiry time in the signed artifact after considering the behavior they expect for consumers of the artifact after it expires. Users can choose to consume an artifact even after the expiry time based on their specific needs. -### Signature Portability +### OCI Signature Portability Portability of signatures is associated with the portability of associated artifacts which are being signed. -OCI artifacts are inherently location agnostic, artifacts can be pulled from and pushed to any OCI compliant registry to which a user has access. +OCI artifacts are inherently registry agnostic, artifacts can be pulled from and pushed to any OCI compliant registry to which a user has access. The artifacts themselves can be classified as follow. 1. *Public Artifacts* - Artifacts that are distributed publicly for broad consumption. @@ -283,13 +334,13 @@ Signatures associated with these artifacts require broad portability. E.g. Images for containerized applications and services used within an organization, or shared with limited authorized parties. Based on user requirements a private artifact can have different levels of portability, the signature’s portability should at least match the the artifact’s portability. -*The Notary Project signature portability* is based on the following +*The Notary Project OCI signature portability* is based on the following #### Signature discovery -The Notary Project signature specification addressed signature discovery by storing signatures in the same registry (location) where an artifact is present. +The Notary Project OCI signature specification addressed signature discovery by storing signatures in the same registry (location) where an artifact is present. This is supported through [OCI Distribution Referrers API][oci-distribution-referrers] which allows reference artifacts such as signatures, SBOMs to be associated with existing artifacts like Images. -The Notary Project signature specification allows multiple signatures to be associated with an artifact, and clients may automatically push signatures for an artifact to a destination registry when a signed artifact moves from one registry to other. +The Notary Project OCI signature specification allows multiple signatures to be associated with an artifact, and clients may automatically push signatures for an artifact to a destination registry when a signed artifact moves from one registry to other. #### Verification requirements @@ -307,6 +358,9 @@ The Notary Project signatures without any critical extended attributes do not im Whereas, the Notary Project signatures that contain critical extended attributes will require additional dependencies for signature validation, either on Notation compliant plugins or equivalent tooling which may not be available in all environments. Similarly, Notation compliant plugin vendors should be aware that usage of extended signed attributes which are marked critical in signature will have implications on portability of the signature. +### Blob Signature Portability +Notary Project blob signatures provide the maximum portability as there are no requirements on storage or transport medium. Users can store and transport their blobs and associated detached signatures as required. + ### Guidelines for implementations of the Notary Project signature specification Implementations of the Notary Project signature specification, can choose to be [Notation plugin protocol](./plugin-extensibility.md#plugin-contract) aware or not. If an implementation chooses to be plugin protocol aware, and it encounters the Verification Plugin and Verification Plugin minimum version attributes during signature verification, it MUST process these attributes. This involves finding the appropriate plugin and the version to use, and executing `verify-signature` plugin command with correct inputs and processing the plugin response, as per the [Verification Plugin interface](./plugin-extensibility.md#verification-extensibility). diff --git a/specs/signing-and-verification-workflow.md b/specs/signing-and-verification-workflow.md index 1c3b18b..bd9353a 100644 --- a/specs/signing-and-verification-workflow.md +++ b/specs/signing-and-verification-workflow.md @@ -1,8 +1,8 @@ # Signing and Verification Workflow -This document describes the workflow of signing and verifying OCI artifacts. +This document describes workflows for signing and verifying OCI artifacts and arbitrary blobs. -## Signing workflow +## OCI artifact signing workflow The user wants to sign an OCI artifact and push the signature to a repository. @@ -27,7 +27,7 @@ The user wants to sign an OCI artifact and push the signature to a repository. The user pushes the OCI artifact to the repository before the signature generation process as the signature reference must exist for the signature push to succeed. -## Verification workflow +## OCI artifact verification workflow The user wants to pull an OCI artifact only if they are signed by a trusted publisher and the signature is valid. @@ -41,7 +41,7 @@ The user wants to pull an OCI artifact only if they are signed by a trusted publ ### Verification Steps -1. **Should implementations of this specification verify the signature? :** Depending upon [trust-policy](./trust-store-trust-policy.md#trust-policy) configuration, determine whether implementations of this specification need to verify the signature or not. +1. **Should implementations of this specification verify the signature? :** Depending upon [trust-policy](./trust-store-trust-policy.md#oci-trust-policy) configuration, determine whether implementations of this specification need to verify the signature or not. If signature verification should be skipped for the given artifact, skip the below steps and directly jump to step 4. 1. **Get signature artifact descriptors:** Using the [OCI Distribution Referrers API](https://github.com/opencontainers/distribution-spec/blob/main/spec.md#listing-referrers) download the Notary Project signature manifest descriptors. The `artifactType` parameter is set to the Notary Project signature's artifact type `application/vnd.cncf.notary.signature`. @@ -64,9 +64,53 @@ The user wants to pull an OCI artifact only if they are signed by a trusted publ 1. Verify the signature envelope using trust-store and trust-policy as mentioned in [signature evaluation](./trust-store-trust-policy.md#signature-evaluation) section. 1. If the signature verification fails, skip the below steps and move to the next signature artifact descriptor(step 3.1). If all signature artifact descriptors have already been processed, fail the signature verification and exit. - 1. If signature verification succeeds, compare the digest derived from the given OCI artifact reference with the signed digest present in the signature envelope's payload. - If digests are equal, signature verification is considered successful. + 1. If signature verification succeeds, compare the digest derived from the given OCI artifact reference with the signed digest present in the signature envelope's payload. Also, if there are any user-defined/supplied custom annotations, match them as well. + If digests and custom annotations are equal, signature verification is considered successful. Otherwise, move to the next signature artifact descriptor(step 3.1). If all signature artifact descriptors have already been processed, fail the signature verification and exit. 1. **Get OCI artifact:** Using the verified digest, download the OCI artifact. This step is not in the purview of Notary Project. + +## Blob signing workflow + +The user wants to sign an arbitrary blob with a detached signature. + +### Signing Prerequisites + +- User has access to the signing certificate and private key or a remote signing service through a notation plug-in. + +### Signing Steps + +1. **Generate signature:** Using notation CLI or any other compliant signing tool, sign the blob. The signing tool should follow the following guideline. + 1. Construct the blob payload as defined in [`signature specification`](./signature-specification.md#payload) + 1. Verify that the signing certificate is valid and satisfies [certificate requirements](./signature-specification.md#certificate-requirements). + 1. Verify that the signing algorithm satisfies [algorithm requirements](./signature-specification.md#signature-algorithm-requirements). + 1. Generate signature. + 1. Generate signature using a signature format specified in [supported signature envelopes](./signature-specification.md#supported-signature-envelopes). Also, as part of this step, the user-defined/supplied custom attributes should be added to the annotations of the signature payload. + 1. If the user wants to timestamp the signature, obtain an [RFC-3161](https://datatracker.ietf.org/doc/html/rfc3161.html) compliant timestamp for the signature generated in the previous step. Otherwise, continue to the next step. + 1. Verify that the timestamp signing certificate satisfies [certificate requirements](./signature-specification.md#certificate-requirements). + 1. Verify that the timestamp signing algorithm satisfies [algorithm requirements](./signature-specification.md#signature-algorithm-requirements). + 1. Embed timestamp to the signature envelope. +1. **Save the signature envelope:** Save the signature envelope generated in the previous step to a file. File extension should be the original blob file name plus `.sig.jws` for JWS signatures and `.sig.cose` for COSE signatures. + +## Arbitrary blob verification workflow + +The user wants to consume an arbitrary blob only if it was signed by a trusted publisher and the signature associated with the blob is valid. + +### Verification Prerequisites + +- User has the blob that they want to consume, along with its detached signature. +- User has configured [trust store and trust policy](./trust-store-trust-policy.md) required for signature verification. + +### Verification Steps + +1. **Should implementations of this specification verify the signature? :** Depending upon [trust-policy](./trust-store-trust-policy.md#blob-trust-policy) configuration, determine whether implementations of this specification need to verify the signature or not. + If signature verification should be skipped for the given blob, skip the below steps. +1. **Verify the detached signature:** + 1. Parse and validate the signature envelope using the detached signature's file extension as the envelope type. + 1. Verify the signature envelope using trust-store and trust-policy as mentioned in [signature evaluation](./trust-store-trust-policy.md#signature-evaluation) section. + 1. If the signature verification fails, exit. +1. Calculate the blob's size and verify that it matches the size present in `targetArtifact.size`. Fail signature verification if there is a mismatch. +1. If provided by the user, verify blob's media type to the one present in `targetArtifact.mediaType`. Fail signature verification if there is a mismatch. +1. Calculate the digest of the blob using the digest algorithm deduced from signing certificate's public key (see [Algorithm Selection](./signature-specification.md#algorithm-selection)) and match it with the digest specified at `targetArtifact.digest`. Fail signature verification if there is a mismatch. +1. If there any user-defined/supplied custom annotations, match them against the ones present in `targetArtifact.annotations`. If they match, signature verification is considered successful. \ No newline at end of file diff --git a/specs/signing-scheme.md b/specs/signing-scheme.md index 2fd49c7..31fbccd 100644 --- a/specs/signing-scheme.md +++ b/specs/signing-scheme.md @@ -36,7 +36,7 @@ Similarly, a signing authority (SA) will need to demonstrate signing keys were o * A signature envelope can only specify one Signing Scheme * When Notary Project supports an additional Signing Scheme - * Existing signed artifacts MUST be resigned if they need to be verified using the new signing scheme defined verification process. + * Existing signed artifacts MUST be re-signed if they need to be verified using the new signing scheme defined verification process. * Existing clients used by verifying entity MUST be updated to newer versions that support verifying signatures that use the new signing scheme, otherwise the signatures with newer signing schemes which are unknown to existing clients will fail signature verification. Signatures that use older signing schemes which are known to existing clients will continue to verify correctly. * The language of the [Notary Project verification policy](./trust-store-trust-policy.md) in *trustpolicy.json* MAY have breaking changes to support newer concepts/configuration elements introduced by the new signing scheme. The breaking changes are addressed by introducing new major version in the versioned *trustpolicy.json* . diff --git a/specs/trust-store-trust-policy.md b/specs/trust-store-trust-policy.md index 9d2789b..9978579 100644 --- a/specs/trust-store-trust-policy.md +++ b/specs/trust-store-trust-policy.md @@ -2,10 +2,10 @@ Notary Project currently supports X.509 based PKI and identities, and uses a trust store and trust policy to determine if a signed artifact is considered authentic. -The document consists of the following sections: +This document consists of the following sections: - **[Trust Store](#trust-store)**: Contains a set of trusted identities through which trust is derived for the rest of the system. For X.509 PKI, the trust store typically contains a set of root certificates. -- **[Trust Policy](#trust-policy)**: A policy language which indicates which identities are trusted to produce artifacts. Both trust store and trust policy need to be configured by users/administrators before artifact signature can be evaluated. +- **[Trust Policy](#trust-policy)**: A policy language which indicates which identities are trusted to produce artifacts. Both trust store and trust policy need to be configured by users/administrators before artifact signature can be evaluated. Notation supports different trust policies for verifying different types of artifacts like signed OCI images and arbitrary blobs, etc. - **[Signature Verification](#signature-verification)**: Describes how signatures are evaluated using the policy, to determine if a signed artifact is authentic. This section is meant for implementations of the [Notary Project verification specification](./signing-and-verification-workflow.md). Other types of identities and trust models may be supported in future, which may introduce other constructs/policy elements to support signature evaluation. @@ -14,8 +14,8 @@ Other types of identities and trust models may be supported in future, which may All examples use the actors defined in the Notary Project [scenarios](../requirements/scenarios.md#scenario-0-build-publish-consume-enforce-policy-deploy) -- Wabbit Networks company builds, signs and distributes their `net-monitor` software though public registries. -- ACME Rockets consumes the `net-monitor` software from a public registry importing the artifacts and reference artifacts (signatures, SBoMs) into their private registry. The private registry also contains additional artifacts that ACME Rockets themselves sign. +- Wabbit Networks company builds, signs and distributes their `net-monitor` software. +- ACME Rockets consumes the `net-monitor` software from Wabbit Networks. ## Trust Store @@ -53,31 +53,68 @@ $XDG_CONFIG_HOME/notation/trust-store The Trust store currently supports three kinds of identities, additional identities may be supported in future : - **Certificates**: The `x509/ca` trust store contains named stores that contain Certificate Authority (CA) root certificates. -- **SigningAuthority Certificate**: The `x509/signingAuthority` trust store contains named stores that contain Siging Authority's root certificates. +- **SigningAuthority Certificate**: The `x509/signingAuthority` trust store contains named stores that contain Signing Authority's root certificates. - **Timestamping Certificates**: The `x509/tsa` trust store contains named stores with Time Stamping Authority (TSA) root certificates. -Any additional sub directories under names stores and certificates in it are ignored. **NOTE**: Implementation SHOULD warn if it finds sub directories with certificates under a named store, to help diagnose misconfigured store. +Any additional sub directories under a named store and certificates in it are ignored. **NOTE**: Implementation SHOULD warn if it finds sub directories with certificates under a named store, to help diagnose misconfigured store. ## Trust Policy -Users who consume signed artifact from a registry use the trust policy to specify trusted identities which will sign the artifacts, and level of signature verification to use. +Users who consume signed artifacts from OCI registries, or signed arbitrary blobs stored on file system, use trust policies to specify trusted identities that signed the artifacts, and level of signature verification to enforce. Trust policy files are JSON documents. -### Trust Policy Schema +> [!NOTE] +> Users are required to setup separate trust policy files for verifying different types of signed artifacts. Notation expects OCI trust policy file to be placed at `{NOTATION_CONFIG}/trustpolicy.oci.json`. For backward compatibility reasons, Notation accepts `{NOTATION_CONFIG}/trustpolicy.json` as OCI trust policy file as well. For arbitrary blobs, Notation expects trust policy file to be placed at `{NOTATION_CONFIG}/trustpolicy.blob.json`. -The trust policy is a JSON document, here are some examples. +### Trust Policy Properties + +#### OCI Trust Policy + +##### Version 1.0 + +- **`version`**(*string*): This REQUIRED property is the version of the trust policy. This MUST be `1.0` at the moment. +- **`trustPolicies`**(*string-array of objects map*): This REQUIRED property represents a collection of trust policies. + - **`name`**(*string*): This REQUIRED property represents the name of the trust policy. + - **`registryScopes`**(*array of strings*): This REQUIRED property determines which trust policy is applicable for the given artifact. + The scope field supports filtering based on fully qualified repository URI `${registry-name}/${namespace}/${repository-name}`. + For more information, see [trust policy constraints](#oci-trust-policy-constraints) section. + - **`signatureVerification`**(*object*): This REQUIRED property dictates how signature verification is performed. + An *object* that specifies a predefined verification level, with an option to override the Notary Project trust policy defined verification level if user wants to specify a [custom verification level](#custom-verification-level). + - **`level`**(*string*): A REQUIRED property that specifies the verification level, supported values are `strict`, `permissive`, `audit` and `skip`. Detailed explanation of each level is present [here](#signatureverification-details). + - **`override`**(*map of string-string*): This OPTIONAL map is used to specify a [custom verification level](#custom-verification-level). + - **`trustStores`**(*array of string*): This REQUIRED property specifies a set of one or more named trust stores, each of which contain the trusted roots against which signatures are verified. Each named trust store uses the format `{trust-store-type}:{named-store}`. Currently supported values for `trust-store-type` are `ca`, `signingAuthority` and `tsa`. For publicly trusted TSA, `tsa:publicly-trusted-tsa` is the default value, and implied without explicitly specifying it. If a custom TSA is used the format `ca:acme-rockets,tsa:acme-tsa` is supported to specify it. + - **`trustedIdentities`**(*array of strings*): This REQUIRED property specifies a set of identities that the user trusts. For X.509 PKI, it supports list of elements/attributes of the signing certificate's subject. For more information, see [identities constraints](#trusted-identities-constraints) section. A value `*` is supported if user trusts any identity (signing certificate) issued by the CA(s) in `trustStore`. + +#### Blob Trust Policy -Trust policy for a simple scenario where ACME Rockets uses only artifacts signed by their CI/CD. Any third party artifacts also are vetted and signed by ACME Rockets. +##### Version 1.0 + +- **`version`**(*string*): This REQUIRED property is the version of the trust policy. This MUST be `1.0` at the moment. +- **`trustPolicies`**(*string-array of objects map*): This REQUIRED property represents a collection of trust policies. + - **`name`**(*string*): This REQUIRED property represents the name of the trust policy. This will be used to select the policy to verify a signed blob. + - **`signatureVerification`**(*object*): This REQUIRED property dictates how signature verification is performed. + An *object* that specifies a predefined verification level, with an option to override the Notary Project trust policy defined verification level if user wants to specify a [custom verification level](#custom-verification-level). + - **`level`**(*string*): A REQUIRED property that specifies the verification level, supported values are `strict`, `permissive`, `audit` and `skip`. Detailed explanation of each level is present [here](#signatureverification-details). + - **`override`**(*map of string-string*): This OPTIONAL map is used to specify a [custom verification level](#custom-verification-level). + - **`globalPolicy`**(*boolean*): This OPTIONAL property flags the policy as the global trust policy if set to `true`. This policy will be used for verification if the user does not select any policy by its name during verification. + - **`trustStores`**(*array of string*): This REQUIRED property specifies a set of one or more named trust stores, each of which contain the trusted roots against which signatures are verified. Each named trust store uses the format `{trust-store-type}:{named-store}`. Currently supported values for `trust-store-type` are `ca`, `signingAuthority` and `tsa`. For publicly trusted TSA, `tsa:publicly-trusted-tsa` is the default value, and implied without explicitly specifying it. If a custom TSA is used the format `ca:acme-rockets,tsa:acme-tsa` is supported to specify it. + - **`trustedIdentities`**(*array of strings*): This REQUIRED property specifies a set of identities that the user trusts. For X.509 PKI, it supports list of elements/attributes of the signing certificate's subject. For more information, see [identities constraints](#trusted-identities-constraints) section. A value `*` is supported if user trusts any identity (signing certificate) issued by the CA(s) in `trustStore`. + +### Trust Policy Examples + +#### Trust Policy for OCI artifacts + +1. Trust policy for a simple scenario where ACME Rockets consumes only the OCI artifacts signed by their own CI/CD. Any third party artifacts consumed by ACME Rockets are also signed and vetted by their CI/CD. ```jsonc { "version": "1.0", "trustPolicies": [ { - // Policy for all artifacts, from any registry location. + // Policy for all artifacts, from any OCI registry location. "name": "wabbit-networks-images", // Name of the policy. "registryScopes": [ "*" ], // The registry artifacts to which the policy applies. "signatureVerification": { // The level of verification - strict, permissive, audit, skip. - "level" : "audit" + "level" : "audit" }, "trustStores": ["ca:acme-rockets"], // The trust stores that contains the X.509 trusted roots. "trustedIdentities": [ // Identities that are trusted to sign the artifact. @@ -88,7 +125,7 @@ Trust policy for a simple scenario where ACME Rockets uses only artifacts signed } ``` -Trust policy for the scenario where ACME Rockets uses some artifacts signed by Wabbit Networks and some signed by ACME Rockets. +2.Trust policy for a scenario where ACME Rockets consumes some OCI artifacts signed by Wabbit Networks and some signed by ACME Rockets. ```jsonc { @@ -111,7 +148,7 @@ Trust policy for the scenario where ACME Rockets uses some artifacts signed by W ] }, { - // Exception policy for a single unsigned artifact pulled from + // Exception policy for a single unsigned OCI artifact pulled from // Wabbit Networks repository "name": "unsigned-image", "registryScopes": [ "registry.wabbit-networks.io/software/unsigned/net-utils" ], @@ -121,7 +158,7 @@ Trust policy for the scenario where ACME Rockets uses some artifacts signed by W }, { // Policy that uses custom verification level to relax the strict verification. - // It logs expiry and skips recovocation check for a specific artifact. + // It logs expiry and skips revocation check for a specific OCI artifact. "name": "use-expired-image", "registryScopes": [ "registry.acme-rockets.io/software/legacy/metrics" ], "signatureVerification": { @@ -135,15 +172,15 @@ Trust policy for the scenario where ACME Rockets uses some artifacts signed by W "trustedIdentities": ["*"] }, { - // Policy for all other artifacts signed by ACME Rockets + // Policy for all other OCI artifacts signed by ACME Rockets // from any registry location. The policy also specified multiple trust stores. "name": "global-policy-for-all-other-images", "registryScopes": [ "*" ], "signatureVerification": { - "level" : "audit" + "level" : "audit" }, "trustStores": ["ca:acme-rockets", "ca:acme-rockets-ca2"], - "trustedIdentities": [ + "trustedIdentities": [ "x509.subject: C=US, ST=WA, L=Seattle, O=acme-rockets.io, OU=Finance, CN=SecureBuilder" ] } @@ -151,21 +188,54 @@ Trust policy for the scenario where ACME Rockets uses some artifacts signed by W } ``` -### Trust Policy Properties +#### Trust Policy for Blobs -- **`version`**(*string*): This REQUIRED property is the version of the trust policy. - The supported value is `1.0`. -- **`trustPolicies`**(*string-array of objects map*): This REQUIRED property represents a collection of trust policies. - - **`name`**(*string*): This REQUIRED property represents the name of the trust policy. - - **`registryScopes`**(*array of strings*): This REQUIRED property determines which trust policy is applicable for the given artifact. - The scope field supports filtering based on fully qualified repository URI `${registry-name}/${namespace}/${repository-name}`. - For more information, see [registry scopes constraints](#registry-scopes-constraints) section. - - **`signatureVerification`**(*object*): This REQUIRED property dictates how signature verification is performed. - An *object* that specifies a predefined verification level, with an option to override the Notary Project trust policy defined verification level if user wants to specify a [custom verification level](#custom-verification-level). - - **`level`**(*string*): A REQUIRED property that specifies the verification level, supported values are `strict`, `permissive`, `audit` and `skip`. Detailed explanation of each level is present [here](#signatureverification-details). - - **`override`**(*map of string-string*): This OPTIONAL map is used to specify a [custom verification level](#custom-verification-level). - - **`trustStores`**(*array of string*): This REQUIRED property specifies a set of one or more named trust stores, each of which contain the trusted roots against which signatures are verified. Each named trust store uses the format `{trust-store-type}:{named-store}`. Currently supported values for `trust-store-type` are `ca`, `signingAuthority` and `tsa`. For publicly trusted TSA, `tsa:publicly-trusted-tsa` is the default value, and implied without explicitly specifying it. If a custom TSA is used the format `ca:acme-rockets,tsa:acme-tsa` is supported to specify it. - - **`trustedIdentities`**(*array of strings*): This REQUIRED property specifies a set of identities that the user trusts. For X.509 PKI, it supports list of elements/attributes of the signing certificate's subject. For more information, see [identities constraints](#trusted-identities-constraints) section. A value `*` is supported if user trusts any identity (signing certificate) issued by the CA(s) in `trustStore`. +1. Trust policy for the scenario where ACME Rockets consumes arbitrary blobs signed by Wabbit Networks and some signed by ACME Rockets. + +```jsonc +{ + "version": "1.0", + "trustPolicies": [ + { + // Policy for set of blobs signed by Wabbit Networks + "name": "wabbit-networks-blobs", + "signatureVerification": { + "level" : "strict" + }, + "trustStores": ["ca:wabbit-networks"], + "trustedIdentities": [ + "x509.subject: C=US, ST=WA, L=Seattle, O=wabbit-networks.io, OU=Security Tools" + ] + }, + { + // Policy that uses custom verification level to relax the strict verification. + // It logs expiry and skips the revocation check. + "name": "use-expired-blobs", + "signatureVerification": { + "level" : "strict", + "override" : { + "expiry" : "log", + "revocation" : "skip" + } + }, + "trustStores": ["ca:acme-rockets"], + "trustedIdentities": ["*"] + }, + { + // Global policy for all arbitrarily blobs + "name": "global-policy-for-all-blobs", + "signatureVerification": { + "level" : "audit" + }, + "globalPolicy": true, + "trustStores": ["ca:acme-rockets", "ca:acme-rockets-ca2"], + "trustedIdentities": [ + "x509.subject: C=US, ST=WA, L=Seattle, O=acme-rockets.io, OU=Finance, CN=SecureBuilder" + ] + } + ] +} +``` #### Signature Verification details @@ -185,7 +255,7 @@ Trust policy for the scenario where ACME Rockets uses some artifacts signed by W - `strict` : Signature verification is performed at `strict` level, which enforces all validations. If any of these validations fail, the signature verification fails. This is the recommended level in environments where a signature verification failure does not have high impact to other concerns (like application availability). It is recommended that build and development environments where images are initially created, or for high assurance at deploy time use `strict` level. - `permissive` : The `permissive` level enforces most validations, but will only logs failures for revocation and expiry. The `permissive` level is recommended to be used if signature verification is done at deploy time or runtime, and the user only needs integrity and authenticity guarantees. - `audit` : The `audit` level only enforces signature integrity if a signature is present. Failure of all other validations are only logged. -- `skip` : The `skip` level does not fetch signatures for artifacts and does not perform any signature verification. This is useful when an application uses multiple artifacts, and has a mix of signed and unsigned artifacts. Note that `skip` cannot be used with a global scope (`*`), the value of `registryScopes` MUST contain fully qualified registry URL(s). +- `skip` : The `skip` level does not perform any signature verification. This is useful when an application uses multiple artifacts, and has a mix of signed and unsigned artifacts. Note that `skip` cannot be used with a global scope (`*`). The following table shows the resultant validation action, either *enforced* (verification fails), or *logged* for each of the checks, based on signature verification level. @@ -231,9 +301,11 @@ Signature verification levels provide defined behavior for each validation e.g. } ``` -#### Registry Scopes Constraints +#### Trust Policy Constraints -- Each trust policy MUST contain scope property and the scope collection MUST contain at least one value. +##### OCI Trust Policy Constraints + +- Each trust policy MUST contain scope property `registryScopes` and the scope collection MUST contain at least one value. - The scope MUST contain one of the following: - List of one or more fully qualified repository URIs. The repository URI MUST NOT contain the asterisk character `*`. @@ -242,16 +314,32 @@ Signature verification levels provide defined behavior for each validation e.g. The trust policy with global scope applies to all the artifacts. There can only be one trust policy that uses a global scope. -#### Selecting a trust policy based on artifact URI +##### Blob Trust Policy Constraints +- There MUST be only one trust policy with `globalPolicy` set to `true` +- `signatureVerification` MUST not be set to `skip` if the policy is marked as a global policy + +#### Selecting a trust policy to verify a signed OCI artifact -- For a given artifact there MUST be only one applicable trust policy, except for trust policy with global scope. -- For a given artifact, if there is no applicable trust policy then implementations of the [Notary Project verification specification](./signing-and-verification-workflow.md) MUST consider the artifact as untrusted and fail signature verification. +- The URI of an OCI artifact dictates the trust policy that gets applied to verify the artifact's signature. +- For a given OCI artifact there MUST be only one applicable trust policy, except for trust policy with a global scope. +- For a given OCI artifact, if there is no applicable trust policy then implementations of the [Notary Project verification specification](./signing-and-verification-workflow.md) MUST consider the artifact as untrusted and fail signature verification. - The scope MUST NOT support reference expansion i.e. URIs must be fully qualified. E.g. the scope should be `docker.io/library/registry` rather than `registry`. - Evaluation order of trust policies: 1. *Exact match*: If there exists a trust policy whose scope contains the artifact's repository URI then the aforementioned policy MUST be used for signature evaluation. Otherwise, continue to the next step. - 1. *Global*: If there exists a trust policy with global scope then use that policy for signature evaluation. + 1. *Global*: If there exists a trust policy with global scope (`*`) then use that policy for signature evaluation. + Otherwise, fail the signature verification. + +#### Selecting a trust policy to verify a signed blob + +- The signature verifier must select the appropriate trust policy for blob signature verification using policy names. +- For a given policy name selected by the verifier, there MUST be only one trust policy with that exact name. +- For a given policy name selected by the verifier, if there is no matching trust policy with that name, then implementations of the [Notary Project verification specification](./signing-and-verification-workflow.md) MUST consider the blob as untrusted and fail signature verification. +- Selecting a trust policy: + 1. *Exact match*: If there exists a trust policy whose name exactly matches the one provided by the signature verifier then the aforementioned policy MUST be used for signature evaluation. + Otherwise, fail the signature verification. + 1. *Global*: If verifier does not select a policy by its name and if there exists a trust policy marked as a global policy (`globalPolicy:true`) then use that policy for signature evaluation. Otherwise, fail the signature verification. ### Trusted Identities Constraints @@ -295,21 +383,27 @@ Notary Project allows user to execute custom validations during verification usi ### Steps 1. **Identify applicable trust policy** - 1. For the given artifact URI [determine the applicable trust policy](#selecting-a-trust-policy-based-on-artifact-uri) using `registryScopes`. - 1. If an applicable trust policy for the artifact URI cannot be found, fail signature verification. + 1. For OCI artifacts, refer to `{NOTATION_CONFIG}/trustpolicy.oci.json` or `{NOTATION_CONFIG}/trustpolicy.json` file and use [the artifact URI as the policy selector](#selecting-a-trust-policy-to-verify-a-signed-oci-artifact) and select the policy with matching scope from `registryScopes`. + 1. For Blob artifacts, refer to `{NOTATION_CONFIG}/trustpolicy.blob.json` and use [the policy name provided by the verifier](#selecting-a-trust-policy-to-verify-a-signed-blob) as the policy selector and select a policy. + 1. If an applicable trust policy cannot be found, fail signature verification. 1. **Proceed based on signature verification level** 1. If `signatureVerification` level is set to `skip` in the trust policy, return success. 1. For all other `signatureVerification` levels, `strict`, `permissive` and `audit`, perform each of the validation defined in the next sections - `integrity`, `authenticity`, `trusted timestamp`, `expiry` and `revocation`. 1. The `signatureVerification` level defines if each validation is `enforced` or `logged` - 1. `enforced` - validation failures are treated as critical, causes the overall signature verification to fail and exit. Subsequent validations are not processed. - 1. `logged` - validation failure is logged and the next validation step is processed. + 1. `enforced` - validation failures are treated as critical, causes the overall signature verification to fail and exit. Subsequent validations are not processed. + 1. `logged` - validation failure is logged and the next validation step is processed. 1. A signature verification is considered successful when all validation steps are completed without critical failure. 1. **Validate Integrity.** - 1. Validate that signature envelope can be parsed sucessfully based on the signature envelope type specified in the `blobs[0].mediaType` attribute of the signature artifact manifest. + 1. Validate signature envelope + 1. For OCI artifacts, validate that signature envelope can be parsed successfully based on the signature envelope type specified in the `blobs[0].mediaType` attribute of the signature artifact manifest. + 1. For Blob artifacts, validate that signature envelope can be parsed successfully based on the signature envelope type specified in the detached signature file extension. If no file extension is available, parse the envelope type by trying each of the [supported signature envelopes](./signature-specification.md#supported-signature-envelopes). Fail integrity check if unsuccessful. 1. Validate that the content type indicated by the `content type` signed attribute in the signature envelope is supported. 1. Get the signing certificate from the parsed [signature envelope](https://github.com/notaryproject/notaryproject/blob/7b7d283038/signature-specification.md#signature-envelope). 1. Determine the signing algorithm(hash+encryption) from the signing certificate and validate that the signing algorithm satisfies [algorithm requirements](./signature-specification.md#signature-algorithm-requirements) 1. Using the public key of the signing certificate and signing algorithm identified in the previous step, validate the integrity of the signature envelope. + 1. Verify signature `payload` + 1. Verify the signature envelope's `payload` matches the source [`payload`](./signature-specification.md#payload) that is getting verified. Make sure the artifact's digest, media type and size match the ones present in the signature envelope. + 1. Additionally for Blob artifacts, calculate the digest of the blob using the hashing algorithm deduced from signing certificate's public key (see [Algorithm Selection](./signature-specification.md#algorithm-selection)) and make sure the digests match. 1. **Validate Authenticity.** 1. For the applicable trust policy, **validate trust store and identities:** 1. Validate that the signature envelope contains a complete certificate chain that starts from a code signing certificate and terminates with a root certificate. Also, validate that code signing certificate satisfies [certificate requirements](./signature-specification.md#certificate-requirements). @@ -340,6 +434,7 @@ Notary Project allows user to execute custom validations during verification usi 1. **Validate Revocation Status:** 1. Validate signing identity(certificate and certificate chain) revocation status using [certificate revocation evaluation](#certificate-revocation-evaluation) section as per `signingIdentityRevocation` setting in trust-policy. 1. Perform extended validation using the applicable (if any) plugin. +1. If present, verify the user provided metadata/custom annotations match the signed attributes present in the signature envelope. 1. If all the steps are completed without critical failures then the signatures is successfully verified. ### Certificate Revocation Evaluation @@ -453,4 +548,4 @@ Not natively supported but a user can configure `revocationValidations` to `skip **A:** Ideally, we should validate the signing identity first and then use the public key in the signing identity to validate the artifact signature. However, this will lead to poor performance in the case where the signature is not valid as there are lots of validations against the signing identity including network calls for revocations, and possibly we won't even need to read the trust store/trust policy if the signature validation fails. -Also, by validating artifact signature first we will still fail the validation if the signing identity is not trusted. +Also, by validating artifact signature first we will still fail the validation if the signing identity is not trusted. \ No newline at end of file diff --git a/threatmodels/notation-threatmodel.md b/threatmodels/notation-threatmodel.md index 6b8b612..f51748b 100644 --- a/threatmodels/notation-threatmodel.md +++ b/threatmodels/notation-threatmodel.md @@ -87,3 +87,4 @@ The certificates trusted by the verifier are stored in Notation trust store in t | Malicious signature faking to be signed by a signing authority | Tampering | Mitigated | High | Notation | Unlike notary.x509 signing scheme, trusted timestamps are not checked against RFC#3161 TSA servers for notary.x509.signingAuthority signing scheme. An attacker can use this and bypass trusted timestamp checks by crafting a signature that uses notary.x509 keys but with signingAuthority as the signing scheme. | To prevent this threat, notary.x509.signingAuthority signing scheme requires trusted roots to be present in a trust store type called signingAuthority as opposed to CA trust store type for notary.x509 signing scheme | | Inaccessible OCSP Responder | Denial of Service | Not Mitigated | High | OCSP Responder | OCSP Responder is not able to service incoming requests or perform up to spec, thus users are unable to validate certificate revocation status | It cannot be mitigated, since revocation status should be retrieved from OCSP responder, which requires network access. Notation verification should fail if revocation check is configured as `enforced` and OCSP responder is inaccessible. Users can configure trust policy to log or skip revocation check if OCSP responder is not reliable. | | Compromised Notation dependencies | Tampering | Mitigated | High | Notation | The dependencies that built into Notation binary was compromised, this may lead to arbitrary code being executed | Notation keeps dependencies up-to-date and adds new dependency after careful consideration and only if it's absolutely required. Always use static build instead of dynamic linking | +| Rollback Attack | Tampering | Mitigated | High | Notation | Attacker can exploit a compromised repository to return outdated vulnerable artifacts | Signer can employ short signature expiration periods (and periodically re-sign artifacts) or revoke outdated vulnerable artifacts | \ No newline at end of file