Skip to content
Draft
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
25 changes: 25 additions & 0 deletions kms/apiv1/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ type KeyManager interface {
Close() error
}

// KeyDeleter is an optional interface for KMS implementations that support
// deleting keys.
//
// # Experimental
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
// release.
type KeyDeleter interface {
DeleteKey(req *DeleteKeyRequest) error
}

// SearchableKeyManager is an optional interface for KMS implementations
// that support searching for keys based on certain attributes.
//
Expand Down Expand Up @@ -54,6 +65,17 @@ type CertificateChainManager interface {
StoreCertificateChain(req *StoreCertificateChainRequest) error
}

// CertificateDeleter is an optional interface for KMS implementations that
// support deleting certificates.
//
// # Experimental
//
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
// release.
type CertificateDeleter interface {
DeleteCertificate(req *DeleteCertificateRequest) error
}

// NameValidator is an interface that KeyManager can implement to validate a
// given name or URI.
type NameValidator interface {
Expand Down Expand Up @@ -151,6 +173,9 @@ const (
TPMKMS Type = "tpmkms"
// MacKMS is the KMS implementation using macOS Keychain and Secure Enclave.
MacKMS Type = "mackms"
// PlatformKMS is the KMS implementation that uses TPMKMS on Windows and
// Linux and MacKMS on macOS..
PlatformKMS Type = "kms"
)

// TypeOf returns the type of of the given uri.
Expand Down
76 changes: 76 additions & 0 deletions kms/platform/kms.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package platform

import (
"context"
"crypto"
"crypto/x509"

"go.step.sm/crypto/kms/apiv1"
)

const Scheme = "kms"

func init() {
apiv1.Register(apiv1.PlatformKMS, func(ctx context.Context, opts apiv1.Options) (apiv1.KeyManager, error) {
return New(ctx, opts)
})
}

type extendedKeyManager interface {
apiv1.KeyManager
apiv1.KeyDeleter
apiv1.CertificateManager
apiv1.CertificateChainManager
}

var _ apiv1.KeyManager = (*KMS)(nil)
var _ apiv1.CertificateManager = (*KMS)(nil)
var _ apiv1.CertificateChainManager = (*KMS)(nil)

type KMS struct {
backend extendedKeyManager
}

func New(ctx context.Context, opts apiv1.Options) (*KMS, error) {
return newKMS(ctx, opts)
}

func (k *KMS) GetPublicKey(req *apiv1.GetPublicKeyRequest) (crypto.PublicKey, error) {
return k.backend.GetPublicKey(req)
}

func (k *KMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyResponse, error) {
return k.backend.CreateKey(req)
}

func (k *KMS) CreateSigner(req *apiv1.CreateSignerRequest) (crypto.Signer, error) {
return k.backend.CreateSigner(req)
}

func (k *KMS) Close() error {
return k.backend.Close()
}

func (k *KMS) DeleteKey(req *apiv1.DeleteKeyRequest) error {
return k.backend.DeleteKey(req)
}

func (k *KMS) LoadCertificate(req *apiv1.LoadCertificateRequest) (*x509.Certificate, error) {
return k.backend.LoadCertificate(req)
}

func (k *KMS) StoreCertificate(req *apiv1.StoreCertificateRequest) error {
return k.backend.StoreCertificate(req)
}

func (k *KMS) LoadCertificateChain(req *apiv1.LoadCertificateChainRequest) ([]*x509.Certificate, error) {
return k.backend.LoadCertificateChain(req)
}

func (k *KMS) StoreCertificateChain(req *apiv1.StoreCertificateChainRequest) error {
if km, ok := k.backend.(apiv1.CertificateChainManager); ok {
return km.StoreCertificateChain(req)
}

return apiv1.NotImplementedError{}
}
33 changes: 33 additions & 0 deletions kms/platform/kms_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package platform

import (
"context"

"go.step.sm/crypto/kms/apiv1"
"go.step.sm/crypto/kms/mackms"
)

var _ apiv1.SearchableKeyManager = (*KMS)(nil)

func newKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
if opts.Type == apiv1.TPMKMS {
return newTPMKMS(ctx, opts)
}

km, err := mackms.New(ctx, opts)
if err != nil {
return nil, err
}

return &KMS{
backend: km,
}, nil
}

func (k *KMS) SearchKeys(req *apiv1.SearchKeysRequest) (*apiv1.SearchKeysResponse, error) {
if km, ok := k.backend.(apiv1.SearchableKeyManager); ok {
return km.SearchKeys(req)
}

return nil, apiv1.NotImplementedError{}
}
13 changes: 13 additions & 0 deletions kms/platform/kms_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:build !darwin && !windows

package platform

import (
"context"

"go.step.sm/crypto/kms/apiv1"
)

func newKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
return newTPMKMS(ctx, opts)
}
41 changes: 41 additions & 0 deletions kms/platform/kms_tpm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package platform

import (
"context"

"go.step.sm/crypto/kms/apiv1"
"go.step.sm/crypto/kms/tpmkms"
"go.step.sm/crypto/tpm"
)

var _ apiv1.Attester = (*KMS)(nil)

func newTPMKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
km, err := tpmkms.New(ctx, opts)
if err != nil {
return nil, err
}

return &KMS{
backend: km,
}, nil
}

func NewWithTPM(ctx context.Context, t *tpm.TPM, opts ...tpmkms.Option) (*KMS, error) {
km, err := tpmkms.NewWithTPM(ctx, t, opts...)
if err != nil {
return nil, err
}

return &KMS{
backend: km,
}, nil
}

func (k *KMS) CreateAttestation(req *apiv1.CreateAttestationRequest) (*apiv1.CreateAttestationResponse, error) {
if km, ok := k.backend.(apiv1.Attester); ok {
return km.CreateAttestation(req)
}

return nil, apiv1.NotImplementedError{}
}
38 changes: 38 additions & 0 deletions kms/platform/kms_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build windows

package platform

import (
"context"

"go.step.sm/crypto/kms/apiv1"
"go.step.sm/crypto/kms/capi"
"go.step.sm/crypto/kms/uri"
)

func newKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
if opts.Type == apiv1.CAPIKMS {
km, err := capi.New(ctx, opts)
if err != nil {
return nil, err
}

return &KMS{
backend: km,
}, nil
}

if opts.URI != "" {
u, err := uri.Parse(opts.URI)
if err != nil {
return nil, err
}

if !u.Has("enable-cng") {
u.Values.Set("enable-cng", "true")
}
opts.URI = u.String()
}

return newTPMKMS(ctx, opts)
}