github.com/cornelk/go-cloud@v0.17.1/secrets/drivertest/drivertest.go (about)

     1  // Copyright 2018 The Go Cloud Development Kit Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package drivertest provides a conformance test for implementations of
    16  // the secrets driver.
    17  package drivertest // import "github.com/cornelk/go-cloud/secrets/drivertest"
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"errors"
    23  	"testing"
    24  
    25  	"github.com/cornelk/go-cloud/secrets"
    26  	"github.com/cornelk/go-cloud/secrets/driver"
    27  	"github.com/google/go-cmp/cmp"
    28  )
    29  
    30  // Harness descibes the functionality test harnesses must provide to run
    31  // conformance tests.
    32  type Harness interface {
    33  	// MakeDriver returns a pair of driver.Keeper, each backed by a different key.
    34  	MakeDriver(ctx context.Context) (driver.Keeper, driver.Keeper, error)
    35  
    36  	// Close is called when the test is complete.
    37  	Close()
    38  }
    39  
    40  // HarnessMaker describes functions that construct a harness for running tests.
    41  // It is called exactly once per test.
    42  type HarnessMaker func(ctx context.Context, t *testing.T) (Harness, error)
    43  
    44  // AsTest represents a test of As functionality.
    45  // The conformance test:
    46  // 1. Tries to decrypt malformed message, and calls ErrorCheck with the error.
    47  type AsTest interface {
    48  	// Name returns a descriptive name for the test.
    49  	Name() string
    50  	// ErrorCheck is called to allow verification of Keeper.ErrorAs.
    51  	ErrorCheck(k *secrets.Keeper, err error) error
    52  }
    53  
    54  type verifyAsFailsOnNil struct{}
    55  
    56  func (v verifyAsFailsOnNil) Name() string {
    57  	return "verify As returns false when passed nil"
    58  }
    59  
    60  func (v verifyAsFailsOnNil) ErrorCheck(k *secrets.Keeper, err error) (ret error) {
    61  	defer func() {
    62  		if recover() == nil {
    63  			ret = errors.New("want ErrorAs to panic when passed nil")
    64  		}
    65  	}()
    66  	k.ErrorAs(err, nil)
    67  	return nil
    68  }
    69  
    70  // RunConformanceTests runs conformance tests for driver implementations of secret management.
    71  func RunConformanceTests(t *testing.T, newHarness HarnessMaker, asTests []AsTest) {
    72  	t.Run("TestEncryptDecrypt", func(t *testing.T) {
    73  		testEncryptDecrypt(t, newHarness)
    74  	})
    75  	t.Run("TestMultipleEncryptionsNotEqual", func(t *testing.T) {
    76  		testMultipleEncryptionsNotEqual(t, newHarness)
    77  	})
    78  	t.Run("TestMultipleKeys", func(t *testing.T) {
    79  		testMultipleKeys(t, newHarness)
    80  	})
    81  	t.Run("TestDecryptMalformedError", func(t *testing.T) {
    82  		testDecryptMalformedError(t, newHarness)
    83  	})
    84  	asTests = append(asTests, verifyAsFailsOnNil{})
    85  	t.Run("TestAs", func(t *testing.T) {
    86  		for _, tc := range asTests {
    87  			if tc.Name() == "" {
    88  				t.Fatal("AsTest.Name is required")
    89  			}
    90  			t.Run(tc.Name(), func(t *testing.T) {
    91  				testAs(t, newHarness, tc)
    92  			})
    93  		}
    94  	})
    95  }
    96  
    97  // testEncryptDecrypt tests the functionality of encryption and decryption
    98  func testEncryptDecrypt(t *testing.T, newHarness HarnessMaker) {
    99  	ctx := context.Background()
   100  	harness, err := newHarness(ctx, t)
   101  	if err != nil {
   102  		t.Fatal(err)
   103  	}
   104  	defer harness.Close()
   105  
   106  	drv, _, err := harness.MakeDriver(ctx)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	keeper := secrets.NewKeeper(drv)
   111  	defer keeper.Close()
   112  
   113  	msg := []byte("I'm a secret message!")
   114  	encryptedMsg, err := keeper.Encrypt(ctx, msg)
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  	if cmp.Equal(msg, encryptedMsg) {
   119  		t.Errorf("Got encrypted message %v, want it to differ from original message %v", string(msg), string(encryptedMsg))
   120  	}
   121  	decryptedMsg, err := keeper.Decrypt(ctx, encryptedMsg)
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	if !cmp.Equal(msg, decryptedMsg) {
   126  		t.Errorf("Got decrypted message %v, want it to match original message %v", string(msg), string(decryptedMsg))
   127  	}
   128  
   129  }
   130  
   131  // testMultipleEncryptionsNotEqual tests that encrypting a plaintext multiple
   132  // times with the same key works, and that the encrypted bytes are different.
   133  func testMultipleEncryptionsNotEqual(t *testing.T, newHarness HarnessMaker) {
   134  	ctx := context.Background()
   135  	harness, err := newHarness(ctx, t)
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  	defer harness.Close()
   140  
   141  	drv, _, err := harness.MakeDriver(ctx)
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	keeper := secrets.NewKeeper(drv)
   146  	defer keeper.Close()
   147  
   148  	msg := []byte("I'm a secret message!")
   149  	encryptedMsg1, err := keeper.Encrypt(ctx, msg)
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	encryptedMsg2, err := keeper.Encrypt(ctx, msg)
   154  	if err != nil {
   155  		t.Fatal(err)
   156  	}
   157  	if cmp.Equal(encryptedMsg1, encryptedMsg2) {
   158  		t.Errorf("Got same encrypted messages from multiple encryptions %v, want them to be different", string(encryptedMsg1))
   159  	}
   160  	decryptedMsg, err := keeper.Decrypt(ctx, encryptedMsg1)
   161  	if err != nil {
   162  		t.Fatal(err)
   163  	}
   164  	if !bytes.Equal(decryptedMsg, msg) {
   165  		t.Errorf("got decrypted %q want %q", string(decryptedMsg), string(msg))
   166  	}
   167  	decryptedMsg, err = keeper.Decrypt(ctx, encryptedMsg2)
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	}
   171  	if !bytes.Equal(decryptedMsg, msg) {
   172  		t.Errorf("got decrypted %q want %q", string(decryptedMsg), string(msg))
   173  	}
   174  }
   175  
   176  // testMultipleKeys tests that encrypting the same text with different
   177  // keys works, and that the encrypted bytes are different.
   178  func testMultipleKeys(t *testing.T, newHarness HarnessMaker) {
   179  	ctx := context.Background()
   180  	harness, err := newHarness(ctx, t)
   181  	if err != nil {
   182  		t.Fatal(err)
   183  	}
   184  	defer harness.Close()
   185  
   186  	drv1, drv2, err := harness.MakeDriver(ctx)
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	keeper1 := secrets.NewKeeper(drv1)
   191  	defer keeper1.Close()
   192  	keeper2 := secrets.NewKeeper(drv2)
   193  	defer keeper2.Close()
   194  
   195  	msg := []byte("I'm a secret message!")
   196  	encryptedMsg1, err := keeper1.Encrypt(ctx, msg)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  	encryptedMsg2, err := keeper2.Encrypt(ctx, msg)
   201  	if err != nil {
   202  		t.Fatal(err)
   203  	}
   204  	if cmp.Equal(encryptedMsg1, encryptedMsg2) {
   205  		t.Errorf("Got same encrypted messages from multiple encryptions %v, want them to be different", string(encryptedMsg1))
   206  	}
   207  
   208  	// We cannot assert that decrypting encryptedMsg1 with keeper2 fails,
   209  	// or that decrypting encryptedMsg2 with keeper1 fails, as Decrypt is allowed
   210  	// to decrypt using a different key than the one given to Keeper.
   211  
   212  	decryptedMsg, err := keeper1.Decrypt(ctx, encryptedMsg1)
   213  	if err != nil {
   214  		t.Fatal(err)
   215  	}
   216  	if !bytes.Equal(decryptedMsg, msg) {
   217  		t.Errorf("got decrypted %q want %q", string(decryptedMsg), string(msg))
   218  	}
   219  
   220  	decryptedMsg, err = keeper2.Decrypt(ctx, encryptedMsg2)
   221  	if err != nil {
   222  		t.Fatal(err)
   223  	}
   224  	if !bytes.Equal(decryptedMsg, msg) {
   225  		t.Errorf("got decrypted %q want %q", string(decryptedMsg), string(msg))
   226  	}
   227  }
   228  
   229  // testDecryptMalformedError tests decryption returns an error when the
   230  // ciphertext is malformed.
   231  func testDecryptMalformedError(t *testing.T, newHarness HarnessMaker) {
   232  	ctx := context.Background()
   233  	harness, err := newHarness(ctx, t)
   234  	if err != nil {
   235  		t.Fatal(err)
   236  	}
   237  	defer harness.Close()
   238  
   239  	drv, _, err := harness.MakeDriver(ctx)
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	keeper := secrets.NewKeeper(drv)
   244  	defer keeper.Close()
   245  
   246  	msg := []byte("I'm a secret message!")
   247  	encryptedMsg, err := keeper.Encrypt(ctx, msg)
   248  	if err != nil {
   249  		t.Fatal(err)
   250  	}
   251  	copyEncryptedMsg := func() []byte {
   252  		return append([]byte{}, encryptedMsg...)
   253  	}
   254  
   255  	l := len(encryptedMsg)
   256  	for _, tc := range []struct {
   257  		name      string
   258  		malformed []byte
   259  	}{
   260  		{
   261  			name:      "wrong first byte",
   262  			malformed: append([]byte{encryptedMsg[0] + 1}, encryptedMsg[1:]...),
   263  		},
   264  		{
   265  			name:      "missing second byte",
   266  			malformed: append(copyEncryptedMsg()[:1], encryptedMsg[2:]...),
   267  		},
   268  		{
   269  			name:      "wrong last byte",
   270  			malformed: append(copyEncryptedMsg()[:l-2], encryptedMsg[l-1]-1),
   271  		},
   272  		{
   273  			name:      "one more byte",
   274  			malformed: append(encryptedMsg, 4),
   275  		},
   276  	} {
   277  		t.Run(tc.name, func(t *testing.T) {
   278  			if _, err := keeper.Decrypt(ctx, []byte(tc.malformed)); err == nil {
   279  				t.Error("Got nil, want decrypt error")
   280  			}
   281  		})
   282  	}
   283  }
   284  
   285  func testAs(t *testing.T, newHarness HarnessMaker, tc AsTest) {
   286  	ctx := context.Background()
   287  	harness, err := newHarness(ctx, t)
   288  	if err != nil {
   289  		t.Fatal(err)
   290  	}
   291  	defer harness.Close()
   292  
   293  	drv, _, err := harness.MakeDriver(ctx)
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  	keeper := secrets.NewKeeper(drv)
   298  	defer keeper.Close()
   299  
   300  	_, gotErr := keeper.Decrypt(ctx, []byte("malformed cipher message"))
   301  	if gotErr == nil {
   302  		t.Error("Got nil, want decrypt error")
   303  	}
   304  	if err := tc.ErrorCheck(keeper, gotErr); err != nil {
   305  		t.Error(err)
   306  	}
   307  }