~juju-qa/ubuntu/xenial/juju/2.0-rc2

« back to all changes in this revision

Viewing changes to src/golang.org/x/crypto/ssh/handshake.go

  • Committer: Nicholas Skaggs
  • Date: 2016-09-30 14:39:30 UTC
  • mfrom: (1.8.1)
  • Revision ID: nicholas.skaggs@canonical.com-20160930143930-vwwhrefh6ftckccy
import upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
        // direction will be effected if a msgNewKeys message is sent
30
30
        // or received.
31
31
        prepareKeyChange(*algorithms, *kexResult) error
32
 
 
33
 
        // getSessionID returns the session ID. prepareKeyChange must
34
 
        // have been called once.
35
 
        getSessionID() []byte
36
 
}
37
 
 
38
 
// rekeyingTransport is the interface of handshakeTransport that we
39
 
// (internally) expose to ClientConn and ServerConn.
40
 
type rekeyingTransport interface {
41
 
        packetConn
42
 
 
43
 
        // requestKeyChange asks the remote side to change keys. All
44
 
        // writes are blocked until the key change succeeds, which is
45
 
        // signaled by reading a msgNewKeys.
46
 
        requestKeyChange() error
47
 
 
48
 
        // getSessionID returns the session ID. This is only valid
49
 
        // after the first key change has completed.
50
 
        getSessionID() []byte
51
32
}
52
33
 
53
34
// handshakeTransport implements rekeying on top of a keyingTransport
86
67
        sentInitMsg     *kexInitMsg
87
68
        writtenSinceKex uint64
88
69
        writeError      error
 
70
 
 
71
        // The session ID or nil if first kex did not complete yet.
 
72
        sessionID []byte
89
73
}
90
74
 
91
75
func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport {
122
106
}
123
107
 
124
108
func (t *handshakeTransport) getSessionID() []byte {
125
 
        return t.conn.getSessionID()
 
109
        return t.sessionID
126
110
}
127
111
 
128
112
func (t *handshakeTransport) id() string {
177
161
 
178
162
        t.readSinceKex += uint64(len(p))
179
163
        if debugHandshake {
180
 
                msg, err := decode(p)
181
 
                log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err)
 
164
                if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
 
165
                        log.Printf("%s got data (packet %d bytes)", t.id(), len(p))
 
166
                } else {
 
167
                        msg, err := decode(p)
 
168
                        log.Printf("%s got %T %v (%v)", t.id(), msg, msg, err)
 
169
                }
182
170
        }
183
171
        if p[0] != msgKexInit {
184
172
                return p, nil
185
173
        }
186
 
        err = t.enterKeyExchange(p)
187
174
 
188
175
        t.mu.Lock()
 
176
 
 
177
        firstKex := t.sessionID == nil
 
178
 
 
179
        err = t.enterKeyExchangeLocked(p)
189
180
        if err != nil {
190
181
                // drop connection
191
182
                t.conn.Close()
193
184
        }
194
185
 
195
186
        if debugHandshake {
196
 
                log.Printf("%s exited key exchange, err %v", t.id(), err)
 
187
                log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err)
197
188
        }
198
189
 
199
190
        // Unblock writers.
208
199
        }
209
200
 
210
201
        t.readSinceKex = 0
211
 
        return []byte{msgNewKeys}, nil
 
202
 
 
203
        // By default, a key exchange is hidden from higher layers by
 
204
        // translating it into msgIgnore.
 
205
        successPacket := []byte{msgIgnore}
 
206
        if firstKex {
 
207
                // sendKexInit() for the first kex waits for
 
208
                // msgNewKeys so the authentication process is
 
209
                // guaranteed to happen over an encrypted transport.
 
210
                successPacket = []byte{msgNewKeys}
 
211
        }
 
212
 
 
213
        return successPacket, nil
212
214
}
213
215
 
 
216
// keyChangeCategory describes whether a key exchange is the first on a
 
217
// connection, or a subsequent one.
 
218
type keyChangeCategory bool
 
219
 
 
220
const (
 
221
        firstKeyExchange      keyChangeCategory = true
 
222
        subsequentKeyExchange keyChangeCategory = false
 
223
)
 
224
 
214
225
// sendKexInit sends a key change message, and returns the message
215
226
// that was sent. After initiating the key change, all writes will be
216
227
// blocked until the change is done, and a failed key change will
217
228
// close the underlying transport. This function is safe for
218
229
// concurrent use by multiple goroutines.
219
 
func (t *handshakeTransport) sendKexInit() (*kexInitMsg, []byte, error) {
 
230
func (t *handshakeTransport) sendKexInit(isFirst keyChangeCategory) error {
 
231
        var err error
 
232
 
220
233
        t.mu.Lock()
221
 
        defer t.mu.Unlock()
222
 
        return t.sendKexInitLocked()
 
234
        // If this is the initial key change, but we already have a sessionID,
 
235
        // then do nothing because the key exchange has already completed
 
236
        // asynchronously.
 
237
        if !isFirst || t.sessionID == nil {
 
238
                _, _, err = t.sendKexInitLocked(isFirst)
 
239
        }
 
240
        t.mu.Unlock()
 
241
        if err != nil {
 
242
                return err
 
243
        }
 
244
        if isFirst {
 
245
                if packet, err := t.readPacket(); err != nil {
 
246
                        return err
 
247
                } else if packet[0] != msgNewKeys {
 
248
                        return unexpectedMessageError(msgNewKeys, packet[0])
 
249
                }
 
250
        }
 
251
        return nil
 
252
}
 
253
 
 
254
func (t *handshakeTransport) requestInitialKeyChange() error {
 
255
        return t.sendKexInit(firstKeyExchange)
223
256
}
224
257
 
225
258
func (t *handshakeTransport) requestKeyChange() error {
226
 
        _, _, err := t.sendKexInit()
227
 
        return err
 
259
        return t.sendKexInit(subsequentKeyExchange)
228
260
}
229
261
 
230
262
// sendKexInitLocked sends a key change message. t.mu must be locked
231
263
// while this happens.
232
 
func (t *handshakeTransport) sendKexInitLocked() (*kexInitMsg, []byte, error) {
 
264
func (t *handshakeTransport) sendKexInitLocked(isFirst keyChangeCategory) (*kexInitMsg, []byte, error) {
233
265
        // kexInits may be sent either in response to the other side,
234
266
        // or because our side wants to initiate a key change, so we
235
267
        // may have already sent a kexInit. In that case, don't send a
237
269
        if t.sentInitMsg != nil {
238
270
                return t.sentInitMsg, t.sentInitPacket, nil
239
271
        }
 
272
 
240
273
        msg := &kexInitMsg{
241
274
                KexAlgos:                t.config.KeyExchanges,
242
275
                CiphersClientServer:     t.config.Ciphers,
276
309
        defer t.mu.Unlock()
277
310
 
278
311
        if t.writtenSinceKex > t.config.RekeyThreshold {
279
 
                t.sendKexInitLocked()
 
312
                t.sendKexInitLocked(subsequentKeyExchange)
280
313
        }
281
314
        for t.sentInitMsg != nil && t.writeError == nil {
282
315
                t.cond.Wait()
300
333
        return t.conn.Close()
301
334
}
302
335
 
303
 
// enterKeyExchange runs the key exchange.
304
 
func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
 
336
// enterKeyExchange runs the key exchange. t.mu must be held while running this.
 
337
func (t *handshakeTransport) enterKeyExchangeLocked(otherInitPacket []byte) error {
305
338
        if debugHandshake {
306
339
                log.Printf("%s entered key exchange", t.id())
307
340
        }
308
 
        myInit, myInitPacket, err := t.sendKexInit()
 
341
        myInit, myInitPacket, err := t.sendKexInitLocked(subsequentKeyExchange)
309
342
        if err != nil {
310
343
                return err
311
344
        }
338
371
        }
339
372
 
340
373
        // We don't send FirstKexFollows, but we handle receiving it.
341
 
        if otherInit.FirstKexFollows && algs.kex != otherInit.KexAlgos[0] {
 
374
        //
 
375
        // RFC 4253 section 7 defines the kex and the agreement method for
 
376
        // first_kex_packet_follows. It states that the guessed packet
 
377
        // should be ignored if the "kex algorithm and/or the host
 
378
        // key algorithm is guessed wrong (server and client have
 
379
        // different preferred algorithm), or if any of the other
 
380
        // algorithms cannot be agreed upon". The other algorithms have
 
381
        // already been checked above so the kex algorithm and host key
 
382
        // algorithm are checked here.
 
383
        if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) {
342
384
                // other side sent a kex message for the wrong algorithm,
343
385
                // which we have to ignore.
344
386
                if _, err := t.conn.readPacket(); err != nil {
362
404
                return err
363
405
        }
364
406
 
 
407
        if t.sessionID == nil {
 
408
                t.sessionID = result.H
 
409
        }
 
410
        result.SessionID = t.sessionID
 
411
 
365
412
        t.conn.prepareKeyChange(algs, result)
366
413
        if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
367
414
                return err
371
418
        } else if packet[0] != msgNewKeys {
372
419
                return unexpectedMessageError(msgNewKeys, packet[0])
373
420
        }
 
421
 
374
422
        return nil
375
423
}
376
424