diff --git a/.github/config/wordlist.txt b/.github/config/wordlist.txt
index 0f3f415d1..46effe5a5 100644
--- a/.github/config/wordlist.txt
+++ b/.github/config/wordlist.txt
@@ -459,11 +459,20 @@ diataxis
callouts
shortcode
shortcodes
+href
+dockerconfigjson
+rhel
+misattributed
+whitespace
+hsms
+helloworld
+centos
wsl
auditable
hasmermaid
-XDG
+xdg
subpaths
-IAM
+iam
+ocirepository
pullable
descriptor's
diff --git a/content/docs/concepts/components.md b/content/docs/concepts/components.md
index c1dcbb3b0..bf42038a2 100644
--- a/content/docs/concepts/components.md
+++ b/content/docs/concepts/components.md
@@ -2,7 +2,7 @@
title : "OCM Components"
description: "Learn about OCM components and their elements."
icon: "๐ฉ"
-weight: 41
+weight: 1
toc: true
---
diff --git a/content/docs/concepts/coordinates.md b/content/docs/concepts/coordinates.md
index 7efd7b206..d550f0ff9 100644
--- a/content/docs/concepts/coordinates.md
+++ b/content/docs/concepts/coordinates.md
@@ -2,7 +2,7 @@
title : "OCM Coordinates"
description: "Discover how OCM components and artifacts are identified."
icon: "๐งญ"
-weight: 42
+weight: 2
toc: true
---
diff --git a/content/docs/concepts/credential-system.md b/content/docs/concepts/credential-system.md
index d44cf3c12..60ba881cc 100644
--- a/content/docs/concepts/credential-system.md
+++ b/content/docs/concepts/credential-system.md
@@ -2,7 +2,7 @@
title: "Credential System"
description: "Why OCM manages credentials centrally and how its resolution model works."
icon: "๐"
-weight: 43
+weight: 6
toc: true
---
@@ -77,7 +77,7 @@ flowchart TB
subgraph repos ["Repositories (fallback)"]
direction TB
- docker["DockerConfig/v1
~/.docker/config.json"]
+ docker["DockerConfig/v1
$HOME/.docker/config.json"]
end
```
@@ -91,3 +91,7 @@ To see resolution in action, try the [Understand Credential Resolution]({{< relr
- [Tutorial: Credential Resolution]({{< relref "/docs/tutorials/credential-resolution.md" >}}) โ Learn how OCM picks the right credentials by experimenting with a config
- [How-To: Configure Credentials for Multiple Registries]({{< relref "/docs/how-to/configure-multiple-credentials.md" >}}) โ Quick task-oriented setup
- [Tutorial: Credentials for OCM Controllers]({{< relref "/docs/tutorials/configure-credentials-for-controllers.md" >}}) โ How to provide credentials in Kubernetes environments
+
+## Related Documentation
+
+- [Reference: Consumer Identities]({{< relref "/docs/reference/credential-consumer-identities.md" >}}) โ Complete list of identity types, attributes, and credential properties
diff --git a/content/docs/concepts/ocm-controllers.md b/content/docs/concepts/ocm-controllers.md
index a57219ba8..22b9f7107 100644
--- a/content/docs/concepts/ocm-controllers.md
+++ b/content/docs/concepts/ocm-controllers.md
@@ -2,7 +2,7 @@
title: OCM Controllers
description: "Learn about the OCM controllers and their capabilities."
icon: "๐"
-weight: 43
+weight: 3
toc: true
---
diff --git a/content/docs/concepts/resolvers.md b/content/docs/concepts/resolvers.md
index 6b29d9e2f..db80b22ae 100644
--- a/content/docs/concepts/resolvers.md
+++ b/content/docs/concepts/resolvers.md
@@ -2,7 +2,7 @@
title: "Resolvers"
description: "Learn how OCM resolvers map component name patterns to repositories for recursive resolution."
icon: "๐"
-weight: 44
+weight: 7
toc: true
---
diff --git a/content/docs/concepts/signing-and-verification-concept.md b/content/docs/concepts/signing-and-verification-concept.md
new file mode 100644
index 000000000..e815a0c2f
--- /dev/null
+++ b/content/docs/concepts/signing-and-verification-concept.md
@@ -0,0 +1,261 @@
+---
+title: "Signing and Verification"
+description: "Understanding how OCM ensures component integrity and authenticity through cryptographic signatures."
+weight: 5
+toc: true
+---
+
+OCM uses cryptographic signatures to guarantee that component versions are authentic (created by a trusted party) and have not been tampered with during storage or transfer.
+
+## Why Sign Components?
+
+Software supply chains involve multiple stages: development, build, packaging, distribution, and deployment. At each stage, components could potentially be:
+
+- **Modified** โ malicious actors could inject code or alter resources
+- **Replaced** โ components could be swapped for compromised versions
+- **Misattributed** โ components could falsely claim to come from a trusted source
+
+Signing addresses these risks by creating a cryptographic proof of:
+
+1. **Integrity**: The component has not changed since it was signed
+2. **Authenticity**: The signature was created by someone with access to the private key
+3. **Provenance**: The signer cannot deny having signed the component
+
+## How OCM Signing Works
+
+```mermaid
+flowchart TB
+ subgraph sign ["Sign (Producer)"]
+ direction TB
+ A[Component Version] --> B[Normalize & Hash]
+ B --> C[Sign with Private Key]
+ C --> D["Signature embedded in CV"]
+ end
+
+ sign --> T["Transfer Component Version"]
+
+ T --> verify
+
+ subgraph verify ["Verify (Consumer)"]
+ direction TB
+ E[Component Version] --> F[Extract Signature]
+ E --> G[Normalize & Hash]
+ F --> H[Verify with Public Key]
+ G --> H
+ H --> I{Valid?}
+ I -->|Yes| VALID["โ Trusted"]
+ I -->|No| INVALID["โ Rejected"]
+ end
+```
+
+### Normalization and Digest Calculation
+
+OCM uses a two-layer approach to ensure consistent and reproducible digests:
+
+#### Component Descriptor Normalization
+
+Before hashing, the component descriptor is normalized into a canonical form, eliminating any ambiguities
+that could cause the same logical descriptor to produce different digests. The default normalization
+algorithm ([`jsonNormalisation/v4alpha1`](https://github.com/open-component-model/ocm-spec/blob/main/doc/04-extensions/04-algorithms/component-descriptor-normalization-algorithms.md#normalization-algorithms)) defines exactly how this canonical form is derived, ensuring
+identical component descriptors always yield the same digest.
+
+#### Artifact Digest Normalization
+
+Each artifact's digest is calculated using a type-specific normalization algorithm:
+
+| Artifact Type | Algorithm | Description |
+|---------------|-----------|-------------|
+| OCI artifact | `ociArtifactDigest/v1` | Digest of the OCI manifest (used for container images, Helm charts, and other OCI-native content) |
+| Generic blob | `genericBlobDigest/v1` | Direct hash of blob content (used for executables, blueprints, and other non-OCI content) |
+
+This allows OCM to use the most appropriate digest mechanism for each artifact type.
+OCI artifacts use their manifest digest rather than re-hashing the blob,
+improving performance and ensuring consistency with OCI registry behavior. Generic blobs are hashed directly.
+
+#### Recursive Component References
+
+When a component references other components, their digests are calculated recursively and embedded:
+
+```yaml
+references:
+ - componentName: ocm.software/helper
+ name: helper
+ version: 1.0.0
+ digest:
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: jsonNormalisation/v4alpha1
+ value: 01c211f5c9cfd7c40e5b84d66a2fb7d19cb0...
+```
+
+This creates a **complete integrity chain** โ verifying the root component automatically verifies all transitive dependencies.
+
+### What Gets Signed?
+
+OCM signs a **digest** of the component descriptor, which includes:
+
+- Component metadata (name, version, provider)
+- Resource declarations with their digests
+- Source references
+- Component references
+
+The signature does **not** cover the raw resource content directly โ instead, it covers the **digests** of those resources as recorded in the component descriptor. Crucially, the `access` field (which describes *where* a resource is stored) is **excluded** from the signed digest by the normalization process. This is a key design principle:
+
+- **Location-independent integrity** โ a component version can be transferred to a different registry (changing all `access` references) without invalidating its signature. The digest remains stable because it depends only on *what* the artifacts contain, not *where* they are stored.
+- Any change to resource content changes its digest, invalidating the signature.
+- Signature verification is fast (no need to re-hash large binaries).
+
+This separation of content identity from storage location is what enables secure delivery across environments: a producer signs a component version once, and consumers can verify it after any number of transfers โ even into air-gapped environments with completely different registries.
+
+The following example shows a signed component descriptor. Notice that each resource has both an `access` field (storage location) and a `digest` field (content hash). Only the `digest` is included in the signature โ the `access` can change freely during transfers:
+
+{{< details "Example Signed Component Descriptor" >}}
+```yaml
+component:
+ name: github.com/acme.org/helloworld
+ version: 1.0.0
+ provider: acme.org
+ resources:
+ - name: mylocalfile
+ type: blob
+ version: 1.0.0
+ relation: local
+ access: # NOT included in signature
+ type: localBlob
+ localReference: sha256:70a257...
+ mediaType: text/plain; charset=utf-8
+ digest: # Included in signature
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: genericBlobDigest/v1
+ value: 70a2577d7b649574cbbba99a2f2ebdf27904a4abf80c9729923ee67ea8d2d9d8
+ - name: image
+ type: ociImage
+ version: 1.0.0
+ relation: external
+ access: # NOT included in signature
+ type: ociArtifact
+ imageReference: ghcr.io/stefanprodan/podinfo:6.9.1@sha256:262578cd...
+ digest: # Included in signature
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: genericBlobDigest/v1
+ value: 262578cde928d5c9eba3bce079976444f624c13ed0afb741d90d5423877496cb
+signatures:
+ - name: default
+ digest:
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: jsonNormalisation/v4alpha1
+ value: 91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad
+ signature:
+ algorithm: RSASSA-PSS
+ mediaType: application/vnd.ocm.signature.rsa.pss
+ value: 7feb449229c6ffe368144995432befd1505d2d29...
+```
+{{< /details >}}
+
+### Signature Storage
+
+Signatures are stored as part of the component version:
+
+```yaml
+signatures:
+ - name: acme-release-signing
+ digest:
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: jsonNormalisation/v4alpha1
+ value: abc123...
+ signature:
+ algorithm: RSASSA-PSS
+ mediaType: application/vnd.ocm.signature.rsa
+ value:
+```
+
+A component version can have **multiple signatures** from different parties, enabling:
+
+- Separation of build and release signing
+- Multiple approval workflows
+- Cross-organizational trust chains
+
+## Supported Signing Algorithms
+
+OCM currently only supports RSA-based signing algorithms:
+
+| Algorithm | Type | Characteristics |
+|----------------------|------|-----------------|
+| RSASSA-PSS (default) | Asymmetric | Probabilistic, stronger security guarantees, recommended for new implementations |
+| RSA-PKCS#1 v1.5 | Asymmetric | Deterministic, widely supported, compatible with legacy systems |
+
+To override the default signing algorithm or encoding policy, see the --signer-spec flag in the [CLI reference]({{< relref "/docs/reference/ocm-cli/ocm_sign_component-version.md" >}}).
+The signer spec file configures only the algorithm and encoding policy โ credentials are always resolved separately via the [`.ocmconfig`]({{< relref "configure-multiple-credentials.md" >}}) file.
+
+For key management, OCM uses PEM-encoded key files configured in the `.ocmconfig`:
+
+- **Private keys**: Used by producers to sign component versions
+- **Public keys**: Distributed to consumers for verification
+
+See [How-to: Generate Signing Keys]({{< relref "docs/how-to/generate-signing-keys.md" >}}) for creating RSA key pairs.
+
+{{< callout context="tip" title="Upcoming Sigstore Support" icon="outline/bulb" >}}
+We are planning to add support for [Sigstore](https://www.sigstore.dev/) and Cosign as an additional signing mechanism.
+This will enable keyless signing workflows and improved supply chain security. Stay tuned for updates.
+{{< /callout >}}
+
+### Signature Encoding Policies
+
+The `signatureEncodingPolicy` in the [signer spec]({{< relref "/docs/reference/ocm-cli/ocm_sign_component-version.md" >}}) controls how the **signature output** is serialized and stored. It does **not** affect the format of key input files, which are always PEM-encoded.
+
+| Policy | Signature Format | Media Type | Certificate Chain | Verification Requires |
+|--------|-----------------|------------|-------------------|-----------------------|
+| **Plain** (default) | Hex-encoded raw bytes | `application/vnd.ocm.signature.rsa.pss` | Not embedded | Externally supplied public key |
+| **PEM** (experimental) | PEM `SIGNATURE` block + `CERTIFICATE` blocks | `application/x-pem-file` | Embedded in signature | Valid certificate chain in signature |
+
+#### Plain Encoding (Default)
+
+The raw RSA signature bytes are hex-encoded and stored directly. This is the most compact representation. Verification always requires the public key to be provided separately via `.ocmconfig` credentials.
+
+Example signature in a component descriptor:
+
+```yaml
+signature:
+ algorithm: RSASSA-PSS
+ mediaType: application/vnd.ocm.signature.rsa.pss
+ value: d1ea6e0cd850c8dbd0d20cd39b9c7954...
+```
+
+#### PEM Encoding (Experimental)
+
+The signature is wrapped in a PEM block of type `SIGNATURE`, optionally followed by the signer's X.509 certificate chain. This makes the signature **self-contained**: verifiers can extract and validate the public key from the embedded chain without needing a separately distributed key.
+
+Example of a PEM-encoded signature value:
+
+```text
+-----BEGIN SIGNATURE-----
+Signature Algorithm: RSASSA-PSS
+
+-----END SIGNATURE-----
+-----BEGIN CERTIFICATE-----
+
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+
+-----END CERTIFICATE-----
+```
+
+{{< callout context="caution" title="PEM encoding is experimental" icon="outline/alert-triangle" >}}
+This encoding policy may change or be deprecated in future versions. For production use, prefer the default Plain encoding.
+{{< /callout >}}
+
+{{< callout context="note" title="Key files vs. signature encoding" icon="outline/info-circle" >}}
+A common source of confusion: "PEM" in `signatureEncodingPolicy` refers to the **signature output** format, not the key input format. Input keys are **always** PEM-encoded files (e.g. `-----BEGIN RSA PRIVATE KEY-----`), regardless of which encoding policy is selected.
+
+When using PEM encoding for signing, the credential referenced by `public_key_pem` / `public_key_pem_file` must contain **X.509 certificates** (not bare public keys), because the certificate chain is embedded into the signature for self-contained verification.
+{{< /callout >}}
+
+## Next Steps
+
+- [How-to: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}) - Step-by-step creating RSA key pairs.
+- [How-to: Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) - Set up OCM to use your keys for signing and verification
+- [How-to: Sign a Component Version]({{< relref "sign-component-version.md" >}}) - Step-by-step signing instructions
+- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) - Step-by-step verification instructions
+
+## Related Documentation
+
+- [Concept: Component Versions]({{< relref "components.md" >}}) - Understanding component structure
diff --git a/content/docs/concepts/transfer-concept.md b/content/docs/concepts/transfer-concept.md
index 22397ad27..46a3e35b9 100644
--- a/content/docs/concepts/transfer-concept.md
+++ b/content/docs/concepts/transfer-concept.md
@@ -1,7 +1,7 @@
---
title: "Transfer and Transport"
description: "Understand how OCM moves component versions between repositories while preserving identity, integrity, and signatures."
-weight: 44
+weight: 4
toc: true
hasMermaid: true
---
diff --git a/content/docs/how-to/air-gap-transfer.md b/content/docs/how-to/air-gap-transfer.md
index 72e1797b9..7e36f7f60 100644
--- a/content/docs/how-to/air-gap-transfer.md
+++ b/content/docs/how-to/air-gap-transfer.md
@@ -1,7 +1,7 @@
---
-title: "Transfer Components Across an Air Gap"
+title: "Transfer Components across an Air Gap"
description: "Transfer a signed OCM component version into an air-gapped registry via a CTF archive."
-weight: 10
+weight: 1
toc: true
---
@@ -9,13 +9,11 @@ toc: true
Transfer a signed component version from a source registry into an air-gapped target registry using a CTF archive as the transport medium. An air-gapped environment is a network that is physically isolated from untrusted networks such as the public internet.
-{{< callout context="note" title="You will end up with" >}}
+## You'll end up with
- A verified, signed component version available in your air-gapped registry
- All resource artifacts (container images, Helm charts) copied into the target registry
-{{< /callout >}}
-
**Estimated time:** ~10 minutes
## Prerequisites
diff --git a/content/docs/how-to/configure-credentials-ocm-controllers.md b/content/docs/how-to/configure-credentials-ocm-controllers.md
new file mode 100644
index 000000000..2b38d88b4
--- /dev/null
+++ b/content/docs/how-to/configure-credentials-ocm-controllers.md
@@ -0,0 +1,318 @@
+---
+title: "Configure Credentials for OCM Controllers"
+description: "Configure authentication for OCM Controllers to access private OCM repositories."
+weight: 2
+toc: true
+---
+
+## Goal
+
+Configure credentials to allow OCM Controllers to access OCM components stored in private OCI registries.
+
+## You will end up with
+
+- A Kubernetes secret containing registry credentials
+- OCM Controller resources configured to use these credentials
+- Verified access to private OCM repositories
+
+**Estimated time:** ~5 minutes
+
+## Prerequisites
+
+- [Controller environment]({{< relref "setup-controller-environment.md" >}}) set up (OCM Controllers, kro and Flux in a Kubernetes cluster)
+- [OCM CLI]({{< relref "ocm-cli-installation.md" >}}) installed
+- [kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl) installed
+- Credentials for your private OCI registry (username and password, Docker config file, or OCM CLI config file)
+- The registry URL where your OCM components are stored
+
+{{< callout context="caution" title="Security Warning" icon="outline/alert-triangle" >}}
+Kubernetes secrets are only base64-encoded, not encrypted.
+Ensure proper RBAC policies to restrict access to secrets containing credentials.
+{{< /callout >}}
+
+## Configure and propagate credentials for OCM resources
+
+{{< steps >}}
+{{< step >}}
+
+### Create a Kubernetes secret with credentials
+
+Choose one of two methods to create the secret:
+
+{{< tabs "credential-methods" >}}
+{{< tab "OCM Config (.ocmconfig)" >}}
+
+Use this method if you already use the OCM CLI and have an `.ocmconfig` file configured with credentials.
+[Configure Credentials for Multiple Registries]({{< relref "configure-multiple-credentials.md" >}}) helps with creating this file.
+
+#### Create the secret from your existing `.ocmconfig` file
+
+Point the command to your existing `.ocmconfig` file. The secret key must be named `.ocmconfig` (with the dot).
+The `--from-file` command automatically uses the filename as the key.
+
+```bash
+kubectl create secret generic ocm-secret --from-file=
+```
+
+
+You should see this output
+
+```text
+secret/ocm-secret created
+```
+
+
+{{< /tab >}}
+
+{{< tab "Docker Config (dockerconfigjson)" >}}
+
+#### Option A: From existing Docker config file
+
+```bash
+kubectl create secret docker-registry ocm-secret --from-file=
+```
+
+
+You should see this output
+
+```text
+secret/ocm-secret created
+```
+
+
+#### Option B: Create from command line
+
+```bash
+kubectl create secret docker-registry ocm-secret \
+ --docker-username= \
+ --docker-password= \
+ --docker-server=
+```
+
+
+You should see this output
+
+```text
+secret/ocm-secret created
+```
+
+
+{{< /tab >}}
+{{< /tabs >}}
+{{< /step >}}
+
+{{< step >}}
+
+### Reference the secret in OCM Controller resources
+
+Add the `spec.ocmConfig` field to your OCM Controller resources to use the credentials.
+Create a `repository.yaml` with a `Repository` resource.
+Replace `` with your actual namespace in the registry URL.
+
+```yaml
+apiVersion: delivery.ocm.software/v1alpha1
+kind: Repository
+metadata:
+ name: my-repository
+spec:
+ repositorySpec:
+ baseUrl: ghcr.io/
+ type: OCIRegistry
+ interval: 1m
+ ocmConfig:
+ - kind: Secret
+ name: ocm-secret
+```
+
+Apply the resource:
+
+```bash
+kubectl apply -f repository.yaml
+```
+
+
+You should see this output
+
+```text
+repository.delivery.ocm.software/my-repository created
+```
+
+
+
+Verify the resource is ready and can access your registry (due to the complex status field of OCM resources, to show the status, we need to use `custom-columns`)
+
+```shell
+kubectl get repository my-repository -o 'custom-columns=NAME:.metadata.name,READY:.status.conditions[0].message,AGE:.metadata.creationTimestamp'
+```
+
+
+You should see this output
+
+```text
+NAME READY AGE
+my-repository Successfully reconciled OCM repository 2026-02-25T15:45:49Z
+```
+
+
+{{< /step >}}
+
+{{< step >}}
+
+### Propagate credentials to dependent resources (optional)
+
+OCM Controller resources can inherit credentials from referenced resources, reducing duplication.
+Create a `component.yaml` with a component referencing the OCM config from the `Repository` resource you just created.
+Specify the component reference to an existing component in your registry.
+
+```yaml
+apiVersion: delivery.ocm.software/v1alpha1
+kind: Component
+metadata:
+ name: my-component
+spec:
+ component: /my-component
+ repositoryRef:
+ name: my-repository
+ semver: 1.0.0
+ interval: 1m
+ ocmConfig:
+ - kind: Repository
+ apiVersion: delivery.ocm.software/v1alpha1
+ name: my-repository
+```
+
+The `Component` resource inherits credentials from the `Repository` resource named `my-repository`.
+
+Apply the resource:
+
+```shell
+kubectl apply -f component.yaml
+```
+
+
+You should see this output
+
+```text
+component.delivery.ocm.software/my-component created
+```
+
+
+
+Verify the resource is ready and can access your registry (due to the complex status field of OCM resources, to show the status, we need to use `custom-columns`)
+
+```shell
+kubectl get component my-component -o 'custom-columns=NAME:.metadata.name,READY:.status.conditions[0].message,AGE:.metadata.creationTimestamp'
+```
+
+
+You should see this output
+
+```text
+NAME READY AGE
+my-component Applied version 1.0.0 2026-02-25T15:49:58Z
+```
+
+
+### Credential propagation
+
+- Credentials are propagated by default when referencing other OCM Controller resources
+- You must still specify the `ocmConfig` field on each resource that needs credentials
+- Credentials are not automatically inherited across all resources in the cluster
+
+{{< /step >}}
+
+{{< /steps >}}
+
+## Advanced: Prevent credential propagation
+
+To prevent a resource from propagating its credentials to dependent resources, set the `policy` to `DoNotPropagate`:
+
+```yaml
+apiVersion: delivery.ocm.software/v1alpha1
+kind: Component
+metadata:
+ name: my-component
+spec:
+ component: /my-component
+ repositoryRef:
+ name: my-repository
+ semver: 1.0.0
+ interval: 1m
+ ocmConfig:
+ - kind: Repository
+ apiVersion: delivery.ocm.software/v1alpha1
+ name: my-repository
+ policy: DoNotPropagate
+```
+
+## Troubleshooting
+
+### Symptom: "failed to list versions: response status code 401: unauthorized"
+
+**Cause:** The credentials are incorrect, missing, or the secret is not referenced in the resource.
+
+**Fix:**
+
+1. Verify the secret exists:
+ ```bash
+ kubectl get secret ocm-secret
+ ```
+
+2. Check the secret contains the correct credentials:
+ ```bash
+ kubectl get secret ocm-secret -o yaml
+ ```
+
+3. Ensure the `ocmConfig` field references the correct secret name in your resource.
+
+### Symptom: "failed to read OCM config: key .ocmconfig not found in secret"
+
+**Cause:** When using the OCM config method, the secret key must be named `.ocmconfig`.
+
+**Fix:**
+
+Recreate the secret with the correct key name, e.g., referencing an `.ocmconfig` file in the same folder:
+
+```bash
+kubectl delete secret ocm-secret
+kubectl create secret generic ocm-secret --from-file=./.ocmconfig
+```
+
+The filename in `--from-file` must be `.ocmconfig` (with the dot).
+
+### Symptom: "Component shows `Not Ready` with credential errors"
+
+**Cause:** The `ocmConfig` is not specified or references a non-existent resource.
+
+**Fix:**
+
+Add the `ocmConfig` field to your Component resource:
+
+```yaml
+spec:
+ # ...existing configuration...
+ ocmConfig:
+ - kind: Repository
+ apiVersion: delivery.ocm.software/v1alpha1
+ name: my-repository
+```
+
+Or reference the secret directly:
+
+```yaml
+spec:
+ # ...existing configuration...
+ ocmConfig:
+ - kind: Secret
+ name: ocm-secret
+```
+
+## Next Steps
+
+- [Tutorial: Deploy a Helm Chart]({{< relref "deploy-helm-chart.md" >}}) - Use the OCM Controllers to deploy applications from component versions
+- [How-To: Configure Credentials for Multiple Registries]({{< relref "configure-multiple-credentials.md" >}}) - Configure credentials for multiple registries in an `.ocmconfig` file
+
+## Related documentation
+
+- [Concept: OCM Controllers]({{< relref "ocm-controllers.md" >}})
+- [Concept: Credential System]({{< relref "credential-system.md" >}})
diff --git a/content/docs/how-to/configure-multiple-credentials.md b/content/docs/how-to/configure-multiple-credentials.md
index 70a6900fc..07db6ef6e 100644
--- a/content/docs/how-to/configure-multiple-credentials.md
+++ b/content/docs/how-to/configure-multiple-credentials.md
@@ -2,7 +2,7 @@
title: "Configure Credentials for Multiple Registries"
description: "Set up OCM credentials to authenticate against multiple OCI registries with explicit entries and Docker config fallback."
icon: "๐"
-weight: 45
+weight: 3
toc: true
---
@@ -10,17 +10,15 @@ toc: true
Configure OCM to authenticate against multiple OCI registries โ pinning explicit credentials for specific registries while using Docker config as a catch-all fallback.
-{{< callout context="note" >}}
-**You will end up with**
+## You'll end up with
- An OCM config file that resolves credentials automatically for every `ocm` command
- Explicit control over specific registry paths with Docker config covering the rest
-{{< /callout >}}
## Prerequisites
- [OCM CLI]({{< relref "/docs/getting-started/ocm-cli-installation.md" >}}) installed
-- Docker CLI installed and `docker login` run for any registries you want as fallback (creates `~/.docker/config.json`)
+- Docker CLI installed and `docker login` run for any registries you want as fallback (creates `$HOME/.docker/config.json`)
## Steps
@@ -29,7 +27,7 @@ Configure OCM to authenticate against multiple OCI registries โ pinning explic
{{< step >}}
**Identity by hostname only**
-Create `~/.ocmconfig` with an identity that matches **any path** on a hostname:
+Create `$HOME/.ocmconfig` with an identity that matches **any path** on a hostname:
```yaml
type: generic.config.ocm.software/v1
@@ -122,10 +120,10 @@ configurations:
repositories:
- repository:
type: DockerConfig/v1
- dockerConfigFile: "~/.docker/config.json" # Fallback for unmatched registries
+ dockerConfigFile: "$HOME/.docker/config.json" # Fallback for unmatched registries
```
-**Identity:** Derived from the `auths` section in Docker config file (`~/.docker/config.json`)
+**Identity:** Derived from the `auths` section in Docker config file (`$HOME/.docker/config.json`)
**Matches:** Any registry with credentials in Docker config that wasn't matched by a consumer
**Differs from steps 1-3:** This is a **repository** (not a consumer). OCM checks all consumers first, then falls back to repositories. Use this for registries you authenticate with `docker login`.
{{< /step >}}
@@ -174,7 +172,7 @@ configurations:
repositories:
- repository:
type: DockerConfig/v1
- dockerConfigFile: "~/.docker/config.json"
+ dockerConfigFile: "$HOME/.docker/config.json"
```
**Resolution order** (see [Credential Resolution Tutorial]({{< relref "/docs/tutorials/credential-resolution.md" >}}) for details):
diff --git a/content/docs/how-to/configure-signing-credentials.md b/content/docs/how-to/configure-signing-credentials.md
new file mode 100644
index 000000000..e57e30121
--- /dev/null
+++ b/content/docs/how-to/configure-signing-credentials.md
@@ -0,0 +1,192 @@
+---
+title: "Configure Credentials for Signing"
+description: "Configure OCM signing and verification keys using .ocmconfig or signer specification files."
+icon: "๐"
+weight: 4
+toc: true
+---
+
+Set up credential configuration so OCM can find your signing keys when signing or verifying component versions.
+
+## You'll end up with
+
+- A configured `.ocmconfig` file that OCM uses to locate your signing keys
+- Ability to sign and verify component versions without specifying key paths manually
+
+**Estimated time:** ~3 minutes
+
+## Prerequisites
+
+- [OCM CLI installed]({{< relref "docs/getting-started/ocm-cli-installation.md" >}})
+- [RSA key pair generated]({{< relref "generate-signing-keys.md" >}})
+- A component version to test your configuration (we'll use `github.com/acme.org/helloworld:1.0.0` from the [getting started guide]({{< relref "create-component-version.md" >}})) in this guide, but you can use any component version you have.
+
+## Steps
+
+{{< steps >}}
+{{< step >}}
+
+## Create your .ocmconfig file (optional)
+
+Create `$HOME/.ocmconfig` if it doesn't exist:
+
+```bash
+touch $HOME/.ocmconfig
+```
+
+{{< /step >}}
+
+{{< step >}}
+
+## Add the signing credential configuration to your .ocmconfig
+
+Copy the following YAML into your `.ocmconfig` file.
+
+We use the key pair you created in the [How-To: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}).
+If you already have a key pair that is located in a different location, simply update the file paths accordingly.
+
+All three identity attributes (`type`, `algorithm`, `signature`) are required for credential matching.
+See the [Consumer Identities Reference]({{< relref "docs/reference/credential-consumer-identities.md" >}}) for details.
+
+```yaml
+type: generic.config.ocm.software/v1
+configurations:
+ - type: credentials.config.ocm.software
+ consumers:
+ - identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: default
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /tmp/keys/private-key.pem
+ public_key_pem_file: /tmp/keys/public-key.pem
+```
+
+**Key paths:**
+
+- `private_key_pem_file` - Required for **signing** operations
+- `public_key_pem_file` - Required for **verification** operations
+
+{{< /step >}}
+
+{{< step >}}
+
+## Test the configuration
+
+```bash
+ocm sign cv --dry-run /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0
+```
+
+If configured correctly, the dry run completes without "no private key found" errors.
+
+{{< details "Expected output" >}}
+
+```text
+time=2026-03-12T17:05:46.428+01:00 level=INFO msg="no signer spec file provided, using default" algorithm=RSASSA-PSS encodingPolicy=Plain
+digest:
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: jsonNormalisation/v4alpha1
+ value: 91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad
+name: default
+signature:
+ algorithm: RSASSA-PSS
+ mediaType: application/vnd.ocm.signature.rsa.pss
+ value: 0cb48e5867575151fca94e995fc03c6df734163aed8fbee46231c9b36e59956d51df60263d8cd58e3de7662b2fbc3c4f800107d96b4fc27e7a16807388f7e5a73d2269290c0f367d0eb92d930b485054911c10e22ed1fe6c5bfab441f1af28d8deec4df8d67ca5a54fa4495510e2fff809fe8162f875d6b91a6bc1d29e7466f113a9d9d23f16956588a5792e4c7553a8ceb6f8c630aa6090aceb83e763734c33902d4697beadc65a6bc4761e6221ec49a6882bd46c87a14c5a5c24c70bf95880d0a43b176a5bf6200837ce344abff360e13f07db35290b3e1e3639a0fdc87252542965ea95231444807564c718734ccf10a5dbbb58a8b11f7df418002e6bebfa
+
+time=2026-03-12T17:05:46.437+01:00 level=INFO msg="dry run: signature not persisted"
+```
+
+{{< /details >}}
+{{< /step >}}
+
+{{< /steps >}}
+
+### Configure multiple signing identities
+
+For different environments (e.g., dev and prod) you can create different key pairs and
+add multiple consumer blocks to your `.ocmconfig` with different `signature` names:
+
+```yaml
+type: generic.config.ocm.software/v1
+configurations:
+ - type: credentials.config.ocm.software
+ consumers:
+ - identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: dev
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /tmp/keys/dev/private-key.pem
+ public_key_pem_file: /tmp/keys/dev/public-key.pem
+ - identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: prod
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /tmp/keys/prod/private-key.pem
+ public_key_pem_file: /tmp/keys/prod/public-key.pem
+```
+
+Specify the signature name when signing:
+
+```bash
+ocm sign cv --signature dev /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0
+ocm sign cv --signature prod /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0
+```
+
+## Identity Attributes Reference
+
+The consumer identity for RSA signing/verification supports these attributes:
+
+| Attribute | Required | Description |
+|-------------|----------|-----------------------------------------------------|
+| `type` | Yes | Must be `RSA/v1alpha1` |
+| `algorithm` | Yes | `RSASSA-PSS` (default) or `RSASSA-PKCS1-V1_5`. Required for credential matching โ the lookup always includes this field. |
+| `signature` | Yes | Logical name for this key configuration (default: `default`). Must match the `--signature` CLI flag. |
+
+## Troubleshooting
+
+### Symptom: "no private key found"
+
+**Cause:** OCM cannot find a matching consumer entry in `.ocmconfig`.
+
+**Fix:** Ensure:
+
+- The file path `private_key_pem_file` is correct and the file exists
+- The `algorithm` attribute is present in the identity (e.g. `algorithm: RSASSA-PSS`). See [Consumer Identities Reference]({{< relref "docs/reference/credential-consumer-identities.md" >}}).
+- The `signature` name matches what you're using (or is `default` if not specified)
+- The file is valid YAML with correct indentation
+
+### Symptom: "permission denied" reading key file
+
+**Cause:** Key file has restrictive permissions.
+
+**Fix:** Ensure your user can read the key file:
+
+```bash
+chmod 600 /tmp/keys/private-key.pem
+ls -la /tmp/keys/private-key.pem
+```
+
+## CLI Reference
+
+| Command | Description |
+|--------------------------------------------------------------------------|-------------|
+| [`ocm sign cv --dry-run`]({{< relref "/docs/reference/ocm-cli/ocm_sign_component-version.md" >}}) | Test signing configuration |
+| [`ocm verify cv`]({{< relref "/docs/reference/ocm-cli/ocm_verify_component-version.md" >}}) | Test verification configuration |
+
+## Next Steps
+
+- [How-to: Sign Component Versions]({{< relref "sign-component-version.md" >}}) - Sign components with your configured credentials
+- [How-to: Verify Component Versions]({{< relref "verify-component-version.md" >}}) - Verify signatures using public keys
+
+## Related Documentation
+
+- [How-to: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}) - Create the key pair needed for this configuration
+- [Concept: Signing and Verification]({{< relref "signing-and-verification-concept.md" >}}) - Understand how OCM signing works
diff --git a/content/docs/how-to/download-resources-from-component-versions.md b/content/docs/how-to/download-resources-from-component-versions.md
index 866571cba..10e61fb67 100644
--- a/content/docs/how-to/download-resources-from-component-versions.md
+++ b/content/docs/how-to/download-resources-from-component-versions.md
@@ -2,12 +2,14 @@
title: "Download Resources from Component Versions"
description: "Extract resources from OCM component versions to your local filesystem."
icon: "๐ฅ"
-weight: 10
+weight: 5
toc: true
---
-This guide shows you how to download resources from a component version using the OCM CLI.
-You'll learn how to fetch specific resources, optionally transform them to their native format,
+## Goal
+
+Download resources from a component version using the OCM CLI.
+Learn how to fetch specific resources, optionally transform them to their native format,
and save them to your local filesystem.
## You'll end up with
@@ -15,9 +17,7 @@ and save them to your local filesystem.
- A resource file downloaded from a component version
- Optionally a resource transformed to its native format (e.g., Helm chart `.tgz`)
-## Estimated time
-
-~5 minutes
+**Estimated time:** ~5 minutes
## How it works
diff --git a/content/docs/how-to/generate-signing-keys.md b/content/docs/how-to/generate-signing-keys.md
new file mode 100644
index 000000000..a5b270d16
--- /dev/null
+++ b/content/docs/how-to/generate-signing-keys.md
@@ -0,0 +1,119 @@
+---
+title: "Generate Signing Keys"
+description: "Create an RSA key pair for signing and verifying OCM component versions."
+weight: 10
+toc: true
+---
+
+## Goal
+
+Generate an RSA key pair that can be used to sign and verify OCM component versions.
+
+## You'll end up with
+
+- A private key file for signing component versions
+- A public key file for sharing with consumers who need to verify signatures
+
+**Estimated time:** ~2 minutes
+
+## Prerequisites
+
+- [OpenSSL](https://openssl-library.org) installed on your system (typically pre-installed on Linux/macOS)
+
+## Generate an RSA key pair
+
+To be able to use the keys across all How-to guides, we'll create them in your home directory (`$HOME`).
+
+{{< steps >}}
+
+{{< step >}}
+
+### Generate the private key
+
+Create a folder `/tmp/keys` and create a 4096-bit RSA private key in it:
+
+```bash
+mkdir /tmp/keys && cd /tmp/keys
+openssl genpkey -algorithm RSA -out private-key.pem -pkeyopt rsa_keygen_bits:4096
+```
+
+Verify the private key file was created:
+
+```bash
+ls -la /tmp/keys
+```
+
+> โ ๏ธ **Keep your private key secure!** โ ๏ธ
+> Anyone with access to this file can sign components as you.
+> Store it in a secure location and never commit it to version control.
+
+{{< /step >}}
+
+{{< step >}}
+
+### Extract the public key
+
+Derive the public key from your private key:
+
+```bash
+openssl rsa -in private-key.pem -pubout -out public-key.pem
+```
+
+This creates `public-key.pem` which you can safely share with others.
+
+{{< /step >}}
+
+{{< step >}}
+
+### Verify the keys were created
+
+```bash
+ls -la *.pem
+```
+
+You should see both files:
+
+```text
+-rw------- 1 user group 3272 Jan 15 10:00 private-key.pem
+-rw-r--r-- 1 user group 800 Jan 15 10:00 public-key.pem
+```
+
+{{< /step >}}
+
+{{< /steps >}}
+
+## Key management tips
+
+| Key | Who has it | Purpose |
+|-----|------------|---------|
+| **Private key** | Only you (the signer) | Sign component versions |
+| **Public key** | Anyone who needs to verify | Verify signatures |
+
+- Use different key pairs for different environments (dev, staging, production)
+- Document which public key corresponds to which signing identity
+- Consider key rotation policies for long-lived projects
+
+## Troubleshooting
+
+### Symptom: "command not found: openssl"
+
+**Fix:** Install OpenSSL:
+
+- macOS: `brew install openssl`
+- Ubuntu/Debian: `sudo apt-get install openssl`
+- RHEL/CentOS: `sudo dnf install openssl`
+
+### Symptom: Permission denied when creating files
+
+**Fix:** Ensure you have write permissions in the current directory, or specify a full path where you have access.
+
+## Next steps
+
+- [How-to: Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) - Set up OCM to use your keys for signing and verification
+- [How-to: Sign a Component Version]({{< relref "sign-component-version.md" >}}) - Use your private key to sign components
+- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) - Share your public key and verify signatures
+
+## Related documentation
+
+- [Concept: Signing and Verification]({{< relref "signing-and-verification-concept.md" >}}) - Understand how OCM signing and verification works
+- [Tutorial: Sign Your First Component]({{< relref "signing-and-verification.md" >}}) - A hands-on tutorial for signing components end-to-end
diff --git a/content/docs/how-to/legacy-credential-compatibility.md b/content/docs/how-to/legacy-credential-compatibility.md
index 0e263d3fa..72c38c25b 100644
--- a/content/docs/how-to/legacy-credential-compatibility.md
+++ b/content/docs/how-to/legacy-credential-compatibility.md
@@ -2,7 +2,7 @@
title: "Migrate Legacy Credentials"
description: "Update your legacy OCM credential configuration to work with the new OCM."
icon: "๐"
-weight: 46
+weight: 6
toc: true
---
@@ -21,7 +21,7 @@ Migrate an existing legacy OCM `.ocmconfig` file so it works with the new OCM.
## Steps
-Suppose you have the following legacy config in `~/.ocmconfig`:
+Suppose you have the following legacy config in `$HOME/.ocmconfig`:
```yaml
type: generic.config.ocm.software/v1
@@ -40,7 +40,7 @@ configurations:
repositories:
- repository:
type: DockerConfig/v1
- dockerConfigFile: "~/.docker/config.json"
+ dockerConfigFile: "$HOME/.docker/config.json"
```
The following steps walk you through each change needed to make this config work with the new OCM.
@@ -100,7 +100,7 @@ The following parts of your legacy config work unchanged in the new OCM:
- `Credentials/v1` type and `properties` field
- `DockerConfig/v1` repository entries
- `dockerConfigFile` and `dockerConfig` fields
-- Config file locations (`~/.ocmconfig`, `$OCM_CONFIG`)
+- Config file locations (`$HOME/.ocmconfig`, `$OCM_CONFIG`)
Your migrated config now looks like this:
@@ -121,7 +121,7 @@ configurations:
repositories:
- repository:
type: DockerConfig/v1
- dockerConfigFile: "~/.docker/config.json"
+ dockerConfigFile: "$HOME/.docker/config.json"
```
{{< /step >}}
diff --git a/content/docs/how-to/migrate-from-deprecated-resolvers.md b/content/docs/how-to/migrate-from-deprecated-resolvers.md
index e5ec5b3ba..ba4d1d47c 100644
--- a/content/docs/how-to/migrate-from-deprecated-resolvers.md
+++ b/content/docs/how-to/migrate-from-deprecated-resolvers.md
@@ -29,7 +29,7 @@ against component names, which is simpler and more efficient.
## Steps
-Suppose you have the following legacy resolver config in `~/.ocmconfig`:
+Suppose you have the following legacy resolver config in `$HOME/.ocmconfig`:
```yaml
type: generic.config.ocm.software/v1
diff --git a/content/docs/how-to/resolve-components-from-multiple-repositories.md b/content/docs/how-to/resolve-components-from-multiple-repositories.md
index f85d8f8a0..068142652 100644
--- a/content/docs/how-to/resolve-components-from-multiple-repositories.md
+++ b/content/docs/how-to/resolve-components-from-multiple-repositories.md
@@ -1,7 +1,7 @@
---
-title: "Resolving Components Across Multiple Registries"
+title: "Resolving Components across Multiple Registries"
description: "Configure resolvers to recursively resolve component references distributed across multiple OCI registries."
-weight: 10
+weight: 7
toc: true
---
@@ -36,7 +36,7 @@ configurations:
repositories:
- repository:
type: DockerConfig/v1
- dockerConfigFile: "~/.docker/config.json"
+ dockerConfigFile: "$HOME/.docker/config.json"
- type: resolvers.config.ocm.software/v1alpha1
resolvers:
- repository:
diff --git a/content/docs/how-to/sign-component-version.md b/content/docs/how-to/sign-component-version.md
new file mode 100644
index 000000000..27471852e
--- /dev/null
+++ b/content/docs/how-to/sign-component-version.md
@@ -0,0 +1,143 @@
+---
+title: "Sign Component Versions"
+description: "Cryptographically sign a component version to establish authenticity and enable verification."
+icon: "๐"
+weight: 8
+toc: true
+---
+
+## Goal
+
+Sign a component version to certify its authenticity and enable downstream verification.
+
+## You'll end up with
+
+- A component version with a cryptographic signature attached
+
+**Estimated time:** ~3 minutes
+
+## Prerequisites
+
+- [OCM CLI installed]({{< relref "ocm-cli-installation.md" >}})
+- [Signing credentials configured]({{< relref "docs/how-to/configure-signing-credentials.md" >}})
+- A component version in a CTF archive or OCI registry (we'll use `github.com/acme.org/helloworld:1.0.0` from the [getting started guide]({{< relref "create-component-version.md" >}})) in this guide, but you can use any component version you have.
+
+## Steps
+
+{{< steps >}}
+
+{{< step >}}
+
+### Sign the component version
+
+Run the sign command against your component:
+
+{{< tabs >}}
+{{< tab "Local CTF Archive" >}}
+
+```bash
+ocm sign cv /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0
+```
+{{< /tab >}}
+{{< tab "Remote OCI Registry" >}}
+
+```bash
+ocm sign cv ghcr.io///github.com/acme.org/helloworld:1.0.0
+```
+{{< /tab >}}
+{{< /tabs >}}
+
+{{< details "Expected output from signing" >}}
+
+```text
+time=2026-03-12T21:45:16.517+01:00 level=INFO msg="no signer spec file provided, using default" algorithm=RSASSA-PSS encodingPolicy=Plain
+digest:
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: jsonNormalisation/v4alpha1
+ value: 91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad
+name: default
+signature:
+ algorithm: RSASSA-PSS
+ mediaType: application/vnd.ocm.signature.rsa.pss
+ value: d1ea6e0cd850c8dbd0d20cd39b9c79547005e56a3df08974543e8a8b2f4ce17784d473a9397928432dfac1cefbf9c74087d3f0432275d692025b65d4feca6acabd6ed2cb495f77026a699f3e5009515d6b845cd698c210718a0788dbb08c4a345dae6c64a39c652edc1ede71ff2c7b0d4315351abede51c136d680b478a0ae9ae1a88916b289c59a8d263a8ad2223386f76104356b060caf8643405646bf106811cddbf7df1cdc7ba2a8323a1803d76238a9cd5bf700752ce4d9666acdb361f55d4fbda99ff794cf6d743f56a3d974441e708a4455686d5aefe1d22bc068c2e91acd18492af8624c0e6ef62afac0e176abd1db581ec12871281ad26f996c64d8ec164e9b9100f19d37491d2c13464f40c51ca8e0521e17578df4d8a89deb141c0fe7f4833ddee19ebffe292a065cf1a428860280905826469f1d44fed54c8654b94b32d19a798d6e40518fb53988f23a6266c968706d5276c1dc2664085337d169d1375413b75b86fc379bda3c1abab27c646502850eb27d88bdad4400d08ec1ca8dfe98806dff2bfd24cc1f50bd74fd632a881b99f72cf5ef7b20df910da663410b7021afffd5bd983805d461d27585225c933d52a2bea3a438c65a494b03d17fc9421fc02dff7d5bc36782fa5e9d1314bd5bfc291fed341fad084e3a5bb5da895fdaa00d6947c66e8cf0ed671ec44591c5fb84898e3263190c13d511380ad5
+
+time=2026-03-12T21:45:16.532+01:00 level=INFO msg="signed successfully" name=default digest=91dd197868907487e62872695db1fa7b397fde300bcbae23e24abc188fb147ad hashAlgorithm=SHA-256 normalisationAlgorithm=jsonNormalisation/v4alpha1
+```
+{{< /details >}}
+{{< /step >}}
+
+{{< step >}}
+
+### Use a named signature (optional)
+
+If you have multiple signing configurations in your `.ocmconfig`,
+use `--signature` flag to specify which one to use.
+Without the flag, OCM uses the configuration named `default`. In this example, we'll use a configuration named `prod`:
+
+```bash
+ocm sign cv --signature prod ghcr.io///github.com/acme.org/helloworld:1.0.0
+```
+
+{{< /step >}}
+
+{{< step >}}
+
+### Verify the signature was added
+
+Check that the signature is present in the component descriptor:
+
+```bash
+ocm get cv /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml
+```
+
+Look for the `signatures` section in the output:
+
+```yaml
+signatures:
+ - name: default
+ digest:
+ hashAlgorithm: SHA-256
+ normalisationAlgorithm: jsonNormalisation/v4alpha1
+ value: 91dd197...
+ signature:
+ algorithm: RSASSA-PSS
+ value: d1ea6e0...
+```
+
+{{< /step >}}
+{{< /steps >}}
+
+## Troubleshooting
+
+### Symptom: "no private key found"
+
+**Cause:** OCM cannot find a matching signing configuration in `.ocmconfig`.
+
+**Fix:** Ensure your `.ocmconfig` has a consumer entry with matching `signature` name:
+
+- Without `--signature` flag: must have `signature: default`
+- With `--signature prod`: must have `signature: prod`
+
+See [Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) guide.
+
+### Symptom: "signature already exists"
+
+**Cause:** The component version already has a signature with this name.
+
+**Fix:** Use a different signature name with `--signature newname`, or remove the existing signature first.
+
+### Symptom: Permission denied on registry
+
+**Cause:** Missing write access to the OCI registry.
+
+**Fix:** Ensure you're `.ocmconfig` file is configure with credentials for the registry.
+See [How-To: Configure Credentials for Multiple Registries]({{< relref "configure-multiple-credentials.md" >}}) for details.
+
+## Next Steps
+
+- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) โ Verify signatures using public keys
+
+## Related Documentation
+
+- [Concept: Signing and Verification]({{< relref "signing-and-verification-concept.md" >}}) โ Understand how OCM signing works
+- [Tutorial: Sign and Verify Components]({{< relref "signing-and-verification.md" >}}) โ End-to-end signing workflow
diff --git a/content/docs/how-to/verify-component-version.md b/content/docs/how-to/verify-component-version.md
new file mode 100644
index 000000000..b8f763d40
--- /dev/null
+++ b/content/docs/how-to/verify-component-version.md
@@ -0,0 +1,138 @@
+---
+title: "Verify Component Versions"
+description: "Validate component version signatures to ensure authenticity and integrity."
+icon: "๐"
+weight: 9
+toc: true
+---
+
+## You'll end up with
+
+- Confidence that a component version is authentic and hasn't been tampered with
+
+**Estimated time:** ~3 minutes
+
+## Prerequisites
+
+- [OCM CLI installed]({{< relref "ocm-cli-installation.md" >}})
+- [Verification credentials configured]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) with the public key
+- A signed component version to verify
+
+## Steps
+
+{{< steps >}}
+
+{{< step >}}
+
+### Verify the component version
+
+Run the verify command against your signed component:
+
+```bash
+ocm verify cv //:
+```
+
+**Local CTF Archive:**
+
+```bash
+ocm verify cv ./transport-archive//github.com/acme.org/helloworld:1.0.0
+```
+
+**Remote OCI Registry:**
+
+```bash
+ocm verify cv ghcr.io/myorg/components//github.com/acme.org/helloworld:1.0.0
+```
+
+
+Expected output
+
+```text
+time=2025-11-19T15:58:22.431+01:00 level=INFO msg="verifying signature" name=default
+time=2025-11-19T15:58:22.435+01:00 level=INFO msg="signature verification completed" name=default duration=4.287541ms
+time=2025-11-19T15:58:22.435+01:00 level=INFO msg="SIGNATURE VERIFICATION SUCCESSFUL"
+```
+
+
+
+The command exits with status code `0` on success.
+
+{{< /step >}}
+
+{{< step >}}
+
+### Verify a specific signature (optional)
+
+If the component has multiple signatures, specify which one to verify:
+
+```bash
+ocm verify cv --signature prod ghcr.io/myorg/components//github.com/acme.org/helloworld:1.0.0
+```
+
+> ๐ Without the `--signature` flag, OCM uses the configuration named `default`.
+
+{{< /step >}}
+
+{{< step >}}
+
+### List available signatures (optional)
+
+View all signatures in a component version:
+
+```bash
+ocm get cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 10 signatures:
+```
+
+{{< /step >}}
+
+{{< /steps >}}
+
+## Troubleshooting
+
+### Symptom: "signature verification failed"
+
+**Cause:** Public key doesn't match the signing private key, or the component was modified after signing.
+
+**Fix:** Ensure you're using the correct public key that corresponds to the private key used for signing:
+
+```bash
+# Check which signature names exist
+ocm get cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 3 "signatures:"
+
+# Verify with the correct signature name
+ocm verify cv --signature ./transport-archive//github.com/acme.org/helloworld:1.0.0
+```
+
+### Symptom: "no public key found"
+
+**Cause:** OCM cannot find a matching verification configuration in `.ocmconfig`.
+
+**Fix:** Ensure your `.ocmconfig` has a consumer entry with the matching `signature` name and `public_key_pem_file` path.
+
+See [Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}).
+
+### Symptom: "invalid key format"
+
+**Cause:** The public key file is not in PEM format.
+
+**Fix:** Verify the key starts with `-----BEGIN PUBLIC KEY-----`:
+
+```bash
+head -n 1 $HOME/.ocm/keys/public.pem
+```
+
+## CLI Reference
+
+| Command | Description |
+|---------|-------------|
+| [`ocm verify componentversions`]({{< relref "docs/reference/ocm-cli/ocm_verify_component-version.md" >}}) | Verify a component version signature |
+| [`ocm get componentversions`]({{< relref "docs/reference/ocm-cli/ocm_get_component-version.md" >}}) | View component with signatures |
+
+## Next Steps
+
+- [How-to: Sign Component Versions]({{< relref "sign-component-version.md" >}}) - Add signatures to your components
+- [Tutorial: Signing and Verification]({{< relref "signing-and-verification.md" >}}) - Learn how to sign and verify components in a complete tutorial
+
+## Related Documentation
+
+- [Concept: Signing and Verification]({{< relref "docs/concepts/signing-and-verification-concept.md" >}}) - Understand how OCM signing works
diff --git a/content/docs/reference/_index.md b/content/docs/reference/_index.md
index 1ed82f145..c1717de52 100644
--- a/content/docs/reference/_index.md
+++ b/content/docs/reference/_index.md
@@ -2,7 +2,7 @@
title: Reference
description: "Browse reference documentation for the OCM CLI and OCM controllers."
icon: "๐พ"
-weight:
+weight: 60
toc: true
sidebar:
collapsed: true
diff --git a/content/docs/reference/credential-consumer-identities.md b/content/docs/reference/credential-consumer-identities.md
new file mode 100644
index 000000000..7a3b2e3cd
--- /dev/null
+++ b/content/docs/reference/credential-consumer-identities.md
@@ -0,0 +1,251 @@
+---
+title: "Credential Consumer Identities"
+description: "Complete reference for OCM credential consumer identity types, their attributes, and credential properties."
+icon: "๐"
+weight: 2
+toc: true
+---
+
+This page is the technical reference for credential consumer identities โ the key-value maps OCM uses to look up credentials for a given operation. For a high-level introduction, see [Credential System]({{< relref "docs/concepts/credential-system.md" >}}).
+
+## Overview
+
+Every time OCM needs credentials (accessing a registry, signing a component version), it constructs a **lookup identity** โ a map of string attributes describing what it needs credentials for. The credential system then searches configured consumers for a matching entry.
+
+A consumer entry in `.ocmconfig` looks like this:
+
+```yaml
+type: generic.config.ocm.software/v1
+configurations:
+ - type: credentials.config.ocm.software
+ consumers:
+ - identity:
+ type:
+ # ... type-specific attributes
+ credentials:
+ - type: Credentials/v1
+ properties:
+ # ... key-value credential properties
+```
+
+OCM currently defines two consumer identity types:
+
+| Identity Type | Used For |
+|---|---|
+| [`OCIRepository`](#ocirepository) | Authenticating against OCI registries |
+| [`RSA/v1alpha1`](#rsav1alpha1) | Providing signing and verification keys |
+
+---
+
+## OCIRepository
+
+Used when OCM accesses an OCI registry โ pushing, pulling, or resolving component versions and resources.
+
+### Identity Attributes
+
+| Attribute | Required | Description |
+|---|---|---|
+| `type` | Yes | Must be `OCIRepository` |
+| `hostname` | Yes | Registry hostname (e.g. `ghcr.io`, `registry.example.com`) |
+| `path` | No | Repository path. Supports glob patterns (`*` matches one path segment). If omitted, matches any path on the hostname. |
+| `scheme` | No | URL scheme (`https`, `http`, `oci`). If omitted, matches any scheme. If set, must match exactly. |
+| `port` | No | Port number as string. Default ports are applied when `scheme` is set: `https` and `oci` default to `443`, `http` defaults to `80`. |
+
+### Credential Properties
+
+| Property | Description |
+|---|---|
+| `username` | Registry username |
+| `password` | Registry password or token |
+
+### Matching Behavior
+
+Matching runs three chained checks โ all must pass:
+
+1. **Path matcher** โ compares `path` using `path.Match` (glob). `*` matches one segment, not across `/`. If the configured entry has no `path`, any request path is accepted.
+2. **URL matcher** โ compares `scheme`, `hostname`, and `port`. Applies default ports when a scheme is present (`https` โ `443`, `http` โ `80`).
+3. **Equality matcher** โ all remaining attributes (like `type`) must be exactly equal.
+
+For detailed matching examples and edge cases, see [Tutorial: Understand Credential Resolution]({{< relref "docs/tutorials/credential-resolution.md" >}}).
+
+### Examples
+
+**Hostname only** โ matches all paths on `ghcr.io`:
+
+```yaml
+- identity:
+ type: OCIRepository
+ hostname: ghcr.io
+ credentials:
+ - type: Credentials/v1
+ properties:
+ username: my-user
+ password: ghp_token
+```
+
+**Hostname + path glob** โ matches any single-segment path under `my-org/`:
+
+```yaml
+- identity:
+ type: OCIRepository
+ hostname: ghcr.io
+ path: my-org/*
+ credentials:
+ - type: Credentials/v1
+ properties:
+ username: org-user
+ password: ghp_org_token
+```
+
+**Hostname + scheme + port** โ matches only HTTPS on a custom port:
+
+```yaml
+- identity:
+ type: OCIRepository
+ hostname: registry.internal
+ scheme: https
+ port: "8443"
+ credentials:
+ - type: Credentials/v1
+ properties:
+ username: internal-user
+ password: internal_pass
+```
+
+---
+
+## RSA/v1alpha1
+
+Used when OCM signs or verifies component versions with RSA keys.
+
+### Identity Attributes
+
+| Attribute | Required | Description |
+|---|---|---|
+| `type` | Yes | Must be `RSA/v1alpha1` |
+| `algorithm` | Yes | Signing algorithm. Must be `RSASSA-PSS` (recommended) or `RSASSA-PKCS1-V1_5`. |
+| `signature` | Yes | Logical signature name (e.g. `default`). Must match the `--signature` flag used with `ocm sign cv`. Defaults to `default` if not specified on the CLI. |
+
+{{< callout context="caution" >}}
+**All three attributes are required.** When OCM looks up signing credentials, it always constructs a lookup identity with `type`, `algorithm`, and `signature`. If your consumer entry omits `algorithm`, the credential system will not find a match โ even though the signing algorithm defaults to `RSASSA-PSS` internally.
+
+If you are unsure which algorithm to use, specify `algorithm: RSASSA-PSS`.
+{{< /callout >}}
+
+### Credential Properties
+
+| Property | Used For | Description |
+|---|---|---|
+| `private_key_pem` | Signing | Inline PEM-encoded private key |
+| `private_key_pem_file` | Signing | Path to PEM-encoded private key file |
+| `public_key_pem` | Verification | Inline PEM-encoded public key |
+| `public_key_pem_file` | Verification | Path to PEM-encoded public key file |
+
+You can specify both `private_key_pem_file` and `public_key_pem_file` in the same entry to use it for both signing and verification.
+
+### Matching Behavior
+
+Unlike OCI identities, RSA signing identities use **strict equality matching** โ every attribute in the lookup identity must be present in the configured consumer identity with the exact same value. There is no glob or subset matching.
+
+### Examples
+
+**Signing and verification with default settings:**
+
+```yaml
+- identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: default
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /path/to/private-key.pem
+ public_key_pem_file: /path/to/public-key.pem
+```
+
+**Multiple signature identities** (e.g. dev and prod):
+
+```yaml
+- identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: dev
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /path/to/dev/private-key.pem
+ public_key_pem_file: /path/to/dev/public-key.pem
+- identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: prod
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /path/to/prod/private-key.pem
+ public_key_pem_file: /path/to/prod/public-key.pem
+```
+
+Sign with a specific identity:
+
+```bash
+ocm sign cv --signature dev
+ocm sign cv --signature prod
+```
+
+**Using PKCS#1 v1.5 algorithm:**
+
+```yaml
+- identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PKCS1-V1_5
+ signature: legacy
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /path/to/private-key.pem
+```
+
+---
+
+## Complete Configuration Example
+
+A single `.ocmconfig` combining registry credentials (with Docker fallback) and signing credentials:
+
+```yaml
+type: generic.config.ocm.software/v1
+configurations:
+ - type: credentials.config.ocm.software
+ consumers:
+ # OCI registry โ hostname catch-all
+ - identity:
+ type: OCIRepository
+ hostname: ghcr.io
+ credentials:
+ - type: Credentials/v1
+ properties:
+ username: my-user
+ password: ghp_token
+ # RSA signing โ default signature
+ - identity:
+ type: RSA/v1alpha1
+ algorithm: RSASSA-PSS
+ signature: default
+ credentials:
+ - type: Credentials/v1
+ properties:
+ private_key_pem_file: /path/to/private-key.pem
+ public_key_pem_file: /path/to/public-key.pem
+ # Docker config fallback for registries not matched above
+ repositories:
+ - repository:
+ type: DockerConfig/v1
+ dockerConfigFile: "$HOME/.docker/config.json"
+```
+
+## Related Documentation
+
+- [Concept: Credential System]({{< relref "docs/concepts/credential-system.md" >}}) โ How the credential system works
+- [Tutorial: Understand Credential Resolution]({{< relref "docs/tutorials/credential-resolution.md" >}}) โ Step-by-step matching examples for OCI registries
+- [How-To: Configure Credentials for Multiple Registries]({{< relref "docs/how-to/configure-multiple-credentials.md" >}}) โ Task-oriented registry credential setup
+- [How-To: Configure Credentials for Signing]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) โ Task-oriented signing credential setup
diff --git a/content/docs/reference/resolver-configuration.md b/content/docs/reference/resolver-configuration.md
index 9dc7f2a64..8a41a1b4e 100644
--- a/content/docs/reference/resolver-configuration.md
+++ b/content/docs/reference/resolver-configuration.md
@@ -2,7 +2,7 @@
title: "Resolver Configuration"
description: "Complete reference for OCM resolver configuration: schema, repository types, and component name patterns."
icon: "๐"
-weight: 10
+weight: 1
toc: true
---
diff --git a/content/docs/tutorials/configure-resolvers.md b/content/docs/tutorials/configure-resolvers.md
index 3414ac794..3bc79d852 100644
--- a/content/docs/tutorials/configure-resolvers.md
+++ b/content/docs/tutorials/configure-resolvers.md
@@ -85,7 +85,7 @@ configurations:
repositories:
- repository:
type: DockerConfig/v1
- dockerConfigFile: "~/.docker/config.json"
+ dockerConfigFile: "$HOME/.docker/config.json"
```
For more information about the OCM configuration file,
diff --git a/content/docs/tutorials/credential-resolution.md b/content/docs/tutorials/credential-resolution.md
index 992d79cd3..4737da3b4 100644
--- a/content/docs/tutorials/credential-resolution.md
+++ b/content/docs/tutorials/credential-resolution.md
@@ -10,6 +10,8 @@ toc: true
Every time OCM accesses a registry, it resolves credentials automatically. This tutorial walks you through how that resolution works โ given a config, which credentials does OCM pick for each request, and why?
+This tutorial focuses on OCI registry credentials. For signing credential identities (`RSA/v1alpha1`), see the [Consumer Identities Reference]({{< relref "/docs/reference/credential-consumer-identities.md" >}}).
+
For the full concept, see [Credential System]({{< relref "/docs/concepts/credential-system.md" >}}).
**Estimated time:** ~10 minutes
@@ -350,3 +352,4 @@ Then retry the OCM command.
## Related Documentation
- [Concept: Credential System]({{< relref "/docs/concepts/credential-system.md" >}}) - Learn how the credential system automatically finds the right credentials for each operation
+- [Reference: Consumer Identities]({{< relref "/docs/reference/credential-consumer-identities.md" >}}) โ Complete reference for all identity types (OCI registries and RSA signing)
diff --git a/content/docs/tutorials/signing-and-verification.md b/content/docs/tutorials/signing-and-verification.md
index 6e029d7f0..72a6e152f 100644
--- a/content/docs/tutorials/signing-and-verification.md
+++ b/content/docs/tutorials/signing-and-verification.md
@@ -1,231 +1,145 @@
---
-title: "Signing and Verification"
-description: "Complete guide to cryptographic signing and verification in OCM."
+title: "Sign and Verify Components"
+description: "Learn to cryptographically sign a component version and verify its authenticity."
icon: "โ๏ธ"
-weight: 60
+weight: 55
toc: true
---
-## Overview
-
-The Open Component Model provides cryptographic signing and verification capabilities
-to establish **provenance** and **authenticity** of component versions.
-This guide covers the complete signing and verification workflow, from key pair generation to trust model selection.
-
-**This guide is for users who want to:**
-
-- Understand how OCM handles component signing and verification
-- Learn about supported signature types
-- See step-by-step signing and verification examples
-- Plan multi-environment workflows with dedicated signing profiles (dev/staging/prod)
-- Understand how signer specifications and encoding policies complement `.ocmconfig`
-
-## Signing and Verification Workflow
-
-### High-Level Process
-
-A side-by-side comparison makes it clear how both flows mirror the same normalization and hashing steps while differing only in credential handling.
-
-### Workflow Comparison
-
-| Step | Signing Flow | Verification Flow |
-| --- | --- | --- |
-| 1 | Resolve signing credentials from `.ocmconfig` or signer spec | Resolve signature by name and load public key/certificate (config, CLI flag, or embedded PEM) |
-| 2 | Normalize component descriptor (selected algorithm) | Normalize component descriptor with the same algorithm |
-| 3 | Hash normalized descriptor (selected hash) | Hash normalized descriptor and compare against signature digest |
-| 4 | Produce signature, store it with descriptor metadata | Verify signature (and certificate chain if PEM) |
-
-### What Gets Signed?
-
-OCM signs the **component descriptor**, which contains:
-
-- Component metadata (name, version, provider)
-- Resources (artifacts like container images, Helm charts)
-- Sources (references to source code)
-- References to other components
-- **Resource digests** (cryptographic hashes of artifacts)
-
-**Important:** OCM does **not** sign the artifacts themselves, but rather their digests in the component descriptor. This provides:
-
-- โ
Efficient verification (no external dependencies)
-- โ
Tamper detection (any change to artifacts invalidates the signature)
-- โ
Provenance (signature proves who created/released the component version)
-
-## Key Pair Generation (Optional)
-
-> **Already have RSA key pairs?** Skip to [Configuring Keys in an .ocmconfig File](#configuring-keys-in-an-ocmconfig-file).
-
-This section covers general RSA key pair generation and management. If you already have suitable RSA keys (self-signed or CA-signed), you can use them directly with OCM and skip to the configuration section.
-
-### Choose Your Approach
-
-Before generating keys, decide which approach fits your needs:
-
-| Your Situation | Recommended Approach |
-| --- | --- |
-| Local development or testing | **Self-Signed Keys** |
-| Production environment | **CA-Signed Keys** |
-| Enterprise/Multi-organization | **CA-Signed Keys** |
-| Compliance requirements | **CA-Signed Keys** |
-
-### Self-Signed vs. CA-Signed
+In this tutorial, you'll sign a component version with a private key and verify it with the corresponding public key.
+By the end, you'll understand the complete signing and verification workflow that ensures component authenticity and integrity.
+
+## What You'll Learn
+
+- Create an RSA key pair for signing and verification
+- Sign component version in a CTF archive
+- Hands-on experience verifying the signature
+
+**Estimated time:** ~15 minutes
+
+## Scenario
+
+You're a software engineer who has built a `helloworld` component and packaged it as an OCM component version. Before distributing it to your team, you need to sign it so consumers can verify that:
+
+1. **The component is authentic** โ it comes from you, not an imposter
+2. **The component has integrity** โ it hasn't been tampered with since signing
+
+## How It Works
+
+```mermaid
+flowchart LR
+ subgraph sign ["Sign (You)"]
+ direction TB
+ A[Component Version] --> C[Sign with Private Key]
+ C --> D[Signed Component Version]
+ end
+
+ D --> T["Share Component"]
+
+ T --> verify
+
+ subgraph verify ["Verify (Consumer)"]
+ direction TB
+ E[Signed Component Version] --> H[Verify with Public Key]
+ H --> I{Valid?}
+ I -->|Yes| VALID["โ Trusted"]
+ I -->|No| INVALID["โ Rejected"]
+ end
+
+ style VALID fill:#dcfce7,color:#166534
+ style INVALID fill:#fee2e2,color:#991b1b
+```
-**Self-Signed Keys:**
+The producer signs the component version with a private key, creating a signed component. Consumers verify the signature using the corresponding public key to ensure authenticity and integrity.
-- Simple to create (no external CA required)
-- Full control over key lifecycle
-- Trust based on explicit key distribution
-- Public key must be manually distributed to verifiers
+## Prerequisites
-**CA-Signed Certificates:**
+- [OCM CLI installed]({{< relref "docs/getting-started/ocm-cli-installation.md" >}})
+- A component version to sign (we'll create one if you don't have one)
-- Requires Certificate Authority (CA)
-- Certificate chain validates against trusted root CAs
-- Trust leverages existing PKI
-- Automatic trust propagation via certificate validation
+## Steps
-## Key Pair Generation
+{{< steps >}}
-OCM supports **RSA** signatures with two algorithms:
+{{< step >}}
-- **RSASSA-PSS** - Default and recommended
-- **RSASSA-PKCS1v15** - Legacy support
+### Create a sample component (if needed)
-### Directory Structure Setup
+If you already have a component version in a CTF archive,
+e.g, by following our [Create a Component Version]({{< relref "create-component-version.md" >}}) guide, skip to the next step.
-First, create a consistent directory structure for your keys. This guide uses the following convention:
+Create a simple helloworld component:
```bash
-# Create a directory for your OCM keys
-mkdir -p ~/.ocm/keys
-
-# Recommended structure:
-# ~/.ocm/keys/
-# โโโ dev/ # Development keys
-# โโโ staging/ # Staging keys
-# โโโ prod/ # Production keys
-```
+# Create a directory for the tutorial
+mkdir -p /tmp/ocm-signing-tutorial && cd /tmp/ocm-signing-tutorial
-Throughout this guide, we'll use this structure and reference files with their full paths.
+# Create a basic `component-constructor.yaml` without any resources:
+cat > component-constructor.yaml << 'EOF'
+components:
+- name: github.com/acme.org/helloworld
+ version: 1.0.0
+ provider:
+ name: acme.org
+EOF
-### Self-Signed Keys (Development)
+# Create component version in a CTF archive located at ./transport-archive
+ocm add cv
-Self-signed keys are ideal for development, testing, and environments without PKI infrastructure.
-
-#### Generate Development Keys
+```
-```bash
-# Create directory for development keys
-mkdir -p ~/.ocm/keys/dev
+You should see that the component version was created successfully.
-# Generate private key (4096 bits recommended)
-openssl genrsa -out ~/.ocm/keys/dev/private.pem 4096
+
+Expected output
-# Extract public key
-openssl rsa -in ~/.ocm/keys/dev/private.pem -pubout -out ~/.ocm/keys/dev/public.pem
-
-# Set secure permissions
-chmod 600 ~/.ocm/keys/dev/private.pem
-chmod 644 ~/.ocm/keys/dev/public.pem
+```text
+ COMPONENT โ VERSION โ PROVIDER
+โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโ
+ github.com/acme.org/helloworld โ 1.0.0 โ acme.org
```
-**Files created:**
-
-- `~/.ocm/keys/dev/private.pem` - Private key (4096 bits)
-- `~/.ocm/keys/dev/public.pem` - Public key
+
+{{< /step >}}
-### CA-Signed Keys (Production)
+{{< step >}}
-CA-signed certificates provide a trust chain that can be validated against a certificate authority.
-They are recommended for production environments, enterprise deployments,
-and scenarios requiring PKI integration or compliance.
+### Generate an RSA key pair
-#### Generate Production Keys with CSR
+Create a directory for your keys and generate a 4096-bit RSA key pair:
```bash
-# Create directory for production keys
-mkdir -p ~/.ocm/keys/prod
+# Create a directory for the generated keys
+mkdir keys
# Generate private key
-openssl genrsa -out ~/.ocm/keys/prod/private.pem 4096
-
-# Create certificate signing request (CSR)
-openssl req -new -key ~/.ocm/keys/prod/private.pem \
- -out ~/.ocm/keys/prod/request.csr \
- -subj "/C=US/O=MyOrg/OU=Engineering/CN=OCM Production Signer"
+openssl genpkey -algorithm RSA -out ./keys/private-key.pem -pkeyopt rsa_keygen_bits:4096
-# Set secure permissions
-chmod 600 ~/.ocm/keys/prod/private.pem
-chmod 644 ~/.ocm/keys/prod/request.csr
+# Extract public key
+openssl rsa -in ./keys/private-key.pem -pubout -out ./keys/public-key.pem
-# Send request.csr to your CA and save the response
-# After receiving from CA, save as:
-# ~/.ocm/keys/prod/certificate.pem
-# ~/.ocm/keys/prod/ca-chain.pem (if provided)
+# Secure the private key
+chmod 600 ./keys/private-key.pem
```
-**Files created:**
-
-- `~/.ocm/keys/prod/private.pem` - Private key (4096 bits)
-- `~/.ocm/keys/prod/request.csr` - Certificate signing request (send to CA)
-
-**Files received from CA:**
-
-- `~/.ocm/keys/prod/certificate.pem` - Signed certificate
-- `~/.ocm/keys/prod/ca-chain.pem` - CA certificate chain (optional but recommended)
-
-#### Create Certificate with Chain
-
-If you receive individual certificates, combine them into a chain:
+Verify both files exist:
```bash
-# Combine leaf certificate with intermediate and root CA certificates
-cat ~/.ocm/keys/prod/certificate.pem \
- ~/.ocm/keys/prod/intermediate-ca.pem \
- ~/.ocm/keys/prod/root-ca.pem \
- > ~/.ocm/keys/prod/cert-chain.pem
-
-chmod 644 ~/.ocm/keys/prod/cert-chain.pem
+ls -la ./keys/*.pem
```
-## Configuring Keys in an .ocmconfig File
-
-OCM uses its credential system to resolve signing and verification keys.
-The keys are configured as credentials for a special consumer type: `RSA/v1alpha1`.
-
-> **Using your own keys?** Simply reference your existing key file paths in the configuration examples below instead of the `~/.ocm/keys/` paths shown here.
-
-All examples below use the **exact file paths** from the key generation section above.
-
-> **Tip:** Add the entries below to your `.ocmconfig`. If the file is present in your home directory (`~/.ocmconfig`), the OCM CLI will use it automatically. Only provide `--config ` when you want to reference a different configuration file.
-
-### Basic Signing Configuration (Development)
-
-Using the development keys we created earlier:
-
-```yaml
-type: generic.config.ocm.software/v1
-configurations:
- - type: credentials.config.ocm.software
- consumers:
- - identity:
- type: RSA/v1alpha1
- algorithm: RSASSA-PSS
- signature: default
- credentials:
- - type: Credentials/v1
- properties:
- private_key_pem_file: ~/.ocm/keys/dev/private.pem
-```
+> โ ๏ธ **Keep your private key secure!** โ ๏ธ
+> Never commit it to version control or share it.
-**Note:** This references `~/.ocm/keys/dev/private.pem` which we created with the OpenSSL command in the previous section.
+For more details, see [How-to: Generate Signing Keys]({{< relref "docs/how-to/generate-signing-keys.md" >}}).
+{{< /step >}}
-> **Alternative:** Keys can also be embedded inline using `private_key_pem` property.
-> The inline format uses a multi-line YAML string with the PEM block.
+{{< step >}}
-### Basic Verification Configuration (Development)
+### Configure signing credentials
-Using the public key we generated earlier:
+Create or update your `$HOME/.ocmconfig` file and copy the content below to it, to tell OCM where to find your keys.
+A detailed How-To guide is available here: [How-to: Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}).
```yaml
type: generic.config.ocm.software/v1
@@ -239,538 +153,140 @@ configurations:
credentials:
- type: Credentials/v1
properties:
- public_key_pem_file: ~/.ocm/keys/dev/public.pem
-```
-
-**Note:** This configuration references `~/.ocm/keys/dev/public.pem` which was extracted from the private key using OpenSSL.
-
-### Identity Attributes Explained
-
-The consumer identity for RSA signing/verification supports these attributes:
-
-| Attribute | Required | Description |
-|-------------|----------|------------------------------------------------------------------|
-| `type` | Yes | Must be `RSA/v1alpha1` |
-| `algorithm` | No | `RSASSA-PSS` (default) or `RSASSA-PKCS1V15` (legacy) |
-| `signature` | No | Name/label for this signature configuration (default: `default`) |
-
-The `signature` attribute is particularly useful for multi-environment setups.
-
-## Multi-Environment Configuration
-
-> **Optional (advanced):** Skip this section if you operate a single environment. You can continue with [Signer Specifications](#signer-specifications) without missing any required setup.
-
-In many organizations, you'll want different signing keys for different environments or purposes.
-
-For multiple environments, generate separate keys using the same process:
-
-- **Development:** Self-signed keys (see [Self-Signed Keys](#self-signed-keys-development) section)
-- **Staging:** Self-signed keys in `~/.ocm/keys/staging/` (same process)
-- **Production:** CA-signed keys (see [CA-Signed Keys](#ca-signed-keys-production) section)
-
-### Combined Configuration Example
-
-This example shows a complete `.ocmconfig` with signing and verification keys for all environments:
-
-```yaml
-type: generic.config.ocm.software/v1
-configurations:
- - type: credentials.config.ocm.software
- consumers:
- # Development environment
- - identity:
- type: RSA/v1alpha1
- algorithm: RSASSA-PSS
- signature: dev
- credentials:
- - type: Credentials/v1
- properties:
- private_key_pem_file: ~/.ocm/keys/dev/private.pem
- public_key_pem_file: ~/.ocm/keys/dev/public.pem
-
- # Staging environment
- - identity:
- type: RSA/v1alpha1
- algorithm: RSASSA-PSS
- signature: staging
- credentials:
- - type: Credentials/v1
- properties:
- private_key_pem_file: ~/.ocm/keys/staging/private.pem
- public_key_pem_file: ~/.ocm/keys/staging/public.pem
-
- # Production environment (CA-signed with certificate chain)
- - identity:
- type: RSA/v1alpha1
- algorithm: RSASSA-PSS
- signature: prod
- credentials:
- - type: Credentials/v1
- properties:
- private_key_pem_file: ~/.ocm/keys/prod/private.pem
- public_key_pem_file: ~/.ocm/keys/prod/cert-chain.pem
+ private_key_pem_file: /tmp/ocm-signing-tutorial/keys/private-key.pem
+ public_key_pem_file: /tmp/ocm-signing-tutorial/keys/public-key.pem
```
-**Notes:**
+> ๐ The `signature: default` name is used when you don't specify `--signature` on the command line.
-- Each environment has both private and public keys
-- Production uses the certificate chain for verification
-- The same configuration works for both signing and verification
+For more details, see [How-to: Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}).
+{{< /step >}}
-### Usage Examples
+{{< step >}}
-**Signing:**
-
-```bash
-# Sign with development key
-ocm sign cv --signature dev ghcr.io/myorg/component:1.0.0
-
-# Sign with staging key
-ocm sign cv --signature staging ghcr.io/myorg/component:1.0.0
-
-# Sign with production key
-ocm sign cv --signature prod ghcr.io/myorg/component:1.0.0
-```
+### Sign the component version
-**Verification:**
+Sign your component with the private key:
```bash
-# Verify with development key
-ocm verify cv --signature dev ghcr.io/myorg/component:1.0.0
-
-# Verify with staging key
-ocm verify cv --signature staging ghcr.io/myorg/component:1.0.0
-
-# Verify with production key
-ocm verify cv --signature prod ghcr.io/myorg/component:1.0.0
+ocm sign cv ./transport-archive//github.com/acme.org/helloworld:1.0.0
```
-### Verification-Only Configuration
+
+Expected output
-If you only need to verify signatures (e.g., on CI/CD runners or deployment systems), you can omit the private keys:
-
-```yaml
-type: generic.config.ocm.software/v1
-configurations:
- - type: credentials.config.ocm.software
- consumers:
- - identity:
- type: RSA/v1alpha1
- signature: prod
- credentials:
- - type: Credentials/v1
- properties:
- # Only public key needed for verification
- public_key_pem_file: ~/.ocm/keys/prod/cert-chain.pem
+```text
+time=... level=INFO msg="signing component version" name=default
+time=... level=INFO msg="signature added" name=default
```
-**Note:** This configuration contains only the public key. Verification works, but signing operations will fail (as intended for read-only environments).
-
-## Signer Specifications
+
-> **Optional (advanced):** If you do not need per-command overrides or CI-friendly specs, skip ahead to [Signature Encoding Policies](#signature-encoding-policies). Core functionality continues there.
-
-The `--signer-spec` flag provides fine-grained control over the signing process via a YAML configuration file.
-
-### When to Use Signer Specs
-
-Use signer specifications when you need:
-
-- โ
Command-specific signing config
-- โ
CI/CD pipeline integration
-- โ
Explicit control over signing parameters
-- โ
Different encoding policies
-- โ
Temporary or one-off signing operations
-
-**Signer specs vs. .ocmconfig:**
-
-| Aspect | Signer Spec File | .ocmconfig |
-|---------------------|--------------------------|--------------------------|
-| Scope | Command-specific | Global configuration |
-| Portability | Easy to version control | User/machine-specific |
-| Use case | CI/CD, explicit control | Local development |
-| Key distribution | Embedded or referenced | Centralized config |
-
-### Signer Spec File Format
-
-A signer specification file contains only signing configuration, **not** the signature name (which is provided via `--signature` flag).
-
-```yaml
-type: RSA/v1alpha1
-signatureAlgorithm: RSASSA-PSS # or RSASSA-PKCS1V15
-signatureEncodingPolicy: Plain # or PEM
-
-# Option 1: Reference external file (preferred)
-privateKeyPEMFile: ~/.ocm/keys/dev/private.pem
-
-# Option 2: Inline private key
-# privateKeyPEM: |
-# -----BEGIN PRIVATE KEY-----
-# ...
-# -----END PRIVATE KEY-----
-```
-
-**Note:** The **signature name** is specified via the `--signature` flag when running the command, not in this file.
-
-### Default Signer Spec Behavior
-
-If `--signer-spec` is **not** provided, OCM uses defaults:
-
-```yaml
-type: RSA/v1alpha1
-signatureAlgorithm: RSASSA-PSS
-signatureEncodingPolicy: Plain
-# Private key resolved from .ocmconfig
-```
-
-This means:
-
-- Algorithm: RSASSA-PSS
-- Encoding: Plain (raw signature bytes)
-- Key: Retrieved from `.ocmconfig` config file
-
-### Example: Using Signer Spec in CI/CD
-
-**signer-config.yaml:**
-
-```yaml
-type: RSA/v1alpha1
-signatureAlgorithm: RSASSA-PSS
-signatureEncodingPolicy: Plain
-privateKeyPEMFile: /secrets/signing-key.pem
-```
-
-**CI/CD pipeline:**
+Verify the signature was added:
```bash
-# Inject private key into CI/CD secrets
-echo "$SIGNING_PRIVATE_KEY" > /secrets/signing-key.pem
-chmod 600 /secrets/signing-key.pem
-
-# Sign component version
-ocm sign cv \
- --signer-spec ./signer-config.yaml \
- --signature release \
- ghcr.io/myorg/component:${VERSION}
+ocm get cv ./transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 10 signatures:
```
-## Signature Encoding Policies
-
-> **Optional (advanced):** Readers who only work with the default signing setup can skip directly to [Signing Component Versions](#signing-component-versions). The sections below cover advanced storage and trust scenarios.
+You should see a `signatures:` section with your signature.
+{{< /step >}}
-OCM supports two encoding policies that affect how signatures are stored and verified.
+{{< step >}}
-### Plain Encoding (Default)
+### Verify the signature
-Stores only the raw signature bytes. Compact but requires the public key to be provided separately (via `.ocmconfig` or `--public-key` flag).
-
-**Configuration:**
-
-```yaml
-type: RSA/v1alpha1
-signatureEncodingPolicy: Plain
-```
-
-Suitable for self-signed keys and scenarios where public keys are distributed through `.ocmconfig`.
-
-### PEM Encoding
-
-Embeds the certificate chain directly in the signature, enabling verification against the system trust store without requiring public keys in `.ocmconfig`.
-
-**Configuration:**
-
-```yaml
-type: RSA/v1alpha1
-signatureEncodingPolicy: PEM
-```
-
-**How it works:**
-
-1. Creates a PEM block containing the signature
-2. Appends the signer's certificate chain
-3. During verification, validates the chain against the system trust store
-4. Extracts the public key from the validated certificate
-
-**Requirements:**
-
-- Signature name must match the config
-- Certificate chain must be included in the signature
-- System trust store must contain the root CA, or root CA must be provided in `.ocmconfig`
-
-Suitable for enterprise PKI integration and scenarios requiring automated trust validation.
-
-## Signing Component Versions
-
-### Basic Signing
-
-```sh
-# Sign with default signature name and configuration
-ocm sign cv ghcr.io/myorg/component:1.0.0
-
-# Sign with custom signature name
-ocm sign cv --signature release ghcr.io/myorg/component:1.0.0
-```
-
-### Advanced Signing Options
-
-```sh
-# Use specific signer specification
-ocm sign cv \
- --signer-spec ./config/prod-signer.yaml \
- --signature prod-release \
- ghcr.io/myorg/component:1.0.0
-
-# Dry run (compute signature without storing)
-ocm sign cv \
- --signature test \
- --dry-run \
- ghcr.io/myorg/component:1.0.0
-
-# Force overwrite existing signature
-ocm sign cv \
- --signature release \
- --force \
- ghcr.io/myorg/component:1.0.0
-
-# Custom normalization and hash algorithms
-ocm sign cv \
- --normalisation jsonNormalisation/v4alpha1 \
- --hash SHA512 \
- --signature release \
- ghcr.io/myorg/component:1.0.0
-```
-
-### Common Signing Flags
-
-| Flag | Description | Default |
-|-------------------|------------------------------------------|---------------|
-| `--signature` | Name of the signature | `default` |
-| `--signer-spec` | Path to signer specification file | (uses config) |
-| `--force` | Overwrite existing signature | `false` |
-| `--dry-run` | Compute signature without storing | `false` |
-
-For complete flag reference, see `ocm sign cv --help`.
-
-## Verifying Component Versions
-
-### Basic Verification
-
-```sh
-# Verify default signature
-ocm verify cv ghcr.io/myorg/component:1.0.0
-
-# Verify specific signature
-ocm verify cv --signature release ghcr.io/myorg/component:1.0.0
-```
+Now verify the signature using the public key:
-### Verification with External Public Key
-
-```sh
-# Provide public key via command line
-ocm verify cv \
- --public-key ./keys/public.pem \
- --signature release \
- ghcr.io/myorg/component:1.0.0
+```bash
+ocm verify cv ./transport-archive//github.com/acme.org/helloworld:1.0.0
```
-### Verification Process
-
-1. **Fetch component version** from repository
-2. **Locate signature** by name in component descriptor
-3. **Resolve public key** from:
- - `.ocmconfig` credential system, OR
- - `--public-key` flag, OR
- - Certificate chain in signature (PEM encoding only)
-4. **Normalize component descriptor** using specified algorithm
-5. **Hash normalized descriptor**
-6. **Verify signature** using public key
-7. **Validate certificate chain** (PEM encoding only)
-
-### Verification Success Criteria
-
-For verification to succeed:
-
-- โ
Signature exists with specified name
-- โ
Public key can be resolved
-- โ
Signature cryptographically valid
-- โ
Component descriptor unchanged since signing
-- โ
Certificate chain valid (PEM encoding only)
-- โ
Certificate DN matches signature name (PEM encoding only)
-
-## Trust Models
+
+Expected output
-OCM supports multiple trust models depending on your security requirements.
-
-### 1. Key Pinning (Self-Signed)
-
-Specific public keys configured in `.ocmconfig`. Trust is based on exact key match without certificate validation.
-
-**Trust chain:**
-
-```code
-Component Signature โ Public Key in .ocmconfig โ Trust
+```text
+time=2026-03-12T22:06:37.357+01:00 level=INFO msg="no verifier specification file given, using default RSASSA-PSS"
+time=2026-03-12T22:06:37.357+01:00 level=INFO msg="verifying signature" name=default
+time=2026-03-12T22:06:37.358+01:00 level=INFO msg="signature verification completed" name=default duration=798.25ยตs
+time=2026-03-12T22:06:37.358+01:00 level=INFO msg="SIGNATURE VERIFICATION SUCCESSFUL"
```
-Simple setup with full control, suitable for small teams and development environments.
-
-### 2. System Trust Store (CA-Signed, PEM Encoding)
-
-Certificate chain embedded in signature and validated against system trust store or distributed root CA. No manual public key distribution needed.
-
-**Trust chain:**
+
-```code
-Component Signature โ Embedded Cert Chain โ System Trust Store โ Root CA โ Trust
-```
+> โ
**Success!** โ
+> The component version is verified as authentic and unmodified.
-Suitable for automatic trust propagation in enterprise PKI infrastructure.
+{{< /step >}}
+{{< /steps >}}
-## Complete Configuration Examples
+## What You've Learned
-### Example 1: Development Setup (Self-Signed)
+Congratulations! You've successfully:
-**Prerequisites:** Generate self-signed keys (see "Self-Signed Keys" section):
+- โ
Generated an RSA key pair for signing and verification
+- โ
Configured OCM to use your keys via `.ocmconfig`
+- โ
Signed a component version with your private key
+- โ
Verified the signature using the public key
+- โ
Understood how signatures detect tampering
-```bash
-mkdir -p ~/.ocm/keys/dev
-openssl genrsa -out ~/.ocm/keys/dev/private.pem 4096
-openssl rsa -in ~/.ocm/keys/dev/private.pem -pubout -out ~/.ocm/keys/dev/public.pem
-chmod 600 ~/.ocm/keys/dev/private.pem
-chmod 644 ~/.ocm/keys/dev/public.pem
-```
+## Best Practices for Production
-**.ocmconfig:**
+Now that you understand the workflow, here are key practices for production environments:
-```yaml
-type: generic.config.ocm.software/v1
-configurations:
- - type: credentials.config.ocm.software
- consumers:
- - identity:
- type: RSA/v1alpha1
- signature: dev
- credentials:
- - type: Credentials/v1
- properties:
- private_key_pem_file: ~/.ocm/keys/dev/private.pem
- public_key_pem_file: ~/.ocm/keys/dev/public.pem
-```
+- **Protect private keys** โ Use hardware security modules (HSMs) or secrets managers instead of local PEM files
+- **Rotate keys periodically** โ Have a key rotation strategy; OCM supports multiple signatures to ease transitions
+- **Sign at the right time** โ Sign after all resources are finalized; re-signing is possible but creates audit complexity
+- **Distribute public keys securely** โ Document how consumers should obtain and verify public keys
+- **Verify before deployment** โ Make signature verification a mandatory step in your deployment pipeline
-**Usage:**
+## Check Your Understanding
-```bash
-# Sign
-ocm sign cv --signature dev ghcr.io/myorg/component:1.0.0
+{{< details "Why does OCM sign the component descriptor instead of the artifacts directly?" >}}
+OCM signs the component descriptor because it contains **digests** (cryptographic hashes) of all resources.
+This approach is:
-# Verify
-ocm verify cv --signature dev ghcr.io/myorg/component:1.0.0
-```
+- **Efficient**: Verification doesn't require downloading large artifacts
+- **Complete**: Any change to any resource changes its digest, invalidating the signature
+- **Portable**: The descriptor can be verified independently of artifact storage
-### Example 2: Enterprise Production Setup (CA-Signed, PEM Encoding)
+{{< /details >}}
-**Prerequisites:** Use CA-signed production keys (see "CA-Signed Keys" section).
+{{< details "What's the difference between the private and public key?" >}}
-**Key differences from Development:**
+- **Private key**: Used to create signatures. Keep it secret โ anyone with this key can sign components as you.
+- **Public key**: Used to verify signatures. Share it freely with anyone who needs to verify your components.
-- Uses `signatureEncodingPolicy: PEM`
-- Certificate chain embedded in signature
-- Validates against system trust store
-- Minimal `.ocmconfig` needed for verification
+{{< /details >}}
-**Signer specification (~/prod-signer.yaml):**
+{{< details "Can a component have multiple signatures?" >}}
+Yes! A component version can have multiple signatures from different parties. This enables:
-```yaml
-type: RSA/v1alpha1
-signatureAlgorithm: RSASSA-PSS
-signatureEncodingPolicy: PEM
-privateKeyPEMFile: ~/.ocm/keys/prod/private.pem
-```
+- Different signing identities (dev, staging, prod)
+- Multiple approval workflows
+- Cross-organizational trust chains
-**Sign:**
+Use `--signature ` to specify which signature to create or verify.
+{{< /details >}}
-```bash
-ocm sign cv --signer-spec ~/prod-signer.yaml --signature prod ghcr.io/myorg/component:1.0.0
-```
+## Cleanup
-**Verify:**
+Remove the tutorial artifacts:
```bash
-# Certificate chain validated automatically from signature
-ocm verify cv --signature prod ghcr.io/myorg/component:1.0.0
+rm -rf $HOME/ocm-signing-tutorial
+# Optionally remove keys: rm -rf $HOME/.ocm/keys
+# Optionally remove config: rm $HOME/.ocmconfig
```
-## Troubleshooting
-
-### Signature Verification Fails
-
-**Error:** "signature verification failed"
-
-**Common causes:**
-
-1. Wrong public key configured
-2. Component version modified after signing
-3. Signature name mismatch
-4. Certificate chain invalid (PEM encoding)
-
-**Solutions:**
-
-- Verify public key matches private key: `openssl rsa -in private.pem -pubout`
-- Check signature name: `ocm get cv -o yaml ghcr.io/myorg/component:1.0.0`
-- Verify certificate chain: `openssl verify -CAfile ca-chain.pem certificate.pem`
-
-### Private Key Not Found
-
-**Error:** "could not resolve credentials for identity"
-
-**Solutions:**
-
-- Check `.ocmconfig` path and syntax
-- Verify file paths in `private_key_pem_file`
-- Ensure `signature` attribute matches between config and command
-
-### Certificate Chain Validation Fails (PEM)
-
-**Error:** "certificate validation failed"
-
-**Solutions:**
-
-- Ensure system trust store includes required root CAs
-- Provide root CA in `.ocmconfig`: `public_key_pem_file: ./ca-root.pem`
-- Verify certificate DN matches signature name
-- Check certificate expiry: `openssl x509 -in cert.pem -noout -dates`
-
-### Signature Already Exists
-
-**Error:** "signature 'name' already exists"
-
-**Solutions:**
-
-- Use `--force` to overwrite: `ocm sign cv ... --force`
-- Use a different signature name: `--signature name-v2`
-- Remove old signature first (manual descriptor editing)
-
-## Summary
-
-OCM's signing and verification system provides:
-
-- โ
**Flexible trust models** - From simple key pinning to enterprise PKI
-- โ
**Multiple algorithms** - RSASSA-PSS (recommended) and PKCS1v15
-- โ
**Encoding options** - Plain (compact) and PEM (with cert chains)
-- โ
**Multi-environment support** - Separate keys for dev, staging, prod
-- โ
**Signer specifications** - Fine-grained control over signing process
-- โ
**Credential integration** - Unified with OCM credential system
-
-**Choosing the right approach:**
+## Next Steps
-| Scenario | Recommended Approach |
-| --- | --- |
-| Local development | Self-signed, Plain encoding |
-| Small team | Self-signed, key pinning |
-| Medium organization | CA-signed, Plain, certificate pinning |
-| Enterprise | CA-signed, PEM, system trust store |
-| Compliance-driven | CA-signed, PEM, HSM integration |
+- [How-to: Generate Signing Keys]({{< relref "generate-signing-keys.md" >}}) - Step-by-step creating RSA key pairs.
+- [How-to: Configure Signing Credentials]({{< relref "configure-signing-credentials.md" >}}) - Set up OCM to use your keys for signing and verification
+- [How-to: Sign a Component Version]({{< relref "sign-component-version.md" >}}) - Step-by-step signing instructions
+- [How-to: Verify a Component Version]({{< relref "verify-component-version.md" >}}) - Step-by-step verification instructions
## Related Documentation
-- [OCM Credentials]({{< relref "/docs/concepts/credential-system.md" >}}) - How OCM resolves credentials for registries and services
-- [OCM CLI Reference]({{< relref "docs/reference/ocm-cli/_index.md" >}}) - Complete command-line options
+- [Concept: Signing and Verification]({{< relref "docs/concepts/signing-and-verification-concept.md" >}}) - Understand the theory behind OCM signing
+- [How-to: Generate Signing Keys]({{< relref "docs/how-to/generate-signing-keys.md" >}}) - Detailed key generation guide
+- [How-to: Configure Signing Credentials]({{< relref "docs/how-to/configure-signing-credentials.md" >}}) - Multi-environment and advanced configurations