1
0
mirror of synced 2026-03-04 12:16:57 +00:00

Replace SSH shell-outs with Go implementation

This commit is contained in:
Hidde Beydals
2020-06-05 22:22:54 +02:00
parent 25f6291403
commit a332e12338
5 changed files with 183 additions and 51 deletions

47
internal/ssh/host_scan.go Normal file
View File

@@ -0,0 +1,47 @@
package ssh
import (
"encoding/base64"
"fmt"
"net"
"golang.org/x/crypto/ssh"
"golang.org/x/crypto/ssh/knownhosts"
)
func ScanHostKey(host string, user string, pair *KeyPair) ([]byte, error) {
signer, err := ssh.ParsePrivateKey(pair.PrivateKey)
if err != nil {
return nil, err
}
col := &collector{}
config := &ssh.ClientConfig{
User: user,
Auth: []ssh.AuthMethod{
ssh.PublicKeys(signer),
},
HostKeyCallback: col.StoreKey(),
}
client, err := ssh.Dial("tcp", host, config)
if err == nil {
defer client.Close()
}
if len(col.knownKeys) > 0 {
return col.knownKeys, nil
}
return col.knownKeys, err
}
type collector struct {
knownKeys []byte
}
func (c *collector) StoreKey() ssh.HostKeyCallback {
return func(hostname string, remote net.Addr, key ssh.PublicKey) error {
c.knownKeys = append(
c.knownKeys,
fmt.Sprintf("%s %s %s\n", knownhosts.Normalize(hostname), key.Type(), base64.StdEncoding.EncodeToString(key.Marshal()))...,
)
return nil
}
}

89
internal/ssh/key_pair.go Normal file
View File

@@ -0,0 +1,89 @@
package ssh
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"golang.org/x/crypto/ssh"
)
type KeyPair struct {
PublicKey []byte
PrivateKey []byte
}
type KeyPairGenerator interface {
Generate() (*KeyPair, error)
}
type RSAGenerator struct {
bits int
}
func NewRSAGenerator(bits int) KeyPairGenerator {
return &RSAGenerator{bits}
}
func (g *RSAGenerator) Generate() (*KeyPair, error) {
pk, err := rsa.GenerateKey(rand.Reader, g.bits)
if err != nil {
return nil, err
}
err = pk.Validate()
if err != nil {
return nil, err
}
pub, err := generatePublicKey(&pk.PublicKey)
if err != nil {
return nil, err
}
return &KeyPair{
PublicKey: pub,
PrivateKey: encodePrivateKeyToPEM(pk),
}, nil
}
type ECDSAGenerator struct {
c elliptic.Curve
}
func NewECDSAGenerator(c elliptic.Curve) KeyPairGenerator {
return &ECDSAGenerator{c}
}
func (g *ECDSAGenerator) Generate() (*KeyPair, error) {
pk, err := ecdsa.GenerateKey(g.c, rand.Reader)
if err != nil {
return nil, err
}
pub, err := generatePublicKey(&pk.PublicKey)
if err != nil {
return nil, err
}
return &KeyPair{
PublicKey: pub,
PrivateKey: encodePrivateKeyToPEM(pk),
}, nil
}
func generatePublicKey(pk interface{}) ([]byte, error) {
b, err := ssh.NewPublicKey(pk)
if err != nil {
return nil, err
}
k := ssh.MarshalAuthorizedKey(b)
return k, nil
}
func encodePrivateKeyToPEM(pk interface{}) []byte {
b, _ := x509.MarshalPKCS8PrivateKey(pk)
block := pem.Block{
Type: "PRIVATE KEY",
Bytes: b,
}
return pem.EncodeToMemory(&block)
}