1
0

Vault-11713: Add the ability for transit to use managed keys (#18844)

* add the ability for transit to use managed keys

* add fields for rotate

* reorganize managed keys for better error messaging

* add aad for managed keys

* change encrypting key interface

* fix import error

* fix fmt errors

* move managed key rotation to a separate function

* fix fmt issue

* fix import error

* fix go.mod issue

* fix go.mod

* remove extra rotate param

* fix locking issue in rotation

* fix errors in policy tests

* move managed key params to fit existing policy functions

* fix sign and verify

* fix policy tests

* fix test error
This commit is contained in:
Rachel Culpepper 2023-01-27 14:39:58 -05:00 committed by GitHub
parent 7a0c055c2a
commit d228e62b51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 341 additions and 43 deletions

View File

@ -30,6 +30,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6 // indirect
github.com/hashicorp/go-plugin v1.4.5 // indirect
github.com/hashicorp/go-secure-stdlib/mlock v0.1.1 // indirect
github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect
@ -46,6 +47,7 @@ require (
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/oklog/run v1.0.0 // indirect
github.com/pierrec/lz4 v2.5.2+incompatible // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/ryanuber/go-glob v1.0.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/crypto v0.5.0 // indirect
@ -53,5 +55,5 @@ require (
golang.org/x/text v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/grpc v1.41.0 // indirect
google.golang.org/protobuf v1.26.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
)

View File

@ -73,8 +73,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
@ -91,6 +91,8 @@ github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJFeZnpfm2KLowc=
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6 h1:szfBtjzqyJ/sjOAOGM1XIGnzkLFSAbCqgrNZXBqojMY=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6/go.mod h1:sDQAfwJGv25uGPZA04x87ERglCG6avnRcBT9wYoMII8=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
@ -129,8 +131,8 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@ -186,6 +188,8 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
@ -284,8 +288,9 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@ -73,6 +73,8 @@ func Backend(ctx context.Context, conf *logical.BackendConfig) (*backend, error)
PeriodicFunc: b.periodicFunc,
}
b.backendUUID = conf.BackendUUID
// determine cacheSize to use. Defaults to 0 which means unlimited
cacheSize := 0
useCache := !conf.System.CachingDisabled()
@ -106,6 +108,7 @@ type backend struct {
cacheSizeChanged bool
checkAutoRotateAfter time.Time
autoRotateOnce sync.Once
backendUUID string
}
func GetCacheSizeFromStorage(ctx context.Context, s logical.Storage) (int, error) {

View File

@ -0,0 +1,12 @@
package transit
import (
"context"
"errors"
)
var errEntOnly = errors.New("managed keys are supported within enterprise edition only")
func GetManagedKeyUUID(ctx context.Context, b *backend, keyName string, keyId string) (uuid string, err error) {
return "", errEntOnly
}

View File

@ -3,6 +3,7 @@ package transit
import (
"context"
"encoding/base64"
"errors"
"fmt"
"github.com/hashicorp/vault/sdk/framework"
@ -191,7 +192,23 @@ func (b *backend) pathDecryptWrite(ctx context.Context, req *logical.Request, d
factory = AssocDataFactory{item.AssociatedData}
}
plaintext, err := p.DecryptWithFactory(item.DecodedContext, item.DecodedNonce, item.Ciphertext, factory)
var managedKeyFactory ManagedKeyFactory
if p.Type == keysutil.KeyType_MANAGED_KEY {
managedKeySystemView, ok := b.System().(logical.ManagedKeySystemView)
if !ok {
batchResponseItems[i].Error = errors.New("unsupported system view").Error()
}
managedKeyFactory = ManagedKeyFactory{
managedKeyParams: keysutil.ManagedKeyParameters{
ManagedKeySystemView: managedKeySystemView,
BackendUUID: b.backendUUID,
Context: ctx,
},
}
}
plaintext, err := p.DecryptWithFactory(item.DecodedContext, item.DecodedNonce, item.Ciphertext, factory, managedKeyFactory)
if err != nil {
switch err.(type) {
case errutil.InternalError:

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"net/http"
"reflect"
@ -74,6 +75,14 @@ func (a AssocDataFactory) GetAssociatedData() ([]byte, error) {
return base64.StdEncoding.DecodeString(a.Encoded)
}
type ManagedKeyFactory struct {
managedKeyParams keysutil.ManagedKeyParameters
}
func (m ManagedKeyFactory) GetManagedKeyParameters() keysutil.ManagedKeyParameters {
return m.managedKeyParams
}
func (b *backend) pathEncrypt() *framework.Path {
return &framework.Path{
Pattern: "encrypt/" + framework.GenericNameRegex("name"),
@ -420,6 +429,8 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
polReq.KeyType = keysutil.KeyType_ChaCha20_Poly1305
case "ecdsa-p256", "ecdsa-p384", "ecdsa-p521":
return logical.ErrorResponse(fmt.Sprintf("key type %v not supported for this operation", keyType)), logical.ErrInvalidRequest
case "managed_key":
polReq.KeyType = keysutil.KeyType_MANAGED_KEY
default:
return logical.ErrorResponse(fmt.Sprintf("unknown key type %v", keyType)), logical.ErrInvalidRequest
}
@ -465,7 +476,23 @@ func (b *backend) pathEncryptWrite(ctx context.Context, req *logical.Request, d
factory = AssocDataFactory{item.AssociatedData}
}
ciphertext, err := p.EncryptWithFactory(item.KeyVersion, item.DecodedContext, item.DecodedNonce, item.Plaintext, factory)
var managedKeyFactory ManagedKeyFactory
if p.Type == keysutil.KeyType_MANAGED_KEY {
managedKeySystemView, ok := b.System().(logical.ManagedKeySystemView)
if !ok {
batchResponseItems[i].Error = errors.New("unsupported system view").Error()
}
managedKeyFactory = ManagedKeyFactory{
managedKeyParams: keysutil.ManagedKeyParameters{
ManagedKeySystemView: managedKeySystemView,
BackendUUID: b.backendUUID,
Context: ctx,
},
}
}
ciphertext, err := p.EncryptWithFactory(item.KeyVersion, item.DecodedContext, item.DecodedNonce, item.Plaintext, factory, managedKeyFactory)
if err != nil {
switch err.(type) {
case errutil.InternalError:

View File

@ -4,6 +4,7 @@ import (
"context"
"crypto/hmac"
"encoding/base64"
"errors"
"fmt"
"strconv"
"strings"
@ -143,7 +144,7 @@ func (b *backend) pathHMACWrite(ctx context.Context, req *logical.Request, d *fr
p.Unlock()
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
if key == nil {
if key == nil && p.Type != keysutil.KeyType_MANAGED_KEY {
p.Unlock()
return nil, fmt.Errorf("HMAC key value could not be computed")
}
@ -199,9 +200,23 @@ func (b *backend) pathHMACWrite(ctx context.Context, req *logical.Request, d *fr
continue
}
hf := hmac.New(hashAlg, key)
hf.Write(input)
retBytes := hf.Sum(nil)
var retBytes []byte
if p.Type == keysutil.KeyType_MANAGED_KEY {
managedKeySystemView, ok := b.System().(logical.ManagedKeySystemView)
if !ok {
response[i].err = errors.New("unsupported system view")
}
retBytes, err = p.HMACWithManagedKey(ctx, ver, managedKeySystemView, b.backendUUID, algorithm, input)
if err != nil {
response[i].err = err
}
} else {
hf := hmac.New(hashAlg, key)
hf.Write(input)
retBytes = hf.Sum(nil)
}
retStr := base64.StdEncoding.EncodeToString(retBytes)
retStr = fmt.Sprintf("vault:v%s:%s", strconv.Itoa(ver), retStr)

View File

@ -108,6 +108,14 @@ key.`,
Default: 0,
Description: fmt.Sprintf("The key size in bytes for the algorithm. Only applies to HMAC and must be no fewer than %d bytes and no more than %d", keysutil.HmacMinKeySize, keysutil.HmacMaxKeySize),
},
"managed_key_name": {
Type: framework.TypeString,
Description: "The name of the managed key to use for this transit key",
},
"managed_key_id": {
Type: framework.TypeString,
Description: "The UUID of the managed key to use for this transit key",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
@ -139,6 +147,8 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
exportable := d.Get("exportable").(bool)
allowPlaintextBackup := d.Get("allow_plaintext_backup").(bool)
autoRotatePeriod := time.Second * time.Duration(d.Get("auto_rotate_period").(int))
managedKeyName := d.Get("managed_key_name").(string)
managedKeyId := d.Get("managed_key_id").(string)
if autoRotatePeriod != 0 && autoRotatePeriod < time.Hour {
return logical.ErrorResponse("auto rotate period must be 0 to disable or at least an hour"), nil
@ -182,6 +192,8 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
polReq.KeyType = keysutil.KeyType_RSA4096
case "hmac":
polReq.KeyType = keysutil.KeyType_HMAC
case "managed_key":
polReq.KeyType = keysutil.KeyType_MANAGED_KEY
default:
return logical.ErrorResponse(fmt.Sprintf("unknown key type %v", keyType)), logical.ErrInvalidRequest
}
@ -195,6 +207,15 @@ func (b *backend) pathPolicyWrite(ctx context.Context, req *logical.Request, d *
polReq.KeySize = keySize
}
if polReq.KeyType == keysutil.KeyType_MANAGED_KEY {
keyId, err := GetManagedKeyUUID(ctx, b, managedKeyName, managedKeyId)
if err != nil {
return nil, err
}
polReq.ManagedKeyUUID = keyId
}
p, upserted, err := b.GetPolicy(ctx, polReq, b.GetRandomReader())
if err != nil {
return nil, err

View File

@ -16,6 +16,14 @@ func (b *backend) pathRotate() *framework.Path {
Type: framework.TypeString,
Description: "Name of the key",
},
"managed_key_name": {
Type: framework.TypeString,
Description: "The name of the managed key to use for the new version of this transit key",
},
"managed_key_id": {
Type: framework.TypeString,
Description: "The UUID of the managed key to use for the new version of this transit key",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
@ -29,6 +37,8 @@ func (b *backend) pathRotate() *framework.Path {
func (b *backend) pathRotateWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
name := d.Get("name").(string)
managedKeyName := d.Get("managed_key_name").(string)
managedKeyId := d.Get("managed_key_id").(string)
// Get the policy
p, _, err := b.GetPolicy(ctx, keysutil.PolicyRequest{
@ -45,8 +55,18 @@ func (b *backend) pathRotateWrite(ctx context.Context, req *logical.Request, d *
p.Lock(true)
}
// Rotate the policy
err = p.Rotate(ctx, req.Storage, b.GetRandomReader())
if p.Type == keysutil.KeyType_MANAGED_KEY {
var keyId string
keyId, err = GetManagedKeyUUID(ctx, b, managedKeyName, managedKeyId)
if err != nil {
p.Unlock()
return nil, err
}
err = p.RotateManagedKey(ctx, req.Storage, keyId)
} else {
// Rotate the policy
err = p.Rotate(ctx, req.Storage, b.GetRandomReader())
}
p.Unlock()
return nil, err

View File

@ -4,6 +4,7 @@ import (
"context"
"crypto/rsa"
"encoding/base64"
"errors"
"fmt"
"strconv"
"strings"
@ -416,11 +417,26 @@ func (b *backend) pathSignWrite(ctx context.Context, req *logical.Request, d *fr
}
}
var managedKeyParameters keysutil.ManagedKeyParameters
if p.Type == keysutil.KeyType_MANAGED_KEY {
managedKeySystemView, ok := b.System().(logical.ManagedKeySystemView)
if !ok {
return nil, errors.New("unsupported system view")
}
managedKeyParameters = keysutil.ManagedKeyParameters{
ManagedKeySystemView: managedKeySystemView,
BackendUUID: b.backendUUID,
Context: ctx,
}
}
sig, err := p.SignWithOptions(ver, context, input, &keysutil.SigningOptions{
HashAlgorithm: hashAlgorithm,
Marshaling: marshaling,
SaltLength: saltLength,
SigAlgorithm: sigAlgorithm,
HashAlgorithm: hashAlgorithm,
Marshaling: marshaling,
SaltLength: saltLength,
SigAlgorithm: sigAlgorithm,
ManagedKeyParams: managedKeyParameters,
})
if err != nil {
if batchInputRaw != nil {
@ -638,13 +654,29 @@ func (b *backend) pathVerifyWrite(ctx context.Context, req *logical.Request, d *
continue
}
}
var managedKeyParameters keysutil.ManagedKeyParameters
if p.Type == keysutil.KeyType_MANAGED_KEY {
managedKeySystemView, ok := b.System().(logical.ManagedKeySystemView)
if !ok {
return nil, errors.New("unsupported system view")
}
valid, err := p.VerifySignatureWithOptions(context, input, sig, &keysutil.SigningOptions{
HashAlgorithm: hashAlgorithm,
Marshaling: marshaling,
SaltLength: saltLength,
SigAlgorithm: sigAlgorithm,
})
managedKeyParameters = keysutil.ManagedKeyParameters{
ManagedKeySystemView: managedKeySystemView,
BackendUUID: b.backendUUID,
Context: ctx,
}
}
signingOptions := &keysutil.SigningOptions{
HashAlgorithm: hashAlgorithm,
Marshaling: marshaling,
SaltLength: saltLength,
SigAlgorithm: sigAlgorithm,
ManagedKeyParams: managedKeyParameters,
}
valid, err := p.VerifySignatureWithOptions(context, input, sig, signingOptions)
if err != nil {
switch err.(type) {
case errutil.UserError:

4
go.mod
View File

@ -69,7 +69,7 @@ require (
github.com/hashicorp/go-discover v0.0.0-20210818145131-c573d69da192
github.com/hashicorp/go-gcp-common v0.8.0
github.com/hashicorp/go-hclog v1.4.0
github.com/hashicorp/go-kms-wrapping/v2 v2.0.5
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6
github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2 v2.0.4
github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2 v2.0.1
github.com/hashicorp/go-kms-wrapping/wrappers/awskms/v2 v2.0.1
@ -398,7 +398,7 @@ require (
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/renier/xmlrpc v0.0.0-20170708154548-ce4a1a486c03 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect
github.com/snowflakedb/gosnowflake v1.6.3 // indirect

11
go.sum
View File

@ -995,8 +995,8 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8=
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.5 h1:rOFDv+3k05mnW0oaDLffhVUwg03Csn0mvfO98Wdd2bE=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.5/go.mod h1:sDQAfwJGv25uGPZA04x87ERglCG6avnRcBT9wYoMII8=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6 h1:szfBtjzqyJ/sjOAOGM1XIGnzkLFSAbCqgrNZXBqojMY=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6/go.mod h1:sDQAfwJGv25uGPZA04x87ERglCG6avnRcBT9wYoMII8=
github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2 v2.0.4 h1:ws2CPDuXMKwaBb2z/duBCdnB9pSxlN2nuDZWXcVj6RU=
github.com/hashicorp/go-kms-wrapping/wrappers/aead/v2 v2.0.4/go.mod h1:dDxt3GXi5QONVHYrJi2+EjsJLCUs59FktZQA8ZMnm+U=
github.com/hashicorp/go-kms-wrapping/wrappers/alicloudkms/v2 v2.0.1 h1:ydUCtmr8f9F+mHZ1iCsvzqFTXqNVpewX3s9zcYipMKI=
@ -1477,6 +1477,7 @@ github.com/mongodb-forks/digest v1.0.3/go.mod h1:eHRfgovT+dvSFfltrOa27hy1oR/rcwy
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@ -1672,8 +1673,8 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.4.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
@ -1955,6 +1956,7 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220313003712-b769efc7c000/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
@ -2599,7 +2601,6 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=

View File

@ -39,7 +39,7 @@ require (
golang.org/x/crypto v0.5.0
golang.org/x/text v0.6.0
google.golang.org/grpc v1.41.0
google.golang.org/protobuf v1.26.0
google.golang.org/protobuf v1.27.1
)
require (
@ -48,6 +48,7 @@ require (
github.com/frankban/quicktest v1.10.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.3.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.0 // indirect
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6 // indirect
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-colorable v0.1.6 // indirect

View File

@ -96,6 +96,8 @@ github.com/hashicorp/go-immutable-radix v1.3.1 h1:DKHmCUm2hRBK510BaiZlwvpD40f8bJ
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0 h1:pSjQfW3vPtrOTcasTUKgCTQT7OGPPTTMVRrOfU6FJD8=
github.com/hashicorp/go-kms-wrapping/entropy/v2 v2.0.0/go.mod h1:xvb32K2keAc+R8DSFG2IwDcydK9DBQE+fGA5fsw6hSk=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6 h1:szfBtjzqyJ/sjOAOGM1XIGnzkLFSAbCqgrNZXBqojMY=
github.com/hashicorp/go-kms-wrapping/v2 v2.0.6/go.mod h1:sDQAfwJGv25uGPZA04x87ERglCG6avnRcBT9wYoMII8=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
@ -304,6 +306,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=

View File

@ -59,6 +59,9 @@ type PolicyRequest struct {
// AllowImportedKeyRotation indicates whether an imported key may be rotated by Vault
AllowImportedKeyRotation bool
// The UUID of the managed key, if using one
ManagedKeyUUID string
}
type LockManager struct {
@ -382,6 +385,12 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest, rand io
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)
}
case KeyType_MANAGED_KEY:
if req.Derived || req.Convergent {
cleanup()
return nil, false, fmt.Errorf("key derivation and convergent encryption not supported for keys of type %v", req.KeyType)
}
default:
cleanup()
return nil, false, fmt.Errorf("unsupported key type %v", req.KeyType)
@ -412,7 +421,11 @@ func (lm *LockManager) GetPolicy(ctx context.Context, req PolicyRequest, rand io
}
// Performs the actual persist and does setup
err = p.Rotate(ctx, req.Storage, rand)
if p.Type == KeyType_MANAGED_KEY {
err = p.RotateManagedKey(ctx, req.Storage, req.ManagedKeyUUID)
} else {
err = p.Rotate(ctx, req.Storage, rand)
}
if err != nil {
cleanup()
return nil, false, err

View File

@ -0,0 +1,40 @@
package keysutil
import (
"context"
"errors"
"github.com/hashicorp/vault/sdk/logical"
)
type ManagedKeyParameters struct {
ManagedKeySystemView logical.ManagedKeySystemView
BackendUUID string
Context context.Context
}
var errEntOnly = errors.New("managed keys are supported within enterprise edition only")
func (p *Policy) decryptWithManagedKey(params ManagedKeyParameters, keyEntry KeyEntry, ciphertext []byte, nonce []byte, aad []byte) (plaintext []byte, err error) {
return nil, errEntOnly
}
func (p *Policy) encryptWithManagedKey(params ManagedKeyParameters, keyEntry KeyEntry, plaintext []byte, nonce []byte, aad []byte) (ciphertext []byte, err error) {
return nil, errEntOnly
}
func (p *Policy) signWithManagedKey(options *SigningOptions, keyEntry KeyEntry, input []byte) (sig []byte, err error) {
return nil, errEntOnly
}
func (p *Policy) verifyWithManagedKey(options *SigningOptions, keyEntry KeyEntry, input, sig []byte) (verified bool, err error) {
return false, errEntOnly
}
func (p *Policy) HMACWithManagedKey(ctx context.Context, ver int, managedKeySystemView logical.ManagedKeySystemView, backendUUID string, algorithm string, data []byte) (hmacBytes []byte, err error) {
return nil, errEntOnly
}
func (p *Policy) RotateManagedKey(ctx context.Context, storage logical.Storage, managedKeyUUID string) error {
return errEntOnly
}

View File

@ -83,6 +83,10 @@ type AssociatedDataFactory interface {
GetAssociatedData() ([]byte, error)
}
type ManagedKeyFactory interface {
GetManagedKeyParameters() ManagedKeyParameters
}
type RestoreInfo struct {
Time time.Time `json:"time"`
Version int `json:"version"`
@ -94,10 +98,11 @@ type BackupInfo struct {
}
type SigningOptions struct {
HashAlgorithm HashType
Marshaling MarshalingType
SaltLength int
SigAlgorithm string
HashAlgorithm HashType
Marshaling MarshalingType
SaltLength int
SigAlgorithm string
ManagedKeyParams ManagedKeyParameters
}
type SigningResult struct {
@ -113,7 +118,7 @@ type KeyType int
func (kt KeyType) EncryptionSupported() bool {
switch kt {
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096, KeyType_MANAGED_KEY:
return true
}
return false
@ -121,7 +126,7 @@ func (kt KeyType) EncryptionSupported() bool {
func (kt KeyType) DecryptionSupported() bool {
switch kt {
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096, KeyType_MANAGED_KEY:
return true
}
return false
@ -129,7 +134,7 @@ func (kt KeyType) DecryptionSupported() bool {
func (kt KeyType) SigningSupported() bool {
switch kt {
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521, KeyType_ED25519, KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096:
case KeyType_ECDSA_P256, KeyType_ECDSA_P384, KeyType_ECDSA_P521, KeyType_ED25519, KeyType_RSA2048, KeyType_RSA3072, KeyType_RSA4096, KeyType_MANAGED_KEY:
return true
}
return false
@ -153,7 +158,7 @@ func (kt KeyType) DerivationSupported() bool {
func (kt KeyType) AssociatedDataSupported() bool {
switch kt {
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305:
case KeyType_AES128_GCM96, KeyType_AES256_GCM96, KeyType_ChaCha20_Poly1305, KeyType_MANAGED_KEY:
return true
}
return false
@ -183,6 +188,8 @@ func (kt KeyType) String() string {
return "rsa-4096"
case KeyType_HMAC:
return "hmac"
case KeyType_MANAGED_KEY:
return "managed_key"
}
return "[unknown]"
@ -220,6 +227,8 @@ type KeyEntry struct {
// This is deprecated (but still filled) in favor of the value above which
// is more precise
DeprecatedCreationTime int64 `json:"creation_time"`
ManagedKeyUUID string `json:"managed_key_id,omitempty"`
}
// deprecatedKeyEntryMap is used to allow JSON marshal/unmarshal
@ -419,8 +428,6 @@ type Policy struct {
// AllowImportedKeyRotation indicates whether an imported key may be rotated by Vault
AllowImportedKeyRotation bool
ManagedKeyName string `json:"managed_key_name,omitempty"`
}
func (p *Policy) Lock(exclusive bool) {
@ -943,6 +950,7 @@ func (p *Policy) DecryptWithFactory(context, nonce []byte, value string, factori
if err != nil {
return "", errutil.InternalError{Err: fmt.Sprintf("unable to get associated_data/additional_data from factory[%d]: %v", index, err)}
}
case ManagedKeyFactory:
default:
return "", errutil.InternalError{Err: fmt.Sprintf("unknown type of factory[%d]: %T", index, rawFactory)}
}
@ -962,6 +970,33 @@ func (p *Policy) DecryptWithFactory(context, nonce []byte, value string, factori
if err != nil {
return "", errutil.InternalError{Err: fmt.Sprintf("failed to RSA decrypt the ciphertext: %v", err)}
}
case KeyType_MANAGED_KEY:
keyEntry, err := p.safeGetKeyEntry(ver)
if err != nil {
return "", err
}
var aad []byte
var managedKeyFactory ManagedKeyFactory
for _, f := range factories {
switch factory := f.(type) {
case AssociatedDataFactory:
aad, err = factory.GetAssociatedData()
if err != nil {
return "", err
}
case ManagedKeyFactory:
managedKeyFactory = factory
}
}
if managedKeyFactory == nil {
return "", errors.New("key type is managed_key, but managed key parameters were not provided")
}
plain, err = p.decryptWithManagedKey(managedKeyFactory.GetManagedKeyParameters(), keyEntry, decoded, nonce, aad)
if err != nil {
return "", err
}
default:
return "", errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)}
@ -1160,6 +1195,17 @@ func (p *Policy) SignWithOptions(ver int, context, input []byte, options *Signin
return nil, errutil.InternalError{Err: fmt.Sprintf("unsupported rsa signature algorithm %s", sigAlgorithm)}
}
case KeyType_MANAGED_KEY:
keyEntry, err := p.safeGetKeyEntry(ver)
if err != nil {
return nil, err
}
sig, err = p.signWithManagedKey(options, keyEntry, input)
if err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported key type %v", p.Type)
}
@ -1333,6 +1379,14 @@ func (p *Policy) VerifySignatureWithOptions(context, input []byte, sig string, o
return err == nil, nil
case KeyType_MANAGED_KEY:
keyEntry, err := p.safeGetKeyEntry(ver)
if err != nil {
return false, err
}
return p.verifyWithManagedKey(options, keyEntry, input, sigBytes)
default:
return false, errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)}
}
@ -1941,6 +1995,7 @@ func (p *Policy) EncryptWithFactory(ver int, context []byte, nonce []byte, value
if err != nil {
return "", errutil.InternalError{Err: fmt.Sprintf("unable to get associated_data/additional_data from factory[%d]: %v", index, err)}
}
case ManagedKeyFactory:
default:
return "", errutil.InternalError{Err: fmt.Sprintf("unknown type of factory[%d]: %T", index, rawFactory)}
}
@ -1960,6 +2015,34 @@ func (p *Policy) EncryptWithFactory(ver int, context []byte, nonce []byte, value
if err != nil {
return "", errutil.InternalError{Err: fmt.Sprintf("failed to RSA encrypt the plaintext: %v", err)}
}
case KeyType_MANAGED_KEY:
keyEntry, err := p.safeGetKeyEntry(ver)
if err != nil {
return "", err
}
var aad []byte
var managedKeyFactory ManagedKeyFactory
for _, f := range factories {
switch factory := f.(type) {
case AssociatedDataFactory:
aad, err = factory.GetAssociatedData()
if err != nil {
return "", nil
}
case ManagedKeyFactory:
managedKeyFactory = factory
}
}
if managedKeyFactory == nil {
return "", errors.New("key type is managed_key, but managed key parameters were not provided")
}
ciphertext, err = p.encryptWithManagedKey(managedKeyFactory.GetManagedKeyParameters(), keyEntry, plaintext, nonce, aad)
if err != nil {
return "", err
}
default:
return "", errutil.InternalError{Err: fmt.Sprintf("unsupported key type %v", p.Type)}

View File

@ -3,8 +3,9 @@ package logical
import (
"context"
"crypto"
"crypto/cipher"
"io"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
)
type KeyUsage int
@ -102,7 +103,8 @@ type ManagedSigningKey interface {
type ManagedEncryptingKey interface {
ManagedKey
GetAEAD(iv []byte) (cipher.AEAD, error)
Encrypt(ctx context.Context, plaintext []byte, options ...wrapping.Option) ([]byte, error)
Decrypt(ctx context.Context, ciphertext []byte, options ...wrapping.Option) ([]byte, error)
}
type ManagedMACKey interface {