尝试通过SSH连接到远程主机时出错

时间:2019-10-19 01:21:01

标签: go encryption ssh

我试图连接到远程主机以发出命令,但是在运行代码时出现以下错误消息:

  

ssh:握手失败:ssh:没有通用的密钥交换算法;提供的客户端:[curve25519-sha256@libssh.org ecdh-sha2-nistp256 ecdh-sha2-nistp384 ecdh-sha2-nistp521 diffie-hellman-group14-sha1],服务器提供的:[diffie-hellman-group1-sha1]应急:运行时错误:无效的内存地址或nil指针取消引用   [信号SIGSEGV:细分违规代码= 0x1 addr = 0x10 pc = 0x759836]

这是我正在使用的代码:

func (SSHClient *SSH) Connect(mode int) {
    var SSHConfig *ssh.ClientConfig
    var auth []ssh.AuthMethod

    if mode == CERT_PUBLIC_KEY_FILE {
        auth = []ssh.AuthMethod{SSHClient.readPublicKeyFile(SSHClient.Cert)}
    }

    SSHConfig = &ssh.ClientConfig{
        User:            SSHClient.User,
        Auth:            auth,
        HostKeyCallback: ssh.InsecureIgnoreHostKey(),
        Timeout:         time.Second * DEFAULT_TIMEOUT,
    }

    SSHConfig.Config.Ciphers = append(SSHConfig.Config.Ciphers, "diffie-hellman-group1-sha1")

    client, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", SSHClient.IP, SSHClient.Port), SSHConfig)

    if err != nil {
        fmt.Printf("ERROR - While trying to Dial to the host %s with error: %s", SSHClient.IP, err.Error())
        return
    }

    session, err := client.NewSession()
    if err != nil {
        fmt.Printf("ERROR - While trying to create a new session on host %s with error: %s", SSHClient.IP, err.Error())
        client.Close()
        return
    }

    SSHClient.session = session
    SSHClient.client = client
}

关于如何解决此问题的任何想法?

谢谢。

3 个答案:

答案 0 :(得分:2)

问题是...。服务器只愿意通过diffie-hellman-group1-sha1进行通话

并且:

  • golang/go issue 2903:ssh:添加diffie-hellman-group1-sha1,已于6天前关闭
  • golang/go/issue 17230:建议:x/crypto/ssh:支持RFC 4419中的Diffie-Hellman Group Exchange,目前正在实施中。

因此,您的客户需要golang.org/x/crypto/ssh的分支,例如bored-engineer/ssh,其中commit 39a91bcommit fe5e4ff确实增加了对diffie-hellman-group1-sha1的支持。
或安装最新的golang/crypto,其中包括commit 57b3e21

答案 1 :(得分:0)

恐慌有些奇怪。显然,如果无法商定密钥交换算法,就会出问题。作为VonC notes,Diffie-Helman <密钥交换只是最近才添加的(6月3日)。由于您的服务器仅提供该算法,因此,没有它就无法上手。

这不是引起恐慌的原因(它似乎发生在ssh.Dial内部),但是我会注意到,当您这样做时:

SSHConfig.Config.Ciphers = append(SSHConfig.Config.Ciphers, "diffie-hellman-group1-sha1")

您最终告诉Go代码仅 使用diffie-helman-group1-sha1作为通道加密。您没有在此处添加任何内容。原因是SSHConfig.Config.Ciphers最初是nil。因此,您最好写:

SSHConfig.Config.Ciphers = []string{"diffie-hellman-group1-sha1"}

要获得相同的效果,那就是:事情不起作用。

您可以调用SetDefaults,以使列表在添加到列表之前为非空,但是如果没有该模式的实现,即使添加了新的提交Diffie-,添加到列表也无效。除密钥交换本身外,Helman不允许进行任何其他操作。请注意,ssh.Dial调用heressh.NewClientConn,其开头为:

fullConf := *config
fullConf.SetDefaults()

SetDefaults依次为here,其中包含:

if c.Ciphers == nil {
    c.Ciphers = preferredCiphers
}
var ciphers []string
for _, c := range c.Ciphers {
    if cipherModes[c] != nil {
        // reject the cipher if we have no cipherModes definition
        ciphers = append(ciphers, c)
    }
}
c.Ciphers = ciphers

这首先表示如果未设置配置的Ciphers,则应使用默认值,然后紧接着,过滤掉任何不在cipherModes中的字符串。依次定义为here,并以以下注释开头:

// cipherModes documents properties of supported ciphers. Ciphers not included
// are not supported and will not be negotiated, even if explicitly requested in
// ClientConfig.Crypto.Ciphers.

此短语不在文档中。它应该是! 不支持未包含的密码,即使在ClientConfig.Crypto.Ciphers中明确要求,也不会进行协商。

(有关支持 的一组密码,请参阅上面的最后一个链接。请注意,此列表随着时间的推移而增长。)

答案 2 :(得分:0)

Diffie-hellman-group1-sha1是密钥交换算法。应该是KeyExchange,而不是Config结构中的密码

SSHConfig.Config.KeyExchanges = append(SSHConfig.Config.KeyExchanges, "diffie-hellman-group1-sha1")

代替

SSHConfig.Config.Ciphers = append(SSHConfig.Config.Ciphers, "diffie-hellman-group1-sha1")

如果未指定KeyExchanges,则可以在ssh / common.go中找到使用的默认算法

// preferredKexAlgos specifies the default preference for key-exchange algorithms
// in preference order.
var preferredKexAlgos = []string{
    kexAlgoCurve25519SHA256,
    kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
    kexAlgoDH14SHA1,
}

如您所见,目前未列出kexAlgoDH1SHA1或diffie-hellman-group1-sha1