Merge branch 'master' into hs/acme-eab

This commit is contained in:
Herman Slatman 2021-09-16 18:20:39 +02:00
commit 66464ae302
No known key found for this signature in database
GPG Key ID: F4D8A44EA0A75A4F
30 changed files with 370 additions and 63 deletions

View File

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
go: [ '1.15', '1.16' ] go: [ '1.15', '1.16', '1.17' ]
outputs: outputs:
is_prerelease: ${{ steps.is_prerelease.outputs.IS_PRERELEASE }} is_prerelease: ${{ steps.is_prerelease.outputs.IS_PRERELEASE }}
steps: steps:
@ -62,8 +62,15 @@ jobs:
needs: test needs: test
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
outputs: outputs:
debversion: ${{ steps.extract-tag.outputs.DEB_VERSION }}
is_prerelease: ${{ steps.is_prerelease.outputs.IS_PRERELEASE }} is_prerelease: ${{ steps.is_prerelease.outputs.IS_PRERELEASE }}
steps: steps:
-
name: Extract Tag Names
id: extract-tag
run: |
DEB_VERSION=$(echo ${GITHUB_REF#refs/tags/v} | sed 's/-/./')
echo "::set-output name=DEB_VERSION::${DEB_VERSION}"
- -
name: Is Pre-release name: Is Pre-release
id: is_prerelease id: is_prerelease
@ -99,62 +106,71 @@ jobs:
name: Set up Go name: Set up Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: 1.16 go-version: 1.17
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@56f5b77f7fa4a8fe068bf22b732ec036cc9bc13f # v2.4.1
with:
version: latest
args: release --rm-dist
env:
GITHUB_TOKEN: ${{ secrets.PAT }}
release_deb:
name: Build & Upload Debian Package To Github
runs-on: ubuntu-20.04
needs: create_release
steps:
-
name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
-
name: Set up Go
uses: actions/setup-go@v2
with:
go-version: '1.16'
- -
name: APT Install name: APT Install
id: aptInstall id: aptInstall
run: sudo apt-get -y install build-essential debhelper fakeroot run: sudo apt-get -y install build-essential debhelper fakeroot
- -
name: Build Debian package name: Build Debian package
id: build id: make_debian
run: | run: |
PATH=$PATH:/usr/local/go/bin:/home/admin/go/bin PATH=$PATH:/usr/local/go/bin:/home/admin/go/bin
make debian make debian
# need to restore the git state otherwise goreleaser fails due to dirty state
git restore debian/changelog
git clean -fd
- -
name: Upload Debian Package name: Install cosign
id: upload_deb uses: sigstore/cosign-installer@v1.1.0
with:
cosign-release: 'v1.1.0'
-
name: Write cosign key to disk
id: write_key
run: echo "${{ secrets.COSIGN_KEY }}" > "/tmp/cosign.key"
-
name: Get Release Date
id: release_date
run: | run: |
tag_name="${GITHUB_REF##*/}" RELEASE_DATE=$(date +"%y-%m-%d")
hub release edit $(find ./.releases -type f -printf "-a %p ") -m "" "$tag_name" echo "::set-output name=RELEASE_DATE::${RELEASE_DATE}"
-
name: Run GoReleaser
uses: goreleaser/goreleaser-action@5a54d7e660bda43b405e8463261b3d25631ffe86 # v2.7.0
with:
version: latest
args: release --rm-dist
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.PAT }}
COSIGN_PWD: ${{ secrets.COSIGN_PWD }}
DEB_VERSION: ${{ needs.create_release.outputs.debversion }}
RELEASE_DATE: ${{ steps.release_date.outputs.RELEASE_DATE }}
build_upload_docker: build_upload_docker:
name: Build & Upload Docker Images name: Build & Upload Docker Images
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
needs: test needs: test
steps: steps:
- name: Checkout -
name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Setup Go -
name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.16' go-version: '1.17'
- name: Build -
name: Install cosign
uses: sigstore/cosign-installer@v1.1.0
with:
cosign-release: 'v1.1.0'
-
name: Write cosign key to disk
id: write_key
run: echo "${{ secrets.COSIGN_KEY }}" > "/tmp/cosign.key"
-
name: Build
id: build id: build
run: | run: |
PATH=$PATH:/usr/local/go/bin:/home/admin/go/bin PATH=$PATH:/usr/local/go/bin:/home/admin/go/bin
@ -162,3 +178,4 @@ jobs:
env: env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
COSIGN_PWD: ${{ secrets.COSIGN_PWD }}

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
strategy: strategy:
matrix: matrix:
go: [ '1.15', '1.16' ] go: [ '1.15', '1.16', '1.17' ]
steps: steps:
- -
name: Checkout name: Checkout

4
.gitignore vendored
View File

@ -14,8 +14,8 @@
# Others # Others
*.swp *.swp
.travis-releases .releases
coverage.txt coverage.txt
vendor
output output
vendor
.idea .idea

View File

@ -1,10 +1,12 @@
# This is an example .goreleaser.yml file with some sane defaults. # This is an example .goreleaser.yml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com # Make sure to check the documentation at http://goreleaser.com
project_name: step-ca project_name: step-ca
before: before:
hooks: hooks:
# You may remove this if you don't use go modules. # You may remove this if you don't use go modules.
- go mod download - go mod download
builds: builds:
- -
id: step-ca id: step-ca
@ -93,6 +95,7 @@ builds:
binary: bin/step-awskms-init binary: bin/step-awskms-init
ldflags: ldflags:
- -w -X main.Version={{.Version}} -X main.BuildTime={{.Date}} - -w -X main.Version={{.Version}} -X main.BuildTime={{.Date}}
archives: archives:
- -
# Can be used to change the archive formats for specific GOOSs. # Can be used to change the archive formats for specific GOOSs.
@ -106,13 +109,25 @@ archives:
files: files:
- README.md - README.md
- LICENSE - LICENSE
source: source:
enabled: true enabled: true
name_template: '{{ .ProjectName }}_{{ .Version }}' name_template: '{{ .ProjectName }}_{{ .Version }}'
checksum: checksum:
name_template: 'checksums.txt' name_template: 'checksums.txt'
extra_files:
- glob: ./.releases/*
signs:
- cmd: cosign
stdin: '{{ .Env.COSIGN_PWD }}'
args: ["sign-blob", "-key=/tmp/cosign.key", "-output=${signature}", "${artifact}"]
artifacts: all
snapshot: snapshot:
name_template: "{{ .Tag }}-next" name_template: "{{ .Tag }}-next"
release: release:
# Repo in which the release will be created. # Repo in which the release will be created.
# Default is extracted from the origin remote URL or empty if its private hosted. # Default is extracted from the origin remote URL or empty if its private hosted.
@ -139,7 +154,55 @@ release:
# You can change the name of the release. # You can change the name of the release.
# Default is `{{.Tag}}` # Default is `{{.Tag}}`
#name_template: "{{.ProjectName}}-v{{.Version}} {{.Env.USER}}" name_template: "Step CA {{ .Tag }} ({{ .Env.RELEASE_DATE }})"
# Header template for the release body.
# Defaults to empty.
header: |
## Official Release Artifacts
#### Linux
- 📦 [step-ca_linux_{{ .Version }}_amd64.tar.gz](https://dl.step.sm/certificates/{{ .Tag }}/step-ca_linux_{{ .Version }}_amd64.tar.gz)
- 📦 [step-ca_{{ .Env.DEB_VERSION }}_amd64.deb](https://dl.step.sm/certificates/{{ .Tag }}/step-ca_{{ .Env.DEB_VERSION }}_amd64.deb)
#### OSX Darwin
- 📦 [step-ca_darwin_{{ .Version }}_amd64.tar.gz](https://dl.step.sm/certificates/{{ .Tag }}/step-ca_darwin_{{ .Version }}_amd64.tar.gz)
- 📦 [step-ca_darwin_{{ .Version }}_arm64.tar.gz](https://dl.step.sm/certificates/{{ .Tag }}/step-ca_darwin_{{ .Version }}_arm64.tar.gz)
#### Windows
- 📦 [step-ca_windows_{{ .Version }}_arm64.zip](https://dl.step.sm/certificates/{{ .Tag }}/step-ca_windows_{{ .Version }}_amd64.zip)
For more builds across platforms and architectures, see the `Assets` section below.
And for packaged versions (Docker, k8s, Homebrew), see our [installation docs](https://smallstep.com/docs/step-ca/installation).
Don't see the artifact you need? Open an issue [here](https://github.com/smallstep/certificates/issues/new/choose).
## Signatures and Checksums
`step-ca` uses [sigstore/cosign](https://github.com/sigstore/cosign) for signing and verifying release artifacts.
Below is an example using `cosign` to verify a release artifact:
```
cosign verify-blob \
-key https://raw.githubusercontent.com/smallstep/certificates/master/cosign.pub \
-signature ~/Downloads/step-ca_darwin_{{ .Version }}_amd64.tar.gz.sig
~/Downloads/step-ca_darwin_{{ .Version }}_amd64.tar.gz
```
The `checksums.txt` file (in the `Assets` section below) contains a checksum for every artifact in the release.
# Footer template for the release body.
# Defaults to empty.
footer: |
## Thanks!
Those were the changes on {{ .Tag }}!
Come join us on [Discord](https://discord.gg/X2RKGwEbV9) to ask questions, chat about PKI, or get a sneak peak at the freshest PKI memes.
# You can disable this pipe in order to not upload any artifacts. # You can disable this pipe in order to not upload any artifacts.
# Defaults to false. # Defaults to false.
@ -149,6 +212,8 @@ release:
# The filename on the release will be the last part of the path (base). If # The filename on the release will be the last part of the path (base). If
# another file with the same name exists, the latest one found will be used. # another file with the same name exists, the latest one found will be used.
# Defaults to empty. # Defaults to empty.
extra_files:
- glob: ./.releases/*
#extra_files: #extra_files:
# - glob: ./path/to/file.txt # - glob: ./path/to/file.txt
# - glob: ./glob/**/to/**/file/**/* # - glob: ./glob/**/to/**/file/**/*

View File

@ -4,10 +4,37 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased - 0.0.1] - DATE ## [Unreleased - 0.17.3] - DATE
### Added ### Added
- go 1.17 to github action test matrix
- Support for CloudKMS RSA-PSS signers without using templates.
### Changed ### Changed
- Using go 1.17 for binaries
### Deprecated ### Deprecated
### Removed ### Removed
### Fixed ### Fixed
### Security ### Security
- Use cosign to sign and upload signatures for multi-arch Docker container.
- Add debian checksum
## [0.17.2] - 2021-08-30
### Added
- Additional way to distinguish Azure IID and Azure OIDC tokens.
### Security
- Sign over all goreleaser github artifacts using cosign
## [0.17.1] - 2021-08-26
## [0.17.0] - 2021-08-25
### Added
- Add support for Linked CAs using protocol buffers and gRPC
- `step-ca init` adds support for
- configuring a StepCAS RA
- configuring a Linked CA
- congifuring a `step-ca` using Helm
### Changed
- Update badger driver to use v2 by default
- Update TLS cipher suites to include 1.3
### Security
- Fix key version when SHA512WithRSA is used. There was a typo creating RSA keys with SHA256 digests instead of SHA512.

View File

@ -29,7 +29,7 @@ ci: testcgo build
bootstra%: bootstra%:
# Using a released version of golangci-lint to take into account custom replacements in their go.mod # Using a released version of golangci-lint to take into account custom replacements in their go.mod
$Q curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.39.0 $Q curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.42.0
.PHONY: bootstra% .PHONY: bootstra%
@ -68,7 +68,7 @@ PUSHTYPE := branch
endif endif
VERSION := $(shell echo $(VERSION) | sed 's/^v//') VERSION := $(shell echo $(VERSION) | sed 's/^v//')
DEB_VERSION := $(shell echo $(VERSION) | sed 's/-/~/g') DEB_VERSION := $(shell echo $(VERSION) | sed 's/-/./g')
ifdef V ifdef V
$(info TRAVIS_TAG is $(TRAVIS_TAG)) $(info TRAVIS_TAG is $(TRAVIS_TAG))

View File

@ -11,6 +11,7 @@ import (
"net" "net"
"reflect" "reflect"
"testing" "testing"
"time"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/smallstep/assert" "github.com/smallstep/assert"
@ -82,6 +83,10 @@ func testAuthority(t *testing.T, opts ...Option) *Authority {
} }
a, err := New(c, opts...) a, err := New(c, opts...)
assert.FatalError(t, err) assert.FatalError(t, err)
// Avoid errors when test tokens are created before the test authority. This
// happens in some tests where we re-create the same authority to test
// special cases without re-creating the token.
a.startTime = a.startTime.Add(-1 * time.Minute)
return a return a
} }

View File

@ -37,6 +37,7 @@ func (p provisionerSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
// provisioner. // provisioner.
type loadByTokenPayload struct { type loadByTokenPayload struct {
jose.Claims jose.Claims
Email string `json:"email"` // OIDC email
AuthorizedParty string `json:"azp"` // OIDC client id AuthorizedParty string `json:"azp"` // OIDC client id
TenantID string `json:"tid"` // Microsoft Azure tenant id TenantID string `json:"tid"` // Microsoft Azure tenant id
} }
@ -129,12 +130,20 @@ func (c *Collection) LoadByToken(token *jose.JSONWebToken, claims *jose.Claims)
return p, ok return p, ok
} }
} }
// Try with tid (Azure) // Try with tid (Azure, Azure OIDC)
if payload.TenantID != "" { if payload.TenantID != "" {
// Try to load an OIDC provisioner first.
if payload.Email != "" {
if p, ok := c.LoadByTokenID(payload.Audience[0]); ok {
return p, ok
}
}
// Try to load an Azure provisioner.
if p, ok := c.LoadByTokenID(payload.TenantID); ok { if p, ok := c.LoadByTokenID(payload.TenantID); ok {
return p, ok return p, ok
} }
} }
// Fallback to aud // Fallback to aud
return c.LoadByTokenID(payload.Audience[0]) return c.LoadByTokenID(payload.Audience[0])
} }

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"encoding/json" "encoding/json"
"math/big" "math/big"
"strings"
"time" "time"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -455,10 +456,10 @@ func containsAllMembers(group, subgroup []string) bool {
} }
visit := make(map[string]struct{}, lg) visit := make(map[string]struct{}, lg)
for i := 0; i < lg; i++ { for i := 0; i < lg; i++ {
visit[group[i]] = struct{}{} visit[strings.ToLower(group[i])] = struct{}{}
} }
for i := 0; i < lsg; i++ { for i := 0; i < lsg; i++ {
if _, ok := visit[subgroup[i]]; !ok { if _, ok := visit[strings.ToLower(subgroup[i])]; !ok {
return false return false
} }
} }

View File

@ -1,6 +1,7 @@
package apiv1 package apiv1
import ( import (
"crypto/x509"
"net/http" "net/http"
"strings" "strings"
) )
@ -26,6 +27,12 @@ type CertificateAuthorityCreator interface {
CreateCertificateAuthority(req *CreateCertificateAuthorityRequest) (*CreateCertificateAuthorityResponse, error) CreateCertificateAuthority(req *CreateCertificateAuthorityRequest) (*CreateCertificateAuthorityResponse, error)
} }
// SignatureAlgorithmGetter is an optional implementation in a crypto.Signer
// that returns the SignatureAlgorithm to use.
type SignatureAlgorithmGetter interface {
SignatureAlgorithm() x509.SignatureAlgorithm
}
// Type represents the CAS type used. // Type represents the CAS type used.
type Type string type Type string

View File

@ -68,7 +68,7 @@ func (c *SoftCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1
} }
req.Template.Issuer = c.CertificateChain[0].Subject req.Template.Issuer = c.CertificateChain[0].Subject
cert, err := x509util.CreateCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer) cert, err := createCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -93,7 +93,7 @@ func (c *SoftCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.R
req.Template.NotAfter = t.Add(req.Lifetime) req.Template.NotAfter = t.Add(req.Lifetime)
req.Template.Issuer = c.CertificateChain[0].Subject req.Template.Issuer = c.CertificateChain[0].Subject
cert, err := x509util.CreateCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer) cert, err := createCertificate(req.Template, c.CertificateChain[0], req.Template.PublicKey, c.Signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -150,12 +150,12 @@ func (c *SoftCAS) CreateCertificateAuthority(req *apiv1.CreateCertificateAuthori
var cert *x509.Certificate var cert *x509.Certificate
switch req.Type { switch req.Type {
case apiv1.RootCA: case apiv1.RootCA:
cert, err = x509util.CreateCertificate(req.Template, req.Template, signer.Public(), signer) cert, err = createCertificate(req.Template, req.Template, signer.Public(), signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
case apiv1.IntermediateCA: case apiv1.IntermediateCA:
cert, err = x509util.CreateCertificate(req.Template, req.Parent.Certificate, signer.Public(), req.Parent.Signer) cert, err = createCertificate(req.Template, req.Parent.Certificate, signer.Public(), req.Parent.Signer)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -210,3 +210,16 @@ func (c *SoftCAS) createSigner(req *kmsapi.CreateSignerRequest) (crypto.Signer,
} }
return c.KeyManager.CreateSigner(req) return c.KeyManager.CreateSigner(req)
} }
// createCertificate sets the SignatureAlgorithm of the template if necessary
// and calls x509util.CreateCertificate.
func createCertificate(template, parent *x509.Certificate, pub crypto.PublicKey, signer crypto.Signer) (*x509.Certificate, error) {
// Signers can specify the signature algorithm. This is especially important
// when x509.CreateCertificate attempts to validate a RSAPSS signature.
if template.SignatureAlgorithm == 0 {
if sa, ok := signer.(apiv1.SignatureAlgorithmGetter); ok {
template.SignatureAlgorithm = sa.SignatureAlgorithm()
}
}
return x509util.CreateCertificate(template, parent, pub, signer)
}

View File

@ -75,6 +75,15 @@ var (
testSignedIntermediateTemplate = mustSign(testIntermediateTemplate, testSignedRootTemplate, testNow, testNow.Add(24*time.Hour)) testSignedIntermediateTemplate = mustSign(testIntermediateTemplate, testSignedRootTemplate, testNow, testNow.Add(24*time.Hour))
) )
type signatureAlgorithmSigner struct {
crypto.Signer
algorithm x509.SignatureAlgorithm
}
func (s *signatureAlgorithmSigner) SignatureAlgorithm() x509.SignatureAlgorithm {
return s.algorithm
}
type mockKeyManager struct { type mockKeyManager struct {
signer crypto.Signer signer crypto.Signer
errGetPublicKey error errGetPublicKey error
@ -247,6 +256,13 @@ func TestSoftCAS_CreateCertificate(t *testing.T) {
tmplNoSerial := *testTemplate tmplNoSerial := *testTemplate
tmplNoSerial.SerialNumber = nil tmplNoSerial.SerialNumber = nil
saTemplate := *testSignedTemplate
saTemplate.SignatureAlgorithm = 0
saSigner := &signatureAlgorithmSigner{
Signer: testSigner,
algorithm: x509.PureEd25519,
}
type fields struct { type fields struct {
Issuer *x509.Certificate Issuer *x509.Certificate
Signer crypto.Signer Signer crypto.Signer
@ -267,6 +283,12 @@ func TestSoftCAS_CreateCertificate(t *testing.T) {
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok signature algorithm", fields{testIssuer, saSigner}, args{&apiv1.CreateCertificateRequest{
Template: &saTemplate, Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateResponse{
Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer},
}, false},
{"ok with notBefore", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{ {"ok with notBefore", fields{testIssuer, testSigner}, args{&apiv1.CreateCertificateRequest{
Template: &tmplNotBefore, Lifetime: 24 * time.Hour, Template: &tmplNotBefore, Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateResponse{ }}, &apiv1.CreateCertificateResponse{
@ -316,6 +338,11 @@ func TestSoftCAS_RenewCertificate(t *testing.T) {
tmplNoSerial := *testTemplate tmplNoSerial := *testTemplate
tmplNoSerial.SerialNumber = nil tmplNoSerial.SerialNumber = nil
saSigner := &signatureAlgorithmSigner{
Signer: testSigner,
algorithm: x509.PureEd25519,
}
type fields struct { type fields struct {
Issuer *x509.Certificate Issuer *x509.Certificate
Signer crypto.Signer Signer crypto.Signer
@ -336,6 +363,12 @@ func TestSoftCAS_RenewCertificate(t *testing.T) {
Certificate: testSignedTemplate, Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer}, CertificateChain: []*x509.Certificate{testIssuer},
}, false}, }, false},
{"ok signature algorithm", fields{testIssuer, saSigner}, args{&apiv1.RenewCertificateRequest{
Template: testTemplate, Lifetime: 24 * time.Hour,
}}, &apiv1.RenewCertificateResponse{
Certificate: testSignedTemplate,
CertificateChain: []*x509.Certificate{testIssuer},
}, false},
{"fail template", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true}, {"fail template", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Lifetime: 24 * time.Hour}}, nil, true},
{"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Template: testTemplate}}, nil, true}, {"fail lifetime", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{Template: testTemplate}}, nil, true},
{"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{ {"fail CreateCertificate", fields{testIssuer, testSigner}, args{&apiv1.RenewCertificateRequest{
@ -425,6 +458,11 @@ func Test_now(t *testing.T) {
func TestSoftCAS_CreateCertificateAuthority(t *testing.T) { func TestSoftCAS_CreateCertificateAuthority(t *testing.T) {
mockNow(t) mockNow(t)
saSigner := &signatureAlgorithmSigner{
Signer: testSigner,
algorithm: x509.PureEd25519,
}
type fields struct { type fields struct {
Issuer *x509.Certificate Issuer *x509.Certificate
Signer crypto.Signer Signer crypto.Signer
@ -467,6 +505,17 @@ func TestSoftCAS_CreateCertificateAuthority(t *testing.T) {
PrivateKey: testSigner, PrivateKey: testSigner,
Signer: testSigner, Signer: testSigner,
}, false}, }, false},
{"ok signature algorithm", fields{nil, nil, &mockKeyManager{signer: saSigner}}, args{&apiv1.CreateCertificateAuthorityRequest{
Type: apiv1.RootCA,
Template: testRootTemplate,
Lifetime: 24 * time.Hour,
}}, &apiv1.CreateCertificateAuthorityResponse{
Name: "Test Root CA",
Certificate: testSignedRootTemplate,
PublicKey: testSignedRootTemplate.PublicKey,
PrivateKey: saSigner,
Signer: saSigner,
}, false},
{"fail template", fields{nil, nil, &mockKeyManager{}}, args{&apiv1.CreateCertificateAuthorityRequest{ {"fail template", fields{nil, nil, &mockKeyManager{}}, args{&apiv1.CreateCertificateAuthorityRequest{
Type: apiv1.RootCA, Type: apiv1.RootCA,
Lifetime: 24 * time.Hour, Lifetime: 24 * time.Hour,

4
cosign.pub Normal file
View File

@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEs+6THbAiXx4bja5ARQFNZmPwZjlD
GRvt5H+9ZFDhrcFPR1E7eB2rt1B/DhobANdHGKjvEBZEf0v4X/7S+SHrIw==
-----END PUBLIC KEY-----

8
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-isatty v0.0.13 // indirect github.com/mattn/go-isatty v0.0.13 // indirect
github.com/micromdm/scep/v2 v2.0.0 github.com/micromdm/scep/v2 v2.1.0
github.com/newrelic/go-agent v2.15.0+incompatible github.com/newrelic/go-agent v2.15.0+incompatible
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/rs/xid v1.2.1 github.com/rs/xid v1.2.1
@ -25,7 +25,7 @@ require (
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
github.com/smallstep/nosql v0.3.8 github.com/smallstep/nosql v0.3.8
github.com/urfave/cli v1.22.4 github.com/urfave/cli v1.22.4
go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
go.step.sm/cli-utils v0.4.1 go.step.sm/cli-utils v0.4.1
go.step.sm/crypto v0.9.2 go.step.sm/crypto v0.9.2
go.step.sm/linkedca v0.5.0 go.step.sm/linkedca v0.5.0
@ -42,7 +42,3 @@ require (
// replace go.step.sm/crypto => ../crypto // replace go.step.sm/crypto => ../crypto
// replace go.step.sm/cli-utils => ../cli-utils // replace go.step.sm/cli-utils => ../cli-utils
// replace go.step.sm/linkedca => ../linkedca // replace go.step.sm/linkedca => ../linkedca
//replace go.step.sm/linkedca => ../linkedca
replace go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 => github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568

9
go.sum
View File

@ -358,8 +358,8 @@ github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1y
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/micromdm/scep/v2 v2.0.0 h1:cRzcY0S5QX+0+J+7YC4P2uZSnfMup8S8zJu/bLFgOkA= github.com/micromdm/scep/v2 v2.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU=
github.com/micromdm/scep/v2 v2.0.0/go.mod h1:ouaDs5tcjOjdHD/h8BGaQsWE87MUnQ/wMTMgfMMIpPc= github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f h1:eVB9ELsoq5ouItQBr5Tj334bhPJG/MX+m7rTchmzVUQ= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f h1:eVB9ELsoq5ouItQBr5Tj334bhPJG/MX+m7rTchmzVUQ=
github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
@ -392,8 +392,6 @@ github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HD
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568 h1:+MPqEswjYiS0S1FCTg8MIhMBMzxiVQ94rooFwvPPiWk=
github.com/omorsi/pkcs7 v0.0.0-20210217142924-a7b80a2a8568/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@ -510,6 +508,9 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.mozilla.org/pkcs7 v0.0.0-20210730143726-725912489c62/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 h1:CCriYyAfq1Br1aIYettdHZTy8mBTIPo7We18TuO/bak=
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352/go.mod h1:SNgMg+EgDFwmvSmLRTNKC5fegJjB7v23qTQ0XLGUNHk=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=

View File

@ -3,6 +3,7 @@ package cloudkms
import ( import (
"context" "context"
"crypto" "crypto"
"crypto/x509"
"log" "log"
"strings" "strings"
"time" "time"
@ -63,6 +64,19 @@ var signatureAlgorithmMapping = map[apiv1.SignatureAlgorithm]interface{}{
apiv1.ECDSAWithSHA384: kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384, apiv1.ECDSAWithSHA384: kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384,
} }
var cryptoKeyVersionMapping = map[kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm]x509.SignatureAlgorithm{
kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256: x509.ECDSAWithSHA256,
kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384: x509.ECDSAWithSHA384,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256: x509.SHA256WithRSA,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256: x509.SHA256WithRSA,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256: x509.SHA256WithRSA,
kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512: x509.SHA512WithRSA,
kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256: x509.SHA256WithRSAPSS,
kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256: x509.SHA256WithRSAPSS,
kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256: x509.SHA256WithRSAPSS,
kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512: x509.SHA512WithRSAPSS,
}
// KeyManagementClient defines the methods on KeyManagementClient that this // KeyManagementClient defines the methods on KeyManagementClient that this
// package will use. This interface will be used for unit testing. // package will use. This interface will be used for unit testing.
type KeyManagementClient interface { type KeyManagementClient interface {

View File

@ -2,6 +2,7 @@ package cloudkms
import ( import (
"crypto" "crypto"
"crypto/x509"
"io" "io"
"github.com/pkg/errors" "github.com/pkg/errors"
@ -13,6 +14,7 @@ import (
type Signer struct { type Signer struct {
client KeyManagementClient client KeyManagementClient
signingKey string signingKey string
algorithm x509.SignatureAlgorithm
publicKey crypto.PublicKey publicKey crypto.PublicKey
} }
@ -40,7 +42,7 @@ func (s *Signer) preloadKey(signingKey string) error {
if err != nil { if err != nil {
return errors.Wrap(err, "cloudKMS GetPublicKey failed") return errors.Wrap(err, "cloudKMS GetPublicKey failed")
} }
s.algorithm = cryptoKeyVersionMapping[response.Algorithm]
s.publicKey, err = pemutil.ParseKey([]byte(response.Pem)) s.publicKey, err = pemutil.ParseKey([]byte(response.Pem))
return err return err
} }
@ -84,3 +86,10 @@ func (s *Signer) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]
return response.Signature, nil return response.Signature, nil
} }
// SignatureAlgorithm returns the algorithm that must be specified in a
// certificate to sign. This is specially important to distinguish RSA and
// RSAPSS schemas.
func (s *Signer) SignatureAlgorithm() x509.SignatureAlgorithm {
return s.algorithm
}

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"crypto" "crypto"
"crypto/rand" "crypto/rand"
"crypto/x509"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -156,3 +157,79 @@ func Test_signer_Sign(t *testing.T) {
}) })
} }
} }
func TestSigner_SignatureAlgorithm(t *testing.T) {
pemBytes, err := ioutil.ReadFile("testdata/pub.pem")
if err != nil {
t.Fatal(err)
}
client := &MockClient{
getPublicKey: func(_ context.Context, req *kmspb.GetPublicKeyRequest, _ ...gax.CallOption) (*kmspb.PublicKey, error) {
var algorithm kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm
switch req.Name {
case "ECDSA-SHA256":
algorithm = kmspb.CryptoKeyVersion_EC_SIGN_P256_SHA256
case "ECDSA-SHA384":
algorithm = kmspb.CryptoKeyVersion_EC_SIGN_P384_SHA384
case "SHA256-RSA-2048":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_2048_SHA256
case "SHA256-RSA-3072":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_3072_SHA256
case "SHA256-RSA-4096":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA256
case "SHA512-RSA-4096":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PKCS1_4096_SHA512
case "SHA256-RSAPSS-2048":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PSS_2048_SHA256
case "SHA256-RSAPSS-3072":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PSS_3072_SHA256
case "SHA256-RSAPSS-4096":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA256
case "SHA512-RSAPSS-4096":
algorithm = kmspb.CryptoKeyVersion_RSA_SIGN_PSS_4096_SHA512
}
return &kmspb.PublicKey{
Pem: string(pemBytes),
Algorithm: algorithm,
}, nil
},
}
if err != nil {
t.Fatal(err)
}
type fields struct {
client KeyManagementClient
signingKey string
}
tests := []struct {
name string
fields fields
want x509.SignatureAlgorithm
}{
{"ECDSA-SHA256", fields{client, "ECDSA-SHA256"}, x509.ECDSAWithSHA256},
{"ECDSA-SHA384", fields{client, "ECDSA-SHA384"}, x509.ECDSAWithSHA384},
{"SHA256-RSA-2048", fields{client, "SHA256-RSA-2048"}, x509.SHA256WithRSA},
{"SHA256-RSA-3072", fields{client, "SHA256-RSA-3072"}, x509.SHA256WithRSA},
{"SHA256-RSA-4096", fields{client, "SHA256-RSA-4096"}, x509.SHA256WithRSA},
{"SHA512-RSA-4096", fields{client, "SHA512-RSA-4096"}, x509.SHA512WithRSA},
{"SHA256-RSAPSS-2048", fields{client, "SHA256-RSAPSS-2048"}, x509.SHA256WithRSAPSS},
{"SHA256-RSAPSS-3072", fields{client, "SHA256-RSAPSS-3072"}, x509.SHA256WithRSAPSS},
{"SHA256-RSAPSS-4096", fields{client, "SHA256-RSAPSS-4096"}, x509.SHA256WithRSAPSS},
{"SHA512-RSAPSS-4096", fields{client, "SHA512-RSAPSS-4096"}, x509.SHA512WithRSAPSS},
{"unknown", fields{client, "UNKNOWN"}, x509.UnknownSignatureAlgorithm},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
signer, err := NewSigner(tt.fields.client, tt.fields.signingKey)
if err != nil {
t.Errorf("NewSigner() error = %v", err)
}
if got := signer.SignatureAlgorithm(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Signer.SignatureAlgorithm() = %v, want %v", got, tt.want)
}
})
}
}

View File

@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build opensc
// +build opensc // +build opensc
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo && !softhsm2 && !yubihsm2 && !opensc
// +build cgo,!softhsm2,!yubihsm2,!opensc // +build cgo,!softhsm2,!yubihsm2,!opensc
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build !cgo
// +build !cgo // +build !cgo
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo && softhsm2
// +build cgo,softhsm2 // +build cgo,softhsm2
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo && yubihsm2
// +build cgo,yubihsm2 // +build cgo,yubihsm2
package pkcs11 package pkcs11

View File

@ -1,3 +1,4 @@
//go:build cgo
// +build cgo // +build cgo
package yubikey package yubikey

View File

@ -1,3 +1,4 @@
//go:build !cgo
// +build !cgo // +build !cgo
package yubikey package yubikey

View File

@ -54,6 +54,8 @@ define DOCKER_BUILDX
# $(1) -- Image Tag # $(1) -- Image Tag
# $(2) -- Push (empty is no push | --push will push to dockerhub) # $(2) -- Push (empty is no push | --push will push to dockerhub)
docker buildx build . --progress plain -t $(DOCKER_IMAGE_NAME):$(1) -f docker/Dockerfile.step-ca --platform="$(DOCKER_PLATFORMS)" $(2) docker buildx build . --progress plain -t $(DOCKER_IMAGE_NAME):$(1) -f docker/Dockerfile.step-ca --platform="$(DOCKER_PLATFORMS)" $(2)
echo -n "$(COSIGN_PWD)" | cosign sign -key /tmp/cosign.key -r $(DOCKER_IMAGE_NAME):$(1)
endef endef
# For non-master builds don't build the docker containers. # For non-master builds don't build the docker containers.