本站源代码
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.

790 lines
21KB

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