Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PKCS11 signing support #985

Merged
merged 10 commits into from
Nov 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ builds:
env:
- PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/"

- id: linux-pkcs11key-amd64
binary: cosign-linux-pkcs11key-amd64
main: ./cmd/cosign
flags:
- -trimpath
mod_timestamp: '{{ .CommitTimestamp }}'
goos:
- linux
goarch:
- amd64
ldflags:
- "{{ .Env.LDFLAGS }}"
tags:
- pkcs11key

- id: darwin-amd64
binary: cosign-darwin-amd64
no_unique_dist_dir: true
Expand Down
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ cosign: $(SRCS)
cosign-pivkey: $(SRCS)
CGO_ENABLED=1 go build -trimpath -tags=pivkey -ldflags $(LDFLAGS) -o cosign ./cmd/cosign

cosign-pkcs11key: $(SRCS)
CGO_ENABLED=1 go build -trimpath -tags=pkcs11key -ldflags $(LDFLAGS) -o cosign ./cmd/cosign

GOLANGCI_LINT_DIR = $(shell pwd)/bin
GOLANGCI_LINT_BIN = $(GOLANGCI_LINT_DIR)/golangci-lint
golangci-lint:
Expand Down
89 changes: 89 additions & 0 deletions PKCS11.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# PKCS11 Tokens

The `cosign` command line tool optionally supports PKCS11 tokens for signing.
This support is enabled through the [crypto11](https://github.com/ThalesIgnite/crypto11) and the [pkcs11](https://github.com/miekg/pkcs11) libraries, which are not included in the standard release. Use [`make cosign-pkcs11key`](https://github.com/sigstore/cosign/blob/a8d1cc1132d4a019a62ff515b9375c8c5b98a5c5/Makefile#L52), or `go build -tags=pkcs11key`, to build `cosign` with support for PKCS11 tokens.

## Quick Start

### Setup

To get started, make sure you already have your PKCS11 module installed, and insert your PKCS11-compatible token.

Then, run the command `cosign pkcs11-tool list-tokens` to get the slot id of your token, as follows :

```shell
$ cosign pkcs11-tool list-tokens --module-path /usr/local/lib/libp11.so
Listing tokens of PKCS11 module '/usr/local/lib/libp11.so'
Token in slot 1
Label: TokenLabel
Manufacturer: Token Manufacturer
Model: Token Model
S/N: 68800ca5c75e074c
```

Afterwards, run the command `cosign pkcs11-tool list-keys-uris` to retrieve the PKCS11 URI of the key you wish to use, as follows :

```shell
$ cosign pkcs11-tool list-keys-uris --module-path /usr/local/lib/libp11.so --slot-id 1 --pin 1234
Listing URIs of keys in slot '1' of PKCS11 module '/usr/local/lib/libp11.so'
Object 0
Label: key_label_1
ID: 4a8d2f6ed9c4152b260d6c74a1ae72fcfdc64b65
URI: pkcs11:token=TokenLabel;slot-id=1;id=%4a%8d%2f%6e%d9%c4%15%2b%26%0d%6c%74%a1%ae%72%fc%fd%c6%4b%65?module-path=/usr/local/lib/libp11.so&pin-value=1234
Object 1
Label: key_label_2
ID: 57b39235cc6dec404c2310d7e37d5cbb5f1bba70
URI: pkcs11:token=TokenLabel;slot-id=1;id=%57%b3%92%35%cc%6d%ec%40%4c%23%10%d7%e3%7d%5c%bb%5f%1b%ba%70?module-path=/usr/local/lib/libp11.so&pin-value=1234
```

You can also construct the PKCS11 URI of your key manually by providing the following URI components :

* **module-path** : the absolute path to the PKCS11 module **(optional)**

* **token** and/or **slot-id** : either or both of the PKCS11 token label and the PKCS11 slot id **(mandatory)**

* **object** and/or **id** : either or both of the PKCS11 key label and the PKCS11 key id **(mandatory)**

* **pin-value** : the PIN of the PKCS11 token **(optional)**

If `module-path` is not present in the URI, `cosign` expects the PKCS11 module path to be set using the environment variable `COSIGN_PKCS11_MODULE_PATH`. If neither are set, `cosign` will fail. If both are set, `module-path` has priority over `COSIGN_PKCS11_MODULE_PATH` environment variable.

If `pin-value` is not present in the URI, `cosign` expects the PIN to be set using the environment variable `COSIGN_PKCS11_PIN`. If it is not, `cosign` checks whether the PKCS11 token requires user login (flag CKF_LOGIN_REQUIRED set), and if so, `cosign` will invite the user to enter the PIN only during signing. If both `pin-value` and `COSIGN_PKCS11_PIN` environment variable are set, `pin-value` has priority over `COSIGN_PKCS11_PIN`.

### Signing

You can then use the normal `cosign` commands to sign images and blobs with your PKCS11 key.

```shell
$ cosign sign --key "<PKCS11_URI>" gcr.io/dlorenc-vmtest2/demo
Pushing signature to: gcr.io/dlorenc-vmtest2/demo:sha256-410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd.sig
```

To verify, you can either use the PKCS11 token key directly:

```shell
$ cosign verify --key "<PKCS11_URI>" gcr.io/dlorenc-vmtest2/demo
Verification for gcr.io/dlorenc-vmtest2/demo --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
- Any certificates were verified against the Fulcio roots.

[{"critical":{"identity":{"docker-reference":"gcr.io/dlorenc-vmtest2/demo"},"image":{"docker-manifest-digest":"sha256:410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd"},"type":"cosign container image signature"},"optional":null}]
```

Or export the public key and verify against that:

```shell
$ cosign public-key --key "<PKCS11_URI>" > pub.key

$ cosign verify --key pub.key gcr.io/dlorenc-vmtest2/demo
Verification for gcr.io/dlorenc-vmtest2/demo --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
- Any certificates were verified against the Fulcio roots.

[{"critical":{"identity":{"docker-reference":"gcr.io/dlorenc-vmtest2/demo"},"image":{"docker-manifest-digest":"sha256:410a07f17151ffffb513f942a01748dfdb921de915ea6427d61d60b0357c1dcd"},"type":"cosign container image signature"},"optional":null}]

```
1 change: 1 addition & 0 deletions cmd/cosign/cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func New() *cobra.Command {
cmd.AddCommand(Initialize())
cmd.AddCommand(Manifest())
cmd.AddCommand(PIVTool())
cmd.AddCommand(PKCS11Tool())
cmd.AddCommand(Policy())
cmd.AddCommand(PublicKey())
cmd.AddCommand(Sign())
Expand Down
54 changes: 54 additions & 0 deletions cmd/cosign/cli/options/pkcs11_tool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package options

import (
"github.com/spf13/cobra"
)

// PKCS11ToolListTokens is the wrapper for `pkcs11-tool list-tokens` related options.
type PKCS11ToolListTokensOptions struct {
ModulePath string
}

var _ Interface = (*PKCS11ToolListTokensOptions)(nil)

// AddFlags implements Interface
func (o *PKCS11ToolListTokensOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.ModulePath, "module-path", "",
"absolute path to the PKCS11 module")
}

// PKCS11ToolListKeysUrisOptions is the wrapper for `pkcs11-tool list-keys-uris` related options.
type PKCS11ToolListKeysUrisOptions struct {
ModulePath string
SlotID uint
Pin string
}

var _ Interface = (*PKCS11ToolListKeysUrisOptions)(nil)

// AddFlags implements Interface
func (o *PKCS11ToolListKeysUrisOptions) AddFlags(cmd *cobra.Command) {
cmd.Flags().StringVar(&o.ModulePath, "module-path", "",
"absolute path to the PKCS11 module")

cmd.Flags().UintVar(&o.SlotID, "slot-id", 0,
"id of the PKCS11 slot, uses 0 if empty")

cmd.Flags().StringVar(&o.Pin, "pin", "",
"pin of the PKCS11 slot, uses environment variable COSIGN_PKCS11_PIN if empty")
}
80 changes: 80 additions & 0 deletions cmd/cosign/cli/pkcs11_tool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//go:build pkcs11key
// +build pkcs11key

// Copyright 2021 The Sigstore Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
"github.com/spf13/cobra"

"github.com/sigstore/cosign/cmd/cosign/cli/options"
"github.com/sigstore/cosign/cmd/cosign/cli/pkcs11cli"
)

var pkcs11ToolForce bool

func PKCS11Tool() *cobra.Command {
cmd := &cobra.Command{
Use: "pkcs11-tool",
Short: "Provides utilities for retrieving information from a PKCS11 token.",
}

cmd.AddCommand(
pkcs11ToolListTokens(),
PKCS11ToolListKeysUrisOptions(),
)

// TODO: drop -f in favor of --no-input only
// TODO: use the force flag.
cmd.PersistentFlags().BoolVarP(&pkcs11ToolForce, "no-input", "f", false,
"skip warnings and confirmations")

return cmd
}

func pkcs11ToolListTokens() *cobra.Command {
o := &options.PKCS11ToolListTokensOptions{}

cmd := &cobra.Command{
Use: "list-tokens",
Short: "list-tokens lists all PKCS11 tokens linked to a PKCS11 module",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return pkcs11cli.ListTokensCmd(cmd.Context(), o.ModulePath)
},
}

o.AddFlags(cmd)

return cmd
}

func PKCS11ToolListKeysUrisOptions() *cobra.Command {
o := &options.PKCS11ToolListKeysUrisOptions{}

cmd := &cobra.Command{
Use: "list-keys-uris",
Short: "list-keys-uris lists URIs of all keys in a PKCS11 token",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
return pkcs11cli.ListKeysUrisCmd(cmd.Context(), o.ModulePath, o.SlotID, o.Pin)
},
}

o.AddFlags(cmd)

return cmd
}
29 changes: 29 additions & 0 deletions cmd/cosign/cli/pkcs11_tool_disabled.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//go:build !pkcs11key
// +build !pkcs11key

// Copyright 2021 The Sigstore Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cli

import (
"github.com/spf13/cobra"
)

func PKCS11Tool() *cobra.Command {
return &cobra.Command{
Use: "pkcs11-tool",
Short: "This cosign was not built with pkcs11-tool support!",
}
}
Loading