@cryptotaxi247 / kubo / commits / 91dd044d5

config: guard against privkey being overwritten in fsrepo setConfig

License: MIT Signed-off-by: Jeromy <why@ipfs.io>

Jeromy committed Aug 29, 2016 at 14:56 UTC 91dd044d55dcb0b8d12388e2194cb4dac01bafe1
3 files changed +63 -30
core/commands/config.go
+46 -30
@@ -163,28 +163,12 @@ included in the output of this command.
163 return
164 }
165
166 - idmap, ok := cfg["Identity"].(map[string]interface{})
167 - if !ok {
168 - res.SetError(errors.New("config has no identity"), cmds.ErrNormal)
166 + err = scrubValue(cfg, []string{config.IdentityTag, config.PrivKeyTag})
167 + if err != nil {
168 + res.SetError(err, cmds.ErrNormal)
169 return
170 }
171
172 - privKeyKey := "" // make sure we both find the name of privkey and we delete it
173 - for key, _ := range idmap {
174 - if strings.ToLower(key) == "privkey" {
175 - if privKeyKey != "" {
176 - res.SetError(errors.New("found multiple PrivKey keys"), cmds.ErrNormal)
177 - return
178 - }
179 - privKeyKey = key
180 - }
181 - }
182 - if privKeyKey == "" {
183 - res.SetError(errors.New("haven't found PriveKey key"), cmds.ErrNormal)
184 - }
185 -
186 - delete(idmap, privKeyKey)
187 -
172 output, err := config.HumanOutput(cfg)
173 if err != nil {
174 res.SetError(err, cmds.ErrNormal)
@@ -195,6 +179,47 @@ included in the output of this command.
179 },
180 }
181
182 +func scrubValue(m map[string]interface{}, key []string) error {
183 + find := func(m map[string]interface{}, k string) (string, interface{}, bool) {
184 + lckey := strings.ToLower(k)
185 + for mkey, val := range m {
186 + lcmkey := strings.ToLower(mkey)
187 + if lckey == lcmkey {
188 + return mkey, val, true
189 + }
190 + }
191 + return "", nil, false
192 + }
193 +
194 + cur := m
195 + for _, k := range key[:len(key)-1] {
196 + foundk, val, ok := find(cur, k)
197 + if !ok {
198 + return fmt.Errorf("failed to find specified key")
199 + }
200 +
201 + if foundk != k {
202 + // case mismatch, calling this an error
203 + return fmt.Errorf("case mismatch in config, expected %q but got %q", k, foundk)
204 + }
205 +
206 + mval, mok := val.(map[string]interface{})
207 + if !mok {
208 + return fmt.Errorf("%s was not a map", foundk)
209 + }
210 +
211 + cur = mval
212 + }
213 +
214 + todel, _, ok := find(cur, key[len(key)-1])
215 + if !ok {
216 + return fmt.Errorf("%s, not found", strings.Join(key, "."))
217 + }
218 +
219 + delete(cur, todel)
220 + return nil
221 +}
222 +
223 var configEditCmd = &cmds.Command{
224 Helptext: cmds.HelpText{
225 Tagline: "Opens the config file for editing in $EDITOR.",
@@ -265,19 +290,10 @@ func getConfig(r repo.Repo, key string) (*ConfigField, error) {
290 }
291
292 func setConfig(r repo.Repo, key string, value interface{}) (*ConfigField, error) {
268 - keyF, err := getConfig(r, "Identity.PrivKey")
269 - if err != nil {
270 - return nil, errors.New("failed to get PrivKey")
271 - }
272 - privkey := keyF.Value
273 - err = r.SetConfigKey(key, value)
293 + err := r.SetConfigKey(key, value)
294 if err != nil {
295 return nil, fmt.Errorf("failed to set config value: %s (maybe use --json?)", err)
296 }
277 - err = r.SetConfigKey("Identity.PrivKey", privkey)
278 - if err != nil {
279 - return nil, errors.New("failed to set PrivKey")
280 - }
297 return getConfig(r, key)
298 }
299
@@ -301,7 +317,7 @@ func replaceConfig(r repo.Repo, file io.Reader) error {
317 return errors.New("setting private key with API is not supported")
318 }
319
304 - keyF, err := getConfig(r, "Identity.PrivKey")
320 + keyF, err := getConfig(r, config.PrivKeySelector)
321 if err != nil {
322 return fmt.Errorf("Failed to get PrivKey")
323 }
repo/config/identity.go
+4
@@ -5,6 +5,10 @@ import (
5 ic "gx/ipfs/QmUWER4r4qMvaCnX5zREcfyiWN7cXN9g3a7fkRqNz8qWPP/go-libp2p-crypto"
6 )
7
8 +const IdentityTag = "Identity"
9 +const PrivKeyTag = "PrivKey"
10 +const PrivKeySelector = IdentityTag + "." + PrivKeyTag
11 +
12 // Identity tracks the configuration of the local node's identity.
13 type Identity struct {
14 PeerID string
repo/fsrepo/fsrepo.go
+13
@@ -482,6 +482,14 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
482 return err
483 }
484
485 + // Load private key to guard against it being overwritten.
486 + // NOTE: this is a temporary measure to secure this field until we move
487 + // keys out of the config file.
488 + pkval, err := common.MapGetKV(mapconf, config.PrivKeySelector)
489 + if err != nil {
490 + return err
491 + }
492 +
493 // Get the type of the value associated with the key
494 oldValue, err := common.MapGetKV(mapconf, key)
495 ok := true
@@ -523,6 +531,11 @@ func (r *FSRepo) SetConfigKey(key string, value interface{}) error {
531 return err
532 }
533
534 + // replace private key, in case it was overwritten.
535 + if err := common.MapSetKV(mapconf, "Identity.PrivKey", pkval); err != nil {
536 + return err
537 + }
538 +
539 // This step doubles as to validate the map against the struct
540 // before serialization
541 conf, err := config.FromMap(mapconf)