1// Copyright 2016 Keybase Inc. All rights reserved.
2// Use of this source code is governed by a BSD
3// license that can be found in the LICENSE file.
4
5package libkbfs
6
7import (
8	"crypto/rand"
9	"errors"
10	"fmt"
11	"sync"
12	"testing"
13	"time"
14
15	"github.com/golang/mock/gomock"
16	"github.com/keybase/client/go/kbfs/idutil"
17	"github.com/keybase/client/go/kbfs/kbfscodec"
18	"github.com/keybase/client/go/kbfs/kbfscrypto"
19	"github.com/keybase/client/go/kbfs/kbfsmd"
20	"github.com/keybase/client/go/kbfs/libkey"
21	"github.com/keybase/client/go/kbfs/test/clocktest"
22	"github.com/keybase/client/go/kbfs/tlf"
23	"github.com/keybase/client/go/kbfs/tlfhandle"
24	kbname "github.com/keybase/client/go/kbun"
25	"github.com/keybase/client/go/protocol/keybase1"
26	merkle "github.com/keybase/go-merkle-tree"
27	"github.com/stretchr/testify/require"
28	"golang.org/x/net/context"
29)
30
31type shimCrypto struct {
32	Crypto
33	pure cryptoPure
34	key  kbfscrypto.SigningKey
35}
36
37func (c shimCrypto) Sign(
38	ctx context.Context, data []byte) (kbfscrypto.SignatureInfo, error) {
39	return c.key.Sign(data), nil
40}
41
42func (c shimCrypto) SignForKBFS(
43	ctx context.Context, data []byte) (kbfscrypto.SignatureInfo, error) {
44	return c.key.SignForKBFS(data)
45}
46
47func (c shimCrypto) Verify(
48	msg []byte, sigInfo kbfscrypto.SignatureInfo) (err error) {
49	return kbfscrypto.Verify(msg, sigInfo)
50}
51
52func injectShimCrypto(config Config) {
53	signingKey := kbfscrypto.MakeFakeSigningKeyOrBust("test key")
54	crypto := shimCrypto{
55		config.Crypto(),
56		MakeCryptoCommon(kbfscodec.NewMsgpack(), makeBlockCryptV1()),
57		signingKey,
58	}
59	config.SetCrypto(crypto)
60}
61
62func mdOpsInit(t *testing.T, ver kbfsmd.MetadataVer) (mockCtrl *gomock.Controller,
63	config *ConfigMock, ctx context.Context) {
64	ctr := NewSafeTestReporter(t)
65	mockCtrl = gomock.NewController(ctr)
66	config = NewConfigMock(mockCtrl, ctr)
67	config.SetMetadataVersion(ver)
68	mdops := NewMDOpsStandard(config)
69	config.SetMDOps(mdops)
70	config.SetCodec(kbfscodec.NewMsgpack())
71	config.SetKeyBundleCache(kbfsmd.NewKeyBundleCacheLRU(0))
72	config.mockMdserv.EXPECT().OffsetFromServerTime().
73		Return(time.Duration(0), true).AnyTimes()
74	config.mockClock.EXPECT().Now().Return(time.Now()).AnyTimes()
75	injectShimCrypto(config)
76	interposeDaemonKBPKI(config, "alice", "bob", "charlie")
77	ctx = context.Background()
78
79	// Don't test implicit teams.
80	config.mockKbpki.EXPECT().ResolveImplicitTeam(
81		gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
82		AnyTimes().Return(idutil.ImplicitTeamInfo{}, errors.New("No such team"))
83	// Don't cache IDs.
84	config.mockMdcache.EXPECT().GetIDForHandle(gomock.Any()).AnyTimes().
85		Return(tlf.NullID, NoSuchTlfIDError{nil})
86	config.mockMdcache.EXPECT().PutIDForHandle(gomock.Any(), gomock.Any()).
87		AnyTimes().Return(nil)
88	mockNormalizeSocialAssertion(config)
89
90	return mockCtrl, config, ctx
91}
92
93func mdOpsShutdown(mockCtrl *gomock.Controller, config *ConfigMock) {
94	config.ctr.CheckForFailures()
95	mockCtrl.Finish()
96}
97
98func addPrivateDataToRMD(t *testing.T,
99	codec kbfscodec.Codec, rmd *RootMetadata, h *tlfhandle.Handle,
100	pmd PrivateMetadata) {
101	rmd.SetRevision(kbfsmd.Revision(1))
102	// TODO: Will have to change this for private folders if we
103	// un-mock out those tests.
104	buf, err := codec.Encode(pmd)
105	require.NoError(t, err)
106	rmd.SetSerializedPrivateMetadata(buf)
107	rmd.SetLastModifyingWriter(h.FirstResolvedWriter().AsUserOrBust())
108	rmd.SetLastModifyingUser(h.FirstResolvedWriter().AsUserOrBust())
109	if h.Type() == tlf.Private {
110		rmd.fakeInitialRekey()
111	}
112}
113
114func addFakeRMDData(t *testing.T,
115	codec kbfscodec.Codec, rmd *RootMetadata, h *tlfhandle.Handle) {
116	addPrivateDataToRMD(t, codec, rmd, h, PrivateMetadata{})
117}
118
119func newRMDS(t *testing.T, config Config, h *tlfhandle.Handle) (
120	*RootMetadataSigned, kbfsmd.ExtraMetadata) {
121	id := h.TlfID()
122	if id == tlf.NullID {
123		id = tlf.FakeID(1, h.Type())
124	}
125
126	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), id, h)
127	require.NoError(t, err)
128
129	addFakeRMDData(t, config.Codec(), rmd, h)
130	ctx := context.Background()
131
132	// Encode and sign writer metadata.
133	err = rmd.bareMd.SignWriterMetadataInternally(ctx, config.Codec(), config.Crypto())
134	require.NoError(t, err)
135
136	rmds, err := SignBareRootMetadata(
137		ctx, config.Codec(), config.Crypto(), config.Crypto(),
138		rmd.bareMd, time.Now())
139	require.NoError(t, err)
140	return rmds, rmd.extra
141}
142
143func verifyMDForPublic(config *ConfigMock, rmds *RootMetadataSigned,
144	hasVerifyingKeyErr error) {
145	config.mockKbpki.EXPECT().HasVerifyingKey(
146		gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
147		AnyTimes().Return(hasVerifyingKeyErr)
148	if hasVerifyingKeyErr == nil {
149		config.mockMdcache.EXPECT().Put(gomock.Any())
150	}
151}
152
153// kmdMatcher implements the gomock.Matcher interface to compare
154// KeyMetadata objects.
155type kmdMatcher struct {
156	kmd libkey.KeyMetadata
157}
158
159func (m kmdMatcher) Matches(x interface{}) bool {
160	kmd, ok := x.(libkey.KeyMetadata)
161	if !ok {
162		return false
163	}
164	return (m.kmd.TlfID() == kmd.TlfID()) &&
165		(m.kmd.LatestKeyGeneration() == kmd.LatestKeyGeneration())
166}
167
168func (m kmdMatcher) String() string {
169	return fmt.Sprintf("Matches KeyMetadata with TlfID=%s and key generation %d",
170		m.kmd.TlfID(), m.kmd.LatestKeyGeneration())
171}
172
173func expectGetTLFCryptKeyForEncryption(config *ConfigMock, kmd libkey.KeyMetadata) {
174	config.mockKeyman.EXPECT().GetTLFCryptKeyForEncryption(gomock.Any(),
175		kmdMatcher{kmd}).Return(kbfscrypto.TLFCryptKey{}, nil)
176}
177
178func expectGetTLFCryptKeyForMDDecryptionAtMostOnce(config *ConfigMock,
179	kmd libkey.KeyMetadata) {
180	config.mockKeyman.EXPECT().GetTLFCryptKeyForMDDecryption(gomock.Any(),
181		kmdMatcher{kmd}, kmdMatcher{kmd}).MaxTimes(1).Return(
182		kbfscrypto.TLFCryptKey{}, nil)
183}
184
185func verifyMDForPrivateHelper(
186	config *ConfigMock, rmds *RootMetadataSigned, minTimes, maxTimes int,
187	forceFinal bool) {
188	mdCopy, err := rmds.MD.DeepCopy(config.Codec())
189	if err != nil {
190		panic(err)
191	}
192	fakeRMD := RootMetadata{
193		bareMd: mdCopy,
194	}
195	expectGetTLFCryptKeyForMDDecryptionAtMostOnce(config, &fakeRMD)
196	var pmd PrivateMetadata
197	config.mockCrypto.EXPECT().DecryptPrivateMetadata(
198		gomock.Any(), kbfscrypto.TLFCryptKey{}).
199		MinTimes(minTimes).MaxTimes(maxTimes).Return(pmd, nil)
200
201	config.mockKbpki.EXPECT().HasVerifyingKey(
202		gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
203		AnyTimes().Return(nil)
204	config.mockMdcache.EXPECT().Put(gomock.Any()).AnyTimes()
205	config.mockKeyman.EXPECT().GetFirstTLFCryptKey(gomock.Any(), gomock.Any()).
206		AnyTimes().Return(kbfscrypto.TLFCryptKey{}, nil)
207}
208
209func verifyMDForPrivate(
210	config *ConfigMock, rmds *RootMetadataSigned) {
211	verifyMDForPrivateHelper(config, rmds, 1, 1, false)
212}
213
214func putMDForPrivate(config *ConfigMock, rmd *RootMetadata) {
215	expectGetTLFCryptKeyForEncryption(config, rmd)
216	config.mockCrypto.EXPECT().EncryptPrivateMetadata(
217		rmd.data, kbfscrypto.TLFCryptKey{}).Return(
218		kbfscrypto.EncryptedPrivateMetadata{}, nil)
219	config.mockBsplit.EXPECT().ShouldEmbedData(gomock.Any()).Return(true)
220	config.mockMdserv.EXPECT().Put(gomock.Any(), gomock.Any(), gomock.Any(),
221		nil, gomock.Any()).Return(nil)
222	config.mockMdcache.EXPECT().Replace(gomock.Any(), gomock.Any())
223}
224
225func testMDOpsGetIDForHandlePublicSuccess(
226	t *testing.T, ver kbfsmd.MetadataVer) {
227	mockCtrl, config, ctx := mdOpsInit(t, ver)
228	defer mdOpsShutdown(mockCtrl, config)
229
230	id := tlf.FakeID(1, tlf.Public)
231	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Public, id)
232	rmds, _ := newRMDS(t, config, h)
233	h.SetTlfID(tlf.NullID)
234
235	verifyMDForPublic(config, rmds, nil)
236
237	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
238		kbfsmd.Merged, nil).Return(id, rmds, nil)
239
240	id2, err := config.MDOps().GetIDForHandle(ctx, h)
241	require.NoError(t, err)
242	require.Equal(t, id, id2)
243}
244
245func expectGetKeyBundles(ctx context.Context, config *ConfigMock, extra kbfsmd.ExtraMetadata) {
246	if extraV3, ok := extra.(*kbfsmd.ExtraMetadataV3); ok {
247		wkb := extraV3.GetWriterKeyBundle()
248		rkb := extraV3.GetReaderKeyBundle()
249		config.mockMdserv.EXPECT().GetKeyBundles(
250			ctx, gomock.Any(), gomock.Any(), gomock.Any()).
251			Return(&wkb, &rkb, nil)
252	}
253}
254
255func testMDOpsGetIDForHandlePrivateSuccess(
256	t *testing.T, ver kbfsmd.MetadataVer) {
257	mockCtrl, config, ctx := mdOpsInit(t, ver)
258	defer mdOpsShutdown(mockCtrl, config)
259
260	id := tlf.FakeID(1, tlf.Private)
261	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
262	rmds, extra := newRMDS(t, config, h)
263	h.SetTlfID(tlf.NullID)
264
265	verifyMDForPrivate(config, rmds)
266
267	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
268		kbfsmd.Merged, nil).Return(id, rmds, nil)
269	expectGetKeyBundles(ctx, config, extra)
270
271	id2, err := config.MDOps().GetIDForHandle(ctx, h)
272	require.NoError(t, err)
273	require.Equal(t, id, id2)
274}
275
276func testMDOpsGetIDForUnresolvedHandlePublicSuccess(
277	t *testing.T, ver kbfsmd.MetadataVer) {
278	mockCtrl, config, ctx := mdOpsInit(t, ver)
279	defer mdOpsShutdown(mockCtrl, config)
280
281	id := tlf.FakeID(1, tlf.Public)
282	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Public, id)
283	rmds, _ := newRMDS(t, config, h)
284	h.SetTlfID(tlf.NullID)
285
286	// Do this before setting tlfHandle to nil.
287	verifyMDForPublic(config, rmds, nil)
288
289	hUnresolved, err := tlfhandle.ParseHandle(
290		ctx, config.KBPKI(), tlfhandle.ConstIDGetter{ID: id}, nil,
291		"alice,bob@twitter", tlf.Public)
292	require.NoError(t, err)
293	hUnresolved.SetTlfID(tlf.NullID)
294
295	config.mockMdserv.EXPECT().GetForHandle(ctx,
296		hUnresolved.ToBareHandleOrBust(), kbfsmd.Merged, nil).Return(
297		id, rmds, nil).Times(2)
298
299	// First time should fail.
300	_, err = config.MDOps().GetIDForHandle(ctx, hUnresolved)
301	if _, ok := err.(tlfhandle.HandleMismatchError); !ok {
302		t.Errorf("Got unexpected error on bad handle check test: %v", err)
303	}
304
305	daemon := config.KeybaseService().(*KeybaseDaemonLocal)
306	daemon.AddNewAssertionForTestOrBust("bob", "bob@twitter")
307
308	// Second time should succeed.
309	if _, err := config.MDOps().GetIDForHandle(ctx, hUnresolved); err != nil {
310		t.Errorf("Got error on get: %v", err)
311	}
312}
313
314func testMDOpsGetIDForUnresolvedMdHandlePublicSuccess(
315	t *testing.T, ver kbfsmd.MetadataVer) {
316	mockCtrl, config, ctx := mdOpsInit(t, ver)
317	defer mdOpsShutdown(mockCtrl, config)
318
319	id := tlf.FakeID(1, tlf.Public)
320	mdHandle1, err := tlfhandle.ParseHandle(
321		ctx, config.KBPKI(), tlfhandle.ConstIDGetter{ID: id}, nil,
322		"alice,dave@twitter", tlf.Public)
323	require.NoError(t, err)
324	mdHandle1.SetTlfID(tlf.NullID)
325
326	mdHandle2, err := tlfhandle.ParseHandle(
327		ctx, config.KBPKI(), tlfhandle.ConstIDGetter{ID: id}, nil,
328		"alice,bob,charlie", tlf.Public)
329	require.NoError(t, err)
330	mdHandle2.SetTlfID(tlf.NullID)
331
332	mdHandle3, err := tlfhandle.ParseHandle(
333		ctx, config.KBPKI(), tlfhandle.ConstIDGetter{ID: id}, nil,
334		"alice,bob@twitter,charlie@twitter", tlf.Public)
335	require.NoError(t, err)
336	mdHandle3.SetTlfID(tlf.NullID)
337
338	rmds1, _ := newRMDS(t, config, mdHandle1)
339
340	rmds2, _ := newRMDS(t, config, mdHandle2)
341
342	rmds3, _ := newRMDS(t, config, mdHandle3)
343
344	// Do this before setting tlfHandles to nil.
345	verifyMDForPublic(config, rmds2, nil)
346	verifyMDForPublic(config, rmds3, nil)
347
348	h, err := tlfhandle.ParseHandle(
349		ctx, config.KBPKI(), tlfhandle.ConstIDGetter{ID: id}, nil,
350		"alice,bob,charlie@twitter", tlf.Public)
351	require.NoError(t, err)
352	h.SetTlfID(tlf.NullID)
353
354	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
355		kbfsmd.Merged, nil).Return(id, rmds1, nil)
356
357	// First time should fail.
358	_, err = config.MDOps().GetIDForHandle(ctx, h)
359	if _, ok := err.(tlfhandle.HandleMismatchError); !ok {
360		t.Errorf("Got unexpected error on bad handle check test: %v", err)
361	}
362
363	daemon := config.KeybaseService().(*KeybaseDaemonLocal)
364	daemon.AddNewAssertionForTestOrBust("bob", "bob@twitter")
365	daemon.AddNewAssertionForTestOrBust("charlie", "charlie@twitter")
366
367	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
368		kbfsmd.Merged, nil).Return(id, rmds2, nil)
369
370	// Second time should succeed.
371	if _, err := config.MDOps().GetIDForHandle(ctx, h); err != nil {
372		t.Errorf("Got error on get: %v", err)
373	}
374
375	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
376		kbfsmd.Merged, nil).Return(id, rmds3, nil)
377
378	if _, err := config.MDOps().GetIDForHandle(ctx, h); err != nil {
379		t.Errorf("Got error on get: %v", err)
380	}
381}
382
383func testMDOpsGetIDForUnresolvedHandlePublicFailure(
384	t *testing.T, ver kbfsmd.MetadataVer) {
385	mockCtrl, config, ctx := mdOpsInit(t, ver)
386	defer mdOpsShutdown(mockCtrl, config)
387
388	id := tlf.FakeID(1, tlf.Public)
389	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Public, id)
390	rmds, _ := newRMDS(t, config, h)
391
392	hUnresolved, err := tlfhandle.ParseHandle(
393		ctx, config.KBPKI(), tlfhandle.ConstIDGetter{ID: id}, nil,
394		"alice,bob@github,bob@twitter", tlf.Public)
395	require.NoError(t, err)
396	hUnresolved.SetTlfID(tlf.NullID)
397
398	daemon := config.KeybaseService().(*KeybaseDaemonLocal)
399	daemon.AddNewAssertionForTestOrBust("bob", "bob@twitter")
400
401	config.mockMdserv.EXPECT().GetForHandle(ctx,
402		hUnresolved.ToBareHandleOrBust(), kbfsmd.Merged, nil).Return(
403		id, rmds, nil)
404
405	// Should still fail.
406	_, err = config.MDOps().GetIDForHandle(ctx, hUnresolved)
407	if _, ok := err.(tlfhandle.HandleMismatchError); !ok {
408		t.Errorf("Got unexpected error on bad handle check test: %v", err)
409	}
410}
411
412func testMDOpsGetIDForHandlePublicFailFindKey(
413	t *testing.T, ver kbfsmd.MetadataVer) {
414	mockCtrl, config, ctx := mdOpsInit(t, ver)
415	defer mdOpsShutdown(mockCtrl, config)
416
417	id := tlf.FakeID(1, tlf.Public)
418	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Public, id)
419	rmds, _ := newRMDS(t, config, h)
420	h.SetTlfID(tlf.NullID)
421
422	// Do this before setting tlfHandle to nil.
423	verifyMDForPublic(config, rmds, VerifyingKeyNotFoundError{})
424
425	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
426		kbfsmd.Merged, nil).Return(id, rmds, nil)
427
428	_, err := config.MDOps().GetIDForHandle(ctx, h)
429	if _, ok := err.(UnverifiableTlfUpdateError); !ok {
430		t.Errorf("Got unexpected error on get: %v", err)
431	}
432}
433
434func testMDOpsGetIDForHandlePublicFailVerify(
435	t *testing.T, ver kbfsmd.MetadataVer) {
436	mockCtrl, config, ctx := mdOpsInit(t, ver)
437	defer mdOpsShutdown(mockCtrl, config)
438
439	id := tlf.FakeID(1, tlf.Public)
440	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Public, id)
441	rmds, _ := newRMDS(t, config, h)
442	h.SetTlfID(tlf.NullID)
443
444	// Change something in rmds that affects the computed MdID,
445	// which will then cause an MDMismatchError.
446	rmds.MD.(kbfsmd.MutableRootMetadata).SetRefBytes(100)
447	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
448		kbfsmd.Merged, nil).Return(id, rmds, nil)
449
450	_, err := config.MDOps().GetIDForHandle(ctx, h)
451	require.IsType(t, MDMismatchError{}, err)
452}
453
454func testMDOpsGetIDForHandleFailGet(t *testing.T, ver kbfsmd.MetadataVer) {
455	mockCtrl, config, ctx := mdOpsInit(t, ver)
456	defer mdOpsShutdown(mockCtrl, config)
457
458	id := tlf.FakeID(1, tlf.Private)
459	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
460	h.SetTlfID(tlf.NullID)
461
462	err := errors.New("Fake fail")
463
464	// only the get happens, no verify needed with a blank sig
465	config.mockMdserv.EXPECT().GetForHandle(ctx, h.ToBareHandleOrBust(),
466		kbfsmd.Merged, nil).Return(tlf.NullID, nil, err)
467
468	if _, err2 := config.MDOps().GetIDForHandle(ctx, h); err2 != err {
469		t.Errorf("Got bad error on get: %v", err2)
470	}
471}
472
473func testMDOpsGetIDForHandleFailHandleCheck(
474	t *testing.T, ver kbfsmd.MetadataVer) {
475	mockCtrl, config, ctx := mdOpsInit(t, ver)
476	defer mdOpsShutdown(mockCtrl, config)
477
478	id := tlf.FakeID(1, tlf.Private)
479	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
480	rmds, extra := newRMDS(t, config, h)
481	h.SetTlfID(tlf.NullID)
482
483	// Make a different handle.
484	otherH := parseTlfHandleOrBust(t, config, "alice", tlf.Private, id)
485	otherH.SetTlfID(tlf.NullID)
486	config.mockMdserv.EXPECT().GetForHandle(ctx, otherH.ToBareHandleOrBust(),
487		kbfsmd.Merged, nil).Return(id, rmds, nil)
488	expectGetKeyBundles(ctx, config, extra)
489
490	_, err := config.MDOps().GetIDForHandle(ctx, otherH)
491	if _, ok := err.(tlfhandle.HandleMismatchError); !ok {
492		t.Errorf("Got unexpected error on bad handle check test: %v", err)
493	}
494}
495
496func testMDOpsGetSuccess(t *testing.T, ver kbfsmd.MetadataVer) {
497	mockCtrl, config, ctx := mdOpsInit(t, ver)
498	defer mdOpsShutdown(mockCtrl, config)
499
500	id := tlf.FakeID(1, tlf.Private)
501	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
502	rmds, extra := newRMDS(t, config, h)
503
504	// Do this before setting tlfHandle to nil.
505	verifyMDForPrivate(config, rmds)
506
507	config.mockMdserv.EXPECT().GetForTLF(ctx, rmds.MD.TlfID(), kbfsmd.NullBranchID,
508		kbfsmd.Merged, nil).Return(rmds, nil)
509	expectGetKeyBundles(ctx, config, extra)
510
511	// Do this first, since rmds is consumed.
512	expectedMD := rmds.MD
513	rmd2, err := config.MDOps().GetForTLF(ctx, rmds.MD.TlfID(), nil)
514	require.NoError(t, err)
515	require.Equal(t, expectedMD, rmd2.bareMd)
516}
517
518func testMDOpsGetBlankSigFailure(t *testing.T, ver kbfsmd.MetadataVer) {
519	mockCtrl, config, ctx := mdOpsInit(t, ver)
520	defer mdOpsShutdown(mockCtrl, config)
521
522	id := tlf.FakeID(1, tlf.Private)
523	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
524	rmds, extra := newRMDS(t, config, h)
525	rmds.SigInfo = kbfscrypto.SignatureInfo{}
526
527	verifyMDForPrivate(config, rmds)
528	config.mockMdserv.EXPECT().GetForTLF(ctx, rmds.MD.TlfID(), kbfsmd.NullBranchID,
529		kbfsmd.Merged, nil).Return(rmds, nil)
530	expectGetKeyBundles(ctx, config, extra)
531
532	if _, err := config.MDOps().GetForTLF(ctx, rmds.MD.TlfID(), nil); err == nil {
533		t.Error("Got no error on get")
534	}
535}
536
537func testMDOpsGetFailGet(t *testing.T, ver kbfsmd.MetadataVer) {
538	mockCtrl, config, ctx := mdOpsInit(t, ver)
539	defer mdOpsShutdown(mockCtrl, config)
540
541	id := tlf.FakeID(1, tlf.Public)
542	err := errors.New("Fake fail")
543
544	// only the get happens, no verify needed with a blank sig
545	config.mockMdserv.EXPECT().GetForTLF(ctx, id, kbfsmd.NullBranchID,
546		kbfsmd.Merged, nil).Return(nil, err)
547
548	if _, err2 := config.MDOps().GetForTLF(ctx, id, nil); err2 != err {
549		t.Errorf("Got bad error on get: %v", err2)
550	}
551}
552
553func testMDOpsGetFailIDCheck(t *testing.T, ver kbfsmd.MetadataVer) {
554	mockCtrl, config, ctx := mdOpsInit(t, ver)
555	defer mdOpsShutdown(mockCtrl, config)
556
557	id := tlf.FakeID(1, tlf.Private)
558	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
559	rmds, extra := newRMDS(t, config, h)
560
561	id2 := tlf.FakeID(2, tlf.Public)
562
563	config.mockMdserv.EXPECT().GetForTLF(ctx, id2, kbfsmd.NullBranchID,
564		kbfsmd.Merged, nil).Return(rmds, nil)
565	expectGetKeyBundles(ctx, config, extra)
566
567	if _, err := config.MDOps().GetForTLF(ctx, id2, nil); err == nil {
568		t.Errorf("Got no error on bad id check test")
569	}
570}
571
572func makeRMDSRange(t *testing.T, config Config,
573	start kbfsmd.Revision, count int, prevID kbfsmd.ID) (
574	rmdses []*RootMetadataSigned, extras []kbfsmd.ExtraMetadata) {
575	id := tlf.FakeID(1, tlf.Private)
576	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
577	for i := 0; i < count; i++ {
578		rmd, err := makeInitialRootMetadata(config.MetadataVersion(), id, h)
579		if err != nil {
580			t.Fatal(err)
581		}
582
583		addFakeRMDData(t, config.Codec(), rmd, h)
584		rmd.SetPrevRoot(prevID)
585		rmd.SetRevision(start + kbfsmd.Revision(i))
586
587		ctx := context.Background()
588
589		// Encode and sign writer metadata.
590		err = rmd.bareMd.SignWriterMetadataInternally(ctx, config.Codec(), config.Crypto())
591		require.NoError(t, err)
592
593		rmds, err := SignBareRootMetadata(
594			ctx, config.Codec(), config.Crypto(), config.Crypto(),
595			rmd.bareMd, time.Now())
596		require.NoError(t, err)
597		currID, err := kbfsmd.MakeID(config.Codec(), rmds.MD)
598		require.NoError(t, err)
599		prevID = currID
600		rmdses = append(rmdses, rmds)
601		extras = append(extras, rmd.extra)
602	}
603	return rmdses, extras
604}
605
606type keyBundleMDServer struct {
607	MDServer
608	nextHead     *RootMetadataSigned
609	nextGetRange []*RootMetadataSigned
610
611	nextMerkleRoot      *kbfsmd.MerkleRoot
612	nextMerkleNodes     [][]byte
613	nextMerkleRootSeqno keybase1.Seqno
614
615	lock sync.RWMutex
616	wkbs map[kbfsmd.TLFWriterKeyBundleID]kbfsmd.TLFWriterKeyBundleV3
617	rkbs map[kbfsmd.TLFReaderKeyBundleID]kbfsmd.TLFReaderKeyBundleV3
618}
619
620func makeKeyBundleMDServer(mdServer MDServer) *keyBundleMDServer {
621	return &keyBundleMDServer{
622		MDServer: mdServer,
623		wkbs:     make(map[kbfsmd.TLFWriterKeyBundleID]kbfsmd.TLFWriterKeyBundleV3),
624		rkbs:     make(map[kbfsmd.TLFReaderKeyBundleID]kbfsmd.TLFReaderKeyBundleV3),
625	}
626}
627
628func (mds *keyBundleMDServer) putWKB(
629	id kbfsmd.TLFWriterKeyBundleID, wkb kbfsmd.TLFWriterKeyBundleV3) {
630	mds.lock.Lock()
631	defer mds.lock.Unlock()
632	mds.wkbs[id] = wkb
633}
634
635func (mds *keyBundleMDServer) putRKB(
636	id kbfsmd.TLFReaderKeyBundleID, rkb kbfsmd.TLFReaderKeyBundleV3) {
637	mds.lock.Lock()
638	defer mds.lock.Unlock()
639	mds.rkbs[id] = rkb
640}
641
642func (mds *keyBundleMDServer) processRMDSes(
643	rmds *RootMetadataSigned, extra kbfsmd.ExtraMetadata) {
644	if extraV3, ok := extra.(*kbfsmd.ExtraMetadataV3); ok {
645		mds.putWKB(rmds.MD.GetTLFWriterKeyBundleID(), extraV3.GetWriterKeyBundle())
646		mds.putRKB(rmds.MD.GetTLFReaderKeyBundleID(), extraV3.GetReaderKeyBundle())
647	}
648}
649
650func (mds *keyBundleMDServer) GetForTLF(ctx context.Context, id tlf.ID,
651	bid kbfsmd.BranchID, mStatus kbfsmd.MergeStatus, _ *keybase1.LockID) (
652	*RootMetadataSigned, error) {
653	rmd := mds.nextHead
654	mds.nextHead = nil
655	return rmd, nil
656}
657
658func (mds *keyBundleMDServer) GetRange(ctx context.Context, id tlf.ID,
659	bid kbfsmd.BranchID, mStatus kbfsmd.MergeStatus, start, stop kbfsmd.Revision,
660	_ *keybase1.LockID) ([]*RootMetadataSigned, error) {
661	rmdses := mds.nextGetRange
662	mds.nextGetRange = nil
663	return rmdses, nil
664}
665
666func (mds *keyBundleMDServer) GetKeyBundles(ctx context.Context, tlfID tlf.ID,
667	wkbID kbfsmd.TLFWriterKeyBundleID, rkbID kbfsmd.TLFReaderKeyBundleID) (
668	*kbfsmd.TLFWriterKeyBundleV3, *kbfsmd.TLFReaderKeyBundleV3, error) {
669	mds.lock.RLock()
670	defer mds.lock.RUnlock()
671	wkb := mds.wkbs[wkbID]
672	rkb := mds.rkbs[rkbID]
673	return &wkb, &rkb, nil
674}
675
676func (mds *keyBundleMDServer) FindNextMD(
677	ctx context.Context, tlfID tlf.ID, rootSeqno keybase1.Seqno) (
678	nextKbfsRoot *kbfsmd.MerkleRoot, nextMerkleNodes [][]byte,
679	nextRootSeqno keybase1.Seqno, err error) {
680	nextKbfsRoot = mds.nextMerkleRoot
681	nextMerkleNodes = mds.nextMerkleNodes
682	nextRootSeqno = mds.nextMerkleRootSeqno
683
684	mds.nextMerkleRoot = nil
685	mds.nextMerkleNodes = nil
686	mds.nextMerkleRootSeqno = 0
687	return nextKbfsRoot, nextMerkleNodes, nextRootSeqno, nil
688}
689
690func testMDOpsGetRangeSuccessHelper(
691	t *testing.T, ver kbfsmd.MetadataVer, fromStart bool) {
692	mockCtrl, config, ctx := mdOpsInit(t, ver)
693	defer mdOpsShutdown(mockCtrl, config)
694
695	rmdses, extras := makeRMDSRange(t, config, 100, 5, kbfsmd.FakeID(1))
696
697	start := kbfsmd.Revision(100)
698	stop := start + kbfsmd.Revision(len(rmdses))
699	if fromStart {
700		start = 0
701	}
702
703	for _, rmds := range rmdses {
704		verifyMDForPrivate(config, rmds)
705	}
706
707	mdServer := makeKeyBundleMDServer(config.MDServer())
708	config.SetMDServer(mdServer)
709
710	mdServer.nextGetRange = rmdses
711	for i, e := range extras {
712		mdServer.processRMDSes(rmdses[i], e)
713	}
714
715	// Do this first since rmdses is consumed.
716	expectedMDs := make([]kbfsmd.RootMetadata, len(rmdses))
717	for i, rmds := range rmdses {
718		expectedMDs[i] = rmds.MD
719	}
720	rmds, err := config.MDOps().GetRange(ctx, rmdses[0].MD.TlfID(), start, stop, nil)
721	require.NoError(t, err)
722	require.Equal(t, len(rmdses), len(rmds))
723	for i := 0; i < len(rmdses); i++ {
724		require.Equal(t, expectedMDs[i], rmds[i].bareMd)
725	}
726}
727
728func testMDOpsGetRangeSuccess(t *testing.T, ver kbfsmd.MetadataVer) {
729	testMDOpsGetRangeSuccessHelper(t, ver, false)
730}
731
732func testMDOpsGetRangeFromStartSuccess(t *testing.T, ver kbfsmd.MetadataVer) {
733	testMDOpsGetRangeSuccessHelper(t, ver, true)
734}
735
736func testMDOpsGetRangeFailBadPrevRoot(t *testing.T, ver kbfsmd.MetadataVer) {
737	mockCtrl, config, ctx := mdOpsInit(t, ver)
738	defer mdOpsShutdown(mockCtrl, config)
739
740	rmdses, extras := makeRMDSRange(t, config, 100, 5, kbfsmd.FakeID(1))
741
742	rmdses[2].MD.(kbfsmd.MutableRootMetadata).SetPrevRoot(kbfsmd.FakeID(1))
743
744	start := kbfsmd.Revision(100)
745	stop := start + kbfsmd.Revision(len(rmdses))
746
747	// Verification is parallelized, so we have to expect at most one
748	// verification for each rmds.
749	for _, rmds := range rmdses {
750		verifyMDForPrivateHelper(config, rmds, 0, 1, false)
751	}
752
753	mdServer := makeKeyBundleMDServer(config.MDServer())
754	config.SetMDServer(mdServer)
755
756	mdServer.nextGetRange = rmdses
757	for i, e := range extras {
758		mdServer.processRMDSes(rmdses[i], e)
759	}
760
761	_, err := config.MDOps().GetRange(ctx, rmdses[0].MD.TlfID(), start, stop, nil)
762	require.IsType(t, MDMismatchError{}, err)
763}
764
765type fakeMDServerPut struct {
766	MDServer
767
768	lastRmdsLock sync.Mutex
769	lastRmds     *RootMetadataSigned
770}
771
772func (s *fakeMDServerPut) Put(ctx context.Context, rmds *RootMetadataSigned,
773	_ kbfsmd.ExtraMetadata, _ *keybase1.LockContext, _ keybase1.MDPriority) error {
774	s.lastRmdsLock.Lock()
775	defer s.lastRmdsLock.Unlock()
776	s.lastRmds = rmds
777	return nil
778}
779
780func (s *fakeMDServerPut) getLastRmds() *RootMetadataSigned {
781	s.lastRmdsLock.Lock()
782	defer s.lastRmdsLock.Unlock()
783	return s.lastRmds
784}
785
786func (s *fakeMDServerPut) Shutdown() {}
787
788func validatePutPublicRMDS(
789	ctx context.Context, t *testing.T, ver kbfsmd.MetadataVer, config Config,
790	inputRmd kbfsmd.RootMetadata, rmds *RootMetadataSigned) {
791	// TODO: Handle private RMDS, too.
792
793	// Verify LastModifying* fields.
794	session, err := config.KBPKI().GetCurrentSession(ctx)
795	require.NoError(t, err)
796	require.Equal(t, session.UID, rmds.MD.LastModifyingWriter())
797	require.Equal(t, session.UID, rmds.MD.GetLastModifyingUser())
798
799	// Verify signature of WriterMetadata.
800	buf, err := rmds.MD.GetSerializedWriterMetadata(config.Codec())
801	require.NoError(t, err)
802	err = kbfscrypto.Verify(buf, rmds.GetWriterMetadataSigInfo())
803	require.NoError(t, err)
804
805	// Verify encoded PrivateMetadata.
806	var data PrivateMetadata
807	err = config.Codec().Decode(rmds.MD.GetSerializedPrivateMetadata(), &data)
808	require.NoError(t, err)
809
810	// Verify signature of RootMetadata.
811	buf, err = config.Codec().Encode(rmds.MD)
812	require.NoError(t, err)
813	err = kbfscrypto.Verify(buf, rmds.SigInfo)
814	require.NoError(t, err)
815
816	expectedRmd, err := inputRmd.DeepCopy(config.Codec())
817	require.NoError(t, err)
818
819	// Overwrite written fields.
820	expectedRmd.SetLastModifyingWriter(rmds.MD.LastModifyingWriter())
821	expectedRmd.SetLastModifyingUser(rmds.MD.GetLastModifyingUser())
822	if ver < kbfsmd.SegregatedKeyBundlesVer {
823		expectedRmd.(*kbfsmd.RootMetadataV2).WriterMetadataSigInfo =
824			rmds.MD.(*kbfsmd.RootMetadataV2).WriterMetadataSigInfo
825	}
826	expectedRmd.SetSerializedPrivateMetadata(rmds.MD.GetSerializedPrivateMetadata())
827
828	require.Equal(t, expectedRmd, rmds.MD)
829}
830
831func testMDOpsPutPublicSuccess(t *testing.T, ver kbfsmd.MetadataVer) {
832	ctx := context.Background()
833	config := MakeTestConfigOrBust(t, "alice", "bob")
834	config.SetMetadataVersion(ver)
835	defer CheckConfigAndShutdown(ctx, t, config)
836
837	config.MDServer().Shutdown()
838	var mdServer fakeMDServerPut
839	config.SetMDServer(&mdServer)
840
841	id := tlf.FakeID(1, tlf.Public)
842	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Public, id)
843
844	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), id, h)
845	require.NoError(t, err)
846	rmd.data = makeFakePrivateMetadataFuture(t).toCurrent()
847	rmd.tlfHandle = h
848
849	session, err := config.KBPKI().GetCurrentSession(ctx)
850	require.NoError(t, err)
851	_, err = config.MDOps().Put(
852		ctx, rmd, session.VerifyingKey, nil, keybase1.MDPriorityNormal, nil)
853	require.NoError(t, err)
854
855	rmds := mdServer.getLastRmds()
856	validatePutPublicRMDS(ctx, t, ver, config, rmd.bareMd, rmds)
857}
858
859func testMDOpsPutPrivateSuccess(t *testing.T, ver kbfsmd.MetadataVer) {
860	mockCtrl, config, ctx := mdOpsInit(t, ver)
861	defer mdOpsShutdown(mockCtrl, config)
862
863	config.SetCodec(kbfscodec.NewMsgpack())
864
865	id := tlf.FakeID(1, tlf.Private)
866	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
867	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), id, h)
868	require.NoError(t, err)
869	addFakeRMDData(t, config.Codec(), rmd, h)
870
871	putMDForPrivate(config, rmd)
872
873	key := kbfscrypto.MakeFakeVerifyingKeyOrBust("test key")
874	if _, err := config.MDOps().Put(
875		ctx, rmd, key, nil, keybase1.MDPriorityNormal, nil); err != nil {
876		t.Errorf("Got error on put: %v", err)
877	}
878}
879
880type failEncodeCodec struct {
881	kbfscodec.Codec
882	err error
883}
884
885func (c failEncodeCodec) Encode(obj interface{}) ([]byte, error) {
886	return nil, c.err
887}
888
889func testMDOpsPutFailEncode(t *testing.T, ver kbfsmd.MetadataVer) {
890	mockCtrl, config, ctx := mdOpsInit(t, ver)
891	defer mdOpsShutdown(mockCtrl, config)
892
893	id := tlf.FakeID(1, tlf.Private)
894	h := parseTlfHandleOrBust(t, config, "alice,bob", tlf.Private, id)
895	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), id, h)
896	require.NoError(t, err)
897
898	expectGetTLFCryptKeyForEncryption(config, rmd)
899	config.mockCrypto.EXPECT().EncryptPrivateMetadata(
900		rmd.data, kbfscrypto.TLFCryptKey{}).Return(
901		kbfscrypto.EncryptedPrivateMetadata{}, nil)
902	config.mockBsplit.EXPECT().ShouldEmbedData(gomock.Any()).Return(true)
903
904	session, err := config.KBPKI().GetCurrentSession(ctx)
905	require.NoError(t, err)
906
907	err = errors.New("Fake fail")
908	config.SetCodec(failEncodeCodec{config.Codec(), err})
909
910	if _, err2 := config.MDOps().Put(
911		ctx, rmd, session.VerifyingKey, nil, keybase1.MDPriorityNormal,
912		nil); err2 != err {
913		t.Errorf("Got bad error on put: %v", err2)
914	}
915}
916
917func testMDOpsGetRangeFailFinal(t *testing.T, ver kbfsmd.MetadataVer) {
918	mockCtrl, config, ctx := mdOpsInit(t, ver)
919	defer mdOpsShutdown(mockCtrl, config)
920
921	rmdses, extras := makeRMDSRange(t, config, 100, 5, kbfsmd.FakeID(1))
922	rmdses[2].MD.(kbfsmd.MutableRootMetadata).SetFinalBit()
923	rmdses[2].MD.(kbfsmd.MutableRootMetadata).SetPrevRoot(rmdses[1].MD.GetPrevRoot())
924
925	start := kbfsmd.Revision(100)
926	stop := start + kbfsmd.Revision(len(rmdses))
927
928	// Verification is parallelized, so we have to expect at most one
929	// verification for each rmds.
930	for _, rmds := range rmdses {
931		verifyMDForPrivateHelper(config, rmds, 0, 1, false)
932	}
933
934	mdServer := makeKeyBundleMDServer(config.MDServer())
935	config.SetMDServer(mdServer)
936
937	mdServer.nextGetRange = rmdses
938	for i, e := range extras {
939		mdServer.processRMDSes(rmdses[i], e)
940	}
941	_, err := config.MDOps().GetRange(ctx, rmdses[0].MD.TlfID(), start, stop, nil)
942	require.IsType(t, MDMismatchError{}, err)
943}
944
945func testMDOpsGetFinalSuccess(t *testing.T, ver kbfsmd.MetadataVer) {
946	mockCtrl, config, ctx := mdOpsInit(t, ver)
947	defer mdOpsShutdown(mockCtrl, config)
948
949	rmdses, extras := makeRMDSRange(
950		t, config, kbfsmd.RevisionInitial, 5, kbfsmd.ID{})
951
952	now := time.Now()
953	finalizedInfo, err := tlf.NewHandleExtension(
954		tlf.HandleExtensionFinalized, 1, kbname.NormalizedUsername("<unknown>"),
955		now)
956	require.NoError(t, err)
957	finalRMDS, err := rmdses[len(rmdses)-1].MakeFinalCopy(
958		config.Codec(), now, finalizedInfo)
959	require.NoError(t, err)
960	verifyMDForPrivateHelper(config, finalRMDS, 1, 1, false)
961
962	config.SetMDCache(NewMDCacheStandard(10))
963	mdServer := makeKeyBundleMDServer(config.MDServer())
964	config.SetMDServer(mdServer)
965
966	// A finalized head will force MDOps to fetch the preceding MD, in
967	// order to check the authenticity of the copied writer MD.
968	// However the key that signed that MD could be a pre-reset key,
969	// so we need to make calls to get unverified keys.
970	mdServer.nextHead = finalRMDS
971	lastRMDRange := rmdses[len(rmdses)-1:]
972	mdServer.nextGetRange = lastRMDRange
973	for i, e := range extras {
974		mdServer.processRMDSes(rmdses[i], e)
975	}
976
977	verifyMDForPrivateHelper(config, lastRMDRange[0], 1, 1, true)
978
979	_, err = config.MDOps().GetForTLF(ctx, finalRMDS.MD.TlfID(), nil)
980	require.NoError(t, err)
981}
982
983func makeRealInitialRMDForTesting(
984	ctx context.Context, t *testing.T, config Config, h *tlfhandle.Handle,
985	id tlf.ID) (*RootMetadata, *RootMetadataSigned) {
986	rmd, err := makeInitialRootMetadata(config.MetadataVersion(), id, h)
987	require.NoError(t, err)
988	if h.TypeForKeying() == tlf.TeamKeying {
989		rmd.bareMd.SetLatestKeyGenerationForTeamTLF(1)
990	} else {
991		rekeyDone, _, err := config.KeyManager().Rekey(ctx, rmd, false)
992		require.NoError(t, err)
993		require.True(t, rekeyDone)
994	}
995	_, _, _, err = ResetRootBlock(ctx, config, rmd)
996	require.NoError(t, err)
997	session, err := config.KBPKI().GetCurrentSession(ctx)
998	require.NoError(t, err)
999	err = encryptMDPrivateData(
1000		ctx, config.Codec(), config.Crypto(),
1001		config.Crypto(), config.KeyManager(), session.UID, rmd)
1002	require.NoError(t, err)
1003	err = rmd.bareMd.SignWriterMetadataInternally(
1004		ctx, config.Codec(), config.Crypto())
1005	require.NoError(t, err)
1006	now := config.Clock().Now()
1007	rmds, err := SignBareRootMetadata(
1008		ctx, config.Codec(), config.Crypto(), config.Crypto(), rmd.bareMd, now)
1009	require.NoError(t, err)
1010	return rmd, rmds
1011}
1012
1013func makeSuccessorRMDForTesting(
1014	ctx context.Context, t *testing.T, config Config, currRMD *RootMetadata,
1015	deviceToRevoke int) (
1016	*RootMetadata, *RootMetadataSigned) {
1017	mdID, err := kbfsmd.MakeID(config.Codec(), currRMD.bareMd)
1018	require.NoError(t, err)
1019
1020	rmd, err := currRMD.MakeSuccessor(
1021		ctx, config.MetadataVersion(), config.Codec(), config.KeyManager(),
1022		config.KBPKI(), config.KBPKI(), config, mdID, true)
1023	require.NoError(t, err)
1024
1025	session, err := config.KBPKI().GetCurrentSession(ctx)
1026	require.NoError(t, err)
1027	if deviceToRevoke > 0 {
1028		RevokeDeviceForLocalUserOrBust(t, config, session.UID, deviceToRevoke)
1029		rekeyDone, _, err := config.KeyManager().Rekey(ctx, rmd, false)
1030		require.NoError(t, err)
1031		require.True(t, rekeyDone)
1032	}
1033	_, _, _, err = ResetRootBlock(ctx, config, rmd)
1034	require.NoError(t, err)
1035	err = encryptMDPrivateData(
1036		ctx, config.Codec(), config.Crypto(),
1037		config.Crypto(), config.KeyManager(), session.UID, rmd)
1038	require.NoError(t, err)
1039
1040	err = rmd.bareMd.SignWriterMetadataInternally(
1041		ctx, config.Codec(), config.Crypto())
1042	require.NoError(t, err)
1043	now := config.Clock().Now()
1044	rmds, err := SignBareRootMetadata(
1045		ctx, config.Codec(), config.Crypto(), config.Crypto(),
1046		rmd.bareMd, now)
1047	require.NoError(t, err)
1048	return rmd, rmds
1049}
1050
1051func makeEncryptedMerkleLeafForTesting(
1052	t *testing.T, config Config, rmd *RootMetadata) (
1053	root *kbfsmd.MerkleRoot, rootNodeBytes []byte,
1054	mLeaf kbfsmd.MerkleLeaf, leafBytes []byte) {
1055	ePubKey, ePrivKey, err := kbfscrypto.MakeRandomTLFEphemeralKeys()
1056	require.NoError(t, err)
1057	var nonce [24]byte
1058	_, err = rand.Read(nonce[:])
1059	require.NoError(t, err)
1060	now := config.Clock().Now().Unix()
1061	root = &kbfsmd.MerkleRoot{
1062		EPubKey:   &ePubKey,
1063		Nonce:     &nonce,
1064		Timestamp: now,
1065	}
1066
1067	mLeaf = kbfsmd.MerkleLeaf{
1068		Revision:  1,
1069		Timestamp: now,
1070	}
1071	var pubKey kbfscrypto.TLFPublicKey
1072	if rmd.TypeForKeying() == tlf.TeamKeying {
1073		crypto, ok := config.Crypto().(*CryptoLocal)
1074		require.True(t, ok)
1075		tid := rmd.GetTlfHandle().FirstResolvedWriter().AsTeamOrBust()
1076		pubKey, err = crypto.pubKeyForTeamKeyGeneration(
1077			tid, keybase1.PerTeamKeyGeneration(rmd.LatestKeyGeneration()))
1078		require.NoError(t, err)
1079	} else {
1080		pubKey, err = rmd.bareMd.GetCurrentTLFPublicKey(rmd.extra)
1081		require.NoError(t, err)
1082	}
1083	eLeaf, err := mLeaf.Encrypt(config.Codec(), pubKey, &nonce, ePrivKey)
1084	require.NoError(t, err)
1085	leafBytes, err = config.Codec().Encode(eLeaf)
1086	require.NoError(t, err)
1087
1088	rootNode := merkle.Node{
1089		Type: 2,
1090		Leafs: []merkle.KeyValuePair{{
1091			Key:   merkle.Hash(rmd.TlfID().Bytes()),
1092			Value: leafBytes,
1093		}},
1094	}
1095	rootNodeBytes, err = config.Codec().Encode(rootNode)
1096	require.NoError(t, err)
1097	hasher := merkle.SHA512Hasher{}
1098	root.Hash = hasher.Hash(rootNodeBytes)
1099
1100	return root, rootNodeBytes, mLeaf, leafBytes
1101}
1102
1103func testMDOpsDecryptMerkleLeafPrivate(t *testing.T, ver kbfsmd.MetadataVer) {
1104	var u1 kbname.NormalizedUsername = "u1"
1105	config, _, ctx, cancel := kbfsOpsConcurInit(t, u1)
1106	defer kbfsConcurTestShutdown(ctx, t, config, cancel)
1107	config.SetMetadataVersion(ver)
1108
1109	mdServer := makeKeyBundleMDServer(config.MDServer())
1110	config.SetMDServer(mdServer)
1111
1112	session, err := config.KBPKI().GetCurrentSession(ctx)
1113	require.NoError(t, err)
1114	var extraDevice int
1115	for i := 0; i < 4; i++ {
1116		extraDevice = AddDeviceForLocalUserOrBust(t, config, session.UID)
1117	}
1118
1119	t.Log("Making an initial RMD")
1120	id := tlf.FakeID(1, tlf.Private)
1121	h := parseTlfHandleOrBust(t, config, "u1", tlf.Private, id)
1122	rmd, rmds := makeRealInitialRMDForTesting(ctx, t, config, h, id)
1123
1124	t.Log("Making an encrypted Merkle leaf")
1125	root, _, mLeaf, leafBytes := makeEncryptedMerkleLeafForTesting(
1126		t, config, rmd)
1127
1128	mdServer.nextHead = rmds
1129	mdServer.processRMDSes(rmds, rmd.extra)
1130
1131	t.Log("Try to decrypt with the right key")
1132	mdOps := config.MDOps().(*MDOpsStandard)
1133	mLeaf2, err := mdOps.decryptMerkleLeaf(ctx, rmd.ReadOnly(), root, leafBytes)
1134	require.NoError(t, err)
1135	require.Equal(t, mLeaf.Revision, mLeaf2.Revision)
1136	require.Equal(t, mLeaf.Timestamp, mLeaf2.Timestamp)
1137
1138	// `rmds` gets destroyed by `MDOpsStandard.GetForTLF()`, so we
1139	// need to make another one.
1140	now := config.Clock().Now()
1141	rmds, err = SignBareRootMetadata(
1142		ctx, config.Codec(), config.Crypto(), config.Crypto(), rmd.bareMd, now)
1143	require.NoError(t, err)
1144	mdServer.nextHead = rmds
1145
1146	t.Log("Try to decrypt with the wrong key; should fail")
1147	_, privKeyWrong, _, err := config.Crypto().MakeRandomTLFKeys()
1148	require.NoError(t, err)
1149	privKey := rmd.data.TLFPrivateKey
1150	rmd.data.TLFPrivateKey = privKeyWrong
1151	_, err = mdOps.decryptMerkleLeaf(ctx, rmd.ReadOnly(), root, leafBytes)
1152	require.Error(t, err)
1153
1154	t.Log("Make some successors, every once in a while bumping the keygen")
1155	rmd.data.TLFPrivateKey = privKey
1156	allRMDs := []*RootMetadata{rmd}
1157	allRMDSs := []*RootMetadataSigned{rmds}
1158	for i := 2; i < 20; i++ {
1159		deviceToRevoke := -1
1160		if i%5 == 0 {
1161			deviceToRevoke = extraDevice
1162			extraDevice--
1163		}
1164
1165		rmd, rmds = makeSuccessorRMDForTesting(
1166			ctx, t, config, rmd, deviceToRevoke)
1167		allRMDs = append(allRMDs, rmd)
1168		allRMDSs = append(allRMDSs, rmds)
1169
1170		if i%5 == 0 {
1171			mdServer.processRMDSes(rmds, rmd.extra)
1172		}
1173	}
1174
1175	t.Log("Decrypt a leaf that's encrypted with the next keygen")
1176	leafRMD := allRMDs[6]
1177	root, _, mLeaf, leafBytes = makeEncryptedMerkleLeafForTesting(
1178		t, config, leafRMD)
1179	rmds, err = SignBareRootMetadata(
1180		ctx, config.Codec(), config.Crypto(), config.Crypto(),
1181		rmd.bareMd, now)
1182	require.NoError(t, err)
1183	mdServer.nextHead = rmds
1184	mdServer.nextGetRange = allRMDSs[1:10]
1185	mLeaf2, err = mdOps.decryptMerkleLeaf(
1186		ctx, allRMDs[0].ReadOnly(), root, leafBytes)
1187	require.NoError(t, err)
1188	require.Equal(t, mLeaf.Revision, mLeaf2.Revision)
1189	require.Equal(t, mLeaf.Timestamp, mLeaf2.Timestamp)
1190}
1191
1192func testMDOpsDecryptMerkleLeafTeam(t *testing.T, ver kbfsmd.MetadataVer) {
1193	if ver < kbfsmd.SegregatedKeyBundlesVer {
1194		t.Skip("Teams not supported")
1195	}
1196
1197	var u1 kbname.NormalizedUsername = "u1"
1198	config, _, ctx, cancel := kbfsOpsConcurInit(t, u1)
1199	defer kbfsConcurTestShutdown(ctx, t, config, cancel)
1200	config.SetMetadataVersion(ver)
1201
1202	session, err := config.KBPKI().GetCurrentSession(ctx)
1203	require.NoError(t, err)
1204
1205	t.Log("Making an initial RMD")
1206	id := tlf.FakeID(1, tlf.SingleTeam)
1207	teamInfos := AddEmptyTeamsForTestOrBust(t, config, "t1")
1208	AddTeamWriterForTestOrBust(t, config, teamInfos[0].TID, session.UID)
1209	h := parseTlfHandleOrBust(t, config, "t1", tlf.SingleTeam, id)
1210	rmd, _ := makeRealInitialRMDForTesting(ctx, t, config, h, id)
1211
1212	t.Log("Making an encrypted Merkle leaf")
1213	root, _, mLeaf, leafBytes := makeEncryptedMerkleLeafForTesting(
1214		t, config, rmd)
1215
1216	t.Log("Try to decrypt with the right key")
1217	mdOps := config.MDOps().(*MDOpsStandard)
1218	mLeaf2, err := mdOps.decryptMerkleLeaf(ctx, rmd.ReadOnly(), root, leafBytes)
1219	require.NoError(t, err)
1220	require.Equal(t, mLeaf.Revision, mLeaf2.Revision)
1221	require.Equal(t, mLeaf.Timestamp, mLeaf2.Timestamp)
1222
1223	// Error scenarios and multiple keygens are handled by the
1224	// service, and are not worth testing here.
1225}
1226
1227func testMDOpsVerifyRevokedDeviceWrite(t *testing.T, ver kbfsmd.MetadataVer) {
1228	var u1 kbname.NormalizedUsername = "u1"
1229	config, _, ctx, cancel := kbfsOpsConcurInit(t, u1)
1230	defer kbfsConcurTestShutdown(ctx, t, config, cancel)
1231	config.SetMetadataVersion(ver)
1232	clock := clocktest.NewTestClockNow()
1233	config.SetClock(clock)
1234
1235	session, err := config.KBPKI().GetCurrentSession(ctx)
1236	require.NoError(t, err)
1237	config2 := ConfigAsUser(config, u1)
1238	defer CheckConfigAndShutdown(ctx, t, config2)
1239	AddDeviceForLocalUserOrBust(t, config, session.UID)
1240	extraDevice := AddDeviceForLocalUserOrBust(t, config2, session.UID)
1241	SwitchDeviceForLocalUserOrBust(t, config2, extraDevice)
1242
1243	mdServer := makeKeyBundleMDServer(config.MDServer())
1244	config.SetMDServer(mdServer)
1245	config2.SetMDServer(mdServer)
1246
1247	t.Log("Initial MD written by the device we will revoke")
1248	id := tlf.FakeID(1, tlf.Private)
1249	h := parseTlfHandleOrBust(t, config, "u1", tlf.Private, id)
1250	rmd, rmds := makeRealInitialRMDForTesting(ctx, t, config2, h, id)
1251	mdServer.processRMDSes(rmds, rmd.extra)
1252
1253	t.Log("A few writes by a device that won't be revoked")
1254	allRMDs := []*RootMetadata{rmd}
1255	allRMDSs := []*RootMetadataSigned{rmds}
1256	for i := 2; i < 5; i++ {
1257		rmd, rmds = makeSuccessorRMDForTesting(ctx, t, config, rmd, -1)
1258		allRMDs = append(allRMDs, rmd)
1259		allRMDSs = append(allRMDSs, rmds)
1260	}
1261
1262	t.Log("A write after the revoke happens")
1263	rmd, rmds = makeSuccessorRMDForTesting(ctx, t, config, rmd, extraDevice)
1264	allRMDs = append(allRMDs, rmd)
1265	allRMDSs = append(allRMDSs, rmds)
1266	mdServer.processRMDSes(rmds, rmd.extra)
1267	mdServer.nextHead = rmds
1268	mdServer.nextGetRange = allRMDSs[1 : len(allRMDSs)-1]
1269
1270	t.Log("Make a merkle leaf using the new generation")
1271	clock.Add(1 * time.Second)
1272	root, rootNodeBytes, _, leafBytes := makeEncryptedMerkleLeafForTesting(
1273		t, config, rmd)
1274	mdServer.nextMerkleRoot = root
1275	mdServer.nextMerkleNodes = [][]byte{rootNodeBytes, leafBytes}
1276	mdServer.nextMerkleRootSeqno = 100
1277
1278	irmd := MakeImmutableRootMetadata(
1279		allRMDs[0], allRMDSs[0].SigInfo.VerifyingKey, allRMDs[1].PrevRoot(),
1280		time.Now(), false)
1281
1282	mdOps := config.MDOps().(*MDOpsStandard)
1283	cacheable, err := mdOps.verifyKey(
1284		ctx, allRMDSs[0], allRMDSs[0].MD.GetLastModifyingUser(),
1285		allRMDSs[0].SigInfo.VerifyingKey, irmd)
1286	require.NoError(t, err)
1287	require.True(t, cacheable)
1288
1289	t.Log("Make the server return no information, but within the max gap")
1290	SetGlobalMerkleRootForTestOrBust(
1291		t, config, keybase1.MerkleRootV2{}, clock.Now())
1292	clock.Add(1 * time.Minute)
1293	mdServer.nextMerkleRoot = nil
1294	mdServer.nextMerkleNodes = nil
1295	mdServer.nextMerkleRootSeqno = 0
1296	mdLocal, ok := mdServer.MDServer.(mdServerLocal)
1297	require.True(t, ok)
1298	mdLocal.setKbfsMerkleRoot(keybase1.MerkleTreeID_KBFS_PRIVATE, root)
1299	cacheable, err = mdOps.verifyKey(
1300		ctx, allRMDSs[0], allRMDSs[0].MD.GetLastModifyingUser(),
1301		allRMDSs[0].SigInfo.VerifyingKey, irmd)
1302	require.NoError(t, err)
1303	require.True(t, cacheable)
1304
1305	t.Log("Make the server return no information, but outside the max gap")
1306	config.MDCache().(*MDCacheStandard).nextMDLRU.Purge()
1307	clock.Add(maxAllowedMerkleGap) // already added one minute above
1308	_, err = mdOps.verifyKey(
1309		ctx, allRMDSs[0], allRMDSs[0].MD.GetLastModifyingUser(),
1310		allRMDSs[0].SigInfo.VerifyingKey, irmd)
1311	require.Error(t, err)
1312
1313	t.Log("Make the server return a root, but which is outside the max gap")
1314	config.MDCache().(*MDCacheStandard).nextMDLRU.Purge()
1315	root.Timestamp = clock.Now().Unix()
1316	mdServer.nextMerkleRoot = root
1317	mdServer.nextMerkleNodes = [][]byte{leafBytes}
1318	mdServer.nextMerkleRootSeqno = 100
1319	_, err = mdOps.verifyKey(
1320		ctx, allRMDSs[0], allRMDSs[0].MD.GetLastModifyingUser(),
1321		allRMDSs[0].SigInfo.VerifyingKey, irmd)
1322	require.Error(t, err)
1323}
1324
1325func testMDOpsVerifyRemovedUserWrite(t *testing.T, ver kbfsmd.MetadataVer) {
1326	if ver < kbfsmd.SegregatedKeyBundlesVer {
1327		t.Skip("Teams not supported")
1328	}
1329
1330	var u1, u2 kbname.NormalizedUsername = "u1", "u2"
1331	config, _, ctx, cancel := kbfsOpsConcurInit(t, u1, u2)
1332	defer kbfsConcurTestShutdown(ctx, t, config, cancel)
1333	config.SetMetadataVersion(ver)
1334
1335	session, err := config.KBPKI().GetCurrentSession(ctx)
1336	require.NoError(t, err)
1337
1338	config2 := ConfigAsUser(config, u2)
1339	defer CheckConfigAndShutdown(ctx, t, config2)
1340	session2, err := config2.KBPKI().GetCurrentSession(ctx)
1341	require.NoError(t, err)
1342
1343	mdServer := makeKeyBundleMDServer(config.MDServer())
1344	config.SetMDServer(mdServer)
1345	config2.SetMDServer(mdServer)
1346
1347	t.Log("Initial MD written by the user we will remove")
1348	id := tlf.FakeID(1, tlf.SingleTeam)
1349	teamInfos := AddEmptyTeamsForTestOrBust(t, config, "t1")
1350	AddEmptyTeamsForTestOrBust(t, config2, "t1")
1351	tid := teamInfos[0].TID
1352	AddTeamWriterForTestOrBust(t, config, tid, session.UID)
1353	AddTeamWriterForTestOrBust(t, config2, tid, session.UID)
1354	AddTeamWriterForTestOrBust(t, config, tid, session2.UID)
1355	AddTeamWriterForTestOrBust(t, config2, tid, session2.UID)
1356	h := parseTlfHandleOrBust(t, config, "t1", tlf.SingleTeam, id)
1357	rmd, rmds := makeRealInitialRMDForTesting(ctx, t, config, h, id)
1358	mdServer.processRMDSes(rmds, rmd.extra)
1359
1360	RemoveTeamWriterForTestOrBust(t, config, tid, session.UID)
1361	RemoveTeamWriterForTestOrBust(t, config2, tid, session.UID)
1362
1363	t.Log("A few writes by a user that won't be removed")
1364	allRMDSs := []*RootMetadataSigned{rmds}
1365	for i := 2; i < 5; i++ {
1366		rmd, rmds = makeSuccessorRMDForTesting(ctx, t, config2, rmd, -1)
1367		allRMDSs = append(allRMDSs, rmds)
1368	}
1369
1370	mdServer.processRMDSes(rmds, rmd.extra)
1371	mdServer.nextHead = rmds
1372	mdServer.nextGetRange = allRMDSs[1 : len(allRMDSs)-1]
1373
1374	t.Log("Make a merkle leaf")
1375	root, rootNodeBytes, _, leafBytes := makeEncryptedMerkleLeafForTesting(
1376		t, config, rmd)
1377	mdServer.nextMerkleRoot = root
1378	mdServer.nextMerkleNodes = [][]byte{rootNodeBytes, leafBytes}
1379	mdServer.nextMerkleRootSeqno = 100
1380
1381	mdOps := config.MDOps().(*MDOpsStandard)
1382	_, err = mdOps.processMetadata(ctx, h, allRMDSs[0], rmd.extra, nil)
1383	require.NoError(t, err)
1384
1385	t.Log("Try another write by the removed user and make sure it fails")
1386	rmd, rmds = makeSuccessorRMDForTesting(ctx, t, config, rmd, -1)
1387	mdServer.processRMDSes(rmds, rmd.extra)
1388	mdServer.nextHead = rmds
1389	mdServer.nextGetRange = nil
1390	mdServer.nextMerkleRoot = root
1391	mdServer.nextMerkleNodes = [][]byte{rootNodeBytes, leafBytes}
1392	mdServer.nextMerkleRootSeqno = 100
1393	_, err = mdOps.processMetadata(ctx, h, rmds, rmd.extra, nil)
1394	require.Error(t, err)
1395
1396}
1397
1398func TestMDOps(t *testing.T) {
1399	tests := []func(*testing.T, kbfsmd.MetadataVer){
1400		testMDOpsGetIDForHandlePublicSuccess,
1401		testMDOpsGetIDForHandlePrivateSuccess,
1402		testMDOpsGetIDForUnresolvedHandlePublicSuccess,
1403		testMDOpsGetIDForUnresolvedMdHandlePublicSuccess,
1404		testMDOpsGetIDForUnresolvedHandlePublicFailure,
1405		testMDOpsGetIDForHandlePublicFailFindKey,
1406		testMDOpsGetIDForHandlePublicFailVerify,
1407		testMDOpsGetIDForHandleFailGet,
1408		testMDOpsGetIDForHandleFailHandleCheck,
1409		testMDOpsGetSuccess,
1410		testMDOpsGetBlankSigFailure,
1411		testMDOpsGetFailGet,
1412		testMDOpsGetFailIDCheck,
1413		testMDOpsGetRangeSuccess,
1414		testMDOpsGetRangeFromStartSuccess,
1415		testMDOpsGetRangeFailBadPrevRoot,
1416		testMDOpsPutPublicSuccess,
1417		testMDOpsPutPrivateSuccess,
1418		testMDOpsPutFailEncode,
1419		testMDOpsGetRangeFailFinal,
1420		testMDOpsGetFinalSuccess,
1421		testMDOpsDecryptMerkleLeafPrivate,
1422		testMDOpsDecryptMerkleLeafTeam,
1423		testMDOpsVerifyRevokedDeviceWrite,
1424		testMDOpsVerifyRemovedUserWrite,
1425	}
1426	runTestsOverMetadataVers(t, "testMDOps", tests)
1427}
1428