github.com/deis/deis@v1.13.5-0.20170519182049-1d9e59fbdbfc/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/client_test.go (about)

     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  package agent
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/rand"
    10  	"errors"
    11  	"net"
    12  	"os"
    13  	"os/exec"
    14  	"path/filepath"
    15  	"strconv"
    16  	"testing"
    17  
    18  	"golang.org/x/crypto/ssh"
    19  )
    20  
    21  // startAgent executes ssh-agent, and returns a Agent interface to it.
    22  func startAgent(t *testing.T) (client Agent, socket string, cleanup func()) {
    23  	if testing.Short() {
    24  		// ssh-agent is not always available, and the key
    25  		// types supported vary by platform.
    26  		t.Skip("skipping test due to -short")
    27  	}
    28  
    29  	bin, err := exec.LookPath("ssh-agent")
    30  	if err != nil {
    31  		t.Skip("could not find ssh-agent")
    32  	}
    33  
    34  	cmd := exec.Command(bin, "-s")
    35  	out, err := cmd.Output()
    36  	if err != nil {
    37  		t.Fatalf("cmd.Output: %v", err)
    38  	}
    39  
    40  	/* Output looks like:
    41  
    42  		   SSH_AUTH_SOCK=/tmp/ssh-P65gpcqArqvH/agent.15541; export SSH_AUTH_SOCK;
    43  	           SSH_AGENT_PID=15542; export SSH_AGENT_PID;
    44  	           echo Agent pid 15542;
    45  	*/
    46  	fields := bytes.Split(out, []byte(";"))
    47  	line := bytes.SplitN(fields[0], []byte("="), 2)
    48  	line[0] = bytes.TrimLeft(line[0], "\n")
    49  	if string(line[0]) != "SSH_AUTH_SOCK" {
    50  		t.Fatalf("could not find key SSH_AUTH_SOCK in %q", fields[0])
    51  	}
    52  	socket = string(line[1])
    53  
    54  	line = bytes.SplitN(fields[2], []byte("="), 2)
    55  	line[0] = bytes.TrimLeft(line[0], "\n")
    56  	if string(line[0]) != "SSH_AGENT_PID" {
    57  		t.Fatalf("could not find key SSH_AGENT_PID in %q", fields[2])
    58  	}
    59  	pidStr := line[1]
    60  	pid, err := strconv.Atoi(string(pidStr))
    61  	if err != nil {
    62  		t.Fatalf("Atoi(%q): %v", pidStr, err)
    63  	}
    64  
    65  	conn, err := net.Dial("unix", string(socket))
    66  	if err != nil {
    67  		t.Fatalf("net.Dial: %v", err)
    68  	}
    69  
    70  	ac := NewClient(conn)
    71  	return ac, socket, func() {
    72  		proc, _ := os.FindProcess(pid)
    73  		if proc != nil {
    74  			proc.Kill()
    75  		}
    76  		conn.Close()
    77  		os.RemoveAll(filepath.Dir(socket))
    78  	}
    79  }
    80  
    81  func testAgent(t *testing.T, key interface{}, cert *ssh.Certificate) {
    82  	agent, _, cleanup := startAgent(t)
    83  	defer cleanup()
    84  
    85  	testAgentInterface(t, agent, key, cert)
    86  }
    87  
    88  func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate) {
    89  	signer, err := ssh.NewSignerFromKey(key)
    90  	if err != nil {
    91  		t.Fatalf("NewSignerFromKey(%T): %v", key, err)
    92  	}
    93  	// The agent should start up empty.
    94  	if keys, err := agent.List(); err != nil {
    95  		t.Fatalf("RequestIdentities: %v", err)
    96  	} else if len(keys) > 0 {
    97  		t.Fatalf("got %d keys, want 0: %v", len(keys), keys)
    98  	}
    99  
   100  	// Attempt to insert the key, with certificate if specified.
   101  	var pubKey ssh.PublicKey
   102  	if cert != nil {
   103  		err = agent.Add(key, cert, "comment")
   104  		pubKey = cert
   105  	} else {
   106  		err = agent.Add(key, nil, "comment")
   107  		pubKey = signer.PublicKey()
   108  	}
   109  	if err != nil {
   110  		t.Fatalf("insert(%T): %v", key, err)
   111  	}
   112  
   113  	// Did the key get inserted successfully?
   114  	if keys, err := agent.List(); err != nil {
   115  		t.Fatalf("List: %v", err)
   116  	} else if len(keys) != 1 {
   117  		t.Fatalf("got %v, want 1 key", keys)
   118  	} else if keys[0].Comment != "comment" {
   119  		t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment")
   120  	} else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) {
   121  		t.Fatalf("key mismatch")
   122  	}
   123  
   124  	// Can the agent make a valid signature?
   125  	data := []byte("hello")
   126  	sig, err := agent.Sign(pubKey, data)
   127  	if err != nil {
   128  		t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
   129  	}
   130  
   131  	if err := pubKey.Verify(data, sig); err != nil {
   132  		t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
   133  	}
   134  }
   135  
   136  func TestAgent(t *testing.T) {
   137  	for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
   138  		testAgent(t, testPrivateKeys[keyType], nil)
   139  	}
   140  }
   141  
   142  func TestCert(t *testing.T) {
   143  	cert := &ssh.Certificate{
   144  		Key:         testPublicKeys["rsa"],
   145  		ValidBefore: ssh.CertTimeInfinity,
   146  		CertType:    ssh.UserCert,
   147  	}
   148  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   149  
   150  	testAgent(t, testPrivateKeys["rsa"], cert)
   151  }
   152  
   153  // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
   154  // therefore is buffered (net.Pipe deadlocks if both sides start with
   155  // a write.)
   156  func netPipe() (net.Conn, net.Conn, error) {
   157  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   158  	if err != nil {
   159  		return nil, nil, err
   160  	}
   161  	defer listener.Close()
   162  	c1, err := net.Dial("tcp", listener.Addr().String())
   163  	if err != nil {
   164  		return nil, nil, err
   165  	}
   166  
   167  	c2, err := listener.Accept()
   168  	if err != nil {
   169  		c1.Close()
   170  		return nil, nil, err
   171  	}
   172  
   173  	return c1, c2, nil
   174  }
   175  
   176  func TestAuth(t *testing.T) {
   177  	a, b, err := netPipe()
   178  	if err != nil {
   179  		t.Fatalf("netPipe: %v", err)
   180  	}
   181  
   182  	defer a.Close()
   183  	defer b.Close()
   184  
   185  	agent, _, cleanup := startAgent(t)
   186  	defer cleanup()
   187  
   188  	if err := agent.Add(testPrivateKeys["rsa"], nil, "comment"); err != nil {
   189  		t.Errorf("Add: %v", err)
   190  	}
   191  
   192  	serverConf := ssh.ServerConfig{}
   193  	serverConf.AddHostKey(testSigners["rsa"])
   194  	serverConf.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
   195  		if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
   196  			return nil, nil
   197  		}
   198  
   199  		return nil, errors.New("pubkey rejected")
   200  	}
   201  
   202  	go func() {
   203  		conn, _, _, err := ssh.NewServerConn(a, &serverConf)
   204  		if err != nil {
   205  			t.Fatalf("Server: %v", err)
   206  		}
   207  		conn.Close()
   208  	}()
   209  
   210  	conf := ssh.ClientConfig{}
   211  	conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
   212  	conn, _, _, err := ssh.NewClientConn(b, "", &conf)
   213  	if err != nil {
   214  		t.Fatalf("NewClientConn: %v", err)
   215  	}
   216  	conn.Close()
   217  }
   218  
   219  func TestLockClient(t *testing.T) {
   220  	agent, _, cleanup := startAgent(t)
   221  	defer cleanup()
   222  	testLockAgent(agent, t)
   223  }
   224  
   225  func testLockAgent(agent Agent, t *testing.T) {
   226  	if err := agent.Add(testPrivateKeys["rsa"], nil, "comment 1"); err != nil {
   227  		t.Errorf("Add: %v", err)
   228  	}
   229  	if err := agent.Add(testPrivateKeys["dsa"], nil, "comment dsa"); err != nil {
   230  		t.Errorf("Add: %v", err)
   231  	}
   232  	if keys, err := agent.List(); err != nil {
   233  		t.Errorf("List: %v", err)
   234  	} else if len(keys) != 2 {
   235  		t.Errorf("Want 2 keys, got %v", keys)
   236  	}
   237  
   238  	passphrase := []byte("secret")
   239  	if err := agent.Lock(passphrase); err != nil {
   240  		t.Errorf("Lock: %v", err)
   241  	}
   242  
   243  	if keys, err := agent.List(); err != nil {
   244  		t.Errorf("List: %v", err)
   245  	} else if len(keys) != 0 {
   246  		t.Errorf("Want 0 keys, got %v", keys)
   247  	}
   248  
   249  	signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"])
   250  	if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil {
   251  		t.Fatalf("Sign did not fail")
   252  	}
   253  
   254  	if err := agent.Remove(signer.PublicKey()); err == nil {
   255  		t.Fatalf("Remove did not fail")
   256  	}
   257  
   258  	if err := agent.RemoveAll(); err == nil {
   259  		t.Fatalf("RemoveAll did not fail")
   260  	}
   261  
   262  	if err := agent.Unlock(nil); err == nil {
   263  		t.Errorf("Unlock with wrong passphrase succeeded")
   264  	}
   265  	if err := agent.Unlock(passphrase); err != nil {
   266  		t.Errorf("Unlock: %v", err)
   267  	}
   268  
   269  	if err := agent.Remove(signer.PublicKey()); err != nil {
   270  		t.Fatalf("Remove: %v", err)
   271  	}
   272  
   273  	if keys, err := agent.List(); err != nil {
   274  		t.Errorf("List: %v", err)
   275  	} else if len(keys) != 1 {
   276  		t.Errorf("Want 1 keys, got %v", keys)
   277  	}
   278  }