func (s *CLISuite) TestKey(t *c.C) { app := s.newGitRepo(t, "empty") t.Assert(app.flynn("create"), Succeeds) t.Assert(app.flynn("key", "add", s.sshKeys(t).Pub), Succeeds) // calculate fingerprint data, err := ioutil.ReadFile(s.sshKeys(t).Pub) t.Assert(err, c.IsNil) pubKey, _, _, _, err := ssh.ParseAuthorizedKey(data) t.Assert(err, c.IsNil) digest := md5.Sum(pubKey.Marshal()) fingerprint := formatKeyID(hex.EncodeToString(digest[:])) t.Assert(app.flynn("key"), SuccessfulOutputContains, fingerprint) t.Assert(app.git("commit", "--allow-empty", "-m", "should succeed"), Succeeds) t.Assert(app.git("push", "flynn", "master"), Succeeds) t.Assert(app.flynn("key", "remove", fingerprint), Succeeds) t.Assert(app.flynn("key"), c.Not(SuccessfulOutputContains), fingerprint) t.Assert(app.git("commit", "--allow-empty", "-m", "should fail"), Succeeds) t.Assert(app.git("push", "flynn", "master"), c.Not(Succeeds)) t.Assert(app.flynn("delete", "--yes"), Succeeds) }
func TestAgentForward(t *testing.T) { server := newServer(t) defer server.Shutdown() conn := server.Dial(clientConfig()) defer conn.Close() keyring := agent.NewKeyring() keyring.Add(testPrivateKeys["dsa"], nil, "") pub := testPublicKeys["dsa"] sess, err := conn.NewSession() if err != nil { t.Fatalf("NewSession: %v", err) } if err := agent.RequestAgentForwarding(sess); err != nil { t.Fatalf("RequestAgentForwarding: %v", err) } if err := agent.ForwardToAgent(conn, keyring); err != nil { t.Fatalf("SetupForwardKeyring: %v", err) } out, err := sess.CombinedOutput("ssh-add -L") if err != nil { t.Fatalf("running ssh-add: %v, out %s", err, out) } key, _, _, _, err := ssh.ParseAuthorizedKey(out) if err != nil { t.Fatalf("ParseAuthorizedKey(%q): %v", out, err) } if !bytes.Equal(key.Marshal(), pub.Marshal()) { t.Fatalf("got key %s, want %s", ssh.MarshalAuthorizedKey(key), ssh.MarshalAuthorizedKey(pub)) } }
func (c *SSHCluster) findSSHKeySigners() (signers []privateKeySigner) { keyDir := filepath.Join(c.sshDir()) if stat, err := os.Stat(keyDir); err != nil || !stat.IsDir() { return } walkFunc := func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } if strings.HasSuffix(path, ".pub") { return nil } data, err := ioutil.ReadFile(path) if err != nil { return nil } b, _ := pem.Decode(data) if b == nil { return nil } s := privateKeySigner{ base: c.base, path: path, pem: b, Encrypted: x509.IsEncryptedPEMBlock(b), } if s.Encrypted { publicKeyPath := fmt.Sprintf("%s.pub", path) if stat, err := os.Stat(publicKeyPath); err == nil && !stat.IsDir() { if data, err := ioutil.ReadFile(publicKeyPath); err == nil { pk, _, _, _, err := ssh.ParseAuthorizedKey(data) if err == nil { s.publicKey = pk } } } signers = append(signers, s) return nil } privateKey, err := x509.ParsePKCS1PrivateKey(b.Bytes) if err != nil { return nil } s.key = privateKey signers = append(signers, s) return nil } filepath.Walk(keyDir, walkFunc) sort.Sort(decryptedFirst(signers)) return }
func RegisterInstance(info Info) (string, error) { data := struct { Data Instance `json:"data"` }{Instance{ Name: info.Name, URL: info.InstanceURL, SSHPublicKeys: make([]SSHPublicKey, 0, 4), FlynnVersion: version.String(), }} for _, t := range []string{"dsa", "rsa", "ecdsa", "ed25519"} { keyData, err := ioutil.ReadFile(fmt.Sprintf("/etc/ssh/ssh_host_%s_key.pub", t)) if err != nil { // TODO(titanous): log this? continue } k, _, _, _, err := ssh.ParseAuthorizedKey(keyData) if err != nil { // TODO(titanous): log this? continue } data.Data.SSHPublicKeys = append(data.Data.SSHPublicKeys, SSHPublicKey{Type: t, Data: k.Marshal()}) } jsonData, err := json.Marshal(&data) if err != nil { return "", err } // TODO(titanous): retry uri := info.ClusterURL + "/instances" res, err := http.Post(uri, "application/json", bytes.NewReader(jsonData)) if err != nil { return "", err } if res.StatusCode != http.StatusCreated && res.StatusCode != http.StatusConflict { return "", urlError("POST", uri, res.StatusCode) } if err := json.NewDecoder(res.Body).Decode(&data); err != nil { return "", err } return data.Data.ID, nil }
func (S) TestMixedKeyTypes(c *C) { const sep = " " var input bytes.Buffer ipAddress := "192.0.2.203" // ECDSA ecdsaKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte("ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAN1At7ODzOADlqMknviOG5GRHjVy53PPC1DVhun2pMhzCjNgHMt/XvRaeMKhRvUUaUVaNLmCBi75B/2KJH289g=")) c.Assert(err, IsNil) c.Assert(ecdsaKey, NotNil) input.WriteString("|1|apo1+O3sutQ2AxrFoUgiucqL2vs=|fQljlEPB/ICE1TT7VMBYqQhiq+w= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBAN1At7ODzOADlqMknviOG5GRHjVy53PPC1DVhun2pMhzCjNgHMt/XvRaeMKhRvUUaUVaNLmCBi75B/2KJH289g=") // hashed entry for 192.0.2.203:22 // RSA rsaKey := genPublicKey(c) k, err := Unmarshal(&input) c.Assert(err, IsNil) c.Assert(k.HostKeyCallback(net.JoinHostPort(ipAddress, "22"), &net.TCPAddr{Port: 22}, ecdsaKey), IsNil) c.Assert(k.HostKeyCallback(net.JoinHostPort(ipAddress, "22"), &net.TCPAddr{Port: 22}, rsaKey), Equals, HostNotFoundError) // wrong key type }
func (r *KeyRepo) Add(data interface{}) error { key := data.(*ct.Key) if key.Key == "" { return errors.New("controller: key must not be blank") } pubKey, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(key.Key)) if err != nil { return err } key.ID = fingerprintKey(pubKey.Marshal()) key.Key = string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(pubKey))) key.Comment = comment tx, err := r.db.Begin() if err != nil { return err } err = tx.QueryRow("INSERT INTO keys (fingerprint, key, comment) VALUES ($1, $2, $3) RETURNING created_at", key.ID, key.Key, key.Comment).Scan(&key.CreatedAt) if postgres.IsUniquenessError(err, "") { tx.Rollback() return nil } if err != nil { tx.Rollback() return err } if err := createEvent(tx.Exec, &ct.Event{ ObjectID: key.ID, ObjectType: ct.EventTypeKey, }, key); err != nil { tx.Rollback() return err } return tx.Commit() }
func (r *KeyRepo) Add(data interface{}) error { key := data.(*ct.Key) if key.Key == "" { return errors.New("controller: key must not be blank") } pubKey, comment, _, _, err := ssh.ParseAuthorizedKey([]byte(key.Key)) if err != nil { return err } key.ID = fingerprintKey(pubKey.Marshal()) key.Key = string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(pubKey))) key.Comment = comment err = r.db.QueryRow("INSERT INTO keys (fingerprint, key, comment) VALUES ($1, $2, $3) RETURNING created_at", key.ID, key.Key, key.Comment).Scan(&key.CreatedAt) if e, ok := err.(*pq.Error); ok && e.Code.Name() == "unique_violation" { return nil } return err }
func parseHosts(line string) (*Line, error) { const whitespace = "\t " l := &Line{ Revoked: false, CertAuthority: false, } line = strings.TrimLeft(line, whitespace) line = strings.TrimRight(line, whitespace) nextPart := func(line string) (string, string, error) { i := strings.IndexAny(line, whitespace) if i < 0 { return "", "", fmt.Errorf("knownhosts: Invalid line: %s", line) } return line[0:i], strings.TrimLeft(line[i:], whitespace), nil } // ignore empty lines and comments if line == "" || line[0] == '#' { return nil, nil } // parse flags if line[0] == '@' { var flag string var err error flag, line, err = nextPart(line) if err != nil { return nil, err } flag = flag[1:] // trim @ switch flag { case "revoked": l.Revoked = true case "cert-authority": l.CertAuthority = true default: return nil, fmt.Errorf("knownhosts: Unknown flag @%s", flag) } } // parse hosts { var part string var err error part, line, err = nextPart(line) if err != nil { return nil, err } if part != "" && part[0] == '|' { hash, err := parseHostHash(part) if err != nil { return nil, fmt.Errorf("knownhosts: Error parsing hashed host: %#v: %s", part, err) } l.Hosts = append(l.Hosts, &Host{ Hash: hash, Port: "22", line: l, }) } else { for _, h := range strings.Split(part, ",") { host, err := parseHost(h) if err != nil { return nil, fmt.Errorf("knownhosts: Error parsing host: %#v: %s", h, err) } else { host.line = l l.Hosts = append(l.Hosts, host) } } } } // the remainder is the key key, _, _, _, err := ssh.ParseAuthorizedKey([]byte(line)) if err != nil { return nil, err } l.PublicKey = key return l, nil }