blob: e640000ac85429cd088e5f145cbc1baaad7569f1 [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 hostAlgoRSA = "ssh-rsa"
Jonathan Pittman9b05c272012-02-24 12:52:06 -050020 hostAlgoDSA = "ssh-dss"
Russ Cox470549d2012-01-25 15:31:12 -050021 compressionNone = "none"
22 serviceUserAuth = "ssh-userauth"
23 serviceSSH = "ssh-connection"
24)
25
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -040026var supportedKexAlgos = []string{
27 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
28 kexAlgoDH14SHA1, kexAlgoDH1SHA1,
29}
30
Russ Cox470549d2012-01-25 15:31:12 -050031var supportedHostKeyAlgos = []string{hostAlgoRSA}
Russ Cox470549d2012-01-25 15:31:12 -050032var supportedCompressions = []string{compressionNone}
33
Jonathan Pittman6a743c52013-09-09 13:06:04 -040034// hashFuncs keeps the mapping of supported algorithms to their respective
35// hashes needed for signature verification.
36var hashFuncs = map[string]crypto.Hash{
37 KeyAlgoRSA: crypto.SHA1,
38 KeyAlgoDSA: crypto.SHA1,
39 KeyAlgoECDSA256: crypto.SHA256,
40 KeyAlgoECDSA384: crypto.SHA384,
41 KeyAlgoECDSA521: crypto.SHA512,
42 CertAlgoRSAv01: crypto.SHA1,
43 CertAlgoDSAv01: crypto.SHA1,
44 CertAlgoECDSA256v01: crypto.SHA256,
45 CertAlgoECDSA384v01: crypto.SHA384,
46 CertAlgoECDSA521v01: crypto.SHA512,
47}
48
Russ Cox470549d2012-01-25 15:31:12 -050049// UnexpectedMessageError results when the SSH message that we received didn't
50// match what we wanted.
51type UnexpectedMessageError struct {
52 expected, got uint8
53}
54
55func (u UnexpectedMessageError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +110056 return fmt.Sprintf("ssh: unexpected message type %d (expected %d)", u.got, u.expected)
Russ Cox470549d2012-01-25 15:31:12 -050057}
58
59// ParseError results from a malformed SSH message.
60type ParseError struct {
61 msgType uint8
62}
63
64func (p ParseError) Error() string {
Dave Cheney1582bf02012-10-30 18:13:59 +110065 return fmt.Sprintf("ssh: parse error in message type %d", p.msgType)
Russ Cox470549d2012-01-25 15:31:12 -050066}
67
Russ Cox470549d2012-01-25 15:31:12 -050068func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
69 for _, clientAlgo := range clientAlgos {
70 for _, serverAlgo := range serverAlgos {
71 if clientAlgo == serverAlgo {
72 return clientAlgo, true
73 }
74 }
75 }
Dave Cheney1582bf02012-10-30 18:13:59 +110076 return
77}
Russ Cox470549d2012-01-25 15:31:12 -050078
Dave Cheney1582bf02012-10-30 18:13:59 +110079func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCipher string, ok bool) {
80 for _, clientCipher := range clientCiphers {
81 for _, serverCipher := range serverCiphers {
82 // reject the cipher if we have no cipherModes definition
83 if clientCipher == serverCipher && cipherModes[clientCipher] != nil {
84 return clientCipher, true
85 }
86 }
87 }
Russ Cox470549d2012-01-25 15:31:12 -050088 return
89}
90
91func findAgreedAlgorithms(transport *transport, clientKexInit, serverKexInit *kexInitMsg) (kexAlgo, hostKeyAlgo string, ok bool) {
92 kexAlgo, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexInit.KexAlgos)
93 if !ok {
94 return
95 }
96
97 hostKeyAlgo, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgos, serverKexInit.ServerHostKeyAlgos)
98 if !ok {
99 return
100 }
101
Dave Cheney1582bf02012-10-30 18:13:59 +1100102 transport.writer.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer)
Russ Cox470549d2012-01-25 15:31:12 -0500103 if !ok {
104 return
105 }
106
Dave Cheney1582bf02012-10-30 18:13:59 +1100107 transport.reader.cipherAlgo, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient)
Russ Cox470549d2012-01-25 15:31:12 -0500108 if !ok {
109 return
110 }
111
112 transport.writer.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, serverKexInit.MACsClientServer)
113 if !ok {
114 return
115 }
116
117 transport.reader.macAlgo, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, serverKexInit.MACsServerClient)
118 if !ok {
119 return
120 }
121
122 transport.writer.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionClientServer, serverKexInit.CompressionClientServer)
123 if !ok {
124 return
125 }
126
127 transport.reader.compressionAlgo, ok = findCommonAlgorithm(clientKexInit.CompressionServerClient, serverKexInit.CompressionServerClient)
128 if !ok {
129 return
130 }
131
132 ok = true
133 return
134}
135
136// Cryptographic configuration common to both ServerConfig and ClientConfig.
137type CryptoConfig struct {
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400138 // The allowed key exchanges algorithms. If unspecified then a
139 // default set of algorithms is used.
140 KeyExchanges []string
141
Russ Cox470549d2012-01-25 15:31:12 -0500142 // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is
143 // used.
144 Ciphers []string
Dave Cheney6de97b52012-02-27 19:40:52 -0500145
146 // The allowed MAC algorithms. If unspecified then DefaultMACOrder is used.
147 MACs []string
Russ Cox470549d2012-01-25 15:31:12 -0500148}
149
150func (c *CryptoConfig) ciphers() []string {
151 if c.Ciphers == nil {
152 return DefaultCipherOrder
153 }
154 return c.Ciphers
155}
156
Han-Wen Nienhuysd7d50b02013-08-28 10:50:25 -0400157func (c *CryptoConfig) kexes() []string {
158 if c.KeyExchanges == nil {
159 return defaultKeyExchangeOrder
160 }
161 return c.KeyExchanges
162}
163
Dave Cheney6de97b52012-02-27 19:40:52 -0500164func (c *CryptoConfig) macs() []string {
165 if c.MACs == nil {
166 return DefaultMACOrder
167 }
168 return c.MACs
169}
170
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400171// serialize a signed slice according to RFC 4254 6.6. The name should
172// be a key type name, rather than a cert type name.
173func serializeSignature(name string, sig []byte) []byte {
174 length := stringLength(len(name))
Adam Langley63f855d2012-04-20 15:17:42 -0400175 length += stringLength(len(sig))
Russ Cox470549d2012-01-25 15:31:12 -0500176
177 ret := make([]byte, length)
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400178 r := marshalString(ret, []byte(name))
Russ Cox470549d2012-01-25 15:31:12 -0500179 r = marshalString(r, sig)
180
181 return ret
182}
183
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400184// MarshalPublicKey serializes a supported key or certificate for use
185// by the SSH wire protocol. It can be used for comparison with the
186// pubkey argument of ServerConfig's PublicKeyCallback as well as for
187// generating an authorized_keys or host_keys file.
188func MarshalPublicKey(key PublicKey) []byte {
189 // See also RFC 4253 6.6.
190 algoname := key.PrivateKeyAlgo()
191 blob := key.Marshal()
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500192
Adam Langley63f855d2012-04-20 15:17:42 -0400193 length := stringLength(len(algoname))
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400194 length += len(blob)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500195 ret := make([]byte, length)
196 r := marshalString(ret, []byte(algoname))
Han-Wen Nienhuyse62b2ae2013-09-13 14:25:14 -0400197 copy(r, blob)
Jonathan Pittman9b05c272012-02-24 12:52:06 -0500198 return ret
Russ Cox470549d2012-01-25 15:31:12 -0500199}
200
Jonathan Pittman6a743c52013-09-09 13:06:04 -0400201// pubAlgoToPrivAlgo returns the private key algorithm format name that
202// corresponds to a given public key algorithm format name. For most
203// public keys, the private key algorithm name is the same. For some
204// situations, such as openssh certificates, the private key algorithm and
205// public key algorithm names differ. This accounts for those situations.
206func pubAlgoToPrivAlgo(pubAlgo string) string {
207 switch pubAlgo {
208 case CertAlgoRSAv01:
209 return KeyAlgoRSA
210 case CertAlgoDSAv01:
211 return KeyAlgoDSA
212 case CertAlgoECDSA256v01:
213 return KeyAlgoECDSA256
214 case CertAlgoECDSA384v01:
215 return KeyAlgoECDSA384
216 case CertAlgoECDSA521v01:
217 return KeyAlgoECDSA521
218 }
219 return pubAlgo
220}
221
Russ Cox470549d2012-01-25 15:31:12 -0500222// buildDataSignedForAuth returns the data that is signed in order to prove
223// posession of a private key. See RFC 4252, section 7.
224func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubKey []byte) []byte {
225 user := []byte(req.User)
226 service := []byte(req.Service)
227 method := []byte(req.Method)
228
Adam Langley63f855d2012-04-20 15:17:42 -0400229 length := stringLength(len(sessionId))
Russ Cox470549d2012-01-25 15:31:12 -0500230 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400231 length += stringLength(len(user))
232 length += stringLength(len(service))
233 length += stringLength(len(method))
Russ Cox470549d2012-01-25 15:31:12 -0500234 length += 1
Adam Langley63f855d2012-04-20 15:17:42 -0400235 length += stringLength(len(algo))
236 length += stringLength(len(pubKey))
Russ Cox470549d2012-01-25 15:31:12 -0500237
238 ret := make([]byte, length)
239 r := marshalString(ret, sessionId)
240 r[0] = msgUserAuthRequest
241 r = r[1:]
242 r = marshalString(r, user)
243 r = marshalString(r, service)
244 r = marshalString(r, method)
245 r[0] = 1
246 r = r[1:]
247 r = marshalString(r, algo)
248 r = marshalString(r, pubKey)
249 return ret
250}
251
Adam Langley4002be22012-12-10 18:12:36 -0500252// safeString sanitises s according to RFC 4251, section 9.2.
Russ Cox470549d2012-01-25 15:31:12 -0500253// All control characters except tab, carriage return and newline are
254// replaced by 0x20.
255func safeString(s string) string {
256 out := []byte(s)
257 for i, c := range out {
258 if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
259 out[i] = 0x20
260 }
261 }
262 return string(out)
263}
Dave Cheney79d53bd2012-03-04 14:34:24 -0800264
265func appendU16(buf []byte, n uint16) []byte {
266 return append(buf, byte(n>>8), byte(n))
267}
268
269func appendU32(buf []byte, n uint32) []byte {
270 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
271}
272
273func appendInt(buf []byte, n int) []byte {
274 return appendU32(buf, uint32(n))
275}
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000276
Han-Wen Nienhuysc7df5652013-06-06 10:44:12 -0400277func appendString(buf []byte, s string) []byte {
278 buf = appendU32(buf, uint32(len(s)))
279 buf = append(buf, s...)
280 return buf
281}
282
283func appendBool(buf []byte, b bool) []byte {
284 if b {
285 buf = append(buf, 1)
286 } else {
287 buf = append(buf, 0)
288 }
289 return buf
290}
291
Adam Langley4002be22012-12-10 18:12:36 -0500292// newCond is a helper to hide the fact that there is no usable zero
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000293// value for sync.Cond.
294func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
295
Adam Langley4002be22012-12-10 18:12:36 -0500296// window represents the buffer available to clients
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000297// wishing to write to a channel.
298type window struct {
299 *sync.Cond
300 win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
301}
302
303// add adds win to the amount of window available
304// for consumers.
305func (w *window) add(win uint32) bool {
Dave Cheney55aa0812012-05-22 12:04:51 +1000306 // a zero sized window adjust is a noop.
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000307 if win == 0 {
Dave Cheney55aa0812012-05-22 12:04:51 +1000308 return true
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000309 }
310 w.L.Lock()
311 if w.win+win < win {
312 w.L.Unlock()
313 return false
314 }
315 w.win += win
316 // It is unusual that multiple goroutines would be attempting to reserve
Adam Langley4002be22012-12-10 18:12:36 -0500317 // window space, but not guaranteed. Use broadcast to notify all waiters
Dave Cheney8a2e7c92012-05-11 05:56:44 +1000318 // that additional window is available.
319 w.Broadcast()
320 w.L.Unlock()
321 return true
322}
323
324// reserve reserves win from the available window capacity.
325// If no capacity remains, reserve will block. reserve may
326// return less than requested.
327func (w *window) reserve(win uint32) uint32 {
328 w.L.Lock()
329 for w.win == 0 {
330 w.Wait()
331 }
332 if w.win < win {
333 win = w.win
334 }
335 w.win -= win
336 w.L.Unlock()
337 return win
338}