github.com/in-toto/in-toto-golang@v0.9.1-0.20240517212500-990269f763cf/in_toto/keylib_test.go (about)

     1  package in_toto
     2  
     3  import (
     4  	"crypto/x509"
     5  	"errors"
     6  	"os"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  )
    11  
    12  // TestLoadKey makes sure, that our LoadKey function loads keys correctly
    13  // and that the key IDs of private and public key match.
    14  func TestLoadKey(t *testing.T) {
    15  	validTables := []struct {
    16  		name           string
    17  		path           string
    18  		scheme         string
    19  		hashAlgorithms []string
    20  		expectedKeyID  string
    21  	}{
    22  		{"rsa public key", "alice.pub", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "70ca5750c2eda80b18f41f4ec5f92146789b5d68dd09577be422a0159bd13680"},
    23  		{"rsa private key", "dan", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401"},
    24  		{"rsa public key", "dan.pub", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401"},
    25  		{"ed25519 private key", "carol", "ed25519", []string{"sha256", "sha512"}, "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6"},
    26  		{"ed25519 public key", "carol.pub", "ed25519", []string{"sha256", "sha512"}, "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6"},
    27  		{"ecdsa private key (P521)", "frank", "ecdsa-sha2-nistp521", []string{"sha256", "sha512"}, "434cf7c5b168f6ea4c7e6e67afa74a02625310530f1664f761637bdc7ad8f8df"},
    28  		{"ecdsa public key (P521)", "frank.pub", "ecdsa-sha2-nistp521", []string{"sha256", "sha512"}, "434cf7c5b168f6ea4c7e6e67afa74a02625310530f1664f761637bdc7ad8f8df"},
    29  		{"ecdsa private key (P384)", "grace", "ecdsa-sha2-nistp384", []string{"sha256", "sha512"}, "a5522ebccd492f64e6ec0bbcb5eb782708f6e26709a3712e64fff108b98e5142"},
    30  		{"ecdsa public key (P384)", "grace.pub", "ecdsa-sha2-nistp384", []string{"sha256", "sha512"}, "a5522ebccd492f64e6ec0bbcb5eb782708f6e26709a3712e64fff108b98e5142"},
    31  		{"ecdsa private key (P224)", "heidi", "ecdsa-sha2-nistp224", []string{"sha256", "sha512"}, "fae849ef9247cc7d19ebd33ab63b5d18a31357508fd82d8ad2aad6fdcc584bd7"},
    32  		{"ecdsa public key (P224)", "heidi.pub", "ecdsa-sha2-nistp224", []string{"sha256", "sha512"}, "fae849ef9247cc7d19ebd33ab63b5d18a31357508fd82d8ad2aad6fdcc584bd7"},
    33  		{"rsa public key from certificate", "example.com.write-code.cert.pem", "rsassa-pss-sha256", []string{"sha256", "sha512"}, "4979dea7a8467cbe0299693703b81d490854143b859a469ec0f6349e7bdf582a"},
    34  	}
    35  	for _, table := range validTables {
    36  		var key Key
    37  		err := key.LoadKey(table.path, table.scheme, table.hashAlgorithms)
    38  		if err != nil {
    39  			t.Errorf("failed key.LoadKey() for %s %s. Error: %s", table.name, table.path, err)
    40  		}
    41  		if table.expectedKeyID != key.KeyID {
    42  			t.Errorf("keyID for %s %s does not match expected keyID: %s. Got keyID: %s", table.name, table.path, table.expectedKeyID, key.KeyID)
    43  		}
    44  	}
    45  }
    46  
    47  // TestLoadKeyDefaults makes sure our function loads keys correctly
    48  // with the expected default schemes
    49  func TestLoadKeyDefaults(t *testing.T) {
    50  	validTables := []struct {
    51  		name           string
    52  		path           string
    53  		expectedKeyID  string
    54  		expectedScheme string
    55  	}{
    56  		{"rsa public key", "alice.pub", "70ca5750c2eda80b18f41f4ec5f92146789b5d68dd09577be422a0159bd13680", rsassapsssha256Scheme},
    57  		{"rsa private key", "dan", "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401", rsassapsssha256Scheme},
    58  		{"rsa public key", "dan.pub", "b7d643dec0a051096ee5d87221b5d91a33daa658699d30903e1cefb90c418401", rsassapsssha256Scheme},
    59  		{"ed25519 private key", "carol", "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6", ed25519Scheme},
    60  		{"ed25519 public key", "carol.pub", "be6371bc627318218191ce0780fd3183cce6c36da02938a477d2e4dfae1804a6", ed25519Scheme},
    61  		{"ecdsa private key (P521)", "frank", "0ab02fd8a1195d902d4e71df38123be0d3fa9ea45ebc6e1246d8e82179acb6dd", ecdsaSha2nistp256},
    62  		{"ecdsa public key (P521)", "frank.pub", "0ab02fd8a1195d902d4e71df38123be0d3fa9ea45ebc6e1246d8e82179acb6dd", ecdsaSha2nistp256},
    63  		{"ecdsa private key (P384)", "grace", "a5fe82bffd11c43cd25b41b427496dea8eb61505bfa11907a6a565ebb00fa323", ecdsaSha2nistp256},
    64  		{"ecdsa public key (P384)", "grace.pub", "a5fe82bffd11c43cd25b41b427496dea8eb61505bfa11907a6a565ebb00fa323", ecdsaSha2nistp256},
    65  		{"ecdsa private key (P224)", "heidi", "337f2a2bed46e863a68f17ae0e3e96756eca87c38080d872c5824493cec1ce1a", ecdsaSha2nistp256},
    66  		{"ecdsa public key (P224)", "heidi.pub", "337f2a2bed46e863a68f17ae0e3e96756eca87c38080d872c5824493cec1ce1a", ecdsaSha2nistp256},
    67  		{"rsa public key from certificate", "example.com.write-code.cert.pem", "4979dea7a8467cbe0299693703b81d490854143b859a469ec0f6349e7bdf582a", rsassapsssha256Scheme},
    68  	}
    69  	for _, table := range validTables {
    70  		var key Key
    71  		err := key.LoadKeyDefaults(table.path)
    72  		if err != nil {
    73  			t.Errorf("failed key.LoadKeyDefaults() for %s %s. Error: %s", table.name, table.path, err)
    74  		}
    75  		if table.expectedKeyID != key.KeyID {
    76  			t.Errorf("keyID for %s %s does not match expected keyID: %s. Got keyID: %s", table.name, table.path, table.expectedKeyID, key.KeyID)
    77  		}
    78  		if table.expectedScheme != key.Scheme {
    79  			t.Errorf("scheme for %s %s does not match expected scheme: %s. Got scheme %s", table.name, table.path, table.expectedScheme, key.Scheme)
    80  		}
    81  	}
    82  }
    83  
    84  // TestLoadKeyReader makes sure, that our LoadKeyReader function loads keys correctly
    85  // and that the key IDs of private and public key match.
    86  func TestLoadKeyReader(t *testing.T) {
    87  	var key Key
    88  	if err := key.LoadKeyReader(nil, "ed25519", []string{"sha256", "sha512"}); err != ErrNoPEMBlock {
    89  		t.Errorf("unexpected error loading key: %s", err)
    90  	}
    91  }
    92  
    93  // TestLoadKeyErrors tests the LoadKey functions for the most popular errors:
    94  //
    95  //   - os.ErrNotExist (triggered, when the file does not exist)
    96  //   - ErrNoPEMBlock (for example if the passed file is not a PEM block)
    97  //   - ErrFailedPEMParsing (for example if we pass an EC key, instead a key in PKCS8 format)
    98  func TestLoadKeyErrors(t *testing.T) {
    99  	invalidTables := []struct {
   100  		name           string
   101  		path           string
   102  		scheme         string
   103  		hashAlgorithms []string
   104  		err            error
   105  	}{
   106  		{"not existing file", "inToToRocks", "rsassa-pss-sha256", []string{"sha256", "sha512"}, os.ErrNotExist},
   107  		{"existing, but invalid file", "demo.layout", "ecdsa-sha2-nistp521", []string{"sha512"}, ErrNoPEMBlock},
   108  		{"EC private key file", "erin", "ecdsa-sha2-nistp521", []string{"sha256", "sha512"}, ErrFailedPEMParsing},
   109  		{"valid ed25519 private key, but invalid scheme", "carol", "", []string{"sha256"}, ErrEmptyKeyField},
   110  		{"valid ed25519 public key, but invalid scheme", "carol.pub", "", []string{"sha256"}, ErrEmptyKeyField},
   111  		{"valid rsa private key, but invalid scheme", "dan", "rsassa-psa-sha256", nil, ErrSchemeKeyTypeMismatch},
   112  		{"valid rsa public key, but invalid scheme", "dan.pub", "rsassa-psa-sha256", nil, ErrSchemeKeyTypeMismatch},
   113  		{"valid ecdsa private key, but invalid scheme", "frank", "ecdsa-sha-nistp256", nil, ErrSchemeKeyTypeMismatch},
   114  		{"valid ecdsa public key, but invalid scheme", "frank.pub", "ecdsa-sha-nistp256", nil, ErrSchemeKeyTypeMismatch},
   115  	}
   116  
   117  	for _, table := range invalidTables {
   118  		var key Key
   119  		err := key.LoadKey(table.path, table.scheme, table.hashAlgorithms)
   120  		if !errors.Is(err, table.err) {
   121  			t.Errorf("failed LoadKey() for %s %s, got error: %s. Should have: %s", table.name, table.path, err, table.err)
   122  		}
   123  	}
   124  }
   125  
   126  // TestLoadKeyDefaultsErrors tests the LoadKeyDefaults functions for the most popular errors:
   127  //
   128  //   - os.ErrNotExist (triggered, when the file does not exist)
   129  //   - ErrNoPEMBlock (for example if the passed file is not a PEM block)
   130  //   - ErrFailedPEMParsing (for example if we pass an EC key, instead a key in PKCS8 format)
   131  func TestLoadKeyDefaultsErrors(t *testing.T) {
   132  	invalidTables := []struct {
   133  		name string
   134  		path string
   135  		err  error
   136  	}{
   137  		{"not existing file", "inToToRocks", os.ErrNotExist},
   138  		{"existing, but invalid file", "demo.layout", ErrNoPEMBlock},
   139  		{"EC private key file", "erin", ErrFailedPEMParsing},
   140  	}
   141  
   142  	for _, table := range invalidTables {
   143  		var key Key
   144  		err := key.LoadKeyDefaults(table.path)
   145  		if !errors.Is(err, table.err) {
   146  			t.Errorf("failed LoadKeyDefaults() for %s %s, got error: %s. Should have: %s", table.name, table.path, err, table.err)
   147  		}
   148  	}
   149  }
   150  
   151  func TestSetKeyComponentsErrors(t *testing.T) {
   152  	invalidTables := []struct {
   153  		name                string
   154  		pubkeyBytes         []byte
   155  		privateKeyBytes     []byte
   156  		keyType             string
   157  		scheme              string
   158  		KeyIDHashAlgorithms []string
   159  		err                 error
   160  	}{
   161  		{"test invalid key type", []byte{}, []byte{}, "yolo", "ed25519", []string{"sha512"}, ErrUnsupportedKeyType},
   162  		{"invalid scheme", []byte("393e671b200f964c49083d34a867f5d989ec1c69df7b66758fe471c8591b139c"), []byte{}, "ed25519", "", []string{"sha256"}, ErrEmptyKeyField},
   163  	}
   164  
   165  	for _, table := range invalidTables {
   166  		var key Key
   167  		err := key.setKeyComponents(table.pubkeyBytes, table.privateKeyBytes, table.keyType, table.scheme, table.KeyIDHashAlgorithms)
   168  		if !errors.Is(err, table.err) {
   169  			t.Errorf("'%s' failed, should have: '%s', got: '%s'", table.name, ErrUnsupportedKeyType, err)
   170  		}
   171  	}
   172  }
   173  
   174  func TestVerifyCertificateTrust(t *testing.T) {
   175  	var rootKey, intermediateKey, leafKey Key
   176  	err := rootKey.LoadKeyDefaults("root.cert.pem")
   177  	assert.Nil(t, err, "unexpected error loading root")
   178  	err = intermediateKey.LoadKeyDefaults("example.com.intermediate.cert.pem")
   179  	assert.Nil(t, err, "unexpected error loading intermediate")
   180  	err = leafKey.LoadKeyDefaults("example.com.write-code.cert.pem")
   181  	assert.Nil(t, err, "unexpected error loading leaf")
   182  
   183  	rootPool := x509.NewCertPool()
   184  	ok := rootPool.AppendCertsFromPEM([]byte(rootKey.KeyVal.Certificate))
   185  	assert.True(t, ok, "unexpected error adding cert to root pool")
   186  	intermediatePool := x509.NewCertPool()
   187  	ok = intermediatePool.AppendCertsFromPEM([]byte(intermediateKey.KeyVal.Certificate))
   188  	assert.True(t, ok, "unexpected error adding cert to root pool")
   189  
   190  	_, possibleLeafCert, err := decodeAndParse([]byte(leafKey.KeyVal.Certificate))
   191  	assert.Nil(t, err, "unexpected error parsing leaf certificate")
   192  	leafCert, ok := possibleLeafCert.(*x509.Certificate)
   193  	assert.True(t, ok, "parseKey didn't return a x509 certificate")
   194  
   195  	// Test the happy path
   196  	_, err = VerifyCertificateTrust(leafCert, rootPool, intermediatePool)
   197  	assert.Nil(t, err, "unexpected error verifying trust")
   198  
   199  	// Test with no intermediate connecting the leaf to the root
   200  	_, err = VerifyCertificateTrust(leafCert, rootPool, x509.NewCertPool())
   201  	assert.NotNil(t, err, "expected error with missing intermediate")
   202  
   203  	// Test with no root
   204  	_, err = VerifyCertificateTrust(leafCert, x509.NewCertPool(), intermediatePool)
   205  	assert.NotNil(t, err, "expected error with missing root")
   206  }