github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/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, lifetimeSecs uint32) {
    82  	agent, _, cleanup := startAgent(t)
    83  	defer cleanup()
    84  
    85  	testAgentInterface(t, agent, key, cert, lifetimeSecs)
    86  }
    87  
    88  func testAgentInterface(t *testing.T, agent Agent, key interface{}, cert *ssh.Certificate, lifetimeSecs uint32) {
    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(AddedKey{
   104  			PrivateKey:   key,
   105  			Certificate:  cert,
   106  			Comment:      "comment",
   107  			LifetimeSecs: lifetimeSecs,
   108  		})
   109  		pubKey = cert
   110  	} else {
   111  		err = agent.Add(AddedKey{PrivateKey: key, Comment: "comment", LifetimeSecs: lifetimeSecs})
   112  		pubKey = signer.PublicKey()
   113  	}
   114  	if err != nil {
   115  		t.Fatalf("insert(%T): %v", key, err)
   116  	}
   117  
   118  	// Did the key get inserted successfully?
   119  	if keys, err := agent.List(); err != nil {
   120  		t.Fatalf("List: %v", err)
   121  	} else if len(keys) != 1 {
   122  		t.Fatalf("got %v, want 1 key", keys)
   123  	} else if keys[0].Comment != "comment" {
   124  		t.Fatalf("key comment: got %v, want %v", keys[0].Comment, "comment")
   125  	} else if !bytes.Equal(keys[0].Blob, pubKey.Marshal()) {
   126  		t.Fatalf("key mismatch")
   127  	}
   128  
   129  	// Can the agent make a valid signature?
   130  	data := []byte("hello")
   131  	sig, err := agent.Sign(pubKey, data)
   132  	if err != nil {
   133  		t.Fatalf("Sign(%s): %v", pubKey.Type(), err)
   134  	}
   135  
   136  	if err := pubKey.Verify(data, sig); err != nil {
   137  		t.Fatalf("Verify(%s): %v", pubKey.Type(), err)
   138  	}
   139  }
   140  
   141  func TestAgent(t *testing.T) {
   142  	for _, keyType := range []string{"rsa", "dsa", "ecdsa"} {
   143  		testAgent(t, testPrivateKeys[keyType], nil, 0)
   144  	}
   145  }
   146  
   147  func TestCert(t *testing.T) {
   148  	cert := &ssh.Certificate{
   149  		Key:         testPublicKeys["rsa"],
   150  		ValidBefore: ssh.CertTimeInfinity,
   151  		CertType:    ssh.UserCert,
   152  	}
   153  	cert.SignCert(rand.Reader, testSigners["ecdsa"])
   154  
   155  	testAgent(t, testPrivateKeys["rsa"], cert, 0)
   156  }
   157  
   158  func TestConstraints(t *testing.T) {
   159  	testAgent(t, testPrivateKeys["rsa"], nil, 3600 /* lifetime in seconds */)
   160  }
   161  
   162  // netPipe is analogous to net.Pipe, but it uses a real net.Conn, and
   163  // therefore is buffered (net.Pipe deadlocks if both sides start with
   164  // a write.)
   165  func netPipe() (net.Conn, net.Conn, error) {
   166  	listener, err := net.Listen("tcp", "127.0.0.1:0")
   167  	if err != nil {
   168  		return nil, nil, err
   169  	}
   170  	defer listener.Close()
   171  	c1, err := net.Dial("tcp", listener.Addr().String())
   172  	if err != nil {
   173  		return nil, nil, err
   174  	}
   175  
   176  	c2, err := listener.Accept()
   177  	if err != nil {
   178  		c1.Close()
   179  		return nil, nil, err
   180  	}
   181  
   182  	return c1, c2, nil
   183  }
   184  
   185  func TestAuth(t *testing.T) {
   186  	a, b, err := netPipe()
   187  	if err != nil {
   188  		t.Fatalf("netPipe: %v", err)
   189  	}
   190  
   191  	defer a.Close()
   192  	defer b.Close()
   193  
   194  	agent, _, cleanup := startAgent(t)
   195  	defer cleanup()
   196  
   197  	if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment"}); err != nil {
   198  		t.Errorf("Add: %v", err)
   199  	}
   200  
   201  	serverConf := ssh.ServerConfig{}
   202  	serverConf.AddHostKey(testSigners["rsa"])
   203  	serverConf.PublicKeyCallback = func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
   204  		if bytes.Equal(key.Marshal(), testPublicKeys["rsa"].Marshal()) {
   205  			return nil, nil
   206  		}
   207  
   208  		return nil, errors.New("pubkey rejected")
   209  	}
   210  
   211  	go func() {
   212  		conn, _, _, err := ssh.NewServerConn(a, &serverConf)
   213  		if err != nil {
   214  			t.Fatalf("Server: %v", err)
   215  		}
   216  		conn.Close()
   217  	}()
   218  
   219  	conf := ssh.ClientConfig{}
   220  	conf.Auth = append(conf.Auth, ssh.PublicKeysCallback(agent.Signers))
   221  	conn, _, _, err := ssh.NewClientConn(b, "", &conf)
   222  	if err != nil {
   223  		t.Fatalf("NewClientConn: %v", err)
   224  	}
   225  	conn.Close()
   226  }
   227  
   228  func TestLockClient(t *testing.T) {
   229  	agent, _, cleanup := startAgent(t)
   230  	defer cleanup()
   231  	testLockAgent(agent, t)
   232  }
   233  
   234  func testLockAgent(agent Agent, t *testing.T) {
   235  	if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["rsa"], Comment: "comment 1"}); err != nil {
   236  		t.Errorf("Add: %v", err)
   237  	}
   238  	if err := agent.Add(AddedKey{PrivateKey: testPrivateKeys["dsa"], Comment: "comment dsa"}); err != nil {
   239  		t.Errorf("Add: %v", err)
   240  	}
   241  	if keys, err := agent.List(); err != nil {
   242  		t.Errorf("List: %v", err)
   243  	} else if len(keys) != 2 {
   244  		t.Errorf("Want 2 keys, got %v", keys)
   245  	}
   246  
   247  	passphrase := []byte("secret")
   248  	if err := agent.Lock(passphrase); err != nil {
   249  		t.Errorf("Lock: %v", err)
   250  	}
   251  
   252  	if keys, err := agent.List(); err != nil {
   253  		t.Errorf("List: %v", err)
   254  	} else if len(keys) != 0 {
   255  		t.Errorf("Want 0 keys, got %v", keys)
   256  	}
   257  
   258  	signer, _ := ssh.NewSignerFromKey(testPrivateKeys["rsa"])
   259  	if _, err := agent.Sign(signer.PublicKey(), []byte("hello")); err == nil {
   260  		t.Fatalf("Sign did not fail")
   261  	}
   262  
   263  	if err := agent.Remove(signer.PublicKey()); err == nil {
   264  		t.Fatalf("Remove did not fail")
   265  	}
   266  
   267  	if err := agent.RemoveAll(); err == nil {
   268  		t.Fatalf("RemoveAll did not fail")
   269  	}
   270  
   271  	if err := agent.Unlock(nil); err == nil {
   272  		t.Errorf("Unlock with wrong passphrase succeeded")
   273  	}
   274  	if err := agent.Unlock(passphrase); err != nil {
   275  		t.Errorf("Unlock: %v", err)
   276  	}
   277  
   278  	if err := agent.Remove(signer.PublicKey()); err != nil {
   279  		t.Fatalf("Remove: %v", err)
   280  	}
   281  
   282  	if keys, err := agent.List(); err != nil {
   283  		t.Errorf("List: %v", err)
   284  	} else if len(keys) != 1 {
   285  		t.Errorf("Want 1 keys, got %v", keys)
   286  	}
   287  }