keyring.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. "code.google.com/p/go.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.
  109. func (r *keyring) Add(priv interface{}, cert *ssh.Certificate, comment string) error {
  110. r.mu.Lock()
  111. defer r.mu.Unlock()
  112. if r.locked {
  113. return errLocked
  114. }
  115. signer, err := ssh.NewSignerFromKey(priv)
  116. if err != nil {
  117. return err
  118. }
  119. if cert != nil {
  120. signer, err = ssh.NewCertSigner(cert, signer)
  121. if err != nil {
  122. return err
  123. }
  124. }
  125. r.keys = append(r.keys, privKey{signer, comment})
  126. return nil
  127. }
  128. // Sign returns a signature for the data.
  129. func (r *keyring) Sign(key ssh.PublicKey, data []byte) (*ssh.Signature, error) {
  130. r.mu.Lock()
  131. defer r.mu.Unlock()
  132. if r.locked {
  133. return nil, errLocked
  134. }
  135. wanted := key.Marshal()
  136. for _, k := range r.keys {
  137. if bytes.Equal(k.signer.PublicKey().Marshal(), wanted) {
  138. return k.signer.Sign(rand.Reader, data)
  139. }
  140. }
  141. return nil, errors.New("not found")
  142. }
  143. // Signers returns signers for all the known keys.
  144. func (r *keyring) Signers() ([]ssh.Signer, error) {
  145. r.mu.Lock()
  146. defer r.mu.Unlock()
  147. if r.locked {
  148. return nil, errLocked
  149. }
  150. s := make([]ssh.Signer, len(r.keys))
  151. for _, k := range r.keys {
  152. s = append(s, k.signer)
  153. }
  154. return s, nil
  155. }