github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/ephemeral/kex2_test.go (about) 1 package ephemeral 2 3 import ( 4 "context" 5 "crypto/rand" 6 "fmt" 7 "sync" 8 "testing" 9 10 "github.com/keybase/client/go/engine" 11 "github.com/keybase/client/go/kbtest" 12 "github.com/keybase/client/go/kex2" 13 "github.com/keybase/client/go/libkb" 14 "github.com/keybase/client/go/protocol/keybase1" 15 "github.com/stretchr/testify/require" 16 ) 17 18 func TestKex2Provision(t *testing.T) { 19 subTestKex2Provision(t, false /* upgradePerUserKey */) 20 } 21 22 func TestKex2ProvisionPUK(t *testing.T) { 23 subTestKex2Provision(t, true /* upgradePerUserKey */) 24 } 25 26 func fakeSalt() []byte { 27 return []byte("fakeSALTfakeSALT") 28 } 29 30 func subTestKex2Provision(t *testing.T, upgradePerUserKey bool) { 31 // device X (provisioner) context: 32 tcX := libkb.SetupTest(t, "kex2provision", 2) 33 defer tcX.Cleanup() 34 tcX.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 35 mctxX := libkb.NewMetaContextForTest(tcX) 36 NewEphemeralStorageAndInstall(mctxX) 37 38 // provisioner needs to be logged in 39 userX, err := kbtest.CreateAndSignupFakeUser("X", tcX.G) 40 require.NoError(t, err) 41 err = userX.Login(tcX.G) 42 require.NoError(t, err) 43 44 // If we don't have a PUK, we can't make any EKs. 45 if upgradePerUserKey { 46 // The test user has a PUK, but it's not automatically loaded. We have to 47 // explicitly sync it. 48 keyring, err := tcX.G.GetPerUserKeyring(context.Background()) 49 require.NoError(t, err) 50 err = keyring.Sync(mctxX) 51 require.NoError(t, err) 52 53 ekLib := tcX.G.GetEKLib() 54 err = ekLib.KeygenIfNeeded(mctxX) 55 require.NoError(t, err) 56 } 57 58 // After the provision, Y should have access to this userEK generation 59 userEKBoxStorageX := tcX.G.GetUserEKBoxStorage() 60 userEKGenX, err := userEKBoxStorageX.MaxGeneration(mctxX, false) 61 require.NoError(t, err) 62 63 var userEKX keybase1.UserEk 64 if upgradePerUserKey { 65 require.True(t, userEKGenX > 0) 66 userEKX, err = userEKBoxStorageX.Get(mctxX, userEKGenX, nil) 67 require.NoError(t, err) 68 } else { 69 require.EqualValues(t, userEKGenX, -1) 70 } 71 72 // device Y (provisionee) context: 73 tcY := libkb.SetupTest(t, "kex2provision", 2) 74 defer tcY.Cleanup() 75 tcY.Tp.DisableUpgradePerUserKey = !upgradePerUserKey 76 mctxY := libkb.NewMetaContextForTest(tcY) 77 NewEphemeralStorageAndInstall(mctxY) 78 79 var secretX kex2.Secret 80 _, err = rand.Read(secretX[:]) 81 require.NoError(t, err) 82 83 var secretY kex2.Secret 84 _, err = rand.Read(secretY[:]) 85 require.NoError(t, err) 86 87 var wg sync.WaitGroup 88 89 // start provisionee 90 wg.Add(1) 91 go func() { 92 defer wg.Done() 93 94 err := (func() error { 95 uis := libkb.UIs{ 96 ProvisionUI: &kbtest.TestProvisionUI{SecretCh: make(chan kex2.Secret, 1)}, 97 } 98 deviceID, err := libkb.NewDeviceID() 99 if err != nil { 100 return err 101 } 102 suffix, err := libkb.RandBytes(5) 103 if err != nil { 104 return err 105 } 106 dname := fmt.Sprintf("device_%x", suffix) 107 device := &libkb.Device{ 108 ID: deviceID, 109 Description: &dname, 110 Type: keybase1.DeviceTypeV2_DESKTOP, 111 } 112 provisionee := engine.NewKex2Provisionee(tcY.G, device, secretY, userX.GetUID(), fakeSalt()) 113 mctxY = mctxY.WithUIs(uis).WithNewProvisionalLoginContext() 114 return engine.RunEngine2(mctxY, provisionee) 115 })() 116 require.NoError(t, err, "provisionee") 117 }() 118 119 // start provisioner 120 wg.Add(1) 121 go func() { 122 defer wg.Done() 123 uis := libkb.UIs{ 124 SecretUI: userX.NewSecretUI(), 125 ProvisionUI: &kbtest.TestProvisionUI{}, 126 } 127 provisioner := engine.NewKex2Provisioner(tcX.G, secretX, nil) 128 go provisioner.AddSecret(secretY) 129 mctxX = mctxX.WithUIs(uis) 130 if err := engine.RunEngine2(mctxX, provisioner); err != nil { 131 t.Errorf("provisioner error: %s", err) 132 return 133 } 134 }() 135 136 wg.Wait() 137 138 deviceEKStorageY := tcY.G.GetDeviceEKStorage() 139 maxDeviceEKGenerationY, err := deviceEKStorageY.MaxGeneration(mctxY, false) 140 require.NoError(t, err) 141 if upgradePerUserKey { 142 // Confirm that Y has a deviceEK. 143 require.True(t, maxDeviceEKGenerationY > 0) 144 deviceEKY, err := deviceEKStorageY.Get(mctxY, maxDeviceEKGenerationY) 145 require.NoError(t, err) 146 // Clear out DeviceCtime since it won't be present in fetched data, 147 // it's only known locally. 148 require.NotEqual(t, 0, deviceEKY.Metadata.DeviceCtime) 149 deviceEKY.Metadata.DeviceCtime = 0 150 151 // Make sure the server knows about our device_ek 152 merkleRootPtr, err := tcY.G.GetMerkleClient().FetchRootFromServer(mctxY, libkb.EphemeralKeyMerkleFreshness) 153 require.NoError(t, err) 154 155 fetchedDevices, err := allActiveDeviceEKMetadata(mctxY, *merkleRootPtr) 156 require.NoError(t, err) 157 158 deviceEKMetatdata, ok := fetchedDevices[mctxY.ActiveDevice().DeviceID()] 159 require.True(t, ok) 160 require.Equal(t, deviceEKY.Metadata, deviceEKMetatdata) 161 162 } else { 163 require.EqualValues(t, -1, maxDeviceEKGenerationY) 164 } 165 // Confirm Y has a userEK at the same generation as X. If we didn't have a 166 // PUK this generation will be -1. 167 userEKBoxStorageY := tcY.G.GetUserEKBoxStorage() 168 userEKGenY, err := userEKBoxStorageY.MaxGeneration(mctxY, false) 169 require.NoError(t, err) 170 require.EqualValues(t, userEKGenX, userEKGenY) 171 172 if upgradePerUserKey { 173 userEKY, err := userEKBoxStorageY.Get(mctxY, userEKGenY, nil) 174 require.NoError(t, err) 175 require.Equal(t, userEKX, userEKY) 176 177 // Now clear local store and make sure the server has reboxed userEK. 178 rawUserEKBoxStorage := NewUserEKBoxStorage() 179 err = rawUserEKBoxStorage.Delete(mctxY, userEKGenY) 180 require.NoError(t, err) 181 userEKBoxStorageY.ClearCache() 182 183 userEKYFetched, err := userEKBoxStorageY.Get(mctxY, userEKGenY, nil) 184 require.NoError(t, err) 185 require.Equal(t, userEKX, userEKYFetched) 186 } 187 }