1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package mutate
16
17 import (
18 "encoding/base64"
19 "io"
20 "testing"
21
22 "github.com/google/go-cmp/cmp"
23 "github.com/google/go-containerregistry/pkg/v1/types"
24 "github.com/sigstore/cosign/v2/pkg/cosign/bundle"
25 "github.com/sigstore/cosign/v2/pkg/oci"
26 "github.com/sigstore/cosign/v2/pkg/oci/static"
27 )
28
29 var (
30 testCertBytes = []byte(`
31 -----BEGIN CERTIFICATE-----
32 MIICjzCCAhSgAwIBAgITV2heiswW9YldtVEAu98QxDO8TTAKBggqhkjOPQQDAzAq
33 MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx
34 MDkxNDE5MTI0MFoXDTIxMDkxNDE5MzIzOVowADBZMBMGByqGSM49AgEGCCqGSM49
35 AwEHA0IABMF1AWZcfvubslc4ABNnvGbRjm6GWVHxrJ1RRthTHMCE4FpFmiHQBfGt
36 6n80DqszGj77Whb35O33+Dal4Y2po+CjggFBMIIBPTAOBgNVHQ8BAf8EBAMCB4Aw
37 EwYDVR0lBAwwCgYIKwYBBQUHAwMwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU340G
38 3G1ozVNmFC5TBFV0yNuouvowHwYDVR0jBBgwFoAUyMUdAEGaJCkyUSTrDa5K7UoG
39 0+wwgY0GCCsGAQUFBwEBBIGAMH4wfAYIKwYBBQUHMAKGcGh0dHA6Ly9wcml2YXRl
40 Y2EtY29udGVudC02MDNmZTdlNy0wMDAwLTIyMjctYmY3NS1mNGY1ZTgwZDI5NTQu
41 c3RvcmFnZS5nb29nbGVhcGlzLmNvbS9jYTM2YTFlOTYyNDJiOWZjYjE0Ni9jYS5j
42 cnQwOAYDVR0RAQH/BC4wLIEqa2V5bGVzc0BkaXN0cm9sZXNzLmlhbS5nc2Vydmlj
43 ZWFjY291bnQuY29tMAoGCCqGSM49BAMDA2kAMGYCMQDcH9cdkxW6ugsbPHqX9qrM
44 wlMaprcwnlktS3+5xuABr5icuqwrB/Fj5doFtS7AnM0CMQD9MjSaUmHFFF7zoLMx
45 uThR1Z6JuA21HwxtL3GyJ8UQZcEPOlTBV593HrSAwBhiCoY=
46 -----END CERTIFICATE-----
47 `)
48 testChainBytes = []byte(`
49 -----BEGIN CERTIFICATE-----
50 MIIB+DCCAX6gAwIBAgITNVkDZoCiofPDsy7dfm6geLbuhzAKBggqhkjOPQQDAzAq
51 MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxETAPBgNVBAMTCHNpZ3N0b3JlMB4XDTIx
52 MDMwNzAzMjAyOVoXDTMxMDIyMzAzMjAyOVowKjEVMBMGA1UEChMMc2lnc3RvcmUu
53 ZGV2MREwDwYDVQQDEwhzaWdzdG9yZTB2MBAGByqGSM49AgEGBSuBBAAiA2IABLSy
54 A7Ii5k+pNO8ZEWY0ylemWDowOkNa3kL+GZE5Z5GWehL9/A9bRNA3RbrsZ5i0Jcas
55 taRL7Sp5fp/jD5dxqc/UdTVnlvS16an+2Yfswe/QuLolRUCrcOE2+2iA5+tzd6Nm
56 MGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYE
57 FMjFHQBBmiQpMlEk6w2uSu1KBtPsMB8GA1UdIwQYMBaAFMjFHQBBmiQpMlEk6w2u
58 Su1KBtPsMAoGCCqGSM49BAMDA2gAMGUCMH8liWJfMui6vXXBhjDgY4MwslmN/TJx
59 Ve/83WrFomwmNf056y1X48F9c4m3a3ozXAIxAKjRay5/aj/jsKKGIkmQatjI8uup
60 Hr/+CxFvaJWmpYqNkLDGRU+9orzh5hI2RrcuaQ==
61 -----END CERTIFICATE-----
62 `)
63 )
64
65 func mustCreateSignature(t *testing.T, payload []byte, b64sig string, opts ...static.Option) oci.Signature {
66 t.Helper()
67 sig, err := static.NewSignature(payload, b64sig, opts...)
68 if err != nil {
69 t.Fatalf("failed to create static signature: %v", err)
70 }
71 return sig
72 }
73
74 func mustBase64Decode(t *testing.T, s string) []byte {
75 t.Helper()
76 b, err := base64.StdEncoding.DecodeString(s)
77 if err != nil {
78 t.Fatalf("failed to base64 decode: %v", err)
79 }
80 return b
81 }
82
83 func assertSignaturesEqual(t *testing.T, wanted, got oci.Signature) {
84 t.Helper()
85
86 t.Run("Payloads match", func(t *testing.T) {
87 t.Helper()
88 wantedPayload, err := wanted.Payload()
89 if err != nil {
90 t.Fatalf("wanted.Payload() returned error: %v", err)
91 }
92 gotPayload, err := got.Payload()
93 if err != nil {
94 t.Fatalf("got.Payload() returned error: %v", err)
95 }
96 if diff := cmp.Diff(wantedPayload, gotPayload); diff != "" {
97 t.Errorf("Payload() mismatch (-want +got):\n%s", diff)
98 }
99 })
100
101 t.Run("Base64Signatures match", func(t *testing.T) {
102 t.Helper()
103 wantedB64Sig, err := wanted.Base64Signature()
104 if err != nil {
105 t.Fatalf("wanted.Base64Signature() returned error: %v", err)
106 }
107 gotB64Sig, err := got.Base64Signature()
108 if err != nil {
109 t.Fatalf("got.Base64Signature() returned error: %v", err)
110 }
111 if diff := cmp.Diff(wantedB64Sig, gotB64Sig); diff != "" {
112 t.Errorf("Base64Signature() mismatch (-want +got):\n%s", diff)
113 }
114 })
115
116 t.Run("Bundles match", func(t *testing.T) {
117 t.Helper()
118 wantedBundle, err := wanted.Bundle()
119 if err != nil {
120 t.Fatalf("wanted.Bundle() returned error: %v", err)
121 }
122 gotBundle, err := got.Bundle()
123 if err != nil {
124 t.Fatalf("got.Bundle() returned error: %v", err)
125 }
126 if diff := cmp.Diff(wantedBundle, gotBundle); diff != "" {
127 t.Errorf("Bundle() mismatch (-want +got):\n%s", diff)
128 }
129 })
130
131 t.Run("RFC3161 timestamp bundles match", func(t *testing.T) {
132 t.Helper()
133 wantedBundle, err := wanted.RFC3161Timestamp()
134 if err != nil {
135 t.Fatalf("wanted.Bundle() returned error: %v", err)
136 }
137 gotBundle, err := got.RFC3161Timestamp()
138 if err != nil {
139 t.Fatalf("got.RFC3161Timestamp() returned error: %v", err)
140 }
141 if diff := cmp.Diff(wantedBundle, gotBundle); diff != "" {
142 t.Errorf("RFC3161Timestamp() mismatch (-want +got):\n%s", diff)
143 }
144 })
145
146 t.Run("Certs match", func(t *testing.T) {
147 t.Helper()
148 wantedCert, err := wanted.Cert()
149 if err != nil {
150 t.Fatalf("wanted.Bundle() returned error: %v", err)
151 }
152 gotCert, err := got.Cert()
153 if err != nil {
154 t.Fatalf("got.Cert() returned error: %v", err)
155 }
156 if diff := cmp.Diff(wantedCert, gotCert); diff != "" {
157 t.Errorf("Cert() mismatch (-want +got):\n%s", diff)
158 }
159 })
160
161 t.Run("Chains match", func(t *testing.T) {
162 t.Helper()
163 wantedChain, err := wanted.Chain()
164 if err != nil {
165 t.Fatalf("wanted.Bundle() returned error: %v", err)
166 }
167 gotChain, err := got.Chain()
168 if err != nil {
169 t.Fatalf("got.Chain() returned error: %v", err)
170 }
171 if diff := cmp.Diff(wantedChain, gotChain); diff != "" {
172 t.Errorf("Chain() mismatch (-want +got):\n%s", diff)
173 }
174 })
175
176 t.Run("MediaTypes match", func(t *testing.T) {
177 t.Helper()
178 wantedMediaType, err := wanted.MediaType()
179 if err != nil {
180 t.Fatalf("wanted.MediaType() returned error: %v", err)
181 }
182 gotMediaType, err := got.MediaType()
183 if err != nil {
184 t.Fatalf("got.MediaType() returned error: %v", err)
185 }
186 if diff := cmp.Diff(wantedMediaType, gotMediaType); diff != "" {
187 t.Errorf("MediaType() mismatch (-want +got):\n%s", diff)
188 }
189 })
190
191 var gotAnnotations map[string]string
192 t.Run("Annotations match", func(t *testing.T) {
193 t.Helper()
194 wantedAnnotations, err := wanted.Annotations()
195 if err != nil {
196 t.Fatalf("wanted.Annotations() returned error: %v", err)
197 }
198 gotAnnotations, err = got.Annotations()
199 if err != nil {
200 t.Fatalf("got.Annotations() returned error: %v", err)
201 }
202 if diff := cmp.Diff(wantedAnnotations, gotAnnotations); diff != "" {
203 t.Errorf("Annotations() mismatch (-want +got):\n%s", diff)
204 }
205 })
206
207 t.Run("DiffIDs match", func(t *testing.T) {
208 t.Helper()
209 wantedDiffID, err := wanted.DiffID()
210 if err != nil {
211 t.Fatalf("wanted.DiffID() returned error: %v", err)
212 }
213 gotDiffID, err := got.DiffID()
214 if err != nil {
215 t.Fatalf("got.DiffID() returned error: %v", err)
216 }
217 if wantedDiffID != gotDiffID {
218 t.Errorf("DiffID() mismatch. Wanted: %v, got: %v", wantedDiffID, gotDiffID)
219 }
220 })
221
222 t.Run("Sizes match", func(t *testing.T) {
223 t.Helper()
224 wantedSize, err := wanted.Size()
225 if err != nil {
226 t.Fatalf("wanted.Size() returned error: %v", err)
227 }
228 gotSize, err := got.Size()
229 if err != nil {
230 t.Fatalf("got.Size() returned error: %v", err)
231 }
232 if wantedSize != gotSize {
233 t.Errorf("Size() mismatch. Wanted: %v, got: %v", wantedSize, gotSize)
234 }
235 })
236
237 t.Run("Compressed values match", func(t *testing.T) {
238 t.Helper()
239 wantedCompReader, err := wanted.Compressed()
240 if err != nil {
241 t.Fatalf("wanted.Compressed() returned error: %v", err)
242 }
243 defer wantedCompReader.Close()
244 wantedCompressed, err := io.ReadAll(wantedCompReader)
245 if err != nil {
246 t.Fatalf("io.ReadAll(wanted.Compressed()) returned error: %v", err)
247 }
248 gotCompReader, err := got.Compressed()
249 if err != nil {
250 t.Fatalf("got.Compressed() returned error: %v", err)
251 }
252 defer gotCompReader.Close()
253 gotCompressed, err := io.ReadAll(gotCompReader)
254 if err != nil {
255 t.Fatalf("io.ReadAll(got.Compressed()) returned error: %v", err)
256 }
257 if diff := cmp.Diff(wantedCompressed, gotCompressed); diff != "" {
258 t.Errorf("MediaType() mismatch (-want +got):\n%s", diff)
259 }
260 })
261
262 t.Run("Uncompressed values match", func(t *testing.T) {
263 t.Helper()
264 wantedUncompReader, err := wanted.Uncompressed()
265 if err != nil {
266 t.Fatalf("wanted.Uncompressed() returned error: %v", err)
267 }
268 defer wantedUncompReader.Close()
269 wantedUncompressed, err := io.ReadAll(wantedUncompReader)
270 if err != nil {
271 t.Fatalf("io.ReadAll(wanted.Uncompressed()) returned error: %v", err)
272 }
273 gotUncompReader, err := got.Uncompressed()
274 if err != nil {
275 t.Fatalf("got.Compressed() returned error: %v", err)
276 }
277 defer gotUncompReader.Close()
278 gotUncompressed, err := io.ReadAll(gotUncompReader)
279 if err != nil {
280 t.Fatalf("io.ReadAll(got.Uncompressed()) returned error: %v", err)
281 }
282 if diff := cmp.Diff(wantedUncompressed, gotUncompressed); diff != "" {
283 t.Errorf("MediaType() mismatch (-want +got):\n%s", diff)
284 }
285 })
286 }
287
288 func TestSignatureWithAnnotations(t *testing.T) {
289 payload := "this is the TestSignatureWithAnnotations content!"
290 b64sig := "b64 content1="
291 annotations := map[string]string{
292 "foo": "bar",
293 "test": "yes",
294 }
295 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
296 expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithAnnotations(annotations))
297
298 newSig, err := Signature(originalSig, WithAnnotations(annotations))
299 if err != nil {
300 t.Fatalf("Signature(WithAnnotations()) returned error: %v", err)
301 }
302
303 assertSignaturesEqual(t, expectedSig, newSig)
304 }
305
306 func TestSignatureWithBundle(t *testing.T) {
307 payload := "this is the TestSignatureWithBundle content!"
308 b64sig := "b64 content2="
309 b := &bundle.RekorBundle{
310 SignedEntryTimestamp: mustBase64Decode(t, "MEUCIEDcarEwRYkrxE9ne+kzEVvUhnWaauYzxhUyXOLy1hwAAiEA4VdVCvNRs+D/5o33C2KBy+q2YX3lP4Y7nqRFU+K3hi0="),
311 Payload: bundle.RekorPayload{
312 Body: "REMOVED",
313 IntegratedTime: 1631646761,
314 LogIndex: 693591,
315 LogID: "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
316 },
317 }
318 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
319 expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithBundle(b))
320
321 newSig, err := Signature(originalSig, WithBundle(b))
322 if err != nil {
323 t.Fatalf("Signature(WithBundle()) returned error: %v", err)
324 }
325
326 assertSignaturesEqual(t, expectedSig, newSig)
327 }
328
329 func TestSignatureWithRFC3161Timestamp(t *testing.T) {
330 payload := "this is the TestSignatureWithBundle content!"
331 b64sig := "b64 content2="
332 b := &bundle.RFC3161Timestamp{
333 SignedRFC3161Timestamp: mustBase64Decode(t, "MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="),
334 }
335 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
336 expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithRFC3161Timestamp(b))
337
338 newSig, err := Signature(originalSig, WithRFC3161Timestamp(b))
339 if err != nil {
340 t.Fatalf("Signature(WithRFC3161Timestamp()) returned error: %v", err)
341 }
342
343 assertSignaturesEqual(t, expectedSig, newSig)
344 }
345
346 func TestSignatureWithCertChain(t *testing.T) {
347 payload := "this is the TestSignatureWithCertChain content!"
348 b64sig := "b64 content3="
349
350 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
351 expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithCertChain(testCertBytes, testChainBytes))
352
353 newSig, err := Signature(originalSig, WithCertChain(testCertBytes, testChainBytes))
354 if err != nil {
355 t.Fatalf("Signature(WithCertChain()) returned error: %v", err)
356 }
357
358 assertSignaturesEqual(t, expectedSig, newSig)
359 }
360
361 func TestSignatureWithMediaType(t *testing.T) {
362 payload := "this is the TestSignatureWithMediaType content!"
363 b64sig := "b64 content4="
364 mediaType := types.MediaType("test/media.type")
365
366 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
367 expectedSig := mustCreateSignature(t, []byte(payload), b64sig, static.WithLayerMediaType(mediaType))
368
369 newSig, err := Signature(originalSig, WithMediaType(mediaType))
370 if err != nil {
371 t.Fatalf("Signature(WithMediaType()) returned error: %v", err)
372 }
373
374 assertSignaturesEqual(t, expectedSig, newSig)
375 }
376
377 func TestSignatureWithEverything(t *testing.T) {
378 payload := "this is the TestSignatureWithEverything content!"
379 b64sig := "b64 content5="
380 annotations := map[string]string{
381 "foo": "bar",
382 "test": "yes",
383 }
384 b := &bundle.RekorBundle{
385 SignedEntryTimestamp: mustBase64Decode(t, "MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="),
386 Payload: bundle.RekorPayload{
387 Body: "REMOVED",
388 IntegratedTime: 1631646761,
389 LogIndex: 693591,
390 LogID: "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d",
391 },
392 }
393 mediaType := types.MediaType("test/media.type")
394
395 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
396
397 expectedSig := mustCreateSignature(t, []byte(payload), b64sig,
398 static.WithAnnotations(annotations),
399 static.WithBundle(b),
400 static.WithCertChain(testCertBytes, testChainBytes),
401 static.WithLayerMediaType(mediaType))
402
403 newSig, err := Signature(originalSig,
404 WithAnnotations(annotations),
405 WithBundle(b),
406 WithCertChain(testCertBytes, testChainBytes),
407 WithMediaType(mediaType))
408
409 if err != nil {
410 t.Fatalf("Signature(With...) returned error: %v", err)
411 }
412
413 assertSignaturesEqual(t, expectedSig, newSig)
414 }
415
416 func TestSignatureWithEverythingTSA(t *testing.T) {
417 payload := "this is the TestSignatureWithEverything content!"
418 b64sig := "b64 content5="
419 annotations := map[string]string{
420 "foo": "bar",
421 "test": "yes",
422 }
423 b := &bundle.RFC3161Timestamp{
424 SignedRFC3161Timestamp: mustBase64Decode(t, "MEUCIQClUkUqZNf+6dxBc/pxq22JIluTB7Kmip1G0FIF5E0C1wIgLqXm+IM3JYW/P/qjMZSXW+J8bt5EOqNfe3R+0A9ooFE="),
425 }
426 mediaType := types.MediaType("test/media.type")
427
428 originalSig := mustCreateSignature(t, []byte(payload), b64sig)
429
430 expectedSig := mustCreateSignature(t, []byte(payload), b64sig,
431 static.WithAnnotations(annotations),
432 static.WithRFC3161Timestamp(b),
433 static.WithCertChain(testCertBytes, testChainBytes),
434 static.WithLayerMediaType(mediaType))
435
436 newSig, err := Signature(originalSig,
437 WithAnnotations(annotations),
438 WithRFC3161Timestamp(b),
439 WithCertChain(testCertBytes, testChainBytes),
440 WithMediaType(mediaType))
441
442 if err != nil {
443 t.Fatalf("Signature(With...) returned error: %v", err)
444 }
445
446 assertSignaturesEqual(t, expectedSig, newSig)
447 }
448
View as plain text