keyring.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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 agent
  5. import (
  6. "bytes"
  7. "crypto/rand"
  8. "crypto/subtle"
  9. "errors"
  10. "fmt"
  11. "sync"
  12. "github.com/gogits/gogs/modules/crypto/ssh"
  13. )
  14. type privKey struct {
  15. signer ssh.Signer
  16. comment string
  17. }
  18. type keyring struct {
  19. mu sync.Mutex
  20. keys []privKey
  21. locked bool
  22. passphrase []byte
  23. }
  24. var errLocked = errors.New("agent: locked")
  25. // NewKeyring returns an Agent that holds keys in memory. It is safe
  26. // for concurrent use by multiple goroutines.
  27. func NewKeyring() Agent {
  28. return &keyring{}
  29. }
  30. // RemoveAll removes all identities.
  31. func (r *keyring) RemoveAll() error {
  32. r.mu.Lock()
  33. defer r.mu.Unlock()
  34. if r.locked {
  35. return errLocked
  36. }
  37. r.keys = nil
  38. return nil
  39. }
  40. // Remove removes all identities with the given public key.
  41. func (r *keyring) Remove(key ssh.PublicKey) error {
  42. r.mu.Lock()
  43. defer r.mu.Unlock()
  44. if r.locked {
  45. return errLocked
  46. }
  47. want := key.Marshal()
  48. found := false
  49. for i := 0; i < len(r.keys); {
  50. if bytes.Equal(r.keys[i].signer.PublicKey().Marshal(), want) {
  51. found = true
  52. r.keys[i] = r.keys[len(r.keys)-1]
  53. r.keys = r.keys[len(r.keys)-1:]
  54. continue
  55. } else {
  56. i++
  57. }
  58. }
  59. if !found {
  60. return errors.New("agent: key not found")
  61. }
  62. return nil
  63. }
  64. // Lock locks the agent. Sign and Remove will fail, and List will empty an empty list.
  65. func (r *keyring) Lock(passphrase []byte) error {
  66. r.mu.Lock()
  67. defer r.mu.Unlock()
  68. if r.locked {
  69. return errLocked
  70. }
  71. r.locked = true
  72. r.passphrase = passphrase
  73. return nil
  74. }
  75. // Unlock undoes the effect of Lock
  76. func (r *keyring) Unlock(passphrase []byte) error {
  77. r.mu.Lock()
  78. defer r.mu.Unlock()
  79. if !r.locked {
  80. return errors.New("agent: not locked")
  81. }
  82. if len(passphrase) != len(r.passphrase) || 1 != subtle.ConstantTimeCompare(passphrase, r.passphrase) {
  83. return fmt.Errorf("agent: incorrect passphrase")
  84. }
  85. r.locked = false
  86. r.passphrase = nil
  87. return nil
  88. }
  89. // List returns the identities known to the agent.
  90. func (r *keyring) List() ([]*Key, error) {
  91. r.mu.Lock()
  92. defer r.mu.Unlock()
  93. if r.locked {
  94. // section 2.7: locked agents return empty.
  95. return nil, nil
  96. }
  97. var ids []*Key
  98. for _, k := range r.keys {
  99. pub := k.signer.PublicKey()
  100. ids = append(ids, &Key{
  101. Format: pub.Type(),
  102. Blob: pub.Marshal(),
  103. Comment: k.comment})
  104. }
  105. return ids, nil
  106. }
  107. // Insert adds a private key to the keyring. If a certificate
  108. // is given, that certificate is added as public key. Note that
  109. // any constraints given are ignored.
  110. func (r *keyring) Add(key AddedKey) error {
  111. r.mu.Lock()
  112. defer r.mu.Unlock()
  113. if r.locked {
  114. return errLocked
  115. }
  116. signer, err := ssh.NewSignerFromKey(key.PrivateKey)
  117. if err != nil {
  118. return err
  119. }
  120. if cert := key.Certificate; cert != nil {
  121. signer, err = ssh.NewCertSigner(cert, signer)
  122. if err != nil {
  123. return err
  124. }
  125. }
  126. r.keys = append(r.keys, privKey{signer, key.Comment})
  127. return nil
  128. }
  129. // Sign returns a signature for the data.
  130. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
  131. r.mu.Lock()
  132. defer r.mu.Unlock()
  133. if r.locked {
  134. return nil, errLocked
  135. }
  136. wanted := key.Marshal()
  137. for _, k := range r.keys {
  138. if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
  139. return k.signer.Sign(rand.Reader, data)
  140. }
  141. }
  142. return nil, errors.New("not found")
  143. }
  144. // Signers returns signers for all the known keys.
  145. func (r *keyring) Signers() ([]ssh.Signer, error) {
  146. r.mu.Lock()
  147. defer r.mu.Unlock()
  148. if r.locked {
  149. return nil, errLocked
  150. }
  151. s := make([]ssh.Signer, 0, len(r.keys))
  152. for _, k := range r.keys {
  153. s = append(s, k.signer)
  154. }
  155. return s, nil
  156. }