blob: e536c1a3118e9f82ef67a5546a492f110660dd61 [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 (
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -04008 "crypto"
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -04009 "crypto/elliptic"
Adam Langley63f855d2012-04-20 15:17:42 -040010 "errors"
Dave Cheney1582bf02012-10-30 18:13:59 +110011 "fmt"
Russ Cox470549d2012-01-25 15:31:12 -050012 "math/big"
Russ Cox470549d2012-01-25 15:31:12 -050013 "sync"
Jonathan Pittman6a743c52013-09-09 13:06:04 -040014
15 _ "crypto/sha1"
16 _ "crypto/sha256"
17 _ "crypto/sha512"
Russ Cox470549d2012-01-25 15:31:12 -050018)
19
20// These are string constants in the SSH protocol.
21const (
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040022 kexAlgoDH1SHA1 = "diffie-hellman-group1-sha1"
Russ Cox470549d2012-01-25 15:31:12 -050023 kexAlgoDH14SHA1 = "diffie-hellman-group14-sha1"
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040024 kexAlgoECDH256 = "ecdh-sha2-nistp256"
25 kexAlgoECDH384 = "ecdh-sha2-nistp384"
26 kexAlgoECDH521 = "ecdh-sha2-nistp521"
Russ Cox470549d2012-01-25 15:31:12 -050027 hostAlgoRSA = "ssh-rsa"
Jonathan Pittman9b05c272012-02-24 12:52:06 -050028 hostAlgoDSA = "ssh-dss"
Russ Cox470549d2012-01-25 15:31:12 -050029 compressionNone = "none"
30 serviceUserAuth = "ssh-userauth"
31 serviceSSH = "ssh-connection"
32)
33
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040034var supportedKexAlgos = []string{
35 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
36 kexAlgoDH14SHA1, kexAlgoDH1SHA1,
37}
38
Russ Cox470549d2012-01-25 15:31:12 -050039var supportedHostKeyAlgos = []string{hostAlgoRSA}
Russ Cox470549d2012-01-25 15:31:12 -050040var supportedCompressions = []string{compressionNone}
41
Jonathan Pittman6a743c52013-09-09 13:06:04 -040042// hashFuncs keeps the mapping of supported algorithms to their respective
43// hashes needed for signature verification.
44var hashFuncs = map[string]crypto.Hash{
45 KeyAlgoRSA: crypto.SHA1,
46 KeyAlgoDSA: crypto.SHA1,
47 KeyAlgoECDSA256: crypto.SHA256,
48 KeyAlgoECDSA384: crypto.SHA384,
49 KeyAlgoECDSA521: crypto.SHA512,
50 CertAlgoRSAv01: crypto.SHA1,
51 CertAlgoDSAv01: crypto.SHA1,
52 CertAlgoECDSA256v01: crypto.SHA256,
53 CertAlgoECDSA384v01: crypto.SHA384,
54 CertAlgoECDSA521v01: crypto.SHA512,
55}
56
Russ Cox470549d2012-01-25 15:31:12 -050057// dhGroup is a multiplicative group suitable for implementing Diffie-Hellman key agreement.
58type dhGroup struct {
59 g, p *big.Int
60}
61
Adam Langley63f855d2012-04-20 15:17:42 -040062func (group *dhGroup) diffieHellman(theirPublic, myPrivate *big.Int) (*big.Int, error) {
63 if theirPublic.Sign() <= 0 || theirPublic.Cmp(group.p) >= 0 {
64 return nil, errors.New("ssh: DH parameter out of bounds")
65 }
66 return new(big.Int).Exp(theirPublic, myPrivate, group.p), nil
67}
68
Daniel Theophanes36a967d2012-03-06 11:25:32 -050069// dhGroup1 is the group called diffie-hellman-group1-sha1 in RFC 4253 and
70// Oakley Group 2 in RFC 2409.
71var dhGroup1 *dhGroup
72
73var dhGroup1Once sync.Once
74
75func initDHGroup1() {
76 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF", 16)
77
78 dhGroup1 = &dhGroup{
79 g: new(big.Int).SetInt64(2),
80 p: p,
81 }
82}
83
Russ Cox470549d2012-01-25 15:31:12 -050084// dhGroup14 is the group called diffie-hellman-group14-sha1 in RFC 4253 and
85// Oakley Group 14 in RFC 3526.
86var dhGroup14 *dhGroup
87
88var dhGroup14Once sync.Once
89
90func initDHGroup14() {
91 p, _ := new(big.Int).SetString("FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", 16)
92
93 dhGroup14 = &dhGroup{
94 g: new(big.Int).SetInt64(2),
95 p: p,
96 }
97}
98
99// UnexpectedMessageError results when the SSH message that we received didn't
100// match what we wanted.
101type UnexpectedMessageError struct {
102 expected, got uint8
103}
104
105func (u UnexpectedMessageError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +1100106 return fmt.Sprintf("ssh: unexpected message type %d (expected %d)", u.got, u.expected)
Russ Cox470549d2012-01-25 15:31:12 -0500107}
108
109// ParseError results from a malformed SSH message.
110type ParseError struct {
111 msgType uint8
112}
113
114func (p ParseError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +1100115 return fmt.Sprintf("ssh: parse error in message type %d", p.msgType)
Russ Cox470549d2012-01-25 15:31:12 -0500116}
117
118type handshakeMagics struct {
119 clientVersion, serverVersion []byte
120 clientKexInit, serverKexInit []byte
121}
122
123func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
124 for _, clientAlgo := range clientAlgos {
125 for _, serverAlgo := range serverAlgos {
126 if clientAlgo == serverAlgo {
127 return clientAlgo, true
128 }
129 }
130 }
Dave Cheney1582bf02012-10-30 18:13:59 +1100131 return
132}
Russ Cox470549d2012-01-25 15:31:12 -0500133
Dave Cheney1582bf02012-10-30 18:13:59 +1100134func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) {
135 for _, clientCipher := range clientCiphers {
136 for _, serverCipher := range serverCiphers {
137 // reject the cipher if we have no cipherModes definition
138 if clientCipher == serverCipher && cipherModes[clientCipher] != nil {
139 return clientCipher, true
140 }
141 }
142 }
Russ Cox470549d2012-01-25 15:31:12 -0500143 return
144}
145
146func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
147 kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
148 if !ok {
149 return
150 }
151
152 hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
153 if !ok {
154 return
155 }
156
Dave Cheney1582bf02012-10-30 18:13:59 +1100157 transport.writer.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
Russ Cox470549d2012-01-25 15:31:12 -0500158 if !ok {
159 return
160 }
161
Dave Cheney1582bf02012-10-30 18:13:59 +1100162 transport.reader.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
Russ Cox470549d2012-01-25 15:31:12 -0500163 if !ok {
164 return
165 }
166
167 transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
168 if !ok {
169 return
170 }
171
172 transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
173 if !ok {
174 return
175 }
176
177 transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
178 if !ok {
179 return
180 }
181
182 transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
183 if !ok {
184 return
185 }
186
187 ok = true
188 return
189}
190
191// Cryptographic configuration common to both ServerConfig and ClientConfig.
192type CryptoConfig struct {
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400193 // The allowed key exchanges algorithms. If unspecified then a
194 // default set of algorithms is used.
195 KeyExchanges []string
196
Russ Cox470549d2012-01-25 15:31:12 -0500197 // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
198 // used.
199 Ciphers []string
Dave Cheney6de97b52012-02-27 19:40:52 -0500200
201 // The allowed MAC algorithms. If unspecified then DefaultMACOrder is used.
202 MACs []string
Russ Cox470549d2012-01-25 15:31:12 -0500203}
204
205func (c *CryptoConfig) ciphers() []string {
206 if c.Ciphers == nil {
207 return DefaultCipherOrder
208 }
209 return c.Ciphers
210}
211
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400212func (c *CryptoConfig) kexes() []string {
213 if c.KeyExchanges == nil {
214 return defaultKeyExchangeOrder
215 }
216 return c.KeyExchanges
217}
218
Dave Cheney6de97b52012-02-27 19:40:52 -0500219func (c *CryptoConfig) macs() []string {
220 if c.MACs == nil {
221 return DefaultMACOrder
222 }
223 return c.MACs
224}
225
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400226// ecHash returns the hash to match the given elliptic curve, see RFC
227// 5656, section 6.2.1
228func ecHash(curve elliptic.Curve) crypto.Hash {
229 bitSize := curve.Params().BitSize
230 switch {
231 case bitSize <= 256:
232 return crypto.SHA256
233 case bitSize <= 384:
234 return crypto.SHA384
235 }
236 return crypto.SHA512
237}
238
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400239// serialize a signed slice according to RFC 4254 6.6. The name should
240// be a key type name, rather than a cert type name.
241func serializeSignature(name string, sig []byte) []byte {
242 length := stringLength(len(name))
Adam Langley63f855d2012-04-20 15:17:42 -0400243 length += stringLength(len(sig))
Russ Cox470549d2012-01-25 15:31:12 -0500244
245 ret := make([]byte, length)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400246 r := marshalString(ret, []byte(name))
Russ Cox470549d2012-01-25 15:31:12 -0500247 r = marshalString(r, sig)
248
249 return ret
250}
251
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400252// MarshalPublicKey serializes a supported key or certificate for use
253// by the SSH wire protocol. It can be used for comparison with the
254// pubkey argument of ServerConfig's PublicKeyCallback as well as for
255// generating an authorized_keys or host_keys file.
256func MarshalPublicKey(key PublicKey) []byte {
257 // See also RFC 4253 6.6.
258 algoname := key.PrivateKeyAlgo()
259 blob := key.Marshal()
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500260
Adam Langley63f855d2012-04-20 15:17:42 -0400261 length := stringLength(len(algoname))
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400262 length += len(blob)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500263 ret := make([]byte, length)
264 r := marshalString(ret, []byte(algoname))
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400265 copy(r, blob)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500266 return ret
Russ Cox470549d2012-01-25 15:31:12 -0500267}
268
Jonathan Pittman6a743c52013-09-09 13:06:04 -0400269// pubAlgoToPrivAlgo returns the private key algorithm format name that
270// corresponds to a given public key algorithm format name. For most
271// public keys, the private key algorithm name is the same. For some
272// situations, such as openssh certificates, the private key algorithm and
273// public key algorithm names differ. This accounts for those situations.
274func pubAlgoToPrivAlgo(pubAlgo string) string {
275 switch pubAlgo {
276 case CertAlgoRSAv01:
277 return KeyAlgoRSA
278 case CertAlgoDSAv01:
279 return KeyAlgoDSA
280 case CertAlgoECDSA256v01:
281 return KeyAlgoECDSA256
282 case CertAlgoECDSA384v01:
283 return KeyAlgoECDSA384
284 case CertAlgoECDSA521v01:
285 return KeyAlgoECDSA521
286 }
287 return pubAlgo
288}
289
Russ Cox470549d2012-01-25 15:31:12 -0500290// buildDataSignedForAuth returns the data that is signed in order to prove
291// posession of a private key. See RFC 4252, section 7.
292func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
293 user := []byte(req.User)
294 service := []byte(req.Service)
295 method := []byte(req.Method)
296
Adam Langley63f855d2012-04-20 15:17:42 -0400297 length := stringLength(len(sessionId))
Russ Cox470549d2012-01-25 15:31:12 -0500298 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400299 length += stringLength(len(user))
300 length += stringLength(len(service))
301 length += stringLength(len(method))
Russ Cox470549d2012-01-25 15:31:12 -0500302 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400303 length += stringLength(len(algo))
304 length += stringLength(len(pubKey))
Russ Cox470549d2012-01-25 15:31:12 -0500305
306 ret := make([]byte, length)
307 r := marshalString(ret, sessionId)
308 r[0] = msgUserAuthRequest
309 r = r[1:]
310 r = marshalString(r, user)
311 r = marshalString(r, service)
312 r = marshalString(r, method)
313 r[0] = 1
314 r = r[1:]
315 r = marshalString(r, algo)
316 r = marshalString(r, pubKey)
317 return ret
318}
319
Adam Langley4002be22012-12-10 18:12:36 -0500320// safeString sanitises s according to RFC 4251, section 9.2.
Russ Cox470549d2012-01-25 15:31:12 -0500321// All control characters except tab, carriage return and newline are
322// replaced by 0x20.
323func safeString(s string) string {
324 out := []byte(s)
325 for i, c := range out {
326 if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
327 out[i] = 0x20
328 }
329 }
330 return string(out)
331}
Dave Cheney79d53bd2012-03-04 14:34:24 -0800332
333func appendU16(buf []byte, n uint16) []byte {
334 return append(buf, byte(n>>8), byte(n))
335}
336
337func appendU32(buf []byte, n uint32) []byte {
338 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
339}
340
341func appendInt(buf []byte, n int) []byte {
342 return appendU32(buf, uint32(n))
343}
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000344
Han-Wen Nienhuysc7df5652013-06-06 10:44:12 -0400345func appendString(buf []byte, s string) []byte {
346 buf = appendU32(buf, uint32(len(s)))
347 buf = append(buf, s...)
348 return buf
349}
350
351func appendBool(buf []byte, b bool) []byte {
352 if b {
353 buf = append(buf, 1)
354 } else {
355 buf = append(buf, 0)
356 }
357 return buf
358}
359
Adam Langley4002be22012-12-10 18:12:36 -0500360// newCond is a helper to hide the fact that there is no usable zero
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000361// value for sync.Cond.
362func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
363
Adam Langley4002be22012-12-10 18:12:36 -0500364// window represents the buffer available to clients
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000365// wishing to write to a channel.
366type window struct {
367 *sync.Cond
368 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
369}
370
371// add adds win to the amount of window available
372// for consumers.
373func (w *window) add(win uint32) bool {
Dave Cheney55aa0812012-05-22 12:04:51 +1000374 // a zero sized window adjust is a noop.
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000375 if win == 0 {
Dave Cheney55aa0812012-05-22 12:04:51 +1000376 return true
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000377 }
378 w.L.Lock()
379 if w.win+win < win {
380 w.L.Unlock()
381 return false
382 }
383 w.win += win
384 // It is unusual that multiple goroutines would be attempting to reserve
Adam Langley4002be22012-12-10 18:12:36 -0500385 // window space, but not guaranteed. Use broadcast to notify all waiters
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000386 // that additional window is available.
387 w.Broadcast()
388 w.L.Unlock()
389 return true
390}
391
392// reserve reserves win from the available window capacity.
393// If no capacity remains, reserve will block. reserve may
394// return less than requested.
395func (w *window) reserve(win uint32) uint32 {
396 w.L.Lock()
397 for w.win == 0 {
398 w.Wait()
399 }
400 if w.win < win {
401 win = w.win
402 }
403 w.win -= win
404 w.L.Unlock()
405 return win
406}