---
title: How to verify downloaded cosign signatures
tags: cosign, images, containers
---

We're currently working on a way to update the containers we're using for [Dangerzone](https://dangerzone.rocks) without having to issue new releases.

In order to do that, we push new container images to a container registry, and sign them with an hardware key.

In addition, we want to do the verification part without issuing HTTP requests, to avoid leaking the fact we're doing the check.

Signing the image is pretty straighforward, but verifying wasn't. There are tools for this but they mainly expect you're online and its okay to make network requests.

## Signing the image

In order to use `--sk`, you need to compile your own version of `cosign`, which adds suport for hardware keys.

```bash
git clone https://github.com/sigstore/cosign.git
cd cosign
make cosign-pivkey-pkcs11key  
```

Then, initialize the key.:

```bash
cosign piv-tool generate-key
# Or in case you want to disable the "touch" requirement
cosign piv-tool generate-key --touch-policy=never  
```

And sign:

```bash
docker login
./cosign sign --sk ghcr.io/almet/dangerzone/dangerzone@sha256:fa948726aac29a6ac49f01ec8fbbac18522b35b2491fdf716236a0b3502a2ca7
```

You might also need the public key handy. Here is how to get it:

```bash
./dev/cosign/cosign public-key --sk > pub.key  
```

## Verifying the signature

First, download the signatures locally and store them in `signature.json`

```bash
cosign download signature ghcr.io/almet/dangerzone/dangerzone@sha256:fa948726aac29a6ac49f01ec8fbbac18522b35b2491fdf716236a0b3502a2ca7 > signatures.json
```

Then, we will need to extract the information from this `signatures.json` file, and verify it in two different ways:

Either just check the signature against the payload, but bear in mind this won't do all the bells and whistles that come with sigstore / cosign. It will just verify that the signature matches the provided key.

```bash
# Extract the payload and the signature
cat signatures.json | tail -1 | jq -r .Base64Signature | base64 -d > signature
cat signatures.json | tail -1 | jq -r .Payload | base64 -d > payload

# Then, verify it with openssl
openssl dgst -sha256 -verify pub.key -signature signature payload

# Or with cosign
cosign verify-blob --key pub.key -signature signature payload
```

If you want (and you probably do) to verify the signature for the payload, the signed entry timestamp for rekor and the integrity of the rest of the properties (Sigstore SET), we will need to convert some of the keys to match the expected ones, and then invoke cosign:

```bash
# Convert the signature to a format known by --bundle
cat signatures.json | tail -1 | jq -r .Payload | base64 -d > payload
cat signatures.json | tail -1 | jq '{base64Signature: .Base64Signature, Payload, cert: .Cert, chain: .Chain, rekorBundle: {SignedEntryTimestamp: .Bundle.SignedEntryTimestamp, Payload: {body: .Bundle.Payload.body, integratedTime: .Bundle.Payload.integratedTime, logIndex: .Bundle.Payload.logIndex, logID: .Bundle.Payload.logID}}, RFC3161Timestamp}' > bundle.json

# And then use it when verifying
cosign verify-blob --key pub.key --bundle bundle.json payload
```

And :tada:, we've verified the signature offline!
