You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

683 lines
17 KiB

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