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  }