Verify Component Versions
On this page
Goal#
Validate a component version signature to ensure it is authentic and has not been tampered with. OCM supports multiple verification algorithms. Pick the tab that matches the algorithm the signature was made with β each tab is a self-contained walkthrough.
Verify an RSA signature using the matching public key configured in .ocmconfig.
To run this you need the signer’s public key on disk and pointed at by .ocmconfig (see prerequisites). With Sigstore (other tab) you don’t install a public key at all β you just declare which identity you trust.
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
- Verification credentials configured with the public key
- A signed component version to verify in your current directory, here we use the
helloworldcomponent version from the getting started guide that you’ve signed in the How-To: Sign Component Versions guide.
Steps#
Verify the component version#
Run the verify command against your signed component:
ocm verify cv <repository>//<component>:<version>Local CTF Archive:
ocm verify cv /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0Remote OCI Registry:
ocm verify cv ghcr.io/<your-namespace>//github.com/acme.org/helloworld:1.0.0Expected output
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
0on success.Verify a specific signature (optional)#
If the component has multiple signatures, specify which one to verify:
ocm verify cv --signature prod ghcr.io/<your-namespace>//github.com/acme.org/helloworld:1.0.0π Without the
--signatureflag, OCM uses the configuration nameddefault.List available signatures (optional)#
View all signatures in a component version:
ocm get cv ./tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml | grep -A 10 signatures:
Troubleshooting (RSA)#
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:
# Check which signature names exist
ocm get cv /tmp/helloworld/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 <name> /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0Symptom: “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.
Symptom: “invalid key format”#
Cause: The public key file is not in PEM format.
Fix: Verify the key starts with -----BEGIN PUBLIC KEY-----:
head -n 1 /tmp/keys/public-key.pemVerify a Sigstore keyless signature. There’s no public key to install on this side either β you tell OCM which identity you trust, and it checks the signature was made by that identity.
If you’ve done classical key-based verification, here’s what changes:
| Aspect | RSA | Sigstore |
|---|---|---|
| Before you verify | Obtain the signer’s public key, configure .ocmconfig | Nothing β declare expected identity in a verifier spec file |
| What proves trust | Signature decrypts with the public key you have | Signature ties back to an OIDC identity you’ve decided to trust |
| Key rotation problem | You re-distribute the new public key | Doesn’t apply β there’s no long-lived key |
Mental model: instead of asking “does this signature match the public key I was handed?” you ask “was this signed by jane.doe@example.com logging in via GitHub?” The verifier only needs to know who to trust.
You’ll end up with#
- Confidence that a component version was signed by an identity you trust
Estimated time: ~3 minutes
Prerequisites#
- OCM CLI installed
- A component version signed with Sigstore (see How-To: Sign Component Versions)
- The expected signer identity (their OIDC email and which provider they logged in with)
Want the full picture of how Sigstore verification works behind the scenes (Fulcio certificate validation, Rekor inclusion proofs, TUF trust roots)? A dedicated Sigstore tutorial is in the works. For now, ADR 0017: Sigstore Integration covers the design.
Steps#
Declare which identity you trust#
In Sigstore, the verifier’s only job is to decide whose signatures to accept. You do that with a small spec file.
Two values matter:
certificateIdentityβ the email or workload identity of whoever signed (e.g.jane.doe@example.com)certificateOIDCIssuerβ which OIDC provider they logged in with (e.g. GitHub vs. Google β both could have ajane.doe@example.com)
Create
sigstore-verify.yaml:# sigstore-verify.yaml type: SigstoreVerificationConfiguration/v1alpha1 certificateOIDCIssuer: https://github.com/login/oauth certificateIdentity: jane.doe@example.comThat’s the entire trust configuration. No public key to fetch, no certificate to install.
Pick the rightcertificateOIDCIssuervalueOn public Sigstore (
oauth2.sigstore.dev), the issuer recorded in the signing certificate is the upstream identity provider’s issuer URL β not the Sigstore Dex endpoint. Pick the one matching the provider the signer logged in with:Signer logged in via certificateOIDCIssuervalueGoogle https://accounts.google.comGitHub https://github.com/login/oauthMicrosoft https://login.microsoftonline.comBoth
certificateOIDCIssuerandcertificateIdentityare required. They’re what makes the signature meaningful β without them you’d be accepting any Sigstore signature from anyone.Verify the component version#
Run the verify command with the verifier spec:
ocm verify cv \ --verifier-spec ./sigstore-verify.yaml \ /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0ocm verify cv \ --verifier-spec ./sigstore-verify.yaml \ ghcr.io/<my-namespace>//github.com/acme.org/helloworld:1.0.0Expected output
time=2026-05-19T18:49:13.316+02:00 level=INFO msg="verifying signature" name=default time=2026-05-19T18:49:13.856+02:00 level=INFO msg="signature verification completed" name=default duration=539.512209ms time=2026-05-19T18:49:13.856+02:00 level=INFO msg="SIGNATURE VERIFICATION SUCCESSFUL"Verify a specific signature#
If the component carries multiple signatures (e.g. an RSA signature and a Sigstore signature), select one with
--signature:ocm verify cv \ --verifier-spec ./sigstore-verify.yaml \ --signature sigstore \ ghcr.io/<your namespace>//github.com/acme.org/helloworld:1.0.0The verifier spec’s
typefield decides which verifier handles the signature. The--signatureflag picks which signature on the component to verify.
Inspect the recorded identity (optional)#
If verification fails because of an identity mismatch, you can read the identity directly from the signature to see what to put in your spec:
ocm get cv /tmp/helloworld/transport-archive//github.com/acme.org/helloworld:1.0.0 -o yaml \
| yq '.[0].signatures[] | select(.signature.algorithm == "sigstore")'Look for the signer email and the OIDC issuer URL. Those are exactly what certificateIdentity and certificateOIDCIssuer are matched against.
Troubleshooting#
Symptom: “no matching CertificateIdentity found”#
Cause: The signature was made by a different identity than what your spec expects β or the same identity but via a different OIDC provider.
The full error names which side did not match. For an identity mismatch:
Error: SIGNATURE VERIFICATION FAILED: cosign verify-blob failed: exit status 1
stderr: Error: failed to verify certificate identity: no matching CertificateIdentity found, last error: expected SAN value "nobody@nowhere.invalid", got "john.doe@gmail.com"For an issuer mismatch:
Error: SIGNATURE VERIFICATION FAILED: cosign verify-blob failed: exit status 1
stderr: Error: failed to verify certificate identity: no matching CertificateIdentity found, last error: expected issuer value "https://accounts.google.com", got "https://github.com/login/oauth"Fix: Inspect the signature (see above) to read the actual identity, and update certificateIdentity / certificateOIDCIssuer to match. Watch for trailing slashes and capitalization.
Symptom: “keyless verification requires both an issuer constraint … and an identity constraint”#
Cause: Your verifier spec is missing certificateIdentity, certificateOIDCIssuer, or both.
The full error:
Error: SIGNATURE VERIFICATION FAILED: invalid verification config: keyless verification requires both an issuer constraint (CertificateOIDCIssuer or CertificateOIDCIssuerRegexp) and an identity constraint (CertificateIdentity or CertificateIdentityRegexp)Fix: Both are mandatory β they’re how Sigstore knows whose signatures to accept. See Step 1 above.
CLI Reference#
| Command | Description |
|---|---|
ocm verify component-version | Verify a component version signature |
ocm get component-version | View component with signatures |
Next Steps#
- How-to: Sign Component Versions β Add signatures to your components (RSA or Sigstore)
- Tutorial: Signing and Verification β Learn how to sign and verify components in a complete tutorial
Related Documentation#
- Concept: Signing and Verification β Understand how OCM signing works
- ADR 0017: Sigstore Integration β Sigstore design and OIDC flow details