aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/golang.org/x/crypto/ssh/transport.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/transport.go')
-rw-r--r--vendor/golang.org/x/crypto/ssh/transport.go375
1 files changed, 0 insertions, 375 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go
deleted file mode 100644
index f9780e0..0000000
--- a/vendor/golang.org/x/crypto/ssh/transport.go
+++ /dev/null
@@ -1,375 +0,0 @@
1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssh
6
7import (
8 "bufio"
9 "errors"
10 "io"
11 "log"
12)
13
14// debugTransport if set, will print packet types as they go over the
15// wire. No message decoding is done, to minimize the impact on timing.
16const debugTransport = false
17
18const (
19 gcmCipherID = "aes128-gcm@openssh.com"
20 aes128cbcID = "aes128-cbc"
21 tripledescbcID = "3des-cbc"
22)
23
24// packetConn represents a transport that implements packet based
25// operations.
26type packetConn interface {
27 // Encrypt and send a packet of data to the remote peer.
28 writePacket(packet []byte) error
29
30 // Read a packet from the connection. The read is blocking,
31 // i.e. if error is nil, then the returned byte slice is
32 // always non-empty.
33 readPacket() ([]byte, error)
34
35 // Close closes the write-side of the connection.
36 Close() error
37}
38
39// transport is the keyingTransport that implements the SSH packet
40// protocol.
41type transport struct {
42 reader connectionState
43 writer connectionState
44
45 bufReader *bufio.Reader
46 bufWriter *bufio.Writer
47 rand io.Reader
48 isClient bool
49 io.Closer
50}
51
52// packetCipher represents a combination of SSH encryption/MAC
53// protocol. A single instance should be used for one direction only.
54type packetCipher interface {
55 // writePacket encrypts the packet and writes it to w. The
56 // contents of the packet are generally scrambled.
57 writePacket(seqnum uint32, w io.Writer, rand io.Reader, packet []byte) error
58
59 // readPacket reads and decrypts a packet of data. The
60 // returned packet may be overwritten by future calls of
61 // readPacket.
62 readPacket(seqnum uint32, r io.Reader) ([]byte, error)
63}
64
65// connectionState represents one side (read or write) of the
66// connection. This is necessary because each direction has its own
67// keys, and can even have its own algorithms
68type connectionState struct {
69 packetCipher
70 seqNum uint32
71 dir direction
72 pendingKeyChange chan packetCipher
73}
74
75// prepareKeyChange sets up key material for a keychange. The key changes in
76// both directions are triggered by reading and writing a msgNewKey packet
77// respectively.
78func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) error {
79 if ciph, err := newPacketCipher(t.reader.dir, algs.r, kexResult); err != nil {
80 return err
81 } else {
82 t.reader.pendingKeyChange <- ciph
83 }
84
85 if ciph, err := newPacketCipher(t.writer.dir, algs.w, kexResult); err != nil {
86 return err
87 } else {
88 t.writer.pendingKeyChange <- ciph
89 }
90
91 return nil
92}
93
94func (t *transport) printPacket(p []byte, write bool) {
95 if len(p) == 0 {
96 return
97 }
98 who := "server"
99 if t.isClient {
100 who = "client"
101 }
102 what := "read"
103 if write {
104 what = "write"
105 }
106
107 log.Println(what, who, p[0])
108}
109
110// Read and decrypt next packet.
111func (t *transport) readPacket() (p []byte, err error) {
112 for {
113 p, err = t.reader.readPacket(t.bufReader)
114 if err != nil {
115 break
116 }
117 if len(p) == 0 || (p[0] != msgIgnore && p[0] != msgDebug) {
118 break
119 }
120 }
121 if debugTransport {
122 t.printPacket(p, false)
123 }
124
125 return p, err
126}
127
128func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
129 packet, err := s.packetCipher.readPacket(s.seqNum, r)
130 s.seqNum++
131 if err == nil && len(packet) == 0 {
132 err = errors.New("ssh: zero length packet")
133 }
134
135 if len(packet) > 0 {
136 switch packet[0] {
137 case msgNewKeys:
138 select {
139 case cipher := <-s.pendingKeyChange:
140 s.packetCipher = cipher
141 default:
142 return nil, errors.New("ssh: got bogus newkeys message.")
143 }
144
145 case msgDisconnect:
146 // Transform a disconnect message into an
147 // error. Since this is lowest level at which
148 // we interpret message types, doing it here
149 // ensures that we don't have to handle it
150 // elsewhere.
151 var msg disconnectMsg
152 if err := Unmarshal(packet, &msg); err != nil {
153 return nil, err
154 }
155 return nil, &msg
156 }
157 }
158
159 // The packet may point to an internal buffer, so copy the
160 // packet out here.
161 fresh := make([]byte, len(packet))
162 copy(fresh, packet)
163
164 return fresh, err
165}
166
167func (t *transport) writePacket(packet []byte) error {
168 if debugTransport {
169 t.printPacket(packet, true)
170 }
171 return t.writer.writePacket(t.bufWriter, t.rand, packet)
172}
173
174func (s *connectionState) writePacket(w *bufio.Writer, rand io.Reader, packet []byte) error {
175 changeKeys := len(packet) > 0 && packet[0] == msgNewKeys
176
177 err := s.packetCipher.writePacket(s.seqNum, w, rand, packet)
178 if err != nil {
179 return err
180 }
181 if err = w.Flush(); err != nil {
182 return err
183 }
184 s.seqNum++
185 if changeKeys {
186 select {
187 case cipher := <-s.pendingKeyChange:
188 s.packetCipher = cipher
189 default:
190 panic("ssh: no key material for msgNewKeys")
191 }
192 }
193 return err
194}
195
196func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transport {
197 t := &transport{
198 bufReader: bufio.NewReader(rwc),
199 bufWriter: bufio.NewWriter(rwc),
200 rand: rand,
201 reader: connectionState{
202 packetCipher: &streamPacketCipher{cipher: noneCipher{}},
203 pendingKeyChange: make(chan packetCipher, 1),
204 },
205 writer: connectionState{
206 packetCipher: &streamPacketCipher{cipher: noneCipher{}},
207 pendingKeyChange: make(chan packetCipher, 1),
208 },
209 Closer: rwc,
210 }
211 t.isClient = isClient
212
213 if isClient {
214 t.reader.dir = serverKeys
215 t.writer.dir = clientKeys
216 } else {
217 t.reader.dir = clientKeys
218 t.writer.dir = serverKeys
219 }
220
221 return t
222}
223
224type direction struct {
225 ivTag []byte
226 keyTag []byte
227 macKeyTag []byte
228}
229
230var (
231 serverKeys = direction{[]byte{'B'}, []byte{'D'}, []byte{'F'}}
232 clientKeys = direction{[]byte{'A'}, []byte{'C'}, []byte{'E'}}
233)
234
235// generateKeys generates key material for IV, MAC and encryption.
236func generateKeys(d direction, algs directionAlgorithms, kex *kexResult) (iv, key, macKey []byte) {
237 cipherMode := cipherModes[algs.Cipher]
238 macMode := macModes[algs.MAC]
239
240 iv = make([]byte, cipherMode.ivSize)
241 key = make([]byte, cipherMode.keySize)
242 macKey = make([]byte, macMode.keySize)
243
244 generateKeyMaterial(iv, d.ivTag, kex)
245 generateKeyMaterial(key, d.keyTag, kex)
246 generateKeyMaterial(macKey, d.macKeyTag, kex)
247 return
248}
249
250// setupKeys sets the cipher and MAC keys from kex.K, kex.H and sessionId, as
251// described in RFC 4253, section 6.4. direction should either be serverKeys
252// (to setup server->client keys) or clientKeys (for client->server keys).
253func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (packetCipher, error) {
254 iv, key, macKey := generateKeys(d, algs, kex)
255
256 if algs.Cipher == gcmCipherID {
257 return newGCMCipher(iv, key, macKey)
258 }
259
260 if algs.Cipher == aes128cbcID {
261 return newAESCBCCipher(iv, key, macKey, algs)
262 }
263
264 if algs.Cipher == tripledescbcID {
265 return newTripleDESCBCCipher(iv, key, macKey, algs)
266 }
267
268 c := &streamPacketCipher{
269 mac: macModes[algs.MAC].new(macKey),
270 etm: macModes[algs.MAC].etm,
271 }
272 c.macResult = make([]byte, c.mac.Size())
273
274 var err error
275 c.cipher, err = cipherModes[algs.Cipher].createStream(key, iv)
276 if err != nil {
277 return nil, err
278 }
279
280 return c, nil
281}
282
283// generateKeyMaterial fills out with key material generated from tag, K, H
284// and sessionId, as specified in RFC 4253, section 7.2.
285func generateKeyMaterial(out, tag []byte, r *kexResult) {
286 var digestsSoFar []byte
287
288 h := r.Hash.New()
289 for len(out) > 0 {
290 h.Reset()
291 h.Write(r.K)
292 h.Write(r.H)
293
294 if len(digestsSoFar) == 0 {
295 h.Write(tag)
296 h.Write(r.SessionID)
297 } else {
298 h.Write(digestsSoFar)
299 }
300
301 digest := h.Sum(nil)
302 n := copy(out, digest)
303 out = out[n:]
304 if len(out) > 0 {
305 digestsSoFar = append(digestsSoFar, digest...)
306 }
307 }
308}
309
310const packageVersion = "SSH-2.0-Go"
311
312// Sends and receives a version line. The versionLine string should
313// be US ASCII, start with "SSH-2.0-", and should not include a
314// newline. exchangeVersions returns the other side's version line.
315func exchangeVersions(rw io.ReadWriter, versionLine []byte) (them []byte, err error) {
316 // Contrary to the RFC, we do not ignore lines that don't
317 // start with "SSH-2.0-" to make the library usable with
318 // nonconforming servers.
319 for _, c := range versionLine {
320 // The spec disallows non US-ASCII chars, and
321 // specifically forbids null chars.
322 if c < 32 {
323 return nil, errors.New("ssh: junk character in version line")
324 }
325 }
326 if _, err = rw.Write(append(versionLine, '\r', '\n')); err != nil {
327 return
328 }
329
330 them, err = readVersion(rw)
331 return them, err
332}
333
334// maxVersionStringBytes is the maximum number of bytes that we'll
335// accept as a version string. RFC 4253 section 4.2 limits this at 255
336// chars
337const maxVersionStringBytes = 255
338
339// Read version string as specified by RFC 4253, section 4.2.
340func readVersion(r io.Reader) ([]byte, error) {
341 versionString := make([]byte, 0, 64)
342 var ok bool
343 var buf [1]byte
344
345 for len(versionString) < maxVersionStringBytes {
346 _, err := io.ReadFull(r, buf[:])
347 if err != nil {
348 return nil, err
349 }
350 // The RFC says that the version should be terminated with \r\n
351 // but several SSH servers actually only send a \n.
352 if buf[0] == '\n' {
353 ok = true
354 break
355 }
356
357 // non ASCII chars are disallowed, but we are lenient,
358 // since Go doesn't use null-terminated strings.
359
360 // The RFC allows a comment after a space, however,
361 // all of it (version and comments) goes into the
362 // session hash.
363 versionString = append(versionString, buf[0])
364 }
365
366 if !ok {
367 return nil, errors.New("ssh: overflow reading version string")
368 }
369
370 // There might be a '\r' on the end which we should remove.
371 if len(versionString) > 0 && versionString[len(versionString)-1] == '\r' {
372 versionString = versionString[:len(versionString)-1]
373 }
374 return versionString, nil
375}