LEFT | RIGHT |
1 // Copyright 2011 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 package ssh | 5 package ssh |
6 | 6 |
7 import ( | 7 import ( |
8 "errors" | 8 "errors" |
9 "fmt" | 9 "fmt" |
10 "io" | 10 "io" |
11 "log" | 11 "log" |
12 "net" | 12 "net" |
13 "sync" | 13 "sync" |
14 ) | 14 ) |
15 | 15 |
16 // If set, debug will log print messages sent and received. | 16 // If set, debug will log print messages sent and received. |
17 //const debug = false | |
18 const debug = false | 17 const debug = false |
19 | 18 |
20 // keyingTransport is packet based transport that supports key | 19 // keyingTransport is a packet based transport that supports key |
21 // changes. It need not be thread-safe. It should pass through | 20 // changes. It need not be thread-safe. It should pass through |
22 // msgNewKeys in both directions. | 21 // msgNewKeys in both directions. |
23 type keyingTransport interface { | 22 type keyingTransport interface { |
24 packetConn | 23 packetConn |
25 | 24 |
26 // prepareKeyChange sets up a key change. The key change for a | 25 // prepareKeyChange sets up a key change. The key change for a |
27 // direction will be effected if a msgNewKeys message is sent | 26 // direction will be effected if a msgNewKeys message is sent |
28 // or received. | 27 // or received. |
29 prepareKeyChange(*algorithms, *kexResult) error | 28 prepareKeyChange(*algorithms, *kexResult) error |
30 | 29 |
31 » // Returns the session ID. prepareKeyChange must have been | 30 » // getSessionID returns the session ID. prepareKeyChange must |
32 » // called once. | 31 » // have been called once. |
33 » SessionID() []byte | 32 » getSessionID() []byte |
| 33 } |
| 34 |
| 35 // rekeyingTransport is the interface of handshakeTransport that we |
| 36 // (internally) expose to ClientConn and ServerConn. |
| 37 type rekeyingTransport interface { |
| 38 » packetConn |
| 39 |
| 40 » // requestKeyChange asks the remote side to change keys. All |
| 41 » // writes are blocked until the key change succeeds, which is |
| 42 » // signaled by reading a msgNewKeys. |
| 43 » requestKeyChange() error |
| 44 |
| 45 » // getSessionID returns the session ID. This is only valid |
| 46 » // after the first key change has completed. |
| 47 » getSessionID() []byte |
34 } | 48 } |
35 | 49 |
36 // handshakeTransport implements rekeying on top of a keyingTransport | 50 // handshakeTransport implements rekeying on top of a keyingTransport |
37 // and offers a thread-safe writePacket() interface. | 51 // and offers a thread-safe writePacket() interface. |
38 type handshakeTransport struct { | 52 type handshakeTransport struct { |
39 conn keyingTransport | 53 conn keyingTransport |
40 config *CryptoConfig | 54 config *CryptoConfig |
41 | 55 |
42 » // (why is Rand not part of CryptoConfig?) | 56 » // TODO(hanwen): move Rand into CryptoConfig. |
43 rand func() io.Reader | 57 rand func() io.Reader |
44 | 58 |
45 serverVersion []byte | 59 serverVersion []byte |
46 clientVersion []byte | 60 clientVersion []byte |
47 | 61 |
48 hostKeys []Signer // If hostKeys are given, we are the server. | 62 hostKeys []Signer // If hostKeys are given, we are the server. |
49 | 63 |
50 // On read error, incoming is closed, and readError is set. | 64 // On read error, incoming is closed, and readError is set. |
51 incoming chan []byte | 65 incoming chan []byte |
52 readError error | 66 readError error |
53 | 67 |
54 // data for host key checking | 68 // data for host key checking |
55 checker HostKeyChecker | 69 checker HostKeyChecker |
56 dialAddress string | 70 dialAddress string |
57 remoteAddr net.Addr | 71 remoteAddr net.Addr |
58 | 72 |
59 » kexLimit uint64 // rekey after sending/receiving this much data. | 73 » rekeyThreshold uint64 // rekey after sending/receiving this much data. |
60 » readSinceKex uint64 | 74 » readSinceKex uint64 |
61 | 75 |
62 // Protects the writing side of the connection | 76 // Protects the writing side of the connection |
63 mu sync.Mutex | 77 mu sync.Mutex |
64 cond *sync.Cond | 78 cond *sync.Cond |
65 sentInitPacket []byte | 79 sentInitPacket []byte |
66 sentInitMsg *kexInitMsg | 80 sentInitMsg *kexInitMsg |
67 writtenSinceKex uint64 | 81 writtenSinceKex uint64 |
68 writeError error | 82 writeError error |
69 } | 83 } |
70 | 84 |
(...skipping 20 matching lines...) Expand all Loading... |
91 | 105 |
92 func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byt
e, config *ServerConfig) *handshakeTransport { | 106 func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byt
e, config *ServerConfig) *handshakeTransport { |
93 t := newHandshakeTransport(conn, clientVersion, serverVersion) | 107 t := newHandshakeTransport(conn, clientVersion, serverVersion) |
94 t.setCryptoConfig(&config.Crypto) | 108 t.setCryptoConfig(&config.Crypto) |
95 t.hostKeys = config.hostKeys | 109 t.hostKeys = config.hostKeys |
96 t.rand = config.rand | 110 t.rand = config.rand |
97 go t.readLoop() | 111 go t.readLoop() |
98 return t | 112 return t |
99 } | 113 } |
100 | 114 |
101 func (t *handshakeTransport) SessionID() []byte { | 115 func (t *handshakeTransport) getSessionID() []byte { |
102 » return t.conn.SessionID() | 116 » return t.conn.getSessionID() |
103 } | 117 } |
104 | 118 |
105 func (t *handshakeTransport) setCryptoConfig(c *CryptoConfig) { | 119 func (t *handshakeTransport) setCryptoConfig(c *CryptoConfig) { |
106 t.config = c | 120 t.config = c |
107 » t.kexLimit = t.config.RekeyThreshold | 121 » t.rekeyThreshold = t.config.RekeyThreshold |
108 » if t.kexLimit == 0 { | 122 » if t.rekeyThreshold == 0 { |
109 // RFC 4253, section 9 suggests rekeying after 1G. | 123 // RFC 4253, section 9 suggests rekeying after 1G. |
110 » » t.kexLimit = 1 << 30 | 124 » » t.rekeyThreshold = 1 << 30 |
111 } | 125 } |
112 } | 126 } |
113 | 127 |
114 func (t *handshakeTransport) id() string { | 128 func (t *handshakeTransport) id() string { |
115 if len(t.hostKeys) > 0 { | 129 if len(t.hostKeys) > 0 { |
116 return "server" | 130 return "server" |
117 } | 131 } |
118 return "client" | 132 return "client" |
119 } | 133 } |
120 | 134 |
(...skipping 14 matching lines...) Expand all Loading... |
135 break | 149 break |
136 } | 150 } |
137 if p[0] == msgIgnore || p[0] == msgDebug { | 151 if p[0] == msgIgnore || p[0] == msgDebug { |
138 continue | 152 continue |
139 } | 153 } |
140 t.incoming <- p | 154 t.incoming <- p |
141 } | 155 } |
142 } | 156 } |
143 | 157 |
144 func (t *handshakeTransport) readOnePacket() ([]byte, error) { | 158 func (t *handshakeTransport) readOnePacket() ([]byte, error) { |
145 » if t.readSinceKex > t.kexLimit { | 159 » if t.readSinceKex > t.rekeyThreshold { |
146 » » _, _, err := t.sendKexInit() | 160 » » if err := t.requestKeyChange(); err != nil { |
147 » » if err != nil { | |
148 return nil, err | 161 return nil, err |
149 } | 162 } |
150 } | 163 } |
151 | 164 |
152 p, err := t.conn.readPacket() | 165 p, err := t.conn.readPacket() |
153 if err != nil { | 166 if err != nil { |
154 return nil, err | 167 return nil, err |
155 } | 168 } |
156 | 169 |
157 t.readSinceKex += uint64(len(p)) | 170 t.readSinceKex += uint64(len(p)) |
158 if debug { | 171 if debug { |
159 msg, err := decode(p) | 172 msg, err := decode(p) |
160 log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err) | 173 log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err) |
161 } | 174 } |
162 » if p[0] == msgKexInit { | 175 » if p[0] != msgKexInit { |
163 » » err = t.enterKeyExchange(p) | |
164 | |
165 » » t.mu.Lock() | |
166 » » if err != nil { | |
167 » » » // drop connection | |
168 » » » t.conn.Close() | |
169 » » » t.writeError = err | |
170 » » } | |
171 | |
172 » » if debug { | |
173 » » » log.Printf("%s exited key exchange, err %v", t.id(), err
) | |
174 » » } | |
175 | |
176 » » // Unblock writers. | |
177 » » t.sentInitMsg = nil | |
178 » » t.sentInitPacket = nil | |
179 » » t.cond.Broadcast() | |
180 » » t.writtenSinceKex = 0 | |
181 » » t.mu.Unlock() | |
182 | |
183 » » if err != nil { | |
184 » » » return nil, err | |
185 » » } | |
186 | |
187 » » t.readSinceKex = 0 | |
188 » » return []byte{msgNewKeys}, nil | |
189 » } else { | |
190 return p, nil | 176 return p, nil |
191 } | 177 } |
| 178 err = t.enterKeyExchange(p) |
| 179 |
| 180 t.mu.Lock() |
| 181 if err != nil { |
| 182 // drop connection |
| 183 t.conn.Close() |
| 184 t.writeError = err |
| 185 } |
| 186 |
| 187 if debug { |
| 188 log.Printf("%s exited key exchange, err %v", t.id(), err) |
| 189 } |
| 190 |
| 191 // Unblock writers. |
| 192 t.sentInitMsg = nil |
| 193 t.sentInitPacket = nil |
| 194 t.cond.Broadcast() |
| 195 t.writtenSinceKex = 0 |
| 196 t.mu.Unlock() |
| 197 |
| 198 if err != nil { |
| 199 return nil, err |
| 200 } |
| 201 |
| 202 t.readSinceKex = 0 |
| 203 return []byte{msgNewKeys}, nil |
192 } | 204 } |
193 | 205 |
194 // sendKexInit sends a key change message, and returns the message | 206 // sendKexInit sends a key change message, and returns the message |
195 // that was sent. A failed key change will close the underlying | 207 // that was sent. After initiating the key change, all writes will be |
196 // transport. This function is safe for concurrent use by multiple | 208 // blocked until the change is done, and a failed key change will |
197 // goroutines. | 209 // close the underlying transport. This function is safe for |
| 210 // concurrent use by multiple goroutines. |
198 func (t *handshakeTransport) sendKexInit() (*kexInitMsg, []byte, error) { | 211 func (t *handshakeTransport) sendKexInit() (*kexInitMsg, []byte, error) { |
199 t.mu.Lock() | 212 t.mu.Lock() |
200 defer t.mu.Unlock() | 213 defer t.mu.Unlock() |
201 » return t.unlockedSendKexInit() | 214 » return t.sendKexInitLocked() |
202 } | 215 } |
203 | 216 |
204 func (t *handshakeTransport) unlockedSendKexInit() (*kexInitMsg, []byte, error)
{ | 217 func (t *handshakeTransport) requestKeyChange() error { |
| 218 » _, _, err := t.sendKexInit() |
| 219 » return err |
| 220 } |
| 221 |
| 222 // sendKexInitLocked sends a key change message. t.mu must be locked |
| 223 // while this happens. |
| 224 func (t *handshakeTransport) sendKexInitLocked() (*kexInitMsg, []byte, error) { |
| 225 » // kexInits may be sent either in response to the other side, |
| 226 » // or because our side wants to initiate a key change, so we |
| 227 » // may have already sent a kexInit. In that case, don't send a |
| 228 » // second kexInit. |
205 if t.sentInitMsg != nil { | 229 if t.sentInitMsg != nil { |
206 // Since send and receive of kex inits are not | |
207 // ordered, so it may happen that another key change | |
208 // already was underway and we sent an init already. | |
209 return t.sentInitMsg, t.sentInitPacket, nil | 230 return t.sentInitMsg, t.sentInitPacket, nil |
210 } | 231 } |
211 msg := &kexInitMsg{ | 232 msg := &kexInitMsg{ |
212 KexAlgos: t.config.kexes(), | 233 KexAlgos: t.config.kexes(), |
213 CiphersClientServer: t.config.ciphers(), | 234 CiphersClientServer: t.config.ciphers(), |
214 CiphersServerClient: t.config.ciphers(), | 235 CiphersServerClient: t.config.ciphers(), |
215 MACsClientServer: t.config.macs(), | 236 MACsClientServer: t.config.macs(), |
216 MACsServerClient: t.config.macs(), | 237 MACsServerClient: t.config.macs(), |
217 CompressionClientServer: supportedCompressions, | 238 CompressionClientServer: supportedCompressions, |
218 CompressionServerClient: supportedCompressions, | 239 CompressionServerClient: supportedCompressions, |
219 } | 240 } |
| 241 |
| 242 // TODO(hanwen): add random bits to kexInit.Cookie. |
| 243 |
220 if len(t.hostKeys) > 0 { | 244 if len(t.hostKeys) > 0 { |
221 for _, k := range t.hostKeys { | 245 for _, k := range t.hostKeys { |
222 msg.ServerHostKeyAlgos = append( | 246 msg.ServerHostKeyAlgos = append( |
223 msg.ServerHostKeyAlgos, k.PublicKey().PublicKeyA
lgo()) | 247 msg.ServerHostKeyAlgos, k.PublicKey().PublicKeyA
lgo()) |
224 } | 248 } |
225 } else { | 249 } else { |
226 msg.ServerHostKeyAlgos = supportedHostKeyAlgos | 250 msg.ServerHostKeyAlgos = supportedHostKeyAlgos |
227 } | 251 } |
228 packet := marshal(msgKexInit, *msg) | 252 packet := marshal(msgKexInit, *msg) |
229 | 253 |
230 // writePacket destroys the contents, so save a copy. | 254 // writePacket destroys the contents, so save a copy. |
231 packetCopy := make([]byte, len(packet)) | 255 packetCopy := make([]byte, len(packet)) |
232 copy(packetCopy, packet) | 256 copy(packetCopy, packet) |
233 | 257 |
234 if err := t.conn.writePacket(packetCopy); err != nil { | 258 if err := t.conn.writePacket(packetCopy); err != nil { |
235 return nil, nil, err | 259 return nil, nil, err |
236 } | 260 } |
237 | 261 |
238 t.sentInitMsg = msg | 262 t.sentInitMsg = msg |
239 t.sentInitPacket = packet | 263 t.sentInitPacket = packet |
240 return msg, packet, nil | 264 return msg, packet, nil |
241 } | 265 } |
242 | 266 |
243 func (t *handshakeTransport) writePacket(p []byte) error { | 267 func (t *handshakeTransport) writePacket(p []byte) error { |
244 t.mu.Lock() | 268 t.mu.Lock() |
245 » if t.writtenSinceKex > t.kexLimit { | 269 » if t.writtenSinceKex > t.rekeyThreshold { |
246 » » t.unlockedSendKexInit() | 270 » » t.sendKexInitLocked() |
247 } | 271 } |
248 for t.sentInitMsg != nil { | 272 for t.sentInitMsg != nil { |
249 t.cond.Wait() | 273 t.cond.Wait() |
250 } | 274 } |
251 if t.writeError != nil { | 275 if t.writeError != nil { |
252 return t.writeError | 276 return t.writeError |
253 } | 277 } |
254 t.writtenSinceKex += uint64(len(p)) | 278 t.writtenSinceKex += uint64(len(p)) |
255 | 279 |
256 var err error | 280 var err error |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 | 324 |
301 magics.clientKexInit = myInitPacket | 325 magics.clientKexInit = myInitPacket |
302 magics.serverKexInit = otherInitPacket | 326 magics.serverKexInit = otherInitPacket |
303 } | 327 } |
304 | 328 |
305 algs := findAgreedAlgorithms(clientInit, serverInit) | 329 algs := findAgreedAlgorithms(clientInit, serverInit) |
306 if algs == nil { | 330 if algs == nil { |
307 return errors.New("ssh: no common algorithms") | 331 return errors.New("ssh: no common algorithms") |
308 } | 332 } |
309 | 333 |
310 » // TODO(hanwen): add random bits to kexInit.Cookie. | 334 » // We don't send FirstKexFollows, but we handle receiving it. |
311 | |
312 » // We don't send FirstKexFollows, but we handle receiving it | |
313 if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] { | 335 if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] { |
314 // other side sent a kex message for the wrong algorithm, | 336 // other side sent a kex message for the wrong algorithm, |
315 // which we have to ignore. | 337 // which we have to ignore. |
316 if _, err := t.conn.readPacket(); err != nil { | 338 if _, err := t.conn.readPacket(); err != nil { |
317 return err | 339 return err |
318 } | 340 } |
319 } | 341 } |
320 | 342 |
321 kex, ok := kexAlgoMap[algs.kex] | 343 kex, ok := kexAlgoMap[algs.kex] |
322 if !ok { | 344 if !ok { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 | 392 |
371 if t.checker != nil { | 393 if t.checker != nil { |
372 err = t.checker.Check(t.dialAddress, t.remoteAddr, algs.hostKey,
result.HostKey) | 394 err = t.checker.Check(t.dialAddress, t.remoteAddr, algs.hostKey,
result.HostKey) |
373 if err != nil { | 395 if err != nil { |
374 return nil, err | 396 return nil, err |
375 } | 397 } |
376 } | 398 } |
377 | 399 |
378 return result, nil | 400 return result, nil |
379 } | 401 } |
380 | |
381 // verifyHostKeySignature verifies the host key obtained in the key | |
382 // exchange. | |
383 func verifyHostKeySignature(hostKeyAlgo string, result *kexResult) error { | |
384 hostKey, rest, ok := ParsePublicKey(result.HostKey) | |
385 if len(rest) > 0 || !ok { | |
386 return errors.New("ssh: could not parse hostkey") | |
387 } | |
388 | |
389 sig, rest, ok := parseSignatureBody(result.Signature) | |
390 if len(rest) > 0 || !ok { | |
391 return errors.New("ssh: signature parse error") | |
392 } | |
393 if sig.Format != hostKeyAlgo { | |
394 return fmt.Errorf("ssh: got signature type %q, want %q", sig.For
mat, hostKeyAlgo) | |
395 } | |
396 | |
397 if !hostKey.Verify(result.H, sig.Blob) { | |
398 return errors.New("ssh: host key signature error") | |
399 } | |
400 return nil | |
401 } | |
LEFT | RIGHT |