diff --git a/pkg/remote/sshclient.go b/pkg/remote/sshclient.go index b1c9faca21..20cdd3c490 100644 --- a/pkg/remote/sshclient.go +++ b/pkg/remote/sshclient.go @@ -310,6 +310,8 @@ func createPublicKeyCallback(connCtx context.Context, sshKeywords *wconfig.ConnK if len(*authSockSignersPtr) != 0 { authSockSigner := (*authSockSignersPtr)[0] *authSockSignersPtr = (*authSockSignersPtr)[1:] + blocklogger.Infof(connCtx, "[conndebug] trying agent identity %s %s...\n", + authSockSigner.PublicKey().Type(), ssh.FingerprintSHA256(authSockSigner.PublicKey())) return []ssh.Signer{authSockSigner}, nil } @@ -772,10 +774,19 @@ func createClientConfig(connCtx context.Context, sshKeywords *wconfig.ConnKeywor if !utilfn.SafeDeref(sshKeywords.SshIdentitiesOnly) && agentPath != "" { conn, err := dialIdentityAgent(agentPath) if err != nil { + blocklogger.Infof(connCtx, "[conndebug] failed to open identity agent socket %q: %v\n", agentPath, err) log.Printf("Failed to open Identity Agent Socket %q: %v", agentPath, err) } else { agentClient = agent.NewClient(conn) - authSockSigners, _ = agentClient.Signers() + agentSigners, err := agentClient.Signers() + if err != nil { + blocklogger.Infof(connCtx, "[conndebug] failed to list identity agent keys: %v\n", err) + log.Printf("Failed to list identity agent keys: %v", err) + } + blocklogger.Infof(connCtx, "[conndebug] identity agent provided %d identities\n", len(agentSigners)) + for _, agentSigner := range agentSigners { + authSockSigners = append(authSockSigners, failoverSigner{signer: agentSigner, connCtx: connCtx}) + } } } diff --git a/pkg/remote/sshsigners.go b/pkg/remote/sshsigners.go new file mode 100644 index 0000000000..aa635fd8d1 --- /dev/null +++ b/pkg/remote/sshsigners.go @@ -0,0 +1,51 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +package remote + +import ( + "context" + "io" + + "github.com/wavetermdev/waveterm/pkg/blocklogger" + "golang.org/x/crypto/ssh" +) + +type failoverSigner struct { + signer ssh.Signer + connCtx context.Context +} + +func (f failoverSigner) PublicKey() ssh.PublicKey { + return f.signer.PublicKey() +} + +func (f failoverSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) { + sig, err := f.signer.Sign(rand, data) + if err == nil { + return sig, nil + } + blocklogger.Infof(f.connCtx, "[conndebug] agent signing failed for key %s %s (%v); continuing with next identity\n", + f.signer.PublicKey().Type(), ssh.FingerprintSHA256(f.signer.PublicKey()), err) + return f.invalidSignature(), nil +} + +func (f failoverSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*ssh.Signature, error) { + if as, ok := f.signer.(ssh.AlgorithmSigner); ok { + sig, err := as.SignWithAlgorithm(rand, data, algorithm) + if err == nil { + return sig, nil + } + blocklogger.Infof(f.connCtx, "[conndebug] agent signing failed for key %s %s (%v); continuing with next identity\n", + f.signer.PublicKey().Type(), ssh.FingerprintSHA256(f.signer.PublicKey()), err) + return f.invalidSignature(), nil + } + return f.Sign(rand, data) +} + +func (f failoverSigner) invalidSignature() *ssh.Signature { + return &ssh.Signature{ + Format: f.signer.PublicKey().Type(), + Blob: []byte("invalid-signature-identity-skipped"), + } +}