Wrap storage calls with encoding checks (#5819)

* Add encoding backend

* More work on encoding checks

* Update error message

* Update physical/encoding.go

* Disable key checks if configured
This commit is contained in:
Brian Kassouf 2018-11-19 13:13:16 -08:00 committed by GitHub
parent c16f7485e7
commit 33776b89c2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 115 additions and 1 deletions

View File

@ -552,6 +552,7 @@ func (c *ServerCommand) Run(args []string) int {
DisableIndexing: config.DisableIndexing,
AllLoggers: allLoggers,
BuiltinRegistry: builtinplugins.Registry,
DisableKeyEncodingChecks: config.DisablePrintableCheck,
}
if c.flagDev {
coreConfig.DevToken = c.flagDevRootTokenID

View File

@ -639,7 +639,10 @@ func TestHandler_nonPrintableChars(t *testing.T) {
}
func testNonPrintable(t *testing.T, disable bool) {
core, _, token := vault.TestCoreUnsealed(t)
core, _, token := vault.TestCoreUnsealedWithConfig(t, &vault.CoreConfig{
Seal: vault.NewTestSeal(t, nil),
DisableKeyEncodingChecks: disable,
})
ln, addr := TestListener(t)
props := &vault.HandlerProperties{
Core: core,

104
physical/encoding.go Normal file
View File

@ -0,0 +1,104 @@
package physical
import (
"context"
"errors"
"strings"
"unicode"
"unicode/utf8"
)
var ErrNonUTF8 = errors.New("key contains invalid UTF-8 characters")
var ErrNonPrintable = errors.New("key contains non-printable characters")
// StorageEncoding is used to add errors into underlying physical requests
type StorageEncoding struct {
Backend
}
// TransactionalStorageEncoding is the transactional version of the error
// injector
type TransactionalStorageEncoding struct {
*StorageEncoding
Transactional
}
// Verify StorageEncoding satisfies the correct interfaces
var _ Backend = (*StorageEncoding)(nil)
var _ Transactional = (*TransactionalStorageEncoding)(nil)
// NewStorageEncoding returns a wrapped physical backend and verifies the key
// encoding
func NewStorageEncoding(b Backend) Backend {
enc := &StorageEncoding{
Backend: b,
}
if bTxn, ok := b.(Transactional); ok {
return TransactionalStorageEncoding{
StorageEncoding: enc,
Transactional: bTxn,
}
}
return enc
}
func (e *StorageEncoding) containsNonPrintableChars(key string) bool {
idx := strings.IndexFunc(key, func(c rune) bool {
return !unicode.IsPrint(c)
})
return idx != -1
}
func (e *StorageEncoding) Put(ctx context.Context, entry *Entry) error {
if !utf8.ValidString(entry.Key) {
return ErrNonUTF8
}
if e.containsNonPrintableChars(entry.Key) {
return ErrNonPrintable
}
return e.Backend.Put(ctx, entry)
}
func (e *StorageEncoding) Delete(ctx context.Context, key string) error {
if !utf8.ValidString(key) {
return ErrNonUTF8
}
if e.containsNonPrintableChars(key) {
return ErrNonPrintable
}
return e.Backend.Delete(ctx, key)
}
func (e *TransactionalStorageEncoding) Transaction(ctx context.Context, txns []*TxnEntry) error {
for _, txn := range txns {
if !utf8.ValidString(txn.Entry.Key) {
return ErrNonUTF8
}
if e.containsNonPrintableChars(txn.Entry.Key) {
return ErrNonPrintable
}
}
return e.Transactional.Transaction(ctx, txns)
}
func (e *StorageEncoding) Purge(ctx context.Context) {
if purgeable, ok := e.Backend.(ToggleablePurgemonster); ok {
purgeable.Purge(ctx)
}
}
func (e *StorageEncoding) SetEnabled(enabled bool) {
if purgeable, ok := e.Backend.(ToggleablePurgemonster); ok {
purgeable.SetEnabled(enabled)
}
}

View File

@ -466,6 +466,7 @@ type CoreConfig struct {
DisablePerformanceStandby bool
DisableIndexing bool
DisableKeyEncodingChecks bool
AllLoggers []log.Logger
}

View File

@ -31,6 +31,10 @@ func coreInit(c *Core, conf *CoreConfig) error {
}
c.physicalCache = c.physical.(physical.ToggleablePurgemonster)
// Wrap in encoding checks
if !conf.DisableKeyEncodingChecks {
c.physical = physical.NewStorageEncoding(c.physical)
}
return nil
}

View File

@ -148,6 +148,7 @@ func TestCoreWithSealAndUI(t testing.T, opts *CoreConfig) *Core {
conf.EnableRaw = opts.EnableRaw
conf.Seal = opts.Seal
conf.LicensingConfig = opts.LicensingConfig
conf.DisableKeyEncodingChecks = opts.DisableKeyEncodingChecks
c, err := NewCore(conf)
if err != nil {