client.go 15 KB

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