gittuf/internal/signerverifier/ssh/ssh_test.go
Aditya Sirish A Yelgundhalli 2f0be5c46f
*: Refactor TUF
This is a massive commit that isn't easy to split up, my apologies to
reviewers. Here's everything that's happening.

First, the base tuf package now includes interfaces for RootMetadata,
TargetsMetadata, Rule, and Principal. The first two are self-explanatory. Rule
represents some protection rule, currently matched by the Delegation schema,
while Principal defines a new take on who a trusted party is. Existing schemas
have been moved into a v01 subpackage. v01 also includes a Key type based on
signerverifier.SSLibKey which implements the Principal interface. This means
that expectations elsewhere (such as in repository and policy) re a principal
can be met by existing policy metadata.

Second, with most of the policy metadata manipulations having moved to the tuf
package, this commit drops them from the policy package as they were thin
wrappers. While we originally kept them around for the purposes of migrating
versions when a repository must move from the old metadata schema to a newer
one, it doesn't make sense to implement this in every individual manipulation
function.

Finally, the rest of the packages that handle keys (for adding to metadata or
for signing / verifying) have been updated to use either
signerverifier.SSLibKey directly or the new Principal interface, depending on
what the purpose is. For now, the idea is to continue using the
signerverifier.SSLibKey representation of a key itself for the signature
verification flows, though we may eventually move that into gittuf rather than
rely on go-securesystemslib. Note that some of the transitions have been
included in this commit for compatibility reasons, and subsequent PRs will
update that. For example, the GitHub app pull request approval attestation must
be updated to not use tufv01.Key objects to represent approvers.

Signed-off-by: Aditya Sirish A Yelgundhalli <ayelgundhall@bloomberg.net>
2024-10-15 12:58:44 -04:00

149 lines
4.3 KiB
Go

// Copyright The gittuf Authors
// SPDX-License-Identifier: Apache-2.0
package ssh
import (
"context"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
artifacts "github.com/gittuf/gittuf/internal/testartifacts"
"github.com/secure-systems-lab/go-securesystemslib/signerverifier"
"github.com/stretchr/testify/assert"
)
// Basic smoke test for ssh package for all supported keys
func TestSSH(t *testing.T) {
keyidRSA := "SHA256:ESJezAOo+BsiEpddzRXS6+wtF16FID4NCd+3gj96rFo"
keyidECDSA := "SHA256:oNYBImx035m3rl1Sn/+j5DPrlS9+zXn7k3mjNrC5eto"
keyidEd25519 := "SHA256:cewFulOIcROWnolPTGEQXG4q7xvLIn3kNTCMqdfoP4E"
tests := []struct {
keyName string
keyBytes []byte
keyID string
}{
{"rsa", artifacts.SSHRSAPrivate, keyidRSA},
{"rsa.pub", artifacts.SSHRSAPublicSSH, keyidRSA},
{"rsa_enc", artifacts.SSHRSAPrivateEnc, keyidRSA},
{"rsa_enc.pub", artifacts.SSHRSAPublicSSH, keyidRSA},
{"ecdsa", artifacts.SSHECDSAPrivate, keyidECDSA},
{"ecdsa.pub", artifacts.SSHECDSAPublicSSH, keyidECDSA},
{"ecdsa_enc", artifacts.SSHECDSAPrivateEnc, keyidECDSA},
{"ecdsa_enc.pub", artifacts.SSHECDSAPublicSSH, keyidECDSA},
{"ed25519", artifacts.SSHED25519Private, keyidEd25519},
{"ed25519.pub", artifacts.SSHED25519PublicSSH, keyidEd25519},
{"ed25519_enc", artifacts.SSHED25519PrivateEnc, keyidEd25519},
{"ed25519_enc.pub", artifacts.SSHED25519PublicSSH, keyidEd25519},
}
// Setup tests
tmpDir := t.TempDir()
// Write script to mock password prompt
scriptPath := filepath.Join(tmpDir, "askpass.sh")
if err := os.WriteFile(scriptPath, artifacts.AskpassScript, 0o500); err != nil { //nolint:gosec
t.Fatal(err)
}
// Write test key pairs to temp dir with permissions required by ssh-keygen
for _, test := range tests {
keyPath := filepath.Join(tmpDir, test.keyName)
if err := os.WriteFile(keyPath, test.keyBytes, 0o600); err != nil {
t.Fatal(err)
}
}
data := []byte("DATA")
notData := []byte("NOT DATA")
// Run tests
for _, test := range tests {
t.Run(test.keyName, func(t *testing.T) {
if strings.Contains(test.keyName, "_enc") {
if runtime.GOOS == "windows" {
t.Skip("TODO: test encrypted keys on windows")
}
t.Setenv("SSH_ASKPASS", scriptPath)
t.Setenv("SSH_ASKPASS_REQUIRE", "force")
}
keyPath := filepath.Join(tmpDir, test.keyName)
key, err := NewKeyFromFile(keyPath)
if err != nil {
t.Fatalf("%s: %v", test.keyName, err)
}
assert.Equal(t,
key.KeyID,
test.keyID,
)
verifier, err := NewVerifierFromKey(key)
if err != nil {
t.Fatalf("%s: %v", test.keyName, err)
}
signer, err := NewSignerFromFile(keyPath)
if err != nil {
t.Fatalf("%s: %v", test.keyName, err)
}
sig, err := signer.Sign(context.Background(), data)
if err != nil {
t.Fatalf("%s: %v", test.keyName, err)
}
err = verifier.Verify(context.Background(), data, sig)
if err != nil {
t.Fatalf("%s: %v", test.keyName, err)
}
err = verifier.Verify(context.Background(), notData, sig)
if err == nil {
t.Fatalf("%s: %v", test.keyName, err)
}
})
}
}
// Test parseSSH2Key helper function (rsa only)
func TestParseSSH2Key(t *testing.T) {
data := `---- BEGIN SSH2 PUBLIC KEY ----
Comment: "3072-bit RSA, converted by me@me.me from OpenSSH"
AAAAB3NzaC1yc2EAAAADAQABAAABgQDEI4rdCY/zA3oOMet1JYJ+VugUapNfj7hcAZem1C
Rusd5FTiWVmNh4yywgA+1JWDsBnyLfbOZBiz4fiQQ++bRF/mDXQx2Qr2xgCS27tNyyv8tf
ERGuglAu69T7aLsfPGn4WCaVX3+OuALZVaQl/F5MzoDkiaZkCsBrVZkfL3393Zlhseb/bY
87f7UOwArq3WMMK9Qp0cO8/8rsZnzu3nFClYSILKUx7Vrf7uSaUtl39Dh/QMX1m6Ax0Mh4
3gMnk+Fbrhai+BWo3Y58A5+LBUL3jqDkmXzFvhYJgGKISU5nfKCHDDqlug+l5wJmGus1G8
jZ5uY7s2ZHS5yumPQNoCIZztmLm0DgQqNN4J+Yub5+L6yCgA1Q6mKq/631/DyHvF8e5Gln
COb1zE7zaJacJ42tNdVq7Z3x+Hik9PRfgBPt1oF41SFSCp0YRPLxLMFdTjNgV3HZXVNlq6
6IhyoDZ2hjd5XmMmq7h1a8IybBsItJ8Ikk4X12vIzCSqOlylZS4+U=
---- END SSH2 PUBLIC KEY ----`
key, err := parseSSH2Key(data)
if err != nil {
t.Fatalf("%v", err)
}
assert.Equal(t, key.Type(), "ssh-rsa")
}
func TestNewVerifierFromKey(t *testing.T) {
sslibKey := &signerverifier.SSLibKey{
KeyID: "SHA256:cewFulOIcROWnolPTGEQXG4q7xvLIn3kNTCMqdfoP4E",
KeyType: "ssh",
Scheme: "ssh-ed25519",
KeyVal: signerverifier.KeyVal{Public: "AAAAC3NzaC1lZDI1NTE5AAAAIPu3Q15xYZOCg7kzYoApSgy/fPumLVHgSQO+bjSwdGQg"},
}
verifier, err := NewVerifierFromKey(sslibKey)
if err != nil {
t.Fatalf("%v", err)
}
keyid, _ := verifier.KeyID()
assert.Equal(t, sslibKey.KeyID, keyid)
}