|
| 1 | +diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go |
| 2 | +index 653dc4d..e7d4545 100644 |
| 3 | +--- a/vendor/golang.org/x/crypto/ssh/handshake.go |
| 4 | ++++ b/vendor/golang.org/x/crypto/ssh/handshake.go |
| 5 | +@@ -34,6 +34,16 @@ type keyingTransport interface { |
| 6 | + // direction will be effected if a msgNewKeys message is sent |
| 7 | + // or received. |
| 8 | + prepareKeyChange(*algorithms, *kexResult) error |
| 9 | ++ |
| 10 | ++ // setStrictMode sets the strict KEX mode, notably triggering |
| 11 | ++ // sequence number resets on sending or receiving msgNewKeys. |
| 12 | ++ // If the sequence number is already > 1 when setStrictMode |
| 13 | ++ // is called, an error is returned. |
| 14 | ++ setStrictMode() error |
| 15 | ++ |
| 16 | ++ // setInitialKEXDone indicates to the transport that the initial key exchange |
| 17 | ++ // was completed |
| 18 | ++ setInitialKEXDone() |
| 19 | + } |
| 20 | + |
| 21 | + // handshakeTransport implements rekeying on top of a keyingTransport |
| 22 | +@@ -94,6 +104,10 @@ type handshakeTransport struct { |
| 23 | + |
| 24 | + // The session ID or nil if first kex did not complete yet. |
| 25 | + sessionID []byte |
| 26 | ++ |
| 27 | ++ // strictMode indicates if the other side of the handshake indicated |
| 28 | ++ // that we should be following the strict KEX protocol restrictions. |
| 29 | ++ strictMode bool |
| 30 | + } |
| 31 | + |
| 32 | + type pendingKex struct { |
| 33 | +@@ -201,7 +215,10 @@ func (t *handshakeTransport) readLoop() { |
| 34 | + close(t.incoming) |
| 35 | + break |
| 36 | + } |
| 37 | +- if p[0] == msgIgnore || p[0] == msgDebug { |
| 38 | ++ // If this is the first kex, and strict KEX mode is enabled, |
| 39 | ++ // we don't ignore any messages, as they may be used to manipulate |
| 40 | ++ // the packet sequence numbers. |
| 41 | ++ if !(t.sessionID == nil && t.strictMode) && (p[0] == msgIgnore || p[0] == msgDebug) { |
| 42 | + continue |
| 43 | + } |
| 44 | + t.incoming <- p |
| 45 | +@@ -432,6 +449,11 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { |
| 46 | + return successPacket, nil |
| 47 | + } |
| 48 | + |
| 49 | ++const ( |
| 50 | ++ kexStrictClient = "kex-strict-c-v00@openssh.com" |
| 51 | ++ kexStrictServer = "kex-strict-s-v00@openssh.com" |
| 52 | ++) |
| 53 | ++ |
| 54 | + // sendKexInit sends a key change message. |
| 55 | + func (t *handshakeTransport) sendKexInit() error { |
| 56 | + t.mu.Lock() |
| 57 | +@@ -445,7 +467,6 @@ func (t *handshakeTransport) sendKexInit() error { |
| 58 | + } |
| 59 | + |
| 60 | + msg := &kexInitMsg{ |
| 61 | +- KexAlgos: t.config.KeyExchanges, |
| 62 | + CiphersClientServer: t.config.Ciphers, |
| 63 | + CiphersServerClient: t.config.Ciphers, |
| 64 | + MACsClientServer: t.config.MACs, |
| 65 | +@@ -455,6 +476,13 @@ func (t *handshakeTransport) sendKexInit() error { |
| 66 | + } |
| 67 | + io.ReadFull(rand.Reader, msg.Cookie[:]) |
| 68 | + |
| 69 | ++ // We mutate the KexAlgos slice, in order to add the kex-strict extension algorithm, |
| 70 | ++ // and possibly to add the ext-info extension algorithm. Since the slice may be the |
| 71 | ++ // user owned KeyExchanges, we create our own slice in order to avoid using user |
| 72 | ++ // owned memory by mistake. |
| 73 | ++ msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+2) // room for kex-strict and ext-info |
| 74 | ++ msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...) |
| 75 | ++ |
| 76 | + isServer := len(t.hostKeys) > 0 |
| 77 | + if isServer { |
| 78 | + for _, k := range t.hostKeys { |
| 79 | +@@ -474,17 +502,24 @@ func (t *handshakeTransport) sendKexInit() error { |
| 80 | + msg.ServerHostKeyAlgos = append(msg.ServerHostKeyAlgos, keyFormat) |
| 81 | + } |
| 82 | + } |
| 83 | ++ |
| 84 | ++ if t.sessionID == nil { |
| 85 | ++ msg.KexAlgos = append(msg.KexAlgos, kexStrictServer) |
| 86 | ++ } |
| 87 | + } else { |
| 88 | + msg.ServerHostKeyAlgos = t.hostKeyAlgorithms |
| 89 | + |
| 90 | + // As a client we opt in to receiving SSH_MSG_EXT_INFO so we know what |
| 91 | + // algorithms the server supports for public key authentication. See RFC |
| 92 | + // 8308, Section 2.1. |
| 93 | ++ // |
| 94 | ++ // We also send the strict KEX mode extension algorithm, in order to opt |
| 95 | ++ // into the strict KEX mode. |
| 96 | + if firstKeyExchange := t.sessionID == nil; firstKeyExchange { |
| 97 | +- msg.KexAlgos = make([]string, 0, len(t.config.KeyExchanges)+1) |
| 98 | +- msg.KexAlgos = append(msg.KexAlgos, t.config.KeyExchanges...) |
| 99 | + msg.KexAlgos = append(msg.KexAlgos, "ext-info-c") |
| 100 | ++ msg.KexAlgos = append(msg.KexAlgos, kexStrictClient) |
| 101 | + } |
| 102 | ++ |
| 103 | + } |
| 104 | + |
| 105 | + packet := Marshal(msg) |
| 106 | +@@ -581,6 +616,13 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { |
| 107 | + return err |
| 108 | + } |
| 109 | + |
| 110 | ++ if t.sessionID == nil && ((isClient && contains(serverInit.KexAlgos, kexStrictServer)) || (!isClient && contains(clientInit.KexAlgos, kexStrictClient))) { |
| 111 | ++ t.strictMode = true |
| 112 | ++ if err := t.conn.setStrictMode(); err != nil { |
| 113 | ++ return err |
| 114 | ++ } |
| 115 | ++ } |
| 116 | ++ |
| 117 | + // We don't send FirstKexFollows, but we handle receiving it. |
| 118 | + // |
| 119 | + // RFC 4253 section 7 defines the kex and the agreement method for |
| 120 | +@@ -615,7 +657,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { |
| 121 | + return err |
| 122 | + } |
| 123 | + |
| 124 | +- if t.sessionID == nil { |
| 125 | ++ firstKeyExchange := t.sessionID == nil |
| 126 | ++ if firstKeyExchange { |
| 127 | + t.sessionID = result.H |
| 128 | + } |
| 129 | + result.SessionID = t.sessionID |
| 130 | +@@ -632,6 +675,12 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { |
| 131 | + return unexpectedMessageError(msgNewKeys, packet[0]) |
| 132 | + } |
| 133 | + |
| 134 | ++ if firstKeyExchange { |
| 135 | ++ // Indicates to the transport that the first key exchange is completed |
| 136 | ++ // after receiving SSH_MSG_NEWKEYS. |
| 137 | ++ t.conn.setInitialKEXDone() |
| 138 | ++ } |
| 139 | ++ |
| 140 | + return nil |
| 141 | + } |
| 142 | + |
| 143 | +diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go |
| 144 | +index acf5a21..4df45fc 100644 |
| 145 | +--- a/vendor/golang.org/x/crypto/ssh/transport.go |
| 146 | ++++ b/vendor/golang.org/x/crypto/ssh/transport.go |
| 147 | +@@ -48,6 +48,9 @@ type transport struct { |
| 148 | + rand io.Reader |
| 149 | + isClient bool |
| 150 | + io.Closer |
| 151 | ++ |
| 152 | ++ strictMode bool |
| 153 | ++ initialKEXDone bool |
| 154 | + } |
| 155 | + |
| 156 | + // packetCipher represents a combination of SSH encryption/MAC |
| 157 | +@@ -73,6 +76,18 @@ type connectionState struct { |
| 158 | + pendingKeyChange chan packetCipher |
| 159 | + } |
| 160 | + |
| 161 | ++func (t *transport) setStrictMode() error { |
| 162 | ++ if t.reader.seqNum != 1 { |
| 163 | ++ return errors.New("ssh: sequence number != 1 when strict KEX mode requested") |
| 164 | ++ } |
| 165 | ++ t.strictMode = true |
| 166 | ++ return nil |
| 167 | ++} |
| 168 | ++ |
| 169 | ++func (t *transport) setInitialKEXDone() { |
| 170 | ++ t.initialKEXDone = true |
| 171 | ++} |
| 172 | ++ |
| 173 | + // prepareKeyChange sets up key material for a keychange. The key changes in |
| 174 | + // both directions are triggered by reading and writing a msgNewKey packet |
| 175 | + // respectively. |
| 176 | +@@ -111,11 +126,12 @@ func (t *transport) printPacket(p []byte, write bool) { |
| 177 | + // Read and decrypt next packet. |
| 178 | + func (t *transport) readPacket() (p []byte, err error) { |
| 179 | + for { |
| 180 | +- p, err = t.reader.readPacket(t.bufReader) |
| 181 | ++ p, err = t.reader.readPacket(t.bufReader, t.strictMode) |
| 182 | + if err != nil { |
| 183 | + break |
| 184 | + } |
| 185 | +- if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) { |
| 186 | ++ // in strict mode we pass through DEBUG and IGNORE packets only during the initial KEX |
| 187 | ++ if len(p) == 0 || (t.strictMode && !t.initialKEXDone) || (p[0] != msgIgnore && p[0] != msgDebug) { |
| 188 | + break |
| 189 | + } |
| 190 | + } |
| 191 | +@@ -126,7 +142,7 @@ func (t *transport) readPacket() (p []byte, err error) { |
| 192 | + return p, err |
| 193 | + } |
| 194 | + |
| 195 | +-func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { |
| 196 | ++func (s *connectionState) readPacket(r *bufio.Reader, strictMode bool) ([]byte, error) { |
| 197 | + packet, err := s.packetCipher.readCipherPacket(s.seqNum, r) |
| 198 | + s.seqNum++ |
| 199 | + if err == nil && len(packet) == 0 { |
| 200 | +@@ -139,6 +155,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) { |
| 201 | + select { |
| 202 | + case cipher := <-s.pendingKeyChange: |
| 203 | + s.packetCipher = cipher |
| 204 | ++ if strictMode { |
| 205 | ++ s.seqNum = 0 |
| 206 | ++ } |
| 207 | + default: |
| 208 | + return nil, errors.New("ssh: got bogus newkeys message") |
| 209 | + } |
| 210 | +@@ -169,10 +188,10 @@ func (t *transport) writePacket(packet []byte) error { |
| 211 | + if debugTransport { |
| 212 | + t.printPacket(packet, true) |
| 213 | + } |
| 214 | +- return t.writer.writePacket(t.bufWriter, t.rand, packet) |
| 215 | ++ return t.writer.writePacket(t.bufWriter, t.rand, packet, t.strictMode) |
| 216 | + } |
| 217 | + |
| 218 | +-func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error { |
| 219 | ++func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte, strictMode bool) error { |
| 220 | + changeKeys := len(packet) > 0 && packet[0] == msgNewKeys |
| 221 | + |
| 222 | + err := s.packetCipher.writeCipherPacket(s.seqNum, w, rand, packet) |
| 223 | +@@ -187,6 +206,9 @@ func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet [] |
| 224 | + select { |
| 225 | + case cipher := <-s.pendingKeyChange: |
| 226 | + s.packetCipher = cipher |
| 227 | ++ if strictMode { |
| 228 | ++ s.seqNum = 0 |
| 229 | ++ } |
| 230 | + default: |
| 231 | + panic("ssh: no key material for msgNewKeys") |
| 232 | + } |
0 commit comments