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