Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(416)

Delta Between Two Patch Sets: ssh/common.go

Issue 86190043: code review 86190043: go.crypto/ssh: import gosshnew. (Closed)
Left Patch Set: Created 10 years, 11 months ago
Right Patch Set: diff -r 2990fc550b9f https://code.google.com/p/go.crypto Created 10 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « ssh/client_test.go ('k') | ssh/connection.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package ssh 5 package ssh
6 6
7 import ( 7 import (
8 "crypto" 8 "crypto"
9 "crypto/rand"
9 "fmt" 10 "fmt"
11 "io"
10 "sync" 12 "sync"
11 13
12 _ "crypto/sha1" 14 _ "crypto/sha1"
13 _ "crypto/sha256" 15 _ "crypto/sha256"
14 _ "crypto/sha512" 16 _ "crypto/sha512"
15 ) 17 )
16 18
17 // These are string constants in the SSH protocol. 19 // These are string constants in the SSH protocol.
18 const ( 20 const (
19 compressionNone = "none" 21 compressionNone = "none"
20 serviceUserAuth = "ssh-userauth" 22 serviceUserAuth = "ssh-userauth"
21 serviceSSH = "ssh-connection" 23 serviceSSH = "ssh-connection"
22 ) 24 )
23 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.
24 var supportedKexAlgos = []string{ 35 var supportedKexAlgos = []string{
36 // P384 and P521 are not constant-time yet, but since we don't
37 // reuse ephemeral keys, using them for ECDH should be OK.
25 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521, 38 kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
26 kexAlgoDH14SHA1, kexAlgoDH1SHA1, 39 kexAlgoDH14SHA1, kexAlgoDH1SHA1,
27 } 40 }
28 41
42 // supportedKexAlgos specifies the supported host-key algorithms (i.e. methods
43 // of authenticating servers) in preference order.
29 var supportedHostKeyAlgos = []string{ 44 var supportedHostKeyAlgos = []string{
45 CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
46 CertAlgoECDSA384v01, CertAlgoECDSA521v01,
47
30 KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, 48 KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
31 KeyAlgoRSA, KeyAlgoDSA, 49 KeyAlgoRSA, KeyAlgoDSA,
50 }
51
52 // supportedMACs specifies a default set of MAC algorithms in preference order.
53 // This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
54 // because they have reached the end of their useful life.
55 var supportedMACs = []string{
56 "hmac-sha1", "hmac-sha1-96",
32 } 57 }
33 58
34 var supportedCompressions = []string{compressionNone} 59 var supportedCompressions = []string{compressionNone}
35 60
36 // hashFuncs keeps the mapping of supported algorithms to their respective 61 // hashFuncs keeps the mapping of supported algorithms to their respective
37 // hashes needed for signature verification. 62 // hashes needed for signature verification.
38 var hashFuncs = map[string]crypto.Hash{ 63 var hashFuncs = map[string]crypto.Hash{
39 KeyAlgoRSA: crypto.SHA1, 64 KeyAlgoRSA: crypto.SHA1,
40 KeyAlgoDSA: crypto.SHA1, 65 KeyAlgoDSA: crypto.SHA1,
41 KeyAlgoECDSA256: crypto.SHA256, 66 KeyAlgoECDSA256: crypto.SHA256,
42 KeyAlgoECDSA384: crypto.SHA384, 67 KeyAlgoECDSA384: crypto.SHA384,
43 KeyAlgoECDSA521: crypto.SHA512, 68 KeyAlgoECDSA521: crypto.SHA512,
44 CertAlgoRSAv01: crypto.SHA1, 69 CertAlgoRSAv01: crypto.SHA1,
45 CertAlgoDSAv01: crypto.SHA1, 70 CertAlgoDSAv01: crypto.SHA1,
46 CertAlgoECDSA256v01: crypto.SHA256, 71 CertAlgoECDSA256v01: crypto.SHA256,
47 CertAlgoECDSA384v01: crypto.SHA384, 72 CertAlgoECDSA384v01: crypto.SHA384,
48 CertAlgoECDSA521v01: crypto.SHA512, 73 CertAlgoECDSA521v01: crypto.SHA512,
49 } 74 }
50 75
51 // UnexpectedMessageError results when the SSH message that we received didn't 76 // unexpectedMessageError results when the SSH message that we received didn't
52 // match what we wanted. 77 // match what we wanted.
53 type UnexpectedMessageError struct { 78 func unexpectedMessageError(expected, got uint8) error {
54 » expected, got uint8 79 » return fmt.Errorf("ssh: unexpected message type %d (expected %d)", got, expected)
55 } 80 }
56 81
57 func (u UnexpectedMessageError) Error() string { 82 // parseError results from a malformed SSH message.
58 » return fmt.Sprintf("ssh: unexpected message type %d (expected %d)", u.go t, u.expected) 83 func parseError(tag uint8) error {
59 } 84 » return fmt.Errorf("ssh: parse error in message type %d", tag)
60
61 // ParseError results from a malformed SSH message.
62 type ParseError struct {
63 » msgType uint8
64 }
65
66 func (p ParseError) Error() string {
67 » return fmt.Sprintf("ssh: parse error in message type %d", p.msgType)
68 } 85 }
69 86
70 func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) { 87 func findCommonAlgorithm(clientAlgos []string, serverAlgos []string) (commonAlgo string, ok bool) {
71 for _, clientAlgo := range clientAlgos { 88 for _, clientAlgo := range clientAlgos {
72 for _, serverAlgo := range serverAlgos { 89 for _, serverAlgo := range serverAlgos {
73 if clientAlgo == serverAlgo { 90 if clientAlgo == serverAlgo {
74 return clientAlgo, true 91 return clientAlgo, true
75 } 92 }
76 } 93 }
77 } 94 }
78 return 95 return
79 } 96 }
80 97
81 func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCip her string, ok bool) { 98 func findCommonCipher(clientCiphers []string, serverCiphers []string) (commonCip her string, ok bool) {
82 for _, clientCipher := range clientCiphers { 99 for _, clientCipher := range clientCiphers {
83 for _, serverCipher := range serverCiphers { 100 for _, serverCipher := range serverCiphers {
84 // reject the cipher if we have no cipherModes definitio n 101 // reject the cipher if we have no cipherModes definitio n
85 if clientCipher == serverCipher && cipherModes[clientCip her] != nil { 102 if clientCipher == serverCipher && cipherModes[clientCip her] != nil {
86 return clientCipher, true 103 return clientCipher, true
87 } 104 }
88 } 105 }
89 } 106 }
90 return 107 return
91 } 108 }
92 109
110 type directionAlgorithms struct {
111 Cipher string
112 MAC string
113 Compression string
114 }
115
93 type algorithms struct { 116 type algorithms struct {
94 » kex string 117 » kex string
95 » hostKey string 118 » hostKey string
96 » wCipher string 119 » w directionAlgorithms
97 » rCipher string 120 » r directionAlgorithms
98 » rMAC string
99 » wMAC string
100 » rCompression string
101 » wCompression string
102 } 121 }
103 122
104 func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor ithms) { 123 func findAgreedAlgorithms(clientKexInit, serverKexInit *kexInitMsg) (algs *algor ithms) {
105 var ok bool 124 var ok bool
106 result := &algorithms{} 125 result := &algorithms{}
107 result.kex, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexIn it.KexAlgos) 126 result.kex, ok = findCommonAlgorithm(clientKexInit.KexAlgos, serverKexIn it.KexAlgos)
108 if !ok { 127 if !ok {
109 return 128 return
110 } 129 }
111 130
112 result.hostKey, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgo s, serverKexInit.ServerHostKeyAlgos) 131 result.hostKey, ok = findCommonAlgorithm(clientKexInit.ServerHostKeyAlgo s, serverKexInit.ServerHostKeyAlgos)
113 if !ok { 132 if !ok {
114 return 133 return
115 } 134 }
116 135
117 » result.wCipher, ok = findCommonCipher(clientKexInit.CiphersClientServer, serverKexInit.CiphersClientServer) 136 » result.w.Cipher, ok = findCommonCipher(clientKexInit.CiphersClientServer , serverKexInit.CiphersClientServer)
118 » if !ok { 137 » if !ok {
119 » » return 138 » » return
120 » } 139 » }
121 140
122 » result.rCipher, ok = findCommonCipher(clientKexInit.CiphersServerClient, serverKexInit.CiphersServerClient) 141 » result.r.Cipher, ok = findCommonCipher(clientKexInit.CiphersServerClient , serverKexInit.CiphersServerClient)
123 » if !ok { 142 » if !ok {
124 » » return 143 » » return
125 » } 144 » }
126 145
127 » result.wMAC, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, se rverKexInit.MACsClientServer) 146 » result.w.MAC, ok = findCommonAlgorithm(clientKexInit.MACsClientServer, s erverKexInit.MACsClientServer)
128 » if !ok { 147 » if !ok {
129 » » return 148 » » return
130 » } 149 » }
131 150
132 » result.rMAC, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, se rverKexInit.MACsServerClient) 151 » result.r.MAC, ok = findCommonAlgorithm(clientKexInit.MACsServerClient, s erverKexInit.MACsServerClient)
133 » if !ok { 152 » if !ok {
134 » » return 153 » » return
135 » } 154 » }
136 155
137 » result.wCompression, ok = findCommonAlgorithm(clientKexInit.CompressionC lientServer, serverKexInit.CompressionClientServer) 156 » result.w.Compression, ok = findCommonAlgorithm(clientKexInit.Compression ClientServer, serverKexInit.CompressionClientServer)
138 » if !ok { 157 » if !ok {
139 » » return 158 » » return
140 » } 159 » }
141 160
142 » result.rCompression, ok = findCommonAlgorithm(clientKexInit.CompressionS erverClient, serverKexInit.CompressionServerClient) 161 » result.r.Compression, ok = findCommonAlgorithm(clientKexInit.Compression ServerClient, serverKexInit.CompressionServerClient)
143 if !ok { 162 if !ok {
144 return 163 return
145 } 164 }
146 165
147 return result 166 return result
148 } 167 }
149 168
150 // Cryptographic configuration common to both ServerConfig and ClientConfig. 169 // If rekeythreshold is too small, we can't make any progress sending
151 type CryptoConfig struct { 170 // stuff.
171 const minRekeyThreshold uint64 = 256
172
173 // Config contains configuration data common to both ServerConfig and
174 // ClientConfig.
175 type Config struct {
176 » // Rand provides the source of entropy for cryptographic
177 » // primitives. If Rand is nil, the cryptographic random reader
178 » // in package crypto/rand will be used.
179 » Rand io.Reader
180
181 » // The maximum number of bytes sent or received after which a
182 » // new key is negotiated. It must be at least 256. If
183 » // unspecified, 1 gigabyte is used.
184 » RekeyThreshold uint64
185
152 // The allowed key exchanges algorithms. If unspecified then a 186 // The allowed key exchanges algorithms. If unspecified then a
153 // default set of algorithms is used. 187 // default set of algorithms is used.
154 KeyExchanges []string 188 KeyExchanges []string
155 189
156 » // The allowed cipher algorithms. If unspecified then DefaultCipherOrder is 190 » // The allowed cipher algorithms. If unspecified then a sensible
157 » // used. 191 » // default is used.
158 Ciphers []string 192 Ciphers []string
159 193
160 » // The allowed MAC algorithms. If unspecified then DefaultMACOrder is us ed. 194 » // The allowed MAC algorithms. If unspecified then a sensible default
195 » // is used.
161 MACs []string 196 MACs []string
162 } 197 }
163 198
164 func (c *CryptoConfig) ciphers() []string { 199 // SetDefaults sets sensible values for unset fields in config. This is
200 // exported for testing: Configs passed to SSH functions are copied and have
201 // default values set automatically.
202 func (c *Config) SetDefaults() {
203 » if c.Rand == nil {
204 » » c.Rand = rand.Reader
205 » }
165 if c.Ciphers == nil { 206 if c.Ciphers == nil {
166 » » return DefaultCipherOrder 207 » » c.Ciphers = supportedCiphers
167 » } 208 » }
168 » return c.Ciphers 209
169 }
170
171 func (c *CryptoConfig) kexes() []string {
172 if c.KeyExchanges == nil { 210 if c.KeyExchanges == nil {
173 » » return defaultKeyExchangeOrder 211 » » c.KeyExchanges = supportedKexAlgos
174 » } 212 » }
175 » return c.KeyExchanges 213
176 }
177
178 func (c *CryptoConfig) macs() []string {
179 if c.MACs == nil { 214 if c.MACs == nil {
180 » » return DefaultMACOrder 215 » » c.MACs = supportedMACs
181 » } 216 » }
182 » return c.MACs 217
183 } 218 » if c.RekeyThreshold == 0 {
184 219 » » // RFC 4253, section 9 suggests rekeying after 1G.
185 // serialize a signed slice according to RFC 4254 6.6. The name should 220 » » c.RekeyThreshold = 1 << 30
186 // be a key type name, rather than a cert type name. 221 » }
187 func serializeSignature(name string, sig []byte) []byte { 222 » if c.RekeyThreshold < minRekeyThreshold {
188 » length := stringLength(len(name)) 223 » » c.RekeyThreshold = minRekeyThreshold
189 » length += stringLength(len(sig)) 224 » }
190
191 » ret := make([]byte, length)
192 » r := marshalString(ret, []byte(name))
193 » r = marshalString(r, sig)
194
195 » return ret
196 }
197
198 // MarshalPublicKey serializes a supported key or certificate for use
199 // by the SSH wire protocol. It can be used for comparison with the
200 // pubkey argument of ServerConfig's PublicKeyCallback as well as for
201 // generating an authorized_keys or host_keys file.
202 func MarshalPublicKey(key PublicKey) []byte {
203 » // See also RFC 4253 6.6.
204 » algoname := key.PublicKeyAlgo()
205 » blob := key.Marshal()
206
207 » length := stringLength(len(algoname))
208 » length += len(blob)
209 » ret := make([]byte, length)
210 » r := marshalString(ret, []byte(algoname))
211 » copy(r, blob)
212 » return ret
213 }
214
215 // pubAlgoToPrivAlgo returns the private key algorithm format name that
216 // corresponds to a given public key algorithm format name. For most
217 // public keys, the private key algorithm name is the same. For some
218 // situations, such as openssh certificates, the private key algorithm and
219 // public key algorithm names differ. This accounts for those situations.
220 func pubAlgoToPrivAlgo(pubAlgo string) string {
221 » switch pubAlgo {
222 » case CertAlgoRSAv01:
223 » » return KeyAlgoRSA
224 » case CertAlgoDSAv01:
225 » » return KeyAlgoDSA
226 » case CertAlgoECDSA256v01:
227 » » return KeyAlgoECDSA256
228 » case CertAlgoECDSA384v01:
229 » » return KeyAlgoECDSA384
230 » case CertAlgoECDSA521v01:
231 » » return KeyAlgoECDSA521
232 » }
233 » return pubAlgo
234 } 225 }
235 226
236 // buildDataSignedForAuth returns the data that is signed in order to prove 227 // buildDataSignedForAuth returns the data that is signed in order to prove
237 // possession of a private key. See RFC 4252, section 7. 228 // possession of a private key. See RFC 4252, section 7.
238 func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubK ey []byte) []byte { 229 func buildDataSignedForAuth(sessionId []byte, req userAuthRequestMsg, algo, pubK ey []byte) []byte {
239 » user := []byte(req.User) 230 » data := struct {
240 » service := []byte(req.Service) 231 » » Session []byte
241 » method := []byte(req.Method) 232 » » Type byte
242 233 » » User string
243 » length := stringLength(len(sessionId)) 234 » » Service string
244 » length += 1 235 » » Method string
245 » length += stringLength(len(user)) 236 » » Sign bool
246 » length += stringLength(len(service)) 237 » » Algo []byte
247 » length += stringLength(len(method)) 238 » » PubKey []byte
248 » length += 1 239 » }{
249 » length += stringLength(len(algo)) 240 » » sessionId,
250 » length += stringLength(len(pubKey)) 241 » » msgUserAuthRequest,
251 242 » » req.User,
252 » ret := make([]byte, length) 243 » » req.Service,
253 » r := marshalString(ret, sessionId) 244 » » req.Method,
254 » r[0] = msgUserAuthRequest 245 » » true,
255 » r = r[1:] 246 » » algo,
256 » r = marshalString(r, user) 247 » » pubKey,
257 » r = marshalString(r, service) 248 » }
258 » r = marshalString(r, method) 249 » return Marshal(data)
259 » r[0] = 1
260 » r = r[1:]
261 » r = marshalString(r, algo)
262 » r = marshalString(r, pubKey)
263 » return ret
264 }
265
266 // safeString sanitises s according to RFC 4251, section 9.2.
267 // All control characters except tab, carriage return and newline are
268 // replaced by 0x20.
269 func safeString(s string) string {
270 » out := []byte(s)
271 » for i, c := range out {
272 » » if c < 0x20 && c != 0xd && c != 0xa && c != 0x9 {
273 » » » out[i] = 0x20
274 » » }
275 » }
276 » return string(out)
277 } 250 }
278 251
279 func appendU16(buf []byte, n uint16) []byte { 252 func appendU16(buf []byte, n uint16) []byte {
280 return append(buf, byte(n>>8), byte(n)) 253 return append(buf, byte(n>>8), byte(n))
281 } 254 }
282 255
283 func appendU32(buf []byte, n uint32) []byte { 256 func appendU32(buf []byte, n uint32) []byte {
284 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) 257 return append(buf, byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
258 }
259
260 func appendU64(buf []byte, n uint64) []byte {
261 return append(buf,
262 byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32),
263 byte(n>>24), byte(n>>16), byte(n>>8), byte(n))
285 } 264 }
286 265
287 func appendInt(buf []byte, n int) []byte { 266 func appendInt(buf []byte, n int) []byte {
288 return appendU32(buf, uint32(n)) 267 return appendU32(buf, uint32(n))
289 } 268 }
290 269
291 func appendString(buf []byte, s string) []byte { 270 func appendString(buf []byte, s string) []byte {
292 buf = appendU32(buf, uint32(len(s))) 271 buf = appendU32(buf, uint32(len(s)))
293 buf = append(buf, s...) 272 buf = append(buf, s...)
294 return buf 273 return buf
295 } 274 }
296 275
297 func appendBool(buf []byte, b bool) []byte { 276 func appendBool(buf []byte, b bool) []byte {
298 if b { 277 if b {
299 » » buf = append(buf, 1) 278 » » return append(buf, 1)
300 » } else { 279 » }
301 » » buf = append(buf, 0) 280 » return append(buf, 0)
302 » }
303 » return buf
304 } 281 }
305 282
306 // newCond is a helper to hide the fact that there is no usable zero 283 // newCond is a helper to hide the fact that there is no usable zero
307 // value for sync.Cond. 284 // value for sync.Cond.
308 func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) } 285 func newCond() *sync.Cond { return sync.NewCond(new(sync.Mutex)) }
309 286
310 // window represents the buffer available to clients 287 // window represents the buffer available to clients
311 // wishing to write to a channel. 288 // wishing to write to a channel.
312 type window struct { 289 type window struct {
313 *sync.Cond 290 *sync.Cond
314 » win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1 291 » win uint32 // RFC 4254 5.2 says the window size can grow to 2^3 2-1
292 » writeWaiters int
293 » closed bool
315 } 294 }
316 295
317 // add adds win to the amount of window available 296 // add adds win to the amount of window available
318 // for consumers. 297 // for consumers.
319 func (w *window) add(win uint32) bool { 298 func (w *window) add(win uint32) bool {
320 // a zero sized window adjust is a noop. 299 // a zero sized window adjust is a noop.
321 if win == 0 { 300 if win == 0 {
322 return true 301 return true
323 } 302 }
324 w.L.Lock() 303 w.L.Lock()
325 if w.win+win < win { 304 if w.win+win < win {
326 w.L.Unlock() 305 w.L.Unlock()
327 return false 306 return false
328 } 307 }
329 w.win += win 308 w.win += win
330 // It is unusual that multiple goroutines would be attempting to reserve 309 // It is unusual that multiple goroutines would be attempting to reserve
331 // window space, but not guaranteed. Use broadcast to notify all waiters 310 // window space, but not guaranteed. Use broadcast to notify all waiters
332 // that additional window is available. 311 // that additional window is available.
333 w.Broadcast() 312 w.Broadcast()
334 w.L.Unlock() 313 w.L.Unlock()
335 return true 314 return true
336 } 315 }
337 316
317 // close sets the window to closed, so all reservations fail
318 // immediately.
319 func (w *window) close() {
320 w.L.Lock()
321 w.closed = true
322 w.Broadcast()
323 w.L.Unlock()
324 }
325
338 // reserve reserves win from the available window capacity. 326 // reserve reserves win from the available window capacity.
339 // If no capacity remains, reserve will block. reserve may 327 // If no capacity remains, reserve will block. reserve may
340 // return less than requested. 328 // return less than requested.
341 func (w *window) reserve(win uint32) uint32 { 329 func (w *window) reserve(win uint32) (uint32, error) {
330 » var err error
342 w.L.Lock() 331 w.L.Lock()
343 » for w.win == 0 { 332 » w.writeWaiters++
333 » w.Broadcast()
334 » for w.win == 0 && !w.closed {
344 w.Wait() 335 w.Wait()
345 } 336 }
337 w.writeWaiters--
346 if w.win < win { 338 if w.win < win {
347 win = w.win 339 win = w.win
348 } 340 }
349 w.win -= win 341 w.win -= win
342 if w.closed {
343 err = io.EOF
344 }
350 w.L.Unlock() 345 w.L.Unlock()
351 » return win 346 » return win, err
352 } 347 }
348
349 // waitWriterBlocked waits until some goroutine is blocked for further
350 // writes. It is used in tests only.
351 func (w *window) waitWriterBlocked() {
352 » w.Cond.L.Lock()
353 » for w.writeWaiters == 0 {
354 » » w.Cond.Wait()
355 » }
356 » w.Cond.L.Unlock()
357 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b