open-component-model / ocm-project

OCM Project Backlog
Apache License 2.0
0 stars 0 forks source link

Signing for non-modifiable aggregated component versions #151

Open mandelsoft opened 1 year ago

mandelsoft commented 1 year ago

Problem Statement

When signing a component version the digests directly or indirectly resource artifacts are considered.

For the component version, which is signed, this information is stored along with the resources in the component descriptor. To calculated a digest, the hash algorithm and the normalization algorithm of the resource must be known.

To be able to validate a digest both kinds of information must be available. For the signed component version this information is part of the component descriptor.

Problematic are resources of aggregated component version. The OCM signing process tries to store this information as part of the involved component descriptors, if they are not yet present. This might require to modify these descriptors in their persistence layer.

The CNUDIE signing process does not store this information at all. This is acceptable as long as there is only one default combination for determining the hash and normalization algorithm for a resource. But in the future there will be multiple such possibilities. As a result, the digests use for a signing process are not necessarily reproducible for future signature verification.

This was the reason, why this information will be persisted for aggregated component versions during the signing process along with the component descriptors of the aggregated component versions. Unfortunately this modification of used component version is not always desired or even possible. Especially if component versions of foreign providers stored in separate OCM repositories are used to compose a local component version, it might not be possible to modify those component versions. But, nevertheless, it must be possible to sign those composed composed component versions.

What would you like to be added:

If the required digest information cannot be stored in their component descriptors, they must be stored at the component descriptor of the component version to be signed. This component version must be modifiable, because otherwise it would not be possible to store the signature.

Therefore we need a place in the component descriptor to store digest information for resources described by aggregated component versions. This information must not be specific for a dedicated signature, because it can be reused for different signatures. Basically only those information must be stored, that is not yet available in the referenced component versions. Once present is cannot be changed anymore without invalidation existing signatures.

In contrast to the component references, which are identified by separate identities in the context of their usage, the digest information can be stored per component version identity, because the content is independent of the aggregation path.

This leads to the following proposal:

In complex aggregation graphs it must be possible to sign component versions in any order using any key and digest type. This especially means scenarios like a rhombus:

              A
             / \
            B   C
             \ /
              D

For recursive signing, a signing context might already exist if, for example C should be signed starting from A. So, C must then be signed with the already existing digest settings to avoid to store the context per signature. This means, that there are potentially multiple signing contexts for D, depending on the path it is reached.

The signing process :

When signing a component version, this information is accumulated along the component version aggregation graph. The info is only stored in the top-level component descriptor. If the component version already has a digest information for a resource it is used as it is (after verification of the digest), if it does contradict with the actual signing context. If no info is present, it is freshly calculated by the selected appropriate hash and normalization algorithms under control of the digest handlers. Intermediate digest information for references are ignored.

For the component version, which should be signed, the accumulated info is stored in the additional field in the component descriptor. The complete context is stored. For compatibility reasons, the references in the top-level component version get their digest information, whenever a component version is signed. Selecting different digest creation types for additional signatures may overwrite the info in the references.

This means the first signature determines the digest creation for component descriptors for all following signatures.

The verification process:

During the verification of a signature, the additional resource digest information is passed along the recursive verification of aggregated component versions and hereby enriched by additional information found here. For the verification the information provided by the context is used to determine the hash and normalization algorithm for a resource if is present, otherwise, for compatibility reasons, the verification settings are used to determine the digests. Only the top-level reference digests are checked, if the the digest type matched the settings for the signature.

Why is this needed:

It must be possible to sign component versions aggregating component versions stored in component repositories belonging to different providers for which no write access is possible.

It must be possible to sign component versions along an aggregation chain independent of each other, with different settings.

morri-son commented 8 months ago

@mandelsoft , is this still relevant?