github.com/boxboat/in-toto-golang@v0.0.3-0.20210303203820-2fa16ecbe6f6/in_toto/model_test.go (about)

     1  package in_toto
     2  
     3  import (
     4  	"encoding/hex"
     5  	"errors"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  )
    13  
    14  func TestMatchEcdsaScheme(t *testing.T) {
    15  	curveSize := 224
    16  	scheme := "ecdsa-sha2-nistp512"
    17  	if err := matchEcdsaScheme(curveSize, scheme); err == nil {
    18  		t.Errorf("matchEcdsaScheme should have failed with curveSize: %d and scheme: %s", curveSize, scheme)
    19  	}
    20  }
    21  
    22  func TestMetablockLoad(t *testing.T) {
    23  	// Create a bunch of tmp json files with invalid format and test load errors:
    24  	// - invalid json
    25  	// - missing signatures and signed field
    26  	// - invalid signatures field
    27  	// - invalid signed field
    28  	// - invalid signed type
    29  	// - invalid signed field for type link
    30  	// - invalid signed field for type layout
    31  	invalidJSONBytes := [][]byte{
    32  		[]byte("{"),
    33  		[]byte("{}"),
    34  		[]byte(`{"signatures": null, "signed": {}}`),
    35  		[]byte(`{"signatures": "string", "signed": {}}`),
    36  		[]byte(`{"signatures": [], "signed": []}`),
    37  		[]byte(`{"signatures": [], "signed": {"_type": "something else"}}`),
    38  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    39  			"materials": "invalid", "name": "some name", "products": "invalid",
    40  			"byproducts": "invalid", "command": "some command",
    41  			"environment": "some list"}}`),
    42  		[]byte(`{"signatures": [], "signed": {"_type": "layout",
    43  			"steps": "invalid", "inspect": "invalid", "readme": "some readme",
    44  			"keys": "some keys", "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
    45  		[]byte(`{"signatures": [], "signed": {"_type": "layout",
    46  			"inspect": "invalid", "readme": "some readme", "keys": "some keys",
    47  			"expires": "some date", "rootcas": [], "intermediatecas": []}}`),
    48  		[]byte(`{"signatures": [], "signed": {"_type": "layout",
    49  			"steps": "invalid", "readme": "some readme", "keys": "some keys",
    50  			"expires": "some date", "rootcas": [], "intermediatecas": []}}`),
    51  		[]byte(`{"signatures": [], "signed": {"_type": "layout",
    52  			"steps": "invalid", "inspect": "invalid", "readme": "some readme",
    53  			"expires": "some date", "rootcas": [], "intermediatecas": []}}`),
    54  		[]byte(`{"signatures": [], "signed": {"_type": "layout",
    55  			"steps": "invalid", "inspect": "invalid", "readme": "some readme",
    56  			"keys": "some keys", "rootcas": [], "intermediatecas": []}}`),
    57  		[]byte(`{"signatures": [], "signed": {"_type": "layout",
    58  			"steps": "invalid", "inspect": "invalid",
    59  			"keys": "some keys", "expires": "some date", "rootcas": [], "intermediatecas": []}}`),
    60  		[]byte(`{"signatures": [], "signed": {"_type": "layout", "steps": [],
    61  			"inspect": [], "readme": "some readme", "keys": {},
    62  			"expires": "some date", "foo": "bar", "rootcas": [], "intermediatecas": []}}`),
    63  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    64  			"materials": "invalid", "products": "invalid",
    65  			"byproducts": "invalid", "command": "some command",
    66  			"environment": "some list"}}`),
    67  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    68  			"name": "some name", "products": "invalid",
    69  			"byproducts": "invalid", "command": "some command",
    70  			"environment": "some list"}}`),
    71  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    72  			"materials": "invalid", "name": "some name",
    73  			"byproducts": "invalid", "command": "some command",
    74  			"environment": "some list"}}`),
    75  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    76  			"materials": "invalid", "name": "some name", "products": "invalid",
    77  			"command": "some command",
    78  			"environment": "some list"}}`),
    79  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    80  			"materials": "invalid", "name": "some name", "products": "invalid",
    81  			"byproducts": "invalid", "environment": "some list"}}`),
    82  		[]byte(`{"signatures": [], "signed": {"_type": "link",
    83  			"materials": "invalid", "name": "some name", "products": "invalid",
    84  			"byproducts": "invalid", "command": "some command"}}`),
    85  		[]byte(`{"signatures": [], "signed": {"_type": "link", "materials": {},
    86  			"name": "some name", "products": {}, "byproducts": {},
    87  			"command": [], "environment": {}, "foo": "bar"}}`),
    88  	}
    89  
    90  	expectedErrors := []string{
    91  		"unexpected end",
    92  		"requires 'signed' and 'signatures' parts",
    93  		"requires 'signed' and 'signatures' parts",
    94  		"cannot unmarshal string into Go value of type []in_toto.Signature",
    95  		"cannot unmarshal array into Go value of type map[string]interface {}",
    96  		"metadata must be one of 'link' or 'layout'",
    97  		"cannot unmarshal string into Go struct field Link.materials",
    98  		"cannot unmarshal string into Go struct field Layout.steps",
    99  		"required field steps missing",
   100  		"required field inspect missing",
   101  		"required field keys missing",
   102  		"required field expires missing",
   103  		"required field readme missing",
   104  		"json: unknown field \"foo\"",
   105  		"required field name missing",
   106  		"required field materials missing",
   107  		"required field products missing",
   108  		"required field byproducts missing",
   109  		"required field command missing",
   110  		"required field environment missing",
   111  		"json: unknown field \"foo\"",
   112  	}
   113  
   114  	for i := 0; i < len(invalidJSONBytes); i++ {
   115  		fn := fmt.Sprintf("invalid-metadata-%v.tmp", i)
   116  		if err := ioutil.WriteFile(fn, invalidJSONBytes[i], 0644); err != nil {
   117  			fmt.Printf("Could not write file: %s", err)
   118  		}
   119  		var mb Metablock
   120  		err := mb.Load(fn)
   121  		if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
   122  			t.Errorf("Metablock.Load returned '%s', expected '%s' error", err,
   123  				expectedErrors[i])
   124  		}
   125  		if err := os.Remove(fn); err != nil {
   126  			t.Errorf("Unable to remove directory %s: %s", fn, err)
   127  		}
   128  	}
   129  }
   130  
   131  func TestMetablockDump(t *testing.T) {
   132  	// Test dump metablock errors:
   133  	// - invalid content
   134  	// - invalid path
   135  	mbs := []Metablock{
   136  		{Signed: TestMetablockDump},
   137  		{},
   138  	}
   139  	paths := []string{
   140  		"bad-metadata",
   141  		"bad/path",
   142  	}
   143  	expectedErrors := []string{
   144  		"json: unsupported type",
   145  		"open bad/path",
   146  	}
   147  
   148  	for i := 0; i < len(mbs); i++ {
   149  		err := mbs[i].Dump(paths[i])
   150  		fmt.Println(err)
   151  		if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
   152  			t.Errorf("Metablock.Dump returned '%s', expected '%s'",
   153  				err, expectedErrors[i])
   154  		}
   155  	}
   156  }
   157  
   158  func TestMetablockLoadDumpLoad(t *testing.T) {
   159  	// Dump, load and compare metablock, also compare with metablock loaded
   160  	// from existing equivalent JSON file, assert that they are equal.
   161  	mbMemory := Metablock{
   162  		Signed: Link{
   163  			Type: "link",
   164  			Name: "package",
   165  			Command: []string{
   166  				"tar",
   167  				"zcvf",
   168  				"foo.tar.gz",
   169  				"foo.py",
   170  			},
   171  			Materials: map[string]interface{}{
   172  				"foo.py": map[string]interface{}{
   173  					"sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549",
   174  				},
   175  			},
   176  			Products: map[string]interface{}{
   177  				"foo.tar.gz": map[string]interface{}{
   178  					"sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c1e5aabb7c98514f355",
   179  				},
   180  			},
   181  			ByProducts: map[string]interface{}{
   182  				"return-value": float64(0),
   183  				"stderr":       "a foo.py\n",
   184  				"stdout":       "",
   185  			},
   186  			Environment: map[string]interface{}{},
   187  		},
   188  		Signatures: []Signature{
   189  			{
   190  				KeyID: "2f89b9272acfc8f4a0a0f094d789fdb0ba798b0fe41f2f5f417c12f0085ff498",
   191  				Sig: "66365d379d66a2e76d39a1f048847826393127572ba43bead96419499b0256" +
   192  					"1a08e1cb06cf91f2addd87c30a01f776a8ccc599574bc9a2bd519558351f56cff" +
   193  					"a61ac4f994d0d491204ff54707937e15f9abfa97c5bda1ec1ae2a2afea63f8086" +
   194  					"13f4fb343b85a5a455b668b95fa3a11cb9b34219d4d6af2dd4e80a9af01023954" +
   195  					"a8813b510a6ff6041c3af52056d021fabbc975211b0d8ee7a429a6c22efde583d" +
   196  					"8ac0719fd657b398a3e02cc711897acbe8cadf32d54f47012aa44621728ede42c" +
   197  					"3bc95c662f9c1211df4e18da8e0f6b2de358700cea5db1e76fc61ef5a90bcebcc" +
   198  					"883eed2272e5ca1c8cbb09b868613b839266cd3ae346ce88439bdb5bb4c69dcb7" +
   199  					"398f4373f2b051adb3d44d11ef1b70c7189aa5c0e6906bf7be1228dc553390024" +
   200  					"c9c796316067fda7d63cf60bfac86ef2e13bbd8e4c3575683673f7cdf4639c3a5" +
   201  					"dc225fc0c040dbd9962a6ff51913b240544939ce2d32a5e84792c0acfa94ee07e" +
   202  					"88e474bf4937558d107c6ecdef5b5b3a7f3a44a657662bbc1046df3a",
   203  			},
   204  		},
   205  	}
   206  
   207  	fnExisting := "package.2f89b927.link"
   208  	fnTmp := fnExisting + ".tmp"
   209  	if err := mbMemory.Dump(fnTmp); err != nil {
   210  		t.Errorf("JSON serialization failed: %s", err)
   211  	}
   212  	for _, fn := range []string{fnExisting, fnTmp} {
   213  		var mbFile Metablock
   214  		if err := mbFile.Load(fn); err != nil {
   215  			t.Errorf("Could not parse Metablock: %s", err)
   216  		}
   217  		if !reflect.DeepEqual(mbMemory, mbFile) {
   218  			t.Errorf("Dumped and Loaded Metablocks are not equal: \n%s\n\n\n%s\n",
   219  				mbMemory, mbFile)
   220  		}
   221  	}
   222  	// Remove temporary metablock file (keep other for remaining tests)
   223  	if err := os.Remove(fnTmp); err != nil {
   224  		t.Errorf("Unable to remove directory %s: %s", fnTmp, err)
   225  	}
   226  }
   227  
   228  func TestMetablockGetSignableRepresentation(t *testing.T) {
   229  	// Test successful metadata canonicalization with encoding corner cases
   230  	// (unicode, escapes, non-string types, ...) and compare with reference
   231  	var mb Metablock
   232  	if err := mb.Load("canonical-test.link"); err != nil {
   233  		t.Errorf("Cannot parse link file: %s", err)
   234  	}
   235  	// Use hex representation for unambiguous assignment
   236  	referenceHex := "7b225f74797065223a226c696e6b222" +
   237  		"c22627970726f6475637473223a7b7d2c22636f6d6d616e64223a5b5d2" +
   238  		"c22656e7669726f6e6d656e74223a7b2261223a22575446222c2262223" +
   239  		"a747275652c2263223a66616c73652c2264223a6e756c6c2c2265223a3" +
   240  		"12c2266223a221befbfbf465c5c6e5c22227d2c226d6174657269616c7" +
   241  		"3223a7b7d2c226e616d65223a2274657374222c2270726f64756374732" +
   242  		"23a7b7d7d"
   243  
   244  	canonical, _ := mb.GetSignableRepresentation()
   245  	if fmt.Sprintf("%x", canonical) != referenceHex {
   246  		// Convert hex representation back to string for better error message
   247  		src := []byte(referenceHex)
   248  		reference := make([]byte, hex.DecodedLen(len(src)))
   249  		n, _ := hex.Decode(reference, src)
   250  		t.Errorf("Metablock.GetSignableRepresentation returned '%s', expected '%s'",
   251  			canonical, reference[:n])
   252  	}
   253  }
   254  
   255  func TestMetablockVerifySignature(t *testing.T) {
   256  	// Test metablock signature verification errors:
   257  	// - no signature found
   258  	// - wrong signature for key
   259  	// - invalid metadata (can't canonicalize)
   260  	var key Key
   261  	if err := key.LoadKey("alice.pub", "rsassa-pss-sha256", []string{"sha256", "sha512"}); err != nil {
   262  		t.Errorf("Cannot load public key file: %s", err)
   263  	}
   264  	// Test missing key, bad signature and bad metadata
   265  	mbs := []Metablock{
   266  		{},
   267  		{
   268  			Signatures: []Signature{{KeyID: key.KeyID, Sig: "bad sig"}},
   269  		},
   270  		{
   271  			Signatures: []Signature{{KeyID: key.KeyID}},
   272  			Signed:     TestMetablockVerifySignature,
   273  		},
   274  	}
   275  	expectedErrors := []string{
   276  		"No signature found",
   277  		"encoding/hex: invalid byte: U+0020 ' '",
   278  		"json: unsupported type",
   279  	}
   280  	for i := 0; i < len(mbs); i++ {
   281  		err := mbs[i].VerifySignature(key)
   282  		if err == nil || !strings.Contains(err.Error(), expectedErrors[i]) {
   283  			t.Errorf("Metablock.VerifySignature returned '%s', expected '%s'",
   284  				err, expectedErrors[i])
   285  		}
   286  	}
   287  
   288  	// Test successful metablock signature verification
   289  	var mb Metablock
   290  	if err := mb.Load("demo.layout"); err != nil {
   291  		t.Errorf("Cannot parse template file: %s", err)
   292  	}
   293  	err := mb.VerifySignature(key)
   294  	if err != nil {
   295  		t.Errorf("Metablock.VerifySignature returned '%s', expected nil", err)
   296  	}
   297  }
   298  
   299  func TestValidateLink(t *testing.T) {
   300  	var mb Metablock
   301  	if err := mb.Load("package.2f89b927.link"); err != nil {
   302  		t.Errorf("Metablock load returned '%s'", err)
   303  	}
   304  	if err := validateLink(mb.Signed.(Link)); err != nil {
   305  		t.Errorf("Link metadata validation failed, returned '%s'", err)
   306  	}
   307  
   308  	testMb := Metablock{
   309  		Signed: Link{
   310  			Type: "invalid",
   311  			Name: "test_type",
   312  			Command: []string{
   313  				"tar",
   314  				"zcvf",
   315  				"foo.tar.gz",
   316  				"foo.py",
   317  			},
   318  			Materials: map[string]interface{}{
   319  				"foo.py": map[string]interface{}{
   320  					"sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549",
   321  				},
   322  			},
   323  			Products: map[string]interface{}{
   324  				"foo.tar.gz": map[string]interface{}{
   325  					"sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c1e5aabb7c98514f355",
   326  				},
   327  			},
   328  			ByProducts: map[string]interface{}{
   329  				"return-value": float64(0),
   330  				"stderr":       "a foo.py\n",
   331  				"stdout":       "",
   332  			},
   333  			Environment: map[string]interface{}{},
   334  		},
   335  	}
   336  
   337  	err := validateLink(testMb.Signed.(Link))
   338  	if err.Error() != "invalid type for link 'test_type': should be 'link'" {
   339  		t.Error("validateLink error - incorrect type not detected")
   340  	}
   341  
   342  	testMb = Metablock{
   343  		Signed: Link{
   344  			Type: "link",
   345  			Name: "test_material_hash",
   346  			Command: []string{
   347  				"tar",
   348  				"zcvf",
   349  				"foo.tar.gz",
   350  				"foo.py",
   351  			},
   352  			Materials: map[string]interface{}{
   353  				"foo.py": map[string]interface{}{
   354  					"sha256": "!@#$%",
   355  				},
   356  			},
   357  			Products: map[string]interface{}{
   358  				"foo.tar.gz": map[string]interface{}{
   359  					"sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e69" +
   360  						"36c1e5aabb7c98514f355",
   361  				},
   362  			},
   363  			ByProducts: map[string]interface{}{
   364  				"return-value": float64(0),
   365  				"stderr":       "a foo.py\n",
   366  				"stdout":       "",
   367  			},
   368  			Environment: map[string]interface{}{},
   369  		},
   370  	}
   371  
   372  	err = validateLink(testMb.Signed.(Link))
   373  	if err.Error() != "in materials of link 'test_material_hash': in artifact"+
   374  		" 'foo.py', sha256 hash value: invalid hex string: !@#$%" {
   375  		t.Error("validateLink error - invalid hashes not detected")
   376  	}
   377  
   378  	testMb = Metablock{
   379  		Signed: Link{
   380  			Type: "link",
   381  			Name: "test_product_hash",
   382  			Command: []string{
   383  				"tar",
   384  				"zcvf",
   385  				"foo.tar.gz",
   386  				"foo.py",
   387  			},
   388  			Materials: map[string]interface{}{
   389  				"foo.py": map[string]interface{}{
   390  					"sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a27c013544a60502549",
   391  				},
   392  			},
   393  			Products: map[string]interface{}{
   394  				"foo.tar.gz": map[string]interface{}{
   395  					"sha256": "!@#$%",
   396  				},
   397  			},
   398  			ByProducts: map[string]interface{}{
   399  				"return-value": float64(0),
   400  				"stderr":       "a foo.py\n",
   401  				"stdout":       "",
   402  			},
   403  			Environment: map[string]interface{}{},
   404  		},
   405  	}
   406  
   407  	err = validateLink(testMb.Signed.(Link))
   408  	if err.Error() != "in products of link 'test_product_hash': in artifact "+
   409  		"'foo.tar.gz', sha256 hash value: invalid hex string: !@#$%" {
   410  		t.Error("validateLink error - invalid hashes not detected")
   411  	}
   412  }
   413  
   414  func TestValidateLayout(t *testing.T) {
   415  	var mb Metablock
   416  	if err := mb.Load("demo.layout"); err != nil {
   417  		t.Errorf("Metablock load returned '%s'", err)
   418  	}
   419  	if err := validateLayout(mb.Signed.(Layout)); err != nil {
   420  		t.Errorf("Layout metadata validation failed, returned '%s'", err)
   421  	}
   422  
   423  	testMb := Metablock{
   424  		Signed: Layout{
   425  			Type:    "invalid",
   426  			Expires: "2020-11-18T16:06:36Z",
   427  			Readme:  "some readme text",
   428  			Steps:   []Step{},
   429  			Inspect: []Inspection{},
   430  			Keys:    map[string]Key{},
   431  		},
   432  	}
   433  
   434  	err := validateLayout(testMb.Signed.(Layout))
   435  	if err.Error() != "invalid Type value for layout: should be 'layout'" {
   436  		t.Error("validateLayout error - invalid type not detected")
   437  	}
   438  
   439  	testMb = Metablock{
   440  		Signed: Layout{
   441  			Type:    "layout",
   442  			Expires: "2020-02-31T18:03:43Z",
   443  			Readme:  "some readme text",
   444  			Steps:   []Step{},
   445  			Inspect: []Inspection{},
   446  			Keys:    map[string]Key{},
   447  		},
   448  	}
   449  
   450  	err = validateLayout(testMb.Signed.(Layout))
   451  	if err.Error() != "expiry time parsed incorrectly - date either invalid "+
   452  		"or of incorrect format" {
   453  		t.Error("validateLayout error - invalid date not detected")
   454  	}
   455  
   456  	testMb = Metablock{
   457  		Signed: Layout{
   458  			Type:    "layout",
   459  			Expires: "2020-02-27T18:03:43Zinvalid",
   460  			Readme:  "some readme text",
   461  			Steps:   []Step{},
   462  			Inspect: []Inspection{},
   463  			Keys:    map[string]Key{},
   464  		},
   465  	}
   466  
   467  	err = validateLayout(testMb.Signed.(Layout))
   468  	if err.Error() != "expiry time parsed incorrectly - date either invalid "+
   469  		"or of incorrect format" {
   470  		t.Error("validateLayout error - invalid date not detected")
   471  	}
   472  
   473  	testMb = Metablock{
   474  		Signed: Layout{
   475  			Type:    "layout",
   476  			Expires: "2020-02-27T18:03:43Z",
   477  			Readme:  "some readme text",
   478  			Steps: []Step{
   479  				{
   480  					Type: "step",
   481  					SupplyChainItem: SupplyChainItem{
   482  						Name: "foo",
   483  					},
   484  				},
   485  				{
   486  					Type: "step",
   487  					SupplyChainItem: SupplyChainItem{
   488  						Name: "foo",
   489  					},
   490  				},
   491  			},
   492  			Inspect: []Inspection{},
   493  			Keys:    map[string]Key{},
   494  		},
   495  	}
   496  
   497  	err = validateLayout(testMb.Signed.(Layout))
   498  	if err.Error() != "non unique step or inspection name found" {
   499  		t.Error("validateLayout error - duplicate step/inspection name not " +
   500  			"detected")
   501  	}
   502  
   503  	testMb = Metablock{
   504  		Signed: Layout{
   505  			Type:    "layout",
   506  			Expires: "2020-02-27T18:03:43Z",
   507  			Readme:  "some readme text",
   508  			Steps: []Step{
   509  				{
   510  					Type: "step",
   511  					SupplyChainItem: SupplyChainItem{
   512  						Name: "foo",
   513  					},
   514  				},
   515  			},
   516  			Inspect: []Inspection{
   517  				{
   518  					Type: "inspection",
   519  					SupplyChainItem: SupplyChainItem{
   520  						Name: "foo",
   521  					},
   522  				},
   523  			},
   524  			Keys: map[string]Key{},
   525  		},
   526  	}
   527  
   528  	err = validateLayout(testMb.Signed.(Layout))
   529  	if err.Error() != "non unique step or inspection name found" {
   530  		t.Error("validateLayout error - duplicate step/inspection name not " +
   531  			"detected")
   532  	}
   533  
   534  	testMb = Metablock{
   535  		Signed: Layout{
   536  			Type:    "layout",
   537  			Expires: "2020-02-27T18:03:43Z",
   538  			Readme:  "some readme text",
   539  			Steps:   []Step{},
   540  			Inspect: []Inspection{
   541  				{
   542  					Type: "inspection",
   543  					SupplyChainItem: SupplyChainItem{
   544  						Name: "foo",
   545  					},
   546  				},
   547  				{
   548  					Type: "inspection",
   549  					SupplyChainItem: SupplyChainItem{
   550  						Name: "foo",
   551  					},
   552  				},
   553  			},
   554  			Keys: map[string]Key{},
   555  		},
   556  	}
   557  
   558  	err = validateLayout(testMb.Signed.(Layout))
   559  	if err.Error() != "non unique step or inspection name found" {
   560  		t.Error("validateLayout error - duplicate step/inspection name not " +
   561  			"detected")
   562  	}
   563  
   564  	testMb = Metablock{
   565  		Signed: Layout{
   566  			Type:    "layout",
   567  			Expires: "2020-02-27T18:03:43Z",
   568  			Readme:  "some readme text",
   569  			Steps: []Step{
   570  				{
   571  					Type: "invalid",
   572  					SupplyChainItem: SupplyChainItem{
   573  						Name: "foo",
   574  					},
   575  				},
   576  			},
   577  			Inspect: []Inspection{},
   578  			Keys:    map[string]Key{},
   579  		},
   580  	}
   581  
   582  	err = validateLayout(testMb.Signed.(Layout))
   583  	if err.Error() != "invalid Type value for step 'foo': should be 'step'" {
   584  		t.Error("validateLayout - validateStep error - invalid step type not " +
   585  			"detected")
   586  	}
   587  
   588  	cases := map[string]struct {
   589  		Arg      Layout
   590  		Expected string
   591  	}{
   592  		"invalid key map": {
   593  			Layout{
   594  				Type:    "layout",
   595  				Expires: "2020-02-27T18:03:43Z",
   596  				Keys: map[string]Key{
   597  					"deadbeef": Key{KeyID: "livebeef"},
   598  				},
   599  			},
   600  			"invalid key found",
   601  		},
   602  		"invalid rsa key": {
   603  			Layout{
   604  				Type:    "layout",
   605  				Expires: "2020-02-27T18:03:43Z",
   606  				Keys: map[string]Key{
   607  					"deadbeef": Key{KeyID: "deadbeef"},
   608  				},
   609  			},
   610  			"empty field in key: keytype",
   611  		},
   612  	}
   613  
   614  	for name, tc := range cases {
   615  		err := validateLayout(tc.Arg)
   616  		if err == nil || !strings.Contains(err.Error(), tc.Expected) {
   617  			t.Errorf("%s: '%s' not in '%s'", name, tc.Expected, err)
   618  		}
   619  	}
   620  }
   621  
   622  func TestValidateStep(t *testing.T) {
   623  	testStep := Step{
   624  		Type: "invalid",
   625  		SupplyChainItem: SupplyChainItem{
   626  			Name: "foo",
   627  		},
   628  	}
   629  	err := validateStep(testStep)
   630  	if err.Error() != "invalid Type value for step 'foo': should be 'step'" {
   631  		t.Error("validateStep error - invalid type not detected")
   632  	}
   633  
   634  	testStep = Step{
   635  		Type: "step",
   636  		PubKeys: []string{"776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f4Z" +
   637  			"41132b345b08453f5"},
   638  		SupplyChainItem: SupplyChainItem{
   639  			Name: "foo",
   640  		},
   641  	}
   642  	err = validateStep(testStep)
   643  	if !errors.Is(err, ErrInvalidHexString) {
   644  		t.Error("validateStep - validateHexString error - invalid key ID not " +
   645  			"detected")
   646  	}
   647  
   648  	testStep = Step{
   649  		Type: "step",
   650  		SupplyChainItem: SupplyChainItem{
   651  			Name: "",
   652  		},
   653  	}
   654  	err = validateStep(testStep)
   655  	if err.Error() != "step name cannot be empty" {
   656  		t.Error("validateStep error - empty name not detected")
   657  	}
   658  }
   659  
   660  func TestValidateInspection(t *testing.T) {
   661  	testInspection := Inspection{
   662  		Type: "invalid",
   663  		SupplyChainItem: SupplyChainItem{
   664  			Name: "foo",
   665  		},
   666  	}
   667  	err := validateInspection(testInspection)
   668  	if err.Error() != "invalid Type value for inspection 'foo': should be "+
   669  		"'inspection'" {
   670  		t.Error("validateInspection error - invalid type not detected")
   671  	}
   672  	testInspection = Inspection{
   673  		Type: "inspection",
   674  		SupplyChainItem: SupplyChainItem{
   675  			Name: "",
   676  		},
   677  	}
   678  	err = validateInspection(testInspection)
   679  	if err.Error() != "inspection name cannot be empty" {
   680  		t.Error("validateInspection error - empty name not detected")
   681  	}
   682  
   683  	testInspection = Inspection{
   684  		Type: "inspection",
   685  		SupplyChainItem: SupplyChainItem{
   686  			Name: "inspect",
   687  		},
   688  	}
   689  	err = validateInspection(testInspection)
   690  	if err != nil {
   691  		t.Error("validateInspection should successfully validate an inspection")
   692  	}
   693  }
   694  
   695  func TestValidateHexSchema(t *testing.T) {
   696  	testStr := "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b" +
   697  		"08453f5"
   698  	if err := validateHexString(testStr); err != nil {
   699  		t.Errorf("validateHexString error - valid key ID flagged")
   700  	}
   701  
   702  	testStr = "Z776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b" +
   703  		"08453f5"
   704  	if err := validateHexString(testStr); err == nil {
   705  		t.Errorf("validateHexString error - invalid key ID not detected")
   706  	}
   707  }
   708  
   709  func TestValidatePubKey(t *testing.T) {
   710  	testKey := Key{
   711  		KeyID:   "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
   712  		KeyType: "rsa",
   713  		KeyVal: KeyVal{
   714  			Private: "",
   715  			Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAO" +
   716  				"CAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6" +
   717  				"SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQ" +
   718  				"S8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTy" +
   719  				"ONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK" +
   720  				"\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLR" +
   721  				"qzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSb" +
   722  				"J/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLC" +
   723  				"fQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARR" +
   724  				"wU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1g" +
   725  				"KqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----",
   726  		},
   727  		Scheme: "rsassa-pss-sha256",
   728  	}
   729  
   730  	err := validatePublicKey(testKey)
   731  	if !errors.Is(err, nil) {
   732  		t.Errorf("error validating public key: %s", err)
   733  	}
   734  
   735  	testKey = Key{
   736  		KeyID:   "Z776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
   737  		KeyType: "rsa",
   738  		KeyVal: KeyVal{
   739  			Private: "",
   740  			Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAO" +
   741  				"CAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6" +
   742  				"SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQ" +
   743  				"S8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTy" +
   744  				"ONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK" +
   745  				"\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLR" +
   746  				"qzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSb" +
   747  				"J/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLC" +
   748  				"fQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARR" +
   749  				"wU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1g" +
   750  				"KqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----",
   751  		},
   752  		Scheme: "rsassa-pss-sha256",
   753  	}
   754  
   755  	err = validateKey(testKey)
   756  	if !errors.Is(err, ErrInvalidHexString) {
   757  		t.Error("validateKey error - invalid key ID not detected")
   758  	}
   759  
   760  	testKey = Key{
   761  		KeyID:   "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
   762  		KeyType: "rsa",
   763  		KeyVal: KeyVal{
   764  			Private: "invalid",
   765  			Public: "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAO" +
   766  				"CAY8AMIIBigKCAYEAzgLBsMFSgwBiWTBmVsyW\n5KbJwLFSodAzdUhU2Bq6" +
   767  				"SdRz/W6UOBGdojZXibxupjRtAaEQW/eXDe+1CbKg6ENZ\nGt2D9HGFCQZgQ" +
   768  				"S8ONgNDQGiNxgApMA0T21AaUhru0vEofzdN1DfEF4CAGv5AkcgK\nsalhTy" +
   769  				"ONervFIjFEdXGelFZ7dVMV3Pp5WkZPG0jFQWjnmDZhUrtSxEtqbVghc3kK" +
   770  				"\nAUj9Ll/3jyi2wS92Z1j5ueN8X62hWX2xBqQ6nViOMzdujkoiYCRSwuMLR" +
   771  				"qzW2CbT\nL8hF1+S5KWKFzxl5sCVfpPe7V5HkgEHjwCILXTbCn2fCMKlaSb" +
   772  				"J/MG2lW7qSY2Ro\nwVXWkp1wDrsJ6Ii9f2dErv9vJeOVZeO9DsooQ5EuzLC" +
   773  				"fQLEU5mn7ul7bU7rFsb8J\nxYOeudkNBatnNCgVMAkmDPiNA7E33bmL5ARR" +
   774  				"wU0iZicsqLQR32pmwdap8PjofxqQ\nk7Gtvz/iYzaLrZv33cFWWTsEOqK1g" +
   775  				"KqigSqgW9T26wO9AgMBAAE=\n-----END PUBLIC KEY-----",
   776  		},
   777  		Scheme: "rsassa-pss-sha256",
   778  	}
   779  
   780  	err = validatePublicKey(testKey)
   781  	if !errors.Is(err, ErrNoPublicKey) {
   782  		t.Error("validateKey error - private key not detected")
   783  	}
   784  
   785  	testKey = Key{
   786  		KeyID:   "776a00e29f3559e0141b3b096f696abc6cfb0c657ab40f441132b345b08453f5",
   787  		KeyType: "rsa",
   788  		KeyVal: KeyVal{
   789  			Private: "",
   790  			Public:  "",
   791  		},
   792  		Scheme: "rsassa-pss-sha256",
   793  	}
   794  
   795  	err = validateKey(testKey)
   796  	if !errors.Is(err, ErrEmptyKeyField) {
   797  		t.Error("validateKey error - empty public key not detected")
   798  	}
   799  }
   800  
   801  func TestValidateMetablock(t *testing.T) {
   802  	testMetablock := Metablock{
   803  		Signatures: []Signature{
   804  			{
   805  				KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
   806  					"8f3e9cc48b35",
   807  				Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
   808  					"33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
   809  					"9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
   810  					"51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
   811  					"e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
   812  					"78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
   813  					"4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
   814  					"58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
   815  					"d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
   816  					"2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
   817  					"ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
   818  					"48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
   819  					"a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
   820  					"bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
   821  			},
   822  		},
   823  		Signed: Layout{
   824  			Type:    "layout",
   825  			Expires: "2020-11-18T16:06:36Z",
   826  			Readme:  "some readme text",
   827  			Steps:   []Step{},
   828  			Inspect: []Inspection{},
   829  			Keys:    map[string]Key{},
   830  		},
   831  	}
   832  
   833  	if err := validateMetablock(testMetablock); err != nil {
   834  		t.Error("validateMetablock error: valid metablock failed")
   835  	}
   836  
   837  	testMetablock = Metablock{
   838  		Signatures: []Signature{
   839  			{
   840  				KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
   841  					"8f3e9cc48b35",
   842  				Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
   843  					"33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
   844  					"9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
   845  					"51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
   846  					"e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
   847  					"78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
   848  					"4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
   849  					"58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
   850  					"d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
   851  					"2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
   852  					"ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
   853  					"48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
   854  					"a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
   855  					"bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
   856  			},
   857  		},
   858  		Signed: Link{
   859  			Type: "link",
   860  			Name: "test_type",
   861  			Command: []string{
   862  				"tar",
   863  				"zcvf",
   864  				"foo.tar.gz",
   865  				"foo.py",
   866  			},
   867  			Materials: map[string]interface{}{
   868  				"foo.py": map[string]interface{}{
   869  					"sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a" +
   870  						"27c013544a60502549",
   871  				},
   872  			},
   873  			Products: map[string]interface{}{
   874  				"foo.tar.gz": map[string]interface{}{
   875  					"sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c" +
   876  						"1e5aabb7c98514f355",
   877  				},
   878  			},
   879  			ByProducts: map[string]interface{}{
   880  				"return-value": float64(0),
   881  				"stderr":       "a foo.py\n",
   882  				"stdout":       "",
   883  			},
   884  			Environment: map[string]interface{}{},
   885  		},
   886  	}
   887  
   888  	if err := validateMetablock(testMetablock); err != nil {
   889  		t.Error("validateMetablock error: valid metablock failed")
   890  	}
   891  
   892  	testMetablock = Metablock{
   893  		Signatures: []Signature{
   894  			{
   895  				KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
   896  					"8f3e9cc48b35",
   897  				Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
   898  					"33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
   899  					"9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
   900  					"51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
   901  					"e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
   902  					"78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
   903  					"4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
   904  					"58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
   905  					"d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
   906  					"2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
   907  					"ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
   908  					"48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
   909  					"a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
   910  					"bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
   911  			},
   912  		},
   913  		Signed: Layout{
   914  			Type:    "invalid",
   915  			Expires: "2020-11-18T16:06:36Z",
   916  			Readme:  "some readme text",
   917  			Steps:   []Step{},
   918  			Inspect: []Inspection{},
   919  			Keys:    map[string]Key{},
   920  		},
   921  	}
   922  
   923  	if err := validateMetablock(testMetablock); err.Error() !=
   924  		"invalid Type value for layout: should be 'layout'" {
   925  		t.Error("validateMetablock Error: invalid Type not detected")
   926  	}
   927  
   928  	testMetablock = Metablock{
   929  		Signatures: []Signature{
   930  			{
   931  				KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
   932  					"8f3e9cc48b35",
   933  				Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
   934  					"33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
   935  					"9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
   936  					"51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
   937  					"e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
   938  					"78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
   939  					"4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
   940  					"58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
   941  					"d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
   942  					"2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
   943  					"ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
   944  					"48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
   945  					"a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
   946  					"bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
   947  			},
   948  		},
   949  		Signed: Link{
   950  			Type: "invalid",
   951  			Name: "test_type",
   952  			Command: []string{
   953  				"tar",
   954  				"zcvf",
   955  				"foo.tar.gz",
   956  				"foo.py",
   957  			},
   958  			Materials: map[string]interface{}{
   959  				"foo.py": map[string]interface{}{
   960  					"sha256": "74dc3727c6e89308b39e4dfedf787e37841198b1fa165a" +
   961  						"27c013544a60502549",
   962  				},
   963  			},
   964  			Products: map[string]interface{}{
   965  				"foo.tar.gz": map[string]interface{}{
   966  					"sha256": "52947cb78b91ad01fe81cd6aef42d1f6817e92b9e6936c" +
   967  						"1e5aabb7c98514f355",
   968  				},
   969  			},
   970  			ByProducts: map[string]interface{}{
   971  				"return-value": float64(0),
   972  				"stderr":       "a foo.py\n",
   973  				"stdout":       "",
   974  			},
   975  			Environment: map[string]interface{}{},
   976  		},
   977  	}
   978  
   979  	if err := validateMetablock(testMetablock); err.Error() !=
   980  		"invalid type for link 'test_type': should be 'link'" {
   981  		t.Error("validateMetablock Error: invalid Type not detected")
   982  	}
   983  
   984  	testMetablock = Metablock{
   985  		Signatures: []Signature{
   986  			{
   987  				KeyID: "Z556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b5" +
   988  					"8f3e9cc48b35",
   989  				Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9d" +
   990  					"33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
   991  					"9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
   992  					"51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
   993  					"e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
   994  					"78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
   995  					"4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
   996  					"58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
   997  					"d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
   998  					"2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
   999  					"ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
  1000  					"48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
  1001  					"a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
  1002  					"bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
  1003  			},
  1004  		},
  1005  		Signed: Layout{
  1006  			Type:    "layout",
  1007  			Expires: "2020-11-18T16:06:36Z",
  1008  			Readme:  "some readme text",
  1009  			Steps:   []Step{},
  1010  			Inspect: []Inspection{},
  1011  			Keys:    map[string]Key{},
  1012  		},
  1013  	}
  1014  
  1015  	err := validateMetablock(testMetablock)
  1016  	if !errors.Is(err, ErrInvalidHexString) {
  1017  		t.Error("validateMetablock Error: invalid key ID not detected")
  1018  	}
  1019  
  1020  	testMetablock = Metablock{
  1021  		Signatures: []Signature{
  1022  			{
  1023  				KeyID: "556caebdc0877eed53d419b60eddb1e57fa773e4e31d70698b58" +
  1024  					"8f3e9cc48b35",
  1025  				Sig: "02813858670c66647c17802d84f06453589f41850013a544609e9z" +
  1026  					"33ba21fa19280e8371701f8274fb0c56bd95ff4f34c418456b002af" +
  1027  					"9836ca218b584f51eb0eaacbb1c9bb57448101b07d058dec04d5255" +
  1028  					"51d157f6ae5e3679701735b1b8f52430f9b771d5476db1a2053cd93" +
  1029  					"e2354f20061178a01705f2fa9ac82c7aeca4dd830e2672eb2271271" +
  1030  					"78d52328747ac819e50ec8ff52c662d7a4c58f5040d8f655fe59580" +
  1031  					"4f3e47c4fc98434c44e914445f7cb773439ebf813de8849dd1b5339" +
  1032  					"58f99f671d4e023d34c110d4b169cc02c12a3755ebe537147ff2479" +
  1033  					"d244daaf719e24cf6b2fa6f47d0410d52d67217bcf4d4d4c2c7c0b9" +
  1034  					"2cd2bcd321edc69bc1430f78a188e712b8cb1fff0c14550cd01c41d" +
  1035  					"ae377256f31211fd249c5031bfee86e638bce6aa36aca349b787cef" +
  1036  					"48255b0ef04bd0a21adb37b2a3da888d1530ca6ddeae5261e6fd65a" +
  1037  					"a626d5caebbfae2986f842bd2ce94bcefe5dd0ae9c5b2028a15bd63" +
  1038  					"bbea61be732207f0f5b58d056f118c830981747cb2b245d1377e17",
  1039  			},
  1040  		},
  1041  		Signed: Layout{
  1042  			Type:    "layout",
  1043  			Expires: "2020-11-18T16:06:36Z",
  1044  			Readme:  "some readme text",
  1045  			Steps:   []Step{},
  1046  			Inspect: []Inspection{},
  1047  			Keys:    map[string]Key{},
  1048  		},
  1049  	}
  1050  
  1051  	err = validateMetablock(testMetablock)
  1052  	if !errors.Is(err, ErrInvalidHexString) {
  1053  		t.Error("validateMetablock error: invalid signature not detected")
  1054  	}
  1055  
  1056  	cases := map[string]struct {
  1057  		Arg      Metablock
  1058  		Expected string
  1059  	}{
  1060  		"invalid type": {
  1061  			Metablock{Signed: "invalid"},
  1062  			"unknown type 'invalid', should be 'layout' or 'link'",
  1063  		},
  1064  	}
  1065  	for name, tc := range cases {
  1066  		err := validateMetablock(tc.Arg)
  1067  		if err == nil || !strings.Contains(err.Error(), tc.Expected) {
  1068  			t.Errorf("%s: '%s' not in '%s'", name, tc.Expected, err)
  1069  		}
  1070  	}
  1071  }
  1072  
  1073  func TestValidateSupplyChainItem(t *testing.T) {
  1074  	cases := map[string]struct {
  1075  		Arg      SupplyChainItem
  1076  		Expected string
  1077  	}{
  1078  		"empty name": {SupplyChainItem{Name: ""}, "name cannot be empty"},
  1079  		"material rule": {
  1080  			SupplyChainItem{
  1081  				Name:              "test",
  1082  				ExpectedMaterials: [][]string{{"invalid"}}},
  1083  			"invalid material rule"},
  1084  		"product rule": {
  1085  			SupplyChainItem{
  1086  				Name:             "test",
  1087  				ExpectedProducts: [][]string{{"invalid"}}},
  1088  			"invalid product rule"},
  1089  	}
  1090  
  1091  	for name, tc := range cases {
  1092  		err := validateSupplyChainItem(tc.Arg)
  1093  		if err == nil || !strings.Contains(err.Error(), tc.Expected) {
  1094  			t.Errorf("%s: '%s' not in '%s'", name, tc.Expected, err)
  1095  		}
  1096  	}
  1097  }
  1098  
  1099  func TestMetablockSignWithRSA(t *testing.T) {
  1100  	var mb Metablock
  1101  	if err := mb.Load("demo.layout"); err != nil {
  1102  		t.Errorf("Cannot parse template file: %s", err)
  1103  	}
  1104  	invalidKey := Key{
  1105  		KeyID:               "test",
  1106  		KeyIDHashAlgorithms: nil,
  1107  		KeyType:             "rsa",
  1108  		KeyVal:              KeyVal{},
  1109  		Scheme:              "rsassa-pss-sha256",
  1110  	}
  1111  
  1112  	if err := mb.Sign(invalidKey); err == nil {
  1113  		t.Errorf("signing with an invalid RSA key should fail")
  1114  	}
  1115  }
  1116  
  1117  func TestMetablockSignWithEd25519(t *testing.T) {
  1118  	var mb Metablock
  1119  	if err := mb.Load("demo.layout"); err != nil {
  1120  		t.Errorf("Cannot parse template file: %s", err)
  1121  	}
  1122  	invalidKey := Key{
  1123  		KeyID:               "invalid",
  1124  		KeyIDHashAlgorithms: nil,
  1125  		KeyType:             "ed25519",
  1126  		KeyVal: KeyVal{
  1127  			Private: "BAD",
  1128  			Public:  "BAD",
  1129  		},
  1130  		Scheme: "ed25519",
  1131  	}
  1132  
  1133  	if err := mb.Sign(invalidKey); err == nil {
  1134  		t.Errorf("signing with an invalid ed25519 key should fail")
  1135  	}
  1136  }
  1137  
  1138  func TestMetaBlockSignWithEcdsa(t *testing.T) {
  1139  	var mb Metablock
  1140  	if err := mb.Load("demo.layout"); err != nil {
  1141  		t.Errorf("Cannot parse template file: %s", err)
  1142  	}
  1143  	invalidKey := Key{
  1144  		KeyID:               "invalid",
  1145  		KeyIDHashAlgorithms: nil,
  1146  		KeyType:             "ecdsa",
  1147  		KeyVal: KeyVal{
  1148  			Private: "BAD",
  1149  			Public:  "BAD",
  1150  		},
  1151  		Scheme: "ecdsa",
  1152  	}
  1153  	if err := mb.Sign(invalidKey); err == nil {
  1154  		t.Errorf("signing with an invalid ecdsa key should fail")
  1155  	}
  1156  }
  1157  
  1158  func TestValidateKeyErrors(t *testing.T) {
  1159  	invalidTables := []struct {
  1160  		name string
  1161  		key  Key
  1162  		err  error
  1163  	}{
  1164  		{"empty key", Key{
  1165  			KeyID:               "",
  1166  			KeyIDHashAlgorithms: nil,
  1167  			KeyType:             "",
  1168  			KeyVal:              KeyVal{},
  1169  			Scheme:              "",
  1170  		}, ErrInvalidHexString},
  1171  		{"keytype missing", Key{
  1172  			KeyID:               "bad",
  1173  			KeyIDHashAlgorithms: []string{"sha256"},
  1174  			KeyType:             "",
  1175  			KeyVal: KeyVal{
  1176  				Private: "",
  1177  				Public:  "",
  1178  			},
  1179  			Scheme: "rsassa-psa-sha256",
  1180  		}, ErrEmptyKeyField},
  1181  		{"key scheme missing", Key{
  1182  			KeyID:               "bad",
  1183  			KeyIDHashAlgorithms: []string{"sha256"},
  1184  			KeyType:             "ed25519",
  1185  			KeyVal: KeyVal{
  1186  				Private: "bad",
  1187  				Public:  "bad",
  1188  			},
  1189  			Scheme: "",
  1190  		}, ErrEmptyKeyField},
  1191  		{
  1192  			name: "invalid key type",
  1193  			key: Key{
  1194  				KeyID:               "bad",
  1195  				KeyIDHashAlgorithms: []string{"sha256"},
  1196  				KeyType:             "invalid",
  1197  				KeyVal: KeyVal{
  1198  					Private: "invalid",
  1199  					Public:  "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
  1200  				},
  1201  				Scheme: "ed25519",
  1202  			},
  1203  			err: ErrUnsupportedKeyType,
  1204  		},
  1205  		{
  1206  			name: "keytype scheme mismatch",
  1207  			key: Key{
  1208  				KeyID:               "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
  1209  				KeyIDHashAlgorithms: []string{"sha256"},
  1210  				KeyType:             "ed25519",
  1211  				KeyVal: KeyVal{
  1212  					Private: "29ad59693fe94c9d623afbb66554b4f6bb248c47761689ada4875ebda94840ae393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
  1213  					Public:  "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
  1214  				},
  1215  				Scheme: "rsassa-pss-sha256",
  1216  			},
  1217  			err: ErrSchemeKeyTypeMismatch,
  1218  		},
  1219  		{
  1220  			name: "unsupported KeyIDHashAlgorithms",
  1221  			key: Key{
  1222  				KeyID:               "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
  1223  				KeyIDHashAlgorithms: []string{"sha128"},
  1224  				KeyType:             "ed25519",
  1225  				KeyVal: KeyVal{
  1226  					Private: "29ad59693fe94c9d623afbb66554b4f6bb248c47761689ada4875ebda94840ae393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
  1227  					Public:  "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
  1228  				},
  1229  				Scheme: "ed25519",
  1230  			},
  1231  			err: ErrUnsupportedKeyIDHashAlgorithms,
  1232  		},
  1233  	}
  1234  
  1235  	for _, table := range invalidTables {
  1236  		err := validateKey(table.key)
  1237  		if !errors.Is(err, table.err) {
  1238  			t.Errorf("test '%s' failed, expected error: '%s', got '%s'", table.name, table.err, err)
  1239  		}
  1240  	}
  1241  }
  1242  
  1243  func TestValidateKeyVal(t *testing.T) {
  1244  	tables := []struct {
  1245  		name string
  1246  		key  Key
  1247  		err  error
  1248  	}{
  1249  		{
  1250  			name: "invalid rsa private key",
  1251  			key: Key{
  1252  				KeyID:               "bad",
  1253  				KeyIDHashAlgorithms: []string{"sha256"},
  1254  				KeyType:             "rsa",
  1255  				KeyVal: KeyVal{
  1256  					Private: "invalid",
  1257  					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-----",
  1258  				},
  1259  				Scheme: "rsassa-pss-sha256",
  1260  			},
  1261  			err: ErrNoPEMBlock,
  1262  		},
  1263  		{
  1264  			name: "invalid rsa pub key",
  1265  			key: Key{
  1266  				KeyID:               "bad",
  1267  				KeyIDHashAlgorithms: []string{"sha256"},
  1268  				KeyType:             "rsa",
  1269  				KeyVal: KeyVal{
  1270  					Private: "",
  1271  					Public:  "invalid",
  1272  				},
  1273  				Scheme: "rsassa-pss-sha256",
  1274  			},
  1275  			err: ErrNoPEMBlock,
  1276  		},
  1277  		{
  1278  			name: "invalid ed25519 public key",
  1279  			key: Key{
  1280  				KeyID:               "bad",
  1281  				KeyIDHashAlgorithms: []string{"sha256"},
  1282  				KeyType:             "ed25519",
  1283  				KeyVal: KeyVal{
  1284  					Private: "invalid",
  1285  					Public:  "invalid",
  1286  				},
  1287  				Scheme: "ed25519",
  1288  			},
  1289  			err: ErrInvalidHexString,
  1290  		},
  1291  		{
  1292  			name: "invalid ed25519 private key",
  1293  			key: Key{
  1294  				KeyID:               "bad",
  1295  				KeyIDHashAlgorithms: []string{"sha256"},
  1296  				KeyType:             "ed25519",
  1297  				KeyVal: KeyVal{
  1298  					Private: "invalid",
  1299  					Public:  "393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c",
  1300  				},
  1301  				Scheme: "ed25519",
  1302  			},
  1303  			err: ErrInvalidHexString,
  1304  		},
  1305  		{
  1306  			name: "valid rsa public, but bad private key",
  1307  			key: Key{
  1308  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1309  				KeyIDHashAlgorithms: []string{"sha256"},
  1310  				KeyType:             "rsa",
  1311  				KeyVal: KeyVal{
  1312  					Private: "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB6fQnV71xKx6kFgJv\nYTMq0ytvWi2mDlYu6aNm1761c1OSInbBxBNb0ligpM65KyaeeRce6JR9eQW6TB6R\n+5pNzvOhgYkDgYYABAFy0CeDAyV/2mY1NqxLLgqEXSxaqM3fM8gYn/ZWzrLnO+1h\nK2QAanID3JuPff1NdhehhL/U1prXdyyaItA5X4ChkQHMTsiS/3HkWRuLR8L22SGs\nB+7KqOeO5ELkqHO5tsy4kvsNrmersCGRQGY6A5V/0JFhP1u1JUvAVVhfRbdQXuu3\nrw==\n-----END PRIVATE KEY-----\n",
  1313  					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-----",
  1314  				},
  1315  				Scheme: "rsassa-pss-sha256",
  1316  			},
  1317  			err: ErrKeyKeyTypeMismatch,
  1318  		},
  1319  		{
  1320  			name: "valid ecdsa public key, but invalid ecdsa private key",
  1321  			key: Key{
  1322  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1323  				KeyIDHashAlgorithms: []string{"sha256"},
  1324  				KeyType:             "ecdsa",
  1325  				KeyVal: KeyVal{
  1326  					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-----",
  1327  					Public:  "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBctAngwMlf9pmNTasSy4KhF0sWqjN\n3zPIGJ/2Vs6y5zvtYStkAGpyA9ybj339TXYXoYS/1Naa13csmiLQOV+AoZEBzE7I\nkv9x5Fkbi0fC9tkhrAfuyqjnjuRC5KhzubbMuJL7Da5nq7AhkUBmOgOVf9CRYT9b\ntSVLwFVYX0W3UF7rt68=\n-----END PUBLIC KEY-----\n",
  1328  				},
  1329  				Scheme: "ecdsa",
  1330  			},
  1331  			err: ErrKeyKeyTypeMismatch,
  1332  		},
  1333  		{
  1334  			name: "rsa key, but with ed25519 private key",
  1335  			key: Key{
  1336  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1337  				KeyIDHashAlgorithms: []string{"sha256"},
  1338  				KeyType:             "rsa",
  1339  				KeyVal: KeyVal{
  1340  					Private: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICmtWWk/6UydYjr7tmVUtPa7JIxHdhaJraSHXr2pSECu\n-----END PRIVATE KEY-----\n",
  1341  					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-----",
  1342  				},
  1343  				Scheme: "rsassa-pss-sha256",
  1344  			},
  1345  			err: ErrInvalidKey,
  1346  		},
  1347  		{
  1348  			name: "unsupported key type",
  1349  			key: Key{
  1350  				KeyID:               "",
  1351  				KeyIDHashAlgorithms: nil,
  1352  				KeyType:             "invalid",
  1353  				KeyVal:              KeyVal{},
  1354  				Scheme:              "",
  1355  			},
  1356  			err: ErrUnsupportedKeyType,
  1357  		},
  1358  		{
  1359  			name: "rsa key type, but ed25519 key",
  1360  			key: Key{
  1361  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1362  				KeyIDHashAlgorithms: []string{"sha256"},
  1363  				KeyType:             "rsa",
  1364  				KeyVal: KeyVal{
  1365  					Private: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICmtWWk/6UydYjr7tmVUtPa7JIxHdhaJraSHXr2pSECu\n-----END PRIVATE KEY-----\n",
  1366  					Public:  "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAOT5nGyAPlkxJCD00qGf12YnsHGnfe2Z1j+RxyFkbE5w=\n-----END PUBLIC KEY-----\n",
  1367  				},
  1368  				Scheme: "rsassa-pss-sha256",
  1369  			},
  1370  			err: ErrInvalidKey,
  1371  		},
  1372  		{
  1373  			name: "rsa key, but not ecdsa key type",
  1374  			key: Key{
  1375  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1376  				KeyIDHashAlgorithms: []string{"sha256"},
  1377  				KeyType:             "ecdsa",
  1378  				KeyVal: KeyVal{
  1379  					Private: "",
  1380  					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-----",
  1381  				},
  1382  				Scheme: "ecdsa",
  1383  			},
  1384  			err: ErrKeyKeyTypeMismatch,
  1385  		},
  1386  		{
  1387  			name: "ecdsa key, but rsa key type",
  1388  			key: Key{
  1389  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1390  				KeyIDHashAlgorithms: []string{"sha256"},
  1391  				KeyType:             "rsa",
  1392  				KeyVal: KeyVal{
  1393  					Private: "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB6fQnV71xKx6kFgJv\nYTMq0ytvWi2mDlYu6aNm1761c1OSInbBxBNb0ligpM65KyaeeRce6JR9eQW6TB6R\n+5pNzvOhgYkDgYYABAFy0CeDAyV/2mY1NqxLLgqEXSxaqM3fM8gYn/ZWzrLnO+1h\nK2QAanID3JuPff1NdhehhL/U1prXdyyaItA5X4ChkQHMTsiS/3HkWRuLR8L22SGs\nB+7KqOeO5ELkqHO5tsy4kvsNrmersCGRQGY6A5V/0JFhP1u1JUvAVVhfRbdQXuu3\nrw==\n-----END PRIVATE KEY-----\n",
  1394  					Public:  "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBctAngwMlf9pmNTasSy4KhF0sWqjN\n3zPIGJ/2Vs6y5zvtYStkAGpyA9ybj339TXYXoYS/1Naa13csmiLQOV+AoZEBzE7I\nkv9x5Fkbi0fC9tkhrAfuyqjnjuRC5KhzubbMuJL7Da5nq7AhkUBmOgOVf9CRYT9b\ntSVLwFVYX0W3UF7rt68=\n-----END PUBLIC KEY-----\n",
  1395  				},
  1396  				Scheme: "rsassa-pss-sha256",
  1397  			},
  1398  			err: ErrKeyKeyTypeMismatch,
  1399  		},
  1400  		{
  1401  			name: "ecdsa key, but rsa key type",
  1402  			key: Key{
  1403  				KeyID:               "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401",
  1404  				KeyIDHashAlgorithms: []string{"sha256"},
  1405  				KeyType:             "ecdsa",
  1406  				KeyVal: KeyVal{
  1407  					Private: "-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIB6fQnV71xKx6kFgJv\nYTMq0ytvWi2mDlYu6aNm1761c1OSInbBxBNb0ligpM65KyaeeRce6JR9eQW6TB6R\n+5pNzvOhgYkDgYYABAFy0CeDAyV/2mY1NqxLLgqEXSxaqM3fM8gYn/ZWzrLnO+1h\nK2QAanID3JuPff1NdhehhL/U1prXdyyaItA5X4ChkQHMTsiS/3HkWRuLR8L22SGs\nB+7KqOeO5ELkqHO5tsy4kvsNrmersCGRQGY6A5V/0JFhP1u1JUvAVVhfRbdQXuu3\nrw==\n-----END PRIVATE KEY-----\n",
  1408  					Public:  "-----BEGIN PUBLIC KEY-----\nMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBctAngwMlf9pmNTasSy4KhF0sWqjN\n3zPIGJ/2Vs6y5zvtYStkAGpyA9ybj339TXYXoYS/1Naa13csmiLQOV+AoZEBzE7I\nkv9x5Fkbi0fC9tkhrAfuyqjnjuRC5KhzubbMuJL7Da5nq7AhkUBmOgOVf9CRYT9b\ntSVLwFVYX0W3UF7rt68=\n-----END PUBLIC KEY-----\n",
  1409  				},
  1410  				Scheme: "ecdsa",
  1411  			},
  1412  			err: nil,
  1413  		},
  1414  	}
  1415  	for _, table := range tables {
  1416  		err := validateKeyVal(table.key)
  1417  		if !errors.Is(err, table.err) {
  1418  			t.Errorf("test '%s' failed, expected error: '%s', got '%s'", table.name, table.err, err)
  1419  		}
  1420  	}
  1421  }
  1422  
  1423  func TestMatchKeyTypeScheme(t *testing.T) {
  1424  	tables := []struct {
  1425  		name string
  1426  		key  Key
  1427  		err  error
  1428  	}{
  1429  		{name: "test for unsupported key type",
  1430  			key: Key{
  1431  				KeyID:               "",
  1432  				KeyIDHashAlgorithms: nil,
  1433  				KeyType:             "invalid",
  1434  				KeyVal:              KeyVal{},
  1435  				Scheme:              "",
  1436  			},
  1437  			err: ErrUnsupportedKeyType,
  1438  		},
  1439  		{
  1440  			name: "test for scheme key type mismatch",
  1441  			key: Key{
  1442  				KeyID:               "",
  1443  				KeyIDHashAlgorithms: nil,
  1444  				KeyType:             "rsa",
  1445  				KeyVal:              KeyVal{},
  1446  				Scheme:              "ed25519",
  1447  			},
  1448  			err: ErrSchemeKeyTypeMismatch,
  1449  		},
  1450  	}
  1451  	for _, table := range tables {
  1452  		err := matchKeyTypeScheme(table.key)
  1453  		if !errors.Is(err, table.err) {
  1454  			t.Errorf("%s returned wrong error. We got: %s, we should have got: %s", table.name, err, table.err)
  1455  		}
  1456  	}
  1457  }
  1458  
  1459  func TestValidatePublicKey(t *testing.T) {
  1460  	validTables := []struct {
  1461  		name string
  1462  		key  Key
  1463  	}{
  1464  		{
  1465  			name: "test with valid key",
  1466  			key: Key{
  1467  				KeyID:               "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
  1468  				KeyIDHashAlgorithms: []string{"sha512"},
  1469  				KeyType:             "ed25519",
  1470  				KeyVal: KeyVal{
  1471  					Private: "",
  1472  					Public:  "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAOT5nGyAPlkxJCD00qGf12YnsHGnfe2Z1j+RxyFkbE5w=\n-----END PUBLIC KEY-----\n",
  1473  				},
  1474  				Scheme: "ed25519",
  1475  			},
  1476  		},
  1477  	}
  1478  	for _, table := range validTables {
  1479  		err := validatePublicKey(table.key)
  1480  		if err != nil {
  1481  			t.Errorf("%s returned error %s, instead of nil", table.name, err)
  1482  		}
  1483  	}
  1484  
  1485  	invalidTables := []struct {
  1486  		name string
  1487  		key  Key
  1488  		err  error
  1489  	}{
  1490  		{
  1491  			name: "test with valid key",
  1492  			key: Key{
  1493  				KeyID:               "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6",
  1494  				KeyIDHashAlgorithms: []string{"sha512"},
  1495  				KeyType:             "ed25519",
  1496  				KeyVal: KeyVal{
  1497  					Private: "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEICmtWWk/6UydYjr7tmVUtPa7JIxHdhaJraSHXr2pSECu\n-----END PRIVATE KEY-----\n",
  1498  					Public:  "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAOT5nGyAPlkxJCD00qGf12YnsHGnfe2Z1j+RxyFkbE5w=\n-----END PUBLIC KEY-----\n",
  1499  				},
  1500  				Scheme: "ed25519",
  1501  			},
  1502  			err: ErrNoPublicKey,
  1503  		},
  1504  	}
  1505  	for _, table := range invalidTables {
  1506  		err := validatePublicKey(table.key)
  1507  		if err != table.err {
  1508  			t.Errorf("%s returned unexpected error %s, we should got: %s", table.name, err, table.err)
  1509  		}
  1510  	}
  1511  }