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

     1  // Copyright 2014 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 ssh
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/dsa"
    10  	"crypto/ecdsa"
    11  	"crypto/elliptic"
    12  	"crypto/rand"
    13  	"crypto/rsa"
    14  	"encoding/base64"
    15  	"fmt"
    16  	"reflect"
    17  	"strings"
    18  	"testing"
    19  
    20  	"golang.org/x/crypto/ssh/testdata"
    21  )
    22  
    23  func rawKey(pub PublicKey) interface{} {
    24  	switch k := pub.(type) {
    25  	case *rsaPublicKey:
    26  		return (*rsa.PublicKey)(k)
    27  	case *dsaPublicKey:
    28  		return (*dsa.PublicKey)(k)
    29  	case *ecdsaPublicKey:
    30  		return (*ecdsa.PublicKey)(k)
    31  	case *Certificate:
    32  		return k
    33  	}
    34  	panic("unknown key type")
    35  }
    36  
    37  func TestKeyMarshalParse(t *testing.T) {
    38  	for _, priv := range testSigners {
    39  		pub := priv.PublicKey()
    40  		roundtrip, err := ParsePublicKey(pub.Marshal())
    41  		if err != nil {
    42  			t.Errorf("ParsePublicKey(%T): %v", pub, err)
    43  		}
    44  
    45  		k1 := rawKey(pub)
    46  		k2 := rawKey(roundtrip)
    47  
    48  		if !reflect.DeepEqual(k1, k2) {
    49  			t.Errorf("got %#v in roundtrip, want %#v", k2, k1)
    50  		}
    51  	}
    52  }
    53  
    54  func TestUnsupportedCurves(t *testing.T) {
    55  	raw, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
    56  	if err != nil {
    57  		t.Fatalf("GenerateKey: %v", err)
    58  	}
    59  
    60  	if _, err = NewSignerFromKey(raw); err == nil || !strings.Contains(err.Error(), "only P256") {
    61  		t.Fatalf("NewPrivateKey should not succeed with P224, got: %v", err)
    62  	}
    63  
    64  	if _, err = NewPublicKey(&raw.PublicKey); err == nil || !strings.Contains(err.Error(), "only P256") {
    65  		t.Fatalf("NewPublicKey should not succeed with P224, got: %v", err)
    66  	}
    67  }
    68  
    69  func TestNewPublicKey(t *testing.T) {
    70  	for _, k := range testSigners {
    71  		raw := rawKey(k.PublicKey())
    72  		// Skip certificates, as NewPublicKey does not support them.
    73  		if _, ok := raw.(*Certificate); ok {
    74  			continue
    75  		}
    76  		pub, err := NewPublicKey(raw)
    77  		if err != nil {
    78  			t.Errorf("NewPublicKey(%#v): %v", raw, err)
    79  		}
    80  		if !reflect.DeepEqual(k.PublicKey(), pub) {
    81  			t.Errorf("NewPublicKey(%#v) = %#v, want %#v", raw, pub, k.PublicKey())
    82  		}
    83  	}
    84  }
    85  
    86  func TestKeySignVerify(t *testing.T) {
    87  	for _, priv := range testSigners {
    88  		pub := priv.PublicKey()
    89  
    90  		data := []byte("sign me")
    91  		sig, err := priv.Sign(rand.Reader, data)
    92  		if err != nil {
    93  			t.Fatalf("Sign(%T): %v", priv, err)
    94  		}
    95  
    96  		if err := pub.Verify(data, sig); err != nil {
    97  			t.Errorf("publicKey.Verify(%T): %v", priv, err)
    98  		}
    99  		sig.Blob[5]++
   100  		if err := pub.Verify(data, sig); err == nil {
   101  			t.Errorf("publicKey.Verify on broken sig did not fail")
   102  		}
   103  	}
   104  }
   105  
   106  func TestParseRSAPrivateKey(t *testing.T) {
   107  	key := testPrivateKeys["rsa"]
   108  
   109  	rsa, ok := key.(*rsa.PrivateKey)
   110  	if !ok {
   111  		t.Fatalf("got %T, want *rsa.PrivateKey", rsa)
   112  	}
   113  
   114  	if err := rsa.Validate(); err != nil {
   115  		t.Errorf("Validate: %v", err)
   116  	}
   117  }
   118  
   119  func TestParseECPrivateKey(t *testing.T) {
   120  	key := testPrivateKeys["ecdsa"]
   121  
   122  	ecKey, ok := key.(*ecdsa.PrivateKey)
   123  	if !ok {
   124  		t.Fatalf("got %T, want *ecdsa.PrivateKey", ecKey)
   125  	}
   126  
   127  	if !validateECPublicKey(ecKey.Curve, ecKey.X, ecKey.Y) {
   128  		t.Fatalf("public key does not validate.")
   129  	}
   130  }
   131  
   132  func TestParseDSA(t *testing.T) {
   133  	// We actually exercise the ParsePrivateKey codepath here, as opposed to
   134  	// using the ParseRawPrivateKey+NewSignerFromKey path that testdata_test.go
   135  	// uses.
   136  	s, err := ParsePrivateKey(testdata.PEMBytes["dsa"])
   137  	if err != nil {
   138  		t.Fatalf("ParsePrivateKey returned error: %s", err)
   139  	}
   140  
   141  	data := []byte("sign me")
   142  	sig, err := s.Sign(rand.Reader, data)
   143  	if err != nil {
   144  		t.Fatalf("dsa.Sign: %v", err)
   145  	}
   146  
   147  	if err := s.PublicKey().Verify(data, sig); err != nil {
   148  		t.Errorf("Verify failed: %v", err)
   149  	}
   150  }
   151  
   152  // Tests for authorized_keys parsing.
   153  
   154  // getTestKey returns a public key, and its base64 encoding.
   155  func getTestKey() (PublicKey, string) {
   156  	k := testPublicKeys["rsa"]
   157  
   158  	b := &bytes.Buffer{}
   159  	e := base64.NewEncoder(base64.StdEncoding, b)
   160  	e.Write(k.Marshal())
   161  	e.Close()
   162  
   163  	return k, b.String()
   164  }
   165  
   166  func TestMarshalParsePublicKey(t *testing.T) {
   167  	pub, pubSerialized := getTestKey()
   168  	line := fmt.Sprintf("%s %s user@host", pub.Type(), pubSerialized)
   169  
   170  	authKeys := MarshalAuthorizedKey(pub)
   171  	actualFields := strings.Fields(string(authKeys))
   172  	if len(actualFields) == 0 {
   173  		t.Fatalf("failed authKeys: %v", authKeys)
   174  	}
   175  
   176  	// drop the comment
   177  	expectedFields := strings.Fields(line)[0:2]
   178  
   179  	if !reflect.DeepEqual(actualFields, expectedFields) {
   180  		t.Errorf("got %v, expected %v", actualFields, expectedFields)
   181  	}
   182  
   183  	actPub, _, _, _, err := ParseAuthorizedKey([]byte(line))
   184  	if err != nil {
   185  		t.Fatalf("cannot parse %v: %v", line, err)
   186  	}
   187  	if !reflect.DeepEqual(actPub, pub) {
   188  		t.Errorf("got %v, expected %v", actPub, pub)
   189  	}
   190  }
   191  
   192  type authResult struct {
   193  	pubKey   PublicKey
   194  	options  []string
   195  	comments string
   196  	rest     string
   197  	ok       bool
   198  }
   199  
   200  func testAuthorizedKeys(t *testing.T, authKeys []byte, expected []authResult) {
   201  	rest := authKeys
   202  	var values []authResult
   203  	for len(rest) > 0 {
   204  		var r authResult
   205  		var err error
   206  		r.pubKey, r.comments, r.options, rest, err = ParseAuthorizedKey(rest)
   207  		r.ok = (err == nil)
   208  		t.Log(err)
   209  		r.rest = string(rest)
   210  		values = append(values, r)
   211  	}
   212  
   213  	if !reflect.DeepEqual(values, expected) {
   214  		t.Errorf("got %#v, expected %#v", values, expected)
   215  	}
   216  }
   217  
   218  func TestAuthorizedKeyBasic(t *testing.T) {
   219  	pub, pubSerialized := getTestKey()
   220  	line := "ssh-rsa " + pubSerialized + " user@host"
   221  	testAuthorizedKeys(t, []byte(line),
   222  		[]authResult{
   223  			{pub, nil, "user@host", "", true},
   224  		})
   225  }
   226  
   227  func TestAuth(t *testing.T) {
   228  	pub, pubSerialized := getTestKey()
   229  	authWithOptions := []string{
   230  		`# comments to ignore before any keys...`,
   231  		``,
   232  		`env="HOME=/home/root",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`,
   233  		`# comments to ignore, along with a blank line`,
   234  		``,
   235  		`env="HOME=/home/root2" ssh-rsa ` + pubSerialized + ` user2@host2`,
   236  		``,
   237  		`# more comments, plus a invalid entry`,
   238  		`ssh-rsa data-that-will-not-parse user@host3`,
   239  	}
   240  	for _, eol := range []string{"\n", "\r\n"} {
   241  		authOptions := strings.Join(authWithOptions, eol)
   242  		rest2 := strings.Join(authWithOptions[3:], eol)
   243  		rest3 := strings.Join(authWithOptions[6:], eol)
   244  		testAuthorizedKeys(t, []byte(authOptions), []authResult{
   245  			{pub, []string{`env="HOME=/home/root"`, "no-port-forwarding"}, "user@host", rest2, true},
   246  			{pub, []string{`env="HOME=/home/root2"`}, "user2@host2", rest3, true},
   247  			{nil, nil, "", "", false},
   248  		})
   249  	}
   250  }
   251  
   252  func TestAuthWithQuotedSpaceInEnv(t *testing.T) {
   253  	pub, pubSerialized := getTestKey()
   254  	authWithQuotedSpaceInEnv := []byte(`env="HOME=/home/root dir",no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host`)
   255  	testAuthorizedKeys(t, []byte(authWithQuotedSpaceInEnv), []authResult{
   256  		{pub, []string{`env="HOME=/home/root dir"`, "no-port-forwarding"}, "user@host", "", true},
   257  	})
   258  }
   259  
   260  func TestAuthWithQuotedCommaInEnv(t *testing.T) {
   261  	pub, pubSerialized := getTestKey()
   262  	authWithQuotedCommaInEnv := []byte(`env="HOME=/home/root,dir",no-port-forwarding ssh-rsa ` + pubSerialized + `   user@host`)
   263  	testAuthorizedKeys(t, []byte(authWithQuotedCommaInEnv), []authResult{
   264  		{pub, []string{`env="HOME=/home/root,dir"`, "no-port-forwarding"}, "user@host", "", true},
   265  	})
   266  }
   267  
   268  func TestAuthWithQuotedQuoteInEnv(t *testing.T) {
   269  	pub, pubSerialized := getTestKey()
   270  	authWithQuotedQuoteInEnv := []byte(`env="HOME=/home/\"root dir",no-port-forwarding` + "\t" + `ssh-rsa` + "\t" + pubSerialized + `   user@host`)
   271  	authWithDoubleQuotedQuote := []byte(`no-port-forwarding,env="HOME=/home/ \"root dir\"" ssh-rsa ` + pubSerialized + "\t" + `user@host`)
   272  	testAuthorizedKeys(t, []byte(authWithQuotedQuoteInEnv), []authResult{
   273  		{pub, []string{`env="HOME=/home/\"root dir"`, "no-port-forwarding"}, "user@host", "", true},
   274  	})
   275  
   276  	testAuthorizedKeys(t, []byte(authWithDoubleQuotedQuote), []authResult{
   277  		{pub, []string{"no-port-forwarding", `env="HOME=/home/ \"root dir\""`}, "user@host", "", true},
   278  	})
   279  }
   280  
   281  func TestAuthWithInvalidSpace(t *testing.T) {
   282  	_, pubSerialized := getTestKey()
   283  	authWithInvalidSpace := []byte(`env="HOME=/home/root dir", no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
   284  #more to follow but still no valid keys`)
   285  	testAuthorizedKeys(t, []byte(authWithInvalidSpace), []authResult{
   286  		{nil, nil, "", "", false},
   287  	})
   288  }
   289  
   290  func TestAuthWithMissingQuote(t *testing.T) {
   291  	pub, pubSerialized := getTestKey()
   292  	authWithMissingQuote := []byte(`env="HOME=/home/root,no-port-forwarding ssh-rsa ` + pubSerialized + ` user@host
   293  env="HOME=/home/root",shared-control ssh-rsa ` + pubSerialized + ` user@host`)
   294  
   295  	testAuthorizedKeys(t, []byte(authWithMissingQuote), []authResult{
   296  		{pub, []string{`env="HOME=/home/root"`, `shared-control`}, "user@host", "", true},
   297  	})
   298  }
   299  
   300  func TestInvalidEntry(t *testing.T) {
   301  	authInvalid := []byte(`ssh-rsa`)
   302  	_, _, _, _, err := ParseAuthorizedKey(authInvalid)
   303  	if err == nil {
   304  		t.Errorf("got valid entry for %q", authInvalid)
   305  	}
   306  }