Skip to content

Commit 5323148

Browse files
committed
cosign: fix image signature verification by tag
For a tag (e.g. :latest), there is no reference.digest(). image-rs falls back to image.manifest_digest, which comes from pull_manifest in the image pull path. Cosign (and sigstore triangulation) uses fetch_manifest_digest for that ref — the same digest cosign verify uses. For multi-arch images, pull_manifest can be a platform-specific child while the signature (and triangulation) refer to the list/index digest, so the two strings don’t match even when verification is correct. verify_signature_and_get_payload now returns (payloads, source_image_digest), where source_image_digest is the digest from client.triangulate (same as cosign’s triangulation / fetch_manifest_digest). Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> Assisted-by: AI For the payload digest check: * @sha256:… in the reference -> still use reference digest. * Tag only (:latest, etc.) -> use triangulated_manifest_digest, not pull_manifest’s digest. So tag pulls stay aligned with cosign verify --key … image:tag. Signed-off-by: Emanuele Giuseppe Esposito <eesposit@redhat.com>
1 parent 00b55b2 commit 5323148

1 file changed

Lines changed: 15 additions & 12 deletions

File tree

  • image-rs/src/signature/policy/cosign

image-rs/src/signature/policy/cosign/mod.rs

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ impl CosignParameters {
9494
};
9595

9696
// Verification, will access the network
97-
let payloads = self
97+
let (payloads, triangulated_manifest_digest) = self
9898
.verify_signature_and_get_payload(image, auth, key, certificates, proxy_config)
9999
.await?;
100100

@@ -104,14 +104,16 @@ impl CosignParameters {
104104
payload.validate_signed_docker_reference(&image.reference, rule)?;
105105
}
106106

107-
// When the user pins `@sha256:…`, cosign payloads usually record that digest (often a
108-
// multi-arch manifest list). `pull_manifest` may resolve to a platform-specific child
109-
// manifest with a different digest — compare against the reference digest when set.
110-
let digest_for_comparison = image
111-
.reference
112-
.digest()
113-
.map(str::to_string)
114-
.unwrap_or_else(|| image.manifest_digest.to_string());
107+
// Digest to compare with the cosign simple-signing payload:
108+
// - If the user pinned `@sha256:…`, use that (matches multi-arch index vs per-arch pull).
109+
// - If they used a tag (e.g. `:latest`), use the digest from sigstore triangulation —
110+
// same as `cosign verify` / `fetch_manifest_digest`, not necessarily `pull_manifest`'s
111+
// digest (which can be a platform-specific child of a manifest list).
112+
let digest_for_comparison = if let Some(d) = image.reference.digest() {
113+
d.to_string()
114+
} else {
115+
triangulated_manifest_digest.clone()
116+
};
115117
payload.validate_signed_docker_manifest_digest(&digest_for_comparison)?;
116118
}
117119

@@ -142,7 +144,8 @@ impl CosignParameters {
142144
/// * Download the signature image, gather the signatures and verify them
143145
/// using the pubkey.
144146
///
145-
/// If succeeds, the payloads of the signature will be returned.
147+
/// If succeeds, returns the verified payloads and the manifest digest string from cosign
148+
/// triangulation (registry `fetch_manifest_digest`), aligned with `cosign verify`.
146149
#[allow(clippy::too_many_arguments)]
147150
async fn verify_signature_and_get_payload(
148151
&self,
@@ -151,7 +154,7 @@ impl CosignParameters {
151154
key: Vec<u8>,
152155
certificates: Vec<&Certificate>,
153156
proxy_config: Option<&ProxyConfig>,
154-
) -> Result<Vec<SigPayload>> {
157+
) -> Result<(Vec<SigPayload>, String)> {
155158
let image_ref = OciReference::from_str(&image.reference.whole())?;
156159
let auth = match auth {
157160
RegistryAuth::Anonymous => Auth::Anonymous,
@@ -212,7 +215,7 @@ impl CosignParameters {
212215
.iter()
213216
.map(|layer| SigPayload::from(layer.simple_signing.clone()))
214217
.collect();
215-
return Ok(payloads);
218+
return Ok((payloads, source_image_digest));
216219
}
217220
Err(SigstoreVerifyConstraintsError {
218221
unsatisfied_constraints,

0 commit comments

Comments
 (0)