keyring.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. // Copyright 2014 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 main
  5. import (
  6. "bytes"
  7. "crypto/rand"
  8. "crypto/subtle"
  9. "errors"
  10. "fmt"
  11. "sync"
  12. "time"
  13. "golang.org/x/crypto/ssh"
  14. "golang.org/x/crypto/ssh/agent"
  15. )
  16. type privKey struct {
  17. signer ssh.Signer
  18. comment string
  19. confirm bool
  20. expire *time.Time
  21. }
  22. type ConfirmFunction func(comment string) bool
  23. type keyring struct {
  24. confirmFunction ConfirmFunction
  25. mu sync.Mutex
  26. keys []privKey
  27. locked bool
  28. passphrase []byte
  29. }
  30. var errLocked = errors.New("agent: locked")
  31. // NewKeyring returns an Agent that holds keys in memory. It is safe
  32. // for concurrent use by multiple goroutines.
  33. func NewKeyring(confirmFunction ConfirmFunction) agent.ExtendedAgent {
  34. return &keyring{
  35. confirmFunction: confirmFunction,
  36. }
  37. }
  38. // RemoveAll removes all identities.
  39. func (r *keyring) RemoveAll() error {
  40. r.mu.Lock()
  41. defer r.mu.Unlock()
  42. if r.locked {
  43. return errLocked
  44. }
  45. r.keys = nil
  46. return nil
  47. }
  48. // removeLocked does the actual key removal. The caller must already be holding the
  49. // keyring mutex.
  50. func (r *keyring) removeLocked(want []byte) error {
  51. found := false
  52. for i := 0; i < len(r.keys); {
  53. if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) {
  54. found = true
  55. r.keys[i] = r.keys[len(r.keys)-1]
  56. r.keys = r.keys[:len(r.keys)-1]
  57. continue
  58. } else {
  59. i++
  60. }
  61. }
  62. if !found {
  63. return errors.New("agent: key not found")
  64. }
  65. return nil
  66. }
  67. // Remove removes all identities with the given public key.
  68. func (r *keyring) Remove(key ssh.PublicKey) error {
  69. r.mu.Lock()
  70. defer r.mu.Unlock()
  71. if r.locked {
  72. return errLocked
  73. }
  74. return r.removeLocked(key.Marshal())
  75. }
  76. // Lock locks the agent. Sign and Remove will fail, and List will return an empty list.
  77. func (r *keyring) Lock(passphrase []byte) error {
  78. r.mu.Lock()
  79. defer r.mu.Unlock()
  80. if r.locked {
  81. return errLocked
  82. }
  83. r.locked = true
  84. r.passphrase = passphrase
  85. return nil
  86. }
  87. // Unlock undoes the effect of Lock
  88. func (r *keyring) Unlock(passphrase []byte) error {
  89. r.mu.Lock()
  90. defer r.mu.Unlock()
  91. if !r.locked {
  92. return errors.New("agent: not locked")
  93. }
  94. if 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
  95. return fmt.Errorf("agent: incorrect passphrase")
  96. }
  97. r.locked = false
  98. r.passphrase = nil
  99. return nil
  100. }
  101. // expireKeysLocked removes expired keys from the keyring. If a key was added
  102. // with a lifetimesecs contraint and seconds >= lifetimesecs seconds have
  103. // elapsed, it is removed. The caller *must* be holding the keyring mutex.
  104. func (r *keyring) expireKeysLocked() {
  105. for _, k := range r.keys {
  106. if k.expire != nil && time.Now().After(*k.expire) {
  107. r.removeLocked(k.signer.PublicKey().Marshal())
  108. }
  109. }
  110. }
  111. // List returns the identities known to the agent.
  112. func (r *keyring) List() ([]*agent.Key, error) {
  113. r.mu.Lock()
  114. defer r.mu.Unlock()
  115. if r.locked {
  116. // section 2.7: locked agents return empty.
  117. return nil, nil
  118. }
  119. r.expireKeysLocked()
  120. var ids []*agent.Key
  121. for _, k := range r.keys {
  122. pub := k.signer.PublicKey()
  123. ids = append(ids, &agent.Key{
  124. Format: pub.Type(),
  125. Blob: pub.Marshal(),
  126. Comment: k.comment})
  127. }
  128. return ids, nil
  129. }
  130. // Insert adds a private key to the keyring. If a certificate
  131. // is given, that certificate is added as public key. Note that
  132. // any constraints given are ignored.
  133. func (r *keyring) Add(key agent.AddedKey) error {
  134. r.mu.Lock()
  135. defer r.mu.Unlock()
  136. if r.locked {
  137. return errLocked
  138. }
  139. signer, err := ssh.NewSignerFromKey(key.PrivateKey)
  140. if err != nil {
  141. return err
  142. }
  143. if cert := key.Certificate; cert != nil {
  144. signer, err = ssh.NewCertSigner(cert, signer)
  145. if err != nil {
  146. return err
  147. }
  148. }
  149. p := privKey{
  150. signer: signer,
  151. comment: key.Comment,
  152. confirm: key.ConfirmBeforeUse,
  153. }
  154. if key.LifetimeSecs > 0 {
  155. t := time.Now().Add(time.Duration(key.LifetimeSecs) * time.Second)
  156. p.expire = &t
  157. }
  158. r.keys = append(r.keys, p)
  159. return nil
  160. }
  161. // Sign returns a signature for the data.
  162. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
  163. return r.SignWithFlags(key, data, 0)
  164. }
  165. func (r *keyring) SignWithFlags(key ssh.PublicKey, data []byte, flags agent.SignatureFlags) (*ssh.Signature, error) {
  166. r.mu.Lock()
  167. defer r.mu.Unlock()
  168. if r.locked {
  169. return nil, errLocked
  170. }
  171. r.expireKeysLocked()
  172. wanted := key.Marshal()
  173. for _, k := range r.keys {
  174. if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
  175. if k.confirm {
  176. if !r.confirmFunction(k.comment) {
  177. return nil, fmt.Errorf("agent: confirmation failed")
  178. }
  179. }
  180. if flags == 0 {
  181. return k.signer.Sign(rand.Reader, data)
  182. } else {
  183. if algorithmSigner, ok := k.signer.(ssh.AlgorithmSigner); !ok {
  184. return nil, fmt.Errorf("agent: signature does not support non-default signature algorithm: %T", k.signer)
  185. } else {
  186. var algorithm string
  187. switch flags {
  188. case agent.SignatureFlagRsaSha256:
  189. algorithm = ssh.KeyAlgoRSASHA256
  190. case agent.SignatureFlagRsaSha512:
  191. algorithm = ssh.KeyAlgoRSASHA512
  192. default:
  193. return nil, fmt.Errorf("agent: unsupported signature flags: %d", flags)
  194. }
  195. return algorithmSigner.SignWithAlgorithm(rand.Reader, data, algorithm)
  196. }
  197. }
  198. }
  199. }
  200. return nil, errors.New("not found")
  201. }
  202. // Signers returns signers for all the known keys.
  203. func (r *keyring) Signers() ([]ssh.Signer, error) {
  204. r.mu.Lock()
  205. defer r.mu.Unlock()
  206. if r.locked {
  207. return nil, errLocked
  208. }
  209. r.expireKeysLocked()
  210. s := make([]ssh.Signer, 0, len(r.keys))
  211. for _, k := range r.keys {
  212. s = append(s, k.signer)
  213. }
  214. return s, nil
  215. }
  216. // The keyring does not support any extensions
  217. func (r *keyring) Extension(extensionType string, contents []byte) ([]byte, error) {
  218. return nil, agent.ErrExtensionUnsupported
  219. }