Commit 0d859f32 authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

go.crypto/ssh: separate kex algorithms into kexAlgorithm class.

Adds readPacket() to conn, and renames conn to packetConn.
Key exchanges operate on packetConn, so they can be
unittested.

R=agl, jpsugar, dave
CC=golang-dev
https://codereview.appspot.com/13352055

Committer: Adam Langley <agl@golang.org>
parent 40b64dbf
...@@ -78,7 +78,7 @@ const ( ...@@ -78,7 +78,7 @@ const (
) )
type channel struct { type channel struct {
conn // the underlying transport packetConn // the underlying transport
localId, remoteId uint32 localId, remoteId uint32
remoteWin window remoteWin window
maxPacket uint32 maxPacket uint32
...@@ -102,7 +102,7 @@ func (c *channel) sendEOF() error { ...@@ -102,7 +102,7 @@ func (c *channel) sendEOF() error {
// sendClose informs the remote side of our intent to close the channel. // sendClose informs the remote side of our intent to close the channel.
func (c *channel) sendClose() error { func (c *channel) sendClose() error {
return c.conn.writePacket(marshal(msgChannelClose, channelCloseMsg{ return c.packetConn.writePacket(marshal(msgChannelClose, channelCloseMsg{
PeersId: c.remoteId, PeersId: c.remoteId,
})) }))
} }
...@@ -124,7 +124,7 @@ func (c *channel) writePacket(b []byte) error { ...@@ -124,7 +124,7 @@ func (c *channel) writePacket(b []byte) error {
if uint32(len(b)) > c.maxPacket { if uint32(len(b)) > c.maxPacket {
return fmt.Errorf("ssh: cannot write %d bytes, maxPacket is %d bytes", len(b), c.maxPacket) return fmt.Errorf("ssh: cannot write %d bytes, maxPacket is %d bytes", len(b), c.maxPacket)
} }
return c.conn.writePacket(b) return c.packetConn.writePacket(b)
} }
func (c *channel) closed() bool { func (c *channel) closed() bool {
...@@ -447,12 +447,12 @@ type clientChan struct { ...@@ -447,12 +447,12 @@ type clientChan struct {
// newClientChan returns a partially constructed *clientChan // newClientChan returns a partially constructed *clientChan
// using the local id provided. To be usable clientChan.remoteId // using the local id provided. To be usable clientChan.remoteId
// needs to be assigned once known. // needs to be assigned once known.
func newClientChan(cc conn, id uint32) *clientChan { func newClientChan(cc packetConn, id uint32) *clientChan {
c := &clientChan{ c := &clientChan{
channel: channel{ channel: channel{
conn: cc, packetConn: cc,
localId: id, localId: id,
remoteWin: window{Cond: newCond()}, remoteWin: window{Cond: newCond()},
}, },
msg: make(chan interface{}, 16), msg: make(chan interface{}, 16),
} }
......
...@@ -5,15 +5,11 @@ ...@@ -5,15 +5,11 @@
package ssh package ssh
import ( import (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand" "crypto/rand"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big"
"net" "net"
"sync" "sync"
) )
...@@ -63,17 +59,14 @@ func clientWithAddress(c net.Conn, addr string, config *ClientConfig) (*ClientCo ...@@ -63,17 +59,14 @@ func clientWithAddress(c net.Conn, addr string, config *ClientConfig) (*ClientCo
// handshake performs the client side key exchange. See RFC 4253 Section 7. // handshake performs the client side key exchange. See RFC 4253 Section 7.
func (c *ClientConn) handshake() error { func (c *ClientConn) handshake() error {
var magics handshakeMagics var myVersion []byte
var version []byte
if len(c.config.ClientVersion) > 0 { if len(c.config.ClientVersion) > 0 {
version = []byte(c.config.ClientVersion) myVersion = []byte(c.config.ClientVersion)
} else { } else {
version = clientVersion myVersion = clientVersion
} }
magics.clientVersion = version
version = append(version, '\r', '\n') if _, err := c.Write(append(myVersion, '\r', '\n')); err != nil {
if _, err := c.Write(version); err != nil {
return err return err
} }
if err := c.Flush(); err != nil { if err := c.Flush(); err != nil {
...@@ -81,12 +74,12 @@ func (c *ClientConn) handshake() error { ...@@ -81,12 +74,12 @@ func (c *ClientConn) handshake() error {
} }
// read remote server version // read remote server version
version, err := readVersion(c) serverVersion, err := readVersion(c)
if err != nil { if err != nil {
return err return err
} }
magics.serverVersion = version c.serverVersion = string(serverVersion)
c.serverVersion = string(version)
clientKexInit := kexInitMsg{ clientKexInit := kexInitMsg{
KexAlgos: c.config.Crypto.kexes(), KexAlgos: c.config.Crypto.kexes(),
ServerHostKeyAlgos: supportedHostKeyAlgos, ServerHostKeyAlgos: supportedHostKeyAlgos,
...@@ -98,8 +91,6 @@ func (c *ClientConn) handshake() error { ...@@ -98,8 +91,6 @@ func (c *ClientConn) handshake() error {
CompressionServerClient: supportedCompressions, CompressionServerClient: supportedCompressions,
} }
kexInitPacket := marshal(msgKexInit, clientKexInit) kexInitPacket := marshal(msgKexInit, clientKexInit)
magics.clientKexInit = kexInitPacket
if err := c.writePacket(kexInitPacket); err != nil { if err := c.writePacket(kexInitPacket); err != nil {
return err return err
} }
...@@ -108,8 +99,6 @@ func (c *ClientConn) handshake() error { ...@@ -108,8 +99,6 @@ func (c *ClientConn) handshake() error {
return err return err
} }
magics.serverKexInit = packet
var serverKexInit kexInitMsg var serverKexInit kexInitMsg
if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil { if err = unmarshal(&serverKexInit, packet, msgKexInit); err != nil {
return err return err
...@@ -128,23 +117,18 @@ func (c *ClientConn) handshake() error { ...@@ -128,23 +117,18 @@ func (c *ClientConn) handshake() error {
} }
} }
var result *kexResult kex, ok := kexAlgoMap[kexAlgo]
switch kexAlgo { if !ok {
case kexAlgoECDH256: return fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo)
result, err = c.kexECDH(elliptic.P256(), &magics, hostKeyAlgo)
case kexAlgoECDH384:
result, err = c.kexECDH(elliptic.P384(), &magics, hostKeyAlgo)
case kexAlgoECDH521:
result, err = c.kexECDH(elliptic.P521(), &magics, hostKeyAlgo)
case kexAlgoDH14SHA1:
dhGroup14Once.Do(initDHGroup14)
result, err = c.kexDH(crypto.SHA1, dhGroup14, &magics, hostKeyAlgo)
case kexAlgoDH1SHA1:
dhGroup1Once.Do(initDHGroup1)
result, err = c.kexDH(crypto.SHA1, dhGroup1, &magics, hostKeyAlgo)
default:
err = fmt.Errorf("ssh: unexpected key exchange algorithm %v", kexAlgo)
} }
magics := handshakeMagics{
clientVersion: myVersion,
serverVersion: serverVersion,
clientKexInit: kexInitPacket,
serverKexInit: packet,
}
result, err := kex.Client(c, c.config.rand(), &magics)
if err != nil { if err != nil {
return err return err
} }
...@@ -164,7 +148,8 @@ func (c *ClientConn) handshake() error { ...@@ -164,7 +148,8 @@ func (c *ClientConn) handshake() error {
if err = c.writePacket([]byte{msgNewKeys}); err != nil { if err = c.writePacket([]byte{msgNewKeys}); err != nil {
return err return err
} }
if err = c.transport.writer.setupKeys(clientKeys, result.K, result.H, result.H, result.Hash); err != nil {
if err = c.transport.writer.setupKeys(clientKeys, result.K, result.H, result.H, kex.Hash()); err != nil {
return err return err
} }
if packet, err = c.readPacket(); err != nil { if packet, err = c.readPacket(); err != nil {
...@@ -173,72 +158,12 @@ func (c *ClientConn) handshake() error { ...@@ -173,72 +158,12 @@ func (c *ClientConn) handshake() error {
if packet[0] != msgNewKeys { if packet[0] != msgNewKeys {
return UnexpectedMessageError{msgNewKeys, packet[0]} return UnexpectedMessageError{msgNewKeys, packet[0]}
} }
if err := c.transport.reader.setupKeys(serverKeys, result.K, result.H, result.H, result.Hash); err != nil { if err := c.transport.reader.setupKeys(serverKeys, result.K, result.H, result.H, kex.Hash()); err != nil {
return err return err
} }
return c.authenticate(result.H) return c.authenticate(result.H)
} }
// kexECDH performs Elliptic Curve Diffie-Hellman key exchange as
// described in RFC 5656, section 4.
func (c *ClientConn) kexECDH(curve elliptic.Curve, magics *handshakeMagics, hostKeyAlgo string) (*kexResult, error) {
ephKey, err := ecdsa.GenerateKey(curve, c.config.rand())
if err != nil {
return nil, err
}
kexInit := kexECDHInitMsg{
ClientPubKey: elliptic.Marshal(curve, ephKey.PublicKey.X, ephKey.PublicKey.Y),
}
serialized := marshal(msgKexECDHInit, kexInit)
if err := c.writePacket(serialized); err != nil {
return nil, err
}
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var reply kexECDHReplyMsg
if err = unmarshal(&reply, packet, msgKexECDHReply); err != nil {
return nil, err
}
x, y := elliptic.Unmarshal(curve, reply.EphemeralPubKey)
if x == nil {
return nil, errors.New("ssh: elliptic.Unmarshal failure")
}
if !validateECPublicKey(curve, x, y) {
return nil, errors.New("ssh: ephemeral server key not on curve")
}
// generate shared secret
secret, _ := curve.ScalarMult(x, y, ephKey.D.Bytes())
hashFunc := ecHash(curve)
h := hashFunc.New()
writeString(h, magics.clientVersion)
writeString(h, magics.serverVersion)
writeString(h, magics.clientKexInit)
writeString(h, magics.serverKexInit)
writeString(h, reply.HostKey)
writeString(h, kexInit.ClientPubKey)
writeString(h, reply.EphemeralPubKey)
K := make([]byte, intLength(secret))
marshalInt(K, secret)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: reply.HostKey,
Signature: reply.Signature,
Hash: hashFunc,
}, nil
}
// Verify the host key obtained in the key exchange. // Verify the host key obtained in the key exchange.
func verifyHostKeySignature(hostKeyAlgo string, hostKeyBytes []byte, data []byte, signature []byte) error { func verifyHostKeySignature(hostKeyAlgo string, hostKeyBytes []byte, data []byte, signature []byte) error {
hostKey, rest, ok := ParsePublicKey(hostKeyBytes) hostKey, rest, ok := ParsePublicKey(hostKeyBytes)
...@@ -260,74 +185,6 @@ func verifyHostKeySignature(hostKeyAlgo string, hostKeyBytes []byte, data []byte ...@@ -260,74 +185,6 @@ func verifyHostKeySignature(hostKeyAlgo string, hostKeyBytes []byte, data []byte
return nil return nil
} }
// kexResult captures the outcome of a key exchange.
type kexResult struct {
// Session hash. See also RFC 4253, section 8.
H []byte
// Shared secret. See also RFC 4253, section 8.
K []byte
// Host key as hashed into H
HostKey []byte
// Signature of H
Signature []byte
// Hash function that was used.
Hash crypto.Hash
}
// kexDH performs Diffie-Hellman key agreement on a ClientConn.
func (c *ClientConn) kexDH(hashFunc crypto.Hash, group *dhGroup, magics *handshakeMagics, hostKeyAlgo string) (*kexResult, error) {
x, err := rand.Int(c.config.rand(), group.p)
if err != nil {
return nil, err
}
X := new(big.Int).Exp(group.g, x, group.p)
kexDHInit := kexDHInitMsg{
X: X,
}
if err := c.writePacket(marshal(msgKexDHInit, kexDHInit)); err != nil {
return nil, err
}
packet, err := c.readPacket()
if err != nil {
return nil, err
}
var kexDHReply kexDHReplyMsg
if err = unmarshal(&kexDHReply, packet, msgKexDHReply); err != nil {
return nil, err
}
kInt, err := group.diffieHellman(kexDHReply.Y, x)
if err != nil {
return nil, err
}
h := hashFunc.New()
writeString(h, magics.clientVersion)
writeString(h, magics.serverVersion)
writeString(h, magics.clientKexInit)
writeString(h, magics.serverKexInit)
writeString(h, kexDHReply.HostKey)
writeInt(h, X)
writeInt(h, kexDHReply.Y)
K := make([]byte, intLength(kInt))
marshalInt(K, kInt)
h.Write(K)
return &kexResult{
H: h.Sum(nil),
K: K,
HostKey: kexDHReply.HostKey,
Signature: kexDHReply.Signature,
Hash: hashFunc,
}, nil
}
// mainLoop reads incoming messages and routes channel messages // mainLoop reads incoming messages and routes channel messages
// to their respective ClientChans. // to their respective ClientChans.
func (c *ClientConn) mainLoop() { func (c *ClientConn) mainLoop() {
...@@ -633,18 +490,18 @@ type chanList struct { ...@@ -633,18 +490,18 @@ type chanList struct {
} }
// Allocate a new ClientChan with the next avail local id. // Allocate a new ClientChan with the next avail local id.
func (c *chanList) newChan(t *transport) *clientChan { func (c *chanList) newChan(p packetConn) *clientChan {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()
for i := range c.chans { for i := range c.chans {
if c.chans[i] == nil { if c.chans[i] == nil {
ch := newClientChan(t, uint32(i)) ch := newClientChan(p, uint32(i))
c.chans[i] = ch c.chans[i] = ch
return ch return ch
} }
} }
i := len(c.chans) i := len(c.chans)
ch := newClientChan(t, uint32(i)) ch := newClientChan(p, uint32(i))
c.chans = append(c.chans, ch) c.chans = append(c.chans, ch)
return ch return ch
} }
......
...@@ -81,7 +81,7 @@ type ClientAuth interface { ...@@ -81,7 +81,7 @@ type ClientAuth interface {
// Returns true if authentication is successful. // Returns true if authentication is successful.
// If authentication is not successful, a []string of alternative // If authentication is not successful, a []string of alternative
// method names is returned. // method names is returned.
auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error)
// method returns the RFC 4252 method name. // method returns the RFC 4252 method name.
method() string method() string
...@@ -90,8 +90,8 @@ type ClientAuth interface { ...@@ -90,8 +90,8 @@ type ClientAuth interface {
// "none" authentication, RFC 4252 section 5.2. // "none" authentication, RFC 4252 section 5.2.
type noneAuth int type noneAuth int
func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
if err := t.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{ if err := c.writePacket(marshal(msgUserAuthRequest, userAuthRequestMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: "none", Method: "none",
...@@ -99,7 +99,7 @@ func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reade ...@@ -99,7 +99,7 @@ func (n *noneAuth) auth(session []byte, user string, t *transport, rand io.Reade
return false, nil, err return false, nil, err
} }
return handleAuthResponse(t) return handleAuthResponse(c)
} }
func (n *noneAuth) method() string { func (n *noneAuth) method() string {
...@@ -111,7 +111,7 @@ type passwordAuth struct { ...@@ -111,7 +111,7 @@ type passwordAuth struct {
ClientPassword ClientPassword
} }
func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { func (p *passwordAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
type passwordAuthMsg struct { type passwordAuthMsg struct {
User string User string
Service string Service string
...@@ -125,7 +125,7 @@ func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.R ...@@ -125,7 +125,7 @@ func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.R
return false, nil, err return false, nil, err
} }
if err := t.writePacket(marshal(msgUserAuthRequest, passwordAuthMsg{ if err := c.writePacket(marshal(msgUserAuthRequest, passwordAuthMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: "password", Method: "password",
...@@ -135,7 +135,7 @@ func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.R ...@@ -135,7 +135,7 @@ func (p *passwordAuth) auth(session []byte, user string, t *transport, rand io.R
return false, nil, err return false, nil, err
} }
return handleAuthResponse(t) return handleAuthResponse(c)
} }
func (p *passwordAuth) method() string { func (p *passwordAuth) method() string {
...@@ -181,7 +181,7 @@ type publickeyAuthMsg struct { ...@@ -181,7 +181,7 @@ type publickeyAuthMsg struct {
Sig []byte `ssh:"rest"` Sig []byte `ssh:"rest"`
} }
func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { func (p *publickeyAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
// Authentication is performed in two stages. The first stage sends an // Authentication is performed in two stages. The first stage sends an
// enquiry to test if each key is acceptable to the remote. The second // enquiry to test if each key is acceptable to the remote. The second
// stage attempts to authenticate with the valid keys obtained in the // stage attempts to authenticate with the valid keys obtained in the
...@@ -200,7 +200,7 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io. ...@@ -200,7 +200,7 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.
break break
} }
if ok, err := p.validateKey(key, user, t); ok { if ok, err := p.validateKey(key, user, c); ok {
validKeys[index] = key validKeys[index] = key
} else { } else {
if err != nil { if err != nil {
...@@ -237,10 +237,10 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io. ...@@ -237,10 +237,10 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.
Sig: sig, Sig: sig,
} }
p := marshal(msgUserAuthRequest, msg) p := marshal(msgUserAuthRequest, msg)
if err := t.writePacket(p); err != nil { if err := c.writePacket(p); err != nil {
return false, nil, err return false, nil, err
} }
success, methods, err := handleAuthResponse(t) success, methods, err := handleAuthResponse(c)
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
...@@ -252,7 +252,7 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io. ...@@ -252,7 +252,7 @@ func (p *publickeyAuth) auth(session []byte, user string, t *transport, rand io.
} }
// validateKey validates the key provided it is acceptable to the server. // validateKey validates the key provided it is acceptable to the server.
func (p *publickeyAuth) validateKey(key PublicKey, user string, t *transport) (bool, error) { func (p *publickeyAuth) validateKey(key PublicKey, user string, c packetConn) (bool, error) {
pubkey := MarshalPublicKey(key) pubkey := MarshalPublicKey(key)
algoname := key.PublicKeyAlgo() algoname := key.PublicKeyAlgo()
msg := publickeyAuthMsg{ msg := publickeyAuthMsg{
...@@ -263,19 +263,19 @@ func (p *publickeyAuth) validateKey(key PublicKey, user string, t *transport) (b ...@@ -263,19 +263,19 @@ func (p *publickeyAuth) validateKey(key PublicKey, user string, t *transport) (b
Algoname: algoname, Algoname: algoname,
Pubkey: string(pubkey), Pubkey: string(pubkey),
} }
if err := t.writePacket(marshal(msgUserAuthRequest, msg)); err != nil { if err := c.writePacket(marshal(msgUserAuthRequest, msg)); err != nil {
return false, err return false, err
} }
return p.confirmKeyAck(key, t) return p.confirmKeyAck(key, c)
} }
func (p *publickeyAuth) confirmKeyAck(key PublicKey, t *transport) (bool, error) { func (p *publickeyAuth) confirmKeyAck(key PublicKey, c packetConn) (bool, error) {
pubkey := MarshalPublicKey(key) pubkey := MarshalPublicKey(key)
algoname := key.PublicKeyAlgo() algoname := key.PublicKeyAlgo()
for { for {
packet, err := t.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return false, err return false, err
} }
...@@ -312,9 +312,9 @@ func ClientAuthKeyring(impl ClientKeyring) ClientAuth { ...@@ -312,9 +312,9 @@ func ClientAuthKeyring(impl ClientKeyring) ClientAuth {
// handleAuthResponse returns whether the preceding authentication request succeeded // handleAuthResponse returns whether the preceding authentication request succeeded
// along with a list of remaining authentication methods to try next and // along with a list of remaining authentication methods to try next and
// an error if an unexpected response was received. // an error if an unexpected response was received.
func handleAuthResponse(t *transport) (bool, []string, error) { func handleAuthResponse(c packetConn) (bool, []string, error) {
for { for {
packet, err := t.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
...@@ -411,11 +411,11 @@ type keyboardInteractiveAuth struct { ...@@ -411,11 +411,11 @@ type keyboardInteractiveAuth struct {
ClientKeyboardInteractive ClientKeyboardInteractive
} }
func (c *keyboardInteractiveAuth) method() string { func (k *keyboardInteractiveAuth) method() string {
return "keyboard-interactive" return "keyboard-interactive"
} }
func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport, rand io.Reader) (bool, []string, error) { func (k *keyboardInteractiveAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
type initiateMsg struct { type initiateMsg struct {
User string User string
Service string Service string
...@@ -424,7 +424,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport ...@@ -424,7 +424,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport
Submethods string Submethods string
} }
if err := t.writePacket(marshal(msgUserAuthRequest, initiateMsg{ if err := c.writePacket(marshal(msgUserAuthRequest, initiateMsg{
User: user, User: user,
Service: serviceSSH, Service: serviceSSH,
Method: "keyboard-interactive", Method: "keyboard-interactive",
...@@ -433,7 +433,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport ...@@ -433,7 +433,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport
} }
for { for {
packet, err := t.readPacket() packet, err := c.readPacket()
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
...@@ -480,7 +480,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport ...@@ -480,7 +480,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport
return false, nil, fmt.Errorf("ssh: junk following message %q", rest) return false, nil, fmt.Errorf("ssh: junk following message %q", rest)
} }
answers, err := c.Challenge(msg.User, msg.Instruction, prompts, echos) answers, err := k.Challenge(msg.User, msg.Instruction, prompts, echos)
if err != nil { if err != nil {
return false, nil, err return false, nil, err
} }
...@@ -501,7 +501,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport ...@@ -501,7 +501,7 @@ func (c *keyboardInteractiveAuth) auth(session []byte, user string, t *transport
p = marshalString(p, []byte(a)) p = marshalString(p, []byte(a))
} }
if err := t.writePacket(serialized); err != nil { if err := c.writePacket(serialized); err != nil {
return false, nil, err return false, nil, err
} }
} }
......
...@@ -6,9 +6,7 @@ package ssh ...@@ -6,9 +6,7 @@ package ssh
import ( import (
"crypto" "crypto"
"errors"
"fmt" "fmt"
"math/big"
"sync" "sync"
_ "crypto/sha1" _ "crypto/sha1"
...@@ -18,11 +16,6 @@ import ( ...@@ -18,11 +16,6 @@ import (
// These are string constants in the SSH protocol. // These are string constants in the SSH protocol.
const ( const (
kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
kexAlgoECDH256 = "ecdh-sha2-nistp256"
kexAlgoECDH384 = "ecdh-sha2-nistp384"
kexAlgoECDH521 = "ecdh-sha2-nistp521"
hostAlgoRSA = "ssh-rsa" hostAlgoRSA = "ssh-rsa"
hostAlgoDSA = "ssh-dss" hostAlgoDSA = "ssh-dss"
compressionNone = "none" compressionNone = "none"
...@@ -53,48 +46,6 @@ var hashFuncs = map[string]crypto.Hash{ ...@@ -53,48 +46,6 @@ var hashFuncs = map[string]crypto.Hash{
CertAlgoECDSA521v01: crypto.SHA512, CertAlgoECDSA521v01: crypto.SHA512,
} }
// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
type dhGroup struct {
g, p *big.Int
}
func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
return nil, errors.New("ssh: DH parameter out of bounds")
}
return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
}
// dhGroup1 is the group called diffie-hellman-group1-sha1 in RFC 4253 and
// Oakley Group 2 in RFC 2409.
var dhGroup1 *dhGroup
var dhGroup1Once sync.Once
func initDHGroup1() {
p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
dhGroup1 = &dhGroup{
g: new(big.Int).SetInt64(2),
p: p,
}
}
// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
// Oakley Group 14 in RFC 3526.
var dhGroup14 *dhGroup
var dhGroup14Once sync.Once