// 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 }
// TestBasicMessage verifies that a message can be sent and // received. func TestBasicMessage(t *testing.T) { tc := SetupEngineTest(t, "kex") defer tc.Cleanup() fu := CreateAndSignupFakeUser(tc, "login") sec, err := kex.NewSecret(fu.Username) if err != nil { t.Fatal(err) } var tok, csrf string err = tc.G.LoginState().LocalSession(func(s *libkb.Session) { tok, csrf = s.APIArgs() }, "TestBasicMessage") if err != nil { t.Fatal(err) } s := kex.NewSender(kex.DirectionYtoX, sec.Secret(), tok, csrf, tc.G) r := kex.NewReceiver(kex.DirectionYtoX, sec, tok, csrf, tc.G) ctx := testKexMeta(t, fu.Username, sec) if err := s.StartKexSession(ctx, ctx.StrongID); err != nil { t.Fatal(err) } rctx := testKexMeta(t, fu.Username, sec) rctx.Swap() n, err := r.Receive(rctx) if err != nil { t.Fatal(err) } if n != 1 { t.Errorf("receive count: %d, expected 1", n) } select { case msg := <-r.Msgs: if msg.Name() != kex.StartKexMsg { t.Errorf("msg: %s, expected %s", msg.Name(), kex.StartKexMsg) } default: t.Fatal("no msg in r.Msgs") } }
func TestBadMACMessage(t *testing.T) { tc := SetupEngineTest(t, "kex") defer tc.Cleanup() fu := CreateAndSignupFakeUser(tc, "login") sec, err := kex.NewSecret(fu.Username) if err != nil { t.Fatal(err) } var tok, csrf string err = tc.G.LoginState().LocalSession(func(s *libkb.Session) { tok, csrf = s.APIArgs() }, "TestBadMACMessage") if err != nil { t.Fatal(err) } s := kex.NewSender(kex.DirectionYtoX, sec.Secret(), tok, csrf, tc.G) r := kex.NewReceiver(kex.DirectionYtoX, sec, tok, csrf, tc.G) ctx := testKexMeta(t, fu.Username, sec) if err := s.CorruptStartKexSession(ctx, ctx.StrongID); err != nil { t.Fatal(err) } rctx := testKexMeta(t, fu.Username, sec) rctx.Swap() n, err := r.Receive(rctx) if err != nil { t.Fatal(err) } if n != 0 { t.Errorf("receive count: %d, expected 0", n) } }
// Run starts the engine. func (k *KexNewDevice) Run(ctx *Context) error { k.G().Log.Debug("KexNewDevice: run starting") defer k.G().Log.Debug("KexNewDevice: run finished") k.user = k.args.User if k.args.DevDesc == "" { return errors.New("Empty device description passed to kex") } // register a new device ndarg := &DeviceRegisterArgs{ Me: k.user, Name: k.args.DevDesc, Lks: k.lks, } devreg := NewDeviceRegister(ndarg, k.G()) if err := RunEngine(devreg, ctx); err != nil { return err } k.deviceID = devreg.DeviceID() token, csrf := k.sessionArgs(ctx) // make random secret S, session id I sec, err := kex.NewSecret(k.user.GetName()) if err != nil { return err } k.secret = sec k.serverMu.Lock() k.server = kex.NewSender(kex.DirectionYtoX, k.secret.Secret(), token, csrf, k.G()) k.serverMu.Unlock() // create the kex meta data m := kex.NewMeta(k.args.User.GetUID(), k.secret.StrongID(), k.deviceID, k.args.Dst, kex.DirectionXtoY) // start message receive loop k.poll(ctx, m, sec) // tell user the command to enter on existing device (X) // note: this has to happen before StartKexSession call for tests to work. k.G().Log.Debug("KexNewDevice: displaying sibkey command") darg := keybase1.DisplaySecretWordsArg{ DeviceNameToAdd: k.args.DevDesc, DeviceNameExisting: k.args.DstName, Secret: sec.Phrase(), } if err := ctx.LocksmithUI.DisplaySecretWords(context.TODO(), darg); err != nil { return err } // start the kex session with X k.G().Log.Debug("KexNewDevice: sending StartKexSession to X") k.kexStatus(ctx, "sending StartKexSession to X", keybase1.KexStatusCode_START_SEND) if err := k.server.StartKexSession(m, k.secret.StrongID()); err != nil { return err } // wait for Hello() from X k.kexStatus(ctx, "waiting for Hello from X", keybase1.KexStatusCode_HELLO_WAIT) if err := k.next(ctx, kex.HelloMsg, kex.HelloTimeout, k.handleHello); err != nil { return err } k.kexStatus(ctx, "received Hello from X", keybase1.KexStatusCode_HELLO_RECEIVED) dkargs := &DeviceKeygenArgs{ Me: k.user, DeviceID: k.deviceID, DeviceName: k.args.DevDesc, DeviceType: libkb.DeviceTypeDesktop, Lks: k.lks, } dkeng := NewDeviceKeygen(dkargs, k.G()) if err := RunEngine(dkeng, ctx); err != nil { return err } signerPub, err := dkeng.SigningKeyPublic() if err != nil { return err } // get reverse signature of X's device key rsig, err := k.revSig(dkeng.SigningKey()) if err != nil { return err } // send PleaseSign message to X m.Sender = k.deviceID m.Receiver = k.args.Dst k.G().Log.Debug("KexNewDevice: sending PleaseSign to X") k.kexStatus(ctx, "sending PleaseSign to X", keybase1.KexStatusCode_PLEASE_SIGN_SEND) if err := k.server.PleaseSign(m, signerPub, rsig, k.args.DevType, k.args.DevDesc); err != nil { return err } // wait for Done() from X k.kexStatus(ctx, "waiting for Done from X", keybase1.KexStatusCode_DONE_WAIT) if err := k.next(ctx, kex.DoneMsg, kex.IntraTimeout, k.handleDone); err != nil { return err } k.kexStatus(ctx, "received Done from X", keybase1.KexStatusCode_DONE_RECEIVED) // push the dh key as a subkey to the server k.G().Log.Debug("KexNewDevice: pushing subkey") pargs := &DeviceKeygenPushArgs{ SkipSignerPush: true, Signer: dkeng.SigningKey(), EldestKID: k.user.GetEldestKID(), User: k.user, } if err := dkeng.Push(ctx, pargs); err != nil { k.G().Log.Debug("error running dkeng.Push(): %s", err) k.G().Log.Debug("push args: %+v", pargs) return err } k.wg.Wait() k.kexStatus(ctx, "kexfwd complete on new device Y", keybase1.KexStatusCode_END) return nil }