Skip to content

Instantly share code, notes, and snippets.

@jeffreytolar
Created April 6, 2022 17:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jeffreytolar/9fd9ed8c01802fb7d36d98ed268f3a18 to your computer and use it in GitHub Desktop.
Save jeffreytolar/9fd9ed8c01802fb7d36d98ed268f3a18 to your computer and use it in GitHub Desktop.
module test
go 1.17
require (
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3 // indirect
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect
)
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3 h1:LRxW8pdmWmyhoNh+TxUjxsAinGtCsVGjsl3xg6zoRSs=
github.com/cbeuw/connutil v0.0.0-20200411215123-966bfaa51ee3/go.mod h1:6jR2SzckGv8hIIS9zWJ160mzGVVOYp4AXZMDtacL6LE=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o=
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
package main
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"log"
"net"
"time"
"github.com/cbeuw/connutil"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/agent"
)
func check(err error) {
if err != nil {
panic(err)
}
}
func newSigner() (*ecdsa.PrivateKey, ssh.Signer) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
check(err)
signer, err := ssh.NewSignerFromKey(key)
check(err)
return key, signer
}
func makeCert() *ssh.Certificate {
cert := &ssh.Certificate{
Key: userSigner.PublicKey(),
Serial: 1,
CertType: ssh.UserCert,
KeyId: "testkey",
ValidPrincipals: []string{"test"},
ValidAfter: uint64(time.Now().Add(-time.Hour).Unix()),
ValidBefore: uint64(time.Now().Add(time.Hour).Unix()),
}
err := cert.SignCert(rand.Reader, userCASigner)
check(err)
return cert
}
var (
userCAKey, userCASigner = newSigner()
hostKey, hostSigner = newSigner()
userKey, userSigner = newSigner()
userCert = makeCert()
)
func server(nConn net.Conn) {
config := &ssh.ServerConfig{
PublicKeyCallback: (&ssh.CertChecker{
IsUserAuthority: func(auth ssh.PublicKey) bool {
return bytes.Equal(auth.Marshal(), userCASigner.PublicKey().Marshal())
},
}).Authenticate,
}
config.AddHostKey(hostSigner)
_, _, _, err := ssh.NewServerConn(nConn, config)
check(err)
log.Print("[server] Completed handshake")
}
func client(nConn net.Conn, signers []ssh.Signer) {
config := &ssh.ClientConfig{
User: "test",
HostKeyCallback: ssh.FixedHostKey(hostSigner.PublicKey()),
Auth: []ssh.AuthMethod{ssh.PublicKeys(signers...)},
}
_, _, _, err := ssh.NewClientConn(nConn, "pipe", config)
check(err)
log.Print("[client] Completed handshake")
}
func signersLocalKey() []ssh.Signer {
certSigner, err := ssh.NewCertSigner(userCert, userSigner)
check(err)
return []ssh.Signer{certSigner}
}
func signersKeyring() []ssh.Signer {
ag := agent.NewKeyring()
check(ag.Add(agent.AddedKey{
PrivateKey: userKey,
Certificate: userCert,
}))
signers, err := ag.Signers()
check(err)
return signers
}
func signersRemoteAgent() []ssh.Signer {
ag := agent.NewKeyring()
check(ag.Add(agent.AddedKey{
Certificate: userCert,
PrivateKey: userKey,
}))
client, server := connutil.AsyncPipe()
go func() {
check(agent.ServeAgent(ag, server))
}()
signers, err := agent.NewClient(client).Signers()
check(err)
return signers
}
func main() {
clientConn, serverConn := connutil.AsyncPipe()
go server(serverConn)
// client(clientConn, signersLocalKey()) // this works
// client(clientConn, signersKeyring()) // this works too
client(clientConn, signersRemoteAgent()) // this fails: ssh: handshake failed: agent: unsupported algorithm "ecdsa-sha2-nistp256"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment