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 }