Skip to content

Commit 28c3d96

Browse files
committed
Platform KMS (WIP)
1 parent 7650294 commit 28c3d96

File tree

6 files changed

+226
-0
lines changed

6 files changed

+226
-0
lines changed

kms/apiv1/options.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,17 @@ type KeyManager interface {
1818
Close() error
1919
}
2020

21+
// KeyDeleter is an optional interface for KMS implementations that support
22+
// deleting keys.
23+
//
24+
// # Experimental
25+
//
26+
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
27+
// release.
28+
type KeyDeleter interface {
29+
DeleteKey(req *DeleteKeyRequest) error
30+
}
31+
2132
// SearchableKeyManager is an optional interface for KMS implementations
2233
// that support searching for keys based on certain attributes.
2334
//
@@ -54,6 +65,17 @@ type CertificateChainManager interface {
5465
StoreCertificateChain(req *StoreCertificateChainRequest) error
5566
}
5667

68+
// CertificateDeleter is an optional interface for KMS implementations that
69+
// support deleting certificates.
70+
//
71+
// # Experimental
72+
//
73+
// Notice: This API is EXPERIMENTAL and may be changed or removed in a later
74+
// release.
75+
type CertificateDeleter interface {
76+
DeleteCertificate(req *DeleteCertificateRequest) error
77+
}
78+
5779
// NameValidator is an interface that KeyManager can implement to validate a
5880
// given name or URI.
5981
type NameValidator interface {
@@ -151,6 +173,9 @@ const (
151173
TPMKMS Type = "tpmkms"
152174
// MacKMS is the KMS implementation using macOS Keychain and Secure Enclave.
153175
MacKMS Type = "mackms"
176+
// PlatformKMS is the KMS implementation that uses TPMKMS on Windows and
177+
// Linux and MacKMS on macOS..
178+
PlatformKMS Type = "kms"
154179
)
155180

156181
// TypeOf returns the type of of the given uri.

kms/platform/kms.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package platform
2+
3+
import (
4+
"context"
5+
"crypto"
6+
"crypto/x509"
7+
8+
"go.step.sm/crypto/kms/apiv1"
9+
)
10+
11+
const Scheme = "kms"
12+
13+
func init() {
14+
apiv1.Register(apiv1.PlatformKMS, func(ctx context.Context, opts apiv1.Options) (apiv1.KeyManager, error) {
15+
return New(ctx, opts)
16+
})
17+
}
18+
19+
type extendedKeyManager interface {
20+
apiv1.KeyManager
21+
apiv1.KeyDeleter
22+
apiv1.CertificateManager
23+
apiv1.CertificateChainManager
24+
}
25+
26+
var _ apiv1.KeyManager = (*KMS)(nil)
27+
var _ apiv1.CertificateManager = (*KMS)(nil)
28+
var _ apiv1.CertificateChainManager = (*KMS)(nil)
29+
30+
type KMS struct {
31+
backend extendedKeyManager
32+
}
33+
34+
func New(ctx context.Context, opts apiv1.Options) (*KMS, error) {
35+
return newKMS(ctx, opts)
36+
}
37+
38+
func (k *KMS) GetPublicKey(req *apiv1.GetPublicKeyRequest) (crypto.PublicKey, error) {
39+
return k.backend.GetPublicKey(req)
40+
}
41+
42+
func (k *KMS) CreateKey(req *apiv1.CreateKeyRequest) (*apiv1.CreateKeyResponse, error) {
43+
return k.backend.CreateKey(req)
44+
}
45+
46+
func (k *KMS) CreateSigner(req *apiv1.CreateSignerRequest) (crypto.Signer, error) {
47+
return k.backend.CreateSigner(req)
48+
}
49+
50+
func (k *KMS) Close() error {
51+
return k.backend.Close()
52+
}
53+
54+
func (k *KMS) DeleteKey(req *apiv1.DeleteKeyRequest) error {
55+
return k.backend.DeleteKey(req)
56+
}
57+
58+
func (k *KMS) LoadCertificate(req *apiv1.LoadCertificateRequest) (*x509.Certificate, error) {
59+
return k.backend.LoadCertificate(req)
60+
}
61+
62+
func (k *KMS) StoreCertificate(req *apiv1.StoreCertificateRequest) error {
63+
return k.backend.StoreCertificate(req)
64+
}
65+
66+
func (k *KMS) LoadCertificateChain(req *apiv1.LoadCertificateChainRequest) ([]*x509.Certificate, error) {
67+
return k.backend.LoadCertificateChain(req)
68+
}
69+
70+
func (k *KMS) StoreCertificateChain(req *apiv1.StoreCertificateChainRequest) error {
71+
if km, ok := k.backend.(apiv1.CertificateChainManager); ok {
72+
return km.StoreCertificateChain(req)
73+
}
74+
75+
return apiv1.NotImplementedError{}
76+
}

kms/platform/kms_darwin.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package platform
2+
3+
import (
4+
"context"
5+
6+
"go.step.sm/crypto/kms/apiv1"
7+
"go.step.sm/crypto/kms/mackms"
8+
)
9+
10+
var _ apiv1.SearchableKeyManager = (*KMS)(nil)
11+
12+
func newKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
13+
if opts.Type == apiv1.TPMKMS {
14+
return newTPMKMS(ctx, opts)
15+
}
16+
17+
km, err := mackms.New(ctx, opts)
18+
if err != nil {
19+
return nil, err
20+
}
21+
22+
return &KMS{
23+
backend: km,
24+
}, nil
25+
}
26+
27+
func (k *KMS) SearchKeys(req *apiv1.SearchKeysRequest) (*apiv1.SearchKeysResponse, error) {
28+
if km, ok := k.backend.(apiv1.SearchableKeyManager); ok {
29+
return km.SearchKeys(req)
30+
}
31+
32+
return nil, apiv1.NotImplementedError{}
33+
}

kms/platform/kms_other.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:build !darwin && !windows
2+
3+
package platform
4+
5+
import (
6+
"context"
7+
8+
"go.step.sm/crypto/kms/apiv1"
9+
)
10+
11+
func newKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
12+
return newTPMKMS(ctx, opts)
13+
}

kms/platform/kms_tpm.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package platform
2+
3+
import (
4+
"context"
5+
6+
"go.step.sm/crypto/kms/apiv1"
7+
"go.step.sm/crypto/kms/tpmkms"
8+
"go.step.sm/crypto/tpm"
9+
)
10+
11+
var _ apiv1.Attester = (*KMS)(nil)
12+
13+
func newTPMKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
14+
km, err := tpmkms.New(ctx, opts)
15+
if err != nil {
16+
return nil, err
17+
}
18+
19+
return &KMS{
20+
backend: km,
21+
}, nil
22+
}
23+
24+
func NewWithTPM(ctx context.Context, t *tpm.TPM, opts ...tpmkms.Option) (*KMS, error) {
25+
km, err := tpmkms.NewWithTPM(ctx, t, opts...)
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
return &KMS{
31+
backend: km,
32+
}, nil
33+
}
34+
35+
func (k *KMS) CreateAttestation(req *apiv1.CreateAttestationRequest) (*apiv1.CreateAttestationResponse, error) {
36+
if km, ok := k.backend.(apiv1.Attester); ok {
37+
return km.CreateAttestation(req)
38+
}
39+
40+
return nil, apiv1.NotImplementedError{}
41+
}

kms/platform/kms_windows.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//go:build windows
2+
3+
package platform
4+
5+
import (
6+
"context"
7+
8+
"go.step.sm/crypto/kms/apiv1"
9+
"go.step.sm/crypto/kms/capi"
10+
"go.step.sm/crypto/kms/uri"
11+
)
12+
13+
func newKMS(ctx context.Context, opts apiv1.Options) (*KMS, error) {
14+
if opts.Type == apiv1.CAPIKMS {
15+
km, err := capi.New(ctx, opts)
16+
if err != nil {
17+
return nil, err
18+
}
19+
20+
return &KMS{
21+
backend: km,
22+
}, nil
23+
}
24+
25+
if opts.URI != "" {
26+
u, err := uri.Parse(opts.URI)
27+
if err != nil {
28+
return nil, err
29+
}
30+
31+
if !u.Has("enable-cng") {
32+
u.Values.Set("enable-cng", "true")
33+
}
34+
opts.URI = u.String()
35+
}
36+
37+
return newTPMKMS(ctx, opts)
38+
}

0 commit comments

Comments
 (0)