func (s *server) insertIdentity(req []byte) error { var record struct { Type string `sshtype:"17"` Rest []byte `ssh:"rest"` } if err := ssh.Unmarshal(req, &record); err != nil { return err } switch record.Type { case ssh.KeyAlgoRSA: var k rsaKeyMsg if err := ssh.Unmarshal(req, &k); err != nil { return err } priv := rsa.PrivateKey{ PublicKey: rsa.PublicKey{ E: int(k.E.Int64()), N: k.N, }, D: k.D, Primes: []*big.Int{k.P, k.Q}, } priv.Precompute() return s.agent.Add(&priv, nil, k.Comments) } return fmt.Errorf("not implemented: %s", record.Type) }
func parseKey(in []byte) (out *Key, rest []byte, err error) { var record struct { Blob []byte Comment string Rest []byte `ssh:"rest"` } if err := ssh.Unmarshal(in, &record); err != nil { return nil, nil, err } var wk wireKey if err := ssh.Unmarshal(record.Blob, &wk); err != nil { return nil, nil, err } return &Key{ Format: wk.Format, Blob: record.Blob, Comment: record.Comment, }, record.Rest, nil }
// unmarshal parses an agent message in packet, returning the parsed // form and the message type of packet. func unmarshal(packet []byte) (interface{}, error) { if len(packet) < 1 { return nil, errors.New("agent: empty packet") } var msg interface{} switch packet[0] { case agentFailure: return new(failureAgentMsg), nil case agentSuccess: return new(successAgentMsg), nil case agentIdentitiesAnswer: msg = new(identitiesAnswerAgentMsg) case agentSignResponse: msg = new(signResponseAgentMsg) default: return nil, fmt.Errorf("agent: unknown type tag %d", packet[0]) } if err := ssh.Unmarshal(packet, msg); err != nil { return nil, err } return msg, nil }
// Sign has the agent sign the data using a protocol 2 key as defined // in [PROTOCOL.agent] section 2.6.2. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) { req := ssh.Marshal(signRequestAgentMsg{ KeyBlob: key.Marshal(), Data: data, }) msg, err := c.call(req) if err != nil { return nil, err } switch msg := msg.(type) { case *signResponseAgentMsg: var sig ssh.Signature if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil { return nil, err } return &sig, nil case *failureAgentMsg: return nil, errors.New("agent: failed to sign challenge") } panic("unreachable") }
func (s *server) processRequest(data []byte) (interface{}, error) { switch data[0] { case agentRequestV1Identities: return &agentV1IdentityMsg{0}, nil case agentRemoveIdentity: var req agentRemoveIdentityMsg if err := ssh.Unmarshal(data, &req); err != nil { return nil, err } var wk wireKey if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { return nil, err } return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) case agentRemoveAllIdentities: return nil, s.agent.RemoveAll() case agentLock: var req agentLockMsg if err := ssh.Unmarshal(data, &req); err != nil { return nil, err } return nil, s.agent.Lock(req.Passphrase) case agentUnlock: var req agentLockMsg if err := ssh.Unmarshal(data, &req); err != nil { return nil, err } return nil, s.agent.Unlock(req.Passphrase) case agentSignRequest: var req signRequestAgentMsg if err := ssh.Unmarshal(data, &req); err != nil { return nil, err } var wk wireKey if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { return nil, err } k := &Key{ Format: wk.Format, Blob: req.KeyBlob, } sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. if err != nil { return nil, err } return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil case agentRequestIdentities: keys, err := s.agent.List() if err != nil { return nil, err } rep := identitiesAnswerAgentMsg{ NumKeys: uint32(len(keys)), } for _, k := range keys { rep.Keys = append(rep.Keys, marshalKey(k)...) } return rep, nil case agentAddIdentity: return nil, s.insertIdentity(data) } return nil, fmt.Errorf("unknown opcode %d", data[0]) }
func processRequests(conn *ssh.ServerConn, reqs <-chan *ssh.Request) { for req := range reqs { if req.Type != "tcpip-forward" { // accept only tcpip-forward requests if req.WantReply { req.Reply(false, nil) } continue } type channelForwardMsg struct { Laddr string Lport uint32 } m := &channelForwardMsg{} ssh.Unmarshal(req.Payload, m) privateBytes, err := ioutil.ReadFile(appConfig.RemotePrivateKeyPath) if err != nil { log.Fatal(err.Error()) } signer, err := ssh.ParsePrivateKey(privateBytes) if err != nil { log.Fatal(err.Error()) } config := &ssh.ClientConfig{ User: appConfig.RemoteSSHUser, Auth: []ssh.AuthMethod{ ssh.PublicKeys(signer), }, } sshClientConn, err := ssh.Dial("tcp", appConfig.RemoteSSHAddr, config) if err != nil { log.Fatal(err.Error()) } type channelOpenForwardMsg struct { raddr string rport uint32 laddr string lport uint32 } fm := &channelOpenForwardMsg{ raddr: "localhost", rport: m.Lport, laddr: "localhost", lport: m.Lport, } channel, reqs, err := conn.Conn.OpenChannel("forwarded-tcpip", ssh.Marshal(fm)) if err != nil { log.Fatal(err.Error()) } go ssh.DiscardRequests(reqs) portListener, err := sshClientConn.Listen("tcp", appConfig.RemoteForwardAddress) if err != nil { log.Fatal(err.Error()) } go func() { for { sshConn, err := portListener.Accept() if err != nil { log.Fatal(err.Error()) } // Copy localConn.Reader to sshConn.Writer go func(sshConn net.Conn) { _, err := io.Copy(sshConn, channel) if err != nil { log.Println("io.Copy failed: %v", err) sshConn.Close() return } }(sshConn) // Copy sshConn.Reader to localConn.Writer go func(sshConn net.Conn) { _, err := io.Copy(channel, sshConn) if err != nil { log.Println("io.Copy failed: %v", err) sshConn.Close() return } }(sshConn) } }() req.Reply(true, nil) } }