1 package in_toto
2
3 import (
4 "bytes"
5 "crypto/x509"
6 "crypto/x509/pkix"
7 "encoding/hex"
8 "errors"
9 "fmt"
10 "os"
11 "reflect"
12 "strings"
13 "testing"
14 "time"
15
16 "github.com/stretchr/testify/assert"
17 )
18
19 func init() {
20
21 os.Setenv("TZ", "UTC")
22 }
23
24 func TestMatchEcdsaScheme(t *testing.T) {
25 curveSize := 224
26 scheme := "ecdsa-sha2-nistp512"
27 if err := matchEcdsaScheme(curveSize, scheme); err == nil {
28 t.Errorf("matchEcdsaScheme should have failed with curveSize: %d and scheme: %s", curveSize, scheme)
29 }
30 }
31
32 func TestMetablockLoad(t *testing.T) {
33
34
35
36
37
38
39
40
41 invalidJSONBytes := [][]byte{
42 []byte("{"),
43 []byte("{}"),
44 []byte(`{"signatures": null, "signed": {}}`),
45 []byte(`{"signatures": "string", "signed": {}}`),
46 []byte(`{"signatures": [], "signed": []}`),
47 []byte(`{"signatures": [], "signed": {"_type": "something else"}}`),
48 []byte(`{"signatures": [], "signed": {"_type": "link",
49 "materials": "invalid", "name": "some name", "products": "invalid",
50 "byproducts": "invalid", "command": "some command",
51 "environment": "some list"}}`),
52 []byte(`{"signatures": [], "signed": {"_type": "layout",
53 "steps": "invalid", "inspect": "invalid", "readme": "some readme",
54 "keys": "some keys", "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
55 []byte(`{"signatures": [], "signed": {"_type": "layout",
56 "inspect": "invalid", "readme": "some readme", "keys": "some keys",
57 "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
58 []byte(`{"signatures": [], "signed": {"_type": "layout",
59 "steps": "invalid", "readme": "some readme", "keys": "some keys",
60 "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
61 []byte(`{"signatures": [], "signed": {"_type": "layout",
62 "steps": "invalid", "inspect": "invalid", "readme": "some readme",
63 "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
64 []byte(`{"signatures": [], "signed": {"_type": "layout",
65 "steps": "invalid", "inspect": "invalid", "readme": "some readme",
66 "keys": "some keys", "rootcas": [], "intermediatecas": []}}`),
67 []byte(`{"signatures": [], "signed": {"_type": "layout",
68 "steps": "invalid", "inspect": "invalid",
69 "keys": "some keys", "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
70 []byte(`{"signatures": [], "signed": {"_type": "layout", "steps": [],
71 "inspect": [], "readme": "some readme", "keys": {},
72 "expires": "some date", "foo": "bar", "rootcas": [], "intermediatecas": []}}`),
73 []byte(`{"signatures": [], "signed": {"_type": "link",
74 "materials": "invalid", "products": "invalid",
75 "byproducts": "invalid", "command": "some command",
76 "environment": "some list"}}`),
77 []byte(`{"signatures": [], "signed": {"_type": "link",
78 "name": "some name", "products": "invalid",
79 "byproducts": "invalid", "command": "some command",
80 "environment": "some list"}}`),
81 []byte(`{"signatures": [], "signed": {"_type": "link",
82 "materials": "invalid", "name": "some name",
83 "byproducts": "invalid", "command": "some command",
84 "environment": "some list"}}`),
85 []byte(`{"signatures": [], "signed": {"_type": "link",
86 "materials": "invalid", "name": "some name", "products": "invalid",
87 "command": "some command",
88 "environment": "some list"}}`),
89 []byte(`{"signatures": [], "signed": {"_type": "link",
90 "materials": "invalid", "name": "some name", "products": "invalid",
91 "byproducts": "invalid", "environment": "some list"}}`),
92 []byte(`{"signatures": [], "signed": {"_type": "link",
93 "materials": "invalid", "name": "some name", "products": "invalid",
94 "byproducts": "invalid", "command": "some command"}}`),
95 []byte(`{"signatures": [], "signed": {"_type": "link", "materials": {},
96 "name": "some name", "products": {}, "byproducts": {},
97 "command": [], "environment": {}, "foo": "bar"}}`),
98 }
99
100 expectedErrors := []string{
101 "unexpected end",
102 "requires 'signed' and 'signatures' parts",
103 "requires 'signed' and 'signatures' parts",
104 "cannot unmarshal string into Go value of type []in_toto.Signature",
105 "cannot unmarshal array into Go value of type map[string]interface {}",
106 ErrUnknownMetadataType.Error(),
107 "cannot unmarshal string into Go struct field Link.materials",
108 "cannot unmarshal string into Go struct field Layout.steps",
109 "required field steps missing",
110 "required field inspect missing",
111 "required field keys missing",
112 "required field expires missing",
113 "required field readme missing",
114 "json: unknown field \"foo\"",
115 "required field name missing",
116 "required field materials missing",
117 "required field products missing",
118 "required field byproducts missing",
119 "required field command missing",
120 "required field environment missing",
121 "json: unknown field \"foo\"",
122 }
123
124 for i := 0; i < len(invalidJSONBytes); i++ {
125 fn := fmt.Sprintf("invalid-metadata-%v.tmp", i)
126 if err := os.WriteFile(fn, invalidJSONBytes[i], 0644); err != nil {
127 fmt.Printf("Could not write file: %s", err)
128 }
129 var mb Metablock
130 err := mb.Load(fn)
131 if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
132 t.Errorf("Metablock.Load returned '%s', expected '%s' error", err,
133 expectedErrors[i])
134 }
135 if err := os.Remove(fn); err != nil {
136 t.Errorf("unable to remove directory %s: %s", fn, err)
137 }
138 }
139 }
140
141 func TestMetablockDump(t *testing.T) {
142
143
144
145 mbs := []Metablock{
146 {Signed: TestMetablockDump},
147 {},
148 }
149 paths := []string{
150 "bad-metadata",
151 "bad/path",
152 }
153 expectedErrors := []string{
154 "json: unsupported type",
155 "open bad/path",
156 }
157
158 for i := 0; i < len(mbs); i++ {
159 err := mbs[i].Dump(paths[i])
160 fmt.Println(err)
161 if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
162 t.Errorf("Metablock.Dump returned '%s', expected '%s'",
163 err, expectedErrors[i])
164 }
165 }
166 }
167
168 func TestMetablockLoadDumpLoad(t *testing.T) {
169
170
171 mbMemory := Metablock{
172 Signed: Link{
173 Type: "link",
174 Name: "package",
175 Command: []string{
176 "tar",
177 "zcvf",
178 "foo.tar.gz",
179 "foo.py",
180 },
181 Materials: map[string]interface{}{
182 "foo.py": map[string]interface{}{
183 "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549",
184 },
185 },
186 Products: map[string]interface{}{
187 "foo.tar.gz": map[string]interface{}{
188 "sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c1e5aabb7c98514f355",
189 },
190 },
191 ByProducts: map[string]interface{}{
192 "return-value": float64(0),
193 "stderr": "a foo.py\n",
194 "stdout": "",
195 },
196 Environment: map[string]interface{}{},
197 },
198 Signatures: []Signature{
199 {
200 KeyID: "d3ffd1086938b3698618adf088bf14b13db4c8ae19e4e78d73da49ee88492710",
201 Sig: "7d42ca77f6bbbb65b015ec9e31abdfa05c0daecc34b016dd7997b26c3a347cb9a3d9045c8ac7e375f017076bc04687eb870e09f76031a014d60421fa288a11a0022ab225bcfde7b22d78891eeab06b0701b5a6d00368534bf7a3f6b16dc7aaed233a3fb5ab7e98e0ed0ffca5d128dd2549f2d2fe296038cd2111e282de31a44c428498e9788f8226d454331af6f582a1e61e88846265d0cd4722a431253f40bb52c9e56feffd90aca8ec0c6970576538eef5824c91159bce7583a10ae1a38c081e3991c7a20f280430cb1eb4e828c8a0f9c8c8ca41c27b2837a88ff7aa5052b4ac45d8fd5897a71f2f488ca3f52c7a770a01f2d8ab775a328cd1d4c45bb2e92c",
202 },
203 },
204 }
205
206 fnExisting := "package.d3ffd108.link"
207 fnTmp := fnExisting + ".tmp"
208 if err := mbMemory.Dump(fnTmp); err != nil {
209 t.Errorf("JSON serialization failed: %s", err)
210 }
211 for _, fn := range []string{fnExisting, fnTmp} {
212 var mbFile Metablock
213 if err := mbFile.Load(fn); err != nil {
214 t.Errorf("could not parse Metablock: %s", err)
215 }
216 if !reflect.DeepEqual(mbMemory, mbFile) {
217 t.Errorf("dumped and Loaded Metablocks are not equal: \n%s\n\n\n%s\n",
218 mbMemory, mbFile)
219 }
220 }
221
222 if err := os.Remove(fnTmp); err != nil {
223 t.Errorf("unable to remove directory %s: %s", fnTmp, err)
224 }
225 }
226
227 func TestMetablockGetSignableRepresentation(t *testing.T) {
228
229
230 var mb Metablock
231 if err := mb.Load("canonical-test.link"); err != nil {
232 t.Errorf("cannot parse link file: %s", err)
233 }
234
235 referenceHex := "7b225f74797065223a226c696e6b222" +
236 "c22627970726f6475637473223a7b7d2c22636f6d6d616e64223a5b5d2" +
237 "c22656e7669726f6e6d656e74223a7b2261223a22575446222c2262223" +
238 "a747275652c2263223a66616c73652c2264223a6e756c6c2c2265223a3" +
239 "12c2266223a221befbfbf465c5c6e5c22227d2c226d6174657269616c7" +
240 "3223a7b7d2c226e616d65223a2274657374222c2270726f64756374732" +
241 "23a7b7d7d"
242
243 canonical, _ := mb.GetSignableRepresentation()
244 if fmt.Sprintf("%x", canonical) != referenceHex {
245
246 src := []byte(referenceHex)
247 reference := make([]byte, hex.DecodedLen(len(src)))
248 n, _ := hex.Decode(reference, src)
249 t.Errorf("Metablock.GetSignableRepresentation returned '%s', expected '%s'",
250 canonical, reference[:n])
251 }
252 }
253
254 func TestMetablockVerifySignature(t *testing.T) {
255
256
257
258
259 var key Key
260 if err := key.LoadKey("alice.pub", "rsassa-pss-sha256", []string{"sha256", "sha512"}); err != nil {
261 t.Errorf("cannot load public key file: %s", err)
262 }
263
264 mbs := []Metablock{
265 {},
266 {
267 Signatures: []Signature{{KeyID: key.KeyID, Sig: "bad sig"}},
268 },
269 {
270 Signatures: []Signature{{KeyID: key.KeyID}},
271 Signed: TestMetablockVerifySignature,
272 },
273 }
274 expectedErrors := []string{
275 "no signature found",
276 "encoding/hex: invalid byte: U+0020 ' '",
277 "json: unsupported type",
278 }
279 for i := 0; i < len(mbs); i++ {
280 err := mbs[i].VerifySignature(key)
281 if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
282 t.Errorf("Metablock.VerifySignature returned '%s', expected '%s'",
283 err, expectedErrors[i])
284 }
285 }
286
287
288 var mb Metablock
289 if err := mb.Load("demo.layout"); err != nil {
290 t.Errorf("cannot parse template file: %s", err)
291 }
292 err := mb.VerifySignature(key)
293 if err != nil {
294 t.Errorf("Metablock.VerifySignature returned '%s', expected nil", err)
295 }
296 }
297
298 func TestValidateLink(t *testing.T) {
299 var mb Metablock
300 if err := mb.Load("package.d3ffd108.link"); err != nil {
301 t.Errorf("Metablock.Load returned '%s'", err)
302 }
303 if err := validateLink(mb.Signed.(Link)); err != nil {
304 t.Errorf("link metadata validation failed, returned '%s'", err)
305 }
306
307 testMb := Metablock{
308 Signed: Link{
309 Type: "invalid",
310 Name: "test_type",
311 Command: []string{
312 "tar",
313 "zcvf",
314 "foo.tar.gz",
315 "foo.py",
316 },
317 Materials: map[string]interface{}{
318 "foo.py": map[string]interface{}{
319 "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549",
320 },
321 },
322 Products: map[string]interface{}{
323 "foo.tar.gz": map[string]interface{}{
324 "sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c1e5aabb7c98514f355",
325 },
326 },
327 ByProducts: map[string]interface{}{
328 "return-value": float64(0),
329 "stderr": "a foo.py\n",
330 "stdout": "",
331 },
332 Environment: map[string]interface{}{},
333 },
334 }
335
336 err := validateLink(testMb.Signed.(Link))
337 if err.Error() != "invalid type for link 'test_type': should be 'link'" {
338 t.Error("validateLink error - incorrect type not detected")
339 }
340
341 testMb = Metablock{
342 Signed: Link{
343 Type: "link",
344 Name: "test_material_hash",
345 Command: []string{
346 "tar",
347 "zcvf",
348 "foo.tar.gz",
349 "foo.py",
350 },
351 Materials: map[string]interface{}{
352 "foo.py": map[string]interface{}{
353 "sha256": "!@#$%",
354 },
355 },
356 Products: map[string]interface{}{
357 "foo.tar.gz": map[string]interface{}{
358 "sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e69" +
359 "36c1e5aabb7c98514f355",
360 },
361 },
362 ByProducts: map[string]interface{}{
363 "return-value": float64(0),
364 "stderr": "a foo.py\n",
365 "stdout": "",
366 },
367 Environment: map[string]interface{}{},
368 },
369 }
370
371 err = validateLink(testMb.Signed.(Link))
372 if err.Error() != "in materials of link 'test_material_hash': in artifact"+
373 " 'foo.py', sha256 hash value: invalid hex string: !@#$%" {
374 t.Error("validateLink error - invalid hashes not detected")
375 }
376
377 testMb = Metablock{
378 Signed: Link{
379 Type: "link",
380 Name: "test_product_hash",
381 Command: []string{
382 "tar",
383 "zcvf",
384 "foo.tar.gz",
385 "foo.py",
386 },
387 Materials: map[string]interface{}{
388 "foo.py": map[string]interface{}{
389 "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549",
390 },
391 },
392 Products: map[string]interface{}{
393 "foo.tar.gz": map[string]interface{}{
394 "sha256": "!@#$%",
395 },
396 },
397 ByProducts: map[string]interface{}{
398 "return-value": float64(0),
399 "stderr": "a foo.py\n",
400 "stdout": "",
401 },
402 Environment: map[string]interface{}{},
403 },
404 }
405
406 err = validateLink(testMb.Signed.(Link))
407 if err.Error() != "in products of link 'test_product_hash': in artifact "+
408 "'foo.tar.gz', sha256 hash value: invalid hex string: !@#$%" {
409 t.Error("validateLink error - invalid hashes not detected")
410 }
411 }
412
413 func TestValidateLayout(t *testing.T) {
414 var mb Metablock
415 if err := mb.Load("demo.layout"); err != nil {
416 t.Errorf("Metablock.Load returned '%s'", err)
417 }
418 if err := validateLayout(mb.Signed.(Layout)); err != nil {
419 t.Errorf("layout metadata validation failed, returned '%s'", err)
420 }
421
422 testMb := Metablock{
423 Signed: Layout{
424 Type: "invalid",
425 Expires: "2020-11-18T16:06:36Z",
426 Readme: "some readme text",
427 Steps: []Step{},
428 Inspect: []Inspection{},
429 Keys: map[string]Key{},
430 },
431 }
432
433 err := validateLayout(testMb.Signed.(Layout))
434 if err.Error() != "invalid Type value for layout: should be 'layout'" {
435 t.Error("validateLayout error - invalid type not detected")
436 }
437
438 testMb = Metablock{
439 Signed: Layout{
440 Type: "layout",
441 Expires: "2020-02-31T18:03:43Z",
442 Readme: "some readme text",
443 Steps: []Step{},
444 Inspect: []Inspection{},
445 Keys: map[string]Key{},
446 },
447 }
448
449 err = validateLayout(testMb.Signed.(Layout))
450 if err.Error() != "expiry time parsed incorrectly - date either invalid "+
451 "or of incorrect format" {
452 t.Error("validateLayout error - invalid date not detected")
453 }
454
455 testMb = Metablock{
456 Signed: Layout{
457 Type: "layout",
458 Expires: "2020-02-27T18:03:43Zinvalid",
459 Readme: "some readme text",
460 Steps: []Step{},
461 Inspect: []Inspection{},
462 Keys: map[string]Key{},
463 },
464 }
465
466 err = validateLayout(testMb.Signed.(Layout))
467 if err.Error() != "expiry time parsed incorrectly - date either invalid "+
468 "or of incorrect format" {
469 t.Error("validateLayout error - invalid date not detected")
470 }
471
472 testMb = Metablock{
473 Signed: Layout{
474 Type: "layout",
475 Expires: "2020-02-27T18:03:43Z",
476 Readme: "some readme text",
477 Steps: []Step{
478 {
479 Type: "step",
480 SupplyChainItem: SupplyChainItem{
481 Name: "foo",
482 },
483 },
484 {
485 Type: "step",
486 SupplyChainItem: SupplyChainItem{
487 Name: "foo",
488 },
489 },
490 },
491 Inspect: []Inspection{},
492 Keys: map[string]Key{},
493 },
494 }
495
496 err = validateLayout(testMb.Signed.(Layout))
497 if err.Error() != "non unique step or inspection name found" {
498 t.Error("validateLayout error - duplicate step/inspection name not " +
499 "detected")
500 }
501
502 testMb = Metablock{
503 Signed: Layout{
504 Type: "layout",
505 Expires: "2020-02-27T18:03:43Z",
506 Readme: "some readme text",
507 Steps: []Step{
508 {
509 Type: "step",
510 SupplyChainItem: SupplyChainItem{
511 Name: "foo",
512 },
513 },
514 },
515 Inspect: []Inspection{
516 {
517 Type: "inspection",
518 SupplyChainItem: SupplyChainItem{
519 Name: "foo",
520 },
521 },
522 },
523 Keys: map[string]Key{},
524 },
525 }
526
527 err = validateLayout(testMb.Signed.(Layout))
528 if err.Error() != "non unique step or inspection name found" {
529 t.Error("validateLayout error - duplicate step/inspection name not " +
530 "detected")
531 }
532
533 testMb = Metablock{
534 Signed: Layout{
535 Type: "layout",
536 Expires: "2020-02-27T18:03:43Z",
537 Readme: "some readme text",
538 Steps: []Step{},
539 Inspect: []Inspection{
540 {
541 Type: "inspection",
542 SupplyChainItem: SupplyChainItem{
543 Name: "foo",
544 },
545 },
546 {
547 Type: "inspection",
548 SupplyChainItem: SupplyChainItem{
549 Name: "foo",
550 },
551 },
552 },
553 Keys: map[string]Key{},
554 },
555 }
556
557 err = validateLayout(testMb.Signed.(Layout))
558 if err.Error() != "non unique step or inspection name found" {
559 t.Error("validateLayout error - duplicate step/inspection name not " +
560 "detected")
561 }
562
563 testMb = Metablock{
564 Signed: Layout{
565 Type: "layout",
566 Expires: "2020-02-27T18:03:43Z",
567 Readme: "some readme text",
568 Steps: []Step{
569 {
570 Type: "invalid",
571 SupplyChainItem: SupplyChainItem{
572 Name: "foo",
573 },
574 },
575 },
576 Inspect: []Inspection{},
577 Keys: map[string]Key{},
578 },
579 }
580
581 err = validateLayout(testMb.Signed.(Layout))
582 if err.Error() != "invalid Type value for step 'foo': should be 'step'" {
583 t.Error("validateLayout - validateStep error - invalid step type not " +
584 "detected")
585 }
586
587 cases := map[string]struct {
588 Arg Layout
589 Expected string
590 }{
591 "invalid key map": {
592 Layout{
593 Type: "layout",
594 Expires: "2020-02-27T18:03:43Z",
595 Keys: map[string]Key{
596 "deadbeef": {KeyID: "livebeef"},
597 },
598 },
599 "invalid key found",
600 },
601 "invalid rsa key": {
602 Layout{
603 Type: "layout",
604 Expires: "2020-02-27T18:03:43Z",
605 Keys: map[string]Key{
606 "deadbeef": {KeyID: "deadbeef"},
607 },
608 },
609 "empty field in key: keytype",
610 },
611 }
612
613 for name, tc := range cases {
614 err := validateLayout(tc.Arg)
615 if err == nil || !strings.Contains(err.Error(), tc.Expected) {
616 t.Errorf("%s: '%s' not in '%s'", name, tc.Expected, err)
617 }
618 }
619 }
620
621 func TestValidateStep(t *testing.T) {
622 testStep := Step{
623 Type: "invalid",
624 SupplyChainItem: SupplyChainItem{
625 Name: "foo",
626 },
627 }
628 err := validateStep(testStep)
629 if err.Error() != "invalid Type value for step 'foo': should be 'step'" {
630 t.Error("validateStep error - invalid type not detected")
631 }
632
633 testStep = Step{
634 Type: "step",
635 PubKeys: []string{"776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f4Z" +
636 "41132b345b08453f5"},
637 SupplyChainItem: SupplyChainItem{
638 Name: "foo",
639 },
640 }
641 err = validateStep(testStep)
642 if !errors.Is(err, ErrInvalidHexString) {
643 t.Error("validateStep - validateHexString error - invalid key ID not " +
644 "detected")
645 }
646
647 testStep = Step{
648 Type: "step",
649 SupplyChainItem: SupplyChainItem{
650 Name: "",
651 },
652 }
653 err = validateStep(testStep)
654 if err.Error() != "step name cannot be empty" {
655 t.Error("validateStep error - empty name not detected")
656 }
657 }
658
659 func TestValidateInspection(t *testing.T) {
660 testInspection := Inspection{
661 Type: "invalid",
662 SupplyChainItem: SupplyChainItem{
663 Name: "foo",
664 },
665 }
666 err := validateInspection(testInspection)
667 if err.Error() != "invalid Type value for inspection 'foo': should be "+
668 "'inspection'" {
669 t.Error("validateInspection error - invalid type not detected")
670 }
671 testInspection = Inspection{
672 Type: "inspection",
673 SupplyChainItem: SupplyChainItem{
674 Name: "",
675 },
676 }
677 err = validateInspection(testInspection)
678 if err.Error() != "inspection name cannot be empty" {
679 t.Error("validateInspection error - empty name not detected")
680 }
681
682 testInspection = Inspection{
683 Type: "inspection",
684 SupplyChainItem: SupplyChainItem{
685 Name: "inspect",
686 },
687 }
688 err = validateInspection(testInspection)
689 if err != nil {
690 t.Error("validateInspection should successfully validate an inspection")
691 }
692 }
693
694 func TestValidateHexSchema(t *testing.T) {
695 testStr := "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b" +
696 "08453f5"
697 if err := validateHexString(testStr); err != nil {
698 t.Errorf("validateHexString error - valid key ID flagged")
699 }
700
701 testStr = "Z776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b" +
702 "08453f5"
703 if err := validateHexString(testStr); err == nil {
704 t.Errorf("validateHexString error - invalid key ID not detected")
705 }
706 }
707
708 func TestValidatePubKey(t *testing.T) {
709 testKey := Key{
710 KeyID: "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
711 KeyType: "rsa",
712 KeyVal: KeyVal{
713 Private: "",
714 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAO" +
715 "CAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6" +
716 "SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQ" +
717 "S8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTy" +
718 "ONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK" +
719 "\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLR" +
720 "qzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSb" +
721 "J/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLC" +
722 "fQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARR" +
723 "wU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1g" +
724 "KqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----",
725 },
726 Scheme: "rsassa-pss-sha256",
727 }
728
729 err := validatePublicKey(testKey)
730 if !errors.Is(err, nil) {
731 t.Errorf("error validating public key: %s", err)
732 }
733
734 testKey = Key{
735 KeyID: "Z776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
736 KeyType: "rsa",
737 KeyVal: KeyVal{
738 Private: "",
739 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAO" +
740 "CAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6" +
741 "SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQ" +
742 "S8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTy" +
743 "ONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK" +
744 "\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLR" +
745 "qzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSb" +
746 "J/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLC" +
747 "fQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARR" +
748 "wU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1g" +
749 "KqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----",
750 },
751 Scheme: "rsassa-pss-sha256",
752 }
753
754 err = validateKey(testKey)
755 if !errors.Is(err, ErrInvalidHexString) {
756 t.Error("validateKey error - invalid key ID not detected")
757 }
758
759 testKey = Key{
760 KeyID: "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
761 KeyType: "rsa",
762 KeyVal: KeyVal{
763 Private: "invalid",
764 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAO" +
765 "CAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6" +
766 "SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQ" +
767 "S8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTy" +
768 "ONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK" +
769 "\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLR" +
770 "qzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSb" +
771 "J/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLC" +
772 "fQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARR" +
773 "wU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1g" +
774 "KqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----",
775 },
776 Scheme: "rsassa-pss-sha256",
777 }
778
779 err = validatePublicKey(testKey)
780 if !errors.Is(err, ErrNoPublicKey) {
781 t.Error("validateKey error - private key not detected")
782 }
783
784 testKey = Key{
785 KeyID: "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
786 KeyType: "rsa",
787 KeyVal: KeyVal{
788 Private: "",
789 Public: "",
790 },
791 Scheme: "rsassa-pss-sha256",
792 }
793
794 err = validateKey(testKey)
795 if !errors.Is(err, ErrEmptyKeyField) {
796 t.Error("validateKey error - empty public key not detected")
797 }
798 }
799
800 func TestValidateMetablock(t *testing.T) {
801 testMetablock := Metablock{
802 Signatures: []Signature{
803 {
804 KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
805 "8f3e9cc48b35",
806 Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
807 "33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
808 "9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
809 "51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
810 "e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
811 "78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
812 "4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
813 "58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
814 "d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
815 "2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
816 "ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
817 "48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
818 "a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
819 "bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
820 },
821 },
822 Signed: Layout{
823 Type: "layout",
824 Expires: "2020-11-18T16:06:36Z",
825 Readme: "some readme text",
826 Steps: []Step{},
827 Inspect: []Inspection{},
828 Keys: map[string]Key{},
829 },
830 }
831
832 if err := ValidateMetablock(testMetablock); err != nil {
833 t.Error("ValidateMetablock error: valid metablock failed")
834 }
835
836 testMetablock = Metablock{
837 Signatures: []Signature{
838 {
839 KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
840 "8f3e9cc48b35",
841 Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
842 "33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
843 "9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
844 "51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
845 "e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
846 "78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
847 "4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
848 "58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
849 "d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
850 "2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
851 "ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
852 "48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
853 "a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
854 "bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
855 },
856 },
857 Signed: Link{
858 Type: "link",
859 Name: "test_type",
860 Command: []string{
861 "tar",
862 "zcvf",
863 "foo.tar.gz",
864 "foo.py",
865 },
866 Materials: map[string]interface{}{
867 "foo.py": map[string]interface{}{
868 "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a" +
869 "27c013544a60502549",
870 },
871 },
872 Products: map[string]interface{}{
873 "foo.tar.gz": map[string]interface{}{
874 "sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c" +
875 "1e5aabb7c98514f355",
876 },
877 },
878 ByProducts: map[string]interface{}{
879 "return-value": float64(0),
880 "stderr": "a foo.py\n",
881 "stdout": "",
882 },
883 Environment: map[string]interface{}{},
884 },
885 }
886
887 if err := ValidateMetablock(testMetablock); err != nil {
888 t.Error("ValidateMetablock error: valid metablock failed")
889 }
890
891 testMetablock = Metablock{
892 Signatures: []Signature{
893 {
894 KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
895 "8f3e9cc48b35",
896 Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
897 "33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
898 "9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
899 "51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
900 "e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
901 "78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
902 "4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
903 "58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
904 "d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
905 "2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
906 "ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
907 "48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
908 "a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
909 "bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
910 },
911 },
912 Signed: Layout{
913 Type: "invalid",
914 Expires: "2020-11-18T16:06:36Z",
915 Readme: "some readme text",
916 Steps: []Step{},
917 Inspect: []Inspection{},
918 Keys: map[string]Key{},
919 },
920 }
921
922 if err := ValidateMetablock(testMetablock); err.Error() !=
923 "invalid Type value for layout: should be 'layout'" {
924 t.Error("ValidateMetablock Error: invalid Type not detected")
925 }
926
927 testMetablock = Metablock{
928 Signatures: []Signature{
929 {
930 KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
931 "8f3e9cc48b35",
932 Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
933 "33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
934 "9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
935 "51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
936 "e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
937 "78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
938 "4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
939 "58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
940 "d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
941 "2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
942 "ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
943 "48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
944 "a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
945 "bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
946 },
947 },
948 Signed: Link{
949 Type: "invalid",
950 Name: "test_type",
951 Command: []string{
952 "tar",
953 "zcvf",
954 "foo.tar.gz",
955 "foo.py",
956 },
957 Materials: map[string]interface{}{
958 "foo.py": map[string]interface{}{
959 "sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a" +
960 "27c013544a60502549",
961 },
962 },
963 Products: map[string]interface{}{
964 "foo.tar.gz": map[string]interface{}{
965 "sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c" +
966 "1e5aabb7c98514f355",
967 },
968 },
969 ByProducts: map[string]interface{}{
970 "return-value": float64(0),
971 "stderr": "a foo.py\n",
972 "stdout": "",
973 },
974 Environment: map[string]interface{}{},
975 },
976 }
977
978 if err := ValidateMetablock(testMetablock); err.Error() !=
979 "invalid type for link 'test_type': should be 'link'" {
980 t.Error("ValidateMetablock Error: invalid Type not detected")
981 }
982
983 testMetablock = Metablock{
984 Signatures: []Signature{
985 {
986 KeyID: "Z556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b5" +
987 "8f3e9cc48b35",
988 Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
989 "33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
990 "9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
991 "51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
992 "e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
993 "78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
994 "4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
995 "58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
996 "d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
997 "2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
998 "ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
999 "48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
1000 "a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
1001 "bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
1002 },
1003 },
1004 Signed: Layout{
1005 Type: "layout",
1006 Expires: "2020-11-18T16:06:36Z",
1007 Readme: "some readme text",
1008 Steps: []Step{},
1009 Inspect: []Inspection{},
1010 Keys: map[string]Key{},
1011 },
1012 }
1013
1014 err := ValidateMetablock(testMetablock)
1015 if !errors.Is(err, ErrInvalidHexString) {
1016 t.Error("ValidateMetablock Error: invalid key ID not detected")
1017 }
1018
1019 testMetablock = Metablock{
1020 Signatures: []Signature{
1021 {
1022 KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
1023 "8f3e9cc48b35",
1024 Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9z" +
1025 "33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
1026 "9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
1027 "51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
1028 "e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
1029 "78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
1030 "4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
1031 "58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
1032 "d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
1033 "2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
1034 "ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
1035 "48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
1036 "a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
1037 "bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
1038 },
1039 },
1040 Signed: Layout{
1041 Type: "layout",
1042 Expires: "2020-11-18T16:06:36Z",
1043 Readme: "some readme text",
1044 Steps: []Step{},
1045 Inspect: []Inspection{},
1046 Keys: map[string]Key{},
1047 },
1048 }
1049
1050 err = ValidateMetablock(testMetablock)
1051 if !errors.Is(err, ErrInvalidHexString) {
1052 t.Error("ValidateMetablock error: invalid signature not detected")
1053 }
1054
1055 cases := map[string]struct {
1056 Arg Metablock
1057 Expected string
1058 }{
1059 "invalid type": {
1060 Metablock{Signed: "invalid"},
1061 "unknown type 'invalid', should be 'layout' or 'link'",
1062 },
1063 }
1064 for name, tc := range cases {
1065 err := ValidateMetablock(tc.Arg)
1066 if err == nil || !strings.Contains(err.Error(), tc.Expected) {
1067 t.Errorf("%s: '%s' not in '%s'", name, tc.Expected, err)
1068 }
1069 }
1070 }
1071
1072 func TestValidateSupplyChainItem(t *testing.T) {
1073 cases := map[string]struct {
1074 Arg SupplyChainItem
1075 Expected string
1076 }{
1077 "empty name": {SupplyChainItem{Name: ""}, "name cannot be empty"},
1078 "material rule": {
1079 SupplyChainItem{
1080 Name: "test",
1081 ExpectedMaterials: [][]string{{"invalid"}}},
1082 "invalid material rule"},
1083 "product rule": {
1084 SupplyChainItem{
1085 Name: "test",
1086 ExpectedProducts: [][]string{{"invalid"}}},
1087 "invalid product rule"},
1088 }
1089
1090 for name, tc := range cases {
1091 err := validateSupplyChainItem(tc.Arg)
1092 if err == nil || !strings.Contains(err.Error(), tc.Expected) {
1093 t.Errorf("%s: '%s' not in '%s'", name, tc.Expected, err)
1094 }
1095 }
1096 }
1097
1098 func TestMetablockSignWithRSA(t *testing.T) {
1099 var mb Metablock
1100 if err := mb.Load("demo.layout"); err != nil {
1101 t.Errorf("cannot parse template file: %s", err)
1102 }
1103 invalidKey := Key{
1104 KeyID: "test",
1105 KeyIDHashAlgorithms: nil,
1106 KeyType: "rsa",
1107 KeyVal: KeyVal{},
1108 Scheme: "rsassa-pss-sha256",
1109 }
1110
1111 if err := mb.Sign(invalidKey); err == nil {
1112 t.Errorf("signing with an invalid RSA key should fail")
1113 }
1114 }
1115
1116 func TestMetablockSignWithEd25519(t *testing.T) {
1117 var mb Metablock
1118 if err := mb.Load("demo.layout"); err != nil {
1119 t.Errorf("cannot parse template file: %s", err)
1120 }
1121 invalidKey := Key{
1122 KeyID: "invalid",
1123 KeyIDHashAlgorithms: nil,
1124 KeyType: "ed25519",
1125 KeyVal: KeyVal{
1126 Private: "BAD",
1127 Public: "BAD",
1128 },
1129 Scheme: "ed25519",
1130 }
1131
1132 if err := mb.Sign(invalidKey); err == nil {
1133 t.Errorf("signing with an invalid ed25519 key should fail")
1134 }
1135 }
1136
1137 func TestMetaBlockSignWithEcdsa(t *testing.T) {
1138 var mb Metablock
1139 if err := mb.Load("demo.layout"); err != nil {
1140 t.Errorf("cannot parse template file: %s", err)
1141 }
1142 invalidKey := Key{
1143 KeyID: "invalid",
1144 KeyIDHashAlgorithms: nil,
1145 KeyType: "ecdsa",
1146 KeyVal: KeyVal{
1147 Private: "BAD",
1148 Public: "BAD",
1149 },
1150 Scheme: "ecdsa",
1151 }
1152 if err := mb.Sign(invalidKey); err == nil {
1153 t.Errorf("signing with an invalid ecdsa key should fail")
1154 }
1155 }
1156
1157 func TestValidateKeyErrors(t *testing.T) {
1158 invalidTables := []struct {
1159 name string
1160 key Key
1161 err error
1162 }{
1163 {"empty key", Key{
1164 KeyID: "",
1165 KeyIDHashAlgorithms: nil,
1166 KeyType: "",
1167 KeyVal: KeyVal{},
1168 Scheme: "",
1169 }, ErrInvalidHexString},
1170 {"keytype missing", Key{
1171 KeyID: "bad",
1172 KeyIDHashAlgorithms: []string{"sha256"},
1173 KeyType: "",
1174 KeyVal: KeyVal{
1175 Private: "",
1176 Public: "",
1177 },
1178 Scheme: "rsassa-psa-sha256",
1179 }, ErrEmptyKeyField},
1180 {"key scheme missing", Key{
1181 KeyID: "bad",
1182 KeyIDHashAlgorithms: []string{"sha256"},
1183 KeyType: "ed25519",
1184 KeyVal: KeyVal{
1185 Private: "bad",
1186 Public: "bad",
1187 },
1188 Scheme: "",
1189 }, ErrEmptyKeyField},
1190 {
1191 name: "invalid key type",
1192 key: Key{
1193 KeyID: "bad",
1194 KeyIDHashAlgorithms: []string{"sha256"},
1195 KeyType: "invalid",
1196 KeyVal: KeyVal{
1197 Private: "invalid",
1198 Public: "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
1199 },
1200 Scheme: "ed25519",
1201 },
1202 err: ErrUnsupportedKeyType,
1203 },
1204 {
1205 name: "keytype scheme mismatch",
1206 key: Key{
1207 KeyID: "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
1208 KeyIDHashAlgorithms: []string{"sha256"},
1209 KeyType: "ed25519",
1210 KeyVal: KeyVal{
1211 Private: "29ad59693fe94c9d623afbb66554b4f6bb248c47761689ada4875ebda94840ae393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
1212 Public: "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
1213 },
1214 Scheme: "rsassa-pss-sha256",
1215 },
1216 err: ErrSchemeKeyTypeMismatch,
1217 },
1218 {
1219 name: "unsupported KeyIDHashAlgorithms",
1220 key: Key{
1221 KeyID: "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
1222 KeyIDHashAlgorithms: []string{"sha128"},
1223 KeyType: "ed25519",
1224 KeyVal: KeyVal{
1225 Private: "29ad59693fe94c9d623afbb66554b4f6bb248c47761689ada4875ebda94840ae393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
1226 Public: "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
1227 },
1228 Scheme: "ed25519",
1229 },
1230 err: ErrUnsupportedKeyIDHashAlgorithms,
1231 },
1232 }
1233
1234 for _, table := range invalidTables {
1235 err := validateKey(table.key)
1236 if !errors.Is(err, table.err) {
1237 t.Errorf("test '%s' failed, expected error: '%s', got '%s'", table.name, table.err, err)
1238 }
1239 }
1240 }
1241
1242 func TestValidateKeyVal(t *testing.T) {
1243 tables := []struct {
1244 name string
1245 key Key
1246 err error
1247 }{
1248 {
1249 name: "invalid rsa private key",
1250 key: Key{
1251 KeyID: "bad",
1252 KeyIDHashAlgorithms: []string{"sha256"},
1253 KeyType: "rsa",
1254 KeyVal: KeyVal{
1255 Private: "invalid",
1256 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxPX3kFs/z645x4UOC3KF\nY3V80YQtKrp6YS3qU+Jlvx/XzK53lb4sCDRU9jqBBx3We45TmFUibroMd8tQXCUS\ne8gYCBUBqBmmz0dEHJYbW0tYF7IoapMIxhRYn76YqNdl1JoRTcmzIaOJ7QrHxQrS\nGpivvTm6kQ9WLeApG1GLYJ3C3Wl4bnsI1bKSv55Zi45/JawHzTzYUAIXX9qCd3Io\nHzDucz9IAj9Ookw0va/q9FjoPGrRB80IReVxLVnbo6pYJfu/O37jvEobHFa8ckHd\nYxUIg8wvkIOy1O3M74lBDm6CVI0ZO25xPlDB/4nHAE1PbA3aF3lw8JGuxLDsetxm\nfzgAleVt4vXLQiCrZaLf+0cM97JcT7wdHcbIvRLsij9LNP+2tWZgeZ/hIAOEdaDq\ncYANPDIAxfTvbe9I0sXrCtrLer1SS7GqUmdFCdkdun8erXdNF0ls9Rp4cbYhjdf3\nyMxdI/24LUOOQ71cHW3ITIDImm6I8KmrXFM2NewTARKfAgMBAAE=\n-----END PUBLIC KEY-----",
1257 },
1258 Scheme: "rsassa-pss-sha256",
1259 },
1260 err: ErrNoPEMBlock,
1261 },
1262 {
1263 name: "invalid rsa pub key",
1264 key: Key{
1265 KeyID: "bad",
1266 KeyIDHashAlgorithms: []string{"sha256"},
1267 KeyType: "rsa",
1268 KeyVal: KeyVal{
1269 Private: "",
1270 Public: "invalid",
1271 },
1272 Scheme: "rsassa-pss-sha256",
1273 },
1274 err: ErrNoPEMBlock,
1275 },
1276 {
1277 name: "invalid ed25519 public key",
1278 key: Key{
1279 KeyID: "bad",
1280 KeyIDHashAlgorithms: []string{"sha256"},
1281 KeyType: "ed25519",
1282 KeyVal: KeyVal{
1283 Private: "invalid",
1284 Public: "invalid",
1285 },
1286 Scheme: "ed25519",
1287 },
1288 err: ErrInvalidHexString,
1289 },
1290 {
1291 name: "invalid ed25519 private key",
1292 key: Key{
1293 KeyID: "bad",
1294 KeyIDHashAlgorithms: []string{"sha256"},
1295 KeyType: "ed25519",
1296 KeyVal: KeyVal{
1297 Private: "invalid",
1298 Public: "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
1299 },
1300 Scheme: "ed25519",
1301 },
1302 err: ErrInvalidHexString,
1303 },
1304 {
1305 name: "valid rsa public, but bad private key",
1306 key: Key{
1307 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1308 KeyIDHashAlgorithms: []string{"sha256"},
1309 KeyType: "rsa",
1310 KeyVal: KeyVal{
1311 Private: "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB6fQnV71xKx6kFgJv\nYTMq0ytvWi2mDlYu6aNm1761c1OSInbBxBNb0ligpM65KyaeeRce6JR9eQW6TB6R\n+5pNzvOhgYkDgYYABAFy0CeDAyV/2mY1NqxLLgqEXSxaqM3fM8gYn/ZWzrLnO+1h\nK2QAanID3JuPff1NdhehhL/U1prXdyyaItA5X4ChkQHMTsiS/3HkWRuLR8L22SGs\nB+7KqOeO5ELkqHO5tsy4kvsNrmersCGRQGY6A5V/0JFhP1u1JUvAVVhfRbdQXuu3\nrw==\n-----END PRIVATE KEY-----\n",
1312 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCTik98953hKl6+B6n5l\n8DVIDwDnvrJfpasbJ3+Rw66YcawOZinRpMxPTqWBKs7sRop7jqsQNcslUoIZLrXP\nr3foPHF455TlrqPVfCZiFQ+O4CafxWOB4mL1NddvpFXTEjmUiwFrrL7PcvQKMbYz\neUHH4tH9MNzqKWbbJoekBsDpCDIxp1NbgivGBKwjRGa281sClKgpd0Q0ebl+RTcT\nvpfZVDbXazQ7VqZkidt7geWq2BidOXZp/cjoXyVneKx/gYiOUv8x94svQMzSEhw2\nLFMQ04A1KnGn1jxO35/fd6/OW32njyWs96RKu9UQVacYHsQfsACPWwmVqgnX/sp5\nujlvSDjyfZu7c5yUQ2asYfQPLvnjG+u7QcBukGf8hAfVgsezzX9QPiK35BKDgBU/\nVk43riJs165TJGYGVuLUhIEhHgiQtwo8pUTJS5npEe5XMDuZoighNdzoWY2nfsBf\np8348k6vJtDMB093/t6V9sTGYQcSbgKPyEQo5Pk6Wd4ZAgMBAAE=\n-----END PUBLIC KEY-----",
1313 },
1314 Scheme: "rsassa-pss-sha256",
1315 },
1316 err: ErrKeyKeyTypeMismatch,
1317 },
1318 {
1319 name: "valid ecdsa public key, but invalid ecdsa private key",
1320 key: Key{
1321 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1322 KeyIDHashAlgorithms: []string{"sha256"},
1323 KeyType: "ecdsa",
1324 KeyVal: KeyVal{
1325 Private: "-----BEGIN RSA PRIVATE KEY-----\nMIIG5QIBAAKCAYEAyCTik98953hKl6+B6n5l8DVIDwDnvrJfpasbJ3+Rw66YcawO\nZinRpMxPTqWBKs7sRop7jqsQNcslUoIZLrXPr3foPHF455TlrqPVfCZiFQ+O4Caf\nxWOB4mL1NddvpFXTEjmUiwFrrL7PcvQKMbYzeUHH4tH9MNzqKWbbJoekBsDpCDIx\np1NbgivGBKwjRGa281sClKgpd0Q0ebl+RTcTvpfZVDbXazQ7VqZkidt7geWq2Bid\nOXZp/cjoXyVneKx/gYiOUv8x94svQMzSEhw2LFMQ04A1KnGn1jxO35/fd6/OW32n\njyWs96RKu9UQVacYHsQfsACPWwmVqgnX/sp5ujlvSDjyfZu7c5yUQ2asYfQPLvnj\nG+u7QcBukGf8hAfVgsezzX9QPiK35BKDgBU/Vk43riJs165TJGYGVuLUhIEhHgiQ\ntwo8pUTJS5npEe5XMDuZoighNdzoWY2nfsBfp8348k6vJtDMB093/t6V9sTGYQcS\nbgKPyEQo5Pk6Wd4ZAgMBAAECggGBAIb8YZiMA2tfNSfy5jNqhoQo223LFYIHOf05\nVvofzwbkdcqM2bVL1SpJ5d9MPr7Jio/VDJpfg3JUjdqFBkj7tJRK0eYaPgoq4XIU\n64JtPM+pi5pgUnfFsi8mwO1MXO7AN7hd/3J1RdLfanjEYS/ADB1nIVI4gIR5KrE7\nvujQqO8pIsI1YEnTLa+wqEA0fSDACfo90pLCjBz1clL6qVAzYmy0a46h4k5ajv7V\nAI/96OHmLYDLsRa1Z60T2K17Q7se0zmHSjfssLQ+d+0zdU5BK8wFn1n2DvCc310T\na0ip+V+YNT0FBtmknTobnr9S688bR8vfBK0q0JsZ1YataGyYS0Rp0RYeEInjKie8\nDIzGuYNRzEjrYMlIOCCY5ybo9mbRiQEQvlSunFAAoKyr8svwU8/e2HV4lXxqDY9v\nKZzxeNYVvX2ZUP3D/uz74VvUWe5fz+ZYmmHVW0erbQC8Cxv2Q6SG/eylcfiNDdLG\narf+HNxcvlJ3v7I2w79tqSbHPcJc1QKBwQD6E/zRYiuJCd0ydnJXPCzZ3dhs/Nz0\ny9QJXg7QyLuHPGEV6r2nIK/Ku3d0NHi/hWglCrg2m8ik7BKaIUjvwVI7M/E3gcZu\ngknmlWjt5QY+LLfQdVgBeqwJdqLHXtw2GAJch6LGSxIcZ5F+1MmqUbfElUJ4h/To\nno6CFGfmAc2n6+PSMWxHT6Oe/rrAFQ2B25Kl9kIrfAUeWhtLm+n0ARXo7wKr63rg\nyJBXwr5Rl3U1NJGnuagQqcS7zDdZ2Glaj1cCgcEAzOIwl5Z0I42vU+2z9e+23Tyc\nHnSyp7AaHLJeuv92T8j7sF8qV1brYQqqzUAGpIGR6OZ9Vj2niPdbtdAQpgcTav+9\nBY9Nyk6YDgsTuN+bQEWsM8VfMUFVUXQAdNFJT6VPO877Fi0PnWhqxVVzr7GuUJFM\nzTUSscsqT40Ht2v1v+qYM4EziPUtUlxUbfuc0RwtfbSpALJG+rpPjvdddQ4Xsdj0\nEIoq1r/0v+vo0Dbpdy63N0iYh9r9yHioiUdCPUgPAoHBAJhKL7260NRFQ4UFiKAD\nLzUF2lSUsGIK9nc15kPS2hCC/oSATTpHt4X4H8iOY7IOJdvY6VGoEMoOUU23U1le\nGxueiBjLWPHXOfXHqvykaebXCKFTtGJCOB4TNxG+fNAcUuPSXZfwA3l0wK/CGYU0\n+nomgzIvaT93v0UL9DGni3vlNPm9yziqEPQ0H7n1mCIqeuXCT413mw5exRyIODK1\nrogJdVEIt+3Hdc9b8tZxK5lZCBJiBy0OlZXfyR1XouDZRQKBwC1++N1gio+ukcVo\nXnL5dTjxkZVtwpJcF6BRt5l8yu/yqHlE2KkmYwRckwsa8Z6sKxN1w1VYQZC3pQTd\nnCTSI2y6N2Y5qUOIalmL+igud1IxZojkhjvwzxpUURmfs9Dc25hjYPxOq03/9t21\nGQhlw1ieu1hCNdGHVPDvV0xSy/J/DKc7RI9gKl1EpXb6zZrdz/g/GtxNuldI8gvE\nQFuS8o4KqD/X/qVLYPURVNSPrQ5LMGI1W7GnXn2a1YoOadYj3wKBwQCh+crvbhDr\njb2ud3CJfdCs5sS5SEKADiUcxiJPcypxhmu+7vhG1Nr6mT0SAYWaA36GDJkU7/Oo\nvoal+uigbOt/UugS1nQYnEzDRkTidQMm1gXVNcWRTBFTKwRP/Gd6yOp9BUHJlFCu\nM2q8HYFtmSqOele6xFOAUnHhwVx4QURJYa+S5A603Jm6ETv0+Y6xdHX/02vA+pRt\nlQqaoEO7ScdRrzjgvVxXkEY3nwLcWdM61/RZTL0+be8goDw5cWt+PaA=\n-----END RSA PRIVATE KEY-----",
1326 Public: "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBctAngwMlf9pmNTasSy4KhF0sWqjN\n3zPIGJ/2Vs6y5zvtYStkAGpyA9ybj339TXYXoYS/1Naa13csmiLQOV+AoZEBzE7I\nkv9x5Fkbi0fC9tkhrAfuyqjnjuRC5KhzubbMuJL7Da5nq7AhkUBmOgOVf9CRYT9b\ntSVLwFVYX0W3UF7rt68=\n-----END PUBLIC KEY-----\n",
1327 },
1328 Scheme: "ecdsa",
1329 },
1330 err: ErrKeyKeyTypeMismatch,
1331 },
1332 {
1333 name: "rsa key, but with ed25519 private key",
1334 key: Key{
1335 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1336 KeyIDHashAlgorithms: []string{"sha256"},
1337 KeyType: "rsa",
1338 KeyVal: KeyVal{
1339 Private: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICmtWWk/6UydYjr7tmVUtPa7JIxHdhaJraSHXr2pSECu\n-----END PRIVATE KEY-----\n",
1340 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCTik98953hKl6+B6n5l\n8DVIDwDnvrJfpasbJ3+Rw66YcawOZinRpMxPTqWBKs7sRop7jqsQNcslUoIZLrXP\nr3foPHF455TlrqPVfCZiFQ+O4CafxWOB4mL1NddvpFXTEjmUiwFrrL7PcvQKMbYz\neUHH4tH9MNzqKWbbJoekBsDpCDIxp1NbgivGBKwjRGa281sClKgpd0Q0ebl+RTcT\nvpfZVDbXazQ7VqZkidt7geWq2BidOXZp/cjoXyVneKx/gYiOUv8x94svQMzSEhw2\nLFMQ04A1KnGn1jxO35/fd6/OW32njyWs96RKu9UQVacYHsQfsACPWwmVqgnX/sp5\nujlvSDjyfZu7c5yUQ2asYfQPLvnjG+u7QcBukGf8hAfVgsezzX9QPiK35BKDgBU/\nVk43riJs165TJGYGVuLUhIEhHgiQtwo8pUTJS5npEe5XMDuZoighNdzoWY2nfsBf\np8348k6vJtDMB093/t6V9sTGYQcSbgKPyEQo5Pk6Wd4ZAgMBAAE=\n-----END PUBLIC KEY-----",
1341 },
1342 Scheme: "rsassa-pss-sha256",
1343 },
1344 err: ErrInvalidKey,
1345 },
1346 {
1347 name: "unsupported key type",
1348 key: Key{
1349 KeyID: "",
1350 KeyIDHashAlgorithms: nil,
1351 KeyType: "invalid",
1352 KeyVal: KeyVal{},
1353 Scheme: "",
1354 },
1355 err: ErrUnsupportedKeyType,
1356 },
1357 {
1358 name: "rsa key type, but ed25519 key",
1359 key: Key{
1360 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1361 KeyIDHashAlgorithms: []string{"sha256"},
1362 KeyType: "rsa",
1363 KeyVal: KeyVal{
1364 Private: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICmtWWk/6UydYjr7tmVUtPa7JIxHdhaJraSHXr2pSECu\n-----END PRIVATE KEY-----\n",
1365 Public: "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAOT5nGyAPlkxJCD00qGf12YnsHGnfe2Z1j+RxyFkbE5w=\n-----END PUBLIC KEY-----\n",
1366 },
1367 Scheme: "rsassa-pss-sha256",
1368 },
1369 err: ErrInvalidKey,
1370 },
1371 {
1372 name: "rsa key, but not ecdsa key type",
1373 key: Key{
1374 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1375 KeyIDHashAlgorithms: []string{"sha256"},
1376 KeyType: "ecdsa",
1377 KeyVal: KeyVal{
1378 Private: "",
1379 Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAyCTik98953hKl6+B6n5l\n8DVIDwDnvrJfpasbJ3+Rw66YcawOZinRpMxPTqWBKs7sRop7jqsQNcslUoIZLrXP\nr3foPHF455TlrqPVfCZiFQ+O4CafxWOB4mL1NddvpFXTEjmUiwFrrL7PcvQKMbYz\neUHH4tH9MNzqKWbbJoekBsDpCDIxp1NbgivGBKwjRGa281sClKgpd0Q0ebl+RTcT\nvpfZVDbXazQ7VqZkidt7geWq2BidOXZp/cjoXyVneKx/gYiOUv8x94svQMzSEhw2\nLFMQ04A1KnGn1jxO35/fd6/OW32njyWs96RKu9UQVacYHsQfsACPWwmVqgnX/sp5\nujlvSDjyfZu7c5yUQ2asYfQPLvnjG+u7QcBukGf8hAfVgsezzX9QPiK35BKDgBU/\nVk43riJs165TJGYGVuLUhIEhHgiQtwo8pUTJS5npEe5XMDuZoighNdzoWY2nfsBf\np8348k6vJtDMB093/t6V9sTGYQcSbgKPyEQo5Pk6Wd4ZAgMBAAE=\n-----END PUBLIC KEY-----",
1380 },
1381 Scheme: "ecdsa",
1382 },
1383 err: ErrKeyKeyTypeMismatch,
1384 },
1385 {
1386 name: "ecdsa key, but rsa key type",
1387 key: Key{
1388 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1389 KeyIDHashAlgorithms: []string{"sha256"},
1390 KeyType: "rsa",
1391 KeyVal: KeyVal{
1392 Private: "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB6fQnV71xKx6kFgJv\nYTMq0ytvWi2mDlYu6aNm1761c1OSInbBxBNb0ligpM65KyaeeRce6JR9eQW6TB6R\n+5pNzvOhgYkDgYYABAFy0CeDAyV/2mY1NqxLLgqEXSxaqM3fM8gYn/ZWzrLnO+1h\nK2QAanID3JuPff1NdhehhL/U1prXdyyaItA5X4ChkQHMTsiS/3HkWRuLR8L22SGs\nB+7KqOeO5ELkqHO5tsy4kvsNrmersCGRQGY6A5V/0JFhP1u1JUvAVVhfRbdQXuu3\nrw==\n-----END PRIVATE KEY-----\n",
1393 Public: "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBctAngwMlf9pmNTasSy4KhF0sWqjN\n3zPIGJ/2Vs6y5zvtYStkAGpyA9ybj339TXYXoYS/1Naa13csmiLQOV+AoZEBzE7I\nkv9x5Fkbi0fC9tkhrAfuyqjnjuRC5KhzubbMuJL7Da5nq7AhkUBmOgOVf9CRYT9b\ntSVLwFVYX0W3UF7rt68=\n-----END PUBLIC KEY-----\n",
1394 },
1395 Scheme: "rsassa-pss-sha256",
1396 },
1397 err: ErrKeyKeyTypeMismatch,
1398 },
1399 {
1400 name: "ecdsa key, but rsa key type",
1401 key: Key{
1402 KeyID: "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
1403 KeyIDHashAlgorithms: []string{"sha256"},
1404 KeyType: "ecdsa",
1405 KeyVal: KeyVal{
1406 Private: "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB6fQnV71xKx6kFgJv\nYTMq0ytvWi2mDlYu6aNm1761c1OSInbBxBNb0ligpM65KyaeeRce6JR9eQW6TB6R\n+5pNzvOhgYkDgYYABAFy0CeDAyV/2mY1NqxLLgqEXSxaqM3fM8gYn/ZWzrLnO+1h\nK2QAanID3JuPff1NdhehhL/U1prXdyyaItA5X4ChkQHMTsiS/3HkWRuLR8L22SGs\nB+7KqOeO5ELkqHO5tsy4kvsNrmersCGRQGY6A5V/0JFhP1u1JUvAVVhfRbdQXuu3\nrw==\n-----END PRIVATE KEY-----\n",
1407 Public: "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBctAngwMlf9pmNTasSy4KhF0sWqjN\n3zPIGJ/2Vs6y5zvtYStkAGpyA9ybj339TXYXoYS/1Naa13csmiLQOV+AoZEBzE7I\nkv9x5Fkbi0fC9tkhrAfuyqjnjuRC5KhzubbMuJL7Da5nq7AhkUBmOgOVf9CRYT9b\ntSVLwFVYX0W3UF7rt68=\n-----END PUBLIC KEY-----\n",
1408 },
1409 Scheme: "ecdsa",
1410 },
1411 err: nil,
1412 },
1413 }
1414 for _, table := range tables {
1415 err := validateKeyVal(table.key)
1416 if !errors.Is(err, table.err) {
1417 t.Errorf("test '%s' failed, expected error: '%s', got '%s'", table.name, table.err, err)
1418 }
1419 }
1420 }
1421
1422 func TestMatchKeyTypeScheme(t *testing.T) {
1423 tables := []struct {
1424 name string
1425 key Key
1426 err error
1427 }{
1428 {name: "test for unsupported key type",
1429 key: Key{
1430 KeyID: "",
1431 KeyIDHashAlgorithms: nil,
1432 KeyType: "invalid",
1433 KeyVal: KeyVal{},
1434 Scheme: "",
1435 },
1436 err: ErrUnsupportedKeyType,
1437 },
1438 {
1439 name: "test for scheme key type mismatch",
1440 key: Key{
1441 KeyID: "",
1442 KeyIDHashAlgorithms: nil,
1443 KeyType: "rsa",
1444 KeyVal: KeyVal{},
1445 Scheme: "ed25519",
1446 },
1447 err: ErrSchemeKeyTypeMismatch,
1448 },
1449 }
1450 for _, table := range tables {
1451 err := matchKeyTypeScheme(table.key)
1452 if !errors.Is(err, table.err) {
1453 t.Errorf("%s returned wrong error. We got: %s, we should have got: %s", table.name, err, table.err)
1454 }
1455 }
1456 }
1457
1458 func TestValidatePublicKey(t *testing.T) {
1459 validTables := []struct {
1460 name string
1461 key Key
1462 }{
1463 {
1464 name: "test with valid key",
1465 key: Key{
1466 KeyID: "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
1467 KeyIDHashAlgorithms: []string{"sha512"},
1468 KeyType: "ed25519",
1469 KeyVal: KeyVal{
1470 Private: "",
1471 Public: "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAOT5nGyAPlkxJCD00qGf12YnsHGnfe2Z1j+RxyFkbE5w=\n-----END PUBLIC KEY-----\n",
1472 },
1473 Scheme: "ed25519",
1474 },
1475 },
1476 }
1477 for _, table := range validTables {
1478 err := validatePublicKey(table.key)
1479 if err != nil {
1480 t.Errorf("%s returned error %s, instead of nil", table.name, err)
1481 }
1482 }
1483
1484 invalidTables := []struct {
1485 name string
1486 key Key
1487 err error
1488 }{
1489 {
1490 name: "test with valid key",
1491 key: Key{
1492 KeyID: "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
1493 KeyIDHashAlgorithms: []string{"sha512"},
1494 KeyType: "ed25519",
1495 KeyVal: KeyVal{
1496 Private: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICmtWWk/6UydYjr7tmVUtPa7JIxHdhaJraSHXr2pSECu\n-----END PRIVATE KEY-----\n",
1497 Public: "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAOT5nGyAPlkxJCD00qGf12YnsHGnfe2Z1j+RxyFkbE5w=\n-----END PUBLIC KEY-----\n",
1498 },
1499 Scheme: "ed25519",
1500 },
1501 err: ErrNoPublicKey,
1502 },
1503 }
1504 for _, table := range invalidTables {
1505 err := validatePublicKey(table.key)
1506 if err != table.err {
1507 t.Errorf("%s returned unexpected error %s, we should got: %s", table.name, err, table.err)
1508 }
1509 }
1510 }
1511
1512 func TestSignatureGetCertificate(t *testing.T) {
1513 sig := Signature{}
1514 _, err := sig.GetCertificate()
1515 assert.NotNil(t, err, "expected empty signature error")
1516
1517 certTemplate := &x509.Certificate{
1518 Subject: pkix.Name{
1519 CommonName: "step1.example.com",
1520 Organization: []string{"example"},
1521 },
1522 }
1523
1524 cert, _, _, err := createTestCert(certTemplate, x509.Ed25519, time.Hour)
1525 assert.Nil(t, err, "unexpected error when creating test certificate")
1526 sig.Certificate = string(generatePEMBlock(cert.Raw, "CERTIFICATE"))
1527 _, err = sig.GetCertificate()
1528 assert.Nil(t, err, "unexpected error getting certificate from signature")
1529 }
1530
1531 func TestStepCheckCertConstraints(t *testing.T) {
1532 step := Step{}
1533 key := Key{}
1534 rootPool := x509.NewCertPool()
1535 intermediatePool := x509.NewCertPool()
1536
1537 err := step.CheckCertConstraints(key, []string{}, rootPool, intermediatePool)
1538 assert.NotNil(t, err, "expected error")
1539
1540 certTemplate := &x509.Certificate{
1541 Subject: pkix.Name{
1542 CommonName: "step1.example.com",
1543 Organization: []string{"example"},
1544 },
1545 }
1546
1547 leaf, intermediate, root, err := createTestCert(certTemplate, x509.Ed25519, time.Hour)
1548 assert.Nil(t, err, "unexpected error creating test certificates")
1549 rootPool.AddCert(root)
1550 intermediatePool.AddCert(intermediate)
1551 step.CertificateConstraints = []CertificateConstraint{
1552 {
1553 CommonName: certTemplate.Subject.CommonName,
1554 Organizations: certTemplate.Subject.Organization,
1555 Emails: certTemplate.EmailAddresses,
1556 DNSNames: certTemplate.DNSNames,
1557 URIs: []string{},
1558 Roots: []string{"*"},
1559 },
1560 }
1561
1562 err = key.LoadKeyReaderDefaults(bytes.NewReader(generatePEMBlock(leaf.Raw, "CERTIFICATE")))
1563 rootCAIDs := []string{key.KeyID}
1564 assert.Nil(t, err, "unexpected error when loading Key")
1565
1566
1567 err = step.CheckCertConstraints(Key{}, rootCAIDs, rootPool, intermediatePool)
1568 assert.NotNil(t, err, "expected error when using key with no certificate")
1569
1570
1571 err = step.CheckCertConstraints(key, rootCAIDs, rootPool, intermediatePool)
1572 assert.Nil(t, err, "unexpected error when checking constraints")
1573
1574
1575 step.CertificateConstraints[0].CommonName = "bad common name"
1576 err = step.CheckCertConstraints(key, rootCAIDs, rootPool, intermediatePool)
1577 assert.NotNil(t, err, "expected error when checking constraint without match")
1578 }
1579
1580 func TestRootCAIDs(t *testing.T) {
1581 layout := Layout{
1582 RootCas: map[string]Key{
1583 "123123": {},
1584 "456456": {},
1585 },
1586 }
1587
1588 expectedCAIDs := []string{"123123", "456456"}
1589 rootCAIDs := layout.RootCAIDs()
1590 assert.ElementsMatch(t, expectedCAIDs, rootCAIDs, "expected root ca ids don't match")
1591 }
1592
1593 func TestLoadMetadata(t *testing.T) {
1594
1595
1596
1597
1598
1599
1600
1601
1602 invalidJSONBytes := [][]byte{
1603 []byte("{"),
1604 []byte("{}"),
1605 []byte(`{"signatures": null, "signed": {}}`),
1606 []byte(`{"signatures": "string", "signed": {}}`),
1607 []byte(`{"signatures": [], "signed": []}`),
1608 []byte(`{"signatures": [], "signed": {"_type": "something else"}}`),
1609 []byte(`{"signatures": [], "signed": {"_type": "link",
1610 "materials": "invalid", "name": "some name", "products": "invalid",
1611 "byproducts": "invalid", "command": "some command",
1612 "environment": "some list"}}`),
1613 []byte(`{"signatures": [], "signed": {"_type": "layout",
1614 "steps": "invalid", "inspect": "invalid", "readme": "some readme",
1615 "keys": "some keys", "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
1616 []byte(`{"signatures": [], "signed": {"_type": "layout",
1617 "inspect": "invalid", "readme": "some readme", "keys": "some keys",
1618 "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
1619 []byte(`{"signatures": [], "signed": {"_type": "layout",
1620 "steps": "invalid", "readme": "some readme", "keys": "some keys",
1621 "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
1622 []byte(`{"signatures": [], "signed": {"_type": "layout",
1623 "steps": "invalid", "inspect": "invalid", "readme": "some readme",
1624 "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
1625 []byte(`{"signatures": [], "signed": {"_type": "layout",
1626 "steps": "invalid", "inspect": "invalid", "readme": "some readme",
1627 "keys": "some keys", "rootcas": [], "intermediatecas": []}}`),
1628 []byte(`{"signatures": [], "signed": {"_type": "layout",
1629 "steps": "invalid", "inspect": "invalid",
1630 "keys": "some keys", "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
1631 []byte(`{"signatures": [], "signed": {"_type": "layout", "steps": [],
1632 "inspect": [], "readme": "some readme", "keys": {},
1633 "expires": "some date", "foo": "bar", "rootcas": [], "intermediatecas": []}}`),
1634 []byte(`{"signatures": [], "signed": {"_type": "link",
1635 "materials": "invalid", "products": "invalid",
1636 "byproducts": "invalid", "command": "some command",
1637 "environment": "some list"}}`),
1638 []byte(`{"signatures": [], "signed": {"_type": "link",
1639 "name": "some name", "products": "invalid",
1640 "byproducts": "invalid", "command": "some command",
1641 "environment": "some list"}}`),
1642 []byte(`{"signatures": [], "signed": {"_type": "link",
1643 "materials": "invalid", "name": "some name",
1644 "byproducts": "invalid", "command": "some command",
1645 "environment": "some list"}}`),
1646 []byte(`{"signatures": [], "signed": {"_type": "link",
1647 "materials": "invalid", "name": "some name", "products": "invalid",
1648 "command": "some command",
1649 "environment": "some list"}}`),
1650 []byte(`{"signatures": [], "signed": {"_type": "link",
1651 "materials": "invalid", "name": "some name", "products": "invalid",
1652 "byproducts": "invalid", "environment": "some list"}}`),
1653 []byte(`{"signatures": [], "signed": {"_type": "link",
1654 "materials": "invalid", "name": "some name", "products": "invalid",
1655 "byproducts": "invalid", "command": "some command"}}`),
1656 []byte(`{"signatures": [], "signed": {"_type": "link", "materials": {},
1657 "name": "some name", "products": {}, "byproducts": {},
1658 "command": [], "environment": {}, "foo": "bar"}}`),
1659 []byte(`{"payloadType": "invalid", "payload": "eyJfdHlwZSI6ICJsaW5rIiwgIm1hdGVyaWFscyI6ICJpbnZhbGlkIiwgIm5hbWUiOiAic29tZSBuYW1lIiwgInByb2R1Y3RzIjogImludmFsaWQiLCAiYnlwcm9kdWN0cyI6ICJpbnZhbGlkIiwgImNvbW1hbmQiOiAic29tZSBjb21tYW5kIn0=", "signatures": []}`),
1660 []byte(`{"payloadType": "application/vnd.in-toto+json", "payload": "eyJfdHlwZSI6ICJsaW5rIiwgIm1hdGVyaWFscyI6ICJpbnZhbGlkIiwgIm5hbWUiOiAic29tZSBuYW1lIiwgInByb2R1Y3RzIjogImludmFsaWQiLCAiYnlwcm9kdWN0cyI6ICJpbnZhbGlkIiwgImNvbW1hbmQiOiAic29tZSBjb21tYW5kIn0="}`),
1661 []byte(`{"payloadType": "application/vnd.in-toto+json", "signatures": []}`),
1662 }
1663
1664 expectedErrors := []string{
1665 "unexpected end",
1666 "requires 'signed' and 'signatures' parts",
1667 "requires 'signed' and 'signatures' parts",
1668 "cannot unmarshal string into Go value of type []in_toto.Signature",
1669 "cannot unmarshal array into Go value of type map[string]interface {}",
1670 ErrUnknownMetadataType.Error(),
1671 "cannot unmarshal string into Go struct field Link.materials",
1672 "cannot unmarshal string into Go struct field Layout.steps",
1673 "required field steps missing",
1674 "required field inspect missing",
1675 "required field keys missing",
1676 "required field expires missing",
1677 "required field readme missing",
1678 "json: unknown field \"foo\"",
1679 "required field name missing",
1680 "required field materials missing",
1681 "required field products missing",
1682 "required field byproducts missing",
1683 "required field command missing",
1684 "required field environment missing",
1685 "json: unknown field \"foo\"",
1686 ErrInvalidPayloadType.Error(),
1687 "in-toto metadata envelope requires 'payload' and 'signatures' parts",
1688 "in-toto metadata envelope requires 'payload' and 'signatures' parts",
1689 }
1690
1691 for i := 0; i < len(invalidJSONBytes); i++ {
1692 fn := fmt.Sprintf("invalid-metadata-%v.tmp", i)
1693 if err := os.WriteFile(fn, invalidJSONBytes[i], 0644); err != nil {
1694 fmt.Printf("Could not write file: %s", err)
1695 }
1696 _, err := LoadMetadata(fn)
1697 if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
1698 t.Log(err)
1699 t.Errorf("LoadMetadata returned '%s', expected '%s' error", err,
1700 expectedErrors[i])
1701 }
1702 if err := os.Remove(fn); err != nil {
1703 t.Errorf("unable to remove directory %s: %s", fn, err)
1704 }
1705 }
1706 }
1707
View as plain text