github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/golang.org/x/crypto/ssh/agent/server.go (about) 1 // Copyright 2012 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 agent 6 7 import ( 8 "crypto/rsa" 9 "encoding/binary" 10 "fmt" 11 "io" 12 "log" 13 "math/big" 14 15 "golang.org/x/crypto/ssh" 16 ) 17 18 // Server wraps an Agent and uses it to implement the agent side of 19 // the SSH-agent, wire protocol. 20 type server struct { 21 agent Agent 22 } 23 24 func (s *server) processRequestBytes(reqData []byte) []byte { 25 rep, err := s.processRequest(reqData) 26 if err != nil { 27 if err != errLocked { 28 // TODO(hanwen): provide better logging interface? 29 log.Printf("agent %d: %v", reqData[0], err) 30 } 31 return []byte{agentFailure} 32 } 33 34 if err == nil && rep == nil { 35 return []byte{agentSuccess} 36 } 37 38 return ssh.Marshal(rep) 39 } 40 41 func marshalKey(k *Key) []byte { 42 var record struct { 43 Blob []byte 44 Comment string 45 } 46 record.Blob = k.Marshal() 47 record.Comment = k.Comment 48 49 return ssh.Marshal(&record) 50 } 51 52 type agentV1IdentityMsg struct { 53 Numkeys uint32 `sshtype:"2"` 54 } 55 56 type agentRemoveIdentityMsg struct { 57 KeyBlob []byte `sshtype:"18"` 58 } 59 60 type agentLockMsg struct { 61 Passphrase []byte `sshtype:"22"` 62 } 63 64 type agentUnlockMsg struct { 65 Passphrase []byte `sshtype:"23"` 66 } 67 68 func (s *server) processRequest(data []byte) (interface{}, error) { 69 switch data[0] { 70 case agentRequestV1Identities: 71 return &agentV1IdentityMsg{0}, nil 72 case agentRemoveIdentity: 73 var req agentRemoveIdentityMsg 74 if err := ssh.Unmarshal(data, &req); err != nil { 75 return nil, err 76 } 77 78 var wk wireKey 79 if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { 80 return nil, err 81 } 82 83 return nil, s.agent.Remove(&Key{Format: wk.Format, Blob: req.KeyBlob}) 84 85 case agentRemoveAllIdentities: 86 return nil, s.agent.RemoveAll() 87 88 case agentLock: 89 var req agentLockMsg 90 if err := ssh.Unmarshal(data, &req); err != nil { 91 return nil, err 92 } 93 94 return nil, s.agent.Lock(req.Passphrase) 95 96 case agentUnlock: 97 var req agentLockMsg 98 if err := ssh.Unmarshal(data, &req); err != nil { 99 return nil, err 100 } 101 return nil, s.agent.Unlock(req.Passphrase) 102 103 case agentSignRequest: 104 var req signRequestAgentMsg 105 if err := ssh.Unmarshal(data, &req); err != nil { 106 return nil, err 107 } 108 109 var wk wireKey 110 if err := ssh.Unmarshal(req.KeyBlob, &wk); err != nil { 111 return nil, err 112 } 113 114 k := &Key{ 115 Format: wk.Format, 116 Blob: req.KeyBlob, 117 } 118 119 sig, err := s.agent.Sign(k, req.Data) // TODO(hanwen): flags. 120 if err != nil { 121 return nil, err 122 } 123 return &signResponseAgentMsg{SigBlob: ssh.Marshal(sig)}, nil 124 case agentRequestIdentities: 125 keys, err := s.agent.List() 126 if err != nil { 127 return nil, err 128 } 129 130 rep := identitiesAnswerAgentMsg{ 131 NumKeys: uint32(len(keys)), 132 } 133 for _, k := range keys { 134 rep.Keys = append(rep.Keys, marshalKey(k)...) 135 } 136 return rep, nil 137 case agentAddIdentity: 138 return nil, s.insertIdentity(data) 139 } 140 141 return nil, fmt.Errorf("unknown opcode %d", data[0]) 142 } 143 144 func (s *server) insertIdentity(req []byte) error { 145 var record struct { 146 Type string `sshtype:"17"` 147 Rest []byte `ssh:"rest"` 148 } 149 if err := ssh.Unmarshal(req, &record); err != nil { 150 return err 151 } 152 153 switch record.Type { 154 case ssh.KeyAlgoRSA: 155 var k rsaKeyMsg 156 if err := ssh.Unmarshal(req, &k); err != nil { 157 return err 158 } 159 160 priv := rsa.PrivateKey{ 161 PublicKey: rsa.PublicKey{ 162 E: int(k.E.Int64()), 163 N: k.N, 164 }, 165 D: k.D, 166 Primes: []*big.Int{k.P, k.Q}, 167 } 168 priv.Precompute() 169 170 return s.agent.Add(&priv, nil, k.Comments) 171 } 172 return fmt.Errorf("not implemented: %s", record.Type) 173 } 174 175 // ServeAgent serves the agent protocol on the given connection. It 176 // returns when an I/O error occurs. 177 func ServeAgent(agent Agent, c io.ReadWriter) error { 178 s := &server{agent} 179 180 var length [4]byte 181 for { 182 if _, err := io.ReadFull(c, length[:]); err != nil { 183 return err 184 } 185 l := binary.BigEndian.Uint32(length[:]) 186 if l > maxAgentResponseBytes { 187 // We also cap requests. 188 return fmt.Errorf("agent: request too large: %d", l) 189 } 190 191 req := make([]byte, l) 192 if _, err := io.ReadFull(c, req); err != nil { 193 return err 194 } 195 196 repData := s.processRequestBytes(req) 197 if len(repData) > maxAgentResponseBytes { 198 return fmt.Errorf("agent: reply too large: %d bytes", len(repData)) 199 } 200 201 binary.BigEndian.PutUint32(length[:], uint32(len(repData))) 202 if _, err := c.Write(length[:]); err != nil { 203 return err 204 } 205 if _, err := c.Write(repData); err != nil { 206 return err 207 } 208 } 209 }