diff options
author | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
---|---|---|
committer | Jake Champlin <jake.champlin.27@gmail.com> | 2017-06-06 12:40:07 -0400 |
commit | bae9f6d2fd5eb5bc80929bd393932b23f14d7c93 (patch) | |
tree | ca9ab12a7d78b1fc27a8f734729081357ce6d252 /vendor/golang.org/x/crypto/ssh | |
parent | 254c495b6bebab3fb72a243c4bce858d79e6ee99 (diff) | |
download | terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.gz terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.tar.zst terraform-provider-statuscake-bae9f6d2fd5eb5bc80929bd393932b23f14d7c93.zip |
Initial transfer of provider code
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh')
19 files changed, 8198 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/buffer.go b/vendor/golang.org/x/crypto/ssh/buffer.go new file mode 100644 index 0000000..6931b51 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/buffer.go | |||
@@ -0,0 +1,98 @@ | |||
1 | // Copyright 2012 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "io" | ||
9 | "sync" | ||
10 | ) | ||
11 | |||
12 | // buffer provides a linked list buffer for data exchange | ||
13 | // between producer and consumer. Theoretically the buffer is | ||
14 | // of unlimited capacity as it does no allocation of its own. | ||
15 | type buffer struct { | ||
16 | // protects concurrent access to head, tail and closed | ||
17 | *sync.Cond | ||
18 | |||
19 | head *element // the buffer that will be read first | ||
20 | tail *element // the buffer that will be read last | ||
21 | |||
22 | closed bool | ||
23 | } | ||
24 | |||
25 | // An element represents a single link in a linked list. | ||
26 | type element struct { | ||
27 | buf []byte | ||
28 | next *element | ||
29 | } | ||
30 | |||
31 | // newBuffer returns an empty buffer that is not closed. | ||
32 | func newBuffer() *buffer { | ||
33 | e := new(element) | ||
34 | b := &buffer{ | ||
35 | Cond: newCond(), | ||
36 | head: e, | ||
37 | tail: e, | ||
38 | } | ||
39 | return b | ||
40 | } | ||
41 | |||
42 | // write makes buf available for Read to receive. | ||
43 | // buf must not be modified after the call to write. | ||
44 | func (b *buffer) write(buf []byte) { | ||
45 | b.Cond.L.Lock() | ||
46 | e := &element{buf: buf} | ||
47 | b.tail.next = e | ||
48 | b.tail = e | ||
49 | b.Cond.Signal() | ||
50 | b.Cond.L.Unlock() | ||
51 | } | ||
52 | |||
53 | // eof closes the buffer. Reads from the buffer once all | ||
54 | // the data has been consumed will receive os.EOF. | ||
55 | func (b *buffer) eof() error { | ||
56 | b.Cond.L.Lock() | ||
57 | b.closed = true | ||
58 | b.Cond.Signal() | ||
59 | b.Cond.L.Unlock() | ||
60 | return nil | ||
61 | } | ||
62 | |||
63 | // Read reads data from the internal buffer in buf. Reads will block | ||
64 | // if no data is available, or until the buffer is closed. | ||
65 | func (b *buffer) Read(buf []byte) (n int, err error) { | ||
66 | b.Cond.L.Lock() | ||
67 | defer b.Cond.L.Unlock() | ||
68 | |||
69 | for len(buf) > 0 { | ||
70 | // if there is data in b.head, copy it | ||
71 | if len(b.head.buf) > 0 { | ||
72 | r := copy(buf, b.head.buf) | ||
73 | buf, b.head.buf = buf[r:], b.head.buf[r:] | ||
74 | n += r | ||
75 | continue | ||
76 | } | ||
77 | // if there is a next buffer, make it the head | ||
78 | if len(b.head.buf) == 0 && b.head != b.tail { | ||
79 | b.head = b.head.next | ||
80 | continue | ||
81 | } | ||
82 | |||
83 | // if at least one byte has been copied, return | ||
84 | if n > 0 { | ||
85 | break | ||
86 | } | ||
87 | |||
88 | // if nothing was read, and there is nothing outstanding | ||
89 | // check to see if the buffer is closed. | ||
90 | if b.closed { | ||
91 | err = io.EOF | ||
92 | break | ||
93 | } | ||
94 | // out of buffers, wait for producer | ||
95 | b.Cond.Wait() | ||
96 | } | ||
97 | return | ||
98 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go new file mode 100644 index 0000000..6331c94 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/certs.go | |||
@@ -0,0 +1,503 @@ | |||
1 | // Copyright 2012 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "errors" | ||
10 | "fmt" | ||
11 | "io" | ||
12 | "net" | ||
13 | "sort" | ||
14 | "time" | ||
15 | ) | ||
16 | |||
17 | // These constants from [PROTOCOL.certkeys] represent the algorithm names | ||
18 | // for certificate types supported by this package. | ||
19 | const ( | ||
20 | CertAlgoRSAv01 = "ssh-rsa-cert-v01@openssh.com" | ||
21 | CertAlgoDSAv01 = "ssh-dss-cert-v01@openssh.com" | ||
22 | CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com" | ||
23 | CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com" | ||
24 | CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com" | ||
25 | CertAlgoED25519v01 = "ssh-ed25519-cert-v01@openssh.com" | ||
26 | ) | ||
27 | |||
28 | // Certificate types distinguish between host and user | ||
29 | // certificates. The values can be set in the CertType field of | ||
30 | // Certificate. | ||
31 | const ( | ||
32 | UserCert = 1 | ||
33 | HostCert = 2 | ||
34 | ) | ||
35 | |||
36 | // Signature represents a cryptographic signature. | ||
37 | type Signature struct { | ||
38 | Format string | ||
39 | Blob []byte | ||
40 | } | ||
41 | |||
42 | // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that | ||
43 | // a certificate does not expire. | ||
44 | const CertTimeInfinity = 1<<64 - 1 | ||
45 | |||
46 | // An Certificate represents an OpenSSH certificate as defined in | ||
47 | // [PROTOCOL.certkeys]?rev=1.8. | ||
48 | type Certificate struct { | ||
49 | Nonce []byte | ||
50 | Key PublicKey | ||
51 | Serial uint64 | ||
52 | CertType uint32 | ||
53 | KeyId string | ||
54 | ValidPrincipals []string | ||
55 | ValidAfter uint64 | ||
56 | ValidBefore uint64 | ||
57 | Permissions | ||
58 | Reserved []byte | ||
59 | SignatureKey PublicKey | ||
60 | Signature *Signature | ||
61 | } | ||
62 | |||
63 | // genericCertData holds the key-independent part of the certificate data. | ||
64 | // Overall, certificates contain an nonce, public key fields and | ||
65 | // key-independent fields. | ||
66 | type genericCertData struct { | ||
67 | Serial uint64 | ||
68 | CertType uint32 | ||
69 | KeyId string | ||
70 | ValidPrincipals []byte | ||
71 | ValidAfter uint64 | ||
72 | ValidBefore uint64 | ||
73 | CriticalOptions []byte | ||
74 | Extensions []byte | ||
75 | Reserved []byte | ||
76 | SignatureKey []byte | ||
77 | Signature []byte | ||
78 | } | ||
79 | |||
80 | func marshalStringList(namelist []string) []byte { | ||
81 | var to []byte | ||
82 | for _, name := range namelist { | ||
83 | s := struct{ N string }{name} | ||
84 | to = append(to, Marshal(&s)...) | ||
85 | } | ||
86 | return to | ||
87 | } | ||
88 | |||
89 | type optionsTuple struct { | ||
90 | Key string | ||
91 | Value []byte | ||
92 | } | ||
93 | |||
94 | type optionsTupleValue struct { | ||
95 | Value string | ||
96 | } | ||
97 | |||
98 | // serialize a map of critical options or extensions | ||
99 | // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, | ||
100 | // we need two length prefixes for a non-empty string value | ||
101 | func marshalTuples(tups map[string]string) []byte { | ||
102 | keys := make([]string, 0, len(tups)) | ||
103 | for key := range tups { | ||
104 | keys = append(keys, key) | ||
105 | } | ||
106 | sort.Strings(keys) | ||
107 | |||
108 | var ret []byte | ||
109 | for _, key := range keys { | ||
110 | s := optionsTuple{Key: key} | ||
111 | if value := tups[key]; len(value) > 0 { | ||
112 | s.Value = Marshal(&optionsTupleValue{value}) | ||
113 | } | ||
114 | ret = append(ret, Marshal(&s)...) | ||
115 | } | ||
116 | return ret | ||
117 | } | ||
118 | |||
119 | // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, | ||
120 | // we need two length prefixes for a non-empty option value | ||
121 | func parseTuples(in []byte) (map[string]string, error) { | ||
122 | tups := map[string]string{} | ||
123 | var lastKey string | ||
124 | var haveLastKey bool | ||
125 | |||
126 | for len(in) > 0 { | ||
127 | var key, val, extra []byte | ||
128 | var ok bool | ||
129 | |||
130 | if key, in, ok = parseString(in); !ok { | ||
131 | return nil, errShortRead | ||
132 | } | ||
133 | keyStr := string(key) | ||
134 | // according to [PROTOCOL.certkeys], the names must be in | ||
135 | // lexical order. | ||
136 | if haveLastKey && keyStr <= lastKey { | ||
137 | return nil, fmt.Errorf("ssh: certificate options are not in lexical order") | ||
138 | } | ||
139 | lastKey, haveLastKey = keyStr, true | ||
140 | // the next field is a data field, which if non-empty has a string embedded | ||
141 | if val, in, ok = parseString(in); !ok { | ||
142 | return nil, errShortRead | ||
143 | } | ||
144 | if len(val) > 0 { | ||
145 | val, extra, ok = parseString(val) | ||
146 | if !ok { | ||
147 | return nil, errShortRead | ||
148 | } | ||
149 | if len(extra) > 0 { | ||
150 | return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") | ||
151 | } | ||
152 | tups[keyStr] = string(val) | ||
153 | } else { | ||
154 | tups[keyStr] = "" | ||
155 | } | ||
156 | } | ||
157 | return tups, nil | ||
158 | } | ||
159 | |||
160 | func parseCert(in []byte, privAlgo string) (*Certificate, error) { | ||
161 | nonce, rest, ok := parseString(in) | ||
162 | if !ok { | ||
163 | return nil, errShortRead | ||
164 | } | ||
165 | |||
166 | key, rest, err := parsePubKey(rest, privAlgo) | ||
167 | if err != nil { | ||
168 | return nil, err | ||
169 | } | ||
170 | |||
171 | var g genericCertData | ||
172 | if err := Unmarshal(rest, &g); err != nil { | ||
173 | return nil, err | ||
174 | } | ||
175 | |||
176 | c := &Certificate{ | ||
177 | Nonce: nonce, | ||
178 | Key: key, | ||
179 | Serial: g.Serial, | ||
180 | CertType: g.CertType, | ||
181 | KeyId: g.KeyId, | ||
182 | ValidAfter: g.ValidAfter, | ||
183 | ValidBefore: g.ValidBefore, | ||
184 | } | ||
185 | |||
186 | for principals := g.ValidPrincipals; len(principals) > 0; { | ||
187 | principal, rest, ok := parseString(principals) | ||
188 | if !ok { | ||
189 | return nil, errShortRead | ||
190 | } | ||
191 | c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) | ||
192 | principals = rest | ||
193 | } | ||
194 | |||
195 | c.CriticalOptions, err = parseTuples(g.CriticalOptions) | ||
196 | if err != nil { | ||
197 | return nil, err | ||
198 | } | ||
199 | c.Extensions, err = parseTuples(g.Extensions) | ||
200 | if err != nil { | ||
201 | return nil, err | ||
202 | } | ||
203 | c.Reserved = g.Reserved | ||
204 | k, err := ParsePublicKey(g.SignatureKey) | ||
205 | if err != nil { | ||
206 | return nil, err | ||
207 | } | ||
208 | |||
209 | c.SignatureKey = k | ||
210 | c.Signature, rest, ok = parseSignatureBody(g.Signature) | ||
211 | if !ok || len(rest) > 0 { | ||
212 | return nil, errors.New("ssh: signature parse error") | ||
213 | } | ||
214 | |||
215 | return c, nil | ||
216 | } | ||
217 | |||
218 | type openSSHCertSigner struct { | ||
219 | pub *Certificate | ||
220 | signer Signer | ||
221 | } | ||
222 | |||
223 | // NewCertSigner returns a Signer that signs with the given Certificate, whose | ||
224 | // private key is held by signer. It returns an error if the public key in cert | ||
225 | // doesn't match the key used by signer. | ||
226 | func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { | ||
227 | if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { | ||
228 | return nil, errors.New("ssh: signer and cert have different public key") | ||
229 | } | ||
230 | |||
231 | return &openSSHCertSigner{cert, signer}, nil | ||
232 | } | ||
233 | |||
234 | func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||
235 | return s.signer.Sign(rand, data) | ||
236 | } | ||
237 | |||
238 | func (s *openSSHCertSigner) PublicKey() PublicKey { | ||
239 | return s.pub | ||
240 | } | ||
241 | |||
242 | const sourceAddressCriticalOption = "source-address" | ||
243 | |||
244 | // CertChecker does the work of verifying a certificate. Its methods | ||
245 | // can be plugged into ClientConfig.HostKeyCallback and | ||
246 | // ServerConfig.PublicKeyCallback. For the CertChecker to work, | ||
247 | // minimally, the IsAuthority callback should be set. | ||
248 | type CertChecker struct { | ||
249 | // SupportedCriticalOptions lists the CriticalOptions that the | ||
250 | // server application layer understands. These are only used | ||
251 | // for user certificates. | ||
252 | SupportedCriticalOptions []string | ||
253 | |||
254 | // IsAuthority should return true if the key is recognized as | ||
255 | // an authority. This allows for certificates to be signed by other | ||
256 | // certificates. | ||
257 | IsAuthority func(auth PublicKey) bool | ||
258 | |||
259 | // Clock is used for verifying time stamps. If nil, time.Now | ||
260 | // is used. | ||
261 | Clock func() time.Time | ||
262 | |||
263 | // UserKeyFallback is called when CertChecker.Authenticate encounters a | ||
264 | // public key that is not a certificate. It must implement validation | ||
265 | // of user keys or else, if nil, all such keys are rejected. | ||
266 | UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) | ||
267 | |||
268 | // HostKeyFallback is called when CertChecker.CheckHostKey encounters a | ||
269 | // public key that is not a certificate. It must implement host key | ||
270 | // validation or else, if nil, all such keys are rejected. | ||
271 | HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error | ||
272 | |||
273 | // IsRevoked is called for each certificate so that revocation checking | ||
274 | // can be implemented. It should return true if the given certificate | ||
275 | // is revoked and false otherwise. If nil, no certificates are | ||
276 | // considered to have been revoked. | ||
277 | IsRevoked func(cert *Certificate) bool | ||
278 | } | ||
279 | |||
280 | // CheckHostKey checks a host key certificate. This method can be | ||
281 | // plugged into ClientConfig.HostKeyCallback. | ||
282 | func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { | ||
283 | cert, ok := key.(*Certificate) | ||
284 | if !ok { | ||
285 | if c.HostKeyFallback != nil { | ||
286 | return c.HostKeyFallback(addr, remote, key) | ||
287 | } | ||
288 | return errors.New("ssh: non-certificate host key") | ||
289 | } | ||
290 | if cert.CertType != HostCert { | ||
291 | return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) | ||
292 | } | ||
293 | |||
294 | return c.CheckCert(addr, cert) | ||
295 | } | ||
296 | |||
297 | // Authenticate checks a user certificate. Authenticate can be used as | ||
298 | // a value for ServerConfig.PublicKeyCallback. | ||
299 | func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { | ||
300 | cert, ok := pubKey.(*Certificate) | ||
301 | if !ok { | ||
302 | if c.UserKeyFallback != nil { | ||
303 | return c.UserKeyFallback(conn, pubKey) | ||
304 | } | ||
305 | return nil, errors.New("ssh: normal key pairs not accepted") | ||
306 | } | ||
307 | |||
308 | if cert.CertType != UserCert { | ||
309 | return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) | ||
310 | } | ||
311 | |||
312 | if err := c.CheckCert(conn.User(), cert); err != nil { | ||
313 | return nil, err | ||
314 | } | ||
315 | |||
316 | return &cert.Permissions, nil | ||
317 | } | ||
318 | |||
319 | // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and | ||
320 | // the signature of the certificate. | ||
321 | func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { | ||
322 | if c.IsRevoked != nil && c.IsRevoked(cert) { | ||
323 | return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial) | ||
324 | } | ||
325 | |||
326 | for opt, _ := range cert.CriticalOptions { | ||
327 | // sourceAddressCriticalOption will be enforced by | ||
328 | // serverAuthenticate | ||
329 | if opt == sourceAddressCriticalOption { | ||
330 | continue | ||
331 | } | ||
332 | |||
333 | found := false | ||
334 | for _, supp := range c.SupportedCriticalOptions { | ||
335 | if supp == opt { | ||
336 | found = true | ||
337 | break | ||
338 | } | ||
339 | } | ||
340 | if !found { | ||
341 | return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) | ||
342 | } | ||
343 | } | ||
344 | |||
345 | if len(cert.ValidPrincipals) > 0 { | ||
346 | // By default, certs are valid for all users/hosts. | ||
347 | found := false | ||
348 | for _, p := range cert.ValidPrincipals { | ||
349 | if p == principal { | ||
350 | found = true | ||
351 | break | ||
352 | } | ||
353 | } | ||
354 | if !found { | ||
355 | return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) | ||
356 | } | ||
357 | } | ||
358 | |||
359 | if !c.IsAuthority(cert.SignatureKey) { | ||
360 | return fmt.Errorf("ssh: certificate signed by unrecognized authority") | ||
361 | } | ||
362 | |||
363 | clock := c.Clock | ||
364 | if clock == nil { | ||
365 | clock = time.Now | ||
366 | } | ||
367 | |||
368 | unixNow := clock().Unix() | ||
369 | if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { | ||
370 | return fmt.Errorf("ssh: cert is not yet valid") | ||
371 | } | ||
372 | if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { | ||
373 | return fmt.Errorf("ssh: cert has expired") | ||
374 | } | ||
375 | if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { | ||
376 | return fmt.Errorf("ssh: certificate signature does not verify") | ||
377 | } | ||
378 | |||
379 | return nil | ||
380 | } | ||
381 | |||
382 | // SignCert sets c.SignatureKey to the authority's public key and stores a | ||
383 | // Signature, by authority, in the certificate. | ||
384 | func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { | ||
385 | c.Nonce = make([]byte, 32) | ||
386 | if _, err := io.ReadFull(rand, c.Nonce); err != nil { | ||
387 | return err | ||
388 | } | ||
389 | c.SignatureKey = authority.PublicKey() | ||
390 | |||
391 | sig, err := authority.Sign(rand, c.bytesForSigning()) | ||
392 | if err != nil { | ||
393 | return err | ||
394 | } | ||
395 | c.Signature = sig | ||
396 | return nil | ||
397 | } | ||
398 | |||
399 | var certAlgoNames = map[string]string{ | ||
400 | KeyAlgoRSA: CertAlgoRSAv01, | ||
401 | KeyAlgoDSA: CertAlgoDSAv01, | ||
402 | KeyAlgoECDSA256: CertAlgoECDSA256v01, | ||
403 | KeyAlgoECDSA384: CertAlgoECDSA384v01, | ||
404 | KeyAlgoECDSA521: CertAlgoECDSA521v01, | ||
405 | KeyAlgoED25519: CertAlgoED25519v01, | ||
406 | } | ||
407 | |||
408 | // certToPrivAlgo returns the underlying algorithm for a certificate algorithm. | ||
409 | // Panics if a non-certificate algorithm is passed. | ||
410 | func certToPrivAlgo(algo string) string { | ||
411 | for privAlgo, pubAlgo := range certAlgoNames { | ||
412 | if pubAlgo == algo { | ||
413 | return privAlgo | ||
414 | } | ||
415 | } | ||
416 | panic("unknown cert algorithm") | ||
417 | } | ||
418 | |||
419 | func (cert *Certificate) bytesForSigning() []byte { | ||
420 | c2 := *cert | ||
421 | c2.Signature = nil | ||
422 | out := c2.Marshal() | ||
423 | // Drop trailing signature length. | ||
424 | return out[:len(out)-4] | ||
425 | } | ||
426 | |||
427 | // Marshal serializes c into OpenSSH's wire format. It is part of the | ||
428 | // PublicKey interface. | ||
429 | func (c *Certificate) Marshal() []byte { | ||
430 | generic := genericCertData{ | ||
431 | Serial: c.Serial, | ||
432 | CertType: c.CertType, | ||
433 | KeyId: c.KeyId, | ||
434 | ValidPrincipals: marshalStringList(c.ValidPrincipals), | ||
435 | ValidAfter: uint64(c.ValidAfter), | ||
436 | ValidBefore: uint64(c.ValidBefore), | ||
437 | CriticalOptions: marshalTuples(c.CriticalOptions), | ||
438 | Extensions: marshalTuples(c.Extensions), | ||
439 | Reserved: c.Reserved, | ||
440 | SignatureKey: c.SignatureKey.Marshal(), | ||
441 | } | ||
442 | if c.Signature != nil { | ||
443 | generic.Signature = Marshal(c.Signature) | ||
444 | } | ||
445 | genericBytes := Marshal(&generic) | ||
446 | keyBytes := c.Key.Marshal() | ||
447 | _, keyBytes, _ = parseString(keyBytes) | ||
448 | prefix := Marshal(&struct { | ||
449 | Name string | ||
450 | Nonce []byte | ||
451 | Key []byte `ssh:"rest"` | ||
452 | }{c.Type(), c.Nonce, keyBytes}) | ||
453 | |||
454 | result := make([]byte, 0, len(prefix)+len(genericBytes)) | ||
455 | result = append(result, prefix...) | ||
456 | result = append(result, genericBytes...) | ||
457 | return result | ||
458 | } | ||
459 | |||
460 | // Type returns the key name. It is part of the PublicKey interface. | ||
461 | func (c *Certificate) Type() string { | ||
462 | algo, ok := certAlgoNames[c.Key.Type()] | ||
463 | if !ok { | ||
464 | panic("unknown cert key type " + c.Key.Type()) | ||
465 | } | ||
466 | return algo | ||
467 | } | ||
468 | |||
469 | // Verify verifies a signature against the certificate's public | ||
470 | // key. It is part of the PublicKey interface. | ||
471 | func (c *Certificate) Verify(data []byte, sig *Signature) error { | ||
472 | return c.Key.Verify(data, sig) | ||
473 | } | ||
474 | |||
475 | func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { | ||
476 | format, in, ok := parseString(in) | ||
477 | if !ok { | ||
478 | return | ||
479 | } | ||
480 | |||
481 | out = &Signature{ | ||
482 | Format: string(format), | ||
483 | } | ||
484 | |||
485 | if out.Blob, in, ok = parseString(in); !ok { | ||
486 | return | ||
487 | } | ||
488 | |||
489 | return out, in, ok | ||
490 | } | ||
491 | |||
492 | func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { | ||
493 | sigBytes, rest, ok := parseString(in) | ||
494 | if !ok { | ||
495 | return | ||
496 | } | ||
497 | |||
498 | out, trailing, ok := parseSignatureBody(sigBytes) | ||
499 | if !ok || len(trailing) > 0 { | ||
500 | return nil, nil, false | ||
501 | } | ||
502 | return | ||
503 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/channel.go b/vendor/golang.org/x/crypto/ssh/channel.go new file mode 100644 index 0000000..195530e --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/channel.go | |||
@@ -0,0 +1,633 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "encoding/binary" | ||
9 | "errors" | ||
10 | "fmt" | ||
11 | "io" | ||
12 | "log" | ||
13 | "sync" | ||
14 | ) | ||
15 | |||
16 | const ( | ||
17 | minPacketLength = 9 | ||
18 | // channelMaxPacket contains the maximum number of bytes that will be | ||
19 | // sent in a single packet. As per RFC 4253, section 6.1, 32k is also | ||
20 | // the minimum. | ||
21 | channelMaxPacket = 1 << 15 | ||
22 | // We follow OpenSSH here. | ||
23 | channelWindowSize = 64 * channelMaxPacket | ||
24 | ) | ||
25 | |||
26 | // NewChannel represents an incoming request to a channel. It must either be | ||
27 | // accepted for use by calling Accept, or rejected by calling Reject. | ||
28 | type NewChannel interface { | ||
29 | // Accept accepts the channel creation request. It returns the Channel | ||
30 | // and a Go channel containing SSH requests. The Go channel must be | ||
31 | // serviced otherwise the Channel will hang. | ||
32 | Accept() (Channel, <-chan *Request, error) | ||
33 | |||
34 | // Reject rejects the channel creation request. After calling | ||
35 | // this, no other methods on the Channel may be called. | ||
36 | Reject(reason RejectionReason, message string) error | ||
37 | |||
38 | // ChannelType returns the type of the channel, as supplied by the | ||
39 | // client. | ||
40 | ChannelType() string | ||
41 | |||
42 | // ExtraData returns the arbitrary payload for this channel, as supplied | ||
43 | // by the client. This data is specific to the channel type. | ||
44 | ExtraData() []byte | ||
45 | } | ||
46 | |||
47 | // A Channel is an ordered, reliable, flow-controlled, duplex stream | ||
48 | // that is multiplexed over an SSH connection. | ||
49 | type Channel interface { | ||
50 | // Read reads up to len(data) bytes from the channel. | ||
51 | Read(data []byte) (int, error) | ||
52 | |||
53 | // Write writes len(data) bytes to the channel. | ||
54 | Write(data []byte) (int, error) | ||
55 | |||
56 | // Close signals end of channel use. No data may be sent after this | ||
57 | // call. | ||
58 | Close() error | ||
59 | |||
60 | // CloseWrite signals the end of sending in-band | ||
61 | // data. Requests may still be sent, and the other side may | ||
62 | // still send data | ||
63 | CloseWrite() error | ||
64 | |||
65 | // SendRequest sends a channel request. If wantReply is true, | ||
66 | // it will wait for a reply and return the result as a | ||
67 | // boolean, otherwise the return value will be false. Channel | ||
68 | // requests are out-of-band messages so they may be sent even | ||
69 | // if the data stream is closed or blocked by flow control. | ||
70 | // If the channel is closed before a reply is returned, io.EOF | ||
71 | // is returned. | ||
72 | SendRequest(name string, wantReply bool, payload []byte) (bool, error) | ||
73 | |||
74 | // Stderr returns an io.ReadWriter that writes to this channel | ||
75 | // with the extended data type set to stderr. Stderr may | ||
76 | // safely be read and written from a different goroutine than | ||
77 | // Read and Write respectively. | ||
78 | Stderr() io.ReadWriter | ||
79 | } | ||
80 | |||
81 | // Request is a request sent outside of the normal stream of | ||
82 | // data. Requests can either be specific to an SSH channel, or they | ||
83 | // can be global. | ||
84 | type Request struct { | ||
85 | Type string | ||
86 | WantReply bool | ||
87 | Payload []byte | ||
88 | |||
89 | ch *channel | ||
90 | mux *mux | ||
91 | } | ||
92 | |||
93 | // Reply sends a response to a request. It must be called for all requests | ||
94 | // where WantReply is true and is a no-op otherwise. The payload argument is | ||
95 | // ignored for replies to channel-specific requests. | ||
96 | func (r *Request) Reply(ok bool, payload []byte) error { | ||
97 | if !r.WantReply { | ||
98 | return nil | ||
99 | } | ||
100 | |||
101 | if r.ch == nil { | ||
102 | return r.mux.ackRequest(ok, payload) | ||
103 | } | ||
104 | |||
105 | return r.ch.ackRequest(ok) | ||
106 | } | ||
107 | |||
108 | // RejectionReason is an enumeration used when rejecting channel creation | ||
109 | // requests. See RFC 4254, section 5.1. | ||
110 | type RejectionReason uint32 | ||
111 | |||
112 | const ( | ||
113 | Prohibited RejectionReason = iota + 1 | ||
114 | ConnectionFailed | ||
115 | UnknownChannelType | ||
116 | ResourceShortage | ||
117 | ) | ||
118 | |||
119 | // String converts the rejection reason to human readable form. | ||
120 | func (r RejectionReason) String() string { | ||
121 | switch r { | ||
122 | case Prohibited: | ||
123 | return "administratively prohibited" | ||
124 | case ConnectionFailed: | ||
125 | return "connect failed" | ||
126 | case UnknownChannelType: | ||
127 | return "unknown channel type" | ||
128 | case ResourceShortage: | ||
129 | return "resource shortage" | ||
130 | } | ||
131 | return fmt.Sprintf("unknown reason %d", int(r)) | ||
132 | } | ||
133 | |||
134 | func min(a uint32, b int) uint32 { | ||
135 | if a < uint32(b) { | ||
136 | return a | ||
137 | } | ||
138 | return uint32(b) | ||
139 | } | ||
140 | |||
141 | type channelDirection uint8 | ||
142 | |||
143 | const ( | ||
144 | channelInbound channelDirection = iota | ||
145 | channelOutbound | ||
146 | ) | ||
147 | |||
148 | // channel is an implementation of the Channel interface that works | ||
149 | // with the mux class. | ||
150 | type channel struct { | ||
151 | // R/O after creation | ||
152 | chanType string | ||
153 | extraData []byte | ||
154 | localId, remoteId uint32 | ||
155 | |||
156 | // maxIncomingPayload and maxRemotePayload are the maximum | ||
157 | // payload sizes of normal and extended data packets for | ||
158 | // receiving and sending, respectively. The wire packet will | ||
159 | // be 9 or 13 bytes larger (excluding encryption overhead). | ||
160 | maxIncomingPayload uint32 | ||
161 | maxRemotePayload uint32 | ||
162 | |||
163 | mux *mux | ||
164 | |||
165 | // decided is set to true if an accept or reject message has been sent | ||
166 | // (for outbound channels) or received (for inbound channels). | ||
167 | decided bool | ||
168 | |||
169 | // direction contains either channelOutbound, for channels created | ||
170 | // locally, or channelInbound, for channels created by the peer. | ||
171 | direction channelDirection | ||
172 | |||
173 | // Pending internal channel messages. | ||
174 | msg chan interface{} | ||
175 | |||
176 | // Since requests have no ID, there can be only one request | ||
177 | // with WantReply=true outstanding. This lock is held by a | ||
178 | // goroutine that has such an outgoing request pending. | ||
179 | sentRequestMu sync.Mutex | ||
180 | |||
181 | incomingRequests chan *Request | ||
182 | |||
183 | sentEOF bool | ||
184 | |||
185 | // thread-safe data | ||
186 | remoteWin window | ||
187 | pending *buffer | ||
188 | extPending *buffer | ||
189 | |||
190 | // windowMu protects myWindow, the flow-control window. | ||
191 | windowMu sync.Mutex | ||
192 | myWindow uint32 | ||
193 | |||
194 | // writeMu serializes calls to mux.conn.writePacket() and | ||
195 | // protects sentClose and packetPool. This mutex must be | ||
196 | // different from windowMu, as writePacket can block if there | ||
197 | // is a key exchange pending. | ||
198 | writeMu sync.Mutex | ||
199 | sentClose bool | ||
200 | |||
201 | // packetPool has a buffer for each extended channel ID to | ||
202 | // save allocations during writes. | ||
203 | packetPool map[uint32][]byte | ||
204 | } | ||
205 | |||
206 | // writePacket sends a packet. If the packet is a channel close, it updates | ||
207 | // sentClose. This method takes the lock c.writeMu. | ||
208 | func (c *channel) writePacket(packet []byte) error { | ||
209 | c.writeMu.Lock() | ||
210 | if c.sentClose { | ||
211 | c.writeMu.Unlock() | ||
212 | return io.EOF | ||
213 | } | ||
214 | c.sentClose = (packet[0] == msgChannelClose) | ||
215 | err := c.mux.conn.writePacket(packet) | ||
216 | c.writeMu.Unlock() | ||
217 | return err | ||
218 | } | ||
219 | |||
220 | func (c *channel) sendMessage(msg interface{}) error { | ||
221 | if debugMux { | ||
222 | log.Printf("send(%d): %#v", c.mux.chanList.offset, msg) | ||
223 | } | ||
224 | |||
225 | p := Marshal(msg) | ||
226 | binary.BigEndian.PutUint32(p[1:], c.remoteId) | ||
227 | return c.writePacket(p) | ||
228 | } | ||
229 | |||
230 | // WriteExtended writes data to a specific extended stream. These streams are | ||
231 | // used, for example, for stderr. | ||
232 | func (c *channel) WriteExtended(data []byte, extendedCode uint32) (n int, err error) { | ||
233 | if c.sentEOF { | ||
234 | return 0, io.EOF | ||
235 | } | ||
236 | // 1 byte message type, 4 bytes remoteId, 4 bytes data length | ||
237 | opCode := byte(msgChannelData) | ||
238 | headerLength := uint32(9) | ||
239 | if extendedCode > 0 { | ||
240 | headerLength += 4 | ||
241 | opCode = msgChannelExtendedData | ||
242 | } | ||
243 | |||
244 | c.writeMu.Lock() | ||
245 | packet := c.packetPool[extendedCode] | ||
246 | // We don't remove the buffer from packetPool, so | ||
247 | // WriteExtended calls from different goroutines will be | ||
248 | // flagged as errors by the race detector. | ||
249 | c.writeMu.Unlock() | ||
250 | |||
251 | for len(data) > 0 { | ||
252 | space := min(c.maxRemotePayload, len(data)) | ||
253 | if space, err = c.remoteWin.reserve(space); err != nil { | ||
254 | return n, err | ||
255 | } | ||
256 | if want := headerLength + space; uint32(cap(packet)) < want { | ||
257 | packet = make([]byte, want) | ||
258 | } else { | ||
259 | packet = packet[:want] | ||
260 | } | ||
261 | |||
262 | todo := data[:space] | ||
263 | |||
264 | packet[0] = opCode | ||
265 | binary.BigEndian.PutUint32(packet[1:], c.remoteId) | ||
266 | if extendedCode > 0 { | ||
267 | binary.BigEndian.PutUint32(packet[5:], uint32(extendedCode)) | ||
268 | } | ||
269 | binary.BigEndian.PutUint32(packet[headerLength-4:], uint32(len(todo))) | ||
270 | copy(packet[headerLength:], todo) | ||
271 | if err = c.writePacket(packet); err != nil { | ||
272 | return n, err | ||
273 | } | ||
274 | |||
275 | n += len(todo) | ||
276 | data = data[len(todo):] | ||
277 | } | ||
278 | |||
279 | c.writeMu.Lock() | ||
280 | c.packetPool[extendedCode] = packet | ||
281 | c.writeMu.Unlock() | ||
282 | |||
283 | return n, err | ||
284 | } | ||
285 | |||
286 | func (c *channel) handleData(packet []byte) error { | ||
287 | headerLen := 9 | ||
288 | isExtendedData := packet[0] == msgChannelExtendedData | ||
289 | if isExtendedData { | ||
290 | headerLen = 13 | ||
291 | } | ||
292 | if len(packet) < headerLen { | ||
293 | // malformed data packet | ||
294 | return parseError(packet[0]) | ||
295 | } | ||
296 | |||
297 | var extended uint32 | ||
298 | if isExtendedData { | ||
299 | extended = binary.BigEndian.Uint32(packet[5:]) | ||
300 | } | ||
301 | |||
302 | length := binary.BigEndian.Uint32(packet[headerLen-4 : headerLen]) | ||
303 | if length == 0 { | ||
304 | return nil | ||
305 | } | ||
306 | if length > c.maxIncomingPayload { | ||
307 | // TODO(hanwen): should send Disconnect? | ||
308 | return errors.New("ssh: incoming packet exceeds maximum payload size") | ||
309 | } | ||
310 | |||
311 | data := packet[headerLen:] | ||
312 | if length != uint32(len(data)) { | ||
313 | return errors.New("ssh: wrong packet length") | ||
314 | } | ||
315 | |||
316 | c.windowMu.Lock() | ||
317 | if c.myWindow < length { | ||
318 | c.windowMu.Unlock() | ||
319 | // TODO(hanwen): should send Disconnect with reason? | ||
320 | return errors.New("ssh: remote side wrote too much") | ||
321 | } | ||
322 | c.myWindow -= length | ||
323 | c.windowMu.Unlock() | ||
324 | |||
325 | if extended == 1 { | ||
326 | c.extPending.write(data) | ||
327 | } else if extended > 0 { | ||
328 | // discard other extended data. | ||
329 | } else { | ||
330 | c.pending.write(data) | ||
331 | } | ||
332 | return nil | ||
333 | } | ||
334 | |||
335 | func (c *channel) adjustWindow(n uint32) error { | ||
336 | c.windowMu.Lock() | ||
337 | // Since myWindow is managed on our side, and can never exceed | ||
338 | // the initial window setting, we don't worry about overflow. | ||
339 | c.myWindow += uint32(n) | ||
340 | c.windowMu.Unlock() | ||
341 | return c.sendMessage(windowAdjustMsg{ | ||
342 | AdditionalBytes: uint32(n), | ||
343 | }) | ||
344 | } | ||
345 | |||
346 | func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { | ||
347 | switch extended { | ||
348 | case 1: | ||
349 | n, err = c.extPending.Read(data) | ||
350 | case 0: | ||
351 | n, err = c.pending.Read(data) | ||
352 | default: | ||
353 | return 0, fmt.Errorf("ssh: extended code %d unimplemented", extended) | ||
354 | } | ||
355 | |||
356 | if n > 0 { | ||
357 | err = c.adjustWindow(uint32(n)) | ||
358 | // sendWindowAdjust can return io.EOF if the remote | ||
359 | // peer has closed the connection, however we want to | ||
360 | // defer forwarding io.EOF to the caller of Read until | ||
361 | // the buffer has been drained. | ||
362 | if n > 0 && err == io.EOF { | ||
363 | err = nil | ||
364 | } | ||
365 | } | ||
366 | |||
367 | return n, err | ||
368 | } | ||
369 | |||
370 | func (c *channel) close() { | ||
371 | c.pending.eof() | ||
372 | c.extPending.eof() | ||
373 | close(c.msg) | ||
374 | close(c.incomingRequests) | ||
375 | c.writeMu.Lock() | ||
376 | // This is not necessary for a normal channel teardown, but if | ||
377 | // there was another error, it is. | ||
378 | c.sentClose = true | ||
379 | c.writeMu.Unlock() | ||
380 | // Unblock writers. | ||
381 | c.remoteWin.close() | ||
382 | } | ||
383 | |||
384 | // responseMessageReceived is called when a success or failure message is | ||
385 | // received on a channel to check that such a message is reasonable for the | ||
386 | // given channel. | ||
387 | func (c *channel) responseMessageReceived() error { | ||
388 | if c.direction == channelInbound { | ||
389 | return errors.New("ssh: channel response message received on inbound channel") | ||
390 | } | ||
391 | if c.decided { | ||
392 | return errors.New("ssh: duplicate response received for channel") | ||
393 | } | ||
394 | c.decided = true | ||
395 | return nil | ||
396 | } | ||
397 | |||
398 | func (c *channel) handlePacket(packet []byte) error { | ||
399 | switch packet[0] { | ||
400 | case msgChannelData, msgChannelExtendedData: | ||
401 | return c.handleData(packet) | ||
402 | case msgChannelClose: | ||
403 | c.sendMessage(channelCloseMsg{PeersId: c.remoteId}) | ||
404 | c.mux.chanList.remove(c.localId) | ||
405 | c.close() | ||
406 | return nil | ||
407 | case msgChannelEOF: | ||
408 | // RFC 4254 is mute on how EOF affects dataExt messages but | ||
409 | // it is logical to signal EOF at the same time. | ||
410 | c.extPending.eof() | ||
411 | c.pending.eof() | ||
412 | return nil | ||
413 | } | ||
414 | |||
415 | decoded, err := decode(packet) | ||
416 | if err != nil { | ||
417 | return err | ||
418 | } | ||
419 | |||
420 | switch msg := decoded.(type) { | ||
421 | case *channelOpenFailureMsg: | ||
422 | if err := c.responseMessageReceived(); err != nil { | ||
423 | return err | ||
424 | } | ||
425 | c.mux.chanList.remove(msg.PeersId) | ||
426 | c.msg <- msg | ||
427 | case *channelOpenConfirmMsg: | ||
428 | if err := c.responseMessageReceived(); err != nil { | ||
429 | return err | ||
430 | } | ||
431 | if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { | ||
432 | return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", msg.MaxPacketSize) | ||
433 | } | ||
434 | c.remoteId = msg.MyId | ||
435 | c.maxRemotePayload = msg.MaxPacketSize | ||
436 | c.remoteWin.add(msg.MyWindow) | ||
437 | c.msg <- msg | ||
438 | case *windowAdjustMsg: | ||
439 | if !c.remoteWin.add(msg.AdditionalBytes) { | ||
440 | return fmt.Errorf("ssh: invalid window update for %d bytes", msg.AdditionalBytes) | ||
441 | } | ||
442 | case *channelRequestMsg: | ||
443 | req := Request{ | ||
444 | Type: msg.Request, | ||
445 | WantReply: msg.WantReply, | ||
446 | Payload: msg.RequestSpecificData, | ||
447 | ch: c, | ||
448 | } | ||
449 | |||
450 | c.incomingRequests <- &req | ||
451 | default: | ||
452 | c.msg <- msg | ||
453 | } | ||
454 | return nil | ||
455 | } | ||
456 | |||
457 | func (m *mux) newChannel(chanType string, direction channelDirection, extraData []byte) *channel { | ||
458 | ch := &channel{ | ||
459 | remoteWin: window{Cond: newCond()}, | ||
460 | myWindow: channelWindowSize, | ||
461 | pending: newBuffer(), | ||
462 | extPending: newBuffer(), | ||
463 | direction: direction, | ||
464 | incomingRequests: make(chan *Request, chanSize), | ||
465 | msg: make(chan interface{}, chanSize), | ||
466 | chanType: chanType, | ||
467 | extraData: extraData, | ||
468 | mux: m, | ||
469 | packetPool: make(map[uint32][]byte), | ||
470 | } | ||
471 | ch.localId = m.chanList.add(ch) | ||
472 | return ch | ||
473 | } | ||
474 | |||
475 | var errUndecided = errors.New("ssh: must Accept or Reject channel") | ||
476 | var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") | ||
477 | |||
478 | type extChannel struct { | ||
479 | code uint32 | ||
480 | ch *channel | ||
481 | } | ||
482 | |||
483 | func (e *extChannel) Write(data []byte) (n int, err error) { | ||
484 | return e.ch.WriteExtended(data, e.code) | ||
485 | } | ||
486 | |||
487 | func (e *extChannel) Read(data []byte) (n int, err error) { | ||
488 | return e.ch.ReadExtended(data, e.code) | ||
489 | } | ||
490 | |||
491 | func (c *channel) Accept() (Channel, <-chan *Request, error) { | ||
492 | if c.decided { | ||
493 | return nil, nil, errDecidedAlready | ||
494 | } | ||
495 | c.maxIncomingPayload = channelMaxPacket | ||
496 | confirm := channelOpenConfirmMsg{ | ||
497 | PeersId: c.remoteId, | ||
498 | MyId: c.localId, | ||
499 | MyWindow: c.myWindow, | ||
500 | MaxPacketSize: c.maxIncomingPayload, | ||
501 | } | ||
502 | c.decided = true | ||
503 | if err := c.sendMessage(confirm); err != nil { | ||
504 | return nil, nil, err | ||
505 | } | ||
506 | |||
507 | return c, c.incomingRequests, nil | ||
508 | } | ||
509 | |||
510 | func (ch *channel) Reject(reason RejectionReason, message string) error { | ||
511 | if ch.decided { | ||
512 | return errDecidedAlready | ||
513 | } | ||
514 | reject := channelOpenFailureMsg{ | ||
515 | PeersId: ch.remoteId, | ||
516 | Reason: reason, | ||
517 | Message: message, | ||
518 | Language: "en", | ||
519 | } | ||
520 | ch.decided = true | ||
521 | return ch.sendMessage(reject) | ||
522 | } | ||
523 | |||
524 | func (ch *channel) Read(data []byte) (int, error) { | ||
525 | if !ch.decided { | ||
526 | return 0, errUndecided | ||
527 | } | ||
528 | return ch.ReadExtended(data, 0) | ||
529 | } | ||
530 | |||
531 | func (ch *channel) Write(data []byte) (int, error) { | ||
532 | if !ch.decided { | ||
533 | return 0, errUndecided | ||
534 | } | ||
535 | return ch.WriteExtended(data, 0) | ||
536 | } | ||
537 | |||
538 | func (ch *channel) CloseWrite() error { | ||
539 | if !ch.decided { | ||
540 | return errUndecided | ||
541 | } | ||
542 | ch.sentEOF = true | ||
543 | return ch.sendMessage(channelEOFMsg{ | ||
544 | PeersId: ch.remoteId}) | ||
545 | } | ||
546 | |||
547 | func (ch *channel) Close() error { | ||
548 | if !ch.decided { | ||
549 | return errUndecided | ||
550 | } | ||
551 | |||
552 | return ch.sendMessage(channelCloseMsg{ | ||
553 | PeersId: ch.remoteId}) | ||
554 | } | ||
555 | |||
556 | // Extended returns an io.ReadWriter that sends and receives data on the given, | ||
557 | // SSH extended stream. Such streams are used, for example, for stderr. | ||
558 | func (ch *channel) Extended(code uint32) io.ReadWriter { | ||
559 | if !ch.decided { | ||
560 | return nil | ||
561 | } | ||
562 | return &extChannel{code, ch} | ||
563 | } | ||
564 | |||
565 | func (ch *channel) Stderr() io.ReadWriter { | ||
566 | return ch.Extended(1) | ||
567 | } | ||
568 | |||
569 | func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { | ||
570 | if !ch.decided { | ||
571 | return false, errUndecided | ||
572 | } | ||
573 | |||
574 | if wantReply { | ||
575 | ch.sentRequestMu.Lock() | ||
576 | defer ch.sentRequestMu.Unlock() | ||
577 | } | ||
578 | |||
579 | msg := channelRequestMsg{ | ||
580 | PeersId: ch.remoteId, | ||
581 | Request: name, | ||
582 | WantReply: wantReply, | ||
583 | RequestSpecificData: payload, | ||
584 | } | ||
585 | |||
586 | if err := ch.sendMessage(msg); err != nil { | ||
587 | return false, err | ||
588 | } | ||
589 | |||
590 | if wantReply { | ||
591 | m, ok := (<-ch.msg) | ||
592 | if !ok { | ||
593 | return false, io.EOF | ||
594 | } | ||
595 | switch m.(type) { | ||
596 | case *channelRequestFailureMsg: | ||
597 | return false, nil | ||
598 | case *channelRequestSuccessMsg: | ||
599 | return true, nil | ||
600 | default: | ||
601 | return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", m) | ||
602 | } | ||
603 | } | ||
604 | |||
605 | return false, nil | ||
606 | } | ||
607 | |||
608 | // ackRequest either sends an ack or nack to the channel request. | ||
609 | func (ch *channel) ackRequest(ok bool) error { | ||
610 | if !ch.decided { | ||
611 | return errUndecided | ||
612 | } | ||
613 | |||
614 | var msg interface{} | ||
615 | if !ok { | ||
616 | msg = channelRequestFailureMsg{ | ||
617 | PeersId: ch.remoteId, | ||
618 | } | ||
619 | } else { | ||
620 | msg = channelRequestSuccessMsg{ | ||
621 | PeersId: ch.remoteId, | ||
622 | } | ||
623 | } | ||
624 | return ch.sendMessage(msg) | ||
625 | } | ||
626 | |||
627 | func (ch *channel) ChannelType() string { | ||
628 | return ch.chanType | ||
629 | } | ||
630 | |||
631 | func (ch *channel) ExtraData() []byte { | ||
632 | return ch.extraData | ||
633 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/cipher.go b/vendor/golang.org/x/crypto/ssh/cipher.go new file mode 100644 index 0000000..13484ab --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/cipher.go | |||
@@ -0,0 +1,627 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "crypto/aes" | ||
9 | "crypto/cipher" | ||
10 | "crypto/des" | ||
11 | "crypto/rc4" | ||
12 | "crypto/subtle" | ||
13 | "encoding/binary" | ||
14 | "errors" | ||
15 | "fmt" | ||
16 | "hash" | ||
17 | "io" | ||
18 | "io/ioutil" | ||
19 | ) | ||
20 | |||
21 | const ( | ||
22 | packetSizeMultiple = 16 // TODO(huin) this should be determined by the cipher. | ||
23 | |||
24 | // RFC 4253 section 6.1 defines a minimum packet size of 32768 that implementations | ||
25 | // MUST be able to process (plus a few more kilobytes for padding and mac). The RFC | ||
26 | // indicates implementations SHOULD be able to handle larger packet sizes, but then | ||
27 | // waffles on about reasonable limits. | ||
28 | // | ||
29 | // OpenSSH caps their maxPacket at 256kB so we choose to do | ||
30 | // the same. maxPacket is also used to ensure that uint32 | ||
31 | // length fields do not overflow, so it should remain well | ||
32 | // below 4G. | ||
33 | maxPacket = 256 * 1024 | ||
34 | ) | ||
35 | |||
36 | // noneCipher implements cipher.Stream and provides no encryption. It is used | ||
37 | // by the transport before the first key-exchange. | ||
38 | type noneCipher struct{} | ||
39 | |||
40 | func (c noneCipher) XORKeyStream(dst, src []byte) { | ||
41 | copy(dst, src) | ||
42 | } | ||
43 | |||
44 | func newAESCTR(key, iv []byte) (cipher.Stream, error) { | ||
45 | c, err := aes.NewCipher(key) | ||
46 | if err != nil { | ||
47 | return nil, err | ||
48 | } | ||
49 | return cipher.NewCTR(c, iv), nil | ||
50 | } | ||
51 | |||
52 | func newRC4(key, iv []byte) (cipher.Stream, error) { | ||
53 | return rc4.NewCipher(key) | ||
54 | } | ||
55 | |||
56 | type streamCipherMode struct { | ||
57 | keySize int | ||
58 | ivSize int | ||
59 | skip int | ||
60 | createFunc func(key, iv []byte) (cipher.Stream, error) | ||
61 | } | ||
62 | |||
63 | func (c *streamCipherMode) createStream(key, iv []byte) (cipher.Stream, error) { | ||
64 | if len(key) < c.keySize { | ||
65 | panic("ssh: key length too small for cipher") | ||
66 | } | ||
67 | if len(iv) < c.ivSize { | ||
68 | panic("ssh: iv too small for cipher") | ||
69 | } | ||
70 | |||
71 | stream, err := c.createFunc(key[:c.keySize], iv[:c.ivSize]) | ||
72 | if err != nil { | ||
73 | return nil, err | ||
74 | } | ||
75 | |||
76 | var streamDump []byte | ||
77 | if c.skip > 0 { | ||
78 | streamDump = make([]byte, 512) | ||
79 | } | ||
80 | |||
81 | for remainingToDump := c.skip; remainingToDump > 0; { | ||
82 | dumpThisTime := remainingToDump | ||
83 | if dumpThisTime > len(streamDump) { | ||
84 | dumpThisTime = len(streamDump) | ||
85 | } | ||
86 | stream.XORKeyStream(streamDump[:dumpThisTime], streamDump[:dumpThisTime]) | ||
87 | remainingToDump -= dumpThisTime | ||
88 | } | ||
89 | |||
90 | return stream, nil | ||
91 | } | ||
92 | |||
93 | // cipherModes documents properties of supported ciphers. Ciphers not included | ||
94 | // are not supported and will not be negotiated, even if explicitly requested in | ||
95 | // ClientConfig.Crypto.Ciphers. | ||
96 | var cipherModes = map[string]*streamCipherMode{ | ||
97 | // Ciphers from RFC4344, which introduced many CTR-based ciphers. Algorithms | ||
98 | // are defined in the order specified in the RFC. | ||
99 | "aes128-ctr": {16, aes.BlockSize, 0, newAESCTR}, | ||
100 | "aes192-ctr": {24, aes.BlockSize, 0, newAESCTR}, | ||
101 | "aes256-ctr": {32, aes.BlockSize, 0, newAESCTR}, | ||
102 | |||
103 | // Ciphers from RFC4345, which introduces security-improved arcfour ciphers. | ||
104 | // They are defined in the order specified in the RFC. | ||
105 | "arcfour128": {16, 0, 1536, newRC4}, | ||
106 | "arcfour256": {32, 0, 1536, newRC4}, | ||
107 | |||
108 | // Cipher defined in RFC 4253, which describes SSH Transport Layer Protocol. | ||
109 | // Note that this cipher is not safe, as stated in RFC 4253: "Arcfour (and | ||
110 | // RC4) has problems with weak keys, and should be used with caution." | ||
111 | // RFC4345 introduces improved versions of Arcfour. | ||
112 | "arcfour": {16, 0, 0, newRC4}, | ||
113 | |||
114 | // AES-GCM is not a stream cipher, so it is constructed with a | ||
115 | // special case. If we add any more non-stream ciphers, we | ||
116 | // should invest a cleaner way to do this. | ||
117 | gcmCipherID: {16, 12, 0, nil}, | ||
118 | |||
119 | // CBC mode is insecure and so is not included in the default config. | ||
120 | // (See http://www.isg.rhul.ac.uk/~kp/SandPfinal.pdf). If absolutely | ||
121 | // needed, it's possible to specify a custom Config to enable it. | ||
122 | // You should expect that an active attacker can recover plaintext if | ||
123 | // you do. | ||
124 | aes128cbcID: {16, aes.BlockSize, 0, nil}, | ||
125 | |||
126 | // 3des-cbc is insecure and is disabled by default. | ||
127 | tripledescbcID: {24, des.BlockSize, 0, nil}, | ||
128 | } | ||
129 | |||
130 | // prefixLen is the length of the packet prefix that contains the packet length | ||
131 | // and number of padding bytes. | ||
132 | const prefixLen = 5 | ||
133 | |||
134 | // streamPacketCipher is a packetCipher using a stream cipher. | ||
135 | type streamPacketCipher struct { | ||
136 | mac hash.Hash | ||
137 | cipher cipher.Stream | ||
138 | etm bool | ||
139 | |||
140 | // The following members are to avoid per-packet allocations. | ||
141 | prefix [prefixLen]byte | ||
142 | seqNumBytes [4]byte | ||
143 | padding [2 * packetSizeMultiple]byte | ||
144 | packetData []byte | ||
145 | macResult []byte | ||
146 | } | ||
147 | |||
148 | // readPacket reads and decrypt a single packet from the reader argument. | ||
149 | func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||
150 | if _, err := io.ReadFull(r, s.prefix[:]); err != nil { | ||
151 | return nil, err | ||
152 | } | ||
153 | |||
154 | var encryptedPaddingLength [1]byte | ||
155 | if s.mac != nil && s.etm { | ||
156 | copy(encryptedPaddingLength[:], s.prefix[4:5]) | ||
157 | s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) | ||
158 | } else { | ||
159 | s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) | ||
160 | } | ||
161 | |||
162 | length := binary.BigEndian.Uint32(s.prefix[0:4]) | ||
163 | paddingLength := uint32(s.prefix[4]) | ||
164 | |||
165 | var macSize uint32 | ||
166 | if s.mac != nil { | ||
167 | s.mac.Reset() | ||
168 | binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) | ||
169 | s.mac.Write(s.seqNumBytes[:]) | ||
170 | if s.etm { | ||
171 | s.mac.Write(s.prefix[:4]) | ||
172 | s.mac.Write(encryptedPaddingLength[:]) | ||
173 | } else { | ||
174 | s.mac.Write(s.prefix[:]) | ||
175 | } | ||
176 | macSize = uint32(s.mac.Size()) | ||
177 | } | ||
178 | |||
179 | if length <= paddingLength+1 { | ||
180 | return nil, errors.New("ssh: invalid packet length, packet too small") | ||
181 | } | ||
182 | |||
183 | if length > maxPacket { | ||
184 | return nil, errors.New("ssh: invalid packet length, packet too large") | ||
185 | } | ||
186 | |||
187 | // the maxPacket check above ensures that length-1+macSize | ||
188 | // does not overflow. | ||
189 | if uint32(cap(s.packetData)) < length-1+macSize { | ||
190 | s.packetData = make([]byte, length-1+macSize) | ||
191 | } else { | ||
192 | s.packetData = s.packetData[:length-1+macSize] | ||
193 | } | ||
194 | |||
195 | if _, err := io.ReadFull(r, s.packetData); err != nil { | ||
196 | return nil, err | ||
197 | } | ||
198 | mac := s.packetData[length-1:] | ||
199 | data := s.packetData[:length-1] | ||
200 | |||
201 | if s.mac != nil && s.etm { | ||
202 | s.mac.Write(data) | ||
203 | } | ||
204 | |||
205 | s.cipher.XORKeyStream(data, data) | ||
206 | |||
207 | if s.mac != nil { | ||
208 | if !s.etm { | ||
209 | s.mac.Write(data) | ||
210 | } | ||
211 | s.macResult = s.mac.Sum(s.macResult[:0]) | ||
212 | if subtle.ConstantTimeCompare(s.macResult, mac) != 1 { | ||
213 | return nil, errors.New("ssh: MAC failure") | ||
214 | } | ||
215 | } | ||
216 | |||
217 | return s.packetData[:length-paddingLength-1], nil | ||
218 | } | ||
219 | |||
220 | // writePacket encrypts and sends a packet of data to the writer argument | ||
221 | func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||
222 | if len(packet) > maxPacket { | ||
223 | return errors.New("ssh: packet too large") | ||
224 | } | ||
225 | |||
226 | aadlen := 0 | ||
227 | if s.mac != nil && s.etm { | ||
228 | // packet length is not encrypted for EtM modes | ||
229 | aadlen = 4 | ||
230 | } | ||
231 | |||
232 | paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple | ||
233 | if paddingLength < 4 { | ||
234 | paddingLength += packetSizeMultiple | ||
235 | } | ||
236 | |||
237 | length := len(packet) + 1 + paddingLength | ||
238 | binary.BigEndian.PutUint32(s.prefix[:], uint32(length)) | ||
239 | s.prefix[4] = byte(paddingLength) | ||
240 | padding := s.padding[:paddingLength] | ||
241 | if _, err := io.ReadFull(rand, padding); err != nil { | ||
242 | return err | ||
243 | } | ||
244 | |||
245 | if s.mac != nil { | ||
246 | s.mac.Reset() | ||
247 | binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum) | ||
248 | s.mac.Write(s.seqNumBytes[:]) | ||
249 | |||
250 | if s.etm { | ||
251 | // For EtM algorithms, the packet length must stay unencrypted, | ||
252 | // but the following data (padding length) must be encrypted | ||
253 | s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5]) | ||
254 | } | ||
255 | |||
256 | s.mac.Write(s.prefix[:]) | ||
257 | |||
258 | if !s.etm { | ||
259 | // For non-EtM algorithms, the algorithm is applied on unencrypted data | ||
260 | s.mac.Write(packet) | ||
261 | s.mac.Write(padding) | ||
262 | } | ||
263 | } | ||
264 | |||
265 | if !(s.mac != nil && s.etm) { | ||
266 | // For EtM algorithms, the padding length has already been encrypted | ||
267 | // and the packet length must remain unencrypted | ||
268 | s.cipher.XORKeyStream(s.prefix[:], s.prefix[:]) | ||
269 | } | ||
270 | |||
271 | s.cipher.XORKeyStream(packet, packet) | ||
272 | s.cipher.XORKeyStream(padding, padding) | ||
273 | |||
274 | if s.mac != nil && s.etm { | ||
275 | // For EtM algorithms, packet and padding must be encrypted | ||
276 | s.mac.Write(packet) | ||
277 | s.mac.Write(padding) | ||
278 | } | ||
279 | |||
280 | if _, err := w.Write(s.prefix[:]); err != nil { | ||
281 | return err | ||
282 | } | ||
283 | if _, err := w.Write(packet); err != nil { | ||
284 | return err | ||
285 | } | ||
286 | if _, err := w.Write(padding); err != nil { | ||
287 | return err | ||
288 | } | ||
289 | |||
290 | if s.mac != nil { | ||
291 | s.macResult = s.mac.Sum(s.macResult[:0]) | ||
292 | if _, err := w.Write(s.macResult); err != nil { | ||
293 | return err | ||
294 | } | ||
295 | } | ||
296 | |||
297 | return nil | ||
298 | } | ||
299 | |||
300 | type gcmCipher struct { | ||
301 | aead cipher.AEAD | ||
302 | prefix [4]byte | ||
303 | iv []byte | ||
304 | buf []byte | ||
305 | } | ||
306 | |||
307 | func newGCMCipher(iv, key, macKey []byte) (packetCipher, error) { | ||
308 | c, err := aes.NewCipher(key) | ||
309 | if err != nil { | ||
310 | return nil, err | ||
311 | } | ||
312 | |||
313 | aead, err := cipher.NewGCM(c) | ||
314 | if err != nil { | ||
315 | return nil, err | ||
316 | } | ||
317 | |||
318 | return &gcmCipher{ | ||
319 | aead: aead, | ||
320 | iv: iv, | ||
321 | }, nil | ||
322 | } | ||
323 | |||
324 | const gcmTagSize = 16 | ||
325 | |||
326 | func (c *gcmCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||
327 | // Pad out to multiple of 16 bytes. This is different from the | ||
328 | // stream cipher because that encrypts the length too. | ||
329 | padding := byte(packetSizeMultiple - (1+len(packet))%packetSizeMultiple) | ||
330 | if padding < 4 { | ||
331 | padding += packetSizeMultiple | ||
332 | } | ||
333 | |||
334 | length := uint32(len(packet) + int(padding) + 1) | ||
335 | binary.BigEndian.PutUint32(c.prefix[:], length) | ||
336 | if _, err := w.Write(c.prefix[:]); err != nil { | ||
337 | return err | ||
338 | } | ||
339 | |||
340 | if cap(c.buf) < int(length) { | ||
341 | c.buf = make([]byte, length) | ||
342 | } else { | ||
343 | c.buf = c.buf[:length] | ||
344 | } | ||
345 | |||
346 | c.buf[0] = padding | ||
347 | copy(c.buf[1:], packet) | ||
348 | if _, err := io.ReadFull(rand, c.buf[1+len(packet):]); err != nil { | ||
349 | return err | ||
350 | } | ||
351 | c.buf = c.aead.Seal(c.buf[:0], c.iv, c.buf, c.prefix[:]) | ||
352 | if _, err := w.Write(c.buf); err != nil { | ||
353 | return err | ||
354 | } | ||
355 | c.incIV() | ||
356 | |||
357 | return nil | ||
358 | } | ||
359 | |||
360 | func (c *gcmCipher) incIV() { | ||
361 | for i := 4 + 7; i >= 4; i-- { | ||
362 | c.iv[i]++ | ||
363 | if c.iv[i] != 0 { | ||
364 | break | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
369 | func (c *gcmCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||
370 | if _, err := io.ReadFull(r, c.prefix[:]); err != nil { | ||
371 | return nil, err | ||
372 | } | ||
373 | length := binary.BigEndian.Uint32(c.prefix[:]) | ||
374 | if length > maxPacket { | ||
375 | return nil, errors.New("ssh: max packet length exceeded.") | ||
376 | } | ||
377 | |||
378 | if cap(c.buf) < int(length+gcmTagSize) { | ||
379 | c.buf = make([]byte, length+gcmTagSize) | ||
380 | } else { | ||
381 | c.buf = c.buf[:length+gcmTagSize] | ||
382 | } | ||
383 | |||
384 | if _, err := io.ReadFull(r, c.buf); err != nil { | ||
385 | return nil, err | ||
386 | } | ||
387 | |||
388 | plain, err := c.aead.Open(c.buf[:0], c.iv, c.buf, c.prefix[:]) | ||
389 | if err != nil { | ||
390 | return nil, err | ||
391 | } | ||
392 | c.incIV() | ||
393 | |||
394 | padding := plain[0] | ||
395 | if padding < 4 || padding >= 20 { | ||
396 | return nil, fmt.Errorf("ssh: illegal padding %d", padding) | ||
397 | } | ||
398 | |||
399 | if int(padding+1) >= len(plain) { | ||
400 | return nil, fmt.Errorf("ssh: padding %d too large", padding) | ||
401 | } | ||
402 | plain = plain[1 : length-uint32(padding)] | ||
403 | return plain, nil | ||
404 | } | ||
405 | |||
406 | // cbcCipher implements aes128-cbc cipher defined in RFC 4253 section 6.1 | ||
407 | type cbcCipher struct { | ||
408 | mac hash.Hash | ||
409 | macSize uint32 | ||
410 | decrypter cipher.BlockMode | ||
411 | encrypter cipher.BlockMode | ||
412 | |||
413 | // The following members are to avoid per-packet allocations. | ||
414 | seqNumBytes [4]byte | ||
415 | packetData []byte | ||
416 | macResult []byte | ||
417 | |||
418 | // Amount of data we should still read to hide which | ||
419 | // verification error triggered. | ||
420 | oracleCamouflage uint32 | ||
421 | } | ||
422 | |||
423 | func newCBCCipher(c cipher.Block, iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||
424 | cbc := &cbcCipher{ | ||
425 | mac: macModes[algs.MAC].new(macKey), | ||
426 | decrypter: cipher.NewCBCDecrypter(c, iv), | ||
427 | encrypter: cipher.NewCBCEncrypter(c, iv), | ||
428 | packetData: make([]byte, 1024), | ||
429 | } | ||
430 | if cbc.mac != nil { | ||
431 | cbc.macSize = uint32(cbc.mac.Size()) | ||
432 | } | ||
433 | |||
434 | return cbc, nil | ||
435 | } | ||
436 | |||
437 | func newAESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||
438 | c, err := aes.NewCipher(key) | ||
439 | if err != nil { | ||
440 | return nil, err | ||
441 | } | ||
442 | |||
443 | cbc, err := newCBCCipher(c, iv, key, macKey, algs) | ||
444 | if err != nil { | ||
445 | return nil, err | ||
446 | } | ||
447 | |||
448 | return cbc, nil | ||
449 | } | ||
450 | |||
451 | func newTripleDESCBCCipher(iv, key, macKey []byte, algs directionAlgorithms) (packetCipher, error) { | ||
452 | c, err := des.NewTripleDESCipher(key) | ||
453 | if err != nil { | ||
454 | return nil, err | ||
455 | } | ||
456 | |||
457 | cbc, err := newCBCCipher(c, iv, key, macKey, algs) | ||
458 | if err != nil { | ||
459 | return nil, err | ||
460 | } | ||
461 | |||
462 | return cbc, nil | ||
463 | } | ||
464 | |||
465 | func maxUInt32(a, b int) uint32 { | ||
466 | if a > b { | ||
467 | return uint32(a) | ||
468 | } | ||
469 | return uint32(b) | ||
470 | } | ||
471 | |||
472 | const ( | ||
473 | cbcMinPacketSizeMultiple = 8 | ||
474 | cbcMinPacketSize = 16 | ||
475 | cbcMinPaddingSize = 4 | ||
476 | ) | ||
477 | |||
478 | // cbcError represents a verification error that may leak information. | ||
479 | type cbcError string | ||
480 | |||
481 | func (e cbcError) Error() string { return string(e) } | ||
482 | |||
483 | func (c *cbcCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, error) { | ||
484 | p, err := c.readPacketLeaky(seqNum, r) | ||
485 | if err != nil { | ||
486 | if _, ok := err.(cbcError); ok { | ||
487 | // Verification error: read a fixed amount of | ||
488 | // data, to make distinguishing between | ||
489 | // failing MAC and failing length check more | ||
490 | // difficult. | ||
491 | io.CopyN(ioutil.Discard, r, int64(c.oracleCamouflage)) | ||
492 | } | ||
493 | } | ||
494 | return p, err | ||
495 | } | ||
496 | |||
497 | func (c *cbcCipher) readPacketLeaky(seqNum uint32, r io.Reader) ([]byte, error) { | ||
498 | blockSize := c.decrypter.BlockSize() | ||
499 | |||
500 | // Read the header, which will include some of the subsequent data in the | ||
501 | // case of block ciphers - this is copied back to the payload later. | ||
502 | // How many bytes of payload/padding will be read with this first read. | ||
503 | firstBlockLength := uint32((prefixLen + blockSize - 1) / blockSize * blockSize) | ||
504 | firstBlock := c.packetData[:firstBlockLength] | ||
505 | if _, err := io.ReadFull(r, firstBlock); err != nil { | ||
506 | return nil, err | ||
507 | } | ||
508 | |||
509 | c.oracleCamouflage = maxPacket + 4 + c.macSize - firstBlockLength | ||
510 | |||
511 | c.decrypter.CryptBlocks(firstBlock, firstBlock) | ||
512 | length := binary.BigEndian.Uint32(firstBlock[:4]) | ||
513 | if length > maxPacket { | ||
514 | return nil, cbcError("ssh: packet too large") | ||
515 | } | ||
516 | if length+4 < maxUInt32(cbcMinPacketSize, blockSize) { | ||
517 | // The minimum size of a packet is 16 (or the cipher block size, whichever | ||
518 | // is larger) bytes. | ||
519 | return nil, cbcError("ssh: packet too small") | ||
520 | } | ||
521 | // The length of the packet (including the length field but not the MAC) must | ||
522 | // be a multiple of the block size or 8, whichever is larger. | ||
523 | if (length+4)%maxUInt32(cbcMinPacketSizeMultiple, blockSize) != 0 { | ||
524 | return nil, cbcError("ssh: invalid packet length multiple") | ||
525 | } | ||
526 | |||
527 | paddingLength := uint32(firstBlock[4]) | ||
528 | if paddingLength < cbcMinPaddingSize || length <= paddingLength+1 { | ||
529 | return nil, cbcError("ssh: invalid packet length") | ||
530 | } | ||
531 | |||
532 | // Positions within the c.packetData buffer: | ||
533 | macStart := 4 + length | ||
534 | paddingStart := macStart - paddingLength | ||
535 | |||
536 | // Entire packet size, starting before length, ending at end of mac. | ||
537 | entirePacketSize := macStart + c.macSize | ||
538 | |||
539 | // Ensure c.packetData is large enough for the entire packet data. | ||
540 | if uint32(cap(c.packetData)) < entirePacketSize { | ||
541 | // Still need to upsize and copy, but this should be rare at runtime, only | ||
542 | // on upsizing the packetData buffer. | ||
543 | c.packetData = make([]byte, entirePacketSize) | ||
544 | copy(c.packetData, firstBlock) | ||
545 | } else { | ||
546 | c.packetData = c.packetData[:entirePacketSize] | ||
547 | } | ||
548 | |||
549 | if n, err := io.ReadFull(r, c.packetData[firstBlockLength:]); err != nil { | ||
550 | return nil, err | ||
551 | } else { | ||
552 | c.oracleCamouflage -= uint32(n) | ||
553 | } | ||
554 | |||
555 | remainingCrypted := c.packetData[firstBlockLength:macStart] | ||
556 | c.decrypter.CryptBlocks(remainingCrypted, remainingCrypted) | ||
557 | |||
558 | mac := c.packetData[macStart:] | ||
559 | if c.mac != nil { | ||
560 | c.mac.Reset() | ||
561 | binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) | ||
562 | c.mac.Write(c.seqNumBytes[:]) | ||
563 | c.mac.Write(c.packetData[:macStart]) | ||
564 | c.macResult = c.mac.Sum(c.macResult[:0]) | ||
565 | if subtle.ConstantTimeCompare(c.macResult, mac) != 1 { | ||
566 | return nil, cbcError("ssh: MAC failure") | ||
567 | } | ||
568 | } | ||
569 | |||
570 | return c.packetData[prefixLen:paddingStart], nil | ||
571 | } | ||
572 | |||
573 | func (c *cbcCipher) writePacket(seqNum uint32, w io.Writer, rand io.Reader, packet []byte) error { | ||
574 | effectiveBlockSize := maxUInt32(cbcMinPacketSizeMultiple, c.encrypter.BlockSize()) | ||
575 | |||
576 | // Length of encrypted portion of the packet (header, payload, padding). | ||
577 | // Enforce minimum padding and packet size. | ||
578 | encLength := maxUInt32(prefixLen+len(packet)+cbcMinPaddingSize, cbcMinPaddingSize) | ||
579 | // Enforce block size. | ||
580 | encLength = (encLength + effectiveBlockSize - 1) / effectiveBlockSize * effectiveBlockSize | ||
581 | |||
582 | length := encLength - 4 | ||
583 | paddingLength := int(length) - (1 + len(packet)) | ||
584 | |||
585 | // Overall buffer contains: header, payload, padding, mac. | ||
586 | // Space for the MAC is reserved in the capacity but not the slice length. | ||
587 | bufferSize := encLength + c.macSize | ||
588 | if uint32(cap(c.packetData)) < bufferSize { | ||
589 | c.packetData = make([]byte, encLength, bufferSize) | ||
590 | } else { | ||
591 | c.packetData = c.packetData[:encLength] | ||
592 | } | ||
593 | |||
594 | p := c.packetData | ||
595 | |||
596 | // Packet header. | ||
597 | binary.BigEndian.PutUint32(p, length) | ||
598 | p = p[4:] | ||
599 | p[0] = byte(paddingLength) | ||
600 | |||
601 | // Payload. | ||
602 | p = p[1:] | ||
603 | copy(p, packet) | ||
604 | |||
605 | // Padding. | ||
606 | p = p[len(packet):] | ||
607 | if _, err := io.ReadFull(rand, p); err != nil { | ||
608 | return err | ||
609 | } | ||
610 | |||
611 | if c.mac != nil { | ||
612 | c.mac.Reset() | ||
613 | binary.BigEndian.PutUint32(c.seqNumBytes[:], seqNum) | ||
614 | c.mac.Write(c.seqNumBytes[:]) | ||
615 | c.mac.Write(c.packetData) | ||
616 | // The MAC is now appended into the capacity reserved for it earlier. | ||
617 | c.packetData = c.mac.Sum(c.packetData) | ||
618 | } | ||
619 | |||
620 | c.encrypter.CryptBlocks(c.packetData[:encLength], c.packetData[:encLength]) | ||
621 | |||
622 | if _, err := w.Write(c.packetData); err != nil { | ||
623 | return err | ||
624 | } | ||
625 | |||
626 | return nil | ||
627 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go new file mode 100644 index 0000000..c97f297 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client.go | |||
@@ -0,0 +1,211 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "errors" | ||
9 | "fmt" | ||
10 | "net" | ||
11 | "sync" | ||
12 | "time" | ||
13 | ) | ||
14 | |||
15 | // Client implements a traditional SSH client that supports shells, | ||
16 | // subprocesses, port forwarding and tunneled dialing. | ||
17 | type Client struct { | ||
18 | Conn | ||
19 | |||
20 | forwards forwardList // forwarded tcpip connections from the remote side | ||
21 | mu sync.Mutex | ||
22 | channelHandlers map[string]chan NewChannel | ||
23 | } | ||
24 | |||
25 | // HandleChannelOpen returns a channel on which NewChannel requests | ||
26 | // for the given type are sent. If the type already is being handled, | ||
27 | // nil is returned. The channel is closed when the connection is closed. | ||
28 | func (c *Client) HandleChannelOpen(channelType string) <-chan NewChannel { | ||
29 | c.mu.Lock() | ||
30 | defer c.mu.Unlock() | ||
31 | if c.channelHandlers == nil { | ||
32 | // The SSH channel has been closed. | ||
33 | c := make(chan NewChannel) | ||
34 | close(c) | ||
35 | return c | ||
36 | } | ||
37 | |||
38 | ch := c.channelHandlers[channelType] | ||
39 | if ch != nil { | ||
40 | return nil | ||
41 | } | ||
42 | |||
43 | ch = make(chan NewChannel, chanSize) | ||
44 | c.channelHandlers[channelType] = ch | ||
45 | return ch | ||
46 | } | ||
47 | |||
48 | // NewClient creates a Client on top of the given connection. | ||
49 | func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client { | ||
50 | conn := &Client{ | ||
51 | Conn: c, | ||
52 | channelHandlers: make(map[string]chan NewChannel, 1), | ||
53 | } | ||
54 | |||
55 | go conn.handleGlobalRequests(reqs) | ||
56 | go conn.handleChannelOpens(chans) | ||
57 | go func() { | ||
58 | conn.Wait() | ||
59 | conn.forwards.closeAll() | ||
60 | }() | ||
61 | go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip")) | ||
62 | return conn | ||
63 | } | ||
64 | |||
65 | // NewClientConn establishes an authenticated SSH connection using c | ||
66 | // as the underlying transport. The Request and NewChannel channels | ||
67 | // must be serviced or the connection will hang. | ||
68 | func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) { | ||
69 | fullConf := *config | ||
70 | fullConf.SetDefaults() | ||
71 | conn := &connection{ | ||
72 | sshConn: sshConn{conn: c}, | ||
73 | } | ||
74 | |||
75 | if err := conn.clientHandshake(addr, &fullConf); err != nil { | ||
76 | c.Close() | ||
77 | return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err) | ||
78 | } | ||
79 | conn.mux = newMux(conn.transport) | ||
80 | return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil | ||
81 | } | ||
82 | |||
83 | // clientHandshake performs the client side key exchange. See RFC 4253 Section | ||
84 | // 7. | ||
85 | func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error { | ||
86 | if config.ClientVersion != "" { | ||
87 | c.clientVersion = []byte(config.ClientVersion) | ||
88 | } else { | ||
89 | c.clientVersion = []byte(packageVersion) | ||
90 | } | ||
91 | var err error | ||
92 | c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion) | ||
93 | if err != nil { | ||
94 | return err | ||
95 | } | ||
96 | |||
97 | c.transport = newClientTransport( | ||
98 | newTransport(c.sshConn.conn, config.Rand, true /* is client */), | ||
99 | c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr()) | ||
100 | if err := c.transport.waitSession(); err != nil { | ||
101 | return err | ||
102 | } | ||
103 | |||
104 | c.sessionID = c.transport.getSessionID() | ||
105 | return c.clientAuthenticate(config) | ||
106 | } | ||
107 | |||
108 | // verifyHostKeySignature verifies the host key obtained in the key | ||
109 | // exchange. | ||
110 | func verifyHostKeySignature(hostKey PublicKey, result *kexResult) error { | ||
111 | sig, rest, ok := parseSignatureBody(result.Signature) | ||
112 | if len(rest) > 0 || !ok { | ||
113 | return errors.New("ssh: signature parse error") | ||
114 | } | ||
115 | |||
116 | return hostKey.Verify(result.H, sig) | ||
117 | } | ||
118 | |||
119 | // NewSession opens a new Session for this client. (A session is a remote | ||
120 | // execution of a program.) | ||
121 | func (c *Client) NewSession() (*Session, error) { | ||
122 | ch, in, err := c.OpenChannel("session", nil) | ||
123 | if err != nil { | ||
124 | return nil, err | ||
125 | } | ||
126 | return newSession(ch, in) | ||
127 | } | ||
128 | |||
129 | func (c *Client) handleGlobalRequests(incoming <-chan *Request) { | ||
130 | for r := range incoming { | ||
131 | // This handles keepalive messages and matches | ||
132 | // the behaviour of OpenSSH. | ||
133 | r.Reply(false, nil) | ||
134 | } | ||
135 | } | ||
136 | |||
137 | // handleChannelOpens channel open messages from the remote side. | ||
138 | func (c *Client) handleChannelOpens(in <-chan NewChannel) { | ||
139 | for ch := range in { | ||
140 | c.mu.Lock() | ||
141 | handler := c.channelHandlers[ch.ChannelType()] | ||
142 | c.mu.Unlock() | ||
143 | |||
144 | if handler != nil { | ||
145 | handler <- ch | ||
146 | } else { | ||
147 | ch.Reject(UnknownChannelType, fmt.Sprintf("unknown channel type: %v", ch.ChannelType())) | ||
148 | } | ||
149 | } | ||
150 | |||
151 | c.mu.Lock() | ||
152 | for _, ch := range c.channelHandlers { | ||
153 | close(ch) | ||
154 | } | ||
155 | c.channelHandlers = nil | ||
156 | c.mu.Unlock() | ||
157 | } | ||
158 | |||
159 | // Dial starts a client connection to the given SSH server. It is a | ||
160 | // convenience function that connects to the given network address, | ||
161 | // initiates the SSH handshake, and then sets up a Client. For access | ||
162 | // to incoming channels and requests, use net.Dial with NewClientConn | ||
163 | // instead. | ||
164 | func Dial(network, addr string, config *ClientConfig) (*Client, error) { | ||
165 | conn, err := net.DialTimeout(network, addr, config.Timeout) | ||
166 | if err != nil { | ||
167 | return nil, err | ||
168 | } | ||
169 | c, chans, reqs, err := NewClientConn(conn, addr, config) | ||
170 | if err != nil { | ||
171 | return nil, err | ||
172 | } | ||
173 | return NewClient(c, chans, reqs), nil | ||
174 | } | ||
175 | |||
176 | // A ClientConfig structure is used to configure a Client. It must not be | ||
177 | // modified after having been passed to an SSH function. | ||
178 | type ClientConfig struct { | ||
179 | // Config contains configuration that is shared between clients and | ||
180 | // servers. | ||
181 | Config | ||
182 | |||
183 | // User contains the username to authenticate as. | ||
184 | User string | ||
185 | |||
186 | // Auth contains possible authentication methods to use with the | ||
187 | // server. Only the first instance of a particular RFC 4252 method will | ||
188 | // be used during authentication. | ||
189 | Auth []AuthMethod | ||
190 | |||
191 | // HostKeyCallback, if not nil, is called during the cryptographic | ||
192 | // handshake to validate the server's host key. A nil HostKeyCallback | ||
193 | // implies that all host keys are accepted. | ||
194 | HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error | ||
195 | |||
196 | // ClientVersion contains the version identification string that will | ||
197 | // be used for the connection. If empty, a reasonable default is used. | ||
198 | ClientVersion string | ||
199 | |||
200 | // HostKeyAlgorithms lists the key types that the client will | ||
201 | // accept from the server as host key, in order of | ||
202 | // preference. If empty, a reasonable default is used. Any | ||
203 | // string returned from PublicKey.Type method may be used, or | ||
204 | // any of the CertAlgoXxxx and KeyAlgoXxxx constants. | ||
205 | HostKeyAlgorithms []string | ||
206 | |||
207 | // Timeout is the maximum amount of time for the TCP connection to establish. | ||
208 | // | ||
209 | // A Timeout of zero means no timeout. | ||
210 | Timeout time.Duration | ||
211 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go new file mode 100644 index 0000000..fd1ec5d --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/client_auth.go | |||
@@ -0,0 +1,475 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "errors" | ||
10 | "fmt" | ||
11 | "io" | ||
12 | ) | ||
13 | |||
14 | // clientAuthenticate authenticates with the remote server. See RFC 4252. | ||
15 | func (c *connection) clientAuthenticate(config *ClientConfig) error { | ||
16 | // initiate user auth session | ||
17 | if err := c.transport.writePacket(Marshal(&serviceRequestMsg{serviceUserAuth})); err != nil { | ||
18 | return err | ||
19 | } | ||
20 | packet, err := c.transport.readPacket() | ||
21 | if err != nil { | ||
22 | return err | ||
23 | } | ||
24 | var serviceAccept serviceAcceptMsg | ||
25 | if err := Unmarshal(packet, &serviceAccept); err != nil { | ||
26 | return err | ||
27 | } | ||
28 | |||
29 | // during the authentication phase the client first attempts the "none" method | ||
30 | // then any untried methods suggested by the server. | ||
31 | tried := make(map[string]bool) | ||
32 | var lastMethods []string | ||
33 | |||
34 | sessionID := c.transport.getSessionID() | ||
35 | for auth := AuthMethod(new(noneAuth)); auth != nil; { | ||
36 | ok, methods, err := auth.auth(sessionID, config.User, c.transport, config.Rand) | ||
37 | if err != nil { | ||
38 | return err | ||
39 | } | ||
40 | if ok { | ||
41 | // success | ||
42 | return nil | ||
43 | } | ||
44 | tried[auth.method()] = true | ||
45 | if methods == nil { | ||
46 | methods = lastMethods | ||
47 | } | ||
48 | lastMethods = methods | ||
49 | |||
50 | auth = nil | ||
51 | |||
52 | findNext: | ||
53 | for _, a := range config.Auth { | ||
54 | candidateMethod := a.method() | ||
55 | if tried[candidateMethod] { | ||
56 | continue | ||
57 | } | ||
58 | for _, meth := range methods { | ||
59 | if meth == candidateMethod { | ||
60 | auth = a | ||
61 | break findNext | ||
62 | } | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | return fmt.Errorf("ssh: unable to authenticate, attempted methods %v, no supported methods remain", keys(tried)) | ||
67 | } | ||
68 | |||
69 | func keys(m map[string]bool) []string { | ||
70 | s := make([]string, 0, len(m)) | ||
71 | |||
72 | for key := range m { | ||
73 | s = append(s, key) | ||
74 | } | ||
75 | return s | ||
76 | } | ||
77 | |||
78 | // An AuthMethod represents an instance of an RFC 4252 authentication method. | ||
79 | type AuthMethod interface { | ||
80 | // auth authenticates user over transport t. | ||
81 | // Returns true if authentication is successful. | ||
82 | // If authentication is not successful, a []string of alternative | ||
83 | // method names is returned. If the slice is nil, it will be ignored | ||
84 | // and the previous set of possible methods will be reused. | ||
85 | auth(session []byte, user string, p packetConn, rand io.Reader) (bool, []string, error) | ||
86 | |||
87 | // method returns the RFC 4252 method name. | ||
88 | method() string | ||
89 | } | ||
90 | |||
91 | // "none" authentication, RFC 4252 section 5.2. | ||
92 | type noneAuth int | ||
93 | |||
94 | func (n *noneAuth) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||
95 | if err := c.writePacket(Marshal(&userAuthRequestMsg{ | ||
96 | User: user, | ||
97 | Service: serviceSSH, | ||
98 | Method: "none", | ||
99 | })); err != nil { | ||
100 | return false, nil, err | ||
101 | } | ||
102 | |||
103 | return handleAuthResponse(c) | ||
104 | } | ||
105 | |||
106 | func (n *noneAuth) method() string { | ||
107 | return "none" | ||
108 | } | ||
109 | |||
110 | // passwordCallback is an AuthMethod that fetches the password through | ||
111 | // a function call, e.g. by prompting the user. | ||
112 | type passwordCallback func() (password string, err error) | ||
113 | |||
114 | func (cb passwordCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||
115 | type passwordAuthMsg struct { | ||
116 | User string `sshtype:"50"` | ||
117 | Service string | ||
118 | Method string | ||
119 | Reply bool | ||
120 | Password string | ||
121 | } | ||
122 | |||
123 | pw, err := cb() | ||
124 | // REVIEW NOTE: is there a need to support skipping a password attempt? | ||
125 | // The program may only find out that the user doesn't have a password | ||
126 | // when prompting. | ||
127 | if err != nil { | ||
128 | return false, nil, err | ||
129 | } | ||
130 | |||
131 | if err := c.writePacket(Marshal(&passwordAuthMsg{ | ||
132 | User: user, | ||
133 | Service: serviceSSH, | ||
134 | Method: cb.method(), | ||
135 | Reply: false, | ||
136 | Password: pw, | ||
137 | })); err != nil { | ||
138 | return false, nil, err | ||
139 | } | ||
140 | |||
141 | return handleAuthResponse(c) | ||
142 | } | ||
143 | |||
144 | func (cb passwordCallback) method() string { | ||
145 | return "password" | ||
146 | } | ||
147 | |||
148 | // Password returns an AuthMethod using the given password. | ||
149 | func Password(secret string) AuthMethod { | ||
150 | return passwordCallback(func() (string, error) { return secret, nil }) | ||
151 | } | ||
152 | |||
153 | // PasswordCallback returns an AuthMethod that uses a callback for | ||
154 | // fetching a password. | ||
155 | func PasswordCallback(prompt func() (secret string, err error)) AuthMethod { | ||
156 | return passwordCallback(prompt) | ||
157 | } | ||
158 | |||
159 | type publickeyAuthMsg struct { | ||
160 | User string `sshtype:"50"` | ||
161 | Service string | ||
162 | Method string | ||
163 | // HasSig indicates to the receiver packet that the auth request is signed and | ||
164 | // should be used for authentication of the request. | ||
165 | HasSig bool | ||
166 | Algoname string | ||
167 | PubKey []byte | ||
168 | // Sig is tagged with "rest" so Marshal will exclude it during | ||
169 | // validateKey | ||
170 | Sig []byte `ssh:"rest"` | ||
171 | } | ||
172 | |||
173 | // publicKeyCallback is an AuthMethod that uses a set of key | ||
174 | // pairs for authentication. | ||
175 | type publicKeyCallback func() ([]Signer, error) | ||
176 | |||
177 | func (cb publicKeyCallback) method() string { | ||
178 | return "publickey" | ||
179 | } | ||
180 | |||
181 | func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||
182 | // Authentication is performed in two stages. The first stage sends an | ||
183 | // enquiry to test if each key is acceptable to the remote. The second | ||
184 | // stage attempts to authenticate with the valid keys obtained in the | ||
185 | // first stage. | ||
186 | |||
187 | signers, err := cb() | ||
188 | if err != nil { | ||
189 | return false, nil, err | ||
190 | } | ||
191 | var validKeys []Signer | ||
192 | for _, signer := range signers { | ||
193 | if ok, err := validateKey(signer.PublicKey(), user, c); ok { | ||
194 | validKeys = append(validKeys, signer) | ||
195 | } else { | ||
196 | if err != nil { | ||
197 | return false, nil, err | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | // methods that may continue if this auth is not successful. | ||
203 | var methods []string | ||
204 | for _, signer := range validKeys { | ||
205 | pub := signer.PublicKey() | ||
206 | |||
207 | pubKey := pub.Marshal() | ||
208 | sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{ | ||
209 | User: user, | ||
210 | Service: serviceSSH, | ||
211 | Method: cb.method(), | ||
212 | }, []byte(pub.Type()), pubKey)) | ||
213 | if err != nil { | ||
214 | return false, nil, err | ||
215 | } | ||
216 | |||
217 | // manually wrap the serialized signature in a string | ||
218 | s := Marshal(sign) | ||
219 | sig := make([]byte, stringLength(len(s))) | ||
220 | marshalString(sig, s) | ||
221 | msg := publickeyAuthMsg{ | ||
222 | User: user, | ||
223 | Service: serviceSSH, | ||
224 | Method: cb.method(), | ||
225 | HasSig: true, | ||
226 | Algoname: pub.Type(), | ||
227 | PubKey: pubKey, | ||
228 | Sig: sig, | ||
229 | } | ||
230 | p := Marshal(&msg) | ||
231 | if err := c.writePacket(p); err != nil { | ||
232 | return false, nil, err | ||
233 | } | ||
234 | var success bool | ||
235 | success, methods, err = handleAuthResponse(c) | ||
236 | if err != nil { | ||
237 | return false, nil, err | ||
238 | } | ||
239 | if success { | ||
240 | return success, methods, err | ||
241 | } | ||
242 | } | ||
243 | return false, methods, nil | ||
244 | } | ||
245 | |||
246 | // validateKey validates the key provided is acceptable to the server. | ||
247 | func validateKey(key PublicKey, user string, c packetConn) (bool, error) { | ||
248 | pubKey := key.Marshal() | ||
249 | msg := publickeyAuthMsg{ | ||
250 | User: user, | ||
251 | Service: serviceSSH, | ||
252 | Method: "publickey", | ||
253 | HasSig: false, | ||
254 | Algoname: key.Type(), | ||
255 | PubKey: pubKey, | ||
256 | } | ||
257 | if err := c.writePacket(Marshal(&msg)); err != nil { | ||
258 | return false, err | ||
259 | } | ||
260 | |||
261 | return confirmKeyAck(key, c) | ||
262 | } | ||
263 | |||
264 | func confirmKeyAck(key PublicKey, c packetConn) (bool, error) { | ||
265 | pubKey := key.Marshal() | ||
266 | algoname := key.Type() | ||
267 | |||
268 | for { | ||
269 | packet, err := c.readPacket() | ||
270 | if err != nil { | ||
271 | return false, err | ||
272 | } | ||
273 | switch packet[0] { | ||
274 | case msgUserAuthBanner: | ||
275 | // TODO(gpaul): add callback to present the banner to the user | ||
276 | case msgUserAuthPubKeyOk: | ||
277 | var msg userAuthPubKeyOkMsg | ||
278 | if err := Unmarshal(packet, &msg); err != nil { | ||
279 | return false, err | ||
280 | } | ||
281 | if msg.Algo != algoname || !bytes.Equal(msg.PubKey, pubKey) { | ||
282 | return false, nil | ||
283 | } | ||
284 | return true, nil | ||
285 | case msgUserAuthFailure: | ||
286 | return false, nil | ||
287 | default: | ||
288 | return false, unexpectedMessageError(msgUserAuthSuccess, packet[0]) | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
293 | // PublicKeys returns an AuthMethod that uses the given key | ||
294 | // pairs. | ||
295 | func PublicKeys(signers ...Signer) AuthMethod { | ||
296 | return publicKeyCallback(func() ([]Signer, error) { return signers, nil }) | ||
297 | } | ||
298 | |||
299 | // PublicKeysCallback returns an AuthMethod that runs the given | ||
300 | // function to obtain a list of key pairs. | ||
301 | func PublicKeysCallback(getSigners func() (signers []Signer, err error)) AuthMethod { | ||
302 | return publicKeyCallback(getSigners) | ||
303 | } | ||
304 | |||
305 | // handleAuthResponse returns whether the preceding authentication request succeeded | ||
306 | // along with a list of remaining authentication methods to try next and | ||
307 | // an error if an unexpected response was received. | ||
308 | func handleAuthResponse(c packetConn) (bool, []string, error) { | ||
309 | for { | ||
310 | packet, err := c.readPacket() | ||
311 | if err != nil { | ||
312 | return false, nil, err | ||
313 | } | ||
314 | |||
315 | switch packet[0] { | ||
316 | case msgUserAuthBanner: | ||
317 | // TODO: add callback to present the banner to the user | ||
318 | case msgUserAuthFailure: | ||
319 | var msg userAuthFailureMsg | ||
320 | if err := Unmarshal(packet, &msg); err != nil { | ||
321 | return false, nil, err | ||
322 | } | ||
323 | return false, msg.Methods, nil | ||
324 | case msgUserAuthSuccess: | ||
325 | return true, nil, nil | ||
326 | default: | ||
327 | return false, nil, unexpectedMessageError(msgUserAuthSuccess, packet[0]) | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | |||
332 | // KeyboardInteractiveChallenge should print questions, optionally | ||
333 | // disabling echoing (e.g. for passwords), and return all the answers. | ||
334 | // Challenge may be called multiple times in a single session. After | ||
335 | // successful authentication, the server may send a challenge with no | ||
336 | // questions, for which the user and instruction messages should be | ||
337 | // printed. RFC 4256 section 3.3 details how the UI should behave for | ||
338 | // both CLI and GUI environments. | ||
339 | type KeyboardInteractiveChallenge func(user, instruction string, questions []string, echos []bool) (answers []string, err error) | ||
340 | |||
341 | // KeyboardInteractive returns a AuthMethod using a prompt/response | ||
342 | // sequence controlled by the server. | ||
343 | func KeyboardInteractive(challenge KeyboardInteractiveChallenge) AuthMethod { | ||
344 | return challenge | ||
345 | } | ||
346 | |||
347 | func (cb KeyboardInteractiveChallenge) method() string { | ||
348 | return "keyboard-interactive" | ||
349 | } | ||
350 | |||
351 | func (cb KeyboardInteractiveChallenge) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) { | ||
352 | type initiateMsg struct { | ||
353 | User string `sshtype:"50"` | ||
354 | Service string | ||
355 | Method string | ||
356 | Language string | ||
357 | Submethods string | ||
358 | } | ||
359 | |||
360 | if err := c.writePacket(Marshal(&initiateMsg{ | ||
361 | User: user, | ||
362 | Service: serviceSSH, | ||
363 | Method: "keyboard-interactive", | ||
364 | })); err != nil { | ||
365 | return false, nil, err | ||
366 | } | ||
367 | |||
368 | for { | ||
369 | packet, err := c.readPacket() | ||
370 | if err != nil { | ||
371 | return false, nil, err | ||
372 | } | ||
373 | |||
374 | // like handleAuthResponse, but with less options. | ||
375 | switch packet[0] { | ||
376 | case msgUserAuthBanner: | ||
377 | // TODO: Print banners during userauth. | ||
378 | continue | ||
379 | case msgUserAuthInfoRequest: | ||
380 | // OK | ||
381 | case msgUserAuthFailure: | ||
382 | var msg userAuthFailureMsg | ||
383 | if err := Unmarshal(packet, &msg); err != nil { | ||
384 | return false, nil, err | ||
385 | } | ||
386 | return false, msg.Methods, nil | ||
387 | case msgUserAuthSuccess: | ||
388 | return true, nil, nil | ||
389 | default: | ||
390 | return false, nil, unexpectedMessageError(msgUserAuthInfoRequest, packet[0]) | ||
391 | } | ||
392 | |||
393 | var msg userAuthInfoRequestMsg | ||
394 | if err := Unmarshal(packet, &msg); err != nil { | ||
395 | return false, nil, err | ||
396 | } | ||
397 | |||
398 | // Manually unpack the prompt/echo pairs. | ||
399 | rest := msg.Prompts | ||
400 | var prompts []string | ||
401 | var echos []bool | ||
402 | for i := 0; i < int(msg.NumPrompts); i++ { | ||
403 | prompt, r, ok := parseString(rest) | ||
404 | if !ok || len(r) == 0 { | ||
405 | return false, nil, errors.New("ssh: prompt format error") | ||
406 | } | ||
407 | prompts = append(prompts, string(prompt)) | ||
408 | echos = append(echos, r[0] != 0) | ||
409 | rest = r[1:] | ||
410 | } | ||
411 | |||
412 | if len(rest) != 0 { | ||
413 | return false, nil, errors.New("ssh: extra data following keyboard-interactive pairs") | ||
414 | } | ||
415 | |||
416 | answers, err := cb(msg.User, msg.Instruction, prompts, echos) | ||
417 | if err != nil { | ||
418 | return false, nil, err | ||
419 | } | ||
420 | |||
421 | if len(answers) != len(prompts) { | ||
422 | return false, nil, errors.New("ssh: not enough answers from keyboard-interactive callback") | ||
423 | } | ||
424 | responseLength := 1 + 4 | ||
425 | for _, a := range answers { | ||
426 | responseLength += stringLength(len(a)) | ||
427 | } | ||
428 | serialized := make([]byte, responseLength) | ||
429 | p := serialized | ||
430 | p[0] = msgUserAuthInfoResponse | ||
431 | p = p[1:] | ||
432 | p = marshalUint32(p, uint32(len(answers))) | ||
433 | for _, a := range answers { | ||
434 | p = marshalString(p, []byte(a)) | ||
435 | } | ||
436 | |||
437 | if err := c.writePacket(serialized); err != nil { | ||
438 | return false, nil, err | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | |||
443 | type retryableAuthMethod struct { | ||
444 | authMethod AuthMethod | ||
445 | maxTries int | ||
446 | } | ||
447 | |||
448 | func (r *retryableAuthMethod) auth(session []byte, user string, c packetConn, rand io.Reader) (ok bool, methods []string, err error) { | ||
449 | for i := 0; r.maxTries <= 0 || i < r.maxTries; i++ { | ||
450 | ok, methods, err = r.authMethod.auth(session, user, c, rand) | ||
451 | if ok || err != nil { // either success or error terminate | ||
452 | return ok, methods, err | ||
453 | } | ||
454 | } | ||
455 | return ok, methods, err | ||
456 | } | ||
457 | |||
458 | func (r *retryableAuthMethod) method() string { | ||
459 | return r.authMethod.method() | ||
460 | } | ||
461 | |||
462 | // RetryableAuthMethod is a decorator for other auth methods enabling them to | ||
463 | // be retried up to maxTries before considering that AuthMethod itself failed. | ||
464 | // If maxTries is <= 0, will retry indefinitely | ||
465 | // | ||
466 | // This is useful for interactive clients using challenge/response type | ||
467 | // authentication (e.g. Keyboard-Interactive, Password, etc) where the user | ||
468 | // could mistype their response resulting in the server issuing a | ||
469 | // SSH_MSG_USERAUTH_FAILURE (rfc4252 #8 [password] and rfc4256 #3.4 | ||
470 | // [keyboard-interactive]); Without this decorator, the non-retryable | ||
471 | // AuthMethod would be removed from future consideration, and never tried again | ||
472 | // (and so the user would never be able to retry their entry). | ||
473 | func RetryableAuthMethod(auth AuthMethod, maxTries int) AuthMethod { | ||
474 | return &retryableAuthMethod{authMethod: auth, maxTries: maxTries} | ||
475 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go new file mode 100644 index 0000000..8656d0f --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/common.go | |||
@@ -0,0 +1,371 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "crypto" | ||
9 | "crypto/rand" | ||
10 | "fmt" | ||
11 | "io" | ||
12 | "sync" | ||
13 | |||
14 | _ "crypto/sha1" | ||
15 | _ "crypto/sha256" | ||
16 | _ "crypto/sha512" | ||
17 | ) | ||
18 | |||
19 | // These are string constants in the SSH protocol. | ||
20 | const ( | ||
21 | compressionNone = "none" | ||
22 | serviceUserAuth = "ssh-userauth" | ||
23 | serviceSSH = "ssh-connection" | ||
24 | ) | ||
25 | |||
26 | // supportedCiphers specifies the supported ciphers in preference order. | ||
27 | var supportedCiphers = []string{ | ||
28 | "aes128-ctr", "aes192-ctr", "aes256-ctr", | ||
29 | "aes128-gcm@openssh.com", | ||
30 | "arcfour256", "arcfour128", | ||
31 | } | ||
32 | |||
33 | // supportedKexAlgos specifies the supported key-exchange algorithms in | ||
34 | // preference order. | ||
35 | var supportedKexAlgos = []string{ | ||
36 | kexAlgoCurve25519SHA256, | ||
37 | // P384 and P521 are not constant-time yet, but since we don't | ||
38 | // reuse ephemeral keys, using them for ECDH should be OK. | ||
39 | kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, | ||
40 | kexAlgoDH14SHA1, kexAlgoDH1SHA1, | ||
41 | } | ||
42 | |||
43 | // supportedKexAlgos specifies the supported host-key algorithms (i.e. methods | ||
44 | // of authenticating servers) in preference order. | ||
45 | var supportedHostKeyAlgos = []string{ | ||
46 | CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, | ||
47 | CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01, | ||
48 | |||
49 | KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, | ||
50 | KeyAlgoRSA, KeyAlgoDSA, | ||
51 | |||
52 | KeyAlgoED25519, | ||
53 | } | ||
54 | |||
55 | // supportedMACs specifies a default set of MAC algorithms in preference order. | ||
56 | // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed | ||
57 | // because they have reached the end of their useful life. | ||
58 | var supportedMACs = []string{ | ||
59 | "hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96", | ||
60 | } | ||
61 | |||
62 | var supportedCompressions = []string{compressionNone} | ||
63 | |||
64 | // hashFuncs keeps the mapping of supported algorithms to their respective | ||
65 | // hashes needed for signature verification. | ||
66 | var hashFuncs = map[string]crypto.Hash{ | ||
67 | KeyAlgoRSA: crypto.SHA1, | ||
68 | KeyAlgoDSA: crypto.SHA1, | ||
69 | KeyAlgoECDSA256: crypto.SHA256, | ||
70 | KeyAlgoECDSA384: crypto.SHA384, | ||
71 | KeyAlgoECDSA521: crypto.SHA512, | ||
72 | CertAlgoRSAv01: crypto.SHA1, | ||
73 | CertAlgoDSAv01: crypto.SHA1, | ||
74 | CertAlgoECDSA256v01: crypto.SHA256, | ||
75 | CertAlgoECDSA384v01: crypto.SHA384, | ||
76 | CertAlgoECDSA521v01: crypto.SHA512, | ||
77 | } | ||
78 | |||
79 | // unexpectedMessageError results when the SSH message that we received didn't | ||
80 | // match what we wanted. | ||
81 | func unexpectedMessageError(expected, got uint8) error { | ||
82 | return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected) | ||
83 | } | ||
84 | |||
85 | // parseError results from a malformed SSH message. | ||
86 | func parseError(tag uint8) error { | ||
87 | return fmt.Errorf("ssh: parse error in message type %d", tag) | ||
88 | } | ||
89 | |||
90 | func findCommon(what string, client []string, server []string) (common string, err error) { | ||
91 | for _, c := range client { | ||
92 | for _, s := range server { | ||
93 | if c == s { | ||
94 | return c, nil | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | return "", fmt.Errorf("ssh: no common algorithm for %s; client offered: %v, server offered: %v", what, client, server) | ||
99 | } | ||
100 | |||
101 | type directionAlgorithms struct { | ||
102 | Cipher string | ||
103 | MAC string | ||
104 | Compression string | ||
105 | } | ||
106 | |||
107 | // rekeyBytes returns a rekeying intervals in bytes. | ||
108 | func (a *directionAlgorithms) rekeyBytes() int64 { | ||
109 | // According to RFC4344 block ciphers should rekey after | ||
110 | // 2^(BLOCKSIZE/4) blocks. For all AES flavors BLOCKSIZE is | ||
111 | // 128. | ||
112 | switch a.Cipher { | ||
113 | case "aes128-ctr", "aes192-ctr", "aes256-ctr", gcmCipherID, aes128cbcID: | ||
114 | return 16 * (1 << 32) | ||
115 | |||
116 | } | ||
117 | |||
118 | // For others, stick with RFC4253 recommendation to rekey after 1 Gb of data. | ||
119 | return 1 << 30 | ||
120 | } | ||
121 | |||
122 | type algorithms struct { | ||
123 | kex string | ||
124 | hostKey string | ||
125 | w directionAlgorithms | ||
126 | r directionAlgorithms | ||
127 | } | ||
128 | |||
129 | func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algorithms, err error) { | ||
130 | result := &algorithms{} | ||
131 | |||
132 | result.kex, err = findCommon("key exchange", clientKexInit.KexAlgos, serverKexInit.KexAlgos) | ||
133 | if err != nil { | ||
134 | return | ||
135 | } | ||
136 | |||
137 | result.hostKey, err = findCommon("host key", clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos) | ||
138 | if err != nil { | ||
139 | return | ||
140 | } | ||
141 | |||
142 | result.w.Cipher, err = findCommon("client to server cipher", clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) | ||
143 | if err != nil { | ||
144 | return | ||
145 | } | ||
146 | |||
147 | result.r.Cipher, err = findCommon("server to client cipher", clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) | ||
148 | if err != nil { | ||
149 | return | ||
150 | } | ||
151 | |||
152 | result.w.MAC, err = findCommon("client to server MAC", clientKexInit.MACsClientServer, serverKexInit.MACsClientServer) | ||
153 | if err != nil { | ||
154 | return | ||
155 | } | ||
156 | |||
157 | result.r.MAC, err = findCommon("server to client MAC", clientKexInit.MACsServerClient, serverKexInit.MACsServerClient) | ||
158 | if err != nil { | ||
159 | return | ||
160 | } | ||
161 | |||
162 | result.w.Compression, err = findCommon("client to server compression", clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer) | ||
163 | if err != nil { | ||
164 | return | ||
165 | } | ||
166 | |||
167 | result.r.Compression, err = findCommon("server to client compression", clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient) | ||
168 | if err != nil { | ||
169 | return | ||
170 | } | ||
171 | |||
172 | return result, nil | ||
173 | } | ||
174 | |||
175 | // If rekeythreshold is too small, we can't make any progress sending | ||
176 | // stuff. | ||
177 | const minRekeyThreshold uint64 = 256 | ||
178 | |||
179 | // Config contains configuration data common to both ServerConfig and | ||
180 | // ClientConfig. | ||
181 | type Config struct { | ||
182 | // Rand provides the source of entropy for cryptographic | ||
183 | // primitives. If Rand is nil, the cryptographic random reader | ||
184 | // in package crypto/rand will be used. | ||
185 | Rand io.Reader | ||
186 | |||
187 | // The maximum number of bytes sent or received after which a | ||
188 | // new key is negotiated. It must be at least 256. If | ||
189 | // unspecified, 1 gigabyte is used. | ||
190 | RekeyThreshold uint64 | ||
191 | |||
192 | // The allowed key exchanges algorithms. If unspecified then a | ||
193 | // default set of algorithms is used. | ||
194 | KeyExchanges []string | ||
195 | |||
196 | // The allowed cipher algorithms. If unspecified then a sensible | ||
197 | // default is used. | ||
198 | Ciphers []string | ||
199 | |||
200 | // The allowed MAC algorithms. If unspecified then a sensible default | ||
201 | // is used. | ||
202 | MACs []string | ||
203 | } | ||
204 | |||
205 | // SetDefaults sets sensible values for unset fields in config. This is | ||
206 | // exported for testing: Configs passed to SSH functions are copied and have | ||
207 | // default values set automatically. | ||
208 | func (c *Config) SetDefaults() { | ||
209 | if c.Rand == nil { | ||
210 | c.Rand = rand.Reader | ||
211 | } | ||
212 | if c.Ciphers == nil { | ||
213 | c.Ciphers = supportedCiphers | ||
214 | } | ||
215 | var ciphers []string | ||
216 | for _, c := range c.Ciphers { | ||
217 | if cipherModes[c] != nil { | ||
218 | // reject the cipher if we have no cipherModes definition | ||
219 | ciphers = append(ciphers, c) | ||
220 | } | ||
221 | } | ||
222 | c.Ciphers = ciphers | ||
223 | |||
224 | if c.KeyExchanges == nil { | ||
225 | c.KeyExchanges = supportedKexAlgos | ||
226 | } | ||
227 | |||
228 | if c.MACs == nil { | ||
229 | c.MACs = supportedMACs | ||
230 | } | ||
231 | |||
232 | if c.RekeyThreshold == 0 { | ||
233 | // RFC 4253, section 9 suggests rekeying after 1G. | ||
234 | c.RekeyThreshold = 1 << 30 | ||
235 | } | ||
236 | if c.RekeyThreshold < minRekeyThreshold { | ||
237 | c.RekeyThreshold = minRekeyThreshold | ||
238 | } | ||
239 | } | ||
240 | |||
241 | // buildDataSignedForAuth returns the data that is signed in order to prove | ||
242 | // possession of a private key. See RFC 4252, section 7. | ||
243 | func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte { | ||
244 | data := struct { | ||
245 | Session []byte | ||
246 | Type byte | ||
247 | User string | ||
248 | Service string | ||
249 | Method string | ||
250 | Sign bool | ||
251 | Algo []byte | ||
252 | PubKey []byte | ||
253 | }{ | ||
254 | sessionId, | ||
255 | msgUserAuthRequest, | ||
256 | req.User, | ||
257 | req.Service, | ||
258 | req.Method, | ||
259 | true, | ||
260 | algo, | ||
261 | pubKey, | ||
262 | } | ||
263 | return Marshal(data) | ||
264 | } | ||
265 | |||
266 | func appendU16(buf []byte, n uint16) []byte { | ||
267 | return append(buf, byte(n>>8), byte(n)) | ||
268 | } | ||
269 | |||
270 | func appendU32(buf []byte, n uint32) []byte { | ||
271 | return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||
272 | } | ||
273 | |||
274 | func appendU64(buf []byte, n uint64) []byte { | ||
275 | return append(buf, | ||
276 | byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), | ||
277 | byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) | ||
278 | } | ||
279 | |||
280 | func appendInt(buf []byte, n int) []byte { | ||
281 | return appendU32(buf, uint32(n)) | ||
282 | } | ||
283 | |||
284 | func appendString(buf []byte, s string) []byte { | ||
285 | buf = appendU32(buf, uint32(len(s))) | ||
286 | buf = append(buf, s...) | ||
287 | return buf | ||
288 | } | ||
289 | |||
290 | func appendBool(buf []byte, b bool) []byte { | ||
291 | if b { | ||
292 | return append(buf, 1) | ||
293 | } | ||
294 | return append(buf, 0) | ||
295 | } | ||
296 | |||
297 | // newCond is a helper to hide the fact that there is no usable zero | ||
298 | // value for sync.Cond. | ||
299 | func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } | ||
300 | |||
301 | // window represents the buffer available to clients | ||
302 | // wishing to write to a channel. | ||
303 | type window struct { | ||
304 | *sync.Cond | ||
305 | win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 | ||
306 | writeWaiters int | ||
307 | closed bool | ||
308 | } | ||
309 | |||
310 | // add adds win to the amount of window available | ||
311 | // for consumers. | ||
312 | func (w *window) add(win uint32) bool { | ||
313 | // a zero sized window adjust is a noop. | ||
314 | if win == 0 { | ||
315 | return true | ||
316 | } | ||
317 | w.L.Lock() | ||
318 | if w.win+win < win { | ||
319 | w.L.Unlock() | ||
320 | return false | ||
321 | } | ||
322 | w.win += win | ||
323 | // It is unusual that multiple goroutines would be attempting to reserve | ||
324 | // window space, but not guaranteed. Use broadcast to notify all waiters | ||
325 | // that additional window is available. | ||
326 | w.Broadcast() | ||
327 | w.L.Unlock() | ||
328 | return true | ||
329 | } | ||
330 | |||
331 | // close sets the window to closed, so all reservations fail | ||
332 | // immediately. | ||
333 | func (w *window) close() { | ||
334 | w.L.Lock() | ||
335 | w.closed = true | ||
336 | w.Broadcast() | ||
337 | w.L.Unlock() | ||
338 | } | ||
339 | |||
340 | // reserve reserves win from the available window capacity. | ||
341 | // If no capacity remains, reserve will block. reserve may | ||
342 | // return less than requested. | ||
343 | func (w *window) reserve(win uint32) (uint32, error) { | ||
344 | var err error | ||
345 | w.L.Lock() | ||
346 | w.writeWaiters++ | ||
347 | w.Broadcast() | ||
348 | for w.win == 0 && !w.closed { | ||
349 | w.Wait() | ||
350 | } | ||
351 | w.writeWaiters-- | ||
352 | if w.win < win { | ||
353 | win = w.win | ||
354 | } | ||
355 | w.win -= win | ||
356 | if w.closed { | ||
357 | err = io.EOF | ||
358 | } | ||
359 | w.L.Unlock() | ||
360 | return win, err | ||
361 | } | ||
362 | |||
363 | // waitWriterBlocked waits until some goroutine is blocked for further | ||
364 | // writes. It is used in tests only. | ||
365 | func (w *window) waitWriterBlocked() { | ||
366 | w.Cond.L.Lock() | ||
367 | for w.writeWaiters == 0 { | ||
368 | w.Cond.Wait() | ||
369 | } | ||
370 | w.Cond.L.Unlock() | ||
371 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/connection.go b/vendor/golang.org/x/crypto/ssh/connection.go new file mode 100644 index 0000000..e786f2f --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/connection.go | |||
@@ -0,0 +1,143 @@ | |||
1 | // Copyright 2013 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "fmt" | ||
9 | "net" | ||
10 | ) | ||
11 | |||
12 | // OpenChannelError is returned if the other side rejects an | ||
13 | // OpenChannel request. | ||
14 | type OpenChannelError struct { | ||
15 | Reason RejectionReason | ||
16 | Message string | ||
17 | } | ||
18 | |||
19 | func (e *OpenChannelError) Error() string { | ||
20 | return fmt.Sprintf("ssh: rejected: %s (%s)", e.Reason, e.Message) | ||
21 | } | ||
22 | |||
23 | // ConnMetadata holds metadata for the connection. | ||
24 | type ConnMetadata interface { | ||
25 | // User returns the user ID for this connection. | ||
26 | User() string | ||
27 | |||
28 | // SessionID returns the sesson hash, also denoted by H. | ||
29 | SessionID() []byte | ||
30 | |||
31 | // ClientVersion returns the client's version string as hashed | ||
32 | // into the session ID. | ||
33 | ClientVersion() []byte | ||
34 | |||
35 | // ServerVersion returns the server's version string as hashed | ||
36 | // into the session ID. | ||
37 | ServerVersion() []byte | ||
38 | |||
39 | // RemoteAddr returns the remote address for this connection. | ||
40 | RemoteAddr() net.Addr | ||
41 | |||
42 | // LocalAddr returns the local address for this connection. | ||
43 | LocalAddr() net.Addr | ||
44 | } | ||
45 | |||
46 | // Conn represents an SSH connection for both server and client roles. | ||
47 | // Conn is the basis for implementing an application layer, such | ||
48 | // as ClientConn, which implements the traditional shell access for | ||
49 | // clients. | ||
50 | type Conn interface { | ||
51 | ConnMetadata | ||
52 | |||
53 | // SendRequest sends a global request, and returns the | ||
54 | // reply. If wantReply is true, it returns the response status | ||
55 | // and payload. See also RFC4254, section 4. | ||
56 | SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) | ||
57 | |||
58 | // OpenChannel tries to open an channel. If the request is | ||
59 | // rejected, it returns *OpenChannelError. On success it returns | ||
60 | // the SSH Channel and a Go channel for incoming, out-of-band | ||
61 | // requests. The Go channel must be serviced, or the | ||
62 | // connection will hang. | ||
63 | OpenChannel(name string, data []byte) (Channel, <-chan *Request, error) | ||
64 | |||
65 | // Close closes the underlying network connection | ||
66 | Close() error | ||
67 | |||
68 | // Wait blocks until the connection has shut down, and returns the | ||
69 | // error causing the shutdown. | ||
70 | Wait() error | ||
71 | |||
72 | // TODO(hanwen): consider exposing: | ||
73 | // RequestKeyChange | ||
74 | // Disconnect | ||
75 | } | ||
76 | |||
77 | // DiscardRequests consumes and rejects all requests from the | ||
78 | // passed-in channel. | ||
79 | func DiscardRequests(in <-chan *Request) { | ||
80 | for req := range in { | ||
81 | if req.WantReply { | ||
82 | req.Reply(false, nil) | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | // A connection represents an incoming connection. | ||
88 | type connection struct { | ||
89 | transport *handshakeTransport | ||
90 | sshConn | ||
91 | |||
92 | // The connection protocol. | ||
93 | *mux | ||
94 | } | ||
95 | |||
96 | func (c *connection) Close() error { | ||
97 | return c.sshConn.conn.Close() | ||
98 | } | ||
99 | |||
100 | // sshconn provides net.Conn metadata, but disallows direct reads and | ||
101 | // writes. | ||
102 | type sshConn struct { | ||
103 | conn net.Conn | ||
104 | |||
105 | user string | ||
106 | sessionID []byte | ||
107 | clientVersion []byte | ||
108 | serverVersion []byte | ||
109 | } | ||
110 | |||
111 | func dup(src []byte) []byte { | ||
112 | dst := make([]byte, len(src)) | ||
113 | copy(dst, src) | ||
114 | return dst | ||
115 | } | ||
116 | |||
117 | func (c *sshConn) User() string { | ||
118 | return c.user | ||
119 | } | ||
120 | |||
121 | func (c *sshConn) RemoteAddr() net.Addr { | ||
122 | return c.conn.RemoteAddr() | ||
123 | } | ||
124 | |||
125 | func (c *sshConn) Close() error { | ||
126 | return c.conn.Close() | ||
127 | } | ||
128 | |||
129 | func (c *sshConn) LocalAddr() net.Addr { | ||
130 | return c.conn.LocalAddr() | ||
131 | } | ||
132 | |||
133 | func (c *sshConn) SessionID() []byte { | ||
134 | return dup(c.sessionID) | ||
135 | } | ||
136 | |||
137 | func (c *sshConn) ClientVersion() []byte { | ||
138 | return dup(c.clientVersion) | ||
139 | } | ||
140 | |||
141 | func (c *sshConn) ServerVersion() []byte { | ||
142 | return dup(c.serverVersion) | ||
143 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go new file mode 100644 index 0000000..d6be894 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/doc.go | |||
@@ -0,0 +1,18 @@ | |||
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 | |||
5 | /* | ||
6 | Package ssh implements an SSH client and server. | ||
7 | |||
8 | SSH is a transport security protocol, an authentication protocol and a | ||
9 | family of application protocols. The most typical application level | ||
10 | protocol is a remote shell and this is specifically implemented. However, | ||
11 | the multiplexed nature of SSH is exposed to users that wish to support | ||
12 | others. | ||
13 | |||
14 | References: | ||
15 | [PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD | ||
16 | [SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1 | ||
17 | */ | ||
18 | package ssh // import "golang.org/x/crypto/ssh" | ||
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go new file mode 100644 index 0000000..8de6506 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/handshake.go | |||
@@ -0,0 +1,625 @@ | |||
1 | // Copyright 2013 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "crypto/rand" | ||
9 | "errors" | ||
10 | "fmt" | ||
11 | "io" | ||
12 | "log" | ||
13 | "net" | ||
14 | "sync" | ||
15 | ) | ||
16 | |||
17 | // debugHandshake, if set, prints messages sent and received. Key | ||
18 | // exchange messages are printed as if DH were used, so the debug | ||
19 | // messages are wrong when using ECDH. | ||
20 | const debugHandshake = false | ||
21 | |||
22 | // chanSize sets the amount of buffering SSH connections. This is | ||
23 | // primarily for testing: setting chanSize=0 uncovers deadlocks more | ||
24 | // quickly. | ||
25 | const chanSize = 16 | ||
26 | |||
27 | // keyingTransport is a packet based transport that supports key | ||
28 | // changes. It need not be thread-safe. It should pass through | ||
29 | // msgNewKeys in both directions. | ||
30 | type keyingTransport interface { | ||
31 | packetConn | ||
32 | |||
33 | // prepareKeyChange sets up a key change. The key change for a | ||
34 | // direction will be effected if a msgNewKeys message is sent | ||
35 | // or received. | ||
36 | prepareKeyChange(*algorithms, *kexResult) error | ||
37 | } | ||
38 | |||
39 | // handshakeTransport implements rekeying on top of a keyingTransport | ||
40 | // and offers a thread-safe writePacket() interface. | ||
41 | type handshakeTransport struct { | ||
42 | conn keyingTransport | ||
43 | config *Config | ||
44 | |||
45 | serverVersion []byte | ||
46 | clientVersion []byte | ||
47 | |||
48 | // hostKeys is non-empty if we are the server. In that case, | ||
49 | // it contains all host keys that can be used to sign the | ||
50 | // connection. | ||
51 | hostKeys []Signer | ||
52 | |||
53 | // hostKeyAlgorithms is non-empty if we are the client. In that case, | ||
54 | // we accept these key types from the server as host key. | ||
55 | hostKeyAlgorithms []string | ||
56 | |||
57 | // On read error, incoming is closed, and readError is set. | ||
58 | incoming chan []byte | ||
59 | readError error | ||
60 | |||
61 | mu sync.Mutex | ||
62 | writeError error | ||
63 | sentInitPacket []byte | ||
64 | sentInitMsg *kexInitMsg | ||
65 | pendingPackets [][]byte // Used when a key exchange is in progress. | ||
66 | |||
67 | // If the read loop wants to schedule a kex, it pings this | ||
68 | // channel, and the write loop will send out a kex | ||
69 | // message. | ||
70 | requestKex chan struct{} | ||
71 | |||
72 | // If the other side requests or confirms a kex, its kexInit | ||
73 | // packet is sent here for the write loop to find it. | ||
74 | startKex chan *pendingKex | ||
75 | |||
76 | // data for host key checking | ||
77 | hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error | ||
78 | dialAddress string | ||
79 | remoteAddr net.Addr | ||
80 | |||
81 | // Algorithms agreed in the last key exchange. | ||
82 | algorithms *algorithms | ||
83 | |||
84 | readPacketsLeft uint32 | ||
85 | readBytesLeft int64 | ||
86 | |||
87 | writePacketsLeft uint32 | ||
88 | writeBytesLeft int64 | ||
89 | |||
90 | // The session ID or nil if first kex did not complete yet. | ||
91 | sessionID []byte | ||
92 | } | ||
93 | |||
94 | type pendingKex struct { | ||
95 | otherInit []byte | ||
96 | done chan error | ||
97 | } | ||
98 | |||
99 | func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion, serverVersion []byte) *handshakeTransport { | ||
100 | t := &handshakeTransport{ | ||
101 | conn: conn, | ||
102 | serverVersion: serverVersion, | ||
103 | clientVersion: clientVersion, | ||
104 | incoming: make(chan []byte, chanSize), | ||
105 | requestKex: make(chan struct{}, 1), | ||
106 | startKex: make(chan *pendingKex, 1), | ||
107 | |||
108 | config: config, | ||
109 | } | ||
110 | |||
111 | // We always start with a mandatory key exchange. | ||
112 | t.requestKex <- struct{}{} | ||
113 | return t | ||
114 | } | ||
115 | |||
116 | func newClientTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ClientConfig, dialAddr string, addr net.Addr) *handshakeTransport { | ||
117 | t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) | ||
118 | t.dialAddress = dialAddr | ||
119 | t.remoteAddr = addr | ||
120 | t.hostKeyCallback = config.HostKeyCallback | ||
121 | if config.HostKeyAlgorithms != nil { | ||
122 | t.hostKeyAlgorithms = config.HostKeyAlgorithms | ||
123 | } else { | ||
124 | t.hostKeyAlgorithms = supportedHostKeyAlgos | ||
125 | } | ||
126 | go t.readLoop() | ||
127 | go t.kexLoop() | ||
128 | return t | ||
129 | } | ||
130 | |||
131 | func newServerTransport(conn keyingTransport, clientVersion, serverVersion []byte, config *ServerConfig) *handshakeTransport { | ||
132 | t := newHandshakeTransport(conn, &config.Config, clientVersion, serverVersion) | ||
133 | t.hostKeys = config.hostKeys | ||
134 | go t.readLoop() | ||
135 | go t.kexLoop() | ||
136 | return t | ||
137 | } | ||
138 | |||
139 | func (t *handshakeTransport) getSessionID() []byte { | ||
140 | return t.sessionID | ||
141 | } | ||
142 | |||
143 | // waitSession waits for the session to be established. This should be | ||
144 | // the first thing to call after instantiating handshakeTransport. | ||
145 | func (t *handshakeTransport) waitSession() error { | ||
146 | p, err := t.readPacket() | ||
147 | if err != nil { | ||
148 | return err | ||
149 | } | ||
150 | if p[0] != msgNewKeys { | ||
151 | return fmt.Errorf("ssh: first packet should be msgNewKeys") | ||
152 | } | ||
153 | |||
154 | return nil | ||
155 | } | ||
156 | |||
157 | func (t *handshakeTransport) id() string { | ||
158 | if len(t.hostKeys) > 0 { | ||
159 | return "server" | ||
160 | } | ||
161 | return "client" | ||
162 | } | ||
163 | |||
164 | func (t *handshakeTransport) printPacket(p []byte, write bool) { | ||
165 | action := "got" | ||
166 | if write { | ||
167 | action = "sent" | ||
168 | } | ||
169 | |||
170 | if p[0] == msgChannelData || p[0] == msgChannelExtendedData { | ||
171 | log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p)) | ||
172 | } else { | ||
173 | msg, err := decode(p) | ||
174 | log.Printf("%s %s %T %v (%v)", t.id(), action, msg, msg, err) | ||
175 | } | ||
176 | } | ||
177 | |||
178 | func (t *handshakeTransport) readPacket() ([]byte, error) { | ||
179 | p, ok := <-t.incoming | ||
180 | if !ok { | ||
181 | return nil, t.readError | ||
182 | } | ||
183 | return p, nil | ||
184 | } | ||
185 | |||
186 | func (t *handshakeTransport) readLoop() { | ||
187 | first := true | ||
188 | for { | ||
189 | p, err := t.readOnePacket(first) | ||
190 | first = false | ||
191 | if err != nil { | ||
192 | t.readError = err | ||
193 | close(t.incoming) | ||
194 | break | ||
195 | } | ||
196 | if p[0] == msgIgnore || p[0] == msgDebug { | ||
197 | continue | ||
198 | } | ||
199 | t.incoming <- p | ||
200 | } | ||
201 | |||
202 | // Stop writers too. | ||
203 | t.recordWriteError(t.readError) | ||
204 | |||
205 | // Unblock the writer should it wait for this. | ||
206 | close(t.startKex) | ||
207 | |||
208 | // Don't close t.requestKex; it's also written to from writePacket. | ||
209 | } | ||
210 | |||
211 | func (t *handshakeTransport) pushPacket(p []byte) error { | ||
212 | if debugHandshake { | ||
213 | t.printPacket(p, true) | ||
214 | } | ||
215 | return t.conn.writePacket(p) | ||
216 | } | ||
217 | |||
218 | func (t *handshakeTransport) getWriteError() error { | ||
219 | t.mu.Lock() | ||
220 | defer t.mu.Unlock() | ||
221 | return t.writeError | ||
222 | } | ||
223 | |||
224 | func (t *handshakeTransport) recordWriteError(err error) { | ||
225 | t.mu.Lock() | ||
226 | defer t.mu.Unlock() | ||
227 | if t.writeError == nil && err != nil { | ||
228 | t.writeError = err | ||
229 | } | ||
230 | } | ||
231 | |||
232 | func (t *handshakeTransport) requestKeyExchange() { | ||
233 | select { | ||
234 | case t.requestKex <- struct{}{}: | ||
235 | default: | ||
236 | // something already requested a kex, so do nothing. | ||
237 | } | ||
238 | } | ||
239 | |||
240 | func (t *handshakeTransport) kexLoop() { | ||
241 | |||
242 | write: | ||
243 | for t.getWriteError() == nil { | ||
244 | var request *pendingKex | ||
245 | var sent bool | ||
246 | |||
247 | for request == nil || !sent { | ||
248 | var ok bool | ||
249 | select { | ||
250 | case request, ok = <-t.startKex: | ||
251 | if !ok { | ||
252 | break write | ||
253 | } | ||
254 | case <-t.requestKex: | ||
255 | break | ||
256 | } | ||
257 | |||
258 | if !sent { | ||
259 | if err := t.sendKexInit(); err != nil { | ||
260 | t.recordWriteError(err) | ||
261 | break | ||
262 | } | ||
263 | sent = true | ||
264 | } | ||
265 | } | ||
266 | |||
267 | if err := t.getWriteError(); err != nil { | ||
268 | if request != nil { | ||
269 | request.done <- err | ||
270 | } | ||
271 | break | ||
272 | } | ||
273 | |||
274 | // We're not servicing t.requestKex, but that is OK: | ||
275 | // we never block on sending to t.requestKex. | ||
276 | |||
277 | // We're not servicing t.startKex, but the remote end | ||
278 | // has just sent us a kexInitMsg, so it can't send | ||
279 | // another key change request, until we close the done | ||
280 | // channel on the pendingKex request. | ||
281 | |||
282 | err := t.enterKeyExchange(request.otherInit) | ||
283 | |||
284 | t.mu.Lock() | ||
285 | t.writeError = err | ||
286 | t.sentInitPacket = nil | ||
287 | t.sentInitMsg = nil | ||
288 | t.writePacketsLeft = packetRekeyThreshold | ||
289 | if t.config.RekeyThreshold > 0 { | ||
290 | t.writeBytesLeft = int64(t.config.RekeyThreshold) | ||
291 | } else if t.algorithms != nil { | ||
292 | t.writeBytesLeft = t.algorithms.w.rekeyBytes() | ||
293 | } | ||
294 | |||
295 | // we have completed the key exchange. Since the | ||
296 | // reader is still blocked, it is safe to clear out | ||
297 | // the requestKex channel. This avoids the situation | ||
298 | // where: 1) we consumed our own request for the | ||
299 | // initial kex, and 2) the kex from the remote side | ||
300 | // caused another send on the requestKex channel, | ||
301 | clear: | ||
302 | for { | ||
303 | select { | ||
304 | case <-t.requestKex: | ||
305 | // | ||
306 | default: | ||
307 | break clear | ||
308 | } | ||
309 | } | ||
310 | |||
311 | request.done <- t.writeError | ||
312 | |||
313 | // kex finished. Push packets that we received while | ||
314 | // the kex was in progress. Don't look at t.startKex | ||
315 | // and don't increment writtenSinceKex: if we trigger | ||
316 | // another kex while we are still busy with the last | ||
317 | // one, things will become very confusing. | ||
318 | for _, p := range t.pendingPackets { | ||
319 | t.writeError = t.pushPacket(p) | ||
320 | if t.writeError != nil { | ||
321 | break | ||
322 | } | ||
323 | } | ||
324 | t.pendingPackets = t.pendingPackets[:0] | ||
325 | t.mu.Unlock() | ||
326 | } | ||
327 | |||
328 | // drain startKex channel. We don't service t.requestKex | ||
329 | // because nobody does blocking sends there. | ||
330 | go func() { | ||
331 | for init := range t.startKex { | ||
332 | init.done <- t.writeError | ||
333 | } | ||
334 | }() | ||
335 | |||
336 | // Unblock reader. | ||
337 | t.conn.Close() | ||
338 | } | ||
339 | |||
340 | // The protocol uses uint32 for packet counters, so we can't let them | ||
341 | // reach 1<<32. We will actually read and write more packets than | ||
342 | // this, though: the other side may send more packets, and after we | ||
343 | // hit this limit on writing we will send a few more packets for the | ||
344 | // key exchange itself. | ||
345 | const packetRekeyThreshold = (1 << 31) | ||
346 | |||
347 | func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) { | ||
348 | p, err := t.conn.readPacket() | ||
349 | if err != nil { | ||
350 | return nil, err | ||
351 | } | ||
352 | |||
353 | if t.readPacketsLeft > 0 { | ||
354 | t.readPacketsLeft-- | ||
355 | } else { | ||
356 | t.requestKeyExchange() | ||
357 | } | ||
358 | |||
359 | if t.readBytesLeft > 0 { | ||
360 | t.readBytesLeft -= int64(len(p)) | ||
361 | } else { | ||
362 | t.requestKeyExchange() | ||
363 | } | ||
364 | |||
365 | if debugHandshake { | ||
366 | t.printPacket(p, false) | ||
367 | } | ||
368 | |||
369 | if first && p[0] != msgKexInit { | ||
370 | return nil, fmt.Errorf("ssh: first packet should be msgKexInit") | ||
371 | } | ||
372 | |||
373 | if p[0] != msgKexInit { | ||
374 | return p, nil | ||
375 | } | ||
376 | |||
377 | firstKex := t.sessionID == nil | ||
378 | |||
379 | kex := pendingKex{ | ||
380 | done: make(chan error, 1), | ||
381 | otherInit: p, | ||
382 | } | ||
383 | t.startKex <- &kex | ||
384 | err = <-kex.done | ||
385 | |||
386 | if debugHandshake { | ||
387 | log.Printf("%s exited key exchange (first %v), err %v", t.id(), firstKex, err) | ||
388 | } | ||
389 | |||
390 | if err != nil { | ||
391 | return nil, err | ||
392 | } | ||
393 | |||
394 | t.readPacketsLeft = packetRekeyThreshold | ||
395 | if t.config.RekeyThreshold > 0 { | ||
396 | t.readBytesLeft = int64(t.config.RekeyThreshold) | ||
397 | } else { | ||
398 | t.readBytesLeft = t.algorithms.r.rekeyBytes() | ||
399 | } | ||
400 | |||
401 | // By default, a key exchange is hidden from higher layers by | ||
402 | // translating it into msgIgnore. | ||
403 | successPacket := []byte{msgIgnore} | ||
404 | if firstKex { | ||
405 | // sendKexInit() for the first kex waits for | ||
406 | // msgNewKeys so the authentication process is | ||
407 | // guaranteed to happen over an encrypted transport. | ||
408 | successPacket = []byte{msgNewKeys} | ||
409 | } | ||
410 | |||
411 | return successPacket, nil | ||
412 | } | ||
413 | |||
414 | // sendKexInit sends a key change message. | ||
415 | func (t *handshakeTransport) sendKexInit() error { | ||
416 | t.mu.Lock() | ||
417 | defer t.mu.Unlock() | ||
418 | if t.sentInitMsg != nil { | ||
419 | // kexInits may be sent either in response to the other side, | ||
420 | // or because our side wants to initiate a key change, so we | ||
421 | // may have already sent a kexInit. In that case, don't send a | ||
422 | // second kexInit. | ||
423 | return nil | ||
424 | } | ||
425 | |||
426 | msg := &kexInitMsg{ | ||
427 | KexAlgos: t.config.KeyExchanges, | ||
428 | CiphersClientServer: t.config.Ciphers, | ||
429 | CiphersServerClient: t.config.Ciphers, | ||
430 | MACsClientServer: t.config.MACs, | ||
431 | MACsServerClient: t.config.MACs, | ||
432 | CompressionClientServer: supportedCompressions, | ||
433 | CompressionServerClient: supportedCompressions, | ||
434 | } | ||
435 | io.ReadFull(rand.Reader, msg.Cookie[:]) | ||
436 | |||
437 | if len(t.hostKeys) > 0 { | ||
438 | for _, k := range t.hostKeys { | ||
439 | msg.ServerHostKeyAlgos = append( | ||
440 | msg.ServerHostKeyAlgos, k.PublicKey().Type()) | ||
441 | } | ||
442 | } else { | ||
443 | msg.ServerHostKeyAlgos = t.hostKeyAlgorithms | ||
444 | } | ||
445 | packet := Marshal(msg) | ||
446 | |||
447 | // writePacket destroys the contents, so save a copy. | ||
448 | packetCopy := make([]byte, len(packet)) | ||
449 | copy(packetCopy, packet) | ||
450 | |||
451 | if err := t.pushPacket(packetCopy); err != nil { | ||
452 | return err | ||
453 | } | ||
454 | |||
455 | t.sentInitMsg = msg | ||
456 | t.sentInitPacket = packet | ||
457 | |||
458 | return nil | ||
459 | } | ||
460 | |||
461 | func (t *handshakeTransport) writePacket(p []byte) error { | ||
462 | switch p[0] { | ||
463 | case msgKexInit: | ||
464 | return errors.New("ssh: only handshakeTransport can send kexInit") | ||
465 | case msgNewKeys: | ||
466 | return errors.New("ssh: only handshakeTransport can send newKeys") | ||
467 | } | ||
468 | |||
469 | t.mu.Lock() | ||
470 | defer t.mu.Unlock() | ||
471 | if t.writeError != nil { | ||
472 | return t.writeError | ||
473 | } | ||
474 | |||
475 | if t.sentInitMsg != nil { | ||
476 | // Copy the packet so the writer can reuse the buffer. | ||
477 | cp := make([]byte, len(p)) | ||
478 | copy(cp, p) | ||
479 | t.pendingPackets = append(t.pendingPackets, cp) | ||
480 | return nil | ||
481 | } | ||
482 | |||
483 | if t.writeBytesLeft > 0 { | ||
484 | t.writeBytesLeft -= int64(len(p)) | ||
485 | } else { | ||
486 | t.requestKeyExchange() | ||
487 | } | ||
488 | |||
489 | if t.writePacketsLeft > 0 { | ||
490 | t.writePacketsLeft-- | ||
491 | } else { | ||
492 | t.requestKeyExchange() | ||
493 | } | ||
494 | |||
495 | if err := t.pushPacket(p); err != nil { | ||
496 | t.writeError = err | ||
497 | } | ||
498 | |||
499 | return nil | ||
500 | } | ||
501 | |||
502 | func (t *handshakeTransport) Close() error { | ||
503 | return t.conn.Close() | ||
504 | } | ||
505 | |||
506 | func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error { | ||
507 | if debugHandshake { | ||
508 | log.Printf("%s entered key exchange", t.id()) | ||
509 | } | ||
510 | |||
511 | otherInit := &kexInitMsg{} | ||
512 | if err := Unmarshal(otherInitPacket, otherInit); err != nil { | ||
513 | return err | ||
514 | } | ||
515 | |||
516 | magics := handshakeMagics{ | ||
517 | clientVersion: t.clientVersion, | ||
518 | serverVersion: t.serverVersion, | ||
519 | clientKexInit: otherInitPacket, | ||
520 | serverKexInit: t.sentInitPacket, | ||
521 | } | ||
522 | |||
523 | clientInit := otherInit | ||
524 | serverInit := t.sentInitMsg | ||
525 | if len(t.hostKeys) == 0 { | ||
526 | clientInit, serverInit = serverInit, clientInit | ||
527 | |||
528 | magics.clientKexInit = t.sentInitPacket | ||
529 | magics.serverKexInit = otherInitPacket | ||
530 | } | ||
531 | |||
532 | var err error | ||
533 | t.algorithms, err = findAgreedAlgorithms(clientInit, serverInit) | ||
534 | if err != nil { | ||
535 | return err | ||
536 | } | ||
537 | |||
538 | // We don't send FirstKexFollows, but we handle receiving it. | ||
539 | // | ||
540 | // RFC 4253 section 7 defines the kex and the agreement method for | ||
541 | // first_kex_packet_follows. It states that the guessed packet | ||
542 | // should be ignored if the "kex algorithm and/or the host | ||
543 | // key algorithm is guessed wrong (server and client have | ||
544 | // different preferred algorithm), or if any of the other | ||
545 | // algorithms cannot be agreed upon". The other algorithms have | ||
546 | // already been checked above so the kex algorithm and host key | ||
547 | // algorithm are checked here. | ||
548 | if otherInit.FirstKexFollows && (clientInit.KexAlgos[0] != serverInit.KexAlgos[0] || clientInit.ServerHostKeyAlgos[0] != serverInit.ServerHostKeyAlgos[0]) { | ||
549 | // other side sent a kex message for the wrong algorithm, | ||
550 | // which we have to ignore. | ||
551 | if _, err := t.conn.readPacket(); err != nil { | ||
552 | return err | ||
553 | } | ||
554 | } | ||
555 | |||
556 | kex, ok := kexAlgoMap[t.algorithms.kex] | ||
557 | if !ok { | ||
558 | return fmt.Errorf("ssh: unexpected key exchange algorithm %v", t.algorithms.kex) | ||
559 | } | ||
560 | |||
561 | var result *kexResult | ||
562 | if len(t.hostKeys) > 0 { | ||
563 | result, err = t.server(kex, t.algorithms, &magics) | ||
564 | } else { | ||
565 | result, err = t.client(kex, t.algorithms, &magics) | ||
566 | } | ||
567 | |||
568 | if err != nil { | ||
569 | return err | ||
570 | } | ||
571 | |||
572 | if t.sessionID == nil { | ||
573 | t.sessionID = result.H | ||
574 | } | ||
575 | result.SessionID = t.sessionID | ||
576 | |||
577 | t.conn.prepareKeyChange(t.algorithms, result) | ||
578 | if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil { | ||
579 | return err | ||
580 | } | ||
581 | if packet, err := t.conn.readPacket(); err != nil { | ||
582 | return err | ||
583 | } else if packet[0] != msgNewKeys { | ||
584 | return unexpectedMessageError(msgNewKeys, packet[0]) | ||
585 | } | ||
586 | |||
587 | return nil | ||
588 | } | ||
589 | |||
590 | func (t *handshakeTransport) server(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | ||
591 | var hostKey Signer | ||
592 | for _, k := range t.hostKeys { | ||
593 | if algs.hostKey == k.PublicKey().Type() { | ||
594 | hostKey = k | ||
595 | } | ||
596 | } | ||
597 | |||
598 | r, err := kex.Server(t.conn, t.config.Rand, magics, hostKey) | ||
599 | return r, err | ||
600 | } | ||
601 | |||
602 | func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *handshakeMagics) (*kexResult, error) { | ||
603 | result, err := kex.Client(t.conn, t.config.Rand, magics) | ||
604 | if err != nil { | ||
605 | return nil, err | ||
606 | } | ||
607 | |||
608 | hostKey, err := ParsePublicKey(result.HostKey) | ||
609 | if err != nil { | ||
610 | return nil, err | ||
611 | } | ||
612 | |||
613 | if err := verifyHostKeySignature(hostKey, result); err != nil { | ||
614 | return nil, err | ||
615 | } | ||
616 | |||
617 | if t.hostKeyCallback != nil { | ||
618 | err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey) | ||
619 | if err != nil { | ||
620 | return nil, err | ||
621 | } | ||
622 | } | ||
623 | |||
624 | return result, nil | ||
625 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/kex.go b/vendor/golang.org/x/crypto/ssh/kex.go new file mode 100644 index 0000000..c87fbeb --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/kex.go | |||
@@ -0,0 +1,540 @@ | |||
1 | // Copyright 2013 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "crypto" | ||
9 | "crypto/ecdsa" | ||
10 | "crypto/elliptic" | ||
11 | "crypto/rand" | ||
12 | "crypto/subtle" | ||
13 | "errors" | ||
14 | "io" | ||
15 | "math/big" | ||
16 | |||
17 | "golang.org/x/crypto/curve25519" | ||
18 | ) | ||
19 | |||
20 | const ( | ||
21 | kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1" | ||
22 | kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1" | ||
23 | kexAlgoECDH256 = "ecdh-sha2-nistp256" | ||
24 | kexAlgoECDH384 = "ecdh-sha2-nistp384" | ||
25 | kexAlgoECDH521 = "ecdh-sha2-nistp521" | ||
26 | kexAlgoCurve25519SHA256 = "curve25519-sha256@libssh.org" | ||
27 | ) | ||
28 | |||
29 | // kexResult captures the outcome of a key exchange. | ||
30 | type kexResult struct { | ||
31 | // Session hash. See also RFC 4253, section 8. | ||
32 | H []byte | ||
33 | |||
34 | // Shared secret. See also RFC 4253, section 8. | ||
35 | K []byte | ||
36 | |||
37 | // Host key as hashed into H. | ||
38 | HostKey []byte | ||
39 | |||
40 | // Signature of H. | ||
41 | Signature []byte | ||
42 | |||
43 | // A cryptographic hash function that matches the security | ||
44 | // level of the key exchange algorithm. It is used for | ||
45 | // calculating H, and for deriving keys from H and K. | ||
46 | Hash crypto.Hash | ||
47 | |||
48 | // The session ID, which is the first H computed. This is used | ||
49 | // to derive key material inside the transport. | ||
50 | SessionID []byte | ||
51 | } | ||
52 | |||
53 | // handshakeMagics contains data that is always included in the | ||
54 | // session hash. | ||
55 | type handshakeMagics struct { | ||
56 | clientVersion, serverVersion []byte | ||
57 | clientKexInit, serverKexInit []byte | ||
58 | } | ||
59 | |||
60 | func (m *handshakeMagics) write(w io.Writer) { | ||
61 | writeString(w, m.clientVersion) | ||
62 | writeString(w, m.serverVersion) | ||
63 | writeString(w, m.clientKexInit) | ||
64 | writeString(w, m.serverKexInit) | ||
65 | } | ||
66 | |||
67 | // kexAlgorithm abstracts different key exchange algorithms. | ||
68 | type kexAlgorithm interface { | ||
69 | // Server runs server-side key agreement, signing the result | ||
70 | // with a hostkey. | ||
71 | Server(p packetConn, rand io.Reader, magics *handshakeMagics, s Signer) (*kexResult, error) | ||
72 | |||
73 | // Client runs the client-side key agreement. Caller is | ||
74 | // responsible for verifying the host key signature. | ||
75 | Client(p packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) | ||
76 | } | ||
77 | |||
78 | // dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement. | ||
79 | type dhGroup struct { | ||
80 | g, p, pMinus1 *big.Int | ||
81 | } | ||
82 | |||
83 | func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) { | ||
84 | if theirPublic.Cmp(bigOne) <= 0 || theirPublic.Cmp(group.pMinus1) >= 0 { | ||
85 | return nil, errors.New("ssh: DH parameter out of bounds") | ||
86 | } | ||
87 | return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil | ||
88 | } | ||
89 | |||
90 | func (group *dhGroup) Client(c packetConn, randSource io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||
91 | hashFunc := crypto.SHA1 | ||
92 | |||
93 | var x *big.Int | ||
94 | for { | ||
95 | var err error | ||
96 | if x, err = rand.Int(randSource, group.pMinus1); err != nil { | ||
97 | return nil, err | ||
98 | } | ||
99 | if x.Sign() > 0 { | ||
100 | break | ||
101 | } | ||
102 | } | ||
103 | |||
104 | X := new(big.Int).Exp(group.g, x, group.p) | ||
105 | kexDHInit := kexDHInitMsg{ | ||
106 | X: X, | ||
107 | } | ||
108 | if err := c.writePacket(Marshal(&kexDHInit)); err != nil { | ||
109 | return nil, err | ||
110 | } | ||
111 | |||
112 | packet, err := c.readPacket() | ||
113 | if err != nil { | ||
114 | return nil, err | ||
115 | } | ||
116 | |||
117 | var kexDHReply kexDHReplyMsg | ||
118 | if err = Unmarshal(packet, &kexDHReply); err != nil { | ||
119 | return nil, err | ||
120 | } | ||
121 | |||
122 | kInt, err := group.diffieHellman(kexDHReply.Y, x) | ||
123 | if err != nil { | ||
124 | return nil, err | ||
125 | } | ||
126 | |||
127 | h := hashFunc.New() | ||
128 | magics.write(h) | ||
129 | writeString(h, kexDHReply.HostKey) | ||
130 | writeInt(h, X) | ||
131 | writeInt(h, kexDHReply.Y) | ||
132 | K := make([]byte, intLength(kInt)) | ||
133 | marshalInt(K, kInt) | ||
134 | h.Write(K) | ||
135 | |||
136 | return &kexResult{ | ||
137 | H: h.Sum(nil), | ||
138 | K: K, | ||
139 | HostKey: kexDHReply.HostKey, | ||
140 | Signature: kexDHReply.Signature, | ||
141 | Hash: crypto.SHA1, | ||
142 | }, nil | ||
143 | } | ||
144 | |||
145 | func (group *dhGroup) Server(c packetConn, randSource io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||
146 | hashFunc := crypto.SHA1 | ||
147 | packet, err := c.readPacket() | ||
148 | if err != nil { | ||
149 | return | ||
150 | } | ||
151 | var kexDHInit kexDHInitMsg | ||
152 | if err = Unmarshal(packet, &kexDHInit); err != nil { | ||
153 | return | ||
154 | } | ||
155 | |||
156 | var y *big.Int | ||
157 | for { | ||
158 | if y, err = rand.Int(randSource, group.pMinus1); err != nil { | ||
159 | return | ||
160 | } | ||
161 | if y.Sign() > 0 { | ||
162 | break | ||
163 | } | ||
164 | } | ||
165 | |||
166 | Y := new(big.Int).Exp(group.g, y, group.p) | ||
167 | kInt, err := group.diffieHellman(kexDHInit.X, y) | ||
168 | if err != nil { | ||
169 | return nil, err | ||
170 | } | ||
171 | |||
172 | hostKeyBytes := priv.PublicKey().Marshal() | ||
173 | |||
174 | h := hashFunc.New() | ||
175 | magics.write(h) | ||
176 | writeString(h, hostKeyBytes) | ||
177 | writeInt(h, kexDHInit.X) | ||
178 | writeInt(h, Y) | ||
179 | |||
180 | K := make([]byte, intLength(kInt)) | ||
181 | marshalInt(K, kInt) | ||
182 | h.Write(K) | ||
183 | |||
184 | H := h.Sum(nil) | ||
185 | |||
186 | // H is already a hash, but the hostkey signing will apply its | ||
187 | // own key-specific hash algorithm. | ||
188 | sig, err := signAndMarshal(priv, randSource, H) | ||
189 | if err != nil { | ||
190 | return nil, err | ||
191 | } | ||
192 | |||
193 | kexDHReply := kexDHReplyMsg{ | ||
194 | HostKey: hostKeyBytes, | ||
195 | Y: Y, | ||
196 | Signature: sig, | ||
197 | } | ||
198 | packet = Marshal(&kexDHReply) | ||
199 | |||
200 | err = c.writePacket(packet) | ||
201 | return &kexResult{ | ||
202 | H: H, | ||
203 | K: K, | ||
204 | HostKey: hostKeyBytes, | ||
205 | Signature: sig, | ||
206 | Hash: crypto.SHA1, | ||
207 | }, nil | ||
208 | } | ||
209 | |||
210 | // ecdh performs Elliptic Curve Diffie-Hellman key exchange as | ||
211 | // described in RFC 5656, section 4. | ||
212 | type ecdh struct { | ||
213 | curve elliptic.Curve | ||
214 | } | ||
215 | |||
216 | func (kex *ecdh) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||
217 | ephKey, err := ecdsa.GenerateKey(kex.curve, rand) | ||
218 | if err != nil { | ||
219 | return nil, err | ||
220 | } | ||
221 | |||
222 | kexInit := kexECDHInitMsg{ | ||
223 | ClientPubKey: elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y), | ||
224 | } | ||
225 | |||
226 | serialized := Marshal(&kexInit) | ||
227 | if err := c.writePacket(serialized); err != nil { | ||
228 | return nil, err | ||
229 | } | ||
230 | |||
231 | packet, err := c.readPacket() | ||
232 | if err != nil { | ||
233 | return nil, err | ||
234 | } | ||
235 | |||
236 | var reply kexECDHReplyMsg | ||
237 | if err = Unmarshal(packet, &reply); err != nil { | ||
238 | return nil, err | ||
239 | } | ||
240 | |||
241 | x, y, err := unmarshalECKey(kex.curve, reply.EphemeralPubKey) | ||
242 | if err != nil { | ||
243 | return nil, err | ||
244 | } | ||
245 | |||
246 | // generate shared secret | ||
247 | secret, _ := kex.curve.ScalarMult(x, y, ephKey.D.Bytes()) | ||
248 | |||
249 | h := ecHash(kex.curve).New() | ||
250 | magics.write(h) | ||
251 | writeString(h, reply.HostKey) | ||
252 | writeString(h, kexInit.ClientPubKey) | ||
253 | writeString(h, reply.EphemeralPubKey) | ||
254 | K := make([]byte, intLength(secret)) | ||
255 | marshalInt(K, secret) | ||
256 | h.Write(K) | ||
257 | |||
258 | return &kexResult{ | ||
259 | H: h.Sum(nil), | ||
260 | K: K, | ||
261 | HostKey: reply.HostKey, | ||
262 | Signature: reply.Signature, | ||
263 | Hash: ecHash(kex.curve), | ||
264 | }, nil | ||
265 | } | ||
266 | |||
267 | // unmarshalECKey parses and checks an EC key. | ||
268 | func unmarshalECKey(curve elliptic.Curve, pubkey []byte) (x, y *big.Int, err error) { | ||
269 | x, y = elliptic.Unmarshal(curve, pubkey) | ||
270 | if x == nil { | ||
271 | return nil, nil, errors.New("ssh: elliptic.Unmarshal failure") | ||
272 | } | ||
273 | if !validateECPublicKey(curve, x, y) { | ||
274 | return nil, nil, errors.New("ssh: public key not on curve") | ||
275 | } | ||
276 | return x, y, nil | ||
277 | } | ||
278 | |||
279 | // validateECPublicKey checks that the point is a valid public key for | ||
280 | // the given curve. See [SEC1], 3.2.2 | ||
281 | func validateECPublicKey(curve elliptic.Curve, x, y *big.Int) bool { | ||
282 | if x.Sign() == 0 && y.Sign() == 0 { | ||
283 | return false | ||
284 | } | ||
285 | |||
286 | if x.Cmp(curve.Params().P) >= 0 { | ||
287 | return false | ||
288 | } | ||
289 | |||
290 | if y.Cmp(curve.Params().P) >= 0 { | ||
291 | return false | ||
292 | } | ||
293 | |||
294 | if !curve.IsOnCurve(x, y) { | ||
295 | return false | ||
296 | } | ||
297 | |||
298 | // We don't check if N * PubKey == 0, since | ||
299 | // | ||
300 | // - the NIST curves have cofactor = 1, so this is implicit. | ||
301 | // (We don't foresee an implementation that supports non NIST | ||
302 | // curves) | ||
303 | // | ||
304 | // - for ephemeral keys, we don't need to worry about small | ||
305 | // subgroup attacks. | ||
306 | return true | ||
307 | } | ||
308 | |||
309 | func (kex *ecdh) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||
310 | packet, err := c.readPacket() | ||
311 | if err != nil { | ||
312 | return nil, err | ||
313 | } | ||
314 | |||
315 | var kexECDHInit kexECDHInitMsg | ||
316 | if err = Unmarshal(packet, &kexECDHInit); err != nil { | ||
317 | return nil, err | ||
318 | } | ||
319 | |||
320 | clientX, clientY, err := unmarshalECKey(kex.curve, kexECDHInit.ClientPubKey) | ||
321 | if err != nil { | ||
322 | return nil, err | ||
323 | } | ||
324 | |||
325 | // We could cache this key across multiple users/multiple | ||
326 | // connection attempts, but the benefit is small. OpenSSH | ||
327 | // generates a new key for each incoming connection. | ||
328 | ephKey, err := ecdsa.GenerateKey(kex.curve, rand) | ||
329 | if err != nil { | ||
330 | return nil, err | ||
331 | } | ||
332 | |||
333 | hostKeyBytes := priv.PublicKey().Marshal() | ||
334 | |||
335 | serializedEphKey := elliptic.Marshal(kex.curve, ephKey.PublicKey.X, ephKey.PublicKey.Y) | ||
336 | |||
337 | // generate shared secret | ||
338 | secret, _ := kex.curve.ScalarMult(clientX, clientY, ephKey.D.Bytes()) | ||
339 | |||
340 | h := ecHash(kex.curve).New() | ||
341 | magics.write(h) | ||
342 | writeString(h, hostKeyBytes) | ||
343 | writeString(h, kexECDHInit.ClientPubKey) | ||
344 | writeString(h, serializedEphKey) | ||
345 | |||
346 | K := make([]byte, intLength(secret)) | ||
347 | marshalInt(K, secret) | ||
348 | h.Write(K) | ||
349 | |||
350 | H := h.Sum(nil) | ||
351 | |||
352 | // H is already a hash, but the hostkey signing will apply its | ||
353 | // own key-specific hash algorithm. | ||
354 | sig, err := signAndMarshal(priv, rand, H) | ||
355 | if err != nil { | ||
356 | return nil, err | ||
357 | } | ||
358 | |||
359 | reply := kexECDHReplyMsg{ | ||
360 | EphemeralPubKey: serializedEphKey, | ||
361 | HostKey: hostKeyBytes, | ||
362 | Signature: sig, | ||
363 | } | ||
364 | |||
365 | serialized := Marshal(&reply) | ||
366 | if err := c.writePacket(serialized); err != nil { | ||
367 | return nil, err | ||
368 | } | ||
369 | |||
370 | return &kexResult{ | ||
371 | H: H, | ||
372 | K: K, | ||
373 | HostKey: reply.HostKey, | ||
374 | Signature: sig, | ||
375 | Hash: ecHash(kex.curve), | ||
376 | }, nil | ||
377 | } | ||
378 | |||
379 | var kexAlgoMap = map[string]kexAlgorithm{} | ||
380 | |||
381 | func init() { | ||
382 | // This is the group called diffie-hellman-group1-sha1 in RFC | ||
383 | // 4253 and Oakley Group 2 in RFC 2409. | ||
384 | p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16) | ||
385 | kexAlgoMap[kexAlgoDH1SHA1] = &dhGroup{ | ||
386 | g: new(big.Int).SetInt64(2), | ||
387 | p: p, | ||
388 | pMinus1: new(big.Int).Sub(p, bigOne), | ||
389 | } | ||
390 | |||
391 | // This is the group called diffie-hellman-group14-sha1 in RFC | ||
392 | // 4253 and Oakley Group 14 in RFC 3526. | ||
393 | p, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16) | ||
394 | |||
395 | kexAlgoMap[kexAlgoDH14SHA1] = &dhGroup{ | ||
396 | g: new(big.Int).SetInt64(2), | ||
397 | p: p, | ||
398 | pMinus1: new(big.Int).Sub(p, bigOne), | ||
399 | } | ||
400 | |||
401 | kexAlgoMap[kexAlgoECDH521] = &ecdh{elliptic.P521()} | ||
402 | kexAlgoMap[kexAlgoECDH384] = &ecdh{elliptic.P384()} | ||
403 | kexAlgoMap[kexAlgoECDH256] = &ecdh{elliptic.P256()} | ||
404 | kexAlgoMap[kexAlgoCurve25519SHA256] = &curve25519sha256{} | ||
405 | } | ||
406 | |||
407 | // curve25519sha256 implements the curve25519-sha256@libssh.org key | ||
408 | // agreement protocol, as described in | ||
409 | // https://git.libssh.org/projects/libssh.git/tree/doc/curve25519-sha256@libssh.org.txt | ||
410 | type curve25519sha256 struct{} | ||
411 | |||
412 | type curve25519KeyPair struct { | ||
413 | priv [32]byte | ||
414 | pub [32]byte | ||
415 | } | ||
416 | |||
417 | func (kp *curve25519KeyPair) generate(rand io.Reader) error { | ||
418 | if _, err := io.ReadFull(rand, kp.priv[:]); err != nil { | ||
419 | return err | ||
420 | } | ||
421 | curve25519.ScalarBaseMult(&kp.pub, &kp.priv) | ||
422 | return nil | ||
423 | } | ||
424 | |||
425 | // curve25519Zeros is just an array of 32 zero bytes so that we have something | ||
426 | // convenient to compare against in order to reject curve25519 points with the | ||
427 | // wrong order. | ||
428 | var curve25519Zeros [32]byte | ||
429 | |||
430 | func (kex *curve25519sha256) Client(c packetConn, rand io.Reader, magics *handshakeMagics) (*kexResult, error) { | ||
431 | var kp curve25519KeyPair | ||
432 | if err := kp.generate(rand); err != nil { | ||
433 | return nil, err | ||
434 | } | ||
435 | if err := c.writePacket(Marshal(&kexECDHInitMsg{kp.pub[:]})); err != nil { | ||
436 | return nil, err | ||
437 | } | ||
438 | |||
439 | packet, err := c.readPacket() | ||
440 | if err != nil { | ||
441 | return nil, err | ||
442 | } | ||
443 | |||
444 | var reply kexECDHReplyMsg | ||
445 | if err = Unmarshal(packet, &reply); err != nil { | ||
446 | return nil, err | ||
447 | } | ||
448 | if len(reply.EphemeralPubKey) != 32 { | ||
449 | return nil, errors.New("ssh: peer's curve25519 public value has wrong length") | ||
450 | } | ||
451 | |||
452 | var servPub, secret [32]byte | ||
453 | copy(servPub[:], reply.EphemeralPubKey) | ||
454 | curve25519.ScalarMult(&secret, &kp.priv, &servPub) | ||
455 | if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { | ||
456 | return nil, errors.New("ssh: peer's curve25519 public value has wrong order") | ||
457 | } | ||
458 | |||
459 | h := crypto.SHA256.New() | ||
460 | magics.write(h) | ||
461 | writeString(h, reply.HostKey) | ||
462 | writeString(h, kp.pub[:]) | ||
463 | writeString(h, reply.EphemeralPubKey) | ||
464 | |||
465 | kInt := new(big.Int).SetBytes(secret[:]) | ||
466 | K := make([]byte, intLength(kInt)) | ||
467 | marshalInt(K, kInt) | ||
468 | h.Write(K) | ||
469 | |||
470 | return &kexResult{ | ||
471 | H: h.Sum(nil), | ||
472 | K: K, | ||
473 | HostKey: reply.HostKey, | ||
474 | Signature: reply.Signature, | ||
475 | Hash: crypto.SHA256, | ||
476 | }, nil | ||
477 | } | ||
478 | |||
479 | func (kex *curve25519sha256) Server(c packetConn, rand io.Reader, magics *handshakeMagics, priv Signer) (result *kexResult, err error) { | ||
480 | packet, err := c.readPacket() | ||
481 | if err != nil { | ||
482 | return | ||
483 | } | ||
484 | var kexInit kexECDHInitMsg | ||
485 | if err = Unmarshal(packet, &kexInit); err != nil { | ||
486 | return | ||
487 | } | ||
488 | |||
489 | if len(kexInit.ClientPubKey) != 32 { | ||
490 | return nil, errors.New("ssh: peer's curve25519 public value has wrong length") | ||
491 | } | ||
492 | |||
493 | var kp curve25519KeyPair | ||
494 | if err := kp.generate(rand); err != nil { | ||
495 | return nil, err | ||
496 | } | ||
497 | |||
498 | var clientPub, secret [32]byte | ||
499 | copy(clientPub[:], kexInit.ClientPubKey) | ||
500 | curve25519.ScalarMult(&secret, &kp.priv, &clientPub) | ||
501 | if subtle.ConstantTimeCompare(secret[:], curve25519Zeros[:]) == 1 { | ||
502 | return nil, errors.New("ssh: peer's curve25519 public value has wrong order") | ||
503 | } | ||
504 | |||
505 | hostKeyBytes := priv.PublicKey().Marshal() | ||
506 | |||
507 | h := crypto.SHA256.New() | ||
508 | magics.write(h) | ||
509 | writeString(h, hostKeyBytes) | ||
510 | writeString(h, kexInit.ClientPubKey) | ||
511 | writeString(h, kp.pub[:]) | ||
512 | |||
513 | kInt := new(big.Int).SetBytes(secret[:]) | ||
514 | K := make([]byte, intLength(kInt)) | ||
515 | marshalInt(K, kInt) | ||
516 | h.Write(K) | ||
517 | |||
518 | H := h.Sum(nil) | ||
519 | |||
520 | sig, err := signAndMarshal(priv, rand, H) | ||
521 | if err != nil { | ||
522 | return nil, err | ||
523 | } | ||
524 | |||
525 | reply := kexECDHReplyMsg{ | ||
526 | EphemeralPubKey: kp.pub[:], | ||
527 | HostKey: hostKeyBytes, | ||
528 | Signature: sig, | ||
529 | } | ||
530 | if err := c.writePacket(Marshal(&reply)); err != nil { | ||
531 | return nil, err | ||
532 | } | ||
533 | return &kexResult{ | ||
534 | H: H, | ||
535 | K: K, | ||
536 | HostKey: hostKeyBytes, | ||
537 | Signature: sig, | ||
538 | Hash: crypto.SHA256, | ||
539 | }, nil | ||
540 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go new file mode 100644 index 0000000..f38de98 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/keys.go | |||
@@ -0,0 +1,905 @@ | |||
1 | // Copyright 2012 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "crypto" | ||
10 | "crypto/dsa" | ||
11 | "crypto/ecdsa" | ||
12 | "crypto/elliptic" | ||
13 | "crypto/md5" | ||
14 | "crypto/rsa" | ||
15 | "crypto/sha256" | ||
16 | "crypto/x509" | ||
17 | "encoding/asn1" | ||
18 | "encoding/base64" | ||
19 | "encoding/hex" | ||
20 | "encoding/pem" | ||
21 | "errors" | ||
22 | "fmt" | ||
23 | "io" | ||
24 | "math/big" | ||
25 | "strings" | ||
26 | |||
27 | "golang.org/x/crypto/ed25519" | ||
28 | ) | ||
29 | |||
30 | // These constants represent the algorithm names for key types supported by this | ||
31 | // package. | ||
32 | const ( | ||
33 | KeyAlgoRSA = "ssh-rsa" | ||
34 | KeyAlgoDSA = "ssh-dss" | ||
35 | KeyAlgoECDSA256 = "ecdsa-sha2-nistp256" | ||
36 | KeyAlgoECDSA384 = "ecdsa-sha2-nistp384" | ||
37 | KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" | ||
38 | KeyAlgoED25519 = "ssh-ed25519" | ||
39 | ) | ||
40 | |||
41 | // parsePubKey parses a public key of the given algorithm. | ||
42 | // Use ParsePublicKey for keys with prepended algorithm. | ||
43 | func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { | ||
44 | switch algo { | ||
45 | case KeyAlgoRSA: | ||
46 | return parseRSA(in) | ||
47 | case KeyAlgoDSA: | ||
48 | return parseDSA(in) | ||
49 | case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: | ||
50 | return parseECDSA(in) | ||
51 | case KeyAlgoED25519: | ||
52 | return parseED25519(in) | ||
53 | case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01: | ||
54 | cert, err := parseCert(in, certToPrivAlgo(algo)) | ||
55 | if err != nil { | ||
56 | return nil, nil, err | ||
57 | } | ||
58 | return cert, nil, nil | ||
59 | } | ||
60 | return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) | ||
61 | } | ||
62 | |||
63 | // parseAuthorizedKey parses a public key in OpenSSH authorized_keys format | ||
64 | // (see sshd(8) manual page) once the options and key type fields have been | ||
65 | // removed. | ||
66 | func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) { | ||
67 | in = bytes.TrimSpace(in) | ||
68 | |||
69 | i := bytes.IndexAny(in, " \t") | ||
70 | if i == -1 { | ||
71 | i = len(in) | ||
72 | } | ||
73 | base64Key := in[:i] | ||
74 | |||
75 | key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key))) | ||
76 | n, err := base64.StdEncoding.Decode(key, base64Key) | ||
77 | if err != nil { | ||
78 | return nil, "", err | ||
79 | } | ||
80 | key = key[:n] | ||
81 | out, err = ParsePublicKey(key) | ||
82 | if err != nil { | ||
83 | return nil, "", err | ||
84 | } | ||
85 | comment = string(bytes.TrimSpace(in[i:])) | ||
86 | return out, comment, nil | ||
87 | } | ||
88 | |||
89 | // ParseKnownHosts parses an entry in the format of the known_hosts file. | ||
90 | // | ||
91 | // The known_hosts format is documented in the sshd(8) manual page. This | ||
92 | // function will parse a single entry from in. On successful return, marker | ||
93 | // will contain the optional marker value (i.e. "cert-authority" or "revoked") | ||
94 | // or else be empty, hosts will contain the hosts that this entry matches, | ||
95 | // pubKey will contain the public key and comment will contain any trailing | ||
96 | // comment at the end of the line. See the sshd(8) manual page for the various | ||
97 | // forms that a host string can take. | ||
98 | // | ||
99 | // The unparsed remainder of the input will be returned in rest. This function | ||
100 | // can be called repeatedly to parse multiple entries. | ||
101 | // | ||
102 | // If no entries were found in the input then err will be io.EOF. Otherwise a | ||
103 | // non-nil err value indicates a parse error. | ||
104 | func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) { | ||
105 | for len(in) > 0 { | ||
106 | end := bytes.IndexByte(in, '\n') | ||
107 | if end != -1 { | ||
108 | rest = in[end+1:] | ||
109 | in = in[:end] | ||
110 | } else { | ||
111 | rest = nil | ||
112 | } | ||
113 | |||
114 | end = bytes.IndexByte(in, '\r') | ||
115 | if end != -1 { | ||
116 | in = in[:end] | ||
117 | } | ||
118 | |||
119 | in = bytes.TrimSpace(in) | ||
120 | if len(in) == 0 || in[0] == '#' { | ||
121 | in = rest | ||
122 | continue | ||
123 | } | ||
124 | |||
125 | i := bytes.IndexAny(in, " \t") | ||
126 | if i == -1 { | ||
127 | in = rest | ||
128 | continue | ||
129 | } | ||
130 | |||
131 | // Strip out the beginning of the known_host key. | ||
132 | // This is either an optional marker or a (set of) hostname(s). | ||
133 | keyFields := bytes.Fields(in) | ||
134 | if len(keyFields) < 3 || len(keyFields) > 5 { | ||
135 | return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data") | ||
136 | } | ||
137 | |||
138 | // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated | ||
139 | // list of hosts | ||
140 | marker := "" | ||
141 | if keyFields[0][0] == '@' { | ||
142 | marker = string(keyFields[0][1:]) | ||
143 | keyFields = keyFields[1:] | ||
144 | } | ||
145 | |||
146 | hosts := string(keyFields[0]) | ||
147 | // keyFields[1] contains the key type (e.g. “ssh-rsa”). | ||
148 | // However, that information is duplicated inside the | ||
149 | // base64-encoded key and so is ignored here. | ||
150 | |||
151 | key := bytes.Join(keyFields[2:], []byte(" ")) | ||
152 | if pubKey, comment, err = parseAuthorizedKey(key); err != nil { | ||
153 | return "", nil, nil, "", nil, err | ||
154 | } | ||
155 | |||
156 | return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil | ||
157 | } | ||
158 | |||
159 | return "", nil, nil, "", nil, io.EOF | ||
160 | } | ||
161 | |||
162 | // ParseAuthorizedKeys parses a public key from an authorized_keys | ||
163 | // file used in OpenSSH according to the sshd(8) manual page. | ||
164 | func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { | ||
165 | for len(in) > 0 { | ||
166 | end := bytes.IndexByte(in, '\n') | ||
167 | if end != -1 { | ||
168 | rest = in[end+1:] | ||
169 | in = in[:end] | ||
170 | } else { | ||
171 | rest = nil | ||
172 | } | ||
173 | |||
174 | end = bytes.IndexByte(in, '\r') | ||
175 | if end != -1 { | ||
176 | in = in[:end] | ||
177 | } | ||
178 | |||
179 | in = bytes.TrimSpace(in) | ||
180 | if len(in) == 0 || in[0] == '#' { | ||
181 | in = rest | ||
182 | continue | ||
183 | } | ||
184 | |||
185 | i := bytes.IndexAny(in, " \t") | ||
186 | if i == -1 { | ||
187 | in = rest | ||
188 | continue | ||
189 | } | ||
190 | |||
191 | if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { | ||
192 | return out, comment, options, rest, nil | ||
193 | } | ||
194 | |||
195 | // No key type recognised. Maybe there's an options field at | ||
196 | // the beginning. | ||
197 | var b byte | ||
198 | inQuote := false | ||
199 | var candidateOptions []string | ||
200 | optionStart := 0 | ||
201 | for i, b = range in { | ||
202 | isEnd := !inQuote && (b == ' ' || b == '\t') | ||
203 | if (b == ',' && !inQuote) || isEnd { | ||
204 | if i-optionStart > 0 { | ||
205 | candidateOptions = append(candidateOptions, string(in[optionStart:i])) | ||
206 | } | ||
207 | optionStart = i + 1 | ||
208 | } | ||
209 | if isEnd { | ||
210 | break | ||
211 | } | ||
212 | if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) { | ||
213 | inQuote = !inQuote | ||
214 | } | ||
215 | } | ||
216 | for i < len(in) && (in[i] == ' ' || in[i] == '\t') { | ||
217 | i++ | ||
218 | } | ||
219 | if i == len(in) { | ||
220 | // Invalid line: unmatched quote | ||
221 | in = rest | ||
222 | continue | ||
223 | } | ||
224 | |||
225 | in = in[i:] | ||
226 | i = bytes.IndexAny(in, " \t") | ||
227 | if i == -1 { | ||
228 | in = rest | ||
229 | continue | ||
230 | } | ||
231 | |||
232 | if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { | ||
233 | options = candidateOptions | ||
234 | return out, comment, options, rest, nil | ||
235 | } | ||
236 | |||
237 | in = rest | ||
238 | continue | ||
239 | } | ||
240 | |||
241 | return nil, "", nil, nil, errors.New("ssh: no key found") | ||
242 | } | ||
243 | |||
244 | // ParsePublicKey parses an SSH public key formatted for use in | ||
245 | // the SSH wire protocol according to RFC 4253, section 6.6. | ||
246 | func ParsePublicKey(in []byte) (out PublicKey, err error) { | ||
247 | algo, in, ok := parseString(in) | ||
248 | if !ok { | ||
249 | return nil, errShortRead | ||
250 | } | ||
251 | var rest []byte | ||
252 | out, rest, err = parsePubKey(in, string(algo)) | ||
253 | if len(rest) > 0 { | ||
254 | return nil, errors.New("ssh: trailing junk in public key") | ||
255 | } | ||
256 | |||
257 | return out, err | ||
258 | } | ||
259 | |||
260 | // MarshalAuthorizedKey serializes key for inclusion in an OpenSSH | ||
261 | // authorized_keys file. The return value ends with newline. | ||
262 | func MarshalAuthorizedKey(key PublicKey) []byte { | ||
263 | b := &bytes.Buffer{} | ||
264 | b.WriteString(key.Type()) | ||
265 | b.WriteByte(' ') | ||
266 | e := base64.NewEncoder(base64.StdEncoding, b) | ||
267 | e.Write(key.Marshal()) | ||
268 | e.Close() | ||
269 | b.WriteByte('\n') | ||
270 | return b.Bytes() | ||
271 | } | ||
272 | |||
273 | // PublicKey is an abstraction of different types of public keys. | ||
274 | type PublicKey interface { | ||
275 | // Type returns the key's type, e.g. "ssh-rsa". | ||
276 | Type() string | ||
277 | |||
278 | // Marshal returns the serialized key data in SSH wire format, | ||
279 | // with the name prefix. | ||
280 | Marshal() []byte | ||
281 | |||
282 | // Verify that sig is a signature on the given data using this | ||
283 | // key. This function will hash the data appropriately first. | ||
284 | Verify(data []byte, sig *Signature) error | ||
285 | } | ||
286 | |||
287 | // CryptoPublicKey, if implemented by a PublicKey, | ||
288 | // returns the underlying crypto.PublicKey form of the key. | ||
289 | type CryptoPublicKey interface { | ||
290 | CryptoPublicKey() crypto.PublicKey | ||
291 | } | ||
292 | |||
293 | // A Signer can create signatures that verify against a public key. | ||
294 | type Signer interface { | ||
295 | // PublicKey returns an associated PublicKey instance. | ||
296 | PublicKey() PublicKey | ||
297 | |||
298 | // Sign returns raw signature for the given data. This method | ||
299 | // will apply the hash specified for the keytype to the data. | ||
300 | Sign(rand io.Reader, data []byte) (*Signature, error) | ||
301 | } | ||
302 | |||
303 | type rsaPublicKey rsa.PublicKey | ||
304 | |||
305 | func (r *rsaPublicKey) Type() string { | ||
306 | return "ssh-rsa" | ||
307 | } | ||
308 | |||
309 | // parseRSA parses an RSA key according to RFC 4253, section 6.6. | ||
310 | func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { | ||
311 | var w struct { | ||
312 | E *big.Int | ||
313 | N *big.Int | ||
314 | Rest []byte `ssh:"rest"` | ||
315 | } | ||
316 | if err := Unmarshal(in, &w); err != nil { | ||
317 | return nil, nil, err | ||
318 | } | ||
319 | |||
320 | if w.E.BitLen() > 24 { | ||
321 | return nil, nil, errors.New("ssh: exponent too large") | ||
322 | } | ||
323 | e := w.E.Int64() | ||
324 | if e < 3 || e&1 == 0 { | ||
325 | return nil, nil, errors.New("ssh: incorrect exponent") | ||
326 | } | ||
327 | |||
328 | var key rsa.PublicKey | ||
329 | key.E = int(e) | ||
330 | key.N = w.N | ||
331 | return (*rsaPublicKey)(&key), w.Rest, nil | ||
332 | } | ||
333 | |||
334 | func (r *rsaPublicKey) Marshal() []byte { | ||
335 | e := new(big.Int).SetInt64(int64(r.E)) | ||
336 | // RSA publickey struct layout should match the struct used by | ||
337 | // parseRSACert in the x/crypto/ssh/agent package. | ||
338 | wirekey := struct { | ||
339 | Name string | ||
340 | E *big.Int | ||
341 | N *big.Int | ||
342 | }{ | ||
343 | KeyAlgoRSA, | ||
344 | e, | ||
345 | r.N, | ||
346 | } | ||
347 | return Marshal(&wirekey) | ||
348 | } | ||
349 | |||
350 | func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { | ||
351 | if sig.Format != r.Type() { | ||
352 | return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) | ||
353 | } | ||
354 | h := crypto.SHA1.New() | ||
355 | h.Write(data) | ||
356 | digest := h.Sum(nil) | ||
357 | return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) | ||
358 | } | ||
359 | |||
360 | func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||
361 | return (*rsa.PublicKey)(r) | ||
362 | } | ||
363 | |||
364 | type dsaPublicKey dsa.PublicKey | ||
365 | |||
366 | func (r *dsaPublicKey) Type() string { | ||
367 | return "ssh-dss" | ||
368 | } | ||
369 | |||
370 | // parseDSA parses an DSA key according to RFC 4253, section 6.6. | ||
371 | func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { | ||
372 | var w struct { | ||
373 | P, Q, G, Y *big.Int | ||
374 | Rest []byte `ssh:"rest"` | ||
375 | } | ||
376 | if err := Unmarshal(in, &w); err != nil { | ||
377 | return nil, nil, err | ||
378 | } | ||
379 | |||
380 | key := &dsaPublicKey{ | ||
381 | Parameters: dsa.Parameters{ | ||
382 | P: w.P, | ||
383 | Q: w.Q, | ||
384 | G: w.G, | ||
385 | }, | ||
386 | Y: w.Y, | ||
387 | } | ||
388 | return key, w.Rest, nil | ||
389 | } | ||
390 | |||
391 | func (k *dsaPublicKey) Marshal() []byte { | ||
392 | // DSA publickey struct layout should match the struct used by | ||
393 | // parseDSACert in the x/crypto/ssh/agent package. | ||
394 | w := struct { | ||
395 | Name string | ||
396 | P, Q, G, Y *big.Int | ||
397 | }{ | ||
398 | k.Type(), | ||
399 | k.P, | ||
400 | k.Q, | ||
401 | k.G, | ||
402 | k.Y, | ||
403 | } | ||
404 | |||
405 | return Marshal(&w) | ||
406 | } | ||
407 | |||
408 | func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { | ||
409 | if sig.Format != k.Type() { | ||
410 | return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) | ||
411 | } | ||
412 | h := crypto.SHA1.New() | ||
413 | h.Write(data) | ||
414 | digest := h.Sum(nil) | ||
415 | |||
416 | // Per RFC 4253, section 6.6, | ||
417 | // The value for 'dss_signature_blob' is encoded as a string containing | ||
418 | // r, followed by s (which are 160-bit integers, without lengths or | ||
419 | // padding, unsigned, and in network byte order). | ||
420 | // For DSS purposes, sig.Blob should be exactly 40 bytes in length. | ||
421 | if len(sig.Blob) != 40 { | ||
422 | return errors.New("ssh: DSA signature parse error") | ||
423 | } | ||
424 | r := new(big.Int).SetBytes(sig.Blob[:20]) | ||
425 | s := new(big.Int).SetBytes(sig.Blob[20:]) | ||
426 | if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) { | ||
427 | return nil | ||
428 | } | ||
429 | return errors.New("ssh: signature did not verify") | ||
430 | } | ||
431 | |||
432 | func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||
433 | return (*dsa.PublicKey)(k) | ||
434 | } | ||
435 | |||
436 | type dsaPrivateKey struct { | ||
437 | *dsa.PrivateKey | ||
438 | } | ||
439 | |||
440 | func (k *dsaPrivateKey) PublicKey() PublicKey { | ||
441 | return (*dsaPublicKey)(&k.PrivateKey.PublicKey) | ||
442 | } | ||
443 | |||
444 | func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||
445 | h := crypto.SHA1.New() | ||
446 | h.Write(data) | ||
447 | digest := h.Sum(nil) | ||
448 | r, s, err := dsa.Sign(rand, k.PrivateKey, digest) | ||
449 | if err != nil { | ||
450 | return nil, err | ||
451 | } | ||
452 | |||
453 | sig := make([]byte, 40) | ||
454 | rb := r.Bytes() | ||
455 | sb := s.Bytes() | ||
456 | |||
457 | copy(sig[20-len(rb):20], rb) | ||
458 | copy(sig[40-len(sb):], sb) | ||
459 | |||
460 | return &Signature{ | ||
461 | Format: k.PublicKey().Type(), | ||
462 | Blob: sig, | ||
463 | }, nil | ||
464 | } | ||
465 | |||
466 | type ecdsaPublicKey ecdsa.PublicKey | ||
467 | |||
468 | func (key *ecdsaPublicKey) Type() string { | ||
469 | return "ecdsa-sha2-" + key.nistID() | ||
470 | } | ||
471 | |||
472 | func (key *ecdsaPublicKey) nistID() string { | ||
473 | switch key.Params().BitSize { | ||
474 | case 256: | ||
475 | return "nistp256" | ||
476 | case 384: | ||
477 | return "nistp384" | ||
478 | case 521: | ||
479 | return "nistp521" | ||
480 | } | ||
481 | panic("ssh: unsupported ecdsa key size") | ||
482 | } | ||
483 | |||
484 | type ed25519PublicKey ed25519.PublicKey | ||
485 | |||
486 | func (key ed25519PublicKey) Type() string { | ||
487 | return KeyAlgoED25519 | ||
488 | } | ||
489 | |||
490 | func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { | ||
491 | var w struct { | ||
492 | KeyBytes []byte | ||
493 | Rest []byte `ssh:"rest"` | ||
494 | } | ||
495 | |||
496 | if err := Unmarshal(in, &w); err != nil { | ||
497 | return nil, nil, err | ||
498 | } | ||
499 | |||
500 | key := ed25519.PublicKey(w.KeyBytes) | ||
501 | |||
502 | return (ed25519PublicKey)(key), w.Rest, nil | ||
503 | } | ||
504 | |||
505 | func (key ed25519PublicKey) Marshal() []byte { | ||
506 | w := struct { | ||
507 | Name string | ||
508 | KeyBytes []byte | ||
509 | }{ | ||
510 | KeyAlgoED25519, | ||
511 | []byte(key), | ||
512 | } | ||
513 | return Marshal(&w) | ||
514 | } | ||
515 | |||
516 | func (key ed25519PublicKey) Verify(b []byte, sig *Signature) error { | ||
517 | if sig.Format != key.Type() { | ||
518 | return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type()) | ||
519 | } | ||
520 | |||
521 | edKey := (ed25519.PublicKey)(key) | ||
522 | if ok := ed25519.Verify(edKey, b, sig.Blob); !ok { | ||
523 | return errors.New("ssh: signature did not verify") | ||
524 | } | ||
525 | |||
526 | return nil | ||
527 | } | ||
528 | |||
529 | func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { | ||
530 | return ed25519.PublicKey(k) | ||
531 | } | ||
532 | |||
533 | func supportedEllipticCurve(curve elliptic.Curve) bool { | ||
534 | return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() | ||
535 | } | ||
536 | |||
537 | // ecHash returns the hash to match the given elliptic curve, see RFC | ||
538 | // 5656, section 6.2.1 | ||
539 | func ecHash(curve elliptic.Curve) crypto.Hash { | ||
540 | bitSize := curve.Params().BitSize | ||
541 | switch { | ||
542 | case bitSize <= 256: | ||
543 | return crypto.SHA256 | ||
544 | case bitSize <= 384: | ||
545 | return crypto.SHA384 | ||
546 | } | ||
547 | return crypto.SHA512 | ||
548 | } | ||
549 | |||
550 | // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. | ||
551 | func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { | ||
552 | var w struct { | ||
553 | Curve string | ||
554 | KeyBytes []byte | ||
555 | Rest []byte `ssh:"rest"` | ||
556 | } | ||
557 | |||
558 | if err := Unmarshal(in, &w); err != nil { | ||
559 | return nil, nil, err | ||
560 | } | ||
561 | |||
562 | key := new(ecdsa.PublicKey) | ||
563 | |||
564 | switch w.Curve { | ||
565 | case "nistp256": | ||
566 | key.Curve = elliptic.P256() | ||
567 | case "nistp384": | ||
568 | key.Curve = elliptic.P384() | ||
569 | case "nistp521": | ||
570 | key.Curve = elliptic.P521() | ||
571 | default: | ||
572 | return nil, nil, errors.New("ssh: unsupported curve") | ||
573 | } | ||
574 | |||
575 | key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) | ||
576 | if key.X == nil || key.Y == nil { | ||
577 | return nil, nil, errors.New("ssh: invalid curve point") | ||
578 | } | ||
579 | return (*ecdsaPublicKey)(key), w.Rest, nil | ||
580 | } | ||
581 | |||
582 | func (key *ecdsaPublicKey) Marshal() []byte { | ||
583 | // See RFC 5656, section 3.1. | ||
584 | keyBytes := elliptic.Marshal(key.Curve, key.X, key.Y) | ||
585 | // ECDSA publickey struct layout should match the struct used by | ||
586 | // parseECDSACert in the x/crypto/ssh/agent package. | ||
587 | w := struct { | ||
588 | Name string | ||
589 | ID string | ||
590 | Key []byte | ||
591 | }{ | ||
592 | key.Type(), | ||
593 | key.nistID(), | ||
594 | keyBytes, | ||
595 | } | ||
596 | |||
597 | return Marshal(&w) | ||
598 | } | ||
599 | |||
600 | func (key *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { | ||
601 | if sig.Format != key.Type() { | ||
602 | return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type()) | ||
603 | } | ||
604 | |||
605 | h := ecHash(key.Curve).New() | ||
606 | h.Write(data) | ||
607 | digest := h.Sum(nil) | ||
608 | |||
609 | // Per RFC 5656, section 3.1.2, | ||
610 | // The ecdsa_signature_blob value has the following specific encoding: | ||
611 | // mpint r | ||
612 | // mpint s | ||
613 | var ecSig struct { | ||
614 | R *big.Int | ||
615 | S *big.Int | ||
616 | } | ||
617 | |||
618 | if err := Unmarshal(sig.Blob, &ecSig); err != nil { | ||
619 | return err | ||
620 | } | ||
621 | |||
622 | if ecdsa.Verify((*ecdsa.PublicKey)(key), digest, ecSig.R, ecSig.S) { | ||
623 | return nil | ||
624 | } | ||
625 | return errors.New("ssh: signature did not verify") | ||
626 | } | ||
627 | |||
628 | func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||
629 | return (*ecdsa.PublicKey)(k) | ||
630 | } | ||
631 | |||
632 | // NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, | ||
633 | // *ecdsa.PrivateKey or any other crypto.Signer and returns a corresponding | ||
634 | // Signer instance. ECDSA keys must use P-256, P-384 or P-521. | ||
635 | func NewSignerFromKey(key interface{}) (Signer, error) { | ||
636 | switch key := key.(type) { | ||
637 | case crypto.Signer: | ||
638 | return NewSignerFromSigner(key) | ||
639 | case *dsa.PrivateKey: | ||
640 | return &dsaPrivateKey{key}, nil | ||
641 | default: | ||
642 | return nil, fmt.Errorf("ssh: unsupported key type %T", key) | ||
643 | } | ||
644 | } | ||
645 | |||
646 | type wrappedSigner struct { | ||
647 | signer crypto.Signer | ||
648 | pubKey PublicKey | ||
649 | } | ||
650 | |||
651 | // NewSignerFromSigner takes any crypto.Signer implementation and | ||
652 | // returns a corresponding Signer interface. This can be used, for | ||
653 | // example, with keys kept in hardware modules. | ||
654 | func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { | ||
655 | pubKey, err := NewPublicKey(signer.Public()) | ||
656 | if err != nil { | ||
657 | return nil, err | ||
658 | } | ||
659 | |||
660 | return &wrappedSigner{signer, pubKey}, nil | ||
661 | } | ||
662 | |||
663 | func (s *wrappedSigner) PublicKey() PublicKey { | ||
664 | return s.pubKey | ||
665 | } | ||
666 | |||
667 | func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||
668 | var hashFunc crypto.Hash | ||
669 | |||
670 | switch key := s.pubKey.(type) { | ||
671 | case *rsaPublicKey, *dsaPublicKey: | ||
672 | hashFunc = crypto.SHA1 | ||
673 | case *ecdsaPublicKey: | ||
674 | hashFunc = ecHash(key.Curve) | ||
675 | case ed25519PublicKey: | ||
676 | default: | ||
677 | return nil, fmt.Errorf("ssh: unsupported key type %T", key) | ||
678 | } | ||
679 | |||
680 | var digest []byte | ||
681 | if hashFunc != 0 { | ||
682 | h := hashFunc.New() | ||
683 | h.Write(data) | ||
684 | digest = h.Sum(nil) | ||
685 | } else { | ||
686 | digest = data | ||
687 | } | ||
688 | |||
689 | signature, err := s.signer.Sign(rand, digest, hashFunc) | ||
690 | if err != nil { | ||
691 | return nil, err | ||
692 | } | ||
693 | |||
694 | // crypto.Signer.Sign is expected to return an ASN.1-encoded signature | ||
695 | // for ECDSA and DSA, but that's not the encoding expected by SSH, so | ||
696 | // re-encode. | ||
697 | switch s.pubKey.(type) { | ||
698 | case *ecdsaPublicKey, *dsaPublicKey: | ||
699 | type asn1Signature struct { | ||
700 | R, S *big.Int | ||
701 | } | ||
702 | asn1Sig := new(asn1Signature) | ||
703 | _, err := asn1.Unmarshal(signature, asn1Sig) | ||
704 | if err != nil { | ||
705 | return nil, err | ||
706 | } | ||
707 | |||
708 | switch s.pubKey.(type) { | ||
709 | case *ecdsaPublicKey: | ||
710 | signature = Marshal(asn1Sig) | ||
711 | |||
712 | case *dsaPublicKey: | ||
713 | signature = make([]byte, 40) | ||
714 | r := asn1Sig.R.Bytes() | ||
715 | s := asn1Sig.S.Bytes() | ||
716 | copy(signature[20-len(r):20], r) | ||
717 | copy(signature[40-len(s):40], s) | ||
718 | } | ||
719 | } | ||
720 | |||
721 | return &Signature{ | ||
722 | Format: s.pubKey.Type(), | ||
723 | Blob: signature, | ||
724 | }, nil | ||
725 | } | ||
726 | |||
727 | // NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, | ||
728 | // or ed25519.PublicKey returns a corresponding PublicKey instance. | ||
729 | // ECDSA keys must use P-256, P-384 or P-521. | ||
730 | func NewPublicKey(key interface{}) (PublicKey, error) { | ||
731 | switch key := key.(type) { | ||
732 | case *rsa.PublicKey: | ||
733 | return (*rsaPublicKey)(key), nil | ||
734 | case *ecdsa.PublicKey: | ||
735 | if !supportedEllipticCurve(key.Curve) { | ||
736 | return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported.") | ||
737 | } | ||
738 | return (*ecdsaPublicKey)(key), nil | ||
739 | case *dsa.PublicKey: | ||
740 | return (*dsaPublicKey)(key), nil | ||
741 | case ed25519.PublicKey: | ||
742 | return (ed25519PublicKey)(key), nil | ||
743 | default: | ||
744 | return nil, fmt.Errorf("ssh: unsupported key type %T", key) | ||
745 | } | ||
746 | } | ||
747 | |||
748 | // ParsePrivateKey returns a Signer from a PEM encoded private key. It supports | ||
749 | // the same keys as ParseRawPrivateKey. | ||
750 | func ParsePrivateKey(pemBytes []byte) (Signer, error) { | ||
751 | key, err := ParseRawPrivateKey(pemBytes) | ||
752 | if err != nil { | ||
753 | return nil, err | ||
754 | } | ||
755 | |||
756 | return NewSignerFromKey(key) | ||
757 | } | ||
758 | |||
759 | // encryptedBlock tells whether a private key is | ||
760 | // encrypted by examining its Proc-Type header | ||
761 | // for a mention of ENCRYPTED | ||
762 | // according to RFC 1421 Section 4.6.1.1. | ||
763 | func encryptedBlock(block *pem.Block) bool { | ||
764 | return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") | ||
765 | } | ||
766 | |||
767 | // ParseRawPrivateKey returns a private key from a PEM encoded private key. It | ||
768 | // supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys. | ||
769 | func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { | ||
770 | block, _ := pem.Decode(pemBytes) | ||
771 | if block == nil { | ||
772 | return nil, errors.New("ssh: no key found") | ||
773 | } | ||
774 | |||
775 | if encryptedBlock(block) { | ||
776 | return nil, errors.New("ssh: cannot decode encrypted private keys") | ||
777 | } | ||
778 | |||
779 | switch block.Type { | ||
780 | case "RSA PRIVATE KEY": | ||
781 | return x509.ParsePKCS1PrivateKey(block.Bytes) | ||
782 | case "EC PRIVATE KEY": | ||
783 | return x509.ParseECPrivateKey(block.Bytes) | ||
784 | case "DSA PRIVATE KEY": | ||
785 | return ParseDSAPrivateKey(block.Bytes) | ||
786 | case "OPENSSH PRIVATE KEY": | ||
787 | return parseOpenSSHPrivateKey(block.Bytes) | ||
788 | default: | ||
789 | return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) | ||
790 | } | ||
791 | } | ||
792 | |||
793 | // ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as | ||
794 | // specified by the OpenSSL DSA man page. | ||
795 | func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { | ||
796 | var k struct { | ||
797 | Version int | ||
798 | P *big.Int | ||
799 | Q *big.Int | ||
800 | G *big.Int | ||
801 | Pub *big.Int | ||
802 | Priv *big.Int | ||
803 | } | ||
804 | rest, err := asn1.Unmarshal(der, &k) | ||
805 | if err != nil { | ||
806 | return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) | ||
807 | } | ||
808 | if len(rest) > 0 { | ||
809 | return nil, errors.New("ssh: garbage after DSA key") | ||
810 | } | ||
811 | |||
812 | return &dsa.PrivateKey{ | ||
813 | PublicKey: dsa.PublicKey{ | ||
814 | Parameters: dsa.Parameters{ | ||
815 | P: k.P, | ||
816 | Q: k.Q, | ||
817 | G: k.G, | ||
818 | }, | ||
819 | Y: k.Pub, | ||
820 | }, | ||
821 | X: k.Priv, | ||
822 | }, nil | ||
823 | } | ||
824 | |||
825 | // Implemented based on the documentation at | ||
826 | // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key | ||
827 | func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) { | ||
828 | magic := append([]byte("openssh-key-v1"), 0) | ||
829 | if !bytes.Equal(magic, key[0:len(magic)]) { | ||
830 | return nil, errors.New("ssh: invalid openssh private key format") | ||
831 | } | ||
832 | remaining := key[len(magic):] | ||
833 | |||
834 | var w struct { | ||
835 | CipherName string | ||
836 | KdfName string | ||
837 | KdfOpts string | ||
838 | NumKeys uint32 | ||
839 | PubKey []byte | ||
840 | PrivKeyBlock []byte | ||
841 | } | ||
842 | |||
843 | if err := Unmarshal(remaining, &w); err != nil { | ||
844 | return nil, err | ||
845 | } | ||
846 | |||
847 | pk1 := struct { | ||
848 | Check1 uint32 | ||
849 | Check2 uint32 | ||
850 | Keytype string | ||
851 | Pub []byte | ||
852 | Priv []byte | ||
853 | Comment string | ||
854 | Pad []byte `ssh:"rest"` | ||
855 | }{} | ||
856 | |||
857 | if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil { | ||
858 | return nil, err | ||
859 | } | ||
860 | |||
861 | if pk1.Check1 != pk1.Check2 { | ||
862 | return nil, errors.New("ssh: checkint mismatch") | ||
863 | } | ||
864 | |||
865 | // we only handle ed25519 keys currently | ||
866 | if pk1.Keytype != KeyAlgoED25519 { | ||
867 | return nil, errors.New("ssh: unhandled key type") | ||
868 | } | ||
869 | |||
870 | for i, b := range pk1.Pad { | ||
871 | if int(b) != i+1 { | ||
872 | return nil, errors.New("ssh: padding not as expected") | ||
873 | } | ||
874 | } | ||
875 | |||
876 | if len(pk1.Priv) != ed25519.PrivateKeySize { | ||
877 | return nil, errors.New("ssh: private key unexpected length") | ||
878 | } | ||
879 | |||
880 | pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) | ||
881 | copy(pk, pk1.Priv) | ||
882 | return &pk, nil | ||
883 | } | ||
884 | |||
885 | // FingerprintLegacyMD5 returns the user presentation of the key's | ||
886 | // fingerprint as described by RFC 4716 section 4. | ||
887 | func FingerprintLegacyMD5(pubKey PublicKey) string { | ||
888 | md5sum := md5.Sum(pubKey.Marshal()) | ||
889 | hexarray := make([]string, len(md5sum)) | ||
890 | for i, c := range md5sum { | ||
891 | hexarray[i] = hex.EncodeToString([]byte{c}) | ||
892 | } | ||
893 | return strings.Join(hexarray, ":") | ||
894 | } | ||
895 | |||
896 | // FingerprintSHA256 returns the user presentation of the key's | ||
897 | // fingerprint as unpadded base64 encoded sha256 hash. | ||
898 | // This format was introduced from OpenSSH 6.8. | ||
899 | // https://www.openssh.com/txt/release-6.8 | ||
900 | // https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding) | ||
901 | func FingerprintSHA256(pubKey PublicKey) string { | ||
902 | sha256sum := sha256.Sum256(pubKey.Marshal()) | ||
903 | hash := base64.RawStdEncoding.EncodeToString(sha256sum[:]) | ||
904 | return "SHA256:" + hash | ||
905 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/mac.go b/vendor/golang.org/x/crypto/ssh/mac.go new file mode 100644 index 0000000..c07a062 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mac.go | |||
@@ -0,0 +1,61 @@ | |||
1 | // Copyright 2012 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 | |||
5 | package ssh | ||
6 | |||
7 | // Message authentication support | ||
8 | |||
9 | import ( | ||
10 | "crypto/hmac" | ||
11 | "crypto/sha1" | ||
12 | "crypto/sha256" | ||
13 | "hash" | ||
14 | ) | ||
15 | |||
16 | type macMode struct { | ||
17 | keySize int | ||
18 | etm bool | ||
19 | new func(key []byte) hash.Hash | ||
20 | } | ||
21 | |||
22 | // truncatingMAC wraps around a hash.Hash and truncates the output digest to | ||
23 | // a given size. | ||
24 | type truncatingMAC struct { | ||
25 | length int | ||
26 | hmac hash.Hash | ||
27 | } | ||
28 | |||
29 | func (t truncatingMAC) Write(data []byte) (int, error) { | ||
30 | return t.hmac.Write(data) | ||
31 | } | ||
32 | |||
33 | func (t truncatingMAC) Sum(in []byte) []byte { | ||
34 | out := t.hmac.Sum(in) | ||
35 | return out[:len(in)+t.length] | ||
36 | } | ||
37 | |||
38 | func (t truncatingMAC) Reset() { | ||
39 | t.hmac.Reset() | ||
40 | } | ||
41 | |||
42 | func (t truncatingMAC) Size() int { | ||
43 | return t.length | ||
44 | } | ||
45 | |||
46 | func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() } | ||
47 | |||
48 | var macModes = map[string]*macMode{ | ||
49 | "hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash { | ||
50 | return hmac.New(sha256.New, key) | ||
51 | }}, | ||
52 | "hmac-sha2-256": {32, false, func(key []byte) hash.Hash { | ||
53 | return hmac.New(sha256.New, key) | ||
54 | }}, | ||
55 | "hmac-sha1": {20, false, func(key []byte) hash.Hash { | ||
56 | return hmac.New(sha1.New, key) | ||
57 | }}, | ||
58 | "hmac-sha1-96": {20, false, func(key []byte) hash.Hash { | ||
59 | return truncatingMAC{12, hmac.New(sha1.New, key)} | ||
60 | }}, | ||
61 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/messages.go b/vendor/golang.org/x/crypto/ssh/messages.go new file mode 100644 index 0000000..e6ecd3a --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/messages.go | |||
@@ -0,0 +1,758 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "encoding/binary" | ||
10 | "errors" | ||
11 | "fmt" | ||
12 | "io" | ||
13 | "math/big" | ||
14 | "reflect" | ||
15 | "strconv" | ||
16 | "strings" | ||
17 | ) | ||
18 | |||
19 | // These are SSH message type numbers. They are scattered around several | ||
20 | // documents but many were taken from [SSH-PARAMETERS]. | ||
21 | const ( | ||
22 | msgIgnore = 2 | ||
23 | msgUnimplemented = 3 | ||
24 | msgDebug = 4 | ||
25 | msgNewKeys = 21 | ||
26 | |||
27 | // Standard authentication messages | ||
28 | msgUserAuthSuccess = 52 | ||
29 | msgUserAuthBanner = 53 | ||
30 | ) | ||
31 | |||
32 | // SSH messages: | ||
33 | // | ||
34 | // These structures mirror the wire format of the corresponding SSH messages. | ||
35 | // They are marshaled using reflection with the marshal and unmarshal functions | ||
36 | // in this file. The only wrinkle is that a final member of type []byte with a | ||
37 | // ssh tag of "rest" receives the remainder of a packet when unmarshaling. | ||
38 | |||
39 | // See RFC 4253, section 11.1. | ||
40 | const msgDisconnect = 1 | ||
41 | |||
42 | // disconnectMsg is the message that signals a disconnect. It is also | ||
43 | // the error type returned from mux.Wait() | ||
44 | type disconnectMsg struct { | ||
45 | Reason uint32 `sshtype:"1"` | ||
46 | Message string | ||
47 | Language string | ||
48 | } | ||
49 | |||
50 | func (d *disconnectMsg) Error() string { | ||
51 | return fmt.Sprintf("ssh: disconnect, reason %d: %s", d.Reason, d.Message) | ||
52 | } | ||
53 | |||
54 | // See RFC 4253, section 7.1. | ||
55 | const msgKexInit = 20 | ||
56 | |||
57 | type kexInitMsg struct { | ||
58 | Cookie [16]byte `sshtype:"20"` | ||
59 | KexAlgos []string | ||
60 | ServerHostKeyAlgos []string | ||
61 | CiphersClientServer []string | ||
62 | CiphersServerClient []string | ||
63 | MACsClientServer []string | ||
64 | MACsServerClient []string | ||
65 | CompressionClientServer []string | ||
66 | CompressionServerClient []string | ||
67 | LanguagesClientServer []string | ||
68 | LanguagesServerClient []string | ||
69 | FirstKexFollows bool | ||
70 | Reserved uint32 | ||
71 | } | ||
72 | |||
73 | // See RFC 4253, section 8. | ||
74 | |||
75 | // Diffie-Helman | ||
76 | const msgKexDHInit = 30 | ||
77 | |||
78 | type kexDHInitMsg struct { | ||
79 | X *big.Int `sshtype:"30"` | ||
80 | } | ||
81 | |||
82 | const msgKexECDHInit = 30 | ||
83 | |||
84 | type kexECDHInitMsg struct { | ||
85 | ClientPubKey []byte `sshtype:"30"` | ||
86 | } | ||
87 | |||
88 | const msgKexECDHReply = 31 | ||
89 | |||
90 | type kexECDHReplyMsg struct { | ||
91 | HostKey []byte `sshtype:"31"` | ||
92 | EphemeralPubKey []byte | ||
93 | Signature []byte | ||
94 | } | ||
95 | |||
96 | const msgKexDHReply = 31 | ||
97 | |||
98 | type kexDHReplyMsg struct { | ||
99 | HostKey []byte `sshtype:"31"` | ||
100 | Y *big.Int | ||
101 | Signature []byte | ||
102 | } | ||
103 | |||
104 | // See RFC 4253, section 10. | ||
105 | const msgServiceRequest = 5 | ||
106 | |||
107 | type serviceRequestMsg struct { | ||
108 | Service string `sshtype:"5"` | ||
109 | } | ||
110 | |||
111 | // See RFC 4253, section 10. | ||
112 | const msgServiceAccept = 6 | ||
113 | |||
114 | type serviceAcceptMsg struct { | ||
115 | Service string `sshtype:"6"` | ||
116 | } | ||
117 | |||
118 | // See RFC 4252, section 5. | ||
119 | const msgUserAuthRequest = 50 | ||
120 | |||
121 | type userAuthRequestMsg struct { | ||
122 | User string `sshtype:"50"` | ||
123 | Service string | ||
124 | Method string | ||
125 | Payload []byte `ssh:"rest"` | ||
126 | } | ||
127 | |||
128 | // Used for debug printouts of packets. | ||
129 | type userAuthSuccessMsg struct { | ||
130 | } | ||
131 | |||
132 | // See RFC 4252, section 5.1 | ||
133 | const msgUserAuthFailure = 51 | ||
134 | |||
135 | type userAuthFailureMsg struct { | ||
136 | Methods []string `sshtype:"51"` | ||
137 | PartialSuccess bool | ||
138 | } | ||
139 | |||
140 | // See RFC 4256, section 3.2 | ||
141 | const msgUserAuthInfoRequest = 60 | ||
142 | const msgUserAuthInfoResponse = 61 | ||
143 | |||
144 | type userAuthInfoRequestMsg struct { | ||
145 | User string `sshtype:"60"` | ||
146 | Instruction string | ||
147 | DeprecatedLanguage string | ||
148 | NumPrompts uint32 | ||
149 | Prompts []byte `ssh:"rest"` | ||
150 | } | ||
151 | |||
152 | // See RFC 4254, section 5.1. | ||
153 | const msgChannelOpen = 90 | ||
154 | |||
155 | type channelOpenMsg struct { | ||
156 | ChanType string `sshtype:"90"` | ||
157 | PeersId uint32 | ||
158 | PeersWindow uint32 | ||
159 | MaxPacketSize uint32 | ||
160 | TypeSpecificData []byte `ssh:"rest"` | ||
161 | } | ||
162 | |||
163 | const msgChannelExtendedData = 95 | ||
164 | const msgChannelData = 94 | ||
165 | |||
166 | // Used for debug print outs of packets. | ||
167 | type channelDataMsg struct { | ||
168 | PeersId uint32 `sshtype:"94"` | ||
169 | Length uint32 | ||
170 | Rest []byte `ssh:"rest"` | ||
171 | } | ||
172 | |||
173 | // See RFC 4254, section 5.1. | ||
174 | const msgChannelOpenConfirm = 91 | ||
175 | |||
176 | type channelOpenConfirmMsg struct { | ||
177 | PeersId uint32 `sshtype:"91"` | ||
178 | MyId uint32 | ||
179 | MyWindow uint32 | ||
180 | MaxPacketSize uint32 | ||
181 | TypeSpecificData []byte `ssh:"rest"` | ||
182 | } | ||
183 | |||
184 | // See RFC 4254, section 5.1. | ||
185 | const msgChannelOpenFailure = 92 | ||
186 | |||
187 | type channelOpenFailureMsg struct { | ||
188 | PeersId uint32 `sshtype:"92"` | ||
189 | Reason RejectionReason | ||
190 | Message string | ||
191 | Language string | ||
192 | } | ||
193 | |||
194 | const msgChannelRequest = 98 | ||
195 | |||
196 | type channelRequestMsg struct { | ||
197 | PeersId uint32 `sshtype:"98"` | ||
198 | Request string | ||
199 | WantReply bool | ||
200 | RequestSpecificData []byte `ssh:"rest"` | ||
201 | } | ||
202 | |||
203 | // See RFC 4254, section 5.4. | ||
204 | const msgChannelSuccess = 99 | ||
205 | |||
206 | type channelRequestSuccessMsg struct { | ||
207 | PeersId uint32 `sshtype:"99"` | ||
208 | } | ||
209 | |||
210 | // See RFC 4254, section 5.4. | ||
211 | const msgChannelFailure = 100 | ||
212 | |||
213 | type channelRequestFailureMsg struct { | ||
214 | PeersId uint32 `sshtype:"100"` | ||
215 | } | ||
216 | |||
217 | // See RFC 4254, section 5.3 | ||
218 | const msgChannelClose = 97 | ||
219 | |||
220 | type channelCloseMsg struct { | ||
221 | PeersId uint32 `sshtype:"97"` | ||
222 | } | ||
223 | |||
224 | // See RFC 4254, section 5.3 | ||
225 | const msgChannelEOF = 96 | ||
226 | |||
227 | type channelEOFMsg struct { | ||
228 | PeersId uint32 `sshtype:"96"` | ||
229 | } | ||
230 | |||
231 | // See RFC 4254, section 4 | ||
232 | const msgGlobalRequest = 80 | ||
233 | |||
234 | type globalRequestMsg struct { | ||
235 | Type string `sshtype:"80"` | ||
236 | WantReply bool | ||
237 | Data []byte `ssh:"rest"` | ||
238 | } | ||
239 | |||
240 | // See RFC 4254, section 4 | ||
241 | const msgRequestSuccess = 81 | ||
242 | |||
243 | type globalRequestSuccessMsg struct { | ||
244 | Data []byte `ssh:"rest" sshtype:"81"` | ||
245 | } | ||
246 | |||
247 | // See RFC 4254, section 4 | ||
248 | const msgRequestFailure = 82 | ||
249 | |||
250 | type globalRequestFailureMsg struct { | ||
251 | Data []byte `ssh:"rest" sshtype:"82"` | ||
252 | } | ||
253 | |||
254 | // See RFC 4254, section 5.2 | ||
255 | const msgChannelWindowAdjust = 93 | ||
256 | |||
257 | type windowAdjustMsg struct { | ||
258 | PeersId uint32 `sshtype:"93"` | ||
259 | AdditionalBytes uint32 | ||
260 | } | ||
261 | |||
262 | // See RFC 4252, section 7 | ||
263 | const msgUserAuthPubKeyOk = 60 | ||
264 | |||
265 | type userAuthPubKeyOkMsg struct { | ||
266 | Algo string `sshtype:"60"` | ||
267 | PubKey []byte | ||
268 | } | ||
269 | |||
270 | // typeTags returns the possible type bytes for the given reflect.Type, which | ||
271 | // should be a struct. The possible values are separated by a '|' character. | ||
272 | func typeTags(structType reflect.Type) (tags []byte) { | ||
273 | tagStr := structType.Field(0).Tag.Get("sshtype") | ||
274 | |||
275 | for _, tag := range strings.Split(tagStr, "|") { | ||
276 | i, err := strconv.Atoi(tag) | ||
277 | if err == nil { | ||
278 | tags = append(tags, byte(i)) | ||
279 | } | ||
280 | } | ||
281 | |||
282 | return tags | ||
283 | } | ||
284 | |||
285 | func fieldError(t reflect.Type, field int, problem string) error { | ||
286 | if problem != "" { | ||
287 | problem = ": " + problem | ||
288 | } | ||
289 | return fmt.Errorf("ssh: unmarshal error for field %s of type %s%s", t.Field(field).Name, t.Name(), problem) | ||
290 | } | ||
291 | |||
292 | var errShortRead = errors.New("ssh: short read") | ||
293 | |||
294 | // Unmarshal parses data in SSH wire format into a structure. The out | ||
295 | // argument should be a pointer to struct. If the first member of the | ||
296 | // struct has the "sshtype" tag set to a '|'-separated set of numbers | ||
297 | // in decimal, the packet must start with one of those numbers. In | ||
298 | // case of error, Unmarshal returns a ParseError or | ||
299 | // UnexpectedMessageError. | ||
300 | func Unmarshal(data []byte, out interface{}) error { | ||
301 | v := reflect.ValueOf(out).Elem() | ||
302 | structType := v.Type() | ||
303 | expectedTypes := typeTags(structType) | ||
304 | |||
305 | var expectedType byte | ||
306 | if len(expectedTypes) > 0 { | ||
307 | expectedType = expectedTypes[0] | ||
308 | } | ||
309 | |||
310 | if len(data) == 0 { | ||
311 | return parseError(expectedType) | ||
312 | } | ||
313 | |||
314 | if len(expectedTypes) > 0 { | ||
315 | goodType := false | ||
316 | for _, e := range expectedTypes { | ||
317 | if e > 0 && data[0] == e { | ||
318 | goodType = true | ||
319 | break | ||
320 | } | ||
321 | } | ||
322 | if !goodType { | ||
323 | return fmt.Errorf("ssh: unexpected message type %d (expected one of %v)", data[0], expectedTypes) | ||
324 | } | ||
325 | data = data[1:] | ||
326 | } | ||
327 | |||
328 | var ok bool | ||
329 | for i := 0; i < v.NumField(); i++ { | ||
330 | field := v.Field(i) | ||
331 | t := field.Type() | ||
332 | switch t.Kind() { | ||
333 | case reflect.Bool: | ||
334 | if len(data) < 1 { | ||
335 | return errShortRead | ||
336 | } | ||
337 | field.SetBool(data[0] != 0) | ||
338 | data = data[1:] | ||
339 | case reflect.Array: | ||
340 | if t.Elem().Kind() != reflect.Uint8 { | ||
341 | return fieldError(structType, i, "array of unsupported type") | ||
342 | } | ||
343 | if len(data) < t.Len() { | ||
344 | return errShortRead | ||
345 | } | ||
346 | for j, n := 0, t.Len(); j < n; j++ { | ||
347 | field.Index(j).Set(reflect.ValueOf(data[j])) | ||
348 | } | ||
349 | data = data[t.Len():] | ||
350 | case reflect.Uint64: | ||
351 | var u64 uint64 | ||
352 | if u64, data, ok = parseUint64(data); !ok { | ||
353 | return errShortRead | ||
354 | } | ||
355 | field.SetUint(u64) | ||
356 | case reflect.Uint32: | ||
357 | var u32 uint32 | ||
358 | if u32, data, ok = parseUint32(data); !ok { | ||
359 | return errShortRead | ||
360 | } | ||
361 | field.SetUint(uint64(u32)) | ||
362 | case reflect.Uint8: | ||
363 | if len(data) < 1 { | ||
364 | return errShortRead | ||
365 | } | ||
366 | field.SetUint(uint64(data[0])) | ||
367 | data = data[1:] | ||
368 | case reflect.String: | ||
369 | var s []byte | ||
370 | if s, data, ok = parseString(data); !ok { | ||
371 | return fieldError(structType, i, "") | ||
372 | } | ||
373 | field.SetString(string(s)) | ||
374 | case reflect.Slice: | ||
375 | switch t.Elem().Kind() { | ||
376 | case reflect.Uint8: | ||
377 | if structType.Field(i).Tag.Get("ssh") == "rest" { | ||
378 | field.Set(reflect.ValueOf(data)) | ||
379 | data = nil | ||
380 | } else { | ||
381 | var s []byte | ||
382 | if s, data, ok = parseString(data); !ok { | ||
383 | return errShortRead | ||
384 | } | ||
385 | field.Set(reflect.ValueOf(s)) | ||
386 | } | ||
387 | case reflect.String: | ||
388 | var nl []string | ||
389 | if nl, data, ok = parseNameList(data); !ok { | ||
390 | return errShortRead | ||
391 | } | ||
392 | field.Set(reflect.ValueOf(nl)) | ||
393 | default: | ||
394 | return fieldError(structType, i, "slice of unsupported type") | ||
395 | } | ||
396 | case reflect.Ptr: | ||
397 | if t == bigIntType { | ||
398 | var n *big.Int | ||
399 | if n, data, ok = parseInt(data); !ok { | ||
400 | return errShortRead | ||
401 | } | ||
402 | field.Set(reflect.ValueOf(n)) | ||
403 | } else { | ||
404 | return fieldError(structType, i, "pointer to unsupported type") | ||
405 | } | ||
406 | default: | ||
407 | return fieldError(structType, i, fmt.Sprintf("unsupported type: %v", t)) | ||
408 | } | ||
409 | } | ||
410 | |||
411 | if len(data) != 0 { | ||
412 | return parseError(expectedType) | ||
413 | } | ||
414 | |||
415 | return nil | ||
416 | } | ||
417 | |||
418 | // Marshal serializes the message in msg to SSH wire format. The msg | ||
419 | // argument should be a struct or pointer to struct. If the first | ||
420 | // member has the "sshtype" tag set to a number in decimal, that | ||
421 | // number is prepended to the result. If the last of member has the | ||
422 | // "ssh" tag set to "rest", its contents are appended to the output. | ||
423 | func Marshal(msg interface{}) []byte { | ||
424 | out := make([]byte, 0, 64) | ||
425 | return marshalStruct(out, msg) | ||
426 | } | ||
427 | |||
428 | func marshalStruct(out []byte, msg interface{}) []byte { | ||
429 | v := reflect.Indirect(reflect.ValueOf(msg)) | ||
430 | msgTypes := typeTags(v.Type()) | ||
431 | if len(msgTypes) > 0 { | ||
432 | out = append(out, msgTypes[0]) | ||
433 | } | ||
434 | |||
435 | for i, n := 0, v.NumField(); i < n; i++ { | ||
436 | field := v.Field(i) | ||
437 | switch t := field.Type(); t.Kind() { | ||
438 | case reflect.Bool: | ||
439 | var v uint8 | ||
440 | if field.Bool() { | ||
441 | v = 1 | ||
442 | } | ||
443 | out = append(out, v) | ||
444 | case reflect.Array: | ||
445 | if t.Elem().Kind() != reflect.Uint8 { | ||
446 | panic(fmt.Sprintf("array of non-uint8 in field %d: %T", i, field.Interface())) | ||
447 | } | ||
448 | for j, l := 0, t.Len(); j < l; j++ { | ||
449 | out = append(out, uint8(field.Index(j).Uint())) | ||
450 | } | ||
451 | case reflect.Uint32: | ||
452 | out = appendU32(out, uint32(field.Uint())) | ||
453 | case reflect.Uint64: | ||
454 | out = appendU64(out, uint64(field.Uint())) | ||
455 | case reflect.Uint8: | ||
456 | out = append(out, uint8(field.Uint())) | ||
457 | case reflect.String: | ||
458 | s := field.String() | ||
459 | out = appendInt(out, len(s)) | ||
460 | out = append(out, s...) | ||
461 | case reflect.Slice: | ||
462 | switch t.Elem().Kind() { | ||
463 | case reflect.Uint8: | ||
464 | if v.Type().Field(i).Tag.Get("ssh") != "rest" { | ||
465 | out = appendInt(out, field.Len()) | ||
466 | } | ||
467 | out = append(out, field.Bytes()...) | ||
468 | case reflect.String: | ||
469 | offset := len(out) | ||
470 | out = appendU32(out, 0) | ||
471 | if n := field.Len(); n > 0 { | ||
472 | for j := 0; j < n; j++ { | ||
473 | f := field.Index(j) | ||
474 | if j != 0 { | ||
475 | out = append(out, ',') | ||
476 | } | ||
477 | out = append(out, f.String()...) | ||
478 | } | ||
479 | // overwrite length value | ||
480 | binary.BigEndian.PutUint32(out[offset:], uint32(len(out)-offset-4)) | ||
481 | } | ||
482 | default: | ||
483 | panic(fmt.Sprintf("slice of unknown type in field %d: %T", i, field.Interface())) | ||
484 | } | ||
485 | case reflect.Ptr: | ||
486 | if t == bigIntType { | ||
487 | var n *big.Int | ||
488 | nValue := reflect.ValueOf(&n) | ||
489 | nValue.Elem().Set(field) | ||
490 | needed := intLength(n) | ||
491 | oldLength := len(out) | ||
492 | |||
493 | if cap(out)-len(out) < needed { | ||
494 | newOut := make([]byte, len(out), 2*(len(out)+needed)) | ||
495 | copy(newOut, out) | ||
496 | out = newOut | ||
497 | } | ||
498 | out = out[:oldLength+needed] | ||
499 | marshalInt(out[oldLength:], n) | ||
500 | } else { | ||
501 | panic(fmt.Sprintf("pointer to unknown type in field %d: %T", i, field.Interface())) | ||
502 | } | ||
503 | } | ||
504 | } | ||
505 | |||
506 | return out | ||
507 | } | ||
508 | |||
509 | var bigOne = big.NewInt(1) | ||
510 | |||
511 | func parseString(in []byte) (out, rest []byte, ok bool) { | ||
512 | if len(in) < 4 { | ||
513 | return | ||
514 | } | ||
515 | length := binary.BigEndian.Uint32(in) | ||
516 | in = in[4:] | ||
517 | if uint32(len(in)) < length { | ||
518 | return | ||
519 | } | ||
520 | out = in[:length] | ||
521 | rest = in[length:] | ||
522 | ok = true | ||
523 | return | ||
524 | } | ||
525 | |||
526 | var ( | ||
527 | comma = []byte{','} | ||
528 | emptyNameList = []string{} | ||
529 | ) | ||
530 | |||
531 | func parseNameList(in []byte) (out []string, rest []byte, ok bool) { | ||
532 | contents, rest, ok := parseString(in) | ||
533 | if !ok { | ||
534 | return | ||
535 | } | ||
536 | if len(contents) == 0 { | ||
537 | out = emptyNameList | ||
538 | return | ||
539 | } | ||
540 | parts := bytes.Split(contents, comma) | ||
541 | out = make([]string, len(parts)) | ||
542 | for i, part := range parts { | ||
543 | out[i] = string(part) | ||
544 | } | ||
545 | return | ||
546 | } | ||
547 | |||
548 | func parseInt(in []byte) (out *big.Int, rest []byte, ok bool) { | ||
549 | contents, rest, ok := parseString(in) | ||
550 | if !ok { | ||
551 | return | ||
552 | } | ||
553 | out = new(big.Int) | ||
554 | |||
555 | if len(contents) > 0 && contents[0]&0x80 == 0x80 { | ||
556 | // This is a negative number | ||
557 | notBytes := make([]byte, len(contents)) | ||
558 | for i := range notBytes { | ||
559 | notBytes[i] = ^contents[i] | ||
560 | } | ||
561 | out.SetBytes(notBytes) | ||
562 | out.Add(out, bigOne) | ||
563 | out.Neg(out) | ||
564 | } else { | ||
565 | // Positive number | ||
566 | out.SetBytes(contents) | ||
567 | } | ||
568 | ok = true | ||
569 | return | ||
570 | } | ||
571 | |||
572 | func parseUint32(in []byte) (uint32, []byte, bool) { | ||
573 | if len(in) < 4 { | ||
574 | return 0, nil, false | ||
575 | } | ||
576 | return binary.BigEndian.Uint32(in), in[4:], true | ||
577 | } | ||
578 | |||
579 | func parseUint64(in []byte) (uint64, []byte, bool) { | ||
580 | if len(in) < 8 { | ||
581 | return 0, nil, false | ||
582 | } | ||
583 | return binary.BigEndian.Uint64(in), in[8:], true | ||
584 | } | ||
585 | |||
586 | func intLength(n *big.Int) int { | ||
587 | length := 4 /* length bytes */ | ||
588 | if n.Sign() < 0 { | ||
589 | nMinus1 := new(big.Int).Neg(n) | ||
590 | nMinus1.Sub(nMinus1, bigOne) | ||
591 | bitLen := nMinus1.BitLen() | ||
592 | if bitLen%8 == 0 { | ||
593 | // The number will need 0xff padding | ||
594 | length++ | ||
595 | } | ||
596 | length += (bitLen + 7) / 8 | ||
597 | } else if n.Sign() == 0 { | ||
598 | // A zero is the zero length string | ||
599 | } else { | ||
600 | bitLen := n.BitLen() | ||
601 | if bitLen%8 == 0 { | ||
602 | // The number will need 0x00 padding | ||
603 | length++ | ||
604 | } | ||
605 | length += (bitLen + 7) / 8 | ||
606 | } | ||
607 | |||
608 | return length | ||
609 | } | ||
610 | |||
611 | func marshalUint32(to []byte, n uint32) []byte { | ||
612 | binary.BigEndian.PutUint32(to, n) | ||
613 | return to[4:] | ||
614 | } | ||
615 | |||
616 | func marshalUint64(to []byte, n uint64) []byte { | ||
617 | binary.BigEndian.PutUint64(to, n) | ||
618 | return to[8:] | ||
619 | } | ||
620 | |||
621 | func marshalInt(to []byte, n *big.Int) []byte { | ||
622 | lengthBytes := to | ||
623 | to = to[4:] | ||
624 | length := 0 | ||
625 | |||
626 | if n.Sign() < 0 { | ||
627 | // A negative number has to be converted to two's-complement | ||
628 | // form. So we'll subtract 1 and invert. If the | ||
629 | // most-significant-bit isn't set then we'll need to pad the | ||
630 | // beginning with 0xff in order to keep the number negative. | ||
631 | nMinus1 := new(big.Int).Neg(n) | ||
632 | nMinus1.Sub(nMinus1, bigOne) | ||
633 | bytes := nMinus1.Bytes() | ||
634 | for i := range bytes { | ||
635 | bytes[i] ^= 0xff | ||
636 | } | ||
637 | if len(bytes) == 0 || bytes[0]&0x80 == 0 { | ||
638 | to[0] = 0xff | ||
639 | to = to[1:] | ||
640 | length++ | ||
641 | } | ||
642 | nBytes := copy(to, bytes) | ||
643 | to = to[nBytes:] | ||
644 | length += nBytes | ||
645 | } else if n.Sign() == 0 { | ||
646 | // A zero is the zero length string | ||
647 | } else { | ||
648 | bytes := n.Bytes() | ||
649 | if len(bytes) > 0 && bytes[0]&0x80 != 0 { | ||
650 | // We'll have to pad this with a 0x00 in order to | ||
651 | // stop it looking like a negative number. | ||
652 | to[0] = 0 | ||
653 | to = to[1:] | ||
654 | length++ | ||
655 | } | ||
656 | nBytes := copy(to, bytes) | ||
657 | to = to[nBytes:] | ||
658 | length += nBytes | ||
659 | } | ||
660 | |||
661 | lengthBytes[0] = byte(length >> 24) | ||
662 | lengthBytes[1] = byte(length >> 16) | ||
663 | lengthBytes[2] = byte(length >> 8) | ||
664 | lengthBytes[3] = byte(length) | ||
665 | return to | ||
666 | } | ||
667 | |||
668 | func writeInt(w io.Writer, n *big.Int) { | ||
669 | length := intLength(n) | ||
670 | buf := make([]byte, length) | ||
671 | marshalInt(buf, n) | ||
672 | w.Write(buf) | ||
673 | } | ||
674 | |||
675 | func writeString(w io.Writer, s []byte) { | ||
676 | var lengthBytes [4]byte | ||
677 | lengthBytes[0] = byte(len(s) >> 24) | ||
678 | lengthBytes[1] = byte(len(s) >> 16) | ||
679 | lengthBytes[2] = byte(len(s) >> 8) | ||
680 | lengthBytes[3] = byte(len(s)) | ||
681 | w.Write(lengthBytes[:]) | ||
682 | w.Write(s) | ||
683 | } | ||
684 | |||
685 | func stringLength(n int) int { | ||
686 | return 4 + n | ||
687 | } | ||
688 | |||
689 | func marshalString(to []byte, s []byte) []byte { | ||
690 | to[0] = byte(len(s) >> 24) | ||
691 | to[1] = byte(len(s) >> 16) | ||
692 | to[2] = byte(len(s) >> 8) | ||
693 | to[3] = byte(len(s)) | ||
694 | to = to[4:] | ||
695 | copy(to, s) | ||
696 | return to[len(s):] | ||
697 | } | ||
698 | |||
699 | var bigIntType = reflect.TypeOf((*big.Int)(nil)) | ||
700 | |||
701 | // Decode a packet into its corresponding message. | ||
702 | func decode(packet []byte) (interface{}, error) { | ||
703 | var msg interface{} | ||
704 | switch packet[0] { | ||
705 | case msgDisconnect: | ||
706 | msg = new(disconnectMsg) | ||
707 | case msgServiceRequest: | ||
708 | msg = new(serviceRequestMsg) | ||
709 | case msgServiceAccept: | ||
710 | msg = new(serviceAcceptMsg) | ||
711 | case msgKexInit: | ||
712 | msg = new(kexInitMsg) | ||
713 | case msgKexDHInit: | ||
714 | msg = new(kexDHInitMsg) | ||
715 | case msgKexDHReply: | ||
716 | msg = new(kexDHReplyMsg) | ||
717 | case msgUserAuthRequest: | ||
718 | msg = new(userAuthRequestMsg) | ||
719 | case msgUserAuthSuccess: | ||
720 | return new(userAuthSuccessMsg), nil | ||
721 | case msgUserAuthFailure: | ||
722 | msg = new(userAuthFailureMsg) | ||
723 | case msgUserAuthPubKeyOk: | ||
724 | msg = new(userAuthPubKeyOkMsg) | ||
725 | case msgGlobalRequest: | ||
726 | msg = new(globalRequestMsg) | ||
727 | case msgRequestSuccess: | ||
728 | msg = new(globalRequestSuccessMsg) | ||
729 | case msgRequestFailure: | ||
730 | msg = new(globalRequestFailureMsg) | ||
731 | case msgChannelOpen: | ||
732 | msg = new(channelOpenMsg) | ||
733 | case msgChannelData: | ||
734 | msg = new(channelDataMsg) | ||
735 | case msgChannelOpenConfirm: | ||
736 | msg = new(channelOpenConfirmMsg) | ||
737 | case msgChannelOpenFailure: | ||
738 | msg = new(channelOpenFailureMsg) | ||
739 | case msgChannelWindowAdjust: | ||
740 | msg = new(windowAdjustMsg) | ||
741 | case msgChannelEOF: | ||
742 | msg = new(channelEOFMsg) | ||
743 | case msgChannelClose: | ||
744 | msg = new(channelCloseMsg) | ||
745 | case msgChannelRequest: | ||
746 | msg = new(channelRequestMsg) | ||
747 | case msgChannelSuccess: | ||
748 | msg = new(channelRequestSuccessMsg) | ||
749 | case msgChannelFailure: | ||
750 | msg = new(channelRequestFailureMsg) | ||
751 | default: | ||
752 | return nil, unexpectedMessageError(0, packet[0]) | ||
753 | } | ||
754 | if err := Unmarshal(packet, msg); err != nil { | ||
755 | return nil, err | ||
756 | } | ||
757 | return msg, nil | ||
758 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/mux.go b/vendor/golang.org/x/crypto/ssh/mux.go new file mode 100644 index 0000000..27a527c --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/mux.go | |||
@@ -0,0 +1,330 @@ | |||
1 | // Copyright 2013 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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "encoding/binary" | ||
9 | "fmt" | ||
10 | "io" | ||
11 | "log" | ||
12 | "sync" | ||
13 | "sync/atomic" | ||
14 | ) | ||
15 | |||
16 | // debugMux, if set, causes messages in the connection protocol to be | ||
17 | // logged. | ||
18 | const debugMux = false | ||
19 | |||
20 | // chanList is a thread safe channel list. | ||
21 | type chanList struct { | ||
22 | // protects concurrent access to chans | ||
23 | sync.Mutex | ||
24 | |||
25 | // chans are indexed by the local id of the channel, which the | ||
26 | // other side should send in the PeersId field. | ||
27 | chans []*channel | ||
28 | |||
29 | // This is a debugging aid: it offsets all IDs by this | ||
30 | // amount. This helps distinguish otherwise identical | ||
31 | // server/client muxes | ||
32 | offset uint32 | ||
33 | } | ||
34 | |||
35 | // Assigns a channel ID to the given channel. | ||
36 | func (c *chanList) add(ch *channel) uint32 { | ||
37 | c.Lock() | ||
38 | defer c.Unlock() | ||
39 | for i := range c.chans { | ||
40 | if c.chans[i] == nil { | ||
41 | c.chans[i] = ch | ||
42 | return uint32(i) + c.offset | ||
43 | } | ||
44 | } | ||
45 | c.chans = append(c.chans, ch) | ||
46 | return uint32(len(c.chans)-1) + c.offset | ||
47 | } | ||
48 | |||
49 | // getChan returns the channel for the given ID. | ||
50 | func (c *chanList) getChan(id uint32) *channel { | ||
51 | id -= c.offset | ||
52 | |||
53 | c.Lock() | ||
54 | defer c.Unlock() | ||
55 | if id < uint32(len(c.chans)) { | ||
56 | return c.chans[id] | ||
57 | } | ||
58 | return nil | ||
59 | } | ||
60 | |||
61 | func (c *chanList) remove(id uint32) { | ||
62 | id -= c.offset | ||
63 | c.Lock() | ||
64 | if id < uint32(len(c.chans)) { | ||
65 | c.chans[id] = nil | ||
66 | } | ||
67 | c.Unlock() | ||
68 | } | ||
69 | |||
70 | // dropAll forgets all channels it knows, returning them in a slice. | ||
71 | func (c *chanList) dropAll() []*channel { | ||
72 | c.Lock() | ||
73 | defer c.Unlock() | ||
74 | var r []*channel | ||
75 | |||
76 | for _, ch := range c.chans { | ||
77 | if ch == nil { | ||
78 | continue | ||
79 | } | ||
80 | r = append(r, ch) | ||
81 | } | ||
82 | c.chans = nil | ||
83 | return r | ||
84 | } | ||
85 | |||
86 | // mux represents the state for the SSH connection protocol, which | ||
87 | // multiplexes many channels onto a single packet transport. | ||
88 | type mux struct { | ||
89 | conn packetConn | ||
90 | chanList chanList | ||
91 | |||
92 | incomingChannels chan NewChannel | ||
93 | |||
94 | globalSentMu sync.Mutex | ||
95 | globalResponses chan interface{} | ||
96 | incomingRequests chan *Request | ||
97 | |||
98 | errCond *sync.Cond | ||
99 | err error | ||
100 | } | ||
101 | |||
102 | // When debugging, each new chanList instantiation has a different | ||
103 | // offset. | ||
104 | var globalOff uint32 | ||
105 | |||
106 | func (m *mux) Wait() error { | ||
107 | m.errCond.L.Lock() | ||
108 | defer m.errCond.L.Unlock() | ||
109 | for m.err == nil { | ||
110 | m.errCond.Wait() | ||
111 | } | ||
112 | return m.err | ||
113 | } | ||
114 | |||
115 | // newMux returns a mux that runs over the given connection. | ||
116 | func newMux(p packetConn) *mux { | ||
117 | m := &mux{ | ||
118 | conn: p, | ||
119 | incomingChannels: make(chan NewChannel, chanSize), | ||
120 | globalResponses: make(chan interface{}, 1), | ||
121 | incomingRequests: make(chan *Request, chanSize), | ||
122 | errCond: newCond(), | ||
123 | } | ||
124 | if debugMux { | ||
125 | m.chanList.offset = atomic.AddUint32(&globalOff, 1) | ||
126 | } | ||
127 | |||
128 | go m.loop() | ||
129 | return m | ||
130 | } | ||
131 | |||
132 | func (m *mux) sendMessage(msg interface{}) error { | ||
133 | p := Marshal(msg) | ||
134 | if debugMux { | ||
135 | log.Printf("send global(%d): %#v", m.chanList.offset, msg) | ||
136 | } | ||
137 | return m.conn.writePacket(p) | ||
138 | } | ||
139 | |||
140 | func (m *mux) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { | ||
141 | if wantReply { | ||
142 | m.globalSentMu.Lock() | ||
143 | defer m.globalSentMu.Unlock() | ||
144 | } | ||
145 | |||
146 | if err := m.sendMessage(globalRequestMsg{ | ||
147 | Type: name, | ||
148 | WantReply: wantReply, | ||
149 | Data: payload, | ||
150 | }); err != nil { | ||
151 | return false, nil, err | ||
152 | } | ||
153 | |||
154 | if !wantReply { | ||
155 | return false, nil, nil | ||
156 | } | ||
157 | |||
158 | msg, ok := <-m.globalResponses | ||
159 | if !ok { | ||
160 | return false, nil, io.EOF | ||
161 | } | ||
162 | switch msg := msg.(type) { | ||
163 | case *globalRequestFailureMsg: | ||
164 | return false, msg.Data, nil | ||
165 | case *globalRequestSuccessMsg: | ||
166 | return true, msg.Data, nil | ||
167 | default: | ||
168 | return false, nil, fmt.Errorf("ssh: unexpected response to request: %#v", msg) | ||
169 | } | ||
170 | } | ||
171 | |||
172 | // ackRequest must be called after processing a global request that | ||
173 | // has WantReply set. | ||
174 | func (m *mux) ackRequest(ok bool, data []byte) error { | ||
175 | if ok { | ||
176 | return m.sendMessage(globalRequestSuccessMsg{Data: data}) | ||
177 | } | ||
178 | return m.sendMessage(globalRequestFailureMsg{Data: data}) | ||
179 | } | ||
180 | |||
181 | func (m *mux) Close() error { | ||
182 | return m.conn.Close() | ||
183 | } | ||
184 | |||
185 | // loop runs the connection machine. It will process packets until an | ||
186 | // error is encountered. To synchronize on loop exit, use mux.Wait. | ||
187 | func (m *mux) loop() { | ||
188 | var err error | ||
189 | for err == nil { | ||
190 | err = m.onePacket() | ||
191 | } | ||
192 | |||
193 | for _, ch := range m.chanList.dropAll() { | ||
194 | ch.close() | ||
195 | } | ||
196 | |||
197 | close(m.incomingChannels) | ||
198 | close(m.incomingRequests) | ||
199 | close(m.globalResponses) | ||
200 | |||
201 | m.conn.Close() | ||
202 | |||
203 | m.errCond.L.Lock() | ||
204 | m.err = err | ||
205 | m.errCond.Broadcast() | ||
206 | m.errCond.L.Unlock() | ||
207 | |||
208 | if debugMux { | ||
209 | log.Println("loop exit", err) | ||
210 | } | ||
211 | } | ||
212 | |||
213 | // onePacket reads and processes one packet. | ||
214 | func (m *mux) onePacket() error { | ||
215 | packet, err := m.conn.readPacket() | ||
216 | if err != nil { | ||
217 | return err | ||
218 | } | ||
219 | |||
220 | if debugMux { | ||
221 | if packet[0] == msgChannelData || packet[0] == msgChannelExtendedData { | ||
222 | log.Printf("decoding(%d): data packet - %d bytes", m.chanList.offset, len(packet)) | ||
223 | } else { | ||
224 | p, _ := decode(packet) | ||
225 | log.Printf("decoding(%d): %d %#v - %d bytes", m.chanList.offset, packet[0], p, len(packet)) | ||
226 | } | ||
227 | } | ||
228 | |||
229 | switch packet[0] { | ||
230 | case msgChannelOpen: | ||
231 | return m.handleChannelOpen(packet) | ||
232 | case msgGlobalRequest, msgRequestSuccess, msgRequestFailure: | ||
233 | return m.handleGlobalPacket(packet) | ||
234 | } | ||
235 | |||
236 | // assume a channel packet. | ||
237 | if len(packet) < 5 { | ||
238 | return parseError(packet[0]) | ||
239 | } | ||
240 | id := binary.BigEndian.Uint32(packet[1:]) | ||
241 | ch := m.chanList.getChan(id) | ||
242 | if ch == nil { | ||
243 | return fmt.Errorf("ssh: invalid channel %d", id) | ||
244 | } | ||
245 | |||
246 | return ch.handlePacket(packet) | ||
247 | } | ||
248 | |||
249 | func (m *mux) handleGlobalPacket(packet []byte) error { | ||
250 | msg, err := decode(packet) | ||
251 | if err != nil { | ||
252 | return err | ||
253 | } | ||
254 | |||
255 | switch msg := msg.(type) { | ||
256 | case *globalRequestMsg: | ||
257 | m.incomingRequests <- &Request{ | ||
258 | Type: msg.Type, | ||
259 | WantReply: msg.WantReply, | ||
260 | Payload: msg.Data, | ||
261 | mux: m, | ||
262 | } | ||
263 | case *globalRequestSuccessMsg, *globalRequestFailureMsg: | ||
264 | m.globalResponses <- msg | ||
265 | default: | ||
266 | panic(fmt.Sprintf("not a global message %#v", msg)) | ||
267 | } | ||
268 | |||
269 | return nil | ||
270 | } | ||
271 | |||
272 | // handleChannelOpen schedules a channel to be Accept()ed. | ||
273 | func (m *mux) handleChannelOpen(packet []byte) error { | ||
274 | var msg channelOpenMsg | ||
275 | if err := Unmarshal(packet, &msg); err != nil { | ||
276 | return err | ||
277 | } | ||
278 | |||
279 | if msg.MaxPacketSize < minPacketLength || msg.MaxPacketSize > 1<<31 { | ||
280 | failMsg := channelOpenFailureMsg{ | ||
281 | PeersId: msg.PeersId, | ||
282 | Reason: ConnectionFailed, | ||
283 | Message: "invalid request", | ||
284 | Language: "en_US.UTF-8", | ||
285 | } | ||
286 | return m.sendMessage(failMsg) | ||
287 | } | ||
288 | |||
289 | c := m.newChannel(msg.ChanType, channelInbound, msg.TypeSpecificData) | ||
290 | c.remoteId = msg.PeersId | ||
291 | c.maxRemotePayload = msg.MaxPacketSize | ||
292 | c.remoteWin.add(msg.PeersWindow) | ||
293 | m.incomingChannels <- c | ||
294 | return nil | ||
295 | } | ||
296 | |||
297 | func (m *mux) OpenChannel(chanType string, extra []byte) (Channel, <-chan *Request, error) { | ||
298 | ch, err := m.openChannel(chanType, extra) | ||
299 | if err != nil { | ||
300 | return nil, nil, err | ||
301 | } | ||
302 | |||
303 | return ch, ch.incomingRequests, nil | ||
304 | } | ||
305 | |||
306 | func (m *mux) openChannel(chanType string, extra []byte) (*channel, error) { | ||
307 | ch := m.newChannel(chanType, channelOutbound, extra) | ||
308 | |||
309 | ch.maxIncomingPayload = channelMaxPacket | ||
310 | |||
311 | open := channelOpenMsg{ | ||
312 | ChanType: chanType, | ||
313 | PeersWindow: ch.myWindow, | ||
314 | MaxPacketSize: ch.maxIncomingPayload, | ||
315 | TypeSpecificData: extra, | ||
316 | PeersId: ch.localId, | ||
317 | } | ||
318 | if err := m.sendMessage(open); err != nil { | ||
319 | return nil, err | ||
320 | } | ||
321 | |||
322 | switch msg := (<-ch.msg).(type) { | ||
323 | case *channelOpenConfirmMsg: | ||
324 | return ch, nil | ||
325 | case *channelOpenFailureMsg: | ||
326 | return nil, &OpenChannelError{msg.Reason, msg.Message} | ||
327 | default: | ||
328 | return nil, fmt.Errorf("ssh: unexpected packet in response to channel open: %T", msg) | ||
329 | } | ||
330 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go new file mode 100644 index 0000000..77c84d1 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/server.go | |||
@@ -0,0 +1,491 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "errors" | ||
10 | "fmt" | ||
11 | "io" | ||
12 | "net" | ||
13 | "strings" | ||
14 | ) | ||
15 | |||
16 | // The Permissions type holds fine-grained permissions that are | ||
17 | // specific to a user or a specific authentication method for a | ||
18 | // user. Permissions, except for "source-address", must be enforced in | ||
19 | // the server application layer, after successful authentication. The | ||
20 | // Permissions are passed on in ServerConn so a server implementation | ||
21 | // can honor them. | ||
22 | type Permissions struct { | ||
23 | // Critical options restrict default permissions. Common | ||
24 | // restrictions are "source-address" and "force-command". If | ||
25 | // the server cannot enforce the restriction, or does not | ||
26 | // recognize it, the user should not authenticate. | ||
27 | CriticalOptions map[string]string | ||
28 | |||
29 | // Extensions are extra functionality that the server may | ||
30 | // offer on authenticated connections. Common extensions are | ||
31 | // "permit-agent-forwarding", "permit-X11-forwarding". Lack of | ||
32 | // support for an extension does not preclude authenticating a | ||
33 | // user. | ||
34 | Extensions map[string]string | ||
35 | } | ||
36 | |||
37 | // ServerConfig holds server specific configuration data. | ||
38 | type ServerConfig struct { | ||
39 | // Config contains configuration shared between client and server. | ||
40 | Config | ||
41 | |||
42 | hostKeys []Signer | ||
43 | |||
44 | // NoClientAuth is true if clients are allowed to connect without | ||
45 | // authenticating. | ||
46 | NoClientAuth bool | ||
47 | |||
48 | // PasswordCallback, if non-nil, is called when a user | ||
49 | // attempts to authenticate using a password. | ||
50 | PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error) | ||
51 | |||
52 | // PublicKeyCallback, if non-nil, is called when a client attempts public | ||
53 | // key authentication. It must return true if the given public key is | ||
54 | // valid for the given user. For example, see CertChecker.Authenticate. | ||
55 | PublicKeyCallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) | ||
56 | |||
57 | // KeyboardInteractiveCallback, if non-nil, is called when | ||
58 | // keyboard-interactive authentication is selected (RFC | ||
59 | // 4256). The client object's Challenge function should be | ||
60 | // used to query the user. The callback may offer multiple | ||
61 | // Challenge rounds. To avoid information leaks, the client | ||
62 | // should be presented a challenge even if the user is | ||
63 | // unknown. | ||
64 | KeyboardInteractiveCallback func(conn ConnMetadata, client KeyboardInteractiveChallenge) (*Permissions, error) | ||
65 | |||
66 | // AuthLogCallback, if non-nil, is called to log all authentication | ||
67 | // attempts. | ||
68 | AuthLogCallback func(conn ConnMetadata, method string, err error) | ||
69 | |||
70 | // ServerVersion is the version identification string to announce in | ||
71 | // the public handshake. | ||
72 | // If empty, a reasonable default is used. | ||
73 | // Note that RFC 4253 section 4.2 requires that this string start with | ||
74 | // "SSH-2.0-". | ||
75 | ServerVersion string | ||
76 | } | ||
77 | |||
78 | // AddHostKey adds a private key as a host key. If an existing host | ||
79 | // key exists with the same algorithm, it is overwritten. Each server | ||
80 | // config must have at least one host key. | ||
81 | func (s *ServerConfig) AddHostKey(key Signer) { | ||
82 | for i, k := range s.hostKeys { | ||
83 | if k.PublicKey().Type() == key.PublicKey().Type() { | ||
84 | s.hostKeys[i] = key | ||
85 | return | ||
86 | } | ||
87 | } | ||
88 | |||
89 | s.hostKeys = append(s.hostKeys, key) | ||
90 | } | ||
91 | |||
92 | // cachedPubKey contains the results of querying whether a public key is | ||
93 | // acceptable for a user. | ||
94 | type cachedPubKey struct { | ||
95 | user string | ||
96 | pubKeyData []byte | ||
97 | result error | ||
98 | perms *Permissions | ||
99 | } | ||
100 | |||
101 | const maxCachedPubKeys = 16 | ||
102 | |||
103 | // pubKeyCache caches tests for public keys. Since SSH clients | ||
104 | // will query whether a public key is acceptable before attempting to | ||
105 | // authenticate with it, we end up with duplicate queries for public | ||
106 | // key validity. The cache only applies to a single ServerConn. | ||
107 | type pubKeyCache struct { | ||
108 | keys []cachedPubKey | ||
109 | } | ||
110 | |||
111 | // get returns the result for a given user/algo/key tuple. | ||
112 | func (c *pubKeyCache) get(user string, pubKeyData []byte) (cachedPubKey, bool) { | ||
113 | for _, k := range c.keys { | ||
114 | if k.user == user && bytes.Equal(k.pubKeyData, pubKeyData) { | ||
115 | return k, true | ||
116 | } | ||
117 | } | ||
118 | return cachedPubKey{}, false | ||
119 | } | ||
120 | |||
121 | // add adds the given tuple to the cache. | ||
122 | func (c *pubKeyCache) add(candidate cachedPubKey) { | ||
123 | if len(c.keys) < maxCachedPubKeys { | ||
124 | c.keys = append(c.keys, candidate) | ||
125 | } | ||
126 | } | ||
127 | |||
128 | // ServerConn is an authenticated SSH connection, as seen from the | ||
129 | // server | ||
130 | type ServerConn struct { | ||
131 | Conn | ||
132 | |||
133 | // If the succeeding authentication callback returned a | ||
134 | // non-nil Permissions pointer, it is stored here. | ||
135 | Permissions *Permissions | ||
136 | } | ||
137 | |||
138 | // NewServerConn starts a new SSH server with c as the underlying | ||
139 | // transport. It starts with a handshake and, if the handshake is | ||
140 | // unsuccessful, it closes the connection and returns an error. The | ||
141 | // Request and NewChannel channels must be serviced, or the connection | ||
142 | // will hang. | ||
143 | func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) { | ||
144 | fullConf := *config | ||
145 | fullConf.SetDefaults() | ||
146 | s := &connection{ | ||
147 | sshConn: sshConn{conn: c}, | ||
148 | } | ||
149 | perms, err := s.serverHandshake(&fullConf) | ||
150 | if err != nil { | ||
151 | c.Close() | ||
152 | return nil, nil, nil, err | ||
153 | } | ||
154 | return &ServerConn{s, perms}, s.mux.incomingChannels, s.mux.incomingRequests, nil | ||
155 | } | ||
156 | |||
157 | // signAndMarshal signs the data with the appropriate algorithm, | ||
158 | // and serializes the result in SSH wire format. | ||
159 | func signAndMarshal(k Signer, rand io.Reader, data []byte) ([]byte, error) { | ||
160 | sig, err := k.Sign(rand, data) | ||
161 | if err != nil { | ||
162 | return nil, err | ||
163 | } | ||
164 | |||
165 | return Marshal(sig), nil | ||
166 | } | ||
167 | |||
168 | // handshake performs key exchange and user authentication. | ||
169 | func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error) { | ||
170 | if len(config.hostKeys) == 0 { | ||
171 | return nil, errors.New("ssh: server has no host keys") | ||
172 | } | ||
173 | |||
174 | if !config.NoClientAuth && config.PasswordCallback == nil && config.PublicKeyCallback == nil && config.KeyboardInteractiveCallback == nil { | ||
175 | return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") | ||
176 | } | ||
177 | |||
178 | if config.ServerVersion != "" { | ||
179 | s.serverVersion = []byte(config.ServerVersion) | ||
180 | } else { | ||
181 | s.serverVersion = []byte(packageVersion) | ||
182 | } | ||
183 | var err error | ||
184 | s.clientVersion, err = exchangeVersions(s.sshConn.conn, s.serverVersion) | ||
185 | if err != nil { | ||
186 | return nil, err | ||
187 | } | ||
188 | |||
189 | tr := newTransport(s.sshConn.conn, config.Rand, false /* not client */) | ||
190 | s.transport = newServerTransport(tr, s.clientVersion, s.serverVersion, config) | ||
191 | |||
192 | if err := s.transport.waitSession(); err != nil { | ||
193 | return nil, err | ||
194 | } | ||
195 | |||
196 | // We just did the key change, so the session ID is established. | ||
197 | s.sessionID = s.transport.getSessionID() | ||
198 | |||
199 | var packet []byte | ||
200 | if packet, err = s.transport.readPacket(); err != nil { | ||
201 | return nil, err | ||
202 | } | ||
203 | |||
204 | var serviceRequest serviceRequestMsg | ||
205 | if err = Unmarshal(packet, &serviceRequest); err != nil { | ||
206 | return nil, err | ||
207 | } | ||
208 | if serviceRequest.Service != serviceUserAuth { | ||
209 | return nil, errors.New("ssh: requested service '" + serviceRequest.Service + "' before authenticating") | ||
210 | } | ||
211 | serviceAccept := serviceAcceptMsg{ | ||
212 | Service: serviceUserAuth, | ||
213 | } | ||
214 | if err := s.transport.writePacket(Marshal(&serviceAccept)); err != nil { | ||
215 | return nil, err | ||
216 | } | ||
217 | |||
218 | perms, err := s.serverAuthenticate(config) | ||
219 | if err != nil { | ||
220 | return nil, err | ||
221 | } | ||
222 | s.mux = newMux(s.transport) | ||
223 | return perms, err | ||
224 | } | ||
225 | |||
226 | func isAcceptableAlgo(algo string) bool { | ||
227 | switch algo { | ||
228 | case KeyAlgoRSA, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoED25519, | ||
229 | CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01: | ||
230 | return true | ||
231 | } | ||
232 | return false | ||
233 | } | ||
234 | |||
235 | func checkSourceAddress(addr net.Addr, sourceAddrs string) error { | ||
236 | if addr == nil { | ||
237 | return errors.New("ssh: no address known for client, but source-address match required") | ||
238 | } | ||
239 | |||
240 | tcpAddr, ok := addr.(*net.TCPAddr) | ||
241 | if !ok { | ||
242 | return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr) | ||
243 | } | ||
244 | |||
245 | for _, sourceAddr := range strings.Split(sourceAddrs, ",") { | ||
246 | if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil { | ||
247 | if allowedIP.Equal(tcpAddr.IP) { | ||
248 | return nil | ||
249 | } | ||
250 | } else { | ||
251 | _, ipNet, err := net.ParseCIDR(sourceAddr) | ||
252 | if err != nil { | ||
253 | return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err) | ||
254 | } | ||
255 | |||
256 | if ipNet.Contains(tcpAddr.IP) { | ||
257 | return nil | ||
258 | } | ||
259 | } | ||
260 | } | ||
261 | |||
262 | return fmt.Errorf("ssh: remote address %v is not allowed because of source-address restriction", addr) | ||
263 | } | ||
264 | |||
265 | func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) { | ||
266 | sessionID := s.transport.getSessionID() | ||
267 | var cache pubKeyCache | ||
268 | var perms *Permissions | ||
269 | |||
270 | userAuthLoop: | ||
271 | for { | ||
272 | var userAuthReq userAuthRequestMsg | ||
273 | if packet, err := s.transport.readPacket(); err != nil { | ||
274 | return nil, err | ||
275 | } else if err = Unmarshal(packet, &userAuthReq); err != nil { | ||
276 | return nil, err | ||
277 | } | ||
278 | |||
279 | if userAuthReq.Service != serviceSSH { | ||
280 | return nil, errors.New("ssh: client attempted to negotiate for unknown service: " + userAuthReq.Service) | ||
281 | } | ||
282 | |||
283 | s.user = userAuthReq.User | ||
284 | perms = nil | ||
285 | authErr := errors.New("no auth passed yet") | ||
286 | |||
287 | switch userAuthReq.Method { | ||
288 | case "none": | ||
289 | if config.NoClientAuth { | ||
290 | authErr = nil | ||
291 | } | ||
292 | case "password": | ||
293 | if config.PasswordCallback == nil { | ||
294 | authErr = errors.New("ssh: password auth not configured") | ||
295 | break | ||
296 | } | ||
297 | payload := userAuthReq.Payload | ||
298 | if len(payload) < 1 || payload[0] != 0 { | ||
299 | return nil, parseError(msgUserAuthRequest) | ||
300 | } | ||
301 | payload = payload[1:] | ||
302 | password, payload, ok := parseString(payload) | ||
303 | if !ok || len(payload) > 0 { | ||
304 | return nil, parseError(msgUserAuthRequest) | ||
305 | } | ||
306 | |||
307 | perms, authErr = config.PasswordCallback(s, password) | ||
308 | case "keyboard-interactive": | ||
309 | if config.KeyboardInteractiveCallback == nil { | ||
310 | authErr = errors.New("ssh: keyboard-interactive auth not configubred") | ||
311 | break | ||
312 | } | ||
313 | |||
314 | prompter := &sshClientKeyboardInteractive{s} | ||
315 | perms, authErr = config.KeyboardInteractiveCallback(s, prompter.Challenge) | ||
316 | case "publickey": | ||
317 | if config.PublicKeyCallback == nil { | ||
318 | authErr = errors.New("ssh: publickey auth not configured") | ||
319 | break | ||
320 | } | ||
321 | payload := userAuthReq.Payload | ||
322 | if len(payload) < 1 { | ||
323 | return nil, parseError(msgUserAuthRequest) | ||
324 | } | ||
325 | isQuery := payload[0] == 0 | ||
326 | payload = payload[1:] | ||
327 | algoBytes, payload, ok := parseString(payload) | ||
328 | if !ok { | ||
329 | return nil, parseError(msgUserAuthRequest) | ||
330 | } | ||
331 | algo := string(algoBytes) | ||
332 | if !isAcceptableAlgo(algo) { | ||
333 | authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo) | ||
334 | break | ||
335 | } | ||
336 | |||
337 | pubKeyData, payload, ok := parseString(payload) | ||
338 | if !ok { | ||
339 | return nil, parseError(msgUserAuthRequest) | ||
340 | } | ||
341 | |||
342 | pubKey, err := ParsePublicKey(pubKeyData) | ||
343 | if err != nil { | ||
344 | return nil, err | ||
345 | } | ||
346 | |||
347 | candidate, ok := cache.get(s.user, pubKeyData) | ||
348 | if !ok { | ||
349 | candidate.user = s.user | ||
350 | candidate.pubKeyData = pubKeyData | ||
351 | candidate.perms, candidate.result = config.PublicKeyCallback(s, pubKey) | ||
352 | if candidate.result == nil && candidate.perms != nil && candidate.perms.CriticalOptions != nil && candidate.perms.CriticalOptions[sourceAddressCriticalOption] != "" { | ||
353 | candidate.result = checkSourceAddress( | ||
354 | s.RemoteAddr(), | ||
355 | candidate.perms.CriticalOptions[sourceAddressCriticalOption]) | ||
356 | } | ||
357 | cache.add(candidate) | ||
358 | } | ||
359 | |||
360 | if isQuery { | ||
361 | // The client can query if the given public key | ||
362 | // would be okay. | ||
363 | if len(payload) > 0 { | ||
364 | return nil, parseError(msgUserAuthRequest) | ||
365 | } | ||
366 | |||
367 | if candidate.result == nil { | ||
368 | okMsg := userAuthPubKeyOkMsg{ | ||
369 | Algo: algo, | ||
370 | PubKey: pubKeyData, | ||
371 | } | ||
372 | if err = s.transport.writePacket(Marshal(&okMsg)); err != nil { | ||
373 | return nil, err | ||
374 | } | ||
375 | continue userAuthLoop | ||
376 | } | ||
377 | authErr = candidate.result | ||
378 | } else { | ||
379 | sig, payload, ok := parseSignature(payload) | ||
380 | if !ok || len(payload) > 0 { | ||
381 | return nil, parseError(msgUserAuthRequest) | ||
382 | } | ||
383 | // Ensure the public key algo and signature algo | ||
384 | // are supported. Compare the private key | ||
385 | // algorithm name that corresponds to algo with | ||
386 | // sig.Format. This is usually the same, but | ||
387 | // for certs, the names differ. | ||
388 | if !isAcceptableAlgo(sig.Format) { | ||
389 | break | ||
390 | } | ||
391 | signedData := buildDataSignedForAuth(sessionID, userAuthReq, algoBytes, pubKeyData) | ||
392 | |||
393 | if err := pubKey.Verify(signedData, sig); err != nil { | ||
394 | return nil, err | ||
395 | } | ||
396 | |||
397 | authErr = candidate.result | ||
398 | perms = candidate.perms | ||
399 | } | ||
400 | default: | ||
401 | authErr = fmt.Errorf("ssh: unknown method %q", userAuthReq.Method) | ||
402 | } | ||
403 | |||
404 | if config.AuthLogCallback != nil { | ||
405 | config.AuthLogCallback(s, userAuthReq.Method, authErr) | ||
406 | } | ||
407 | |||
408 | if authErr == nil { | ||
409 | break userAuthLoop | ||
410 | } | ||
411 | |||
412 | var failureMsg userAuthFailureMsg | ||
413 | if config.PasswordCallback != nil { | ||
414 | failureMsg.Methods = append(failureMsg.Methods, "password") | ||
415 | } | ||
416 | if config.PublicKeyCallback != nil { | ||
417 | failureMsg.Methods = append(failureMsg.Methods, "publickey") | ||
418 | } | ||
419 | if config.KeyboardInteractiveCallback != nil { | ||
420 | failureMsg.Methods = append(failureMsg.Methods, "keyboard-interactive") | ||
421 | } | ||
422 | |||
423 | if len(failureMsg.Methods) == 0 { | ||
424 | return nil, errors.New("ssh: no authentication methods configured but NoClientAuth is also false") | ||
425 | } | ||
426 | |||
427 | if err := s.transport.writePacket(Marshal(&failureMsg)); err != nil { | ||
428 | return nil, err | ||
429 | } | ||
430 | } | ||
431 | |||
432 | if err := s.transport.writePacket([]byte{msgUserAuthSuccess}); err != nil { | ||
433 | return nil, err | ||
434 | } | ||
435 | return perms, nil | ||
436 | } | ||
437 | |||
438 | // sshClientKeyboardInteractive implements a ClientKeyboardInteractive by | ||
439 | // asking the client on the other side of a ServerConn. | ||
440 | type sshClientKeyboardInteractive struct { | ||
441 | *connection | ||
442 | } | ||
443 | |||
444 | func (c *sshClientKeyboardInteractive) Challenge(user, instruction string, questions []string, echos []bool) (answers []string, err error) { | ||
445 | if len(questions) != len(echos) { | ||
446 | return nil, errors.New("ssh: echos and questions must have equal length") | ||
447 | } | ||
448 | |||
449 | var prompts []byte | ||
450 | for i := range questions { | ||
451 | prompts = appendString(prompts, questions[i]) | ||
452 | prompts = appendBool(prompts, echos[i]) | ||
453 | } | ||
454 | |||
455 | if err := c.transport.writePacket(Marshal(&userAuthInfoRequestMsg{ | ||
456 | Instruction: instruction, | ||
457 | NumPrompts: uint32(len(questions)), | ||
458 | Prompts: prompts, | ||
459 | })); err != nil { | ||
460 | return nil, err | ||
461 | } | ||
462 | |||
463 | packet, err := c.transport.readPacket() | ||
464 | if err != nil { | ||
465 | return nil, err | ||
466 | } | ||
467 | if packet[0] != msgUserAuthInfoResponse { | ||
468 | return nil, unexpectedMessageError(msgUserAuthInfoResponse, packet[0]) | ||
469 | } | ||
470 | packet = packet[1:] | ||
471 | |||
472 | n, packet, ok := parseUint32(packet) | ||
473 | if !ok || int(n) != len(questions) { | ||
474 | return nil, parseError(msgUserAuthInfoResponse) | ||
475 | } | ||
476 | |||
477 | for i := uint32(0); i < n; i++ { | ||
478 | ans, rest, ok := parseString(packet) | ||
479 | if !ok { | ||
480 | return nil, parseError(msgUserAuthInfoResponse) | ||
481 | } | ||
482 | |||
483 | answers = append(answers, string(ans)) | ||
484 | packet = rest | ||
485 | } | ||
486 | if len(packet) != 0 { | ||
487 | return nil, errors.New("ssh: junk at end of message") | ||
488 | } | ||
489 | |||
490 | return answers, nil | ||
491 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/session.go b/vendor/golang.org/x/crypto/ssh/session.go new file mode 100644 index 0000000..17e2aa8 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/session.go | |||
@@ -0,0 +1,627 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | // Session implements an interactive session described in | ||
8 | // "RFC 4254, section 6". | ||
9 | |||
10 | import ( | ||
11 | "bytes" | ||
12 | "encoding/binary" | ||
13 | "errors" | ||
14 | "fmt" | ||
15 | "io" | ||
16 | "io/ioutil" | ||
17 | "sync" | ||
18 | ) | ||
19 | |||
20 | type Signal string | ||
21 | |||
22 | // POSIX signals as listed in RFC 4254 Section 6.10. | ||
23 | const ( | ||
24 | SIGABRT Signal = "ABRT" | ||
25 | SIGALRM Signal = "ALRM" | ||
26 | SIGFPE Signal = "FPE" | ||
27 | SIGHUP Signal = "HUP" | ||
28 | SIGILL Signal = "ILL" | ||
29 | SIGINT Signal = "INT" | ||
30 | SIGKILL Signal = "KILL" | ||
31 | SIGPIPE Signal = "PIPE" | ||
32 | SIGQUIT Signal = "QUIT" | ||
33 | SIGSEGV Signal = "SEGV" | ||
34 | SIGTERM Signal = "TERM" | ||
35 | SIGUSR1 Signal = "USR1" | ||
36 | SIGUSR2 Signal = "USR2" | ||
37 | ) | ||
38 | |||
39 | var signals = map[Signal]int{ | ||
40 | SIGABRT: 6, | ||
41 | SIGALRM: 14, | ||
42 | SIGFPE: 8, | ||
43 | SIGHUP: 1, | ||
44 | SIGILL: 4, | ||
45 | SIGINT: 2, | ||
46 | SIGKILL: 9, | ||
47 | SIGPIPE: 13, | ||
48 | SIGQUIT: 3, | ||
49 | SIGSEGV: 11, | ||
50 | SIGTERM: 15, | ||
51 | } | ||
52 | |||
53 | type TerminalModes map[uint8]uint32 | ||
54 | |||
55 | // POSIX terminal mode flags as listed in RFC 4254 Section 8. | ||
56 | const ( | ||
57 | tty_OP_END = 0 | ||
58 | VINTR = 1 | ||
59 | VQUIT = 2 | ||
60 | VERASE = 3 | ||
61 | VKILL = 4 | ||
62 | VEOF = 5 | ||
63 | VEOL = 6 | ||
64 | VEOL2 = 7 | ||
65 | VSTART = 8 | ||
66 | VSTOP = 9 | ||
67 | VSUSP = 10 | ||
68 | VDSUSP = 11 | ||
69 | VREPRINT = 12 | ||
70 | VWERASE = 13 | ||
71 | VLNEXT = 14 | ||
72 | VFLUSH = 15 | ||
73 | VSWTCH = 16 | ||
74 | VSTATUS = 17 | ||
75 | VDISCARD = 18 | ||
76 | IGNPAR = 30 | ||
77 | PARMRK = 31 | ||
78 | INPCK = 32 | ||
79 | ISTRIP = 33 | ||
80 | INLCR = 34 | ||
81 | IGNCR = 35 | ||
82 | ICRNL = 36 | ||
83 | IUCLC = 37 | ||
84 | IXON = 38 | ||
85 | IXANY = 39 | ||
86 | IXOFF = 40 | ||
87 | IMAXBEL = 41 | ||
88 | ISIG = 50 | ||
89 | ICANON = 51 | ||
90 | XCASE = 52 | ||
91 | ECHO = 53 | ||
92 | ECHOE = 54 | ||
93 | ECHOK = 55 | ||
94 | ECHONL = 56 | ||
95 | NOFLSH = 57 | ||
96 | TOSTOP = 58 | ||
97 | IEXTEN = 59 | ||
98 | ECHOCTL = 60 | ||
99 | ECHOKE = 61 | ||
100 | PENDIN = 62 | ||
101 | OPOST = 70 | ||
102 | OLCUC = 71 | ||
103 | ONLCR = 72 | ||
104 | OCRNL = 73 | ||
105 | ONOCR = 74 | ||
106 | ONLRET = 75 | ||
107 | CS7 = 90 | ||
108 | CS8 = 91 | ||
109 | PARENB = 92 | ||
110 | PARODD = 93 | ||
111 | TTY_OP_ISPEED = 128 | ||
112 | TTY_OP_OSPEED = 129 | ||
113 | ) | ||
114 | |||
115 | // A Session represents a connection to a remote command or shell. | ||
116 | type Session struct { | ||
117 | // Stdin specifies the remote process's standard input. | ||
118 | // If Stdin is nil, the remote process reads from an empty | ||
119 | // bytes.Buffer. | ||
120 | Stdin io.Reader | ||
121 | |||
122 | // Stdout and Stderr specify the remote process's standard | ||
123 | // output and error. | ||
124 | // | ||
125 | // If either is nil, Run connects the corresponding file | ||
126 | // descriptor to an instance of ioutil.Discard. There is a | ||
127 | // fixed amount of buffering that is shared for the two streams. | ||
128 | // If either blocks it may eventually cause the remote | ||
129 | // command to block. | ||
130 | Stdout io.Writer | ||
131 | Stderr io.Writer | ||
132 | |||
133 | ch Channel // the channel backing this session | ||
134 | started bool // true once Start, Run or Shell is invoked. | ||
135 | copyFuncs []func() error | ||
136 | errors chan error // one send per copyFunc | ||
137 | |||
138 | // true if pipe method is active | ||
139 | stdinpipe, stdoutpipe, stderrpipe bool | ||
140 | |||
141 | // stdinPipeWriter is non-nil if StdinPipe has not been called | ||
142 | // and Stdin was specified by the user; it is the write end of | ||
143 | // a pipe connecting Session.Stdin to the stdin channel. | ||
144 | stdinPipeWriter io.WriteCloser | ||
145 | |||
146 | exitStatus chan error | ||
147 | } | ||
148 | |||
149 | // SendRequest sends an out-of-band channel request on the SSH channel | ||
150 | // underlying the session. | ||
151 | func (s *Session) SendRequest(name string, wantReply bool, payload []byte) (bool, error) { | ||
152 | return s.ch.SendRequest(name, wantReply, payload) | ||
153 | } | ||
154 | |||
155 | func (s *Session) Close() error { | ||
156 | return s.ch.Close() | ||
157 | } | ||
158 | |||
159 | // RFC 4254 Section 6.4. | ||
160 | type setenvRequest struct { | ||
161 | Name string | ||
162 | Value string | ||
163 | } | ||
164 | |||
165 | // Setenv sets an environment variable that will be applied to any | ||
166 | // command executed by Shell or Run. | ||
167 | func (s *Session) Setenv(name, value string) error { | ||
168 | msg := setenvRequest{ | ||
169 | Name: name, | ||
170 | Value: value, | ||
171 | } | ||
172 | ok, err := s.ch.SendRequest("env", true, Marshal(&msg)) | ||
173 | if err == nil && !ok { | ||
174 | err = errors.New("ssh: setenv failed") | ||
175 | } | ||
176 | return err | ||
177 | } | ||
178 | |||
179 | // RFC 4254 Section 6.2. | ||
180 | type ptyRequestMsg struct { | ||
181 | Term string | ||
182 | Columns uint32 | ||
183 | Rows uint32 | ||
184 | Width uint32 | ||
185 | Height uint32 | ||
186 | Modelist string | ||
187 | } | ||
188 | |||
189 | // RequestPty requests the association of a pty with the session on the remote host. | ||
190 | func (s *Session) RequestPty(term string, h, w int, termmodes TerminalModes) error { | ||
191 | var tm []byte | ||
192 | for k, v := range termmodes { | ||
193 | kv := struct { | ||
194 | Key byte | ||
195 | Val uint32 | ||
196 | }{k, v} | ||
197 | |||
198 | tm = append(tm, Marshal(&kv)...) | ||
199 | } | ||
200 | tm = append(tm, tty_OP_END) | ||
201 | req := ptyRequestMsg{ | ||
202 | Term: term, | ||
203 | Columns: uint32(w), | ||
204 | Rows: uint32(h), | ||
205 | Width: uint32(w * 8), | ||
206 | Height: uint32(h * 8), | ||
207 | Modelist: string(tm), | ||
208 | } | ||
209 | ok, err := s.ch.SendRequest("pty-req", true, Marshal(&req)) | ||
210 | if err == nil && !ok { | ||
211 | err = errors.New("ssh: pty-req failed") | ||
212 | } | ||
213 | return err | ||
214 | } | ||
215 | |||
216 | // RFC 4254 Section 6.5. | ||
217 | type subsystemRequestMsg struct { | ||
218 | Subsystem string | ||
219 | } | ||
220 | |||
221 | // RequestSubsystem requests the association of a subsystem with the session on the remote host. | ||
222 | // A subsystem is a predefined command that runs in the background when the ssh session is initiated | ||
223 | func (s *Session) RequestSubsystem(subsystem string) error { | ||
224 | msg := subsystemRequestMsg{ | ||
225 | Subsystem: subsystem, | ||
226 | } | ||
227 | ok, err := s.ch.SendRequest("subsystem", true, Marshal(&msg)) | ||
228 | if err == nil && !ok { | ||
229 | err = errors.New("ssh: subsystem request failed") | ||
230 | } | ||
231 | return err | ||
232 | } | ||
233 | |||
234 | // RFC 4254 Section 6.9. | ||
235 | type signalMsg struct { | ||
236 | Signal string | ||
237 | } | ||
238 | |||
239 | // Signal sends the given signal to the remote process. | ||
240 | // sig is one of the SIG* constants. | ||
241 | func (s *Session) Signal(sig Signal) error { | ||
242 | msg := signalMsg{ | ||
243 | Signal: string(sig), | ||
244 | } | ||
245 | |||
246 | _, err := s.ch.SendRequest("signal", false, Marshal(&msg)) | ||
247 | return err | ||
248 | } | ||
249 | |||
250 | // RFC 4254 Section 6.5. | ||
251 | type execMsg struct { | ||
252 | Command string | ||
253 | } | ||
254 | |||
255 | // Start runs cmd on the remote host. Typically, the remote | ||
256 | // server passes cmd to the shell for interpretation. | ||
257 | // A Session only accepts one call to Run, Start or Shell. | ||
258 | func (s *Session) Start(cmd string) error { | ||
259 | if s.started { | ||
260 | return errors.New("ssh: session already started") | ||
261 | } | ||
262 | req := execMsg{ | ||
263 | Command: cmd, | ||
264 | } | ||
265 | |||
266 | ok, err := s.ch.SendRequest("exec", true, Marshal(&req)) | ||
267 | if err == nil && !ok { | ||
268 | err = fmt.Errorf("ssh: command %v failed", cmd) | ||
269 | } | ||
270 | if err != nil { | ||
271 | return err | ||
272 | } | ||
273 | return s.start() | ||
274 | } | ||
275 | |||
276 | // Run runs cmd on the remote host. Typically, the remote | ||
277 | // server passes cmd to the shell for interpretation. | ||
278 | // A Session only accepts one call to Run, Start, Shell, Output, | ||
279 | // or CombinedOutput. | ||
280 | // | ||
281 | // The returned error is nil if the command runs, has no problems | ||
282 | // copying stdin, stdout, and stderr, and exits with a zero exit | ||
283 | // status. | ||
284 | // | ||
285 | // If the remote server does not send an exit status, an error of type | ||
286 | // *ExitMissingError is returned. If the command completes | ||
287 | // unsuccessfully or is interrupted by a signal, the error is of type | ||
288 | // *ExitError. Other error types may be returned for I/O problems. | ||
289 | func (s *Session) Run(cmd string) error { | ||
290 | err := s.Start(cmd) | ||
291 | if err != nil { | ||
292 | return err | ||
293 | } | ||
294 | return s.Wait() | ||
295 | } | ||
296 | |||
297 | // Output runs cmd on the remote host and returns its standard output. | ||
298 | func (s *Session) Output(cmd string) ([]byte, error) { | ||
299 | if s.Stdout != nil { | ||
300 | return nil, errors.New("ssh: Stdout already set") | ||
301 | } | ||
302 | var b bytes.Buffer | ||
303 | s.Stdout = &b | ||
304 | err := s.Run(cmd) | ||
305 | return b.Bytes(), err | ||
306 | } | ||
307 | |||
308 | type singleWriter struct { | ||
309 | b bytes.Buffer | ||
310 | mu sync.Mutex | ||
311 | } | ||
312 | |||
313 | func (w *singleWriter) Write(p []byte) (int, error) { | ||
314 | w.mu.Lock() | ||
315 | defer w.mu.Unlock() | ||
316 | return w.b.Write(p) | ||
317 | } | ||
318 | |||
319 | // CombinedOutput runs cmd on the remote host and returns its combined | ||
320 | // standard output and standard error. | ||
321 | func (s *Session) CombinedOutput(cmd string) ([]byte, error) { | ||
322 | if s.Stdout != nil { | ||
323 | return nil, errors.New("ssh: Stdout already set") | ||
324 | } | ||
325 | if s.Stderr != nil { | ||
326 | return nil, errors.New("ssh: Stderr already set") | ||
327 | } | ||
328 | var b singleWriter | ||
329 | s.Stdout = &b | ||
330 | s.Stderr = &b | ||
331 | err := s.Run(cmd) | ||
332 | return b.b.Bytes(), err | ||
333 | } | ||
334 | |||
335 | // Shell starts a login shell on the remote host. A Session only | ||
336 | // accepts one call to Run, Start, Shell, Output, or CombinedOutput. | ||
337 | func (s *Session) Shell() error { | ||
338 | if s.started { | ||
339 | return errors.New("ssh: session already started") | ||
340 | } | ||
341 | |||
342 | ok, err := s.ch.SendRequest("shell", true, nil) | ||
343 | if err == nil && !ok { | ||
344 | return errors.New("ssh: could not start shell") | ||
345 | } | ||
346 | if err != nil { | ||
347 | return err | ||
348 | } | ||
349 | return s.start() | ||
350 | } | ||
351 | |||
352 | func (s *Session) start() error { | ||
353 | s.started = true | ||
354 | |||
355 | type F func(*Session) | ||
356 | for _, setupFd := range []F{(*Session).stdin, (*Session).stdout, (*Session).stderr} { | ||
357 | setupFd(s) | ||
358 | } | ||
359 | |||
360 | s.errors = make(chan error, len(s.copyFuncs)) | ||
361 | for _, fn := range s.copyFuncs { | ||
362 | go func(fn func() error) { | ||
363 | s.errors <- fn() | ||
364 | }(fn) | ||
365 | } | ||
366 | return nil | ||
367 | } | ||
368 | |||
369 | // Wait waits for the remote command to exit. | ||
370 | // | ||
371 | // The returned error is nil if the command runs, has no problems | ||
372 | // copying stdin, stdout, and stderr, and exits with a zero exit | ||
373 | // status. | ||
374 | // | ||
375 | // If the remote server does not send an exit status, an error of type | ||
376 | // *ExitMissingError is returned. If the command completes | ||
377 | // unsuccessfully or is interrupted by a signal, the error is of type | ||
378 | // *ExitError. Other error types may be returned for I/O problems. | ||
379 | func (s *Session) Wait() error { | ||
380 | if !s.started { | ||
381 | return errors.New("ssh: session not started") | ||
382 | } | ||
383 | waitErr := <-s.exitStatus | ||
384 | |||
385 | if s.stdinPipeWriter != nil { | ||
386 | s.stdinPipeWriter.Close() | ||
387 | } | ||
388 | var copyError error | ||
389 | for _ = range s.copyFuncs { | ||
390 | if err := <-s.errors; err != nil && copyError == nil { | ||
391 | copyError = err | ||
392 | } | ||
393 | } | ||
394 | if waitErr != nil { | ||
395 | return waitErr | ||
396 | } | ||
397 | return copyError | ||
398 | } | ||
399 | |||
400 | func (s *Session) wait(reqs <-chan *Request) error { | ||
401 | wm := Waitmsg{status: -1} | ||
402 | // Wait for msg channel to be closed before returning. | ||
403 | for msg := range reqs { | ||
404 | switch msg.Type { | ||
405 | case "exit-status": | ||
406 | wm.status = int(binary.BigEndian.Uint32(msg.Payload)) | ||
407 | case "exit-signal": | ||
408 | var sigval struct { | ||
409 | Signal string | ||
410 | CoreDumped bool | ||
411 | Error string | ||
412 | Lang string | ||
413 | } | ||
414 | if err := Unmarshal(msg.Payload, &sigval); err != nil { | ||
415 | return err | ||
416 | } | ||
417 | |||
418 | // Must sanitize strings? | ||
419 | wm.signal = sigval.Signal | ||
420 | wm.msg = sigval.Error | ||
421 | wm.lang = sigval.Lang | ||
422 | default: | ||
423 | // This handles keepalives and matches | ||
424 | // OpenSSH's behaviour. | ||
425 | if msg.WantReply { | ||
426 | msg.Reply(false, nil) | ||
427 | } | ||
428 | } | ||
429 | } | ||
430 | if wm.status == 0 { | ||
431 | return nil | ||
432 | } | ||
433 | if wm.status == -1 { | ||
434 | // exit-status was never sent from server | ||
435 | if wm.signal == "" { | ||
436 | // signal was not sent either. RFC 4254 | ||
437 | // section 6.10 recommends against this | ||
438 | // behavior, but it is allowed, so we let | ||
439 | // clients handle it. | ||
440 | return &ExitMissingError{} | ||
441 | } | ||
442 | wm.status = 128 | ||
443 | if _, ok := signals[Signal(wm.signal)]; ok { | ||
444 | wm.status += signals[Signal(wm.signal)] | ||
445 | } | ||
446 | } | ||
447 | |||
448 | return &ExitError{wm} | ||
449 | } | ||
450 | |||
451 | // ExitMissingError is returned if a session is torn down cleanly, but | ||
452 | // the server sends no confirmation of the exit status. | ||
453 | type ExitMissingError struct{} | ||
454 | |||
455 | func (e *ExitMissingError) Error() string { | ||
456 | return "wait: remote command exited without exit status or exit signal" | ||
457 | } | ||
458 | |||
459 | func (s *Session) stdin() { | ||
460 | if s.stdinpipe { | ||
461 | return | ||
462 | } | ||
463 | var stdin io.Reader | ||
464 | if s.Stdin == nil { | ||
465 | stdin = new(bytes.Buffer) | ||
466 | } else { | ||
467 | r, w := io.Pipe() | ||
468 | go func() { | ||
469 | _, err := io.Copy(w, s.Stdin) | ||
470 | w.CloseWithError(err) | ||
471 | }() | ||
472 | stdin, s.stdinPipeWriter = r, w | ||
473 | } | ||
474 | s.copyFuncs = append(s.copyFuncs, func() error { | ||
475 | _, err := io.Copy(s.ch, stdin) | ||
476 | if err1 := s.ch.CloseWrite(); err == nil && err1 != io.EOF { | ||
477 | err = err1 | ||
478 | } | ||
479 | return err | ||
480 | }) | ||
481 | } | ||
482 | |||
483 | func (s *Session) stdout() { | ||
484 | if s.stdoutpipe { | ||
485 | return | ||
486 | } | ||
487 | if s.Stdout == nil { | ||
488 | s.Stdout = ioutil.Discard | ||
489 | } | ||
490 | s.copyFuncs = append(s.copyFuncs, func() error { | ||
491 | _, err := io.Copy(s.Stdout, s.ch) | ||
492 | return err | ||
493 | }) | ||
494 | } | ||
495 | |||
496 | func (s *Session) stderr() { | ||
497 | if s.stderrpipe { | ||
498 | return | ||
499 | } | ||
500 | if s.Stderr == nil { | ||
501 | s.Stderr = ioutil.Discard | ||
502 | } | ||
503 | s.copyFuncs = append(s.copyFuncs, func() error { | ||
504 | _, err := io.Copy(s.Stderr, s.ch.Stderr()) | ||
505 | return err | ||
506 | }) | ||
507 | } | ||
508 | |||
509 | // sessionStdin reroutes Close to CloseWrite. | ||
510 | type sessionStdin struct { | ||
511 | io.Writer | ||
512 | ch Channel | ||
513 | } | ||
514 | |||
515 | func (s *sessionStdin) Close() error { | ||
516 | return s.ch.CloseWrite() | ||
517 | } | ||
518 | |||
519 | // StdinPipe returns a pipe that will be connected to the | ||
520 | // remote command's standard input when the command starts. | ||
521 | func (s *Session) StdinPipe() (io.WriteCloser, error) { | ||
522 | if s.Stdin != nil { | ||
523 | return nil, errors.New("ssh: Stdin already set") | ||
524 | } | ||
525 | if s.started { | ||
526 | return nil, errors.New("ssh: StdinPipe after process started") | ||
527 | } | ||
528 | s.stdinpipe = true | ||
529 | return &sessionStdin{s.ch, s.ch}, nil | ||
530 | } | ||
531 | |||
532 | // StdoutPipe returns a pipe that will be connected to the | ||
533 | // remote command's standard output when the command starts. | ||
534 | // There is a fixed amount of buffering that is shared between | ||
535 | // stdout and stderr streams. If the StdoutPipe reader is | ||
536 | // not serviced fast enough it may eventually cause the | ||
537 | // remote command to block. | ||
538 | func (s *Session) StdoutPipe() (io.Reader, error) { | ||
539 | if s.Stdout != nil { | ||
540 | return nil, errors.New("ssh: Stdout already set") | ||
541 | } | ||
542 | if s.started { | ||
543 | return nil, errors.New("ssh: StdoutPipe after process started") | ||
544 | } | ||
545 | s.stdoutpipe = true | ||
546 | return s.ch, nil | ||
547 | } | ||
548 | |||
549 | // StderrPipe returns a pipe that will be connected to the | ||
550 | // remote command's standard error when the command starts. | ||
551 | // There is a fixed amount of buffering that is shared between | ||
552 | // stdout and stderr streams. If the StderrPipe reader is | ||
553 | // not serviced fast enough it may eventually cause the | ||
554 | // remote command to block. | ||
555 | func (s *Session) StderrPipe() (io.Reader, error) { | ||
556 | if s.Stderr != nil { | ||
557 | return nil, errors.New("ssh: Stderr already set") | ||
558 | } | ||
559 | if s.started { | ||
560 | return nil, errors.New("ssh: StderrPipe after process started") | ||
561 | } | ||
562 | s.stderrpipe = true | ||
563 | return s.ch.Stderr(), nil | ||
564 | } | ||
565 | |||
566 | // newSession returns a new interactive session on the remote host. | ||
567 | func newSession(ch Channel, reqs <-chan *Request) (*Session, error) { | ||
568 | s := &Session{ | ||
569 | ch: ch, | ||
570 | } | ||
571 | s.exitStatus = make(chan error, 1) | ||
572 | go func() { | ||
573 | s.exitStatus <- s.wait(reqs) | ||
574 | }() | ||
575 | |||
576 | return s, nil | ||
577 | } | ||
578 | |||
579 | // An ExitError reports unsuccessful completion of a remote command. | ||
580 | type ExitError struct { | ||
581 | Waitmsg | ||
582 | } | ||
583 | |||
584 | func (e *ExitError) Error() string { | ||
585 | return e.Waitmsg.String() | ||
586 | } | ||
587 | |||
588 | // Waitmsg stores the information about an exited remote command | ||
589 | // as reported by Wait. | ||
590 | type Waitmsg struct { | ||
591 | status int | ||
592 | signal string | ||
593 | msg string | ||
594 | lang string | ||
595 | } | ||
596 | |||
597 | // ExitStatus returns the exit status of the remote command. | ||
598 | func (w Waitmsg) ExitStatus() int { | ||
599 | return w.status | ||
600 | } | ||
601 | |||
602 | // Signal returns the exit signal of the remote command if | ||
603 | // it was terminated violently. | ||
604 | func (w Waitmsg) Signal() string { | ||
605 | return w.signal | ||
606 | } | ||
607 | |||
608 | // Msg returns the exit message given by the remote command | ||
609 | func (w Waitmsg) Msg() string { | ||
610 | return w.msg | ||
611 | } | ||
612 | |||
613 | // Lang returns the language tag. See RFC 3066 | ||
614 | func (w Waitmsg) Lang() string { | ||
615 | return w.lang | ||
616 | } | ||
617 | |||
618 | func (w Waitmsg) String() string { | ||
619 | str := fmt.Sprintf("Process exited with status %v", w.status) | ||
620 | if w.signal != "" { | ||
621 | str += fmt.Sprintf(" from signal %v", w.signal) | ||
622 | } | ||
623 | if w.msg != "" { | ||
624 | str += fmt.Sprintf(". Reason was: %v", w.msg) | ||
625 | } | ||
626 | return str | ||
627 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go new file mode 100644 index 0000000..6151241 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/tcpip.go | |||
@@ -0,0 +1,407 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "errors" | ||
9 | "fmt" | ||
10 | "io" | ||
11 | "math/rand" | ||
12 | "net" | ||
13 | "strconv" | ||
14 | "strings" | ||
15 | "sync" | ||
16 | "time" | ||
17 | ) | ||
18 | |||
19 | // Listen requests the remote peer open a listening socket on | ||
20 | // addr. Incoming connections will be available by calling Accept on | ||
21 | // the returned net.Listener. The listener must be serviced, or the | ||
22 | // SSH connection may hang. | ||
23 | func (c *Client) Listen(n, addr string) (net.Listener, error) { | ||
24 | laddr, err := net.ResolveTCPAddr(n, addr) | ||
25 | if err != nil { | ||
26 | return nil, err | ||
27 | } | ||
28 | return c.ListenTCP(laddr) | ||
29 | } | ||
30 | |||
31 | // Automatic port allocation is broken with OpenSSH before 6.0. See | ||
32 | // also https://bugzilla.mindrot.org/show_bug.cgi?id=2017. In | ||
33 | // particular, OpenSSH 5.9 sends a channelOpenMsg with port number 0, | ||
34 | // rather than the actual port number. This means you can never open | ||
35 | // two different listeners with auto allocated ports. We work around | ||
36 | // this by trying explicit ports until we succeed. | ||
37 | |||
38 | const openSSHPrefix = "OpenSSH_" | ||
39 | |||
40 | var portRandomizer = rand.New(rand.NewSource(time.Now().UnixNano())) | ||
41 | |||
42 | // isBrokenOpenSSHVersion returns true if the given version string | ||
43 | // specifies a version of OpenSSH that is known to have a bug in port | ||
44 | // forwarding. | ||
45 | func isBrokenOpenSSHVersion(versionStr string) bool { | ||
46 | i := strings.Index(versionStr, openSSHPrefix) | ||
47 | if i < 0 { | ||
48 | return false | ||
49 | } | ||
50 | i += len(openSSHPrefix) | ||
51 | j := i | ||
52 | for ; j < len(versionStr); j++ { | ||
53 | if versionStr[j] < '0' || versionStr[j] > '9' { | ||
54 | break | ||
55 | } | ||
56 | } | ||
57 | version, _ := strconv.Atoi(versionStr[i:j]) | ||
58 | return version < 6 | ||
59 | } | ||
60 | |||
61 | // autoPortListenWorkaround simulates automatic port allocation by | ||
62 | // trying random ports repeatedly. | ||
63 | func (c *Client) autoPortListenWorkaround(laddr *net.TCPAddr) (net.Listener, error) { | ||
64 | var sshListener net.Listener | ||
65 | var err error | ||
66 | const tries = 10 | ||
67 | for i := 0; i < tries; i++ { | ||
68 | addr := *laddr | ||
69 | addr.Port = 1024 + portRandomizer.Intn(60000) | ||
70 | sshListener, err = c.ListenTCP(&addr) | ||
71 | if err == nil { | ||
72 | laddr.Port = addr.Port | ||
73 | return sshListener, err | ||
74 | } | ||
75 | } | ||
76 | return nil, fmt.Errorf("ssh: listen on random port failed after %d tries: %v", tries, err) | ||
77 | } | ||
78 | |||
79 | // RFC 4254 7.1 | ||
80 | type channelForwardMsg struct { | ||
81 | addr string | ||
82 | rport uint32 | ||
83 | } | ||
84 | |||
85 | // ListenTCP requests the remote peer open a listening socket | ||
86 | // on laddr. Incoming connections will be available by calling | ||
87 | // Accept on the returned net.Listener. | ||
88 | func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) { | ||
89 | if laddr.Port == 0 && isBrokenOpenSSHVersion(string(c.ServerVersion())) { | ||
90 | return c.autoPortListenWorkaround(laddr) | ||
91 | } | ||
92 | |||
93 | m := channelForwardMsg{ | ||
94 | laddr.IP.String(), | ||
95 | uint32(laddr.Port), | ||
96 | } | ||
97 | // send message | ||
98 | ok, resp, err := c.SendRequest("tcpip-forward", true, Marshal(&m)) | ||
99 | if err != nil { | ||
100 | return nil, err | ||
101 | } | ||
102 | if !ok { | ||
103 | return nil, errors.New("ssh: tcpip-forward request denied by peer") | ||
104 | } | ||
105 | |||
106 | // If the original port was 0, then the remote side will | ||
107 | // supply a real port number in the response. | ||
108 | if laddr.Port == 0 { | ||
109 | var p struct { | ||
110 | Port uint32 | ||
111 | } | ||
112 | if err := Unmarshal(resp, &p); err != nil { | ||
113 | return nil, err | ||
114 | } | ||
115 | laddr.Port = int(p.Port) | ||
116 | } | ||
117 | |||
118 | // Register this forward, using the port number we obtained. | ||
119 | ch := c.forwards.add(*laddr) | ||
120 | |||
121 | return &tcpListener{laddr, c, ch}, nil | ||
122 | } | ||
123 | |||
124 | // forwardList stores a mapping between remote | ||
125 | // forward requests and the tcpListeners. | ||
126 | type forwardList struct { | ||
127 | sync.Mutex | ||
128 | entries []forwardEntry | ||
129 | } | ||
130 | |||
131 | // forwardEntry represents an established mapping of a laddr on a | ||
132 | // remote ssh server to a channel connected to a tcpListener. | ||
133 | type forwardEntry struct { | ||
134 | laddr net.TCPAddr | ||
135 | c chan forward | ||
136 | } | ||
137 | |||
138 | // forward represents an incoming forwarded tcpip connection. The | ||
139 | // arguments to add/remove/lookup should be address as specified in | ||
140 | // the original forward-request. | ||
141 | type forward struct { | ||
142 | newCh NewChannel // the ssh client channel underlying this forward | ||
143 | raddr *net.TCPAddr // the raddr of the incoming connection | ||
144 | } | ||
145 | |||
146 | func (l *forwardList) add(addr net.TCPAddr) chan forward { | ||
147 | l.Lock() | ||
148 | defer l.Unlock() | ||
149 | f := forwardEntry{ | ||
150 | addr, | ||
151 | make(chan forward, 1), | ||
152 | } | ||
153 | l.entries = append(l.entries, f) | ||
154 | return f.c | ||
155 | } | ||
156 | |||
157 | // See RFC 4254, section 7.2 | ||
158 | type forwardedTCPPayload struct { | ||
159 | Addr string | ||
160 | Port uint32 | ||
161 | OriginAddr string | ||
162 | OriginPort uint32 | ||
163 | } | ||
164 | |||
165 | // parseTCPAddr parses the originating address from the remote into a *net.TCPAddr. | ||
166 | func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) { | ||
167 | if port == 0 || port > 65535 { | ||
168 | return nil, fmt.Errorf("ssh: port number out of range: %d", port) | ||
169 | } | ||
170 | ip := net.ParseIP(string(addr)) | ||
171 | if ip == nil { | ||
172 | return nil, fmt.Errorf("ssh: cannot parse IP address %q", addr) | ||
173 | } | ||
174 | return &net.TCPAddr{IP: ip, Port: int(port)}, nil | ||
175 | } | ||
176 | |||
177 | func (l *forwardList) handleChannels(in <-chan NewChannel) { | ||
178 | for ch := range in { | ||
179 | var payload forwardedTCPPayload | ||
180 | if err := Unmarshal(ch.ExtraData(), &payload); err != nil { | ||
181 | ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error()) | ||
182 | continue | ||
183 | } | ||
184 | |||
185 | // RFC 4254 section 7.2 specifies that incoming | ||
186 | // addresses should list the address, in string | ||
187 | // format. It is implied that this should be an IP | ||
188 | // address, as it would be impossible to connect to it | ||
189 | // otherwise. | ||
190 | laddr, err := parseTCPAddr(payload.Addr, payload.Port) | ||
191 | if err != nil { | ||
192 | ch.Reject(ConnectionFailed, err.Error()) | ||
193 | continue | ||
194 | } | ||
195 | raddr, err := parseTCPAddr(payload.OriginAddr, payload.OriginPort) | ||
196 | if err != nil { | ||
197 | ch.Reject(ConnectionFailed, err.Error()) | ||
198 | continue | ||
199 | } | ||
200 | |||
201 | if ok := l.forward(*laddr, *raddr, ch); !ok { | ||
202 | // Section 7.2, implementations MUST reject spurious incoming | ||
203 | // connections. | ||
204 | ch.Reject(Prohibited, "no forward for address") | ||
205 | continue | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | |||
210 | // remove removes the forward entry, and the channel feeding its | ||
211 | // listener. | ||
212 | func (l *forwardList) remove(addr net.TCPAddr) { | ||
213 | l.Lock() | ||
214 | defer l.Unlock() | ||
215 | for i, f := range l.entries { | ||
216 | if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port { | ||
217 | l.entries = append(l.entries[:i], l.entries[i+1:]...) | ||
218 | close(f.c) | ||
219 | return | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | // closeAll closes and clears all forwards. | ||
225 | func (l *forwardList) closeAll() { | ||
226 | l.Lock() | ||
227 | defer l.Unlock() | ||
228 | for _, f := range l.entries { | ||
229 | close(f.c) | ||
230 | } | ||
231 | l.entries = nil | ||
232 | } | ||
233 | |||
234 | func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool { | ||
235 | l.Lock() | ||
236 | defer l.Unlock() | ||
237 | for _, f := range l.entries { | ||
238 | if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port { | ||
239 | f.c <- forward{ch, &raddr} | ||
240 | return true | ||
241 | } | ||
242 | } | ||
243 | return false | ||
244 | } | ||
245 | |||
246 | type tcpListener struct { | ||
247 | laddr *net.TCPAddr | ||
248 | |||
249 | conn *Client | ||
250 | in <-chan forward | ||
251 | } | ||
252 | |||
253 | // Accept waits for and returns the next connection to the listener. | ||
254 | func (l *tcpListener) Accept() (net.Conn, error) { | ||
255 | s, ok := <-l.in | ||
256 | if !ok { | ||
257 | return nil, io.EOF | ||
258 | } | ||
259 | ch, incoming, err := s.newCh.Accept() | ||
260 | if err != nil { | ||
261 | return nil, err | ||
262 | } | ||
263 | go DiscardRequests(incoming) | ||
264 | |||
265 | return &tcpChanConn{ | ||
266 | Channel: ch, | ||
267 | laddr: l.laddr, | ||
268 | raddr: s.raddr, | ||
269 | }, nil | ||
270 | } | ||
271 | |||
272 | // Close closes the listener. | ||
273 | func (l *tcpListener) Close() error { | ||
274 | m := channelForwardMsg{ | ||
275 | l.laddr.IP.String(), | ||
276 | uint32(l.laddr.Port), | ||
277 | } | ||
278 | |||
279 | // this also closes the listener. | ||
280 | l.conn.forwards.remove(*l.laddr) | ||
281 | ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m)) | ||
282 | if err == nil && !ok { | ||
283 | err = errors.New("ssh: cancel-tcpip-forward failed") | ||
284 | } | ||
285 | return err | ||
286 | } | ||
287 | |||
288 | // Addr returns the listener's network address. | ||
289 | func (l *tcpListener) Addr() net.Addr { | ||
290 | return l.laddr | ||
291 | } | ||
292 | |||
293 | // Dial initiates a connection to the addr from the remote host. | ||
294 | // The resulting connection has a zero LocalAddr() and RemoteAddr(). | ||
295 | func (c *Client) Dial(n, addr string) (net.Conn, error) { | ||
296 | // Parse the address into host and numeric port. | ||
297 | host, portString, err := net.SplitHostPort(addr) | ||
298 | if err != nil { | ||
299 | return nil, err | ||
300 | } | ||
301 | port, err := strconv.ParseUint(portString, 10, 16) | ||
302 | if err != nil { | ||
303 | return nil, err | ||
304 | } | ||
305 | // Use a zero address for local and remote address. | ||
306 | zeroAddr := &net.TCPAddr{ | ||
307 | IP: net.IPv4zero, | ||
308 | Port: 0, | ||
309 | } | ||
310 | ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port)) | ||
311 | if err != nil { | ||
312 | return nil, err | ||
313 | } | ||
314 | return &tcpChanConn{ | ||
315 | Channel: ch, | ||
316 | laddr: zeroAddr, | ||
317 | raddr: zeroAddr, | ||
318 | }, nil | ||
319 | } | ||
320 | |||
321 | // DialTCP connects to the remote address raddr on the network net, | ||
322 | // which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used | ||
323 | // as the local address for the connection. | ||
324 | func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error) { | ||
325 | if laddr == nil { | ||
326 | laddr = &net.TCPAddr{ | ||
327 | IP: net.IPv4zero, | ||
328 | Port: 0, | ||
329 | } | ||
330 | } | ||
331 | ch, err := c.dial(laddr.IP.String(), laddr.Port, raddr.IP.String(), raddr.Port) | ||
332 | if err != nil { | ||
333 | return nil, err | ||
334 | } | ||
335 | return &tcpChanConn{ | ||
336 | Channel: ch, | ||
337 | laddr: laddr, | ||
338 | raddr: raddr, | ||
339 | }, nil | ||
340 | } | ||
341 | |||
342 | // RFC 4254 7.2 | ||
343 | type channelOpenDirectMsg struct { | ||
344 | raddr string | ||
345 | rport uint32 | ||
346 | laddr string | ||
347 | lport uint32 | ||
348 | } | ||
349 | |||
350 | func (c *Client) dial(laddr string, lport int, raddr string, rport int) (Channel, error) { | ||
351 | msg := channelOpenDirectMsg{ | ||
352 | raddr: raddr, | ||
353 | rport: uint32(rport), | ||
354 | laddr: laddr, | ||
355 | lport: uint32(lport), | ||
356 | } | ||
357 | ch, in, err := c.OpenChannel("direct-tcpip", Marshal(&msg)) | ||
358 | if err != nil { | ||
359 | return nil, err | ||
360 | } | ||
361 | go DiscardRequests(in) | ||
362 | return ch, err | ||
363 | } | ||
364 | |||
365 | type tcpChan struct { | ||
366 | Channel // the backing channel | ||
367 | } | ||
368 | |||
369 | // tcpChanConn fulfills the net.Conn interface without | ||
370 | // the tcpChan having to hold laddr or raddr directly. | ||
371 | type tcpChanConn struct { | ||
372 | Channel | ||
373 | laddr, raddr net.Addr | ||
374 | } | ||
375 | |||
376 | // LocalAddr returns the local network address. | ||
377 | func (t *tcpChanConn) LocalAddr() net.Addr { | ||
378 | return t.laddr | ||
379 | } | ||
380 | |||
381 | // RemoteAddr returns the remote network address. | ||
382 | func (t *tcpChanConn) RemoteAddr() net.Addr { | ||
383 | return t.raddr | ||
384 | } | ||
385 | |||
386 | // SetDeadline sets the read and write deadlines associated | ||
387 | // with the connection. | ||
388 | func (t *tcpChanConn) SetDeadline(deadline time.Time) error { | ||
389 | if err := t.SetReadDeadline(deadline); err != nil { | ||
390 | return err | ||
391 | } | ||
392 | return t.SetWriteDeadline(deadline) | ||
393 | } | ||
394 | |||
395 | // SetReadDeadline sets the read deadline. | ||
396 | // A zero value for t means Read will not time out. | ||
397 | // After the deadline, the error from Read will implement net.Error | ||
398 | // with Timeout() == true. | ||
399 | func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error { | ||
400 | return errors.New("ssh: tcpChan: deadline not supported") | ||
401 | } | ||
402 | |||
403 | // SetWriteDeadline exists to satisfy the net.Conn interface | ||
404 | // but is not implemented by this type. It always returns an error. | ||
405 | func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error { | ||
406 | return errors.New("ssh: tcpChan: deadline not supported") | ||
407 | } | ||
diff --git a/vendor/golang.org/x/crypto/ssh/transport.go b/vendor/golang.org/x/crypto/ssh/transport.go new file mode 100644 index 0000000..f9780e0 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/transport.go | |||
@@ -0,0 +1,375 @@ | |||
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 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
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. | ||
16 | const debugTransport = false | ||
17 | |||
18 | const ( | ||
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. | ||
26 | type 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. | ||
41 | type 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. | ||
54 | type 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 | ||
68 | type 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. | ||
78 | func (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 | |||
94 | func (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. | ||
111 | func (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 | |||
128 | func (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 | |||
167 | func (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 | |||
174 | func (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 | |||
196 | func 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 | |||
224 | type direction struct { | ||
225 | ivTag []byte | ||
226 | keyTag []byte | ||
227 | macKeyTag []byte | ||
228 | } | ||
229 | |||
230 | var ( | ||
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. | ||
236 | func 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). | ||
253 | func 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. | ||
285 | func 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 | |||
310 | const 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. | ||
315 | func 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 | ||
337 | const maxVersionStringBytes = 255 | ||
338 | |||
339 | // Read version string as specified by RFC 4253, section 4.2. | ||
340 | func 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 | } | ||