client.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  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 implements a client to an ssh-agent daemon.
  6. References:
  7. [PROTOCOL.agent]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.agent?rev=HEAD
  8. */
  9. package agent
  10. import (
  11. "bytes"
  12. "crypto/dsa"
  13. "crypto/ecdsa"
  14. "crypto/elliptic"
  15. "crypto/rsa"
  16. "encoding/base64"
  17. "encoding/binary"
  18. "errors"
  19. "fmt"
  20. "io"
  21. "math/big"
  22. "sync"
  23. "github.com/gogits/gogs/modules/crypto/ssh"
  24. )
  25. // Agent represents the capabilities of an ssh-agent.
  26. type Agent interface {
  27. // List returns the identities known to the agent.
  28. List() ([]*Key, error)
  29. // Sign has the agent sign the data using a protocol 2 key as defined
  30. // in [PROTOCOL.agent] section 2.6.2.
  31. Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error)
  32. // Add adds a private key to the agent.
  33. Add(key AddedKey) error
  34. // Remove removes all identities with the given public key.
  35. Remove(key ssh.PublicKey) error
  36. // RemoveAll removes all identities.
  37. RemoveAll() error
  38. // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
  39. Lock(passphrase []byte) error
  40. // Unlock undoes the effect of Lock
  41. Unlock(passphrase []byte) error
  42. // Signers returns signers for all the known keys.
  43. Signers() ([]ssh.Signer, error)
  44. }
  45. // AddedKey describes an SSH key to be added to an Agent.
  46. type AddedKey struct {
  47. // PrivateKey must be a *rsa.PrivateKey, *dsa.PrivateKey or
  48. // *ecdsa.PrivateKey, which will be inserted into the agent.
  49. PrivateKey interface{}
  50. // Certificate, if not nil, is communicated to the agent and will be
  51. // stored with the key.
  52. Certificate *ssh.Certificate
  53. // Comment is an optional, free-form string.
  54. Comment string
  55. // LifetimeSecs, if not zero, is the number of seconds that the
  56. // agent will store the key for.
  57. LifetimeSecs uint32
  58. // ConfirmBeforeUse, if true, requests that the agent confirm with the
  59. // user before each use of this key.
  60. ConfirmBeforeUse bool
  61. }
  62. // See [PROTOCOL.agent], section 3.
  63. const (
  64. agentRequestV1Identities = 1
  65. // 3.2 Requests from client to agent for protocol 2 key operations
  66. agentAddIdentity = 17
  67. agentRemoveIdentity = 18
  68. agentRemoveAllIdentities = 19
  69. agentAddIdConstrained = 25
  70. // 3.3 Key-type independent requests from client to agent
  71. agentAddSmartcardKey = 20
  72. agentRemoveSmartcardKey = 21
  73. agentLock = 22
  74. agentUnlock = 23
  75. agentAddSmartcardKeyConstrained = 26
  76. // 3.7 Key constraint identifiers
  77. agentConstrainLifetime = 1
  78. agentConstrainConfirm = 2
  79. )
  80. // maxAgentResponseBytes is the maximum agent reply size that is accepted. This
  81. // is a sanity check, not a limit in the spec.
  82. const maxAgentResponseBytes = 16 << 20
  83. // Agent messages:
  84. // These structures mirror the wire format of the corresponding ssh agent
  85. // messages found in [PROTOCOL.agent].
  86. // 3.4 Generic replies from agent to client
  87. const agentFailure = 5
  88. type failureAgentMsg struct{}
  89. const agentSuccess = 6
  90. type successAgentMsg struct{}
  91. // See [PROTOCOL.agent], section 2.5.2.
  92. const agentRequestIdentities = 11
  93. type requestIdentitiesAgentMsg struct{}
  94. // See [PROTOCOL.agent], section 2.5.2.
  95. const agentIdentitiesAnswer = 12
  96. type identitiesAnswerAgentMsg struct {
  97. NumKeys uint32 `sshtype:"12"`
  98. Keys []byte `ssh:"rest"`
  99. }
  100. // See [PROTOCOL.agent], section 2.6.2.
  101. const agentSignRequest = 13
  102. type signRequestAgentMsg struct {
  103. KeyBlob []byte `sshtype:"13"`
  104. Data []byte
  105. Flags uint32
  106. }
  107. // See [PROTOCOL.agent], section 2.6.2.
  108. // 3.6 Replies from agent to client for protocol 2 key operations
  109. const agentSignResponse = 14
  110. type signResponseAgentMsg struct {
  111. SigBlob []byte `sshtype:"14"`
  112. }
  113. type publicKey struct {
  114. Format string
  115. Rest []byte `ssh:"rest"`
  116. }
  117. // Key represents a protocol 2 public key as defined in
  118. // [PROTOCOL.agent], section 2.5.2.
  119. type Key struct {
  120. Format string
  121. Blob []byte
  122. Comment string
  123. }
  124. func clientErr(err error) error {
  125. return fmt.Errorf("agent: client error: %v", err)
  126. }
  127. // String returns the storage form of an agent key with the format, base64
  128. // encoded serialized key, and the comment if it is not empty.
  129. func (k *Key) String() string {
  130. s := string(k.Format) + " " + base64.StdEncoding.EncodeToString(k.Blob)
  131. if k.Comment != "" {
  132. s += " " + k.Comment
  133. }
  134. return s
  135. }
  136. // Type returns the public key type.
  137. func (k *Key) Type() string {
  138. return k.Format
  139. }
  140. // Marshal returns key blob to satisfy the ssh.PublicKey interface.
  141. func (k *Key) Marshal() []byte {
  142. return k.Blob
  143. }
  144. // Verify satisfies the ssh.PublicKey interface, but is not
  145. // implemented for agent keys.
  146. func (k *Key) Verify(data []byte, sig *ssh.Signature) error {
  147. return errors.New("agent: agent key does not know how to verify")
  148. }
  149. type wireKey struct {
  150. Format string
  151. Rest []byte `ssh:"rest"`
  152. }
  153. func parseKey(in []byte) (out *Key, rest []byte, err error) {
  154. var record struct {
  155. Blob []byte
  156. Comment string
  157. Rest []byte `ssh:"rest"`
  158. }
  159. if err := ssh.Unmarshal(in, &record); err != nil {
  160. return nil, nil, err
  161. }
  162. var wk wireKey
  163. if err := ssh.Unmarshal(record.Blob, &wk); err != nil {
  164. return nil, nil, err
  165. }
  166. return &Key{
  167. Format: wk.Format,
  168. Blob: record.Blob,
  169. Comment: record.Comment,
  170. }, record.Rest, nil
  171. }
  172. // client is a client for an ssh-agent process.
  173. type client struct {
  174. // conn is typically a *net.UnixConn
  175. conn io.ReadWriter
  176. // mu is used to prevent concurrent access to the agent
  177. mu sync.Mutex
  178. }
  179. // NewClient returns an Agent that talks to an ssh-agent process over
  180. // the given connection.
  181. func NewClient(rw io.ReadWriter) Agent {
  182. return &client{conn: rw}
  183. }
  184. // call sends an RPC to the agent. On success, the reply is
  185. // unmarshaled into reply and replyType is set to the first byte of
  186. // the reply, which contains the type of the message.
  187. func (c *client) call(req []byte) (reply interface{}, err error) {
  188. c.mu.Lock()
  189. defer c.mu.Unlock()
  190. msg := make([]byte, 4+len(req))
  191. binary.BigEndian.PutUint32(msg, uint32(len(req)))
  192. copy(msg[4:], req)
  193. if _, err = c.conn.Write(msg); err != nil {
  194. return nil, clientErr(err)
  195. }
  196. var respSizeBuf [4]byte
  197. if _, err = io.ReadFull(c.conn, respSizeBuf[:]); err != nil {
  198. return nil, clientErr(err)
  199. }
  200. respSize := binary.BigEndian.Uint32(respSizeBuf[:])
  201. if respSize > maxAgentResponseBytes {
  202. return nil, clientErr(err)
  203. }
  204. buf := make([]byte, respSize)
  205. if _, err = io.ReadFull(c.conn, buf); err != nil {
  206. return nil, clientErr(err)
  207. }
  208. reply, err = unmarshal(buf)
  209. if err != nil {
  210. return nil, clientErr(err)
  211. }
  212. return reply, err
  213. }
  214. func (c *client) simpleCall(req []byte) error {
  215. resp, err := c.call(req)
  216. if err != nil {
  217. return err
  218. }
  219. if _, ok := resp.(*successAgentMsg); ok {
  220. return nil
  221. }
  222. return errors.New("agent: failure")
  223. }
  224. func (c *client) RemoveAll() error {
  225. return c.simpleCall([]byte{agentRemoveAllIdentities})
  226. }
  227. func (c *client) Remove(key ssh.PublicKey) error {
  228. req := ssh.Marshal(&agentRemoveIdentityMsg{
  229. KeyBlob: key.Marshal(),
  230. })
  231. return c.simpleCall(req)
  232. }
  233. func (c *client) Lock(passphrase []byte) error {
  234. req := ssh.Marshal(&agentLockMsg{
  235. Passphrase: passphrase,
  236. })
  237. return c.simpleCall(req)
  238. }
  239. func (c *client) Unlock(passphrase []byte) error {
  240. req := ssh.Marshal(&agentUnlockMsg{
  241. Passphrase: passphrase,
  242. })
  243. return c.simpleCall(req)
  244. }
  245. // List returns the identities known to the agent.
  246. func (c *client) List() ([]*Key, error) {
  247. // see [PROTOCOL.agent] section 2.5.2.
  248. req := []byte{agentRequestIdentities}
  249. msg, err := c.call(req)
  250. if err != nil {
  251. return nil, err
  252. }
  253. switch msg := msg.(type) {
  254. case *identitiesAnswerAgentMsg:
  255. if msg.NumKeys > maxAgentResponseBytes/8 {
  256. return nil, errors.New("agent: too many keys in agent reply")
  257. }
  258. keys := make([]*Key, msg.NumKeys)
  259. data := msg.Keys
  260. for i := uint32(0); i < msg.NumKeys; i++ {
  261. var key *Key
  262. var err error
  263. if key, data, err = parseKey(data); err != nil {
  264. return nil, err
  265. }
  266. keys[i] = key
  267. }
  268. return keys, nil
  269. case *failureAgentMsg:
  270. return nil, errors.New("agent: failed to list keys")
  271. }
  272. panic("unreachable")
  273. }
  274. // Sign has the agent sign the data using a protocol 2 key as defined
  275. // in [PROTOCOL.agent] section 2.6.2.
  276. func (c *client) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
  277. req := ssh.Marshal(signRequestAgentMsg{
  278. KeyBlob: key.Marshal(),
  279. Data: data,
  280. })
  281. msg, err := c.call(req)
  282. if err != nil {
  283. return nil, err
  284. }
  285. switch msg := msg.(type) {
  286. case *signResponseAgentMsg:
  287. var sig ssh.Signature
  288. if err := ssh.Unmarshal(msg.SigBlob, &sig); err != nil {
  289. return nil, err
  290. }
  291. return &sig, nil
  292. case *failureAgentMsg:
  293. return nil, errors.New("agent: failed to sign challenge")
  294. }
  295. panic("unreachable")
  296. }
  297. // unmarshal parses an agent message in packet, returning the parsed
  298. // form and the message type of packet.
  299. func unmarshal(packet []byte) (interface{}, error) {
  300. if len(packet) < 1 {
  301. return nil, errors.New("agent: empty packet")
  302. }
  303. var msg interface{}
  304. switch packet[0] {
  305. case agentFailure:
  306. return new(failureAgentMsg), nil
  307. case agentSuccess:
  308. return new(successAgentMsg), nil
  309. case agentIdentitiesAnswer:
  310. msg = new(identitiesAnswerAgentMsg)
  311. case agentSignResponse:
  312. msg = new(signResponseAgentMsg)
  313. default:
  314. return nil, fmt.Errorf("agent: unknown type tag %d", packet[0])
  315. }
  316. if err := ssh.Unmarshal(packet, msg); err != nil {
  317. return nil, err
  318. }
  319. return msg, nil
  320. }
  321. type rsaKeyMsg struct {
  322. Type string `sshtype:"17"`
  323. N *big.Int
  324. E *big.Int
  325. D *big.Int
  326. Iqmp *big.Int // IQMP = Inverse Q Mod P
  327. P *big.Int
  328. Q *big.Int
  329. Comments string
  330. Constraints []byte `ssh:"rest"`
  331. }
  332. type dsaKeyMsg struct {
  333. Type string `sshtype:"17"`
  334. P *big.Int
  335. Q *big.Int
  336. G *big.Int
  337. Y *big.Int
  338. X *big.Int
  339. Comments string
  340. Constraints []byte `ssh:"rest"`
  341. }
  342. type ecdsaKeyMsg struct {
  343. Type string `sshtype:"17"`
  344. Curve string
  345. KeyBytes []byte
  346. D *big.Int
  347. Comments string
  348. Constraints []byte `ssh:"rest"`
  349. }
  350. // Insert adds a private key to the agent.
  351. func (c *client) insertKey(s interface{}, comment string, constraints []byte) error {
  352. var req []byte
  353. switch k := s.(type) {
  354. case *rsa.PrivateKey:
  355. if len(k.Primes) != 2 {
  356. return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
  357. }
  358. k.Precompute()
  359. req = ssh.Marshal(rsaKeyMsg{
  360. Type: ssh.KeyAlgoRSA,
  361. N: k.N,
  362. E: big.NewInt(int64(k.E)),
  363. D: k.D,
  364. Iqmp: k.Precomputed.Qinv,
  365. P: k.Primes[0],
  366. Q: k.Primes[1],
  367. Comments: comment,
  368. Constraints: constraints,
  369. })
  370. case *dsa.PrivateKey:
  371. req = ssh.Marshal(dsaKeyMsg{
  372. Type: ssh.KeyAlgoDSA,
  373. P: k.P,
  374. Q: k.Q,
  375. G: k.G,
  376. Y: k.Y,
  377. X: k.X,
  378. Comments: comment,
  379. Constraints: constraints,
  380. })
  381. case *ecdsa.PrivateKey:
  382. nistID := fmt.Sprintf("nistp%d", k.Params().BitSize)
  383. req = ssh.Marshal(ecdsaKeyMsg{
  384. Type: "ecdsa-sha2-" + nistID,
  385. Curve: nistID,
  386. KeyBytes: elliptic.Marshal(k.Curve, k.X, k.Y),
  387. D: k.D,
  388. Comments: comment,
  389. Constraints: constraints,
  390. })
  391. default:
  392. return fmt.Errorf("agent: unsupported key type %T", s)
  393. }
  394. // if constraints are present then the message type needs to be changed.
  395. if len(constraints) != 0 {
  396. req[0] = agentAddIdConstrained
  397. }
  398. resp, err := c.call(req)
  399. if err != nil {
  400. return err
  401. }
  402. if _, ok := resp.(*successAgentMsg); ok {
  403. return nil
  404. }
  405. return errors.New("agent: failure")
  406. }
  407. type rsaCertMsg struct {
  408. Type string `sshtype:"17"`
  409. CertBytes []byte
  410. D *big.Int
  411. Iqmp *big.Int // IQMP = Inverse Q Mod P
  412. P *big.Int
  413. Q *big.Int
  414. Comments string
  415. Constraints []byte `ssh:"rest"`
  416. }
  417. type dsaCertMsg struct {
  418. Type string `sshtype:"17"`
  419. CertBytes []byte
  420. X *big.Int
  421. Comments string
  422. Constraints []byte `ssh:"rest"`
  423. }
  424. type ecdsaCertMsg struct {
  425. Type string `sshtype:"17"`
  426. CertBytes []byte
  427. D *big.Int
  428. Comments string
  429. Constraints []byte `ssh:"rest"`
  430. }
  431. // Insert adds a private key to the agent. If a certificate is given,
  432. // that certificate is added instead as public key.
  433. func (c *client) Add(key AddedKey) error {
  434. var constraints []byte
  435. if secs := key.LifetimeSecs; secs != 0 {
  436. constraints = append(constraints, agentConstrainLifetime)
  437. var secsBytes [4]byte
  438. binary.BigEndian.PutUint32(secsBytes[:], secs)
  439. constraints = append(constraints, secsBytes[:]...)
  440. }
  441. if key.ConfirmBeforeUse {
  442. constraints = append(constraints, agentConstrainConfirm)
  443. }
  444. if cert := key.Certificate; cert == nil {
  445. return c.insertKey(key.PrivateKey, key.Comment, constraints)
  446. } else {
  447. return c.insertCert(key.PrivateKey, cert, key.Comment, constraints)
  448. }
  449. }
  450. func (c *client) insertCert(s interface{}, cert *ssh.Certificate, comment string, constraints []byte) error {
  451. var req []byte
  452. switch k := s.(type) {
  453. case *rsa.PrivateKey:
  454. if len(k.Primes) != 2 {
  455. return fmt.Errorf("agent: unsupported RSA key with %d primes", len(k.Primes))
  456. }
  457. k.Precompute()
  458. req = ssh.Marshal(rsaCertMsg{
  459. Type: cert.Type(),
  460. CertBytes: cert.Marshal(),
  461. D: k.D,
  462. Iqmp: k.Precomputed.Qinv,
  463. P: k.Primes[0],
  464. Q: k.Primes[1],
  465. Comments: comment,
  466. Constraints: constraints,
  467. })
  468. case *dsa.PrivateKey:
  469. req = ssh.Marshal(dsaCertMsg{
  470. Type: cert.Type(),
  471. CertBytes: cert.Marshal(),
  472. X: k.X,
  473. Comments: comment,
  474. })
  475. case *ecdsa.PrivateKey:
  476. req = ssh.Marshal(ecdsaCertMsg{
  477. Type: cert.Type(),
  478. CertBytes: cert.Marshal(),
  479. D: k.D,
  480. Comments: comment,
  481. })
  482. default:
  483. return fmt.Errorf("agent: unsupported key type %T", s)
  484. }
  485. // if constraints are present then the message type needs to be changed.
  486. if len(constraints) != 0 {
  487. req[0] = agentAddIdConstrained
  488. }
  489. signer, err := ssh.NewSignerFromKey(s)
  490. if err != nil {
  491. return err
  492. }
  493. if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
  494. return errors.New("agent: signer and cert have different public key")
  495. }
  496. resp, err := c.call(req)
  497. if err != nil {
  498. return err
  499. }
  500. if _, ok := resp.(*successAgentMsg); ok {
  501. return nil
  502. }
  503. return errors.New("agent: failure")
  504. }
  505. // Signers provides a callback for client authentication.
  506. func (c *client) Signers() ([]ssh.Signer, error) {
  507. keys, err := c.List()
  508. if err != nil {
  509. return nil, err
  510. }
  511. var result []ssh.Signer
  512. for _, k := range keys {
  513. result = append(result, &agentKeyringSigner{c, k})
  514. }
  515. return result, nil
  516. }
  517. type agentKeyringSigner struct {
  518. agent *client
  519. pub ssh.PublicKey
  520. }
  521. func (s *agentKeyringSigner) PublicKey() ssh.PublicKey {
  522. return s.pub
  523. }
  524. func (s *agentKeyringSigner) Sign(rand io.Reader, data []byte) (*ssh.Signature, error) {
  525. // The agent has its own entropy source, so the rand argument is ignored.
  526. return s.agent.Sign(s.pub, data)
  527. }