Skip to content

cosign cannot verify a P-384 signature it produced, with the matching public key #5092

Description

@duanegrace

Description

cosign verify-blob --key fails against a bundle cosign sign-blob --key produced moments earlier, when the key is ECDSA P-384. The same sequence with a P-256 key succeeds.

The bundle is internally correct. It records SHA2_384 as the digest algorithm, the recorded digest is the correct SHA-384 of the input, and the signature verifies against that digest with the public key when checked with openssl. Only cosign's own verification of it fails.

Declaring the algorithm at signing with --signing-algorithm ecdsa-sha2-384-nistp384 does not change the outcome. verify-blob exposes no corresponding flag, and the algorithm recorded in the bundle appears not to be honoured on the key based verification path.

Versions affected

  • v3.1.3 on linux/x86_64
  • v3.1.3 on darwin/arm64 (GitCommit 11926fa5bbbbde47e88fc006b625a17769b743b2)
  • v2.6.1 on linux/x86_64

v2.6.1 is after #4050, "Remove SHA256 assumption in sign-blob/verify-blob", which was released in v2.6.0. That change appears not to cover this path.

Reproduction

No registry, no transparency log, no key management service, no credentials.

export COSIGN_PASSWORD=""

# 1. a P-384 key
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out p384.pem
cosign import-key-pair --key p384.pem --output-key-prefix p384

# 2. sign, declaring the algorithm
echo "hello" > blob.txt
cosign sign-blob --key p384.key \
  --signing-algorithm ecdsa-sha2-384-nistp384 \
  --bundle p384.bundle \
  --tlog-upload=false --use-signing-config=false --yes blob.txt

# 3. verify with the same tool and the matching public key
cosign verify-blob --key p384.pub --bundle p384.bundle \
  --insecure-ignore-tlog=true blob.txt

Observed

Signing artifact...
Wrote bundle to file p384.bundle

WARNING: Skipping tlog verification is an insecure practice that lacks transparency and auditability verification for the blob.
Error: failed to verify signature: could not verify message: invalid signature when validating ASN.1 encoded signature
error during command execution: failed to verify signature: could not verify message: invalid signature when validating ASN.1 encoded signature

Expected

Verified OK, as the identical sequence gives with a P-256 key.

The bundle is correct, and the signature is valid

The bundle records:

mediaType                                 application/vnd.dev.sigstore.bundle.v0.3+json
messageSignature/messageDigest/algorithm  SHA2_384

The recorded digest equals sha384(blob.txt), and the signature verifies against it:

python3 - <<'PY'
import json, base64, hashlib
b = json.load(open('p384.bundle'))
ms = b['messageSignature']
recorded = base64.b64decode(ms['messageDigest']['digest'])
actual = hashlib.sha384(open('blob.txt','rb').read()).digest()
print("recorded digest == sha384(blob):", recorded == actual)
open('sig.der','wb').write(base64.b64decode(ms['signature']))
PY

openssl pkey -in p384.pem -pubout -out p384.pubkey.pem
openssl dgst -sha384 -verify p384.pubkey.pem -signature sig.der blob.txt

gives

recorded digest == sha384(blob): True
Verified OK

So the signature cosign produced is valid over the digest cosign recorded, using the algorithm cosign recorded. The failure is in verification alone.

Control

The same sequence with a P-256 key returns Verified OK from cosign verify-blob in both v2.6.1 and v3.1.3.

Independently reproduced with a hardware backed key on another platform

The reproduction above uses a software key file, which leaves open the possibility that the fault lies in key import or in local key handling. It does not.

The same failure occurs on darwin/arm64 with cosign v3.1.3 against non exportable EC-HSM keys held in Azure Key Vault, addressed through the azurekms:// key management service provider. No private key material exists outside the hardware module, and the signing operation is performed by the module.

Curve Signer Verifier Result
P-256 Key Vault EC-HSM, azurekms:// public key exported to PEM Verified OK
P-384 Key Vault EC-HSM, azurekms:// public key exported to PEM invalid signature when validating ASN.1 encoded signature

Both blobs were the same input file, signed minutes apart with the same cosign binary against the same vault, with the curve the only variable.

The image path fails differently, and it is the same defect

cosign sign and cosign verify on an OCI image wrap the signature in a DSSE envelope, and the failure there surfaces as:

could not verify envelope: accepted signatures do not match threshold, Found: 0, Expected 1

rather than as the ASN.1 message above. Signing the same image with a P-256 key from the same vault and verifying it with the exported public key returns Verified OK. Anyone searching for the threshold message is looking at this defect, and the two messages should be linked.

Why this may have gone unreported

cosign generate-key-pair produces P-256, so the default path is unaffected. The defect is reached only by supplying a P-384 key, which is the common case for organisations whose signing keys are generated in a hardware security module under a FIPS 140-3 posture and cannot be exported.

Impact

An artefact signed with a P-384 key carries a valid signature that cosign cannot check. A verifier following the documented cosign verify path concludes the artefact is unverified, when it is correctly signed. That is a false negative in a verification tool, which is the direction that erodes trust in signing rather than the direction that breaks it, but it makes P-384 unusable for release signing in practice.

Environment

Two platforms, two key custody models, same result.

  • Linux x86_64, cosign binaries downloaded from the project's GitHub releases, software key files.
  • macOS arm64, cosign v3.1.3, non exportable EC-HSM keys in Azure Key Vault via azurekms://.

OpenSSL and a short Python script are used only as independent checks and are not part of the reproduction.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions