From 600f748cb0a77370bb5533ed38c01e40fbcf11bb Mon Sep 17 00:00:00 2001 From: Unknwon Date: Wed, 1 Mar 2017 21:33:58 -0500 Subject: [PATCH] vendor: update golang.org/x/crypto/ssh Related to #4160 --- gogs.go | 2 +- templates/.VERSION | 2 +- vendor/golang.org/x/crypto/ssh/channel.go | 4 +- vendor/golang.org/x/crypto/ssh/cipher.go | 64 ++- vendor/golang.org/x/crypto/ssh/client.go | 6 +- vendor/golang.org/x/crypto/ssh/client_auth.go | 4 +- vendor/golang.org/x/crypto/ssh/common.go | 17 +- vendor/golang.org/x/crypto/ssh/handshake.go | 435 ++++++++++++------ vendor/golang.org/x/crypto/ssh/keys.go | 6 +- vendor/golang.org/x/crypto/ssh/mac.go | 10 +- vendor/golang.org/x/crypto/ssh/mux.go | 4 +- vendor/golang.org/x/crypto/ssh/server.go | 37 +- vendor/golang.org/x/crypto/ssh/transport.go | 50 +- vendor/vendor.json | 6 +- 14 files changed, 462 insertions(+), 185 deletions(-) diff --git a/gogs.go b/gogs.go index 0d81503e..fc11c85e 100644 --- a/gogs.go +++ b/gogs.go @@ -16,7 +16,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.10.3.0228" +const APP_VER = "0.10.3.0301" func init() { setting.AppVer = APP_VER diff --git a/templates/.VERSION b/templates/.VERSION index 59bae7e5..5c5e94d5 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.10.3.0228 \ No newline at end of file +0.10.3.0301 \ No newline at end of file diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go index 6d709b50..195530ea 100644 --- a/vendor/golang.org/x/crypto/ssh/channel.go +++ b/vendor/golang.org/x/crypto/ssh/channel.go @@ -461,8 +461,8 @@ func (m *mux) newChannel(chanType string, direction channelDirection, extraData pending: newBuffer(), extPending: newBuffer(), direction: direction, - incomingRequests: make(chan *Request, 16), - msg: make(chan interface{}, 16), + incomingRequests: make(chan *Request, chanSize), + msg: make(chan interface{}, chanSize), chanType: chanType, extraData: extraData, mux: m, diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go index 34d3917c..13484ab4 100644 --- a/vendor/golang.org/x/crypto/ssh/cipher.go +++ b/vendor/golang.org/x/crypto/ssh/cipher.go @@ -135,6 +135,7 @@ const prefixLen = 5 type streamPacketCipher struct { mac hash.Hash cipher cipher.Stream + etm bool // The following members are to avoid per-packet allocations. prefix [prefixLen]byte @@ -150,7 +151,14 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err return nil, err } - s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + var encryptedPaddingLength [1]byte + if s.mac != nil && s.etm { + copy(encryptedPaddingLength[:], s.prefix[4:5]) + s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) + } else { + s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + } + length := binary.BigEndian.Uint32(s.prefix[0:4]) paddingLength := uint32(s.prefix[4]) @@ -159,7 +167,12 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err s.mac.Reset() binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) s.mac.Write(s.seqNumBytes[:]) - s.mac.Write(s.prefix[:]) + if s.etm { + s.mac.Write(s.prefix[:4]) + s.mac.Write(encryptedPaddingLength[:]) + } else { + s.mac.Write(s.prefix[:]) + } macSize = uint32(s.mac.Size()) } @@ -184,10 +197,17 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err } mac := s.packetData[length-1:] data := s.packetData[:length-1] + + if s.mac != nil && s.etm { + s.mac.Write(data) + } + s.cipher.XORKeyStream(data, data) if s.mac != nil { - s.mac.Write(data) + if !s.etm { + s.mac.Write(data) + } s.macResult = s.mac.Sum(s.macResult[:0]) if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { return nil, errors.New("ssh: MAC failure") @@ -203,7 +223,13 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea return errors.New("ssh: packet too large") } - paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple + aadlen := 0 + if s.mac != nil && s.etm { + // packet length is not encrypted for EtM modes + aadlen = 4 + } + + paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple if paddingLength < 4 { paddingLength += packetSizeMultiple } @@ -220,15 +246,37 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea s.mac.Reset() binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) s.mac.Write(s.seqNumBytes[:]) + + if s.etm { + // For EtM algorithms, the packet length must stay unencrypted, + // but the following data (padding length) must be encrypted + s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) + } + s.mac.Write(s.prefix[:]) + + if !s.etm { + // For non-EtM algorithms, the algorithm is applied on unencrypted data + s.mac.Write(packet) + s.mac.Write(padding) + } + } + + if !(s.mac != nil && s.etm) { + // For EtM algorithms, the padding length has already been encrypted + // and the packet length must remain unencrypted + s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) + } + + s.cipher.XORKeyStream(packet, packet) + s.cipher.XORKeyStream(padding, padding) + + if s.mac != nil && s.etm { + // For EtM algorithms, packet and padding must be encrypted s.mac.Write(packet) s.mac.Write(padding) } - s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) - s.cipher.XORKeyStream(packet, packet) - s.cipher.XORKeyStream(padding, padding) - if _, err := w.Write(s.prefix[:]); err != nil { return err } diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go index 0212a20c..c97f2978 100644 --- a/vendor/golang.org/x/crypto/ssh/client.go +++ b/vendor/golang.org/x/crypto/ssh/client.go @@ -40,7 +40,7 @@ func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { return nil } - ch = make(chan NewChannel, 16) + ch = make(chan NewChannel, chanSize) c.channelHandlers[channelType] = ch return ch } @@ -97,13 +97,11 @@ func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) e c.transport = newClientTransport( newTransport(c.sshConn.conn, config.Rand, true /* is client */), c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) - if err := c.transport.requestInitialKeyChange(); err != nil { + if err := c.transport.waitSession(); err != nil { return err } - // We just did the key change, so the session ID is established. c.sessionID = c.transport.getSessionID() - return c.clientAuthenticate(config) } diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go index 294af0d4..fd1ec5dd 100644 --- a/vendor/golang.org/x/crypto/ssh/client_auth.go +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go @@ -30,8 +30,10 @@ func (c *connection) clientAuthenticate(config *ClientConfig) error { // then any untried methods suggested by the server. tried := make(map[string]bool) var lastMethods []string + + sessionID := c.transport.getSessionID() for auth := AuthMethod(new(noneAuth)); auth != nil; { - ok, methods, err := auth.auth(c.transport.getSessionID(), config.User, c.transport, config.Rand) + ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) if err != nil { return err } diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go index 2c72ab54..8656d0f8 100644 --- a/vendor/golang.org/x/crypto/ssh/common.go +++ b/vendor/golang.org/x/crypto/ssh/common.go @@ -56,7 +56,7 @@ var supportedHostKeyAlgos = []string{ // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed // because they have reached the end of their useful life. var supportedMACs = []string{ - "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", + "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", } var supportedCompressions = []string{compressionNone} @@ -104,6 +104,21 @@ type directionAlgorithms struct { Compression string } +// rekeyBytes returns a rekeying intervals in bytes. +func (a *directionAlgorithms) rekeyBytes() int64 { + // According to RFC4344 block ciphers should rekey after + // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is + // 128. + switch a.Cipher { + case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID: + return 16 * (1 << 32) + + } + + // For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. + return 1 << 30 +} + type algorithms struct { kex string hostKey string diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go index 37d42e47..8de65064 100644 --- a/vendor/golang.org/x/crypto/ssh/handshake.go +++ b/vendor/golang.org/x/crypto/ssh/handshake.go @@ -19,6 +19,11 @@ import ( // messages are wrong when using ECDH. const debugHandshake = false +// chanSize sets the amount of buffering SSH connections. This is +// primarily for testing: setting chanSize=0 uncovers deadlocks more +// quickly. +const chanSize = 16 + // keyingTransport is a packet based transport that supports key // changes. It need not be thread-safe. It should pass through // msgNewKeys in both directions. @@ -53,34 +58,58 @@ type handshakeTransport struct { incoming chan []byte readError error + mu sync.Mutex + writeError error + sentInitPacket []byte + sentInitMsg *kexInitMsg + pendingPackets [][]byte // Used when a key exchange is in progress. + + // If the read loop wants to schedule a kex, it pings this + // channel, and the write loop will send out a kex + // message. + requestKex chan struct{} + + // If the other side requests or confirms a kex, its kexInit + // packet is sent here for the write loop to find it. + startKex chan *pendingKex + // data for host key checking hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error dialAddress string remoteAddr net.Addr - readSinceKex uint64 + // Algorithms agreed in the last key exchange. + algorithms *algorithms - // Protects the writing side of the connection - mu sync.Mutex - cond *sync.Cond - sentInitPacket []byte - sentInitMsg *kexInitMsg - writtenSinceKex uint64 - writeError error + readPacketsLeft uint32 + readBytesLeft int64 + + writePacketsLeft uint32 + writeBytesLeft int64 // The session ID or nil if first kex did not complete yet. sessionID []byte } +type pendingKex struct { + otherInit []byte + done chan error +} + func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { t := &handshakeTransport{ conn: conn, serverVersion: serverVersion, clientVersion: clientVersion, - incoming: make(chan []byte, 16), - config: config, + incoming: make(chan []byte, chanSize), + requestKex: make(chan struct{}, 1), + startKex: make(chan *pendingKex, 1), + + config: config, } - t.cond = sync.NewCond(&t.mu) + + // We always start with a mandatory key exchange. + t.requestKex <- struct{}{} return t } @@ -95,6 +124,7 @@ func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byt t.hostKeyAlgorithms = supportedHostKeyAlgos } go t.readLoop() + go t.kexLoop() return t } @@ -102,6 +132,7 @@ func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byt t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) t.hostKeys = config.hostKeys go t.readLoop() + go t.kexLoop() return t } @@ -109,6 +140,20 @@ func (t *handshakeTransport) getSessionID() []byte { return t.sessionID } +// waitSession waits for the session to be established. This should be +// the first thing to call after instantiating handshakeTransport. +func (t *handshakeTransport) waitSession() error { + p, err := t.readPacket() + if err != nil { + return err + } + if p[0] != msgNewKeys { + return fmt.Errorf("ssh: first packet should be msgNewKeys") + } + + return nil +} + func (t *handshakeTransport) id() string { if len(t.hostKeys) > 0 { return "server" @@ -116,6 +161,20 @@ func (t *handshakeTransport) id() string { return "client" } +func (t *handshakeTransport) printPacket(p []byte, write bool) { + action := "got" + if write { + action = "sent" + } + + if p[0] == msgChannelData || p[0] == msgChannelExtendedData { + log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) + } else { + msg, err := decode(p) + log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) + } +} + func (t *handshakeTransport) readPacket() ([]byte, error) { p, ok := <-t.incoming if !ok { @@ -125,8 +184,10 @@ func (t *handshakeTransport) readPacket() ([]byte, error) { } func (t *handshakeTransport) readLoop() { + first := true for { - p, err := t.readOnePacket() + p, err := t.readOnePacket(first) + first = false if err != nil { t.readError = err close(t.incoming) @@ -138,67 +199,204 @@ func (t *handshakeTransport) readLoop() { t.incoming <- p } - // If we can't read, declare the writing part dead too. - t.mu.Lock() - defer t.mu.Unlock() - if t.writeError == nil { - t.writeError = t.readError - } - t.cond.Broadcast() + // Stop writers too. + t.recordWriteError(t.readError) + + // Unblock the writer should it wait for this. + close(t.startKex) + + // Don't close t.requestKex; it's also written to from writePacket. } -func (t *handshakeTransport) readOnePacket() ([]byte, error) { - if t.readSinceKex > t.config.RekeyThreshold { - if err := t.requestKeyChange(); err != nil { - return nil, err +func (t *handshakeTransport) pushPacket(p []byte) error { + if debugHandshake { + t.printPacket(p, true) + } + return t.conn.writePacket(p) +} + +func (t *handshakeTransport) getWriteError() error { + t.mu.Lock() + defer t.mu.Unlock() + return t.writeError +} + +func (t *handshakeTransport) recordWriteError(err error) { + t.mu.Lock() + defer t.mu.Unlock() + if t.writeError == nil && err != nil { + t.writeError = err + } +} + +func (t *handshakeTransport) requestKeyExchange() { + select { + case t.requestKex <- struct{}{}: + default: + // something already requested a kex, so do nothing. + } +} + +func (t *handshakeTransport) kexLoop() { + +write: + for t.getWriteError() == nil { + var request *pendingKex + var sent bool + + for request == nil || !sent { + var ok bool + select { + case request, ok = <-t.startKex: + if !ok { + break write + } + case <-t.requestKex: + break + } + + if !sent { + if err := t.sendKexInit(); err != nil { + t.recordWriteError(err) + break + } + sent = true + } } + + if err := t.getWriteError(); err != nil { + if request != nil { + request.done <- err + } + break + } + + // We're not servicing t.requestKex, but that is OK: + // we never block on sending to t.requestKex. + + // We're not servicing t.startKex, but the remote end + // has just sent us a kexInitMsg, so it can't send + // another key change request, until we close the done + // channel on the pendingKex request. + + err := t.enterKeyExchange(request.otherInit) + + t.mu.Lock() + t.writeError = err + t.sentInitPacket = nil + t.sentInitMsg = nil + t.writePacketsLeft = packetRekeyThreshold + if t.config.RekeyThreshold > 0 { + t.writeBytesLeft = int64(t.config.RekeyThreshold) + } else if t.algorithms != nil { + t.writeBytesLeft = t.algorithms.w.rekeyBytes() + } + + // we have completed the key exchange. Since the + // reader is still blocked, it is safe to clear out + // the requestKex channel. This avoids the situation + // where: 1) we consumed our own request for the + // initial kex, and 2) the kex from the remote side + // caused another send on the requestKex channel, + clear: + for { + select { + case <-t.requestKex: + // + default: + break clear + } + } + + request.done <- t.writeError + + // kex finished. Push packets that we received while + // the kex was in progress. Don't look at t.startKex + // and don't increment writtenSinceKex: if we trigger + // another kex while we are still busy with the last + // one, things will become very confusing. + for _, p := range t.pendingPackets { + t.writeError = t.pushPacket(p) + if t.writeError != nil { + break + } + } + t.pendingPackets = t.pendingPackets[:0] + t.mu.Unlock() } + // drain startKex channel. We don't service t.requestKex + // because nobody does blocking sends there. + go func() { + for init := range t.startKex { + init.done <- t.writeError + } + }() + + // Unblock reader. + t.conn.Close() +} + +// The protocol uses uint32 for packet counters, so we can't let them +// reach 1<<32. We will actually read and write more packets than +// this, though: the other side may send more packets, and after we +// hit this limit on writing we will send a few more packets for the +// key exchange itself. +const packetRekeyThreshold = (1 << 31) + +func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { p, err := t.conn.readPacket() if err != nil { return nil, err } - t.readSinceKex += uint64(len(p)) - if debugHandshake { - if p[0] == msgChannelData || p[0] == msgChannelExtendedData { - log.Printf("%s got data (packet %d bytes)", t.id(), len(p)) - } else { - msg, err := decode(p) - log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err) - } + if t.readPacketsLeft > 0 { + t.readPacketsLeft-- + } else { + t.requestKeyExchange() } + + if t.readBytesLeft > 0 { + t.readBytesLeft -= int64(len(p)) + } else { + t.requestKeyExchange() + } + + if debugHandshake { + t.printPacket(p, false) + } + + if first && p[0] != msgKexInit { + return nil, fmt.Errorf("ssh: first packet should be msgKexInit") + } + if p[0] != msgKexInit { return p, nil } - t.mu.Lock() - firstKex := t.sessionID == nil - err = t.enterKeyExchangeLocked(p) - if err != nil { - // drop connection - t.conn.Close() - t.writeError = err + kex := pendingKex{ + done: make(chan error, 1), + otherInit: p, } + t.startKex <- &kex + err = <-kex.done if debugHandshake { log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) } - // Unblock writers. - t.sentInitMsg = nil - t.sentInitPacket = nil - t.cond.Broadcast() - t.writtenSinceKex = 0 - t.mu.Unlock() - if err != nil { return nil, err } - t.readSinceKex = 0 + t.readPacketsLeft = packetRekeyThreshold + if t.config.RekeyThreshold > 0 { + t.readBytesLeft = int64(t.config.RekeyThreshold) + } else { + t.readBytesLeft = t.algorithms.r.rekeyBytes() + } // By default, a key exchange is hidden from higher layers by // translating it into msgIgnore. @@ -213,61 +411,16 @@ func (t *handshakeTransport) readOnePacket() ([]byte, error) { return successPacket, nil } -// keyChangeCategory describes whether a key exchange is the first on a -// connection, or a subsequent one. -type keyChangeCategory bool - -const ( - firstKeyExchange keyChangeCategory = true - subsequentKeyExchange keyChangeCategory = false -) - -// sendKexInit sends a key change message, and returns the message -// that was sent. After initiating the key change, all writes will be -// blocked until the change is done, and a failed key change will -// close the underlying transport. This function is safe for -// concurrent use by multiple goroutines. -func (t *handshakeTransport) sendKexInit(isFirst keyChangeCategory) error { - var err error - +// sendKexInit sends a key change message. +func (t *handshakeTransport) sendKexInit() error { t.mu.Lock() - // If this is the initial key change, but we already have a sessionID, - // then do nothing because the key exchange has already completed - // asynchronously. - if !isFirst || t.sessionID == nil { - _, _, err = t.sendKexInitLocked(isFirst) - } - t.mu.Unlock() - if err != nil { - return err - } - if isFirst { - if packet, err := t.readPacket(); err != nil { - return err - } else if packet[0] != msgNewKeys { - return unexpectedMessageError(msgNewKeys, packet[0]) - } - } - return nil -} - -func (t *handshakeTransport) requestInitialKeyChange() error { - return t.sendKexInit(firstKeyExchange) -} - -func (t *handshakeTransport) requestKeyChange() error { - return t.sendKexInit(subsequentKeyExchange) -} - -// sendKexInitLocked sends a key change message. t.mu must be locked -// while this happens. -func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexInitMsg, []byte, error) { - // kexInits may be sent either in response to the other side, - // or because our side wants to initiate a key change, so we - // may have already sent a kexInit. In that case, don't send a - // second kexInit. + defer t.mu.Unlock() if t.sentInitMsg != nil { - return t.sentInitMsg, t.sentInitPacket, nil + // kexInits may be sent either in response to the other side, + // or because our side wants to initiate a key change, so we + // may have already sent a kexInit. In that case, don't send a + // second kexInit. + return nil } msg := &kexInitMsg{ @@ -295,53 +448,65 @@ func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexI packetCopy := make([]byte, len(packet)) copy(packetCopy, packet) - if err := t.conn.writePacket(packetCopy); err != nil { - return nil, nil, err + if err := t.pushPacket(packetCopy); err != nil { + return err } t.sentInitMsg = msg t.sentInitPacket = packet - return msg, packet, nil + + return nil } func (t *handshakeTransport) writePacket(p []byte) error { - t.mu.Lock() - defer t.mu.Unlock() - - if t.writtenSinceKex > t.config.RekeyThreshold { - t.sendKexInitLocked(subsequentKeyExchange) - } - for t.sentInitMsg != nil && t.writeError == nil { - t.cond.Wait() - } - if t.writeError != nil { - return t.writeError - } - t.writtenSinceKex += uint64(len(p)) - switch p[0] { case msgKexInit: return errors.New("ssh: only handshakeTransport can send kexInit") case msgNewKeys: return errors.New("ssh: only handshakeTransport can send newKeys") - default: - return t.conn.writePacket(p) } + + t.mu.Lock() + defer t.mu.Unlock() + if t.writeError != nil { + return t.writeError + } + + if t.sentInitMsg != nil { + // Copy the packet so the writer can reuse the buffer. + cp := make([]byte, len(p)) + copy(cp, p) + t.pendingPackets = append(t.pendingPackets, cp) + return nil + } + + if t.writeBytesLeft > 0 { + t.writeBytesLeft -= int64(len(p)) + } else { + t.requestKeyExchange() + } + + if t.writePacketsLeft > 0 { + t.writePacketsLeft-- + } else { + t.requestKeyExchange() + } + + if err := t.pushPacket(p); err != nil { + t.writeError = err + } + + return nil } func (t *handshakeTransport) Close() error { return t.conn.Close() } -// enterKeyExchange runs the key exchange. t.mu must be held while running this. -func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) error { +func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { if debugHandshake { log.Printf("%s entered key exchange", t.id()) } - myInit, myInitPacket, err := t.sendKexInitLocked(subsequentKeyExchange) - if err != nil { - return err - } otherInit := &kexInitMsg{} if err := Unmarshal(otherInitPacket, otherInit); err != nil { @@ -352,20 +517,20 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro clientVersion: t.clientVersion, serverVersion: t.serverVersion, clientKexInit: otherInitPacket, - serverKexInit: myInitPacket, + serverKexInit: t.sentInitPacket, } clientInit := otherInit - serverInit := myInit + serverInit := t.sentInitMsg if len(t.hostKeys) == 0 { - clientInit = myInit - serverInit = otherInit + clientInit, serverInit = serverInit, clientInit - magics.clientKexInit = myInitPacket + magics.clientKexInit = t.sentInitPacket magics.serverKexInit = otherInitPacket } - algs, err := findAgreedAlgorithms(clientInit, serverInit) + var err error + t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) if err != nil { return err } @@ -388,16 +553,16 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro } } - kex, ok := kexAlgoMap[algs.kex] + kex, ok := kexAlgoMap[t.algorithms.kex] if !ok { - return fmt.Errorf("ssh: unexpected key exchange algorithm %v", algs.kex) + return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) } var result *kexResult if len(t.hostKeys) > 0 { - result, err = t.server(kex, algs, &magics) + result, err = t.server(kex, t.algorithms, &magics) } else { - result, err = t.client(kex, algs, &magics) + result, err = t.client(kex, t.algorithms, &magics) } if err != nil { @@ -409,7 +574,7 @@ func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) erro } result.SessionID = t.sessionID - t.conn.prepareKeyChange(algs, result) + t.conn.prepareKeyChange(t.algorithms, result) if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { return err } diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go index 21f7d0d2..f38de989 100644 --- a/vendor/golang.org/x/crypto/ssh/keys.go +++ b/vendor/golang.org/x/crypto/ssh/keys.go @@ -798,8 +798,8 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { P *big.Int Q *big.Int G *big.Int - Priv *big.Int Pub *big.Int + Priv *big.Int } rest, err := asn1.Unmarshal(der, &k) if err != nil { @@ -816,9 +816,9 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { Q: k.Q, G: k.G, }, - Y: k.Priv, + Y: k.Pub, }, - X: k.Pub, + X: k.Priv, }, nil } diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go index 07744ad6..c07a0628 100644 --- a/vendor/golang.org/x/crypto/ssh/mac.go +++ b/vendor/golang.org/x/crypto/ssh/mac.go @@ -15,6 +15,7 @@ import ( type macMode struct { keySize int + etm bool new func(key []byte) hash.Hash } @@ -45,13 +46,16 @@ func (t truncatingMAC) Size() int { func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } var macModes = map[string]*macMode{ - "hmac-sha2-256": {32, func(key []byte) hash.Hash { + "hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { return hmac.New(sha256.New, key) }}, - "hmac-sha1": {20, func(key []byte) hash.Hash { + "hmac-sha2-256": {32, false, func(key []byte) hash.Hash { + return hmac.New(sha256.New, key) + }}, + "hmac-sha1": {20, false, func(key []byte) hash.Hash { return hmac.New(sha1.New, key) }}, - "hmac-sha1-96": {20, func(key []byte) hash.Hash { + "hmac-sha1-96": {20, false, func(key []byte) hash.Hash { return truncatingMAC{12, hmac.New(sha1.New, key)} }}, } diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go index f3a3ddd7..27a527c1 100644 --- a/vendor/golang.org/x/crypto/ssh/mux.go +++ b/vendor/golang.org/x/crypto/ssh/mux.go @@ -116,9 +116,9 @@ func (m *mux) Wait() error { func newMux(p packetConn) *mux { m := &mux{ conn: p, - incomingChannels: make(chan NewChannel, 16), + incomingChannels: make(chan NewChannel, chanSize), globalResponses: make(chan interface{}, 1), - incomingRequests: make(chan *Request, 16), + incomingRequests: make(chan *Request, chanSize), errCond: newCond(), } if debugMux { diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go index 90374707..77c84d16 100644 --- a/vendor/golang.org/x/crypto/ssh/server.go +++ b/vendor/golang.org/x/crypto/ssh/server.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "net" + "strings" ) // The Permissions type holds fine-grained permissions that are @@ -188,7 +189,7 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) - if err := s.transport.requestInitialKeyChange(); err != nil { + if err := s.transport.waitSession(); err != nil { return nil, err } @@ -231,7 +232,7 @@ func isAcceptableAlgo(algo string) bool { return false } -func checkSourceAddress(addr net.Addr, sourceAddr string) error { +func checkSourceAddress(addr net.Addr, sourceAddrs string) error { if addr == nil { return errors.New("ssh: no address known for client, but source-address match required") } @@ -241,18 +242,20 @@ func checkSourceAddress(addr net.Addr, sourceAddr string) error { return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) } - if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { - if allowedIP.Equal(tcpAddr.IP) { - return nil - } - } else { - _, ipNet, err := net.ParseCIDR(sourceAddr) - if err != nil { - return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) - } + for _, sourceAddr := range strings.Split(sourceAddrs, ",") { + if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { + if allowedIP.Equal(tcpAddr.IP) { + return nil + } + } else { + _, ipNet, err := net.ParseCIDR(sourceAddr) + if err != nil { + return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) + } - if ipNet.Contains(tcpAddr.IP) { - return nil + if ipNet.Contains(tcpAddr.IP) { + return nil + } } } @@ -260,7 +263,7 @@ func checkSourceAddress(addr net.Addr, sourceAddr string) error { } func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { - var err error + sessionID := s.transport.getSessionID() var cache pubKeyCache var perms *Permissions @@ -385,7 +388,7 @@ userAuthLoop: if !isAcceptableAlgo(sig.Format) { break } - signedData := buildDataSignedForAuth(s.transport.getSessionID(), userAuthReq, algoBytes, pubKeyData) + signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) if err := pubKey.Verify(signedData, sig); err != nil { return nil, err @@ -421,12 +424,12 @@ userAuthLoop: return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") } - if err = s.transport.writePacket(Marshal(&failureMsg)); err != nil { + if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { return nil, err } } - if err = s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { + if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { return nil, err } return perms, nil diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go index 62fba629..f9780e0a 100644 --- a/vendor/golang.org/x/crypto/ssh/transport.go +++ b/vendor/golang.org/x/crypto/ssh/transport.go @@ -8,8 +8,13 @@ import ( "bufio" "errors" "io" + "log" ) +// debugTransport if set, will print packet types as they go over the +// wire. No message decoding is done, to minimize the impact on timing. +const debugTransport = false + const ( gcmCipherID = "aes128-gcm@openssh.com" aes128cbcID = "aes128-cbc" @@ -22,7 +27,9 @@ type packetConn interface { // Encrypt and send a packet of data to the remote peer. writePacket(packet []byte) error - // Read a packet from the connection + // Read a packet from the connection. The read is blocking, + // i.e. if error is nil, then the returned byte slice is + // always non-empty. readPacket() ([]byte, error) // Close closes the write-side of the connection. @@ -38,7 +45,7 @@ type transport struct { bufReader *bufio.Reader bufWriter *bufio.Writer rand io.Reader - + isClient bool io.Closer } @@ -84,9 +91,38 @@ func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) err return nil } +func (t *transport) printPacket(p []byte, write bool) { + if len(p) == 0 { + return + } + who := "server" + if t.isClient { + who = "client" + } + what := "read" + if write { + what = "write" + } + + log.Println(what, who, p[0]) +} + // Read and decrypt next packet. -func (t *transport) readPacket() ([]byte, error) { - return t.reader.readPacket(t.bufReader) +func (t *transport) readPacket() (p []byte, err error) { + for { + p, err = t.reader.readPacket(t.bufReader) + if err != nil { + break + } + if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { + break + } + } + if debugTransport { + t.printPacket(p, false) + } + + return p, err } func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { @@ -129,6 +165,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { } func (t *transport) writePacket(packet []byte) error { + if debugTransport { + t.printPacket(packet, true) + } return t.writer.writePacket(t.bufWriter, t.rand, packet) } @@ -169,6 +208,8 @@ func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transp }, Closer: rwc, } + t.isClient = isClient + if isClient { t.reader.dir = serverKeys t.writer.dir = clientKeys @@ -226,6 +267,7 @@ func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (pac c := &streamPacketCipher{ mac: macModes[algs.MAC].new(macKey), + etm: macModes[algs.MAC].etm, } c.macResult = make([]byte, c.mac.Size()) diff --git a/vendor/vendor.json b/vendor/vendor.json index 0e4cf311..3ec3c9df 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -375,10 +375,10 @@ "revisionTime": "2016-12-13T22:25:08Z" }, { - "checksumSHA1": "RnJfaFwKpC0h06J2MZ8UZX2eohc=", + "checksumSHA1": "fsrFs762jlaILyqqQImS1GfvIvw=", "path": "golang.org/x/crypto/ssh", - "revision": "d8e61c69ab46ca38328da2f4995abaf93b252290", - "revisionTime": "2016-12-13T22:25:08Z" + "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8", + "revisionTime": "2017-02-08T20:51:15Z" }, { "checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",