func TestReset(t *testing.T) { tc := SetupEngineTest(t, "reset") defer tc.Cleanup() // Sign up a new user and have it store its secret in the // secret store (if possible). fu := NewFakeUserOrBust(tc.T, "reset") arg := MakeTestSignupEngineRunArg(fu) arg.StoreSecret = libkb.HasSecretStore() ctx := &Context{ LogUI: tc.G.UI.GetLogUI(), GPGUI: &gpgtestui{}, SecretUI: fu.NewSecretUI(), LoginUI: libkb.TestLoginUI{Username: fu.Username}, } s := NewSignupEngine(&arg, tc.G) err := RunEngine(s, ctx) if err != nil { tc.T.Fatal(err) } if libkb.HasSecretStore() { secretStore := libkb.NewSecretStore(fu.NormalizedUsername()) _, err := secretStore.RetrieveSecret() if err != nil { t.Fatal(err) } } dbPath := tc.G.Env.GetDbFilename() sessionPath := tc.G.Env.GetSessionFilename() assertFileExists(t, dbPath) assertFileExists(t, sessionPath) if !LoggedIn(tc) { t.Fatal("Unexpectedly logged out") } e := NewResetEngine(tc.G) ctx = &Context{} if err := RunEngine(e, ctx); err != nil { t.Fatal(err) } if LoggedIn(tc) { t.Error("Unexpectedly still logged in") } if libkb.HasSecretStore() { secretStore := libkb.NewSecretStore(fu.NormalizedUsername()) secret, err := secretStore.RetrieveSecret() if err == nil { t.Errorf("Unexpectedly got secret %v", secret) } } assertFileDoesNotExist(t, dbPath) assertFileDoesNotExist(t, sessionPath) }
// findAndDecryptPrivatePGPKeys gets the user's private pgp keys if // any exist and decrypts them. func (c *PassphraseChange) findAndDecryptPrivatePGPKeys(ctx *Context) ([]libkb.GenericKey, error) { ska := libkb.SecretKeyArg{ Me: c.me, KeyType: libkb.PGPKeyType, } // get all the pgp key skb blocks from the keyring: var blocks []*libkb.SKB err := c.G().LoginState().Keyring(func(kr *libkb.SKBKeyringFile) { blocks = kr.SearchWithComputedKeyFamily(c.me.GetComputedKeyFamily(), ska) }, "PassphraseChange - findAndDecryptPrivatePGPKey") if err != nil { return nil, err } // and the synced secret keys: syncKeys, err := c.me.AllSyncedSecretKeys(ctx.LoginContext) if err != nil { return nil, err } if syncKeys != nil { blocks = append(blocks, syncKeys...) } secretRetriever := libkb.NewSecretStore(c.G(), c.me.GetNormalizedName()) // avoid duplicates: keys := make(map[keybase1.KID]libkb.GenericKey) for _, block := range blocks { block.SetUID(c.me.GetUID()) var key libkb.GenericKey if c.usingPaper { key, err = block.UnlockWithStoredSecret(secretRetriever) if err != nil { switch err.(type) { case libkb.BadKeyError: // expected error, ok to proceed... continue default: // unexpected error type: return nil, err } } } else { parg := ctx.SecretKeyPromptArg(libkb.SecretKeyArg{}, "passphrase change") key, err = block.PromptAndUnlock(parg, "your keybase passphrase", secretRetriever, nil, c.me) if err != nil { return nil, err } } keys[key.GetKID()] = key } keyList := make([]libkb.GenericKey, 0, len(keys)) for _, key := range keys { keyList = append(keyList, key) } return keyList, nil }
// findAndDecryptPrivatePGPKeys gets the user's private pgp keys if // any exist and decrypts them. func (c *PassphraseChange) findAndDecryptPrivatePGPKeys(ctx *Context) ([]libkb.GenericKey, error) { var keyList []libkb.GenericKey // Using a paper key makes TripleSec-synced keys unrecoverable if c.usingPaper { c.G().Log.Debug("using a paper key, thus TripleSec-synced keys are unrecoverable") return keyList, nil } // Only use the synced secret keys: blocks, err := c.me.AllSyncedSecretKeys(ctx.LoginContext) if err != nil { return nil, err } secretRetriever := libkb.NewSecretStore(c.G(), c.me.GetNormalizedName()) for _, block := range blocks { parg := ctx.SecretKeyPromptArg(libkb.SecretKeyArg{}, "passphrase change") key, err := block.PromptAndUnlock(parg, secretRetriever, c.me) if err != nil { return nil, err } keyList = append(keyList, key) } return keyList, nil }
func userHasStoredSecretViaSecretStore(tc *libkb.TestContext, username string) bool { secretStore := libkb.NewSecretStore(libkb.NewNormalizedUsername(username)) if secretStore == nil { tc.T.Errorf("SecretStore for %s unexpectedly nil", username) return false } _, err := secretStore.RetrieveSecret() // TODO: Have RetrieveSecret return platform-independent errors // so that we can make sure we got the right one. return (err == nil) }
func (e *TrackToken) storeRemoteTrack(ctx *Context) (err error) { e.G().Log.Debug("+ StoreRemoteTrack") defer func() { e.G().Log.Debug("- StoreRemoteTrack -> %s", libkb.ErrToOk(err)) }() var secretStore libkb.SecretStore if e.arg.Me != nil { e.lockedKey.SetUID(e.arg.Me.GetUID()) secretStore = libkb.NewSecretStore(e.G(), e.arg.Me.GetNormalizedName()) } // need to unlock private key parg := ctx.SecretKeyPromptArg(libkb.SecretKeyArg{}, "tracking signature") e.signingKeyPriv, err = e.lockedKey.PromptAndUnlock(parg, e.lockedWhich, secretStore, nil, e.arg.Me) if err != nil { return err } if e.signingKeyPriv == nil { return libkb.NoSecretKeyError{} } sig, sigid, err := e.signingKeyPriv.SignToString(e.trackStatementBytes) if err != nil { return err } _, err = e.G().API.Post(libkb.APIArg{ Endpoint: "follow", NeedSession: true, Args: libkb.HTTPArgs{ "sig_id_base": libkb.S{Val: sigid.ToString(false)}, "sig_id_short": libkb.S{Val: sigid.ToShortID()}, "sig": libkb.S{Val: sig}, "uid": libkb.UIDArg(e.them.GetUID()), "type": libkb.S{Val: "track"}, "signing_kid": e.signingKeyPub.GetKID(), }, }) if err != nil { e.G().Log.Info("api error: %s", err) return err } linkid := libkb.ComputeLinkID(e.trackStatementBytes) e.arg.Me.SigChainBump(linkid, sigid) return err }
func (s *SignupEngine) registerDevice(a libkb.LoginContext, ctx *Context, deviceName string) error { s.lks = libkb.NewLKSec(s.ppStream, s.uid, s.G()) args := &DeviceWrapArgs{ Me: s.me, DeviceName: deviceName, DeviceType: libkb.DeviceTypeDesktop, Lks: s.lks, IsEldest: true, } eng := NewDeviceWrap(args, s.G()) ctx.LoginContext = a if err := RunEngine(eng, ctx); err != nil { return err } s.signingKey = eng.SigningKey() s.encryptionKey = eng.EncryptionKey() if err := ctx.LoginContext.LocalSession().SetDeviceProvisioned(s.G().Env.GetDeviceID()); err != nil { // this isn't a fatal error, session will stay in memory... s.G().Log.Warning("error saving session file: %s", err) } if s.arg.StoreSecret { // Create the secret store as late as possible here // (instead of when we first get the value of // StoreSecret) as the username may change during the // signup process. secretStore := libkb.NewSecretStore(s.G(), s.me.GetNormalizedName()) secret, err := s.lks.GetSecret(a) if err != nil { return err } // Ignore any errors storing the secret. storeSecretErr := secretStore.StoreSecret(secret) if storeSecretErr != nil { s.G().Log.Warning("StoreSecret error: %s", storeSecretErr) } } // is there any reason *not* to do this? ctx.LoginContext.SetCachedSecretKey(libkb.SecretKeyArg{KeyType: libkb.DeviceSigningKeyType}, s.signingKey) ctx.LoginContext.SetCachedSecretKey(libkb.SecretKeyArg{KeyType: libkb.DeviceEncryptionKeyType}, eng.EncryptionKey()) s.G().Log.Debug("registered new device: %s", s.G().Env.GetDeviceID()) s.G().Log.Debug("eldest kid: %s", s.me.GetEldestKID()) return nil }
func (e *PaperKeyGen) getClientHalfFromSecretStore() ([]byte, libkb.PassphraseGeneration, error) { zeroGen := libkb.PassphraseGeneration(0) secretStore := libkb.NewSecretStore(e.G(), e.arg.Me.GetNormalizedName()) if secretStore == nil { return nil, zeroGen, errors.New("No secret store available") } secret, err := secretStore.RetrieveSecret() if err != nil { return nil, zeroGen, err } devid := e.G().Env.GetDeviceID() if devid.IsNil() { return nil, zeroGen, fmt.Errorf("no device id set") } var dev libkb.DeviceKey aerr := e.G().LoginState().Account(func(a *libkb.Account) { if err = libkb.RunSyncer(a.SecretSyncer(), e.arg.Me.GetUID(), a.LoggedIn(), a.LocalSession()); err != nil { return } dev, err = a.SecretSyncer().FindDevice(devid) }, "BackupKeygen.Run() -- retrieving passphrase generation)") if aerr != nil { return nil, zeroGen, aerr } if err != nil { return nil, zeroGen, err } serverHalf, err := hex.DecodeString(dev.LksServerHalf) if err != nil { return nil, zeroGen, err } if len(secret) != len(serverHalf) { return nil, zeroGen, fmt.Errorf("secret has length %d, server half has length %d", len(secret), len(serverHalf)) } clientHalf := make([]byte, len(secret)) libkb.XORBytes(clientHalf, secret, serverHalf) return clientHalf, dev.PPGen, nil }
// Test that the signup engine stores the secret correctly when // StoreSecret is set. func TestLocalKeySecurityStoreSecret(t *testing.T) { tc := SetupEngineTest(t, "signup") defer tc.Cleanup() fu := NewFakeUserOrBust(t, "se") secretStore := libkb.NewSecretStore(tc.G, fu.NormalizedUsername()) if secretStore == nil { t.Skip("No SecretStore on this platform") } _, err := secretStore.RetrieveSecret() if err == nil { t.Fatal("User unexpectedly has secret") } arg := MakeTestSignupEngineRunArg(fu) arg.StoreSecret = true s := SignupFakeUserWithArg(tc, fu, arg) secret, err := s.lks.GetSecret(nil) if err != nil { t.Fatal(err) } storedSecret, err := secretStore.RetrieveSecret() if err != nil { t.Error(err) } if string(secret) != string(storedSecret) { t.Errorf("Expected %v, got %v", secret, storedSecret) } err = secretStore.ClearSecret() if err != nil { t.Error(err) } }
func assertDeprovisionWithSetup(tc libkb.TestContext) { // Sign up a new user and have it store its secret in the // secret store (if possible). fu := NewFakeUserOrBust(tc.T, "dpr") arg := MakeTestSignupEngineRunArg(fu) arg.SkipPaper = false arg.StoreSecret = tc.G.SecretStoreAll != nil ctx := &Context{ LogUI: tc.G.UI.GetLogUI(), GPGUI: &gpgtestui{}, SecretUI: fu.NewSecretUI(), LoginUI: &libkb.TestLoginUI{Username: fu.Username}, } s := NewSignupEngine(&arg, tc.G) err := RunEngine(s, ctx) if err != nil { tc.T.Fatal(err) } if tc.G.SecretStoreAll != nil { secretStore := libkb.NewSecretStore(tc.G, fu.NormalizedUsername()) _, err := secretStore.RetrieveSecret() if err != nil { tc.T.Fatal(err) } } dbPath := tc.G.Env.GetDbFilename() sessionPath := tc.G.Env.GetSessionFilename() secretKeysPath := tc.G.SKBFilenameForUser(fu.NormalizedUsername()) numKeys := getNumKeys(tc, *fu) assertFileExists(tc.T, dbPath) assertFileExists(tc.T, sessionPath) assertFileExists(tc.T, secretKeysPath) if !isUserInConfigFile(tc, *fu) { tc.T.Fatalf("User %s is not in the config file %s", fu.Username, tc.G.Env.GetConfigFilename()) } if !isUserConfigInMemory(tc) { tc.T.Fatal("user config is not in memory") } if !LoggedIn(tc) { tc.T.Fatal("Unexpectedly logged out") } e := NewDeprovisionEngine(tc.G, fu.Username, true /* doRevoke */) ctx = &Context{ LogUI: tc.G.UI.GetLogUI(), SecretUI: fu.NewSecretUI(), } if err := RunEngine(e, ctx); err != nil { tc.T.Fatal(err) } if LoggedIn(tc) { tc.T.Error("Unexpectedly still logged in") } if tc.G.SecretStoreAll != nil { secretStore := libkb.NewSecretStore(tc.G, fu.NormalizedUsername()) secret, err := secretStore.RetrieveSecret() if err == nil { tc.T.Errorf("Unexpectedly got secret %v", secret) } } assertFileDoesNotExist(tc.T, dbPath) assertFileDoesNotExist(tc.T, sessionPath) assertFileDoesNotExist(tc.T, secretKeysPath) if isUserInConfigFile(tc, *fu) { tc.T.Fatalf("User %s is still in the config file %s", fu.Username, tc.G.Env.GetConfigFilename()) } if isUserConfigInMemory(tc) { tc.T.Fatal("user config is still in memory") } newNumKeys := getNumKeys(tc, *fu) if newNumKeys != numKeys-2 { tc.T.Fatalf("failed to revoke device keys, before: %d, after: %d", numKeys, newNumKeys) } }
func TestDeprovisionLoggedOut(t *testing.T) { tc := SetupEngineTest(t, "deprovision") defer tc.Cleanup() // Sign up a new user and have it store its secret in the // secret store (if possible). fu := NewFakeUserOrBust(tc.T, "dpr") arg := MakeTestSignupEngineRunArg(fu) arg.StoreSecret = libkb.HasSecretStore() ctx := &Context{ LogUI: tc.G.UI.GetLogUI(), GPGUI: &gpgtestui{}, SecretUI: fu.NewSecretUI(), LoginUI: &libkb.TestLoginUI{Username: fu.Username}, } s := NewSignupEngine(&arg, tc.G) err := RunEngine(s, ctx) if err != nil { tc.T.Fatal(err) } if libkb.HasSecretStore() { secretStore := libkb.NewSecretStore(tc.G, fu.NormalizedUsername()) _, err := secretStore.RetrieveSecret() if err != nil { t.Fatal(err) } } dbPath := tc.G.Env.GetDbFilename() sessionPath := tc.G.Env.GetSessionFilename() secretKeysPath := tc.G.SKBFilenameForUser(fu.NormalizedUsername()) numKeys := getNumKeys(tc, *fu) assertFileExists(t, dbPath) assertFileExists(t, sessionPath) assertFileExists(t, secretKeysPath) if !isUserInConfigFile(tc, *fu) { t.Fatalf("User %s is not in the config file %s", fu.Username, tc.G.Env.GetConfigFilename()) } if !isUserConfigInMemory(tc) { t.Fatalf("user config is not in memory") } if !LoggedIn(tc) { t.Fatal("Unexpectedly logged out") } // Unlike the first test, this time we log out before we run the // deprovision. That should mean that no keys get revoked, but everything // else should be the same. tc.G.Logout() e := NewDeprovisionEngine(tc.G, fu.Username) ctx = &Context{ LogUI: tc.G.UI.GetLogUI(), SecretUI: fu.NewSecretUI(), } if err := RunEngine(e, ctx); err != nil { t.Fatal(err) } if LoggedIn(tc) { t.Error("Unexpectedly still logged in") } if libkb.HasSecretStore() { secretStore := libkb.NewSecretStore(tc.G, fu.NormalizedUsername()) secret, err := secretStore.RetrieveSecret() if err == nil { t.Errorf("Unexpectedly got secret %v", secret) } } assertFileDoesNotExist(t, dbPath) assertFileDoesNotExist(t, sessionPath) assertFileDoesNotExist(t, secretKeysPath) if isUserInConfigFile(tc, *fu) { t.Fatalf("User %s is still in the config file %s", fu.Username, tc.G.Env.GetConfigFilename()) } if isUserConfigInMemory(tc) { t.Fatalf("user config is still in memory") } newNumKeys := getNumKeys(tc, *fu) if newNumKeys != numKeys { t.Fatalf("expected the same number of device keys, before: %d, after: %d", numKeys, newNumKeys) } }