blob: 7d2df7c8a6608e2c2fc93b07818d4f06901bce4b [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"
Dave Cheney1582bf02012-10-30 18:13:59 +11009 "fmt"
Russ Cox470549d2012-01-25 15:31:12 -050010 "sync"
Jonathan Pittman6a743c52013-09-09 13:06:04 -040011
12 _ "crypto/sha1"
13 _ "crypto/sha256"
14 _ "crypto/sha512"
Russ Cox470549d2012-01-25 15:31:12 -050015)
16
17// These are string constants in the SSH protocol.
18const (
Russ Cox470549d2012-01-25 15:31:12 -050019 compressionNone = "none"
20 serviceUserAuth = "ssh-userauth"
21 serviceSSH = "ssh-connection"
22)
23
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040024var supportedKexAlgos = []string{
25 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
26 kexAlgoDH14SHA1, kexAlgoDH1SHA1,
27}
28
Han-Wen Nienhuys41400fe2013-10-07 18:30:34 -040029var supportedHostKeyAlgos = []string{
30 KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
31 KeyAlgoRSA, KeyAlgoDSA,
32}
33
Russ Cox470549d2012-01-25 15:31:12 -050034var supportedCompressions = []string{compressionNone}
35
Jonathan Pittman6a743c52013-09-09 13:06:04 -040036// hashFuncs keeps the mapping of supported algorithms to their respective
37// hashes needed for signature verification.
38var hashFuncs = map[string]crypto.Hash{
39 KeyAlgoRSA: crypto.SHA1,
40 KeyAlgoDSA: crypto.SHA1,
41 KeyAlgoECDSA256: crypto.SHA256,
42 KeyAlgoECDSA384: crypto.SHA384,
43 KeyAlgoECDSA521: crypto.SHA512,
44 CertAlgoRSAv01: crypto.SHA1,
45 CertAlgoDSAv01: crypto.SHA1,
46 CertAlgoECDSA256v01: crypto.SHA256,
47 CertAlgoECDSA384v01: crypto.SHA384,
48 CertAlgoECDSA521v01: crypto.SHA512,
49}
50
Russ Cox470549d2012-01-25 15:31:12 -050051// UnexpectedMessageError results when the SSH message that we received didn't
52// match what we wanted.
53type UnexpectedMessageError struct {
54 expected, got uint8
55}
56
57func (u UnexpectedMessageError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +110058 return fmt.Sprintf("ssh: unexpected message type %d (expected %d)", u.got, u.expected)
Russ Cox470549d2012-01-25 15:31:12 -050059}
60
61// ParseError results from a malformed SSH message.
62type ParseError struct {
63 msgType uint8
64}
65
66func (p ParseError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +110067 return fmt.Sprintf("ssh: parse error in message type %d", p.msgType)
Russ Cox470549d2012-01-25 15:31:12 -050068}
69
Russ Cox470549d2012-01-25 15:31:12 -050070func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
71 for _, clientAlgo := range clientAlgos {
72 for _, serverAlgo := range serverAlgos {
73 if clientAlgo == serverAlgo {
74 return clientAlgo, true
75 }
76 }
77 }
Dave Cheney1582bf02012-10-30 18:13:59 +110078 return
79}
Russ Cox470549d2012-01-25 15:31:12 -050080
Dave Cheney1582bf02012-10-30 18:13:59 +110081func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) {
82 for _, clientCipher := range clientCiphers {
83 for _, serverCipher := range serverCiphers {
84 // reject the cipher if we have no cipherModes definition
85 if clientCipher == serverCipher && cipherModes[clientCipher] != nil {
86 return clientCipher, true
87 }
88 }
89 }
Russ Cox470549d2012-01-25 15:31:12 -050090 return
91}
92
93func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
94 kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
95 if !ok {
96 return
97 }
98
99 hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
100 if !ok {
101 return
102 }
103
Dave Cheney1582bf02012-10-30 18:13:59 +1100104 transport.writer.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
Russ Cox470549d2012-01-25 15:31:12 -0500105 if !ok {
106 return
107 }
108
Dave Cheney1582bf02012-10-30 18:13:59 +1100109 transport.reader.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
Russ Cox470549d2012-01-25 15:31:12 -0500110 if !ok {
111 return
112 }
113
114 transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
115 if !ok {
116 return
117 }
118
119 transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
120 if !ok {
121 return
122 }
123
124 transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
125 if !ok {
126 return
127 }
128
129 transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
130 if !ok {
131 return
132 }
133
134 ok = true
135 return
136}
137
138// Cryptographic configuration common to both ServerConfig and ClientConfig.
139type CryptoConfig struct {
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400140 // The allowed key exchanges algorithms. If unspecified then a
141 // default set of algorithms is used.
142 KeyExchanges []string
143
Russ Cox470549d2012-01-25 15:31:12 -0500144 // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
145 // used.
146 Ciphers []string
Dave Cheney6de97b52012-02-27 19:40:52 -0500147
148 // The allowed MAC algorithms. If unspecified then DefaultMACOrder is used.
149 MACs []string
Russ Cox470549d2012-01-25 15:31:12 -0500150}
151
152func (c *CryptoConfig) ciphers() []string {
153 if c.Ciphers == nil {
154 return DefaultCipherOrder
155 }
156 return c.Ciphers
157}
158
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400159func (c *CryptoConfig) kexes() []string {
160 if c.KeyExchanges == nil {
161 return defaultKeyExchangeOrder
162 }
163 return c.KeyExchanges
164}
165
Dave Cheney6de97b52012-02-27 19:40:52 -0500166func (c *CryptoConfig) macs() []string {
167 if c.MACs == nil {
168 return DefaultMACOrder
169 }
170 return c.MACs
171}
172
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400173// serialize a signed slice according to RFC 4254 6.6. The name should
174// be a key type name, rather than a cert type name.
175func serializeSignature(name string, sig []byte) []byte {
176 length := stringLength(len(name))
Adam Langley63f855d2012-04-20 15:17:42 -0400177 length += stringLength(len(sig))
Russ Cox470549d2012-01-25 15:31:12 -0500178
179 ret := make([]byte, length)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400180 r := marshalString(ret, []byte(name))
Russ Cox470549d2012-01-25 15:31:12 -0500181 r = marshalString(r, sig)
182
183 return ret
184}
185
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400186// MarshalPublicKey serializes a supported key or certificate for use
187// by the SSH wire protocol. It can be used for comparison with the
188// pubkey argument of ServerConfig's PublicKeyCallback as well as for
189// generating an authorized_keys or host_keys file.
190func MarshalPublicKey(key PublicKey) []byte {
191 // See also RFC 4253 6.6.
192 algoname := key.PrivateKeyAlgo()
193 blob := key.Marshal()
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500194
Adam Langley63f855d2012-04-20 15:17:42 -0400195 length := stringLength(len(algoname))
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400196 length += len(blob)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500197 ret := make([]byte, length)
198 r := marshalString(ret, []byte(algoname))
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400199 copy(r, blob)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500200 return ret
Russ Cox470549d2012-01-25 15:31:12 -0500201}
202
Jonathan Pittman6a743c52013-09-09 13:06:04 -0400203// pubAlgoToPrivAlgo returns the private key algorithm format name that
204// corresponds to a given public key algorithm format name. For most
205// public keys, the private key algorithm name is the same. For some
206// situations, such as openssh certificates, the private key algorithm and
207// public key algorithm names differ. This accounts for those situations.
208func pubAlgoToPrivAlgo(pubAlgo string) string {
209 switch pubAlgo {
210 case CertAlgoRSAv01:
211 return KeyAlgoRSA
212 case CertAlgoDSAv01:
213 return KeyAlgoDSA
214 case CertAlgoECDSA256v01:
215 return KeyAlgoECDSA256
216 case CertAlgoECDSA384v01:
217 return KeyAlgoECDSA384
218 case CertAlgoECDSA521v01:
219 return KeyAlgoECDSA521
220 }
221 return pubAlgo
222}
223
Russ Cox470549d2012-01-25 15:31:12 -0500224// buildDataSignedForAuth returns the data that is signed in order to prove
225// posession of a private key. See RFC 4252, section 7.
226func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
227 user := []byte(req.User)
228 service := []byte(req.Service)
229 method := []byte(req.Method)
230
Adam Langley63f855d2012-04-20 15:17:42 -0400231 length := stringLength(len(sessionId))
Russ Cox470549d2012-01-25 15:31:12 -0500232 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400233 length += stringLength(len(user))
234 length += stringLength(len(service))
235 length += stringLength(len(method))
Russ Cox470549d2012-01-25 15:31:12 -0500236 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400237 length += stringLength(len(algo))
238 length += stringLength(len(pubKey))
Russ Cox470549d2012-01-25 15:31:12 -0500239
240 ret := make([]byte, length)
241 r := marshalString(ret, sessionId)
242 r[0] = msgUserAuthRequest
243 r = r[1:]
244 r = marshalString(r, user)
245 r = marshalString(r, service)
246 r = marshalString(r, method)
247 r[0] = 1
248 r = r[1:]
249 r = marshalString(r, algo)
250 r = marshalString(r, pubKey)
251 return ret
252}
253
Adam Langley4002be22012-12-10 18:12:36 -0500254// safeString sanitises s according to RFC 4251, section 9.2.
Russ Cox470549d2012-01-25 15:31:12 -0500255// All control characters except tab, carriage return and newline are
256// replaced by 0x20.
257func safeString(s string) string {
258 out := []byte(s)
259 for i, c := range out {
260 if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
261 out[i] = 0x20
262 }
263 }
264 return string(out)
265}
Dave Cheney79d53bd2012-03-04 14:34:24 -0800266
267func appendU16(buf []byte, n uint16) []byte {
268 return append(buf, byte(n>>8), byte(n))
269}
270
271func appendU32(buf []byte, n uint32) []byte {
272 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
273}
274
275func appendInt(buf []byte, n int) []byte {
276 return appendU32(buf, uint32(n))
277}
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000278
Han-Wen Nienhuysc7df5652013-06-06 10:44:12 -0400279func appendString(buf []byte, s string) []byte {
280 buf = appendU32(buf, uint32(len(s)))
281 buf = append(buf, s...)
282 return buf
283}
284
285func appendBool(buf []byte, b bool) []byte {
286 if b {
287 buf = append(buf, 1)
288 } else {
289 buf = append(buf, 0)
290 }
291 return buf
292}
293
Adam Langley4002be22012-12-10 18:12:36 -0500294// newCond is a helper to hide the fact that there is no usable zero
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000295// value for sync.Cond.
296func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
297
Adam Langley4002be22012-12-10 18:12:36 -0500298// window represents the buffer available to clients
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000299// wishing to write to a channel.
300type window struct {
301 *sync.Cond
302 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
303}
304
305// add adds win to the amount of window available
306// for consumers.
307func (w *window) add(win uint32) bool {
Dave Cheney55aa0812012-05-22 12:04:51 +1000308 // a zero sized window adjust is a noop.
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000309 if win == 0 {
Dave Cheney55aa0812012-05-22 12:04:51 +1000310 return true
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000311 }
312 w.L.Lock()
313 if w.win+win < win {
314 w.L.Unlock()
315 return false
316 }
317 w.win += win
318 // It is unusual that multiple goroutines would be attempting to reserve
Adam Langley4002be22012-12-10 18:12:36 -0500319 // window space, but not guaranteed. Use broadcast to notify all waiters
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000320 // that additional window is available.
321 w.Broadcast()
322 w.L.Unlock()
323 return true
324}
325
326// reserve reserves win from the available window capacity.
327// If no capacity remains, reserve will block. reserve may
328// return less than requested.
329func (w *window) reserve(win uint32) uint32 {
330 w.L.Lock()
331 for w.win == 0 {
332 w.Wait()
333 }
334 if w.win < win {
335 win = w.win
336 }
337 w.win -= win
338 w.L.Unlock()
339 return win
340}