agent.go 6.3 KB

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