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 (S) TestPatterns(c *C) { const sep = " " var input bytes.Buffer key := genPublicKey(c) keyBytes := bytes.TrimRight(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)), "\n") // format: pattern input.WriteString("*.example") input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: negated pattern input.WriteString("!*.example.or?") input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") k, err := Unmarshal(bytes.NewReader(input.Bytes())) c.Assert(err, IsNil) // Test HostKeyCallback addr := &net.TCPAddr{ Port: 22, } c.Assert(k.HostKeyCallback("foo.example:22", addr, key), IsNil) // pattern match c.Assert(k.HostKeyCallback("foo.example.org:22", addr, key), Equals, HostNotFoundError) // negated pattern match c.Assert(k.HostKeyCallback("anything.example.com:22", addr, key), IsNil) // negated pattern miss // Make sure output is the same as input var output bytes.Buffer c.Assert(k.Marshal(&output), IsNil) c.Assert(output.String(), Equals, input.String()) }
func checkAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { status, err := exitStatus(exec.Command(authChecker[0], append(authChecker[1:], conn.User(), string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key))))...).Run()) if err != nil { return nil, err } if status.Status == 0 { return nil, nil } return nil, ErrUnauthorized }
func genSSHKey() (*sshData, error) { keyFile, err := ioutil.TempFile("", "") if err != nil { return nil, err } defer keyFile.Close() rsaKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, err } pem.Encode(keyFile, &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rsaKey), }) pubFile, err := ioutil.TempFile("", "") if err != nil { return nil, err } defer pubFile.Close() rsaPubKey, err := ssh.NewPublicKey(&rsaKey.PublicKey) if err != nil { return nil, err } if _, err := pubFile.Write(ssh.MarshalAuthorizedKey(rsaPubKey)); err != nil { return nil, err } wrapperFile, err := ioutil.TempFile("", "") if err != nil { return nil, err } defer wrapperFile.Close() if err := sshWrapper.Execute(wrapperFile, map[string]string{"SSHKey": keyFile.Name()}); err != nil { return nil, err } if err := wrapperFile.Chmod(0700); err != nil { return nil, err } return &sshData{ Key: keyFile.Name(), Pub: pubFile.Name(), Env: []string{"GIT_SSH=" + wrapperFile.Name()}, Cleanup: func() { os.RemoveAll(keyFile.Name()) os.RemoveAll(pubFile.Name()) os.RemoveAll(wrapperFile.Name()) }, }, nil }
func (a *GenSSHKeyAction) Run(s *State) error { data := &SSHKey{} s.StepData[a.ID] = data var pemBuf bytes.Buffer rsaKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return err } pem.Encode(&pemBuf, &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rsaKey), }) rsaPubKey, err := ssh.NewPublicKey(&rsaKey.PublicKey) if err != nil { return err } data.RSAPublic = string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(rsaPubKey))) ecKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return err } ecBytes, err := x509.MarshalECPrivateKey(ecKey) if err != nil { return err } pem.Encode(&pemBuf, &pem.Block{Type: "EC PRIVATE KEY", Bytes: ecBytes}) ecPubKey, err := ssh.NewPublicKey(&ecKey.PublicKey) if err != nil { return err } data.ECDSAPublic = string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(ecPubKey))) data.PrivateKeys = pemBuf.String() return nil }
func checkAuth(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { cmd := exec.Command(*authChecker, conn.User(), string(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key))), ) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr status, err := exitStatus(cmd.Run()) if err != nil { return nil, err } if status.Status == 0 { return nil, nil } return nil, ErrUnauthorized }
// This generates a single RSA 2048-bit SSH key func Generate() (*SSHKey, error) { data := &SSHKey{} rsaKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, err } var pemBuf bytes.Buffer pem.Encode(&pemBuf, &pem.Block{ Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rsaKey), }) rsaPubKey, err := ssh.NewPublicKey(&rsaKey.PublicKey) if err != nil { return nil, err } data.PublicKey = bytes.TrimSpace(ssh.MarshalAuthorizedKey(rsaPubKey)) data.PrivateKey = rsaKey return data, nil }
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 (l *Line) Marshal() ([]byte, error) { const sep = " " var buf bytes.Buffer // flag part var flag string if l.Revoked { flag = "revoked" } if l.CertAuthority { flag = "cert-authority" } if flag != "" { fmt.Fprintf(&buf, "@%s", flag) buf.WriteString(sep) } // hosts part for i, h := range l.Hosts { if h.Hash != nil && (i != 0 || len(l.Hosts) > 1) { return nil, fmt.Errorf("knownhosts: Hashed host must be only host on line, found %d!", len(l.Hosts)) } if b := h.Marshal(); b != nil { buf.Write(b) } else { return nil, fmt.Errorf("knownhosts: Invalid host: %#v", h) } if i != len(l.Hosts)-1 { buf.WriteString(",") } } buf.WriteString(sep) // key part (has trailing newline) buf.Write(ssh.MarshalAuthorizedKey(l.PublicKey)) return buf.Bytes(), nil }
func (S) TestComments(c *C) { const sep = " " var input bytes.Buffer key := genPublicKey(c) keyBytes := bytes.TrimRight(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)), "\n") // commented out host host1Addr := "101.102.103.72" input.WriteString("# ") input.WriteString(host1Addr) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") k, err := Unmarshal(&input) c.Assert(err, IsNil) // Test HostKeyCallback addr := &net.TCPAddr{ Port: 22, } c.Assert(k.HostKeyCallback(host1Addr+":22", addr, key), Equals, HostNotFoundError) }
// newServer returns a new mock ssh server. func newServer(t *testing.T) *server { if testing.Short() { t.Skip("skipping test due to -short") } dir, err := ioutil.TempDir("", "sshtest") if err != nil { t.Fatal(err) } f, err := os.Create(filepath.Join(dir, "sshd_config")) if err != nil { t.Fatal(err) } err = configTmpl.Execute(f, map[string]string{ "Dir": dir, }) if err != nil { t.Fatal(err) } f.Close() for k, v := range testdata.PEMBytes { filename := "id_" + k writeFile(filepath.Join(dir, filename), v) writeFile(filepath.Join(dir, filename+".pub"), ssh.MarshalAuthorizedKey(testPublicKeys[k])) } return &server{ t: t, configfile: f.Name(), cleanup: func() { if err := os.RemoveAll(dir); err != nil { t.Error(err) } }, } }
func (S) TestNonPatterns(c *C) { const sep = " " var input bytes.Buffer key := genPublicKey(c) keyBytes := bytes.TrimRight(bytes.TrimSpace(ssh.MarshalAuthorizedKey(key)), "\n") // format: host key host1Addr := "101.102.103.72" input.WriteString(host1Addr) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: host key host2Addr := "test.example.com" input.WriteString(host2Addr) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: @flag [host]:port key host3Addr := "3.example.com" host3Port := "2222" input.WriteString("@revoked") input.WriteString(sep) input.WriteString("[" + host3Addr + "]:" + host3Port) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: host,host,host key host4Addr := "4.example.com" host5Addr := "102.101.72.100" host6Addr := "6.example.com" input.WriteString(strings.Join([]string{host4Addr, host5Addr, host6Addr}, ",")) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: host,[host]:port,host key host7Addr := "7.example.com" host8Addr := "102.101.72.100" host8Port := "2223" host9Addr := "9.example.com" input.WriteString(strings.Join([]string{host7Addr, "[" + host8Addr + "]:" + host8Port, host9Addr}, ",")) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: @flag host,host key host10Addr := "10.example.com" host11Addr := "11.example.com" input.WriteString("@revoked") input.WriteString(sep) input.WriteString(strings.Join([]string{host10Addr, host11Addr}, ",")) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") // format: hashed host12Addr := "12.example.com" host12Salt := random.Bytes(16) host12SaltEncoded := base64.StdEncoding.EncodeToString(host12Salt) host12Mac := hmac.New(sha1.New, host12Salt) host12Mac.Write([]byte(host12Addr)) host12MacEncoded := base64.StdEncoding.EncodeToString(host12Mac.Sum(nil)) input.WriteString("|1|" + host12SaltEncoded + "|" + host12MacEncoded) input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") k, err := Unmarshal(bytes.NewReader(input.Bytes())) c.Assert(err, IsNil) // Test HostKeyCallback addr := &net.TCPAddr{ Port: 22, } c.Assert(k.HostKeyCallback(host1Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host2Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host3Addr+":2222", &net.TCPAddr{Port: 2222}, key), Equals, HostRevokedError) c.Assert(k.HostKeyCallback(host4Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host5Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host6Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host7Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host8Addr+":2223", &net.TCPAddr{Port: 2223}, key), IsNil) c.Assert(k.HostKeyCallback(host9Addr+":22", addr, key), IsNil) c.Assert(k.HostKeyCallback(host10Addr+":22", addr, key), Equals, HostRevokedError) c.Assert(k.HostKeyCallback(host11Addr+":22", addr, key), Equals, HostRevokedError) c.Assert(k.HostKeyCallback("notfound.example.com:22", addr, key), Equals, HostNotFoundError) c.Assert(k.HostKeyCallback(host3Addr+":2223", &net.TCPAddr{Port: 2223}, key), Equals, HostNotFoundError) c.Assert(k.HostKeyCallback(host1Addr+":2222", &net.TCPAddr{Port: 2222}, key), Equals, HostNotFoundError) c.Assert(k.HostKeyCallback(host12Addr+":22", addr, key), IsNil) // hash match // Make sure output is the same as input var output bytes.Buffer c.Assert(k.Marshal(&output), IsNil) c.Assert(output.String(), Equals, input.String()) // Test AppendHost with Writer var output2 bytes.Buffer var input2 bytes.Buffer c.Assert(k.AppendHost("new1.example.com:2223", key, &output2), IsNil) input2.WriteString("[new1.example.com]:2223") input2.WriteString(sep) input2.Write(keyBytes) input2.WriteString("\n") input.Write(input2.Bytes()) c.Assert(output2.String(), Equals, input2.String()) // Test AppendHost without Writer c.Assert(k.AppendHost("new2.example.com:22", key, nil), IsNil) input.WriteString("new2.example.com") input.WriteString(sep) input.Write(keyBytes) input.WriteString("\n") output.Reset() c.Assert(k.Marshal(&output), IsNil) c.Assert(output.String(), Equals, input.String()) }