agent.go 6.6 KB

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