// 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) }