blob: e03a2b39aab57b6222cd739d44d05db7fba8b45d [file] [log] [blame]
Russ Cox470549d2012-01-25 15:31:12 -05001// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package ssh
6
7import (
8 "crypto/dsa"
Jonathan Pittman94c9f922012-12-14 05:52:19 +11009 "crypto/ecdsa"
Russ Cox470549d2012-01-25 15:31:12 -050010 "crypto/rsa"
Adam Langley63f855d2012-04-20 15:17:42 -040011 "errors"
Dave Cheney1582bf02012-10-30 18:13:59 +110012 "fmt"
Russ Cox470549d2012-01-25 15:31:12 -050013 "math/big"
Russ Cox470549d2012-01-25 15:31:12 -050014 "sync"
15)
16
17// These are string constants in the SSH protocol.
18const (
Daniel Theophanes36a967d2012-03-06 11:25:32 -050019 keyAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
Russ Cox470549d2012-01-25 15:31:12 -050020 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
21 hostAlgoRSA = "ssh-rsa"
Jonathan Pittman9b05c272012-02-24 12:52:06 -050022 hostAlgoDSA = "ssh-dss"
Russ Cox470549d2012-01-25 15:31:12 -050023 compressionNone = "none"
24 serviceUserAuth = "ssh-userauth"
25 serviceSSH = "ssh-connection"
26)
27
Daniel Theophanes36a967d2012-03-06 11:25:32 -050028var supportedKexAlgos = []string{kexAlgoDH14SHA1, keyAlgoDH1SHA1}
Russ Cox470549d2012-01-25 15:31:12 -050029var supportedHostKeyAlgos = []string{hostAlgoRSA}
Russ Cox470549d2012-01-25 15:31:12 -050030var supportedCompressions = []string{compressionNone}
31
32// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
33type dhGroup struct {
34 g, p *big.Int
35}
36
Adam Langley63f855d2012-04-20 15:17:42 -040037func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
38 if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
39 return nil, errors.New("ssh: DH parameter out of bounds")
40 }
41 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
42}
43
Daniel Theophanes36a967d2012-03-06 11:25:32 -050044// dhGroup1 is the group called diffie-hellman-group1-sha1 in RFC 4253 and
45// Oakley Group 2 in RFC 2409.
46var dhGroup1 *dhGroup
47
48var dhGroup1Once sync.Once
49
50func initDHGroup1() {
51 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
52
53 dhGroup1 = &dhGroup{
54 g: new(big.Int).SetInt64(2),
55 p: p,
56 }
57}
58
Russ Cox470549d2012-01-25 15:31:12 -050059// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
60// Oakley Group 14 in RFC 3526.
61var dhGroup14 *dhGroup
62
63var dhGroup14Once sync.Once
64
65func initDHGroup14() {
66 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
67
68 dhGroup14 = &dhGroup{
69 g: new(big.Int).SetInt64(2),
70 p: p,
71 }
72}
73
74// UnexpectedMessageError results when the SSH message that we received didn't
75// match what we wanted.
76type UnexpectedMessageError struct {
77 expected, got uint8
78}
79
80func (u UnexpectedMessageError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +110081 return fmt.Sprintf("ssh: unexpected message type %d (expected %d)", u.got, u.expected)
Russ Cox470549d2012-01-25 15:31:12 -050082}
83
84// ParseError results from a malformed SSH message.
85type ParseError struct {
86 msgType uint8
87}
88
89func (p ParseError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +110090 return fmt.Sprintf("ssh: parse error in message type %d", p.msgType)
Russ Cox470549d2012-01-25 15:31:12 -050091}
92
93type handshakeMagics struct {
94 clientVersion, serverVersion []byte
95 clientKexInit, serverKexInit []byte
96}
97
98func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
99 for _, clientAlgo := range clientAlgos {
100 for _, serverAlgo := range serverAlgos {
101 if clientAlgo == serverAlgo {
102 return clientAlgo, true
103 }
104 }
105 }
Dave Cheney1582bf02012-10-30 18:13:59 +1100106 return
107}
Russ Cox470549d2012-01-25 15:31:12 -0500108
Dave Cheney1582bf02012-10-30 18:13:59 +1100109func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) {
110 for _, clientCipher := range clientCiphers {
111 for _, serverCipher := range serverCiphers {
112 // reject the cipher if we have no cipherModes definition
113 if clientCipher == serverCipher && cipherModes[clientCipher] != nil {
114 return clientCipher, true
115 }
116 }
117 }
Russ Cox470549d2012-01-25 15:31:12 -0500118 return
119}
120
121func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
122 kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
123 if !ok {
124 return
125 }
126
127 hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
128 if !ok {
129 return
130 }
131
Dave Cheney1582bf02012-10-30 18:13:59 +1100132 transport.writer.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
Russ Cox470549d2012-01-25 15:31:12 -0500133 if !ok {
134 return
135 }
136
Dave Cheney1582bf02012-10-30 18:13:59 +1100137 transport.reader.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
Russ Cox470549d2012-01-25 15:31:12 -0500138 if !ok {
139 return
140 }
141
142 transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
143 if !ok {
144 return
145 }
146
147 transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
148 if !ok {
149 return
150 }
151
152 transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
153 if !ok {
154 return
155 }
156
157 transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
158 if !ok {
159 return
160 }
161
162 ok = true
163 return
164}
165
166// Cryptographic configuration common to both ServerConfig and ClientConfig.
167type CryptoConfig struct {
168 // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
169 // used.
170 Ciphers []string
Dave Cheney6de97b52012-02-27 19:40:52 -0500171
172 // The allowed MAC algorithms. If unspecified then DefaultMACOrder is used.
173 MACs []string
Russ Cox470549d2012-01-25 15:31:12 -0500174}
175
176func (c *CryptoConfig) ciphers() []string {
177 if c.Ciphers == nil {
178 return DefaultCipherOrder
179 }
180 return c.Ciphers
181}
182
Dave Cheney6de97b52012-02-27 19:40:52 -0500183func (c *CryptoConfig) macs() []string {
184 if c.MACs == nil {
185 return DefaultMACOrder
186 }
187 return c.MACs
188}
189
Russ Cox470549d2012-01-25 15:31:12 -0500190// serialize a signed slice according to RFC 4254 6.6.
191func serializeSignature(algoname string, sig []byte) []byte {
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500192 switch algoname {
193 // The corresponding private key to a public certificate is always a normal
194 // private key. For signature serialization purposes, ensure we use the
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100195 // proper key algorithm name in case the public cert algorithm name is passed.
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500196 case CertAlgoRSAv01:
197 algoname = KeyAlgoRSA
198 case CertAlgoDSAv01:
199 algoname = KeyAlgoDSA
200 case CertAlgoECDSA256v01:
201 algoname = KeyAlgoECDSA256
202 case CertAlgoECDSA384v01:
203 algoname = KeyAlgoECDSA384
204 case CertAlgoECDSA521v01:
205 algoname = KeyAlgoECDSA521
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500206 }
Adam Langley63f855d2012-04-20 15:17:42 -0400207 length := stringLength(len(algoname))
208 length += stringLength(len(sig))
Russ Cox470549d2012-01-25 15:31:12 -0500209
210 ret := make([]byte, length)
211 r := marshalString(ret, []byte(algoname))
212 r = marshalString(r, sig)
213
214 return ret
215}
216
Adam Langleyd33bbf22012-02-23 10:42:21 -0500217// serialize a *rsa.PublicKey or *dsa.PublicKey according to RFC 4253 6.6.
Russ Cox470549d2012-01-25 15:31:12 -0500218func serializePublickey(key interface{}) []byte {
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500219 var pubKeyBytes []byte
Russ Cox470549d2012-01-25 15:31:12 -0500220 algoname := algoName(key)
221 switch key := key.(type) {
Adam Langleyd33bbf22012-02-23 10:42:21 -0500222 case *rsa.PublicKey:
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500223 pubKeyBytes = marshalPubRSA(key)
Adam Langleyd33bbf22012-02-23 10:42:21 -0500224 case *dsa.PublicKey:
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500225 pubKeyBytes = marshalPubDSA(key)
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100226 case *ecdsa.PublicKey:
227 pubKeyBytes = marshalPubECDSA(key)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500228 case *OpenSSHCertV01:
229 pubKeyBytes = marshalOpenSSHCertV01(key)
230 default:
231 panic("unexpected key type")
Russ Cox470549d2012-01-25 15:31:12 -0500232 }
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500233
Adam Langley63f855d2012-04-20 15:17:42 -0400234 length := stringLength(len(algoname))
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500235 length += len(pubKeyBytes)
236 ret := make([]byte, length)
237 r := marshalString(ret, []byte(algoname))
238 copy(r, pubKeyBytes)
239 return ret
Russ Cox470549d2012-01-25 15:31:12 -0500240}
241
242func algoName(key interface{}) string {
243 switch key.(type) {
Adam Langleyd33bbf22012-02-23 10:42:21 -0500244 case *rsa.PublicKey:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500245 return KeyAlgoRSA
Adam Langleyd33bbf22012-02-23 10:42:21 -0500246 case *dsa.PublicKey:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500247 return KeyAlgoDSA
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100248 case *ecdsa.PublicKey:
249 switch key.(*ecdsa.PublicKey).Params().BitSize {
250 case 256:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500251 return KeyAlgoECDSA256
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100252 case 384:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500253 return KeyAlgoECDSA384
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100254 case 521:
Jonathan Pittman54c65ae2012-12-14 10:11:06 -0500255 return KeyAlgoECDSA521
Jonathan Pittman94c9f922012-12-14 05:52:19 +1100256 }
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500257 case *OpenSSHCertV01:
258 return algoName(key.(*OpenSSHCertV01).Key) + "-cert-v01@openssh.com"
Russ Cox470549d2012-01-25 15:31:12 -0500259 }
260 panic("unexpected key type")
261}
262
263// buildDataSignedForAuth returns the data that is signed in order to prove
264// posession of a private key. See RFC 4252, section 7.
265func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
266 user := []byte(req.User)
267 service := []byte(req.Service)
268 method := []byte(req.Method)
269
Adam Langley63f855d2012-04-20 15:17:42 -0400270 length := stringLength(len(sessionId))
Russ Cox470549d2012-01-25 15:31:12 -0500271 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400272 length += stringLength(len(user))
273 length += stringLength(len(service))
274 length += stringLength(len(method))
Russ Cox470549d2012-01-25 15:31:12 -0500275 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400276 length += stringLength(len(algo))
277 length += stringLength(len(pubKey))
Russ Cox470549d2012-01-25 15:31:12 -0500278
279 ret := make([]byte, length)
280 r := marshalString(ret, sessionId)
281 r[0] = msgUserAuthRequest
282 r = r[1:]
283 r = marshalString(r, user)
284 r = marshalString(r, service)
285 r = marshalString(r, method)
286 r[0] = 1
287 r = r[1:]
288 r = marshalString(r, algo)
289 r = marshalString(r, pubKey)
290 return ret
291}
292
Adam Langley4002be22012-12-10 18:12:36 -0500293// safeString sanitises s according to RFC 4251, section 9.2.
Russ Cox470549d2012-01-25 15:31:12 -0500294// All control characters except tab, carriage return and newline are
295// replaced by 0x20.
296func safeString(s string) string {
297 out := []byte(s)
298 for i, c := range out {
299 if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
300 out[i] = 0x20
301 }
302 }
303 return string(out)
304}
Dave Cheney79d53bd2012-03-04 14:34:24 -0800305
306func appendU16(buf []byte, n uint16) []byte {
307 return append(buf, byte(n>>8), byte(n))
308}
309
310func appendU32(buf []byte, n uint32) []byte {
311 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
312}
313
314func appendInt(buf []byte, n int) []byte {
315 return appendU32(buf, uint32(n))
316}
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000317
Adam Langley4002be22012-12-10 18:12:36 -0500318// newCond is a helper to hide the fact that there is no usable zero
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000319// value for sync.Cond.
320func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
321
Adam Langley4002be22012-12-10 18:12:36 -0500322// window represents the buffer available to clients
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000323// wishing to write to a channel.
324type window struct {
325 *sync.Cond
326 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
327}
328
329// add adds win to the amount of window available
330// for consumers.
331func (w *window) add(win uint32) bool {
Dave Cheney55aa0812012-05-22 12:04:51 +1000332 // a zero sized window adjust is a noop.
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000333 if win == 0 {
Dave Cheney55aa0812012-05-22 12:04:51 +1000334 return true
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000335 }
336 w.L.Lock()
337 if w.win+win < win {
338 w.L.Unlock()
339 return false
340 }
341 w.win += win
342 // It is unusual that multiple goroutines would be attempting to reserve
Adam Langley4002be22012-12-10 18:12:36 -0500343 // window space, but not guaranteed. Use broadcast to notify all waiters
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000344 // that additional window is available.
345 w.Broadcast()
346 w.L.Unlock()
347 return true
348}
349
350// reserve reserves win from the available window capacity.
351// If no capacity remains, reserve will block. reserve may
352// return less than requested.
353func (w *window) reserve(win uint32) uint32 {
354 w.L.Lock()
355 for w.win == 0 {
356 w.Wait()
357 }
358 if w.win < win {
359 win = w.win
360 }
361 w.win -= win
362 w.L.Unlock()
363 return win
364}