1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package test
19
20 import (
21 "context"
22 "crypto"
23 "net/http/httptest"
24 "net/url"
25 "os"
26 "path/filepath"
27 "testing"
28
29 "github.com/google/go-cmp/cmp"
30 "github.com/google/go-containerregistry/pkg/authn"
31 "github.com/google/go-containerregistry/pkg/name"
32 "github.com/google/go-containerregistry/pkg/registry"
33 "github.com/google/go-containerregistry/pkg/v1/random"
34 "github.com/google/go-containerregistry/pkg/v1/remote"
35
36
37 _ "k8s.io/client-go/plugin/pkg/client/auth"
38
39 "github.com/sigstore/cosign/v2/cmd/cosign/cli/options"
40 cliverify "github.com/sigstore/cosign/v2/cmd/cosign/cli/verify"
41 "github.com/sigstore/cosign/v2/pkg/cosign"
42 ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote"
43 sigs "github.com/sigstore/cosign/v2/pkg/signature"
44 )
45
46 const (
47 rekorURL = "http://127.0.0.1:3000"
48 fulcioURL = "http://127.0.0.1:5555"
49 certID = "foo@bar.com"
50 )
51
52 var keyPass = []byte("hello")
53
54 var passFunc = func(_ bool) ([]byte, error) {
55 return keyPass, nil
56 }
57
58 var verify = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment string, skipTlogVerify bool) error {
59 cmd := cliverify.VerifyCommand{
60 KeyRef: keyRef,
61 RekorURL: rekorURL,
62 CheckClaims: checkClaims,
63 Annotations: sigs.AnnotationsMap{Annotations: annotations},
64 Attachment: attachment,
65 HashAlgorithm: crypto.SHA256,
66 MaxWorkers: 10,
67 IgnoreTlog: skipTlogVerify,
68 }
69
70 args := []string{imageRef}
71
72 return cmd.Exec(context.Background(), args)
73 }
74
75 var verifyTSA = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment, tsaCertChain string, skipTlogVerify bool) error {
76 cmd := cliverify.VerifyCommand{
77 KeyRef: keyRef,
78 RekorURL: rekorURL,
79 CheckClaims: checkClaims,
80 Annotations: sigs.AnnotationsMap{Annotations: annotations},
81 Attachment: attachment,
82 HashAlgorithm: crypto.SHA256,
83 TSACertChainPath: tsaCertChain,
84 IgnoreTlog: skipTlogVerify,
85 MaxWorkers: 10,
86 }
87
88 args := []string{imageRef}
89
90 return cmd.Exec(context.Background(), args)
91 }
92
93 var verifyKeylessTSA = func(imageRef string, tsaCertChain string, skipSCT bool, skipTlogVerify bool) error {
94 cmd := cliverify.VerifyCommand{
95 CertVerifyOptions: options.CertVerifyOptions{
96 CertOidcIssuerRegexp: ".*",
97 CertIdentityRegexp: ".*",
98 },
99 RekorURL: rekorURL,
100 HashAlgorithm: crypto.SHA256,
101 TSACertChainPath: tsaCertChain,
102 IgnoreSCT: skipSCT,
103 IgnoreTlog: skipTlogVerify,
104 MaxWorkers: 10,
105 }
106
107 args := []string{imageRef}
108
109 return cmd.Exec(context.Background(), args)
110 }
111
112
113 var verifyLocal = func(keyRef, path string, checkClaims bool, annotations map[string]interface{}, attachment string) error {
114 cmd := cliverify.VerifyCommand{
115 KeyRef: keyRef,
116 RekorURL: rekorURL,
117 CheckClaims: checkClaims,
118 Annotations: sigs.AnnotationsMap{Annotations: annotations},
119 Attachment: attachment,
120 HashAlgorithm: crypto.SHA256,
121 LocalImage: true,
122 MaxWorkers: 10,
123 }
124
125 args := []string{path}
126
127 return cmd.Exec(context.Background(), args)
128 }
129
130 var verifyOffline = func(keyRef, imageRef string, checkClaims bool, annotations map[string]interface{}, attachment string) error {
131 cmd := cliverify.VerifyCommand{
132 KeyRef: keyRef,
133 RekorURL: "notreal",
134 Offline: true,
135 CheckClaims: checkClaims,
136 Annotations: sigs.AnnotationsMap{Annotations: annotations},
137 Attachment: attachment,
138 HashAlgorithm: crypto.SHA256,
139 MaxWorkers: 10,
140 }
141
142 args := []string{imageRef}
143
144 return cmd.Exec(context.Background(), args)
145 }
146
147 var ro = &options.RootOptions{Timeout: options.DefaultTimeout}
148
149 func keypair(t *testing.T, td string) (*cosign.KeysBytes, string, string) {
150 wd, err := os.Getwd()
151 if err != nil {
152 t.Fatal(err)
153 }
154 if err := os.Chdir(td); err != nil {
155 t.Fatal(err)
156 }
157 defer func() {
158 os.Chdir(wd)
159 }()
160 keys, err := cosign.GenerateKeyPair(passFunc)
161 if err != nil {
162 t.Fatal(err)
163 }
164
165 privKeyPath := filepath.Join(td, "cosign.key")
166 if err := os.WriteFile(privKeyPath, keys.PrivateBytes, 0600); err != nil {
167 t.Fatal(err)
168 }
169
170 pubKeyPath := filepath.Join(td, "cosign.pub")
171 if err := os.WriteFile(pubKeyPath, keys.PublicBytes, 0600); err != nil {
172 t.Fatal(err)
173 }
174 return keys, privKeyPath, pubKeyPath
175 }
176
177 func importKeyPair(t *testing.T, td string) (*cosign.KeysBytes, string, string) {
178
179 const validrsa1 = `-----BEGIN RSA PRIVATE KEY-----
180 MIIEogIBAAKCAQEAx5piWVlE62NnZ0UzJ8Z6oKiKOC4dbOZ1HsNhIRtqkM+Oq4G+
181 25yq6P+0JU/Qvr9veOGEb3R/J9u8JBo+hv2i5X8OtgvP2V2pi6f1s6vK7L0+6uRb
182 4YTT/UdMshaVf97MgEqbq41Jf/cuvh+3AV0tZ1BpixZg4aXMKpY6HUP69lbsu27o
183 SUN1myMv7TSgZiV4CYs3l/gkEfpysBptWlcHRuw5RsB+C0RbjRtbJ/5VxmE/vd3M
184 lafd5t1WSpMb8yf0a84u5NFaXwZ7CweMfXeOddS0yb19ShSuW3PPRadruBM1mq15
185 js9GfagPxDS75Imcs+fA62lWvHxEujTGjYHxawIDAQABAoIBAH+sgLwmHa9zJfEo
186 klAe5NFe/QpydN/ziXbkAnzqzH9URC3wD+TpkWj4JoK3Sw635NWtasjf+3XDV9S/
187 9L7j/g5N91r6sziWcJykEsWaXXKQmm4lI6BdFjwsHyLKz1W7bZOiJXDWLu1rbrqu
188 DqEQuLoc9WXCKrYrFy0maoXNtfla/1p05kKN0bMigcnnyAQ+xBTwoyco4tkIz5se
189 IYxorz7qzXrkHQI+knz5BawmNe3ekoSaXUPoLoOR7TRTGsLteL5yukvWAi8S/0rE
190 gftC+PZCQpoQhSUYq7wXe7RowJ1f+kXb7HsSedOTfTSW1D/pUb/uW+CcRKig42ZI
191 I9H9TAECgYEA5XGBML6fJyWVqx64sHbUAjQsmQ0RwU6Zo7sqHIEPf6tYVYp7KtzK
192 KOfi8seOOL5FSy4pjCo11Dzyrh9bn45RNmtjSYTgOnVPSoCfuRNfOcpG+/wCHjYf
193 EjDvdrCpbg59kVUeaMeBDiyWAlM48HJAn8O7ez2U/iKQCyJmOIwFhSkCgYEA3rSz
194 Fi1NzqYWxWos4NBmg8iKcQ9SMkmPdgRLAs/WNnZJ8fdgJZwihevkXGytRGJEmav2
195 GMKRx1g6ey8fjXTQH9WM8X/kJC5fv8wLHnUCH/K3Mcp9CYwn7PFvSnBr4kQoc/el
196 bURhcF1+/opEC8vNX/Wk3zAG7Xs1PREXlH2SIHMCgYBV/3kgwBH/JkM25EjtO1yz
197 hsLAivmAruk/SUO7c1RP0fVF+qW3pxHOyztxLALOmeJ3D1JbSubqKf377Zz17O3b
198 q9yHDdrNjnKtxhAX2n7ytjJs+EQC9t4mf1kB761RpvTBqFnBhCWHHocLUA4jcW9v
199 cnmu86IIrwO2aKpPv4vCIQKBgHU9gY3qOazRSOmSlJ+hdmZn+2G7pBTvHsQNTIPl
200 cCrpqNHl3crO4GnKHkT9vVVjuiOAIKU2QNJFwzu4Og8Y8LvhizpTjoHxm9x3iV72
201 UDELcJ+YrqyJCTe2flUcy96o7Pbn50GXnwgtYD6WAW6IUszyn2ITgYIhu4wzZEt6
202 s6O7AoGAPTKbRA87L34LMlXyUBJma+etMARIP1zu8bXJ7hSJeMcog8zaLczN7ruT
203 pGAaLxggvtvuncMuTrG+cdmsR9SafSFKRS92NCxhOUonQ+NP6mLskIGzJZoQ5JvQ
204 qGzRVIDGbNkrVHM0IsAtHRpC0rYrtZY+9OwiraGcsqUMLwwQdCA=
205 -----END RSA PRIVATE KEY-----`
206
207 wd, err := os.Getwd()
208 if err != nil {
209 t.Fatal(err)
210 }
211 if err := os.Chdir(td); err != nil {
212 t.Fatal(err)
213 }
214 defer func() {
215 os.Chdir(wd)
216 }()
217
218 err = os.WriteFile("validrsa1.key", []byte(validrsa1), 0600)
219 if err != nil {
220 t.Fatal(err)
221 }
222
223 keys, err := cosign.ImportKeyPair("validrsa1.key", passFunc)
224 if err != nil {
225 t.Fatal(err)
226 }
227
228 privKeyPath := filepath.Join(td, "import-cosign.key")
229 if err := os.WriteFile(privKeyPath, keys.PrivateBytes, 0600); err != nil {
230 t.Fatal(err)
231 }
232
233 pubKeyPath := filepath.Join(td, "import-cosign.pub")
234 if err := os.WriteFile(pubKeyPath, keys.PublicBytes, 0600); err != nil {
235 t.Fatal(err)
236 }
237 return keys, privKeyPath, pubKeyPath
238
239 }
240
241 func mockStdin(contents, td string, t *testing.T) func() {
242 origin := os.Stdin
243
244 p := mkfile(contents, td, t)
245 f, err := os.Open(p)
246 if err != nil {
247 t.Fatal(err)
248 }
249 os.Stdin = f
250
251 return func() { os.Stdin = origin }
252 }
253
254 func mkfile(contents, td string, t *testing.T) string {
255 f, err := os.CreateTemp(td, "")
256 if err != nil {
257 t.Fatal(err)
258 }
259 defer f.Close()
260 if _, err := f.Write([]byte(contents)); err != nil {
261 t.Fatal(err)
262 }
263 return f.Name()
264 }
265
266 func mkfileWithExt(contents, td, ext string, t *testing.T) string {
267 f := mkfile(contents, td, t)
268 newName := f + ext
269 err := os.Rename(f, newName)
270 if err != nil {
271 t.Fatal(err)
272 }
273 return newName
274 }
275
276 func mkimage(t *testing.T, n string) (name.Reference, *remote.Descriptor, func()) {
277 ref, err := name.ParseReference(n, name.WeakValidation)
278 if err != nil {
279 t.Fatal(err)
280 }
281 img, err := random.Image(512, 5)
282 if err != nil {
283 t.Fatal(err)
284 }
285
286 regClientOpts := registryClientOpts(context.Background())
287
288 if err := remote.Write(ref, img, regClientOpts...); err != nil {
289 t.Fatal(err)
290 }
291
292 remoteImage, err := remote.Get(ref, regClientOpts...)
293 if err != nil {
294 t.Fatal(err)
295 }
296
297 cleanup := func() {
298 _ = remote.Delete(ref, regClientOpts...)
299 ref, _ := ociremote.SignatureTag(ref.Context().Digest(remoteImage.Descriptor.Digest.String()), ociremote.WithRemoteOptions(regClientOpts...))
300 _ = remote.Delete(ref, regClientOpts...)
301 }
302 return ref, remoteImage, cleanup
303 }
304
305 func mkimageindex(t *testing.T, n string) (name.Reference, *remote.Descriptor, func()) {
306 ref, err := name.ParseReference(n, name.WeakValidation)
307 if err != nil {
308 t.Fatal(err)
309 }
310 ii, err := random.Index(512, 5, 4)
311 if err != nil {
312 t.Fatal(err)
313 }
314
315 regClientOpts := registryClientOpts(context.Background())
316
317 if err := remote.WriteIndex(ref, ii, regClientOpts...); err != nil {
318 t.Fatal(err)
319 }
320
321 remoteIndex, err := remote.Get(ref, regClientOpts...)
322 if err != nil {
323 t.Fatal(err)
324 }
325
326 cleanup := func() {
327 _ = remote.Delete(ref, regClientOpts...)
328 ref, _ := ociremote.SignatureTag(ref.Context().Digest(remoteIndex.Descriptor.Digest.String()), ociremote.WithRemoteOptions(regClientOpts...))
329 _ = remote.Delete(ref, regClientOpts...)
330 }
331 return ref, remoteIndex, cleanup
332 }
333
334 func must(err error, t *testing.T) {
335 t.Helper()
336 if err != nil {
337 t.Fatal(err)
338 }
339 }
340
341 func mustErr(err error, t *testing.T) {
342 t.Helper()
343 if err == nil {
344 t.Fatal("expected error")
345 }
346 }
347
348 func equals(v1, v2 interface{}, t *testing.T) {
349 if diff := cmp.Diff(v1, v2); diff != "" {
350 t.Error(diff)
351 }
352 }
353
354 func reg(t *testing.T) (string, func()) {
355 repo := os.Getenv("COSIGN_TEST_REPO")
356 if repo != "" {
357 return repo, func() {}
358 }
359
360 t.Log("COSIGN_TEST_REPO unset, using fake registry")
361 r := httptest.NewServer(registry.New())
362 u, err := url.Parse(r.URL)
363 if err != nil {
364 t.Fatal(err)
365 }
366 return u.Host, r.Close
367 }
368
369 func registryClientOpts(ctx context.Context) []remote.Option {
370 return []remote.Option{
371 remote.WithAuthFromKeychain(authn.DefaultKeychain),
372 remote.WithContext(ctx),
373 }
374 }
375
View as plain text