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

Delta Between Two Patch Sets: ssh/test/test_unix_test.go

Issue 14494058: code review 14494058: go.crypto/ssh: support rekeying in both directions. (Closed)
Left Patch Set: diff -r 5ff5636e18c9 https://code.google.com/p/go.crypto Created 10 years, 5 months ago
Right Patch Set: diff -r cd1eea1eb828 https://code.google.com/p/go.crypto Created 10 years, 5 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:
Left: Side by side diff | Download
Right: Side by side diff | Download
LEFTRIGHT
1 // Copyright 2012 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
5 // +build darwin freebsd linux netbsd openbsd
6
7 package test
8
9 // functional test harness for unix.
10
11 import (
12 "bytes"
13 "fmt"
14 "io"
15 "io/ioutil"
16 "log"
17 "net"
18 "os"
19 "os/exec"
20 "os/user"
21 "path/filepath"
22 "testing"
23 "text/template"
24
25 "code.google.com/p/go.crypto/ssh"
26 )
27
28 const sshd_config = `
29 Protocol 2
30 HostKey {{.Dir}}/ssh_host_rsa_key
31 HostKey {{.Dir}}/ssh_host_dsa_key
32 HostKey {{.Dir}}/ssh_host_ecdsa_key
33 Pidfile {{.Dir}}/sshd.pid
34 #UsePrivilegeSeparation no
35 KeyRegenerationInterval 3600
36 ServerKeyBits 768
37 SyslogFacility AUTH
38 LogLevel DEBUG2
39 LoginGraceTime 120
40 PermitRootLogin no
41 StrictModes no
42 RSAAuthentication yes
43 PubkeyAuthentication yes
44 AuthorizedKeysFile {{.Dir}}/authorized_keys
45 IgnoreRhosts yes
46 RhostsRSAAuthentication no
47 HostbasedAuthentication no
48 `
49
50 var (
51 configTmpl template.Template
52 privateKey ssh.Signer
53 hostKeyRSA ssh.Signer
54 hostKeyECDSA ssh.Signer
55 hostKeyDSA ssh.Signer
56 )
57
58 func init() {
59 template.Must(configTmpl.Parse(sshd_config))
60
61 for n, k := range map[string]*ssh.Signer{
62 "ssh_host_ecdsa_key": &hostKeyECDSA,
63 "ssh_host_rsa_key": &hostKeyRSA,
64 "ssh_host_dsa_key": &hostKeyDSA,
65 } {
66 var err error
67 *k, err = ssh.ParsePrivateKey([]byte(keys[n]))
68 if err != nil {
69 panic(fmt.Sprintf("ParsePrivateKey(%q): %v", n, err))
70 }
71 }
72
73 var err error
74 privateKey, err = ssh.ParsePrivateKey([]byte(testClientPrivateKey))
75 if err != nil {
76 panic(fmt.Sprintf("ParsePrivateKey: %v", err))
77 }
78 }
79
80 type server struct {
81 t *testing.T
82 cleanup func() // executed during Shutdown
83 configfile string
84 cmd *exec.Cmd
85 output bytes.Buffer // holds stderr from sshd process
86
87 // Client half of the network connection.
88 clientConn net.Conn
89 }
90
91 func username() string {
92 var username string
93 if user, err := user.Current(); err == nil {
94 username = user.Username
95 } else {
96 // user.Current() currently requires cgo. If an error is
97 // returned attempt to get the username from the environment.
98 log.Printf("user.Current: %v; falling back on $USER", err)
99 username = os.Getenv("USER")
100 }
101 if username == "" {
102 panic("Unable to get username")
103 }
104 return username
105 }
1 106
2 type storedHostKey struct { 107 type storedHostKey struct {
3 // keys map from an algorithm string to binary key data. 108 // keys map from an algorithm string to binary key data.
4 keys map[string][]byte 109 keys map[string][]byte
110
111 // checkCount counts the Check calls. Used for testing
112 // rekeying.
113 checkCount int
5 } 114 }
6 115
7 func (k *storedHostKey) Add(key ssh.PublicKey) { 116 func (k *storedHostKey) Add(key ssh.PublicKey) {
117 if k.keys == nil {
118 k.keys = map[string][]byte{}
119 }
120 k.keys[key.PublicKeyAlgo()] = ssh.MarshalPublicKey(key)
121 }
122
123 func (k *storedHostKey) Check(addr string, remote net.Addr, algo string, key []b yte) error {
124 k.checkCount++
125 if k.keys == nil || bytes.Compare(key, k.keys[algo]) != 0 {
126 return fmt.Errorf("host key mismatch. Got %q, want %q", key, k.k eys[algo])
127 }
128 return nil
129 }
130
131 func clientConfig() *ssh.ClientConfig {
132 keyChecker := storedHostKey{}
133 keyChecker.Add(hostKeyECDSA.PublicKey())
134 keyChecker.Add(hostKeyRSA.PublicKey())
135 keyChecker.Add(hostKeyDSA.PublicKey())
136
137 kc := new(keychain)
138 kc.keys = append(kc.keys, privateKey)
139 config := &ssh.ClientConfig{
140 User: username(),
141 Auth: []ssh.ClientAuth{
142 ssh.ClientAuthKeyring(kc),
143 },
144 HostKeyChecker: &keyChecker,
145 }
146 return config
147 }
148
149 // unixConnection creates two halves of a connected net.UnixConn. It
150 // is used for connecting the Go SSH client with sshd without opening
151 // ports.
152 func unixConnection() (*net.UnixConn, *net.UnixConn, error) {
153 dir, err := ioutil.TempDir("", "unixConnection")
154 if err != nil {
155 return nil, nil, err
156 }
157 defer os.Remove(dir)
158
159 addr := filepath.Join(dir, "ssh")
160 listener, err := net.Listen("unix", addr)
161 if err != nil {
162 return nil, nil, err
163 }
164 defer listener.Close()
165 c1, err := net.Dial("unix", addr)
166 if err != nil {
167 return nil, nil, err
168 }
169
170 c2, err := listener.Accept()
171 if err != nil {
172 c1.Close()
173 return nil, nil, err
174 }
175
176 return c1.(*net.UnixConn), c2.(*net.UnixConn), nil
177 }
178
179 func (s *server) TryDial(config *ssh.ClientConfig) (*ssh.ClientConn, error) {
180 sshd, err := exec.LookPath("sshd")
181 if err != nil {
182 s.t.Skipf("skipping test: %v", err)
183 }
184
185 c1, c2, err := unixConnection()
186 if err != nil {
187 s.t.Fatalf("unixConnection: %v", err)
188 }
189
190 s.cmd = exec.Command(sshd, "-f", s.configfile, "-i", "-e")
191 f, err := c2.File()
192 if err != nil {
193 s.t.Fatalf("UnixConn.File: %v", err)
194 }
195 defer f.Close()
196 s.cmd.Stdin = f
197 s.cmd.Stdout = f
198 s.cmd.Stderr = &s.output
199 if err := s.cmd.Start(); err != nil {
200 s.t.Fail()
201 s.Shutdown()
202 s.t.Fatalf("s.cmd.Start: %v", err)
203 }
204 s.clientConn = c1
205 return ssh.Client(c1, config)
206 }
207
208 func (s *server) Dial(config *ssh.ClientConfig) *ssh.ClientConn {
209 conn, err := s.TryDial(config)
210 if err != nil {
211 s.t.Fail()
212 s.Shutdown()
213 s.t.Fatalf("ssh.Client: %v", err)
214 }
215 return conn
216 }
217
218 func (s *server) Shutdown() {
219 if s.cmd != nil && s.cmd.Process != nil {
220 // Don't check for errors; if it fails it's most
221 // likely "os: process already finished", and we don't
222 // care about that. Use os.Interrupt, so child
223 // processes are killed too.
224 s.cmd.Process.Signal(os.Interrupt)
225 s.cmd.Wait()
226 }
227 if s.t.Failed() {
228 // log any output from sshd process
229 s.t.Logf("sshd: %s", s.output.String())
230 }
231 s.cleanup()
232 }
233
234 // newServer returns a new mock ssh server.
235 func newServer(t *testing.T) *server {
236 dir, err := ioutil.TempDir("", "sshtest")
237 if err != nil {
238 t.Fatal(err)
239 }
240 f, err := os.Create(filepath.Join(dir, "sshd_config"))
241 if err != nil {
242 t.Fatal(err)
243 }
244 err = configTmpl.Execute(f, map[string]string{
245 "Dir": dir,
246 })
247 if err != nil {
248 t.Fatal(err)
249 }
250 f.Close()
251
252 for k, v := range keys {
253 f, err := os.OpenFile(filepath.Join(dir, k), os.O_WRONLY|os.O_TR UNC|os.O_CREATE, 0600)
254 if err != nil {
255 t.Fatal(err)
256 }
257 if _, err := f.Write([]byte(v)); err != nil {
258 t.Fatal(err)
259 }
260 f.Close()
261 }
262
263 return &server{
264 t: t,
265 configfile: f.Name(),
266 cleanup: func() {
267 if err := os.RemoveAll(dir); err != nil {
268 t.Error(err)
269 }
270 },
271 }
272 }
273
274 // keychain implements the ClientKeyring interface.
275 type keychain struct {
276 keys []ssh.Signer
277 }
278
279 func (k *keychain) Key(i int) (ssh.PublicKey, error) {
280 if i < 0 || i >= len(k.keys) {
281 return nil, nil
282 }
283 return k.keys[i].PublicKey(), nil
284 }
285
286 func (k *keychain) Sign(i int, rand io.Reader, data []byte) (sig []byte, err err or) {
287 return k.keys[i].Sign(rand, data)
288 }
289
290 func (k *keychain) loadPEM(file string) error {
291 buf, err := ioutil.ReadFile(file)
292 if err != nil {
293 return err
294 }
295 key, err := ssh.ParsePrivateKey(buf)
296 if err != nil {
297 return err
298 }
299 k.keys = append(k.keys, key)
300 return nil
301 }
LEFTRIGHT

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