github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/ephemeral/user_ek_test.go (about) 1 package ephemeral 2 3 import ( 4 "testing" 5 6 "github.com/keybase/client/go/engine" 7 "github.com/keybase/client/go/kbtest" 8 "github.com/keybase/client/go/libkb" 9 "github.com/keybase/client/go/protocol/keybase1" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func publishAndVerifyUserEK(mctx libkb.MetaContext, t *testing.T, 14 merkleRoot libkb.MerkleRoot, uid keybase1.UID) keybase1.EkGeneration { 15 16 publishedMetadata, err := publishNewUserEK(mctx, merkleRoot) 17 require.NoError(t, err) 18 19 s := mctx.G().GetUserEKBoxStorage() 20 userEK, err := s.Get(mctx, publishedMetadata.Generation, nil) 21 require.NoError(t, err) 22 require.Equal(t, userEK.Metadata, publishedMetadata) 23 24 uids := []keybase1.UID{uid} 25 statements, err := fetchUserEKStatements(mctx, uids) 26 require.NoError(t, err) 27 statement, ok := statements[uid] 28 require.True(t, ok) 29 require.NotNil(t, statement) 30 currentMetadata := statement.CurrentUserEkMetadata 31 require.Equal(t, currentMetadata, publishedMetadata) 32 33 // We've stored the result in local storage 34 userEKBoxStorage := mctx.G().GetUserEKBoxStorage() 35 maxGeneration, err := userEKBoxStorage.MaxGeneration(mctx, false) 36 require.NoError(t, err) 37 ek, err := userEKBoxStorage.Get(mctx, maxGeneration, nil) 38 require.NoError(t, err) 39 require.Equal(t, ek.Metadata, publishedMetadata) 40 return maxGeneration 41 } 42 43 func TestNewUserEK(t *testing.T) { 44 tc, mctx, user := ephemeralKeyTestSetup(t) 45 defer tc.Cleanup() 46 47 merkleRootPtr, err := tc.G.GetMerkleClient().FetchRootFromServer(mctx, libkb.EphemeralKeyMerkleFreshness) 48 require.NoError(t, err) 49 merkleRoot := *merkleRootPtr 50 51 uid := tc.G.Env.GetUID() 52 maxGeneration := publishAndVerifyUserEK(mctx, t, merkleRoot, uid) 53 54 rawStorage := NewUserEKBoxStorage() 55 // Put our storage in a bad state by deleting the maxGeneration 56 err = rawStorage.Delete(mctx, maxGeneration) 57 require.NoError(t, err) 58 59 // If we publish in a bad local state, we can successfully get the 60 // maxGeneration from the server and continue 61 publishedMetadata2, err := publishNewUserEK(mctx, merkleRoot) 62 require.NoError(t, err) 63 require.EqualValues(t, maxGeneration+1, publishedMetadata2.Generation) 64 65 // Reset the user and verify we can generate a new userEK correctly 66 kbtest.ResetAccount(tc, user) 67 err = user.Login(tc.G) 68 require.NoError(t, err) 69 // create a new device ek 70 err = mctx.G().GetEKLib().KeygenIfNeeded(mctx) 71 require.NoError(t, err) 72 73 publishAndVerifyUserEK(mctx, t, merkleRoot, uid) 74 } 75 76 // TODO: test cases chat verify we can detect invalid signatures and bad metadata 77 78 // Test revoking a device/rolling the PUK both skipping and not skipping the 79 // userEkGeneration during the revoke to simulate revoking a device without 80 // userEK support. 81 func TestDeviceRevokeNewUserEK(t *testing.T) { 82 testDeviceRevoke(t, false /* skipUserEKForTesting */) 83 } 84 85 func TestDeviceRevokeNoNewUserEK(t *testing.T) { 86 testDeviceRevoke(t, true /* skipUserEKForTesting */) 87 } 88 89 func testDeviceRevoke(t *testing.T, skipUserEKForTesting bool) { 90 tc := libkb.SetupTest(t, "testDeviceRevoke", 2) 91 defer tc.Cleanup() 92 mctx := libkb.NewMetaContextForTest(tc) 93 NewEphemeralStorageAndInstall(mctx) 94 95 // Include a paper key with this test user, so that we have something to 96 // revoke. 97 user, err := kbtest.CreateAndSignupFakeUserPaper("e", tc.G) 98 require.NoError(t, err) 99 err = mctx.G().GetEKLib().KeygenIfNeeded(mctx) 100 require.NoError(t, err) 101 102 // Confirm that the user has a userEK. 103 uid := tc.G.Env.GetUID() 104 uids := []keybase1.UID{uid} 105 statements, err := fetchUserEKStatements(mctx, uids) 106 require.NoError(t, err) 107 statement, ok := statements[uid] 108 require.True(t, ok) 109 require.EqualValues(t, statement.CurrentUserEkMetadata.Generation, 1, "should start at userEK gen 1") 110 111 // Load the full user so that we can grab their devices. 112 arg := libkb.NewLoadUserByNameArg(tc.G, user.Username) 113 fullUser, err := libkb.LoadUser(arg) 114 if err != nil { 115 tc.T.Fatal(err) 116 } 117 paperKey := fullUser.GetComputedKeyInfos().PaperDevices()[0] 118 119 // Revoke the paper key. 120 revokeEngine := engine.NewRevokeDeviceEngine(tc.G, engine.RevokeDeviceEngineArgs{ 121 ID: paperKey.ID, 122 SkipUserEKForTesting: skipUserEKForTesting, 123 }) 124 uis := libkb.UIs{ 125 LogUI: tc.G.UI.GetLogUI(), 126 SecretUI: user.NewSecretUI(), 127 } 128 mctx = mctx.WithUIs(uis) 129 err = engine.RunEngine2(mctx, revokeEngine) 130 require.NoError(t, err) 131 132 // Finally, confirm that the revocation above rolled a new userEK. 133 if !skipUserEKForTesting { 134 statements, err = fetchUserEKStatements(mctx, uids) 135 require.NoError(t, err) 136 statement, ok = statements[uid] 137 require.True(t, ok) 138 require.EqualValues(t, statement.CurrentUserEkMetadata.Generation, 2, "after revoke, should have userEK gen 2") 139 userEK, err := tc.G.GetUserEKBoxStorage().Get(mctx, 2, nil) 140 require.NoError(t, err) 141 require.Equal(t, statement.CurrentUserEkMetadata, userEK.Metadata) 142 } 143 144 // Confirm that we can make a new userEK after rolling the PUK 145 merkleRootPtr, err := tc.G.GetMerkleClient().FetchRootFromServer(mctx, libkb.EphemeralKeyMerkleFreshness) 146 require.NoError(t, err) 147 merkleRoot := *merkleRootPtr 148 lib := tc.G.GetEKLib() 149 ekLib, ok := lib.(*EKLib) 150 require.True(t, ok) 151 // disable background keygen 152 err = ekLib.Shutdown(mctx) 153 require.NoError(t, err) 154 needed, err := ekLib.NewUserEKNeeded(mctx) 155 require.NoError(t, err) 156 require.Equal(t, skipUserEKForTesting, needed) 157 publishAndVerifyUserEK(mctx, t, merkleRoot, uid) 158 } 159 160 func TestPukRollNewUserEK(t *testing.T) { 161 tc, mctx, user := ephemeralKeyTestSetup(t) 162 defer tc.Cleanup() 163 164 // Confirm that the user has a userEK. 165 uid := tc.G.Env.GetUID() 166 uids := []keybase1.UID{uid} 167 statements, err := fetchUserEKStatements(mctx, uids) 168 require.NoError(t, err) 169 firstStatement, ok := statements[uid] 170 require.True(t, ok) 171 require.EqualValues(t, firstStatement.CurrentUserEkMetadata.Generation, 1, "should start at userEK gen 1") 172 173 // Do a PUK roll. 174 rollEngine := engine.NewPerUserKeyRoll(tc.G, &engine.PerUserKeyRollArgs{}) 175 uis := libkb.UIs{ 176 LogUI: tc.G.UI.GetLogUI(), 177 SecretUI: user.NewSecretUI(), 178 } 179 mctx = mctx.WithUIs(uis) 180 err = engine.RunEngine2(mctx, rollEngine) 181 require.NoError(t, err) 182 183 // Finally, confirm that the roll above also rolled a new userEK. 184 statements, err = fetchUserEKStatements(mctx, uids) 185 require.NoError(t, err) 186 secondStatement, ok := statements[uid] 187 require.True(t, ok) 188 require.EqualValues(t, secondStatement.CurrentUserEkMetadata.Generation, 2, "after PUK roll, should have userEK gen 2") 189 userEK, err := tc.G.GetUserEKBoxStorage().Get(mctx, 2, nil) 190 require.NoError(t, err) 191 require.Equal(t, secondStatement.CurrentUserEkMetadata, userEK.Metadata) 192 193 // Confirm that we can make a new userEK after rolling the PUK 194 merkleRootPtr, err := tc.G.GetMerkleClient().FetchRootFromServer(mctx, libkb.EphemeralKeyMerkleFreshness) 195 require.NoError(t, err) 196 merkleRoot := *merkleRootPtr 197 publishAndVerifyUserEK(mctx, t, merkleRoot, uid) 198 } 199 200 func TestDeprovision(t *testing.T) { 201 tc, mctx, user := ephemeralKeyTestSetup(t) 202 defer tc.Cleanup() 203 204 // Confirm that the user has a userEK. 205 uid := tc.G.Env.GetUID() 206 uids := []keybase1.UID{uid} 207 statements, err := fetchUserEKStatements(mctx, uids) 208 require.NoError(t, err) 209 firstStatement, ok := statements[uid] 210 require.True(t, ok) 211 require.EqualValues(t, firstStatement.CurrentUserEkMetadata.Generation, 1, "should start at userEK gen 1") 212 213 // make a paper key to log back in with 214 uis := libkb.UIs{ 215 LogUI: tc.G.UI.GetLogUI(), 216 LoginUI: &libkb.TestLoginUI{}, 217 SecretUI: &libkb.TestSecretUI{}, 218 } 219 eng := engine.NewPaperKey(tc.G) 220 mctx = mctx.WithUIs(uis) 221 err = engine.RunEngine2(mctx, eng) 222 require.NoError(t, err) 223 require.NotEqual(t, 0, len(eng.Passphrase()), "empty passphrase") 224 225 // self provision to have a device to create the userEK for 226 provLoginUI := &libkb.TestLoginUI{Username: user.Username} 227 uis = libkb.UIs{ 228 ProvisionUI: &kbtest.TestProvisionUI{}, 229 LogUI: tc.G.Log, 230 SecretUI: user.NewSecretUI(), 231 LoginUI: provLoginUI, 232 } 233 mctx = mctx.WithUIs(uis) 234 libkb.CreateClonedDevice(tc, mctx) 235 newName := "uncloneme" 236 eng1 := engine.NewSelfProvisionEngine(tc.G, newName) 237 err = engine.RunEngine2(mctx, eng1) 238 require.NoError(t, err) 239 require.Equal(t, mctx.ActiveDevice().Name(), newName) 240 241 eng2 := engine.NewDeprovisionEngine(tc.G, user.Username, true /* doRevoke */, libkb.LogoutOptions{}) 242 uis = libkb.UIs{ 243 LogUI: tc.G.UI.GetLogUI(), 244 SecretUI: user.NewSecretUI(), 245 } 246 mctx = mctx.WithUIs(uis) 247 err = engine.RunEngine2(mctx, eng2) 248 require.NoError(t, err) 249 250 // log back in 251 secretUI := user.NewSecretUI() 252 secretUI.Passphrase = eng.Passphrase() 253 provisionUI := &kbtest.TestProvisionUI{} 254 provisionUI.DeviceType = keybase1.DeviceTypeV2_PAPER 255 uis = libkb.UIs{ 256 ProvisionUI: provisionUI, 257 LogUI: tc.G.UI.GetLogUI(), 258 GPGUI: &kbtest.GPGTestUI{}, 259 SecretUI: secretUI, 260 LoginUI: &libkb.TestLoginUI{Username: user.Username}, 261 } 262 eng3 := engine.NewLogin(tc.G, keybase1.DeviceTypeV2_DESKTOP, user.Username, keybase1.ClientType_CLI) 263 mctx = mctx.WithUIs(uis) 264 err = engine.RunEngine2(mctx, eng3) 265 require.NoError(t, err) 266 267 // Finally, confirm that the deprovision above also created a new userEK. 268 statements, err = fetchUserEKStatements(mctx, uids) 269 require.NoError(t, err) 270 secondStatement, ok := statements[uid] 271 require.True(t, ok) 272 require.EqualValues(t, secondStatement.CurrentUserEkMetadata.Generation, 2, "after PUK roll, should have userEK gen 2") 273 }