Skip to content

Commit

Permalink
validate cipher length before decrypting (#14098) (#14156)
Browse files Browse the repository at this point in the history
* validate cipher length before decrypting

* also protect decrypt from short cipher
  • Loading branch information
swayne275 authored Feb 18, 2022
1 parent 80244bc commit 606e98d
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 8 deletions.
10 changes: 10 additions & 0 deletions vault/barrier_aes_gcm.go
Original file line number Diff line number Diff line change
Expand Up @@ -1014,6 +1014,9 @@ func termLabel(term uint32) []metrics.Label {

// decrypt is used to decrypt a value using the keyring
func (b *AESGCMBarrier) decrypt(path string, gcm cipher.AEAD, cipher []byte) ([]byte, error) {
if len(cipher) < 5+gcm.NonceSize() {
return nil, fmt.Errorf("invalid cipher length")
}
// Capture the parts
nonce := cipher[5 : 5+gcm.NonceSize()]
raw := cipher[5+gcm.NonceSize():]
Expand Down Expand Up @@ -1065,7 +1068,14 @@ func (b *AESGCMBarrier) Decrypt(_ context.Context, key string, ciphertext []byte
return nil, ErrBarrierSealed
}

if len(ciphertext) == 0 {
return nil, fmt.Errorf("empty ciphertext")
}

// Verify the term
if len(ciphertext) < 4 {
return nil, fmt.Errorf("invalid ciphertext term")
}
term := binary.BigEndian.Uint32(ciphertext[:4])

// Get the GCM by term
Expand Down
52 changes: 44 additions & 8 deletions vault/barrier_aes_gcm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -517,25 +517,26 @@ func TestEncrypt_BarrierEncryptor(t *testing.T) {
if err != nil {
t.Fatalf("err: %v", err)
}
if err != nil {
t.Fatalf("err: %v", err)
}
b, err := NewAESGCMBarrier(inm)
if err != nil {
t.Fatalf("err: %v", err)
}

// Initialize and unseal
key, _ := b.GenerateKey(rand.Reader)
b.Initialize(context.Background(), key, nil, rand.Reader)
b.Unseal(context.Background(), key)
key, err := b.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("err generating key: %v", err)
}
ctx := context.Background()
b.Initialize(ctx, key, nil, rand.Reader)
b.Unseal(ctx, key)

cipher, err := b.Encrypt(context.Background(), "foo", []byte("quick brown fox"))
cipher, err := b.Encrypt(ctx, "foo", []byte("quick brown fox"))
if err != nil {
t.Fatalf("err: %v", err)
}

plain, err := b.Decrypt(context.Background(), "foo", cipher)
plain, err := b.Decrypt(ctx, "foo", cipher)
if err != nil {
t.Fatalf("err: %v", err)
}
Expand All @@ -545,6 +546,41 @@ func TestEncrypt_BarrierEncryptor(t *testing.T) {
}
}

// Ensure Decrypt returns an error (rather than panic) when given a ciphertext
// that is nil or too short
func TestDecrypt_InvalidCipherLength(t *testing.T) {
inm, err := inmem.NewInmem(nil, logger)
if err != nil {
t.Fatalf("err: %v", err)
}
b, err := NewAESGCMBarrier(inm)
if err != nil {
t.Fatalf("err: %v", err)
}

key, err := b.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("err generating key: %v", err)
}
ctx := context.Background()
b.Initialize(ctx, key, nil, rand.Reader)
b.Unseal(ctx, key)

var nilCipher []byte
if _, err = b.Decrypt(ctx, "", nilCipher); err == nil {
t.Fatal("expected error when given nil cipher")
}
emptyCipher := []byte{}
if _, err = b.Decrypt(ctx, "", emptyCipher); err == nil {
t.Fatal("expected error when given empty cipher")
}

badTermLengthCipher := make([]byte, 3, 3)
if _, err = b.Decrypt(ctx, "", badTermLengthCipher); err == nil {
t.Fatal("expected error when given cipher with too short term")
}
}

func TestAESGCMBarrier_ReloadKeyring(t *testing.T) {
inm, err := inmem.NewInmem(nil, logger)
if err != nil {
Expand Down

0 comments on commit 606e98d

Please sign in to comment.