Example #1
0
// Run starts the engine.
func (e *ProveCheck) Run(ctx *Context) error {
	found, status, err := libkb.CheckPostedViaSigID(e.sigID)
	if err != nil {
		return err
	}
	e.found = found
	e.status = keybase1.ProofStatus(status)

	e.G().Log.Debug("looking for ChainLink for %s", e.sigID)
	me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(e.G()))
	if err != nil {
		return err
	}
	link := me.LinkFromSigID(e.sigID)
	if link == nil {
		return fmt.Errorf("no chain link found for %s", e.sigID)
	}
	e.G().Log.Debug("chain link found: (%T)", link.Typed())
	if rlink, ok := link.Typed().(libkb.RemoteProofChainLink); ok {
		e.proofText = rlink.ProofText()
		e.G().Log.Debug("chain link proof text: %q", e.proofText)
	} else {
		e.G().Log.Warning("chain link had invalid type: %T", link.Typed())
	}
	return nil
}
Example #2
0
func (e *PGPKeyImportEngine) loadMe() (err error) {
	if e.me = e.arg.Me; e.me != nil {
		return
	}
	e.me, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(e.G()))
	return err
}
// Run starts the engine.
func (k *KexProvisioner) Run(ctx *Context) error {
	k.engctx = ctx

	var err error
	uarg := libkb.NewLoadUserPubOptionalArg(k.G())
	uarg.LoginContext = ctx.LoginContext
	k.user, err = libkb.LoadMe(uarg)
	if err != nil {
		return err
	}

	dp := k.G().Env.GetDeviceID()
	if dp.IsNil() {
		// Prereqs w/ Device: true should catch this earlier, but just in case:
		return libkb.DeviceRequiredError{}
	}
	k.deviceID = dp
	k.G().Log.Debug("device id: %s", k.deviceID)

	if k.user.GetComputedKeyFamily() == nil {
		return libkb.KeyFamilyError{Msg: "nil ckf"}
	}

	k.deviceSibkey, err = k.user.GetComputedKeyFamily().GetSibkeyForDevice(k.deviceID)
	if err != nil {
		k.G().Log.Warning("KexProvisioner.Run: error getting device sibkey: %s", err)
		return err
	}

	token, csrf := k.sessionArgs(ctx)

	k.sec, err = kex.SecretFromPhrase(k.user.GetName(), k.secretPhrase)
	if err != nil {
		return err
	}
	k.serverMu.Lock()
	k.server = kex.NewSender(kex.DirectionXtoY, k.sec.Secret(), token, csrf, k.G())
	k.serverMu.Unlock()

	arg := libkb.SecretKeyArg{
		Me:      k.user,
		KeyType: libkb.DeviceSigningKeyType,
	}
	k.sigKey, err = k.G().Keyrings.GetSecretKeyWithPrompt(ctx.LoginContext, arg, ctx.SecretUI, "new device install")
	if err != nil {
		k.G().Log.Warning("KexProvisioner.Run: GetSecretKey error: %s", err)
		return err
	}

	k.G().Log.Debug("KexProvisioner: starting receive loop")
	var nilDeviceID keybase1.DeviceID
	m := kex.NewMeta(k.user.GetUID(), k.sec.StrongID(), nilDeviceID, k.deviceID, kex.DirectionYtoX)
	err = k.loopReceives(ctx, m, k.sec)
	if err != nil {
		k.G().Log.Warning("Error in KEX receive: %s", err)
	}
	return err
}
// createFakeUserWithPGPOnly creates a new fake/testing user, who signed
// up on the Web site, and used the Web site to generate his/her key.  They
// used triplesec-encryption and synced their key to the keybase servers.
func createFakeUserWithPGPOnly(t *testing.T, tc libkb.TestContext) *FakeUser {
	fu := NewFakeUserOrBust(tc.T, "login")

	secui := &libkb.TestSecretUI{Passphrase: fu.Passphrase}
	ctx := &Context{
		GPGUI:    &gpgtestui{},
		SecretUI: secui,
		LogUI:    tc.G.UI.GetLogUI(),
		LoginUI:  &libkb.TestLoginUI{Username: fu.Username},
	}
	s := NewSignupEngine(nil, tc.G)

	f := func(a libkb.LoginContext) error {
		if err := s.genPassphraseStream(a, fu.Passphrase); err != nil {
			return err
		}

		if err := s.join(a, fu.Username, fu.Email, testInviteCode, true); err != nil {
			return err
		}

		return s.fakeLKS()
	}
	if err := s.G().LoginState().ExternalFunc(f, "createFakeUserWithPGPOnly"); err != nil {
		tc.T.Fatal(err)
	}

	// Generate a new test PGP key for the user, and specify the PushSecret
	// flag so that their triplesec'ed key is pushed to the server.
	gen := libkb.PGPGenArg{
		PrimaryBits: 1024,
		SubkeyBits:  1024,
	}
	gen.AddDefaultUID()
	peng := NewPGPKeyImportEngine(PGPKeyImportEngineArg{
		Gen:        &gen,
		PushSecret: true,
		Lks:        s.lks,
		NoSave:     true,
	})

	if err := RunEngine(peng, ctx); err != nil {
		tc.T.Fatal(err)
	}

	var err error
	fu.User, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tc.G))
	if err != nil {
		tc.T.Fatal(err)
	}

	return fu
}
Example #5
0
func (e *DeviceHistory) loadUser() error {
	arg := libkb.NewLoadUserPubOptionalArg(e.G())
	if len(e.username) == 0 {
		arg.Self = true
	} else {
		arg.Name = e.username
	}
	u, err := libkb.LoadUser(arg)
	if err != nil {
		return err
	}
	e.user = u
	return nil
}
Example #6
0
func (e *ListTrackers2Engine) lookupUID() error {
	if len(e.arg.Assertion) == 0 {
		e.uid = e.G().GetMyUID()
		if !e.uid.Exists() {
			return libkb.NoUIDError{}
		}
		return nil
	}

	larg := libkb.NewLoadUserPubOptionalArg(e.G())
	larg.Name = e.arg.Assertion
	u, err := libkb.LoadUser(larg)
	if err != nil {
		return err
	}
	e.uid = u.GetUID()
	return nil
}
Example #7
0
// see issue #578
func TestTrackRetrack(t *testing.T) {
	tc := SetupEngineTest(t, "track")
	defer tc.Cleanup()
	fu := CreateAndSignupFakeUser(tc, "track")

	tc.G.LoginState().Account(func(a *libkb.Account) {
		a.ClearStreamCache()
	}, "clear stream cache")

	idUI := &FakeIdentifyUI{}
	secretUI := fu.NewSecretUI()

	var err error
	fu.User, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tc.G))
	if err != nil {
		t.Fatal(err)
	}
	seqnoBefore := fu.User.GetSigChainLastKnownSeqno()

	arg := &TrackEngineArg{
		UserAssertion: "t_alice",
		Options:       keybase1.TrackOptions{BypassConfirm: true},
	}
	ctx := &Context{
		LogUI:      tc.G.UI.GetLogUI(),
		IdentifyUI: idUI,
		SecretUI:   secretUI,
	}

	eng := NewTrackEngine(arg, tc.G)
	err = RunEngine(eng, ctx)
	if err != nil {
		t.Fatal(err)
	}

	if !secretUI.CalledGetSecret {
		t.Errorf("expected get secret call")
	}

	fu.User, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tc.G))
	if err != nil {
		t.Fatal(err)
	}
	seqnoAfter := fu.User.GetSigChainLastKnownSeqno()

	if seqnoAfter == seqnoBefore {
		t.Errorf("seqno after track: %d, expected > %d", seqnoAfter, seqnoBefore)
	}

	Logout(tc)
	fu.LoginOrBust(tc)
	// clear out the passphrase cache
	tc.G.LoginState().Account(func(a *libkb.Account) {
		a.ClearStreamCache()
	}, "clear stream cache")

	// reset the flag
	secretUI.CalledGetSecret = false

	eng = NewTrackEngine(arg, tc.G)
	err = RunEngine(eng, ctx)
	if err != nil {
		t.Fatal(err)
	}

	if secretUI.CalledGetSecret {
		t.Errorf("get secret called on retrack")
	}

	fu.User, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tc.G))
	if err != nil {
		t.Fatal(err)
	}
	seqnoRetrack := fu.User.GetSigChainLastKnownSeqno()

	if seqnoRetrack > seqnoAfter {
		t.Errorf("seqno after retrack: %d, expected %d", seqnoRetrack, seqnoAfter)
	}
}
func (e *GPGImportKeyEngine) Run(ctx *Context) (err error) {
	gpg := e.G().GetGpgClient()

	me := e.arg.Me
	if me == nil {
		if me, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(e.G())); err != nil {
			return err
		}
	}

	if !e.arg.OnlyImport {
		if err = PGPCheckMulti(me, e.arg.AllowMulti); err != nil {
			return err
		}
	}

	if err = gpg.Configure(); err != nil {
		return err
	}
	index, warns, err := gpg.Index(true, e.arg.Query)
	if err != nil {
		return err
	}
	warns.Warn()

	var gks []keybase1.GPGKey
	for _, key := range index.Keys {
		gk := keybase1.GPGKey{
			Algorithm:  fmt.Sprintf("%d%s", key.Bits, key.AlgoString()),
			KeyID:      key.GetFingerprint().ToKeyID(),
			Expiration: key.ExpirationString(),
			Identities: key.GetPGPIdentities(),
		}
		gks = append(gks, gk)
	}

	if len(gks) == 0 {
		return fmt.Errorf("No PGP keys available to choose from.")
	}

	res, err := ctx.GPGUI.SelectKeyAndPushOption(context.TODO(), keybase1.SelectKeyAndPushOptionArg{Keys: gks})
	if err != nil {
		return err
	}
	e.G().Log.Debug("SelectKey result: %+v", res)

	var selected *libkb.GpgPrimaryKey
	for _, key := range index.Keys {
		if key.GetFingerprint().ToKeyID() == res.KeyID {
			selected = key
			break
		}
	}

	if selected == nil {
		return nil
	}

	publicKeys := me.GetActivePGPKeys(false)
	duplicate := false
	for _, key := range publicKeys {
		if key.GetFingerprint().Eq(*(selected.GetFingerprint())) {
			duplicate = true
			break
		}
	}
	if duplicate && !e.arg.OnlyImport {
		// This key's already been posted to the server.
		res, err := ctx.GPGUI.ConfirmDuplicateKeyChosen(context.TODO(), 0)
		if err != nil {
			return err
		}
		if !res {
			return libkb.SibkeyAlreadyExistsError{}
		}
		// We're sending a key update, then.
		fp := fmt.Sprintf("%s", *(selected.GetFingerprint()))
		eng := NewPGPUpdateEngine([]string{fp}, false, e.G())
		err = RunEngine(eng, ctx)
		e.duplicatedFingerprints = eng.duplicatedFingerprints

		return err
	}

	bundle, err := gpg.ImportKey(true, *(selected.GetFingerprint()))
	if err != nil {
		return fmt.Errorf("ImportKey error: %s", err)
	}

	if err := bundle.Unlock("Import of key into keybase keyring", ctx.SecretUI); err != nil {
		return err
	}

	e.G().Log.Info("Bundle unlocked: %s", selected.GetFingerprint().ToKeyID())

	eng := NewPGPKeyImportEngine(PGPKeyImportEngineArg{
		Pregen:     bundle,
		SigningKey: e.arg.Signer,
		Me:         me,
		AllowMulti: e.arg.AllowMulti,
		NoSave:     e.arg.SkipImport,
		OnlySave:   e.arg.OnlyImport,
		Lks:        e.arg.Lks,
	})

	if err = RunEngine(eng, ctx); err != nil {

		// It's important to propagate a CanceledError unmolested,
		// since the UI needs to know that. See:
		//  https://github.com/keybase/client/issues/226
		if _, ok := err.(libkb.CanceledError); !ok {
			err = libkb.KeyGenError{Msg: err.Error()}
		}
		return
	}

	e.G().Log.Info("Key %s imported", selected.GetFingerprint().ToKeyID())

	e.last = bundle

	return nil
}
Example #9
0
func (e *PGPKeyExportEngine) loadMe() (err error) {
	e.me, err = libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(e.G()))
	return
}
// TestLoginNewDeviceKexCancelOnY is a device provisioning test.  It
// simulates the scenario where a user logs in to a new device and
// uses an existing device to provision it.  This test checks that
// everything works ok if device Y cancels while waiting for
// device X to enter secret phrase.
func TestLoginNewDeviceKexCancelOnY(t *testing.T) {
	kex.HelloTimeout = 5 * time.Second
	kex.IntraTimeout = 5 * time.Second
	kex.PollDuration = 1 * time.Second

	// test context for device X
	tcX := SetupEngineTest(t, "loginX")
	defer tcX.Cleanup()

	// sign up with device X
	u := CreateAndSignupFakeUser(tcX, "login")
	docuiShared := lockuiDeviceShared{}
	docui := &lockuiDevice{lockui: &lockui{deviceName: "device X"}, shared: &docuiShared}

	secui := &libkb.TestSecretUI{Passphrase: u.Passphrase}

	// test that we can get the secret key:
	// XXX this is necessary for the test to pass once the goroutine starts
	me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tcX.G))
	if err != nil {
		t.Fatal(err)
	}
	arg := libkb.SecretKeyArg{
		Me:      me,
		KeyType: libkb.DeviceSigningKeyType,
	}
	_, err = tcX.G.Keyrings.GetSecretKeyWithPrompt(nil, arg, secui, "new device install")
	if err != nil {
		t.Fatal(err)
	}

	var wg sync.WaitGroup
	var li *LoginEngine

	wg.Add(1)
	go func() {
		// authorize on device X
		ctx := &Context{LogUI: tcX.G.UI.GetLogUI(), LocksmithUI: docui, SecretUI: secui}

		// wait for docui to know the secret
		for len(docui.secretPhrase()) == 0 {
			time.Sleep(50 * time.Millisecond)
		}
		// wait a little longer for Y...
		time.Sleep(50 * time.Millisecond)

		// so device Y should be waiting for device X to enter the secret phrase.
		// cancel it here:
		li.Cancel()

		// and now enter the secret phrase on device X and see what happens
		kx := NewKexProvisioner(tcX.G, docui.secretPhrase())
		err := RunEngine(kx, ctx)
		if err == nil {
			t.Error("kex sib succeeded, it should have failed.")
		}
		if _, ok := err.(libkb.CanceledError); !ok {
			t.Errorf("unexpected kex sib run error: %s", err)
		}

		wg.Done()
	}()

	// test context for device Y
	tcY := SetupEngineTest(t, "loginY")
	defer tcY.Cleanup()

	if tcY.G == tcX.G {
		t.Fatalf("tcY.G == tcX.G")
	}

	// log in with device Y
	li = NewLoginWithPromptEngine(u.Username, tcY.G)

	ydocui := &lockuiDevice{lockui: &lockui{deviceName: "device Y"}, shared: &docuiShared}

	ctx := &Context{LogUI: tcY.G.UI.GetLogUI(), LocksmithUI: ydocui, GPGUI: &gpgtestui{}, SecretUI: secui, LoginUI: &libkb.TestLoginUI{}}
	err = RunEngine(li, ctx)
	if err == nil {
		t.Fatal("device Y login should have failed")
	}
	if _, ok := err.(libkb.CanceledError); !ok {
		t.Errorf("device Y login err: %s (%T)", err, err)
	}

	wg.Wait()
}
// TestLoginNewDeviceKex is a device provisioning test.  It
// simulates the scenario where a user logs in to a new device and
// uses an existing device to provision it.  This test uses
// the api server for all kex communication.
func TestLoginNewDeviceKex1(t *testing.T) {
	kex.HelloTimeout = 5 * time.Second
	kex.IntraTimeout = 5 * time.Second
	kex.PollDuration = 1 * time.Second

	// test context for device X
	tcX := SetupEngineTest(t, "loginX")
	defer tcX.Cleanup()

	// sign up with device X
	u := CreateAndSignupFakeUser(tcX, "login")
	docuiShared := lockuiDeviceShared{}
	docui := &lockuiDevice{lockui: &lockui{deviceName: "device X"}, shared: &docuiShared}
	secui := &libkb.TestSecretUI{Passphrase: u.Passphrase}

	// test that we can get the secret key:
	// XXX this is necessary for the test to pass once the goroutine starts
	me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tcX.G))
	if err != nil {
		t.Fatal(err)
	}
	arg := libkb.SecretKeyArg{
		Me:      me,
		KeyType: libkb.DeviceSigningKeyType,
	}
	_, err = tcX.G.Keyrings.GetSecretKeyWithPrompt(nil, arg, secui, "new device install")
	if err != nil {
		t.Fatal(err)
	}

	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		// authorize on device X
		ctx := &Context{LogUI: tcX.G.UI.GetLogUI(), LocksmithUI: docui, SecretUI: secui}

		// wait for docui to know the secret
		for len(docui.secretPhrase()) == 0 {
			time.Sleep(50 * time.Millisecond)
		}

		kx := NewKexProvisioner(tcX.G, docui.secretPhrase())
		if err := RunEngine(kx, ctx); err != nil {
			t.Fatal(err)
		}
		wg.Done()
	}()

	// test context for device Y
	tcY := SetupEngineTest(t, "loginY")
	defer tcY.Cleanup()

	if tcY.G == tcX.G {
		t.Fatalf("tcY.G == tcX.G")
	}

	// log in with device Y
	li := NewLoginWithPromptEngine(u.Username, tcY.G)

	ydocui := &lockuiDevice{lockui: &lockui{deviceName: "device Y"}, shared: &docuiShared}

	ctx := &Context{LogUI: tcY.G.UI.GetLogUI(), LocksmithUI: ydocui, GPGUI: &gpgtestui{}, SecretUI: secui, LoginUI: &libkb.TestLoginUI{}}
	if err := RunEngine(li, ctx); err != nil {
		t.Fatal(err)
	}

	wg.Wait()
	testUserHasDeviceKey(tcY)
}
// TestLoginNewDeviceKexBadPhrase is a device provisioning test.
// It simulates the scenario where a user logs in to a new device and
// uses an existing device to provision it, but a bad secret
// phrase is entered on the existing device.
func TestLoginNewDeviceKexBadPhrase(t *testing.T) {
	kex.HelloTimeout = 5 * time.Second
	kex.IntraTimeout = 5 * time.Second
	kex.PollDuration = 1 * time.Second

	// test context for device X
	tcX := SetupEngineTest(t, "loginX")
	defer tcX.Cleanup()

	// sign up with device X
	u := CreateAndSignupFakeUser(tcX, "login")
	docuiShared := lockuiDeviceShared{}
	docui := &lockuiDevice{lockui: &lockui{deviceName: "device X"}, shared: &docuiShared}
	secui := &libkb.TestSecretUI{Passphrase: u.Passphrase}

	// test that we can get the secret key:
	// XXX this is necessary for the test to pass once the goroutine starts
	me, err := libkb.LoadMe(libkb.NewLoadUserPubOptionalArg(tcX.G))
	if err != nil {
		t.Fatal(err)
	}
	arg := libkb.SecretKeyArg{
		Me:      me,
		KeyType: libkb.DeviceSigningKeyType,
	}
	_, err = tcX.G.Keyrings.GetSecretKeyWithPrompt(nil, arg, secui, "new device install")
	if err != nil {
		t.Fatal(err)
	}

	var li *LoginEngine
	var wg sync.WaitGroup

	wg.Add(1)
	go func() {
		defer func() {
			// cancel the login engine when this is done.
			if li != nil {
				li.Cancel()
			}
		}()

		// authorize on device X
		ctx := &Context{LogUI: tcX.G.UI.GetLogUI(), LocksmithUI: docui, SecretUI: secui}

		// wait for docui to know the secret
		for len(docui.secretPhrase()) == 0 {
			time.Sleep(50 * time.Millisecond)
		}

		// ok, we know the secret phrase, but will enter it incorrectly:
		kx := NewKexProvisioner(tcX.G, docui.secretPhrase()+" gibberish")
		err := RunEngine(kx, ctx)
		if _, ok := err.(libkb.InvalidKexPhraseError); !ok {
			t.Fatal(err)
		}

		wg.Done()
	}()

	// test context for device Y
	tcY := SetupEngineTest(t, "loginY")
	defer tcY.Cleanup()

	if tcY.G == tcX.G {
		t.Fatalf("tcY.G == tcX.G")
	}

	// log in with device Y
	li = NewLoginWithPromptEngine(u.Username, tcY.G)

	ydocui := &lockuiDevice{lockui: &lockui{deviceName: "device Y"}, shared: &docuiShared}

	ctx := &Context{LogUI: tcY.G.UI.GetLogUI(), LocksmithUI: ydocui, GPGUI: &gpgtestui{}, SecretUI: secui, LoginUI: &libkb.TestLoginUI{}}
	err = RunEngine(li, ctx)
	if err != nil {
		if _, ok := err.(libkb.CanceledError); !ok {
			t.Fatal(err)
		}
	} else {
		t.Fatal("login on device Y should have returned error")
	}

	wg.Wait()
}