1package s3crypto
2
3import (
4	"encoding/base64"
5	"encoding/hex"
6	"fmt"
7	"net/http"
8	"net/http/httptest"
9	"testing"
10
11	"github.com/aws/aws-sdk-go/aws"
12	"github.com/aws/aws-sdk-go/awstesting/unit"
13	"github.com/aws/aws-sdk-go/service/kms"
14)
15
16func TestWrapFactory(t *testing.T) {
17	o := DecryptionClientOptions{
18		CryptoRegistry: initCryptoRegistryFrom(map[string]WrapEntry{
19			KMSWrap: (kmsKeyHandler{
20				kms: kms.New(unit.Session),
21			}).decryptHandler,
22		}, map[string]CEKEntry{
23			AESGCMNoPadding: newAESGCMContentCipher,
24		}, map[string]Padder{}),
25	}
26	env := Envelope{
27		WrapAlg: KMSWrap,
28		MatDesc: `{"kms_cmk_id":""}`,
29	}
30	wrap, err := wrapFromEnvelope(o, env)
31	w, ok := wrap.(*kmsKeyHandler)
32
33	if err != nil {
34		t.Errorf("expected no error, but received %v", err)
35	}
36	if wrap == nil {
37		t.Error("expected non-nil value")
38	}
39	if !ok {
40		t.Errorf("expected kmsKeyHandler, but received %v", *w)
41	}
42}
43func TestWrapFactoryErrorNoWrap(t *testing.T) {
44	o := DecryptionClientOptions{
45		CryptoRegistry: initCryptoRegistryFrom(map[string]WrapEntry{
46			KMSWrap: (kmsKeyHandler{
47				kms: kms.New(unit.Session),
48			}).decryptHandler,
49		}, map[string]CEKEntry{
50			AESGCMNoPadding: newAESGCMContentCipher,
51		}, map[string]Padder{}),
52	}
53	env := Envelope{
54		WrapAlg: "none",
55		MatDesc: `{"kms_cmk_id":""}`,
56	}
57	wrap, err := wrapFromEnvelope(o, env)
58
59	if err == nil {
60		t.Error("expected error, but received none")
61	}
62	if wrap != nil {
63		t.Errorf("expected nil wrap value, received %v", wrap)
64	}
65}
66
67func TestWrapFactoryCustomEntry(t *testing.T) {
68	o := DecryptionClientOptions{
69		CryptoRegistry: initCryptoRegistryFrom(map[string]WrapEntry{
70			"custom": (kmsKeyHandler{
71				kms: kms.New(unit.Session),
72			}).decryptHandler,
73		}, map[string]CEKEntry{
74			AESGCMNoPadding: newAESGCMContentCipher,
75		}, map[string]Padder{}),
76	}
77	env := Envelope{
78		WrapAlg: "custom",
79		MatDesc: `{"kms_cmk_id":""}`,
80	}
81	wrap, err := wrapFromEnvelope(o, env)
82
83	if err != nil {
84		t.Errorf("expected no error, but received %v", err)
85	}
86	if wrap == nil {
87		t.Errorf("expected nil wrap value, received %v", wrap)
88	}
89}
90
91func TestCEKFactory(t *testing.T) {
92	key, _ := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
93	keyB64 := base64.URLEncoding.EncodeToString(key)
94	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
95		fmt.Fprintln(w, fmt.Sprintf("%s%s%s", `{"KeyId":"test-key-id","Plaintext":"`, keyB64, `"}`))
96	}))
97	defer ts.Close()
98
99	sess := unit.Session.Copy(&aws.Config{
100		MaxRetries:       aws.Int(0),
101		Endpoint:         aws.String(ts.URL),
102		DisableSSL:       aws.Bool(true),
103		S3ForcePathStyle: aws.Bool(true),
104		Region:           aws.String("us-west-2"),
105	})
106
107	o := DecryptionClientOptions{
108		CryptoRegistry: initCryptoRegistryFrom(map[string]WrapEntry{
109			KMSWrap: (kmsKeyHandler{
110				kms: kms.New(sess),
111			}).decryptHandler,
112		}, map[string]CEKEntry{
113			AESGCMNoPadding: newAESGCMContentCipher,
114		}, map[string]Padder{
115			NoPadder.Name(): NoPadder,
116		}),
117	}
118	iv, err := hex.DecodeString("0d18e06c7c725ac9e362e1ce")
119	if err != nil {
120		t.Errorf("expected no error, but received %v", err)
121	}
122	ivB64 := base64.URLEncoding.EncodeToString(iv)
123
124	cipherKey, err := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
125	if err != nil {
126		t.Errorf("expected no error, but received %v", err)
127	}
128	cipherKeyB64 := base64.URLEncoding.EncodeToString(cipherKey)
129
130	env := Envelope{
131		WrapAlg:   KMSWrap,
132		CEKAlg:    AESGCMNoPadding,
133		CipherKey: cipherKeyB64,
134		IV:        ivB64,
135		MatDesc:   `{"kms_cmk_id":""}`,
136	}
137	wrap, err := wrapFromEnvelope(o, env)
138	cek, err := cekFromEnvelope(o, aws.BackgroundContext(), env, wrap)
139
140	if err != nil {
141		t.Errorf("expected no error, but received %v", err)
142	}
143	if cek == nil {
144		t.Errorf("expected non-nil cek")
145	}
146}
147
148func TestCEKFactoryNoCEK(t *testing.T) {
149	key, _ := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
150	keyB64 := base64.URLEncoding.EncodeToString(key)
151	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
152		fmt.Fprintln(w, fmt.Sprintf("%s%s%s", `{"KeyId":"test-key-id","Plaintext":"`, keyB64, `"}`))
153	}))
154	defer ts.Close()
155
156	sess := unit.Session.Copy(&aws.Config{
157		MaxRetries:       aws.Int(0),
158		Endpoint:         aws.String(ts.URL),
159		DisableSSL:       aws.Bool(true),
160		S3ForcePathStyle: aws.Bool(true),
161		Region:           aws.String("us-west-2"),
162	})
163
164	o := DecryptionClientOptions{
165		CryptoRegistry: initCryptoRegistryFrom(
166			map[string]WrapEntry{
167				KMSWrap: (kmsKeyHandler{
168					kms: kms.New(sess),
169				}).decryptHandler,
170			},
171			map[string]CEKEntry{
172				AESGCMNoPadding: newAESGCMContentCipher,
173			},
174			map[string]Padder{
175				NoPadder.Name(): NoPadder,
176			}),
177	}
178	iv, err := hex.DecodeString("0d18e06c7c725ac9e362e1ce")
179	if err != nil {
180		t.Errorf("expected no error, but received %v", err)
181	}
182	ivB64 := base64.URLEncoding.EncodeToString(iv)
183
184	cipherKey, err := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
185	if err != nil {
186		t.Errorf("expected no error, but received %v", err)
187	}
188	cipherKeyB64 := base64.URLEncoding.EncodeToString(cipherKey)
189
190	env := Envelope{
191		WrapAlg:   KMSWrap,
192		CEKAlg:    "none",
193		CipherKey: cipherKeyB64,
194		IV:        ivB64,
195		MatDesc:   `{"kms_cmk_id":""}`,
196	}
197	wrap, err := wrapFromEnvelope(o, env)
198	cek, err := cekFromEnvelope(o, aws.BackgroundContext(), env, wrap)
199
200	if err == nil {
201		t.Error("expected error, but received none")
202	}
203	if cek != nil {
204		t.Errorf("expected nil cek value, received %v", wrap)
205	}
206}
207
208func TestCEKFactoryCustomEntry(t *testing.T) {
209	key, _ := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
210	keyB64 := base64.URLEncoding.EncodeToString(key)
211	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
212		fmt.Fprintln(w, fmt.Sprintf("%s%s%s", `{"KeyId":"test-key-id","Plaintext":"`, keyB64, `"}`))
213	}))
214	defer ts.Close()
215
216	sess := unit.Session.Copy(&aws.Config{
217		MaxRetries:       aws.Int(0),
218		Endpoint:         aws.String(ts.URL),
219		DisableSSL:       aws.Bool(true),
220		S3ForcePathStyle: aws.Bool(true),
221		Region:           aws.String("us-west-2"),
222	})
223
224	o := DecryptionClientOptions{
225		CryptoRegistry: initCryptoRegistryFrom(
226			map[string]WrapEntry{
227				KMSWrap: (kmsKeyHandler{
228					kms: kms.New(sess),
229				}).decryptHandler,
230			}, map[string]CEKEntry{
231				"custom": newAESGCMContentCipher,
232			}, map[string]Padder{}),
233	}
234	iv, err := hex.DecodeString("0d18e06c7c725ac9e362e1ce")
235	if err != nil {
236		t.Errorf("expected no error, but received %v", err)
237	}
238	ivB64 := base64.URLEncoding.EncodeToString(iv)
239
240	cipherKey, err := hex.DecodeString("31bdadd96698c204aa9ce1448ea94ae1fb4a9a0b3c9d773b51bb1822666b8f22")
241	if err != nil {
242		t.Errorf("expected no error, but received %v", err)
243	}
244	cipherKeyB64 := base64.URLEncoding.EncodeToString(cipherKey)
245
246	env := Envelope{
247		WrapAlg:   KMSWrap,
248		CEKAlg:    "custom",
249		CipherKey: cipherKeyB64,
250		IV:        ivB64,
251		MatDesc:   `{"kms_cmk_id":""}`,
252	}
253	wrap, err := wrapFromEnvelope(o, env)
254	cek, err := cekFromEnvelope(o, aws.BackgroundContext(), env, wrap)
255
256	if err != nil {
257		t.Errorf("expected no error, but received %v", err)
258	}
259	if cek == nil {
260		t.Errorf("expected non-nil cek")
261	}
262}
263