Skip to content

cosign sign --signing-config panics with PKCS#11 keys: nil pointer dereference in SignMessage #4775

@4x0v7

Description

@4x0v7

Description

cosign sign with --signing-config and --key pkcs11:... panics with a nil pointer dereference when attempting to sign. The PKCS#11 session is closed before the signing operation occurs.

Version

  • cosign v3.0.5 (built with -tags pkcs11key)
  • Go 1.25.6
  • Ubuntu 24.04 (GitHub Actions runner)

Steps to Reproduce

  1. Set up a PKCS#11 token with an EC P-256 key (no certificate stored on token)
  2. Create a signing config pointing to a Rekor v2 instance:
    {
      "mediaType": "application/vnd.dev.sigstore.signingconfig.v0.2+json",
      "rekorTlogUrls": [
        { "url": "https://rekor.example.com", "majorApiVersion": 2,
          "validFor": { "start": "2025-01-01T00:00:00Z" } }
      ],
      "caUrls": [], "oidcUrls": [], "tsaUrls": [],
      "rekorTlogConfig": { "selector": "ANY" },
      "tsaConfig": { "selector": "ANY" }
    }
  3. Run:
    cosign sign \
      --key "pkcs11:token=mytoken;object=mykey?pin-value=1234&module-path=/usr/lib/libpkcs11.so" \
      --cert cert.pem --cert-chain chain.pem \
      --signing-config signing-config.json \
      --bundle output.bundle --yes \
      registry.example.com/image@sha256:abc123

Expected Behavior

Image is signed and a bundle is written.

Actual Behavior

Panic with nil pointer dereference:

WARNING: no x509 certificate retrieved from the PKCS11 token
Signing artifact...
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x20 pc=0x1fadc19]

goroutine 1 [running]:
github.com/sigstore/cosign/v3/pkg/cosign/pkcs11key.(*Key).SignMessage(...)
    pkcs11key/pkcs11key.go:250
github.com/sigstore/cosign/v3/internal/key.(*SignerVerifierKeypair).SignData(...)
    internal/key/svkeypair.go:132
github.com/sigstore/sigstore-go/pkg/sign.Bundle(...)
    sigstore-go@v1.1.4/pkg/sign/signer.go:68
github.com/sigstore/cosign/v3/pkg/cosign/bundle.SignData(...)
    pkg/cosign/bundle/sign.go:140
github.com/sigstore/cosign/v3/cmd/cosign/cli/signcommon.WriteNewBundleWithSigningConfig(...)
    cmd/cosign/cli/signcommon/common.go:534

Root Cause

In cmd/cosign/cli/signcommon/common.go, GetKeypairAndToken creates a sign.Keypair from the PKCS#11-backed SignerVerifier, then defers sv.Close():

func GetKeypairAndToken(ctx context.Context, ko options.KeyOpts, cert, certChain string) (sign.Keypair, *SignerVerifier, []byte, string, error) {
    // ...
    sv, ephemeralKeypair, err = signerFromKeyOpts(ctx, cert, certChain, ko)
    // ...
    keypair, err = key.NewSignerVerifierKeypair(sv, ko.DefaultLoadOptions)
    // ...
    defer func() {
        if sv != nil {
            sv.Close()  // <-- closes the PKCS#11 session
        }
    }()
    // ...
    return keypair, sv, certBytes, idToken, nil
}

NewSignerVerifierKeypair wraps the SignerVerifier (which holds a reference to the PKCS#11 Key). The defer sv.Close() fires on return, which calls Key.Close():

func (k *Key) Close() {
    k.ctx.Close()
    k.signer = nil  // <-- nils the signer
    k.cert = nil
    k.ctx = nil
}

The returned keypair still references the same Key struct. When WriteNewBundleWithSigningConfigbundle.SignDataSignerVerifierKeypair.SignDataKey.SignMessage is called, k.signer is nil, causing the panic.

This does not affect file-based or KMS keys because their Close() is a no-op or doesn't nil out the signer. It specifically affects PKCS#11 and likely PIV keys.

Suggested Fix

Remove the defer sv.Close() from GetKeypairAndToken and instead have the caller (WriteNewBundleWithSigningConfig) manage the lifecycle, similar to how GetBundleComponents returns a closeSV function that the caller defers.

Alternatively, NewSignerVerifierKeypair could snapshot the crypto.Signer and crypto.PublicKey at construction time rather than delegating to the underlying key, but that would require the PKCS#11 module to support detached signing which may not always be true.

Affects

  • cosign sign --signing-config --key pkcs11:...
  • cosign attest --signing-config --key pkcs11:...
  • Likely also cosign sign-blob --signing-config --key pkcs11:...
  • Likely affects PIV keys (--sk) in the same code path
  • Present since v2.6.0 (PR Support self-managed keys when signing with sigstore-go #4368) when self-managed key support was added to the signing-config path

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions