agent.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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. package ssh
  5. // References
  6. // PROTOCOL.agent: http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent
  7. import (
  8. "encoding/base64"
  9. "errors"
  10. "io"
  11. "sync"
  12. )
  13. // See PROTOCOL.agent, section 3.
  14. const (
  15. // 3.2 Requests from client to agent for protocol 2 key operations
  16. agentRequestIdentities = 11
  17. agentSignRequest = 13
  18. agentAddIdentity = 17
  19. agentRemoveIdentity = 18
  20. agentRemoveAllIdentities = 19
  21. agentAddIdConstrained = 25
  22. // 3.3 Key-type independent requests from client to agent
  23. agentAddSmartcardKey = 20
  24. agentRemoveSmartcardKey = 21
  25. agentLock = 22
  26. agentUnlock = 23
  27. agentAddSmartcardKeyConstrained = 26
  28. // 3.4 Generic replies from agent to client
  29. agentFailure = 5
  30. agentSuccess = 6
  31. // 3.6 Replies from agent to client for protocol 2 key operations
  32. agentIdentitiesAnswer = 12
  33. agentSignResponse = 14
  34. // 3.7 Key constraint identifiers
  35. agentConstrainLifetime = 1
  36. agentConstrainConfirm = 2
  37. )
  38. // maxAgentResponseBytes is the maximum agent reply size that is accepted. This
  39. // is a sanity check, not a limit in the spec.
  40. const maxAgentResponseBytes = 16 << 20
  41. // Agent messages:
  42. // These structures mirror the wire format of the corresponding ssh agent
  43. // messages found in PROTOCOL.agent.
  44. type failureAgentMsg struct{}
  45. type successAgentMsg struct{}
  46. // See PROTOCOL.agent, section 2.5.2.
  47. type requestIdentitiesAgentMsg struct{}
  48. // See PROTOCOL.agent, section 2.5.2.
  49. type identitiesAnswerAgentMsg struct {
  50. NumKeys uint32
  51. Keys []byte `ssh:"rest"`
  52. }
  53. // See PROTOCOL.agent, section 2.6.2.
  54. type signRequestAgentMsg struct {
  55. KeyBlob []byte
  56. Data []byte
  57. Flags uint32
  58. }
  59. // See PROTOCOL.agent, section 2.6.2.
  60. type signResponseAgentMsg struct {
  61. SigBlob []byte
  62. }
  63. // AgentKey represents a protocol 2 key as defined in PROTOCOL.agent,
  64. // section 2.5.2.
  65. type AgentKey struct {
  66. blob []byte
  67. Comment string
  68. }
  69. // String returns the storage form of an agent key with the format, base64
  70. // encoded serialized key, and the comment if it is not empty.
  71. func (ak *AgentKey) String() string {
  72. algo, _, ok := parseString(ak.blob)
  73. if !ok {
  74. return "ssh: malformed key"
  75. }
  76. s := string(algo) + " " + base64.StdEncoding.EncodeToString(ak.blob)
  77. if ak.Comment != "" {
  78. s += " " + ak.Comment
  79. }
  80. return s
  81. }
  82. // Key returns an agent's public key as a *rsa.PublicKey, *dsa.PublicKey, or
  83. // *OpenSSHCertV01.
  84. func (ak *AgentKey) Key() (interface{}, error) {
  85. if key, _, ok := parsePubKey(ak.blob); ok {
  86. return key, nil
  87. }
  88. return nil, errors.New("ssh: failed to parse key blob")
  89. }
  90. func parseAgentKey(in []byte) (out *AgentKey, rest []byte, ok bool) {
  91. ak := new(AgentKey)
  92. if ak.blob, in, ok = parseString(in); !ok {
  93. return
  94. }
  95. comment, in, ok := parseString(in)
  96. if !ok {
  97. return
  98. }
  99. ak.Comment = string(comment)
  100. return ak, in, true
  101. }
  102. // AgentClient provides a means to communicate with an ssh agent process based
  103. // on the protocol described in PROTOCOL.agent?rev=1.6.
  104. type AgentClient struct {
  105. // conn is typically represented by using a *net.UnixConn
  106. conn io.ReadWriter
  107. // mu is used to prevent concurrent access to the agent
  108. mu sync.Mutex
  109. }
  110. // NewAgentClient creates and returns a new *AgentClient using the
  111. // passed in io.ReadWriter as a connection to a ssh agent.
  112. func NewAgentClient(rw io.ReadWriter) *AgentClient {
  113. return &AgentClient{conn: rw}
  114. }
  115. // sendAndReceive sends req to the agent and waits for a reply. On success,
  116. // the reply is unmarshaled into reply and replyType is set to the first byte of
  117. // the reply, which contains the type of the message.
  118. func (ac *AgentClient) sendAndReceive(req []byte) (reply interface{}, replyType uint8, err error) {
  119. // ac.mu prevents multiple, concurrent requests. Since the agent is typically
  120. // on the same machine, we don't attempt to pipeline the requests.
  121. ac.mu.Lock()
  122. defer ac.mu.Unlock()
  123. msg := make([]byte, stringLength(len(req)))
  124. marshalString(msg, req)
  125. if _, err = ac.conn.Write(msg); err != nil {
  126. return
  127. }
  128. var respSizeBuf [4]byte
  129. if _, err = io.ReadFull(ac.conn, respSizeBuf[:]); err != nil {
  130. return
  131. }
  132. respSize, _, _ := parseUint32(respSizeBuf[:])
  133. if respSize > maxAgentResponseBytes {
  134. err = errors.New("ssh: agent reply too large")
  135. return
  136. }
  137. buf := make([]byte, respSize)
  138. if _, err = io.ReadFull(ac.conn, buf); err != nil {
  139. return
  140. }
  141. return unmarshalAgentMsg(buf)
  142. }
  143. // RequestIdentities queries the agent for protocol 2 keys as defined in
  144. // PROTOCOL.agent section 2.5.2.
  145. func (ac *AgentClient) RequestIdentities() ([]*AgentKey, error) {
  146. req := marshal(agentRequestIdentities, requestIdentitiesAgentMsg{})
  147. msg, msgType, err := ac.sendAndReceive(req)
  148. if err != nil {
  149. return nil, err
  150. }
  151. switch msg := msg.(type) {
  152. case *identitiesAnswerAgentMsg:
  153. if msg.NumKeys > maxAgentResponseBytes/8 {
  154. return nil, errors.New("ssh: too many keys in agent reply")
  155. }
  156. keys := make([]*AgentKey, msg.NumKeys)
  157. data := msg.Keys
  158. for i := uint32(0); i < msg.NumKeys; i++ {
  159. var key *AgentKey
  160. var ok bool
  161. if key, data, ok = parseAgentKey(data); !ok {
  162. return nil, ParseError{agentIdentitiesAnswer}
  163. }
  164. keys[i] = key
  165. }
  166. return keys, nil
  167. case *failureAgentMsg:
  168. return nil, errors.New("ssh: failed to list keys")
  169. }
  170. return nil, UnexpectedMessageError{agentIdentitiesAnswer, msgType}
  171. }
  172. // SignRequest requests the signing of data by the agent using a protocol 2 key
  173. // as defined in PROTOCOL.agent section 2.6.2. Supported key types include
  174. // *rsa.PublicKey, *dsa.PublicKey, *OpenSSHCertV01.
  175. func (ac *AgentClient) SignRequest(key interface{}, data []byte) ([]byte, error) {
  176. req := marshal(agentSignRequest, signRequestAgentMsg{
  177. KeyBlob: serializePublickey(key),
  178. Data: data,
  179. })
  180. msg, msgType, err := ac.sendAndReceive(req)
  181. if err != nil {
  182. return nil, err
  183. }
  184. switch msg := msg.(type) {
  185. case *signResponseAgentMsg:
  186. return msg.SigBlob, nil
  187. case *failureAgentMsg:
  188. return nil, errors.New("ssh: failed to sign challenge")
  189. }
  190. return nil, UnexpectedMessageError{agentSignResponse, msgType}
  191. }
  192. // unmarshalAgentMsg parses an agent message in packet, returning the parsed
  193. // form and the message type of packet.
  194. func unmarshalAgentMsg(packet []byte) (interface{}, uint8, error) {
  195. if len(packet) < 1 {
  196. return nil, 0, ParseError{0}
  197. }
  198. var msg interface{}
  199. switch packet[0] {
  200. case agentFailure:
  201. msg = new(failureAgentMsg)
  202. case agentSuccess:
  203. msg = new(successAgentMsg)
  204. case agentIdentitiesAnswer:
  205. msg = new(identitiesAnswerAgentMsg)
  206. case agentSignResponse:
  207. msg = new(signResponseAgentMsg)
  208. default:
  209. return nil, 0, UnexpectedMessageError{0, packet[0]}
  210. }
  211. if err := unmarshal(msg, packet, packet[0]); err != nil {
  212. return nil, 0, err
  213. }
  214. return msg, packet[0], nil
  215. }