github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libkbfs/md_ops.go (about)

     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  
     5  package libkbfs
     6  
     7  import (
     8  	"fmt"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/keybase/client/go/kbfs/data"
    13  	"github.com/keybase/client/go/kbfs/idutil"
    14  	"github.com/keybase/client/go/kbfs/kbfsblock"
    15  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    16  	"github.com/keybase/client/go/kbfs/kbfsmd"
    17  	"github.com/keybase/client/go/kbfs/tlf"
    18  	"github.com/keybase/client/go/kbfs/tlfhandle"
    19  	kbname "github.com/keybase/client/go/kbun"
    20  	"github.com/keybase/client/go/libkb"
    21  	"github.com/keybase/client/go/logger"
    22  	"github.com/keybase/client/go/protocol/keybase1"
    23  	"github.com/pkg/errors"
    24  	"golang.org/x/net/context"
    25  	"golang.org/x/sync/errgroup"
    26  )
    27  
    28  const (
    29  	// Update 2024-02-16: we decided to increase the merkle gap check to 4 days
    30  	// in case mdmerkle goes down, to give us more time to fix it.
    31  	maxAllowedMerkleGapServer = 4 * (time.Hour * 24)
    32  	maxAllowedMerkleGap       = maxAllowedMerkleGapServer + 15*time.Minute
    33  
    34  	// merkleGapEnforcementStartString indicates when the mdserver
    35  	// started rejecting new writes based on the lack of recent merkle
    36  	// updates (according to `maxAllowedMerkleGap` above).
    37  	merkleGapEnforcementStartString = "2018-06-14T16:21:30-07:00"
    38  )
    39  
    40  var merkleGapEnforcementStart time.Time
    41  
    42  func init() {
    43  	var err error
    44  	merkleGapEnforcementStart, err = time.Parse(
    45  		"2006-01-02T15:04:05-07:00", merkleGapEnforcementStartString)
    46  	if err != nil {
    47  		// Can never happen without a bad global const string.
    48  		panic(err)
    49  	}
    50  }
    51  
    52  // MDOpsStandard provides plaintext RootMetadata objects to upper
    53  // layers, and processes RootMetadataSigned objects (encrypted and
    54  // signed) suitable for passing to/from the MDServer backend.
    55  type MDOpsStandard struct {
    56  	config Config
    57  	log    logger.Logger
    58  	vlog   *libkb.VDebugLog
    59  
    60  	lock sync.Mutex
    61  	// For each TLF, maps an MD revision representing the next MD
    62  	// after a device revoke, with the minimum revision number that's
    63  	// been validated in chain up to the given MD revision.  That is,
    64  	// for TLF 1, if we have a next revision of 1000, and we've
    65  	// validated that MDs 100-1000 form a valid chain, then the map
    66  	// would contain: {1: {1000: 100}}
    67  	leafChainsValidated map[tlf.ID]map[kbfsmd.Revision]kbfsmd.Revision
    68  }
    69  
    70  // NewMDOpsStandard returns a new MDOpsStandard
    71  func NewMDOpsStandard(config Config) *MDOpsStandard {
    72  	log := config.MakeLogger("")
    73  	return &MDOpsStandard{
    74  		config: config,
    75  		log:    log,
    76  		vlog:   config.MakeVLogger(log),
    77  		leafChainsValidated: make(
    78  			map[tlf.ID]map[kbfsmd.Revision]kbfsmd.Revision),
    79  	}
    80  }
    81  
    82  // convertVerifyingKeyError gives a better error when the TLF was
    83  // signed by a key that is no longer associated with the last writer.
    84  func (md *MDOpsStandard) convertVerifyingKeyError(ctx context.Context,
    85  	rmds *RootMetadataSigned, handle *tlfhandle.Handle, err error) error {
    86  	if _, ok := err.(VerifyingKeyNotFoundError); !ok {
    87  		return err
    88  	}
    89  
    90  	tlf := handle.GetCanonicalPath()
    91  	writer, nameErr := md.config.KBPKI().GetNormalizedUsername(
    92  		ctx, rmds.MD.LastModifyingWriter().AsUserOrTeam(),
    93  		md.config.OfflineAvailabilityForPath(tlf))
    94  	if nameErr != nil {
    95  		writer = kbname.NormalizedUsername("uid: " +
    96  			rmds.MD.LastModifyingWriter().String())
    97  	}
    98  	md.log.CDebugf(ctx, "Unverifiable update for TLF %s: %+v",
    99  		rmds.MD.TlfID(), err)
   100  	return UnverifiableTlfUpdateError{tlf, writer, err}
   101  }
   102  
   103  type ctxMDOpsSkipKeyVerificationType int
   104  
   105  // This context key indicates that we should skip verification of
   106  // revoked keys, to avoid recursion issues.  Any resulting MD
   107  // that skips verification shouldn't be trusted or cached.
   108  const ctxMDOpsSkipKeyVerification ctxMDOpsSkipKeyVerificationType = 1
   109  
   110  func (md *MDOpsStandard) decryptMerkleLeaf(
   111  	ctx context.Context, rmd ReadOnlyRootMetadata,
   112  	kbfsRoot *kbfsmd.MerkleRoot, leafBytes []byte) (
   113  	leaf *kbfsmd.MerkleLeaf, err error) {
   114  	var eLeaf kbfsmd.EncryptedMerkleLeaf
   115  	err = md.config.Codec().Decode(leafBytes, &eLeaf)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	if rmd.TypeForKeying() == tlf.TeamKeying {
   121  		// For teams, only the Keybase service has access to the
   122  		// private key that can decrypt the data, so send the request
   123  		// over to the crypto client.
   124  		cryptoLeaf := kbfscrypto.MakeEncryptedMerkleLeaf(
   125  			eLeaf.Version, eLeaf.EncryptedData, kbfsRoot.Nonce)
   126  		teamID := rmd.GetTlfHandle().FirstResolvedWriter().AsTeamOrBust()
   127  		// The merkle tree doesn't yet record which team keygen is
   128  		// used to encrypt a merkle leaf, so just use 1 as the min
   129  		// number and let the service scan.  In the future, we should
   130  		// have the server record the keygen in the merkle leaf header
   131  		// and use that instead.  (Note that "team keygen" is
   132  		// completely separate from "application keygen", so we can't
   133  		// just use `rmd.LatestKeyGeneration()` here.)
   134  		minKeyGen := keybase1.PerTeamKeyGeneration(1)
   135  		md.vlog.CLogf(
   136  			ctx, libkb.VLog1,
   137  			"Decrypting Merkle leaf for team %s with min key generation %d",
   138  			teamID, minKeyGen)
   139  		leafBytes, err := md.config.Crypto().DecryptTeamMerkleLeaf(
   140  			ctx, teamID, *kbfsRoot.EPubKey, cryptoLeaf, minKeyGen)
   141  		if err != nil {
   142  			return nil, err
   143  		}
   144  		var leaf kbfsmd.MerkleLeaf
   145  		if err := md.config.Codec().Decode(leafBytes, &leaf); err != nil {
   146  			return nil, err
   147  		}
   148  		return &leaf, nil
   149  	}
   150  
   151  	// The private key we need to decrypt the leaf does not live in
   152  	// key bundles; it lives only in the MDs that were part of a
   153  	// specific keygen.  But we don't yet know what the keygen was, or
   154  	// what MDs were part of it, except that they have to have a
   155  	// larger revision number than the given `rmd`.  So all we can do
   156  	// is iterate up from `rmd`, looking for a key that will unlock
   157  	// the leaf.
   158  	//
   159  	// Luckily, in the common case we'll be trying to verify the head
   160  	// of the folder, so we should be able to use
   161  	// rmd.data.TLFPrivateKey.
   162  
   163  	// Fetch the latest MD so we have all possible TLF crypt keys
   164  	// available to this device.
   165  	head, err := md.getForTLF(
   166  		ctx, rmd.TlfID(), rmd.BID(), rmd.MergedStatus(), nil)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	var uid keybase1.UID
   172  	if rmd.TlfID().Type() != tlf.Public {
   173  		session, err := md.config.KBPKI().GetCurrentSession(ctx)
   174  		if err != nil {
   175  			return nil, err
   176  		}
   177  		uid = session.UID
   178  	}
   179  
   180  	currRmd := rmd
   181  	for {
   182  		// If currRmd isn't readable, keep fetching MDs until it can
   183  		// be read.  Then try currRmd.data.TLFPrivateKey to decrypt
   184  		// the leaf.  If it doesn't work, fetch MDs until we find the
   185  		// next keygen, and continue the loop.
   186  
   187  		privKey := currRmd.data.TLFPrivateKey
   188  		if !currRmd.IsReadable() {
   189  			pmd, err := decryptMDPrivateData(
   190  				ctx, md.config.Codec(), md.config.Crypto(),
   191  				md.config.BlockCache(), md.config.BlockOps(),
   192  				md.config.KeyManager(), md.config.KBPKI(), md.config,
   193  				md.config.Mode(), uid, currRmd.GetSerializedPrivateMetadata(),
   194  				currRmd, head.ReadOnlyRootMetadata, md.log)
   195  			if err != nil {
   196  				return nil, err
   197  			}
   198  			privKey = pmd.TLFPrivateKey
   199  		}
   200  		currKeyGen := currRmd.LatestKeyGeneration()
   201  		if privKey == (kbfscrypto.TLFPrivateKey{}) {
   202  			return nil, errors.Errorf(
   203  				"Can't get TLF private key for key generation %d", currKeyGen)
   204  		}
   205  
   206  		mLeaf, err := eLeaf.Decrypt(
   207  			md.config.Codec(), privKey, kbfsRoot.Nonce, *kbfsRoot.EPubKey)
   208  		switch errors.Cause(err).(type) {
   209  		case nil:
   210  			return &mLeaf, nil
   211  		case libkb.DecryptionError:
   212  			// Fall-through to try another key generation.
   213  		default:
   214  			return nil, err
   215  		}
   216  
   217  		md.vlog.CLogf(
   218  			ctx, libkb.VLog1, "Key generation %d didn't work; searching for "+
   219  				"the next one", currKeyGen)
   220  
   221  	fetchLoop:
   222  		for {
   223  			start := currRmd.Revision() + 1
   224  			end := start + maxMDsAtATime - 1 // range is inclusive
   225  			nextRMDs, err := getMergedMDUpdatesWithEnd(
   226  				ctx, md.config, currRmd.TlfID(), start, end, nil)
   227  			if err != nil {
   228  				return nil, err
   229  			}
   230  
   231  			for _, nextRmd := range nextRMDs {
   232  				if nextRmd.LatestKeyGeneration() > currKeyGen {
   233  					md.vlog.CLogf(
   234  						ctx, libkb.VLog1, "Revision %d has key gen %d",
   235  						nextRmd.Revision(), nextRmd.LatestKeyGeneration())
   236  					currRmd = nextRmd.ReadOnlyRootMetadata
   237  					break fetchLoop
   238  				}
   239  			}
   240  
   241  			if len(nextRMDs) < maxMDsAtATime {
   242  				md.log.CDebugf(ctx,
   243  					"We tried all revisions and couldn't find a working keygen")
   244  				return nil, errors.Errorf("Can't decrypt merkle leaf")
   245  			}
   246  			currRmd = nextRMDs[len(nextRMDs)-1].ReadOnly()
   247  		}
   248  	}
   249  }
   250  
   251  func (md *MDOpsStandard) makeMerkleLeaf(
   252  	ctx context.Context, rmd ReadOnlyRootMetadata,
   253  	kbfsRoot *kbfsmd.MerkleRoot, leafBytes []byte) (
   254  	leaf *kbfsmd.MerkleLeaf, err error) {
   255  	if rmd.TlfID().Type() != tlf.Public {
   256  		return md.decryptMerkleLeaf(ctx, rmd, kbfsRoot, leafBytes)
   257  	}
   258  
   259  	var mLeaf kbfsmd.MerkleLeaf
   260  	err = md.config.Codec().Decode(leafBytes, &mLeaf)
   261  	if err != nil {
   262  		return nil, err
   263  	}
   264  	return &mLeaf, nil
   265  }
   266  
   267  func mdToMerkleTreeID(irmd ImmutableRootMetadata) keybase1.MerkleTreeID {
   268  	switch irmd.TlfID().Type() {
   269  	case tlf.Private:
   270  		return keybase1.MerkleTreeID_KBFS_PRIVATE
   271  	case tlf.Public:
   272  		return keybase1.MerkleTreeID_KBFS_PUBLIC
   273  	case tlf.SingleTeam:
   274  		return keybase1.MerkleTreeID_KBFS_PRIVATETEAM
   275  	default:
   276  		panic(fmt.Sprintf("Unexpected TLF keying type: %d",
   277  			irmd.TypeForKeying()))
   278  	}
   279  }
   280  
   281  func (md *MDOpsStandard) checkMerkleTimes(ctx context.Context,
   282  	latestRootTime time.Time, kbfsRoot *kbfsmd.MerkleRoot,
   283  	timeToCheck time.Time, allowedGapSinceMerkle time.Duration) error {
   284  	var latestKbfsTime time.Time
   285  	if kbfsRoot != nil {
   286  		latestKbfsTime = time.Unix(kbfsRoot.Timestamp, 0)
   287  	}
   288  
   289  	rootGap := timeToCheck.Sub(latestRootTime)
   290  	kbfsGap := timeToCheck.Sub(latestKbfsTime)
   291  	gapBound := allowedGapSinceMerkle
   292  
   293  	// A negative gap means that we expect the merkle roots to have
   294  	// happened second.
   295  	if allowedGapSinceMerkle < 0 {
   296  		if rootGap > 0 || kbfsGap > 0 {
   297  			return errors.Errorf(
   298  				"Roots were unexpectedly made before event being checked, "+
   299  					"timeToCheck=%s, latestRootTime=%s, latestKbfsTime=%s",
   300  				timeToCheck.Format(time.RFC3339Nano),
   301  				latestRootTime.Format(time.RFC3339Nano),
   302  				latestKbfsTime.Format(time.RFC3339Nano))
   303  		}
   304  		rootGap = -rootGap
   305  		kbfsGap = -kbfsGap
   306  		gapBound = -gapBound
   307  	}
   308  
   309  	// If it's been too long since the last published Merkle root,
   310  	// we can't trust what the server told us.
   311  	if rootGap > gapBound {
   312  		return errors.Errorf("Gap too large between event and global Merkle "+
   313  			"roots: gap=%s, timeToCheck=%s, latestRootTime=%s",
   314  			allowedGapSinceMerkle,
   315  			timeToCheck.Format(time.RFC3339Nano),
   316  			latestRootTime.Format(time.RFC3339Nano))
   317  	}
   318  	if kbfsGap > gapBound {
   319  		return errors.Errorf("Gap too large between event and KBFS Merkle "+
   320  			"roots: gap=%s, timeToCheck=%s, latestRootTime=%s",
   321  			allowedGapSinceMerkle,
   322  			timeToCheck.Format(time.RFC3339Nano),
   323  			latestKbfsTime.Format(time.RFC3339Nano))
   324  	}
   325  	return nil
   326  }
   327  
   328  // startOfValidatedChainForLeaf returns the earliest revision in the
   329  // chain leading up to `leafRev` that's been validated so far.  If no
   330  // validations have occurred yet, it returns `leafRev`.
   331  func (md *MDOpsStandard) startOfValidatedChainForLeaf(
   332  	tlfID tlf.ID, leafRev kbfsmd.Revision) kbfsmd.Revision {
   333  	md.lock.Lock()
   334  	defer md.lock.Unlock()
   335  	revs, ok := md.leafChainsValidated[tlfID]
   336  	if !ok {
   337  		return leafRev
   338  	}
   339  	min, ok := revs[leafRev]
   340  	if !ok {
   341  		return leafRev
   342  	}
   343  	return min
   344  }
   345  
   346  func (md *MDOpsStandard) mdserver(ctx context.Context) (
   347  	mds MDServer, err error) {
   348  	// The init code sets the MDOps before it sets the MDServer, and
   349  	// so it might be used before the MDServer is available (e.g., if
   350  	// the Keybase service is established before the MDServer is set,
   351  	// and it tries to look up handles for the user's public and
   352  	// private TLFs).  So just wait until it's available, which should
   353  	// be happen very quickly.
   354  	first := true
   355  	for mds = md.config.MDServer(); mds == nil; mds = md.config.MDServer() {
   356  		if first {
   357  			md.log.CDebugf(ctx, "Waiting for mdserver")
   358  			first = false
   359  		}
   360  		time.Sleep(10 * time.Millisecond)
   361  		select {
   362  		case <-ctx.Done():
   363  			return nil, ctx.Err()
   364  		default:
   365  		}
   366  	}
   367  	return mds, nil
   368  }
   369  
   370  func (md *MDOpsStandard) checkRevisionCameBeforeMerkle(
   371  	ctx context.Context, rmds *RootMetadataSigned,
   372  	verifyingKey kbfscrypto.VerifyingKey, irmd ImmutableRootMetadata,
   373  	root keybase1.MerkleRootV2, timeToCheck time.Time) (err error) {
   374  	ctx = context.WithValue(ctx, ctxMDOpsSkipKeyVerification, struct{}{})
   375  	// This gives us the KBFS merkle root that comes after the KBFS merkle
   376  	// root right after the one included by `root`. In other words, if the
   377  	// KBFS merkle root included in `root` is K0, the returned KBFS merkle
   378  	// root `kbfsRoot` here would be K2.
   379  	//
   380  	// Since `root` is the merkle root included by the revoke signature,
   381  	// anything written by the revoked device after K2 is not legit. The reason
   382  	// why we don't check K1 is that when K1 was built, it's possible that it
   383  	// only included writes happening right before the revoke happened. For
   384  	// example:
   385  	//
   386  	//    - 8:00am mdmerkle starts to run
   387  	//    - 8:01am mdmerkle scans TLF /keybase/private/alice
   388  	//    - 8:02am Alice's device "Playstation 4" writes to her TLF
   389  	//        /keybase/private/alice
   390  	//    - 8:03am Alice revokes her device "Playstation 4", referencing a
   391  	//        global merkle root that includes KBFS merkle K0
   392  	//    - 8:07am mdmerkle finishes building the merkle tree and publish K1,
   393  	//        which includes the head MD from /keybase/private/alice from 8:01,
   394  	//        the one before the write happened at 8:02am.
   395  	//    - 9:00am mdmerkle starts to run again, producing a KBFS merkle tree
   396  	//        K2.
   397  	//
   398  	// Looking at the per TLF metadata chain, the writes happened at 8:02
   399  	// happened after the MD included in K1, but it was before the revoke and
   400  	// was legit. So we have to compare with K2 instead of K1.
   401  	//
   402  	// To protect against a malicious server indefinitely halting building
   403  	// KBFS merkle trees with the purpose of slipping in malicious writes
   404  	// from a revoked device, we have a "contract" with the mdserver that
   405  	// any writes happening after a grace period of
   406  	// `maxAllowedMerkleGapServer` after the last KBFS merkle tree was
   407  	// published should be rejected. In other words, KBFS should become
   408  	// readonly if `maxAllowedMerkleGapServer` has passed since last KBFS
   409  	// merkle tree was published. We add a small error window to it, and
   410  	// enforce in the client that any MD with a gap greater than
   411  	// `maxAllowedMerkleGap` since last KBFS merkle tree is illegal.
   412  	//
   413  	// However there's no way get a trustable timestamp for the metadata
   414  	// update happening at 8:02am when we haven't verified that metadata yet,
   415  	// we have to proxy it to some sort of ordering from merkle trees. Here we
   416  	// are using K2 as that proxy. Since we already need to guarantee the
   417  	// metadata in question has to happen before K2, we just need to make sure
   418  	// K2 happens within `maxAllowedMerkleGap` since the revoke happened.
   419  	//
   420  	// Unfortunately this means if mdmerkle takes longer than
   421  	// `maxAllowedMerkleGap` to build two trees, and a device both writes to a
   422  	// TLF and then gets revoked within that gap (and those writes are the most
   423  	// recent writes to the TLF), there's no way for us to know for sure the
   424  	// write is legit, from merkle tree perspective, and future reads of the
   425  	// TLF will fail without manual intervention.
   426  	kbfsRoot, merkleNodes, rootSeqno, err :=
   427  		md.config.MDCache().GetNextMD(rmds.MD.TlfID(), root.Seqno)
   428  	switch errors.Cause(err).(type) {
   429  	case nil:
   430  	case NextMDNotCachedError:
   431  		md.vlog.CLogf(
   432  			ctx, libkb.VLog1, "Finding next MD for TLF %s after global root %d",
   433  			rmds.MD.TlfID(), root.Seqno)
   434  		mdserv, err := md.mdserver(ctx)
   435  		if err != nil {
   436  			return err
   437  		}
   438  		kbfsRoot, merkleNodes, rootSeqno, err =
   439  			mdserv.FindNextMD(ctx, rmds.MD.TlfID(), root.Seqno)
   440  		if err != nil {
   441  			return err
   442  		}
   443  		err = md.config.MDCache().PutNextMD(
   444  			rmds.MD.TlfID(), root.Seqno, kbfsRoot, merkleNodes, rootSeqno)
   445  		if err != nil {
   446  			return err
   447  		}
   448  	default:
   449  		return err
   450  	}
   451  
   452  	if len(merkleNodes) == 0 {
   453  		// This can happen legitimately if we are still inside the
   454  		// error window and no new merkle trees have been made yet, or
   455  		// the server could be lying to us.
   456  		md.log.CDebugf(ctx, "The server claims there haven't been any "+
   457  			"KBFS merkle trees published since the merkle root")
   458  
   459  		// Check the most recent global merkle root and KBFS merkle
   460  		// root ctimes and make sure they fall within the expected
   461  		// error window with respect to the revocation.
   462  		_, latestRootTime, err := md.config.KBPKI().GetCurrentMerkleRoot(ctx)
   463  		if err != nil {
   464  			return err
   465  		}
   466  		treeID := mdToMerkleTreeID(irmd)
   467  		// TODO: cache the latest KBFS merkle root somewhere for a while?
   468  		mdserv, err := md.mdserver(ctx)
   469  		if err != nil {
   470  			return err
   471  		}
   472  		latestKbfsRoot, err := mdserv.GetMerkleRootLatest(ctx, treeID)
   473  		if err != nil {
   474  			return err
   475  		}
   476  		serverOffset, _ := mdserv.OffsetFromServerTime()
   477  		if (serverOffset < 0 && serverOffset < -time.Hour) ||
   478  			(serverOffset > 0 && serverOffset > time.Hour) {
   479  			return errors.Errorf("The offset between the server clock "+
   480  				"and the local clock is too large to check the revocation "+
   481  				"time: %s", serverOffset)
   482  		}
   483  		currServerTime := md.config.Clock().Now().Add(-serverOffset)
   484  		err = md.checkMerkleTimes(
   485  			ctx, latestRootTime, latestKbfsRoot, currServerTime,
   486  			maxAllowedMerkleGap)
   487  		if err != nil {
   488  			return err
   489  		}
   490  
   491  		// Verify the chain up to the current head.  By using `ctx`,
   492  		// we'll avoid infinite loops in the writer-key-checking code
   493  		// by skipping revoked key verification.  This is ok, because
   494  		// we only care about the hash chain for the purposes of
   495  		// verifying `irmd`.
   496  		chain, err := getMergedMDUpdates(
   497  			ctx, md.config, irmd.TlfID(), irmd.Revision()+1, nil)
   498  		if err != nil {
   499  			return err
   500  		}
   501  		if len(chain) > 0 {
   502  			err = irmd.CheckValidSuccessor(
   503  				irmd.mdID, chain[0].ReadOnlyRootMetadata)
   504  			if err != nil {
   505  				return err
   506  			}
   507  		}
   508  
   509  		// TODO: Also eventually check the blockchain-published merkles to
   510  		// make sure the server isn't lying (though that will have a
   511  		// much larger error window).
   512  		return nil
   513  	}
   514  
   515  	if !timeToCheck.IsZero() {
   516  		// Check the gap between the event and the global/KBFS roots
   517  		// that include the event, to make sure they fall within the
   518  		// expected error window.  The server didn't begin enforcing this
   519  		// until some time into KBFS's existence though.
   520  		if timeToCheck.After(merkleGapEnforcementStart) {
   521  			// TODO(KBFS-2954): get the right root time for the
   522  			// corresponding global root.
   523  			latestRootTime := time.Unix(kbfsRoot.Timestamp, 0)
   524  			// This is to make sure kbfsRoot is built within
   525  			// maxAllowedMerkleGap from timeToCheck (which is the from the
   526  			// revoke signature). As mentioned in the large comment block
   527  			// above, since there's no other way to get a trustable time from
   528  			// this particular metadata update when we don't trust it yet, we
   529  			// use the "happens before K2" check below as a proxy, and make
   530  			// sure K2 is within the gap.
   531  			err = md.checkMerkleTimes(
   532  				ctx, latestRootTime, kbfsRoot, timeToCheck,
   533  				// Check the gap from the reverse direction, to make sure the
   534  				// roots were made _after_ the revoke within the gap.
   535  				-maxAllowedMerkleGap)
   536  			if err != nil {
   537  				return err
   538  			}
   539  		}
   540  	}
   541  
   542  	md.vlog.CLogf(
   543  		ctx, libkb.VLog1,
   544  		"Next KBFS merkle root is %d, included in global merkle root seqno=%d",
   545  		kbfsRoot.SeqNo, rootSeqno)
   546  
   547  	// Decode (and possibly decrypt) the leaf node, so we can see what
   548  	// the given MD revision number was for the MD that followed the
   549  	// revoke.
   550  	leaf, err := md.makeMerkleLeaf(
   551  		ctx, irmd.ReadOnlyRootMetadata, kbfsRoot,
   552  		merkleNodes[len(merkleNodes)-1])
   553  	if err != nil {
   554  		return err
   555  	}
   556  
   557  	// If the given revision comes after the merkle leaf revision,
   558  	// then don't verify it.
   559  	//
   560  	// In the context of the large comment at the beginning of this method,
   561  	// this is to check a write happens before K2.
   562  	if irmd.Revision() > leaf.Revision {
   563  		return MDWrittenAfterRevokeError{
   564  			irmd.TlfID(), irmd.Revision(), leaf.Revision, verifyingKey}
   565  	} else if irmd.Revision() == leaf.Revision {
   566  		return nil
   567  	}
   568  
   569  	// Otherwise it's valid, as long as there's a valid chain of MD
   570  	// revisions between the two.  First, see which chain we've
   571  	// already validated, and if this revision falls in that chain,
   572  	// we're done.  Otherwise, just fetch the part of the chain we
   573  	// haven't validated yet.
   574  	newChainEnd := md.startOfValidatedChainForLeaf(irmd.TlfID(), leaf.Revision)
   575  	if newChainEnd <= irmd.Revision() {
   576  		return nil
   577  	}
   578  
   579  	// By using `ctx`, we'll avoid infinite loops in the
   580  	// writer-key-checking code by skipping revoked key verification.
   581  	// This is ok, because we only care about the hash chain for the
   582  	// purposes of verifying `irmd`.
   583  	md.vlog.CLogf(
   584  		ctx, libkb.VLog1, "Validating MD chain for TLF %s between %d and %d",
   585  		irmd.TlfID(), irmd.Revision()+1, newChainEnd)
   586  	chain, err := getMergedMDUpdatesWithEnd(
   587  		ctx, md.config, irmd.TlfID(), irmd.Revision()+1, newChainEnd, nil)
   588  	if err != nil {
   589  		return err
   590  	}
   591  	if len(chain) == 0 {
   592  		return errors.Errorf("Unexpectedly found no revisions "+
   593  			"after %d, even though the merkle tree includes revision %d",
   594  			irmd.Revision(), leaf.Revision)
   595  	}
   596  
   597  	err = irmd.CheckValidSuccessor(irmd.mdID, chain[0].ReadOnlyRootMetadata)
   598  	if err != nil {
   599  		return err
   600  	}
   601  
   602  	// Cache this verified chain for later use.
   603  	md.lock.Lock()
   604  	defer md.lock.Unlock()
   605  	revs, ok := md.leafChainsValidated[irmd.TlfID()]
   606  	if !ok {
   607  		revs = make(map[kbfsmd.Revision]kbfsmd.Revision)
   608  		md.leafChainsValidated[irmd.TlfID()] = revs
   609  	}
   610  	revs[leaf.Revision] = irmd.Revision()
   611  	return nil
   612  }
   613  
   614  func (md *MDOpsStandard) verifyKey(
   615  	ctx context.Context, rmds *RootMetadataSigned,
   616  	uid keybase1.UID, verifyingKey kbfscrypto.VerifyingKey,
   617  	irmd ImmutableRootMetadata) (cacheable bool, err error) {
   618  	err = md.config.KBPKI().HasVerifyingKey(
   619  		ctx, uid, verifyingKey, rmds.untrustedServerTimestamp,
   620  		md.config.OfflineAvailabilityForID(irmd.TlfID()))
   621  	var info idutil.RevokedKeyInfo
   622  	switch e := errors.Cause(err).(type) {
   623  	case nil:
   624  		return true, nil
   625  	case RevokedDeviceVerificationError:
   626  		if ctx.Value(ctxMDOpsSkipKeyVerification) != nil {
   627  			md.vlog.CLogf(
   628  				ctx, libkb.VLog1,
   629  				"Skipping revoked key verification due to recursion")
   630  			return false, nil
   631  		}
   632  		if e.info.MerkleRoot.Seqno <= 0 {
   633  			md.log.CDebugf(ctx, "Can't verify an MD written by a revoked "+
   634  				"device if there's no valid root seqno to check: %+v", e)
   635  			return true, nil
   636  		}
   637  
   638  		info = e.info
   639  		// Fall through to check via the merkle tree.
   640  	default:
   641  		return false, err
   642  	}
   643  
   644  	md.vlog.CLogf(
   645  		ctx, libkb.VLog1, "Revision %d for %s was signed by a device that was "+
   646  			"revoked at time=%d,root=%d; checking via Merkle",
   647  		irmd.Revision(), irmd.TlfID(), info.Time, info.MerkleRoot.Seqno)
   648  
   649  	err = md.checkRevisionCameBeforeMerkle(
   650  		ctx, rmds, verifyingKey, irmd, info.MerkleRoot,
   651  		keybase1.FromTime(info.Time))
   652  	if err != nil {
   653  		return false, err
   654  	}
   655  	return true, nil
   656  }
   657  
   658  func (md *MDOpsStandard) verifyWriterKey(ctx context.Context,
   659  	rmds *RootMetadataSigned, irmd ImmutableRootMetadata, handle *tlfhandle.Handle,
   660  	getRangeLock *sync.Mutex) error {
   661  	if !rmds.MD.IsWriterMetadataCopiedSet() {
   662  		// Skip verifying the writer key if it's the same as the
   663  		// overall signer's key (which must be verified elsewhere).
   664  		if rmds.GetWriterMetadataSigInfo().VerifyingKey ==
   665  			rmds.SigInfo.VerifyingKey {
   666  			return nil
   667  		}
   668  
   669  		_, err := md.verifyKey(
   670  			ctx, rmds, rmds.MD.LastModifyingWriter(),
   671  			rmds.GetWriterMetadataSigInfo().VerifyingKey, irmd)
   672  		if err != nil {
   673  			return md.convertVerifyingKeyError(ctx, rmds, handle, err)
   674  		}
   675  		return nil
   676  	}
   677  
   678  	// The writer metadata can be copied only for rekeys or
   679  	// finalizations, neither of which should happen while
   680  	// unmerged.
   681  	if rmds.MD.MergedStatus() != kbfsmd.Merged {
   682  		return errors.Errorf("Revision %d for %s has a copied writer "+
   683  			"metadata, but is unexpectedly not merged",
   684  			rmds.MD.RevisionNumber(), rmds.MD.TlfID())
   685  	}
   686  
   687  	if getRangeLock != nil {
   688  		// If there are multiple goroutines, we don't want to risk
   689  		// several concurrent requests to the MD server, just in case
   690  		// there are several revisions with copied writer MD in this
   691  		// range.
   692  		//
   693  		// TODO: bugs could result in thousands (or more) copied MD
   694  		// updates in a row (i.e., too many to fit in the cache).  We
   695  		// could do something more sophisticated here where once one
   696  		// goroutine finds the copied MD, it stores it somewhere so
   697  		// the other goroutines don't have to also search through all
   698  		// the same MD updates (which may have been evicted from the
   699  		// cache in the meantime).  Also, maybe copied writer MDs
   700  		// should include the original revision number so we don't
   701  		// have to search like this.
   702  		getRangeLock.Lock()
   703  		defer getRangeLock.Unlock()
   704  	}
   705  
   706  	// The server timestamp on rmds does not reflect when the
   707  	// writer MD was actually signed, since it was copied from a
   708  	// previous revision.  Search backwards for the most recent
   709  	// uncopied writer MD to get the right timestamp.
   710  	for prevRev := rmds.MD.RevisionNumber() - 1; prevRev >= kbfsmd.RevisionInitial; prevRev-- {
   711  		// Recursively call into MDOps.  Note that in the case where
   712  		// we were already fetching a range of MDs, this could do
   713  		// extra work by downloading the same MDs twice (for those
   714  		// that aren't yet in the cache).  That should be so rare that
   715  		// it's not worth optimizing.
   716  		rmd, err := GetSingleMD(ctx, md.config, rmds.MD.TlfID(),
   717  			rmds.MD.BID(), prevRev, rmds.MD.MergedStatus(), nil)
   718  		if err != nil {
   719  			return err
   720  		}
   721  
   722  		if !rmd.IsWriterMetadataCopiedSet() {
   723  			// We want to compare the writer signature of
   724  			// rmds with that of prevMDs[i]. However, we've
   725  			// already dropped prevMDs[i]'s writer
   726  			// signature. We can just verify prevMDs[i]'s
   727  			// writer metadata with rmds's signature,
   728  			// though.
   729  			buf, err := rmd.GetSerializedWriterMetadata(md.config.Codec())
   730  			if err != nil {
   731  				return err
   732  			}
   733  
   734  			err = kbfscrypto.Verify(
   735  				buf, rmds.GetWriterMetadataSigInfo())
   736  			if err != nil {
   737  				return errors.Errorf("Could not verify "+
   738  					"uncopied writer metadata "+
   739  					"from revision %d of folder "+
   740  					"%s with signature from "+
   741  					"revision %d: %v",
   742  					rmd.Revision(),
   743  					rmds.MD.TlfID(),
   744  					rmds.MD.RevisionNumber(), err)
   745  			}
   746  
   747  			// The fact the fact that we were able to process this
   748  			// MD correctly means that we already verified its key
   749  			// at the correct timestamp, so we're good.
   750  			return nil
   751  		}
   752  	}
   753  	return errors.Errorf(
   754  		"Couldn't find uncopied MD previous to "+
   755  			"revision %d of folder %s for checking the writer "+
   756  			"timestamp", rmds.MD.RevisionNumber(), rmds.MD.TlfID())
   757  }
   758  
   759  type merkleBasedTeamChecker struct {
   760  	teamMembershipChecker
   761  	md           *MDOpsStandard
   762  	rmds         *RootMetadataSigned
   763  	irmd         ImmutableRootMetadata
   764  	notCacheable bool
   765  }
   766  
   767  func (mbtc merkleBasedTeamChecker) IsTeamWriter(
   768  	ctx context.Context, tid keybase1.TeamID, uid keybase1.UID,
   769  	verifyingKey kbfscrypto.VerifyingKey,
   770  	offline keybase1.OfflineAvailability) (bool, error) {
   771  	isCurrentWriter, err := mbtc.teamMembershipChecker.IsTeamWriter(
   772  		ctx, tid, uid, verifyingKey, offline)
   773  	if err != nil {
   774  		return false, err
   775  	}
   776  	if isCurrentWriter {
   777  		return true, nil
   778  	}
   779  
   780  	if ctx.Value(ctxMDOpsSkipKeyVerification) != nil {
   781  		// Don't cache this fake verification.
   782  		mbtc.notCacheable = true
   783  		mbtc.md.vlog.CLogf(
   784  			ctx, libkb.VLog1,
   785  			"Skipping old team writership verification due to recursion")
   786  		return true, nil
   787  	}
   788  
   789  	// The user is not currently a writer of the team, but maybe they
   790  	// were at the time this MD was written.  Find out the global
   791  	// merkle root where they were no longer a writer, and make sure
   792  	// this revision came before that.
   793  	mbtc.md.vlog.CLogf(
   794  		ctx, libkb.VLog1, "User %s is no longer a writer of team %s; "+
   795  			"checking merkle trees to verify they were a writer at the time the "+
   796  			"MD was written.", uid, tid)
   797  	root, err := mbtc.teamMembershipChecker.NoLongerTeamWriter(
   798  		ctx, tid, mbtc.irmd.TlfID().Type(), uid, verifyingKey, offline)
   799  	switch e := errors.Cause(err).(type) {
   800  	case nil:
   801  		// TODO(CORE-8199): pass in the time for the writer downgrade.
   802  		err = mbtc.md.checkRevisionCameBeforeMerkle(
   803  			ctx, mbtc.rmds, verifyingKey, mbtc.irmd, root, time.Time{})
   804  		if err != nil {
   805  			return false, err
   806  		}
   807  	case libkb.MerkleClientError:
   808  		if e.IsOldTree() {
   809  			mbtc.md.vlog.CLogf(
   810  				ctx, libkb.VLog1, "Merkle root is too old for checking "+
   811  					"the revoked key: %+v", err)
   812  		} else {
   813  			return false, err
   814  		}
   815  	default:
   816  		return false, err
   817  	}
   818  
   819  	return true, nil
   820  }
   821  
   822  func (mbtc merkleBasedTeamChecker) IsTeamReader(
   823  	ctx context.Context, tid keybase1.TeamID, uid keybase1.UID,
   824  	offline keybase1.OfflineAvailability) (
   825  	bool, error) {
   826  	if mbtc.irmd.TlfID().Type() == tlf.Public {
   827  		return true, nil
   828  	}
   829  
   830  	isCurrentReader, err := mbtc.teamMembershipChecker.IsTeamReader(
   831  		ctx, tid, uid, offline)
   832  	if err != nil {
   833  		return false, err
   834  	}
   835  	if isCurrentReader {
   836  		return true, nil
   837  	}
   838  
   839  	// We don't yet have a way to check for past readership based on
   840  	// the Merkle tree, so for now return true.  This isn't too bad,
   841  	// since this is only called for checking the last modifying user
   842  	// of an update (the last modifying _writer_ is tested with the
   843  	// above function).  TODO: fix this once historic team readership
   844  	// is available in the service.
   845  	mbtc.md.vlog.CLogf(
   846  		ctx, libkb.VLog1,
   847  		"Faking old readership for user %s in team %s", uid, tid)
   848  	return true, nil
   849  }
   850  
   851  // processMetadata converts the given rmds to an
   852  // ImmutableRootMetadata. After this function is called, rmds
   853  // shouldn't be used.
   854  func (md *MDOpsStandard) processMetadata(ctx context.Context,
   855  	handle *tlfhandle.Handle, rmds *RootMetadataSigned, extra kbfsmd.ExtraMetadata,
   856  	getRangeLock *sync.Mutex) (ImmutableRootMetadata, error) {
   857  	// First, construct the ImmutableRootMetadata object, even before
   858  	// we validate the writer or the keys, because the irmd will be
   859  	// used in that process to check for valid successors.
   860  
   861  	// Get the UID unless this is a public tlf - then proceed with empty uid.
   862  	var uid keybase1.UID
   863  	if handle.Type() != tlf.Public {
   864  		session, err := md.config.KBPKI().GetCurrentSession(ctx)
   865  		if err != nil {
   866  			return ImmutableRootMetadata{}, err
   867  		}
   868  		uid = session.UID
   869  	}
   870  
   871  	// TODO: Avoid having to do this type assertion.
   872  	brmd, ok := rmds.MD.(kbfsmd.MutableRootMetadata)
   873  	if !ok {
   874  		return ImmutableRootMetadata{}, kbfsmd.MutableRootMetadataNoImplError{}
   875  	}
   876  
   877  	rmd := makeRootMetadata(brmd, extra, handle)
   878  	// Try to decrypt using the keys available in this md.  If that
   879  	// doesn't work, a future MD may contain more keys and will be
   880  	// tried later.
   881  	pmd, err := decryptMDPrivateData(
   882  		ctx, md.config.Codec(), md.config.Crypto(),
   883  		md.config.BlockCache(), md.config.BlockOps(),
   884  		md.config.KeyManager(), md.config.KBPKI(), md.config, md.config.Mode(),
   885  		uid, rmd.GetSerializedPrivateMetadata(), rmd, rmd, md.log)
   886  	if err != nil {
   887  		return ImmutableRootMetadata{}, err
   888  	}
   889  	rmd.data = pmd
   890  
   891  	mdID, err := kbfsmd.MakeID(md.config.Codec(), rmd.bareMd)
   892  	if err != nil {
   893  		return ImmutableRootMetadata{}, err
   894  	}
   895  
   896  	localTimestamp := rmds.untrustedServerTimestamp
   897  	mdserv, err := md.mdserver(ctx)
   898  	if err != nil {
   899  		return ImmutableRootMetadata{}, err
   900  	}
   901  	if offset, ok := mdserv.OffsetFromServerTime(); ok {
   902  		localTimestamp = localTimestamp.Add(offset)
   903  	}
   904  
   905  	key := rmds.GetWriterMetadataSigInfo().VerifyingKey
   906  	irmd := MakeImmutableRootMetadata(rmd, key, mdID, localTimestamp, true)
   907  
   908  	// Next, verify validity and signatures.  Use a checker that can
   909  	// check for writership in the past, using the merkle tree.
   910  	checker := merkleBasedTeamChecker{md.config.KBPKI(), md, rmds, irmd, false}
   911  	err = rmds.IsValidAndSigned(
   912  		ctx, md.config.Codec(), checker, extra,
   913  		md.config.OfflineAvailabilityForID(handle.TlfID()))
   914  	if err != nil {
   915  		return ImmutableRootMetadata{}, MDMismatchError{
   916  			rmds.MD.RevisionNumber(), handle.GetCanonicalPath(),
   917  			rmds.MD.TlfID(), err,
   918  		}
   919  	}
   920  
   921  	// Then, verify the verifying keys.  We do this after decrypting
   922  	// the MD and making the ImmutableRootMetadata, since we may need
   923  	// access to the private metadata when checking the merkle roots,
   924  	// and we also need access to the `mdID`.
   925  	if err := md.verifyWriterKey(
   926  		ctx, rmds, irmd, handle, getRangeLock); err != nil {
   927  		return ImmutableRootMetadata{}, err
   928  	}
   929  
   930  	cacheable, err := md.verifyKey(
   931  		ctx, rmds, rmds.MD.GetLastModifyingUser(), rmds.SigInfo.VerifyingKey,
   932  		irmd)
   933  	if err != nil {
   934  		return ImmutableRootMetadata{}, md.convertVerifyingKeyError(
   935  			ctx, rmds, handle, err)
   936  	}
   937  
   938  	// Make sure the caller doesn't use rmds anymore.
   939  	*rmds = RootMetadataSigned{}
   940  
   941  	if cacheable && !checker.notCacheable {
   942  		err = md.config.MDCache().Put(irmd)
   943  		if err != nil {
   944  			return ImmutableRootMetadata{}, err
   945  		}
   946  	}
   947  	return irmd, nil
   948  }
   949  
   950  func (md *MDOpsStandard) getForHandle(ctx context.Context, handle *tlfhandle.Handle,
   951  	mStatus kbfsmd.MergeStatus, lockBeforeGet *keybase1.LockID) (
   952  	id tlf.ID, rmd ImmutableRootMetadata, err error) {
   953  	// If we already know the tlf ID, we shouldn't be calling this
   954  	// function.
   955  	if handle.TlfID() != tlf.NullID {
   956  		return tlf.ID{}, ImmutableRootMetadata{}, errors.Errorf(
   957  			"GetForHandle called for %s with non-nil TLF ID %s",
   958  			handle.GetCanonicalPath(), handle.TlfID())
   959  	}
   960  
   961  	// Check for handle readership, to give a nice error early.
   962  	if handle.Type() == tlf.Private && !handle.IsBackedByTeam() {
   963  		session, err := md.config.KBPKI().GetCurrentSession(ctx)
   964  		if err != nil {
   965  			return tlf.ID{}, ImmutableRootMetadata{}, err
   966  		}
   967  
   968  		if !handle.IsReader(session.UID) {
   969  			return tlf.ID{}, ImmutableRootMetadata{},
   970  				tlfhandle.NewReadAccessError(
   971  					handle, session.Name, handle.GetCanonicalPath())
   972  		}
   973  	}
   974  
   975  	md.log.CDebugf(
   976  		ctx, "GetForHandle: %s %s", handle.GetCanonicalPath(), mStatus)
   977  	defer func() {
   978  		// Temporary debugging for KBFS-1921.  TODO: remove.
   979  		switch {
   980  		case err != nil:
   981  			md.log.CDebugf(ctx, "GetForHandle done with err=%+v", err)
   982  		case rmd != (ImmutableRootMetadata{}):
   983  			md.log.CDebugf(ctx, "GetForHandle done, id=%s, revision=%d, "+
   984  				"mStatus=%s", id, rmd.Revision(), rmd.MergedStatus())
   985  		default:
   986  			md.log.CDebugf(
   987  				ctx, "GetForHandle done, id=%s, no %s MD revisions yet", id,
   988  				mStatus)
   989  		}
   990  	}()
   991  
   992  	mdserv, err := md.mdserver(ctx)
   993  	if err != nil {
   994  		return tlf.ID{}, ImmutableRootMetadata{}, err
   995  	}
   996  	bh, err := handle.ToBareHandle()
   997  	if err != nil {
   998  		return tlf.ID{}, ImmutableRootMetadata{}, err
   999  	}
  1000  	if handle.IsLocalConflict() {
  1001  		md.log.CDebugf(ctx, "Stripping out local conflict info from %s "+
  1002  			"before fetching the ID", handle.GetCanonicalPath())
  1003  		bh.ConflictInfo = nil
  1004  	}
  1005  
  1006  	id, rmds, err := mdserv.GetForHandle(ctx, bh, mStatus, lockBeforeGet)
  1007  	if err != nil {
  1008  		return tlf.ID{}, ImmutableRootMetadata{}, err
  1009  	}
  1010  
  1011  	if rmds == nil {
  1012  		if mStatus == kbfsmd.Unmerged {
  1013  			// The caller ignores the id argument for
  1014  			// mStatus == kbfsmd.Unmerged.
  1015  			return tlf.ID{}, ImmutableRootMetadata{}, nil
  1016  		}
  1017  		return id, ImmutableRootMetadata{}, nil
  1018  	}
  1019  
  1020  	extra, err := md.getExtraMD(ctx, rmds.MD)
  1021  	if err != nil {
  1022  		return tlf.ID{}, ImmutableRootMetadata{}, err
  1023  	}
  1024  
  1025  	bareMdHandle, err := rmds.MD.MakeBareTlfHandle(extra)
  1026  	if err != nil {
  1027  		return tlf.ID{}, ImmutableRootMetadata{}, err
  1028  	}
  1029  
  1030  	mdHandle, err := tlfhandle.MakeHandle(
  1031  		ctx, bareMdHandle, id.Type(), md.config.KBPKI(), md.config.KBPKI(), nil,
  1032  		md.config.OfflineAvailabilityForID(id))
  1033  	if err != nil {
  1034  		return tlf.ID{}, ImmutableRootMetadata{}, err
  1035  	}
  1036  
  1037  	// Check for mutual handle resolution.
  1038  	if err := mdHandle.MutuallyResolvesTo(ctx, md.config.Codec(),
  1039  		md.config.KBPKI(), nil, md.config, *handle, rmds.MD.RevisionNumber(),
  1040  		rmds.MD.TlfID(), md.log); err != nil {
  1041  		return tlf.ID{}, ImmutableRootMetadata{}, err
  1042  	}
  1043  	// Set the ID after checking the resolve, because `handle` doesn't
  1044  	// have the TLF ID set yet.
  1045  	mdHandle.SetTlfID(id)
  1046  
  1047  	// TODO: For now, use the mdHandle that came with rmds for
  1048  	// consistency. In the future, we'd want to eventually notify
  1049  	// the upper layers of the new name, either directly, or
  1050  	// through a rekey.
  1051  	rmd, err = md.processMetadata(ctx, mdHandle, rmds, extra, nil)
  1052  	if err != nil {
  1053  		return tlf.ID{}, ImmutableRootMetadata{}, err
  1054  	}
  1055  
  1056  	return id, rmd, nil
  1057  }
  1058  
  1059  // GetIDForHandle implements the MDOps interface for MDOpsStandard.
  1060  func (md *MDOpsStandard) GetIDForHandle(
  1061  	ctx context.Context, handle *tlfhandle.Handle) (id tlf.ID, err error) {
  1062  	mdcache := md.config.MDCache()
  1063  	id, err = mdcache.GetIDForHandle(handle)
  1064  	switch errors.Cause(err).(type) {
  1065  	case NoSuchTlfIDError:
  1066  		// Do the server-based lookup below.
  1067  	case nil:
  1068  		return id, nil
  1069  	default:
  1070  		return tlf.NullID, err
  1071  	}
  1072  	id, _, err = md.getForHandle(ctx, handle, kbfsmd.Merged, nil)
  1073  	switch errors.Cause(err).(type) {
  1074  	case kbfsmd.ServerErrorClassicTLFDoesNotExist:
  1075  		// The server thinks we should create an implicit team for this TLF.
  1076  		return tlf.NullID, nil
  1077  	case nil:
  1078  	default:
  1079  		return tlf.NullID, err
  1080  	}
  1081  	if !handle.IsLocalConflict() {
  1082  		err = mdcache.PutIDForHandle(handle, id)
  1083  		if err != nil {
  1084  			return tlf.NullID, err
  1085  		}
  1086  	}
  1087  	return id, nil
  1088  }
  1089  
  1090  func (md *MDOpsStandard) processMetadataWithID(ctx context.Context,
  1091  	id tlf.ID, bid kbfsmd.BranchID, handle *tlfhandle.Handle, rmds *RootMetadataSigned,
  1092  	extra kbfsmd.ExtraMetadata, getRangeLock *sync.Mutex) (ImmutableRootMetadata, error) {
  1093  	// Make sure the signed-over ID matches
  1094  	if id != rmds.MD.TlfID() {
  1095  		return ImmutableRootMetadata{}, MDMismatchError{
  1096  			rmds.MD.RevisionNumber(), id.String(), rmds.MD.TlfID(),
  1097  			errors.Errorf("MD contained unexpected folder id %s, expected %s",
  1098  				rmds.MD.TlfID().String(), id.String()),
  1099  		}
  1100  	}
  1101  	// Make sure the signed-over branch ID matches
  1102  	if bid != kbfsmd.NullBranchID && bid != rmds.MD.BID() {
  1103  		return ImmutableRootMetadata{}, MDMismatchError{
  1104  			rmds.MD.RevisionNumber(), id.String(), rmds.MD.TlfID(),
  1105  			errors.Errorf("MD contained unexpected branch id %s, expected %s, "+
  1106  				"folder id %s", rmds.MD.BID().String(), bid.String(), id.String()),
  1107  		}
  1108  	}
  1109  
  1110  	return md.processMetadata(ctx, handle, rmds, extra, getRangeLock)
  1111  }
  1112  
  1113  func (md *MDOpsStandard) processSignedMD(
  1114  	ctx context.Context, id tlf.ID, bid kbfsmd.BranchID,
  1115  	rmds *RootMetadataSigned) (ImmutableRootMetadata, error) {
  1116  	extra, err := md.getExtraMD(ctx, rmds.MD)
  1117  	if err != nil {
  1118  		return ImmutableRootMetadata{}, err
  1119  	}
  1120  	bareHandle, err := rmds.MD.MakeBareTlfHandle(extra)
  1121  	if err != nil {
  1122  		return ImmutableRootMetadata{}, err
  1123  	}
  1124  	handle, err := tlfhandle.MakeHandleWithTlfID(
  1125  		ctx, bareHandle, rmds.MD.TlfID().Type(), md.config.KBPKI(),
  1126  		md.config.KBPKI(), id, md.config.OfflineAvailabilityForID(id))
  1127  	if err != nil {
  1128  		return ImmutableRootMetadata{}, err
  1129  	}
  1130  	rmd, err := md.processMetadataWithID(ctx, id, bid, handle, rmds, extra, nil)
  1131  	if err != nil {
  1132  		return ImmutableRootMetadata{}, err
  1133  	}
  1134  	return rmd, nil
  1135  }
  1136  
  1137  func (md *MDOpsStandard) getForTLF(ctx context.Context, id tlf.ID,
  1138  	bid kbfsmd.BranchID, mStatus kbfsmd.MergeStatus, lockBeforeGet *keybase1.LockID) (
  1139  	ImmutableRootMetadata, error) {
  1140  	mdserv, err := md.mdserver(ctx)
  1141  	if err != nil {
  1142  		return ImmutableRootMetadata{}, err
  1143  	}
  1144  	rmds, err := mdserv.GetForTLF(ctx, id, bid, mStatus, lockBeforeGet)
  1145  	if err != nil {
  1146  		return ImmutableRootMetadata{}, err
  1147  	}
  1148  	if rmds == nil {
  1149  		// Possible if mStatus is kbfsmd.Unmerged
  1150  		return ImmutableRootMetadata{}, nil
  1151  	}
  1152  	return md.processSignedMD(ctx, id, bid, rmds)
  1153  }
  1154  
  1155  // GetForTLF implements the MDOps interface for MDOpsStandard.
  1156  func (md *MDOpsStandard) GetForTLF(
  1157  	ctx context.Context, id tlf.ID, lockBeforeGet *keybase1.LockID) (
  1158  	ImmutableRootMetadata, error) {
  1159  	return md.getForTLF(ctx, id, kbfsmd.NullBranchID, kbfsmd.Merged, lockBeforeGet)
  1160  }
  1161  
  1162  // GetForTLFByTime implements the MDOps interface for MDOpsStandard.
  1163  func (md *MDOpsStandard) GetForTLFByTime(
  1164  	ctx context.Context, id tlf.ID, serverTime time.Time) (
  1165  	irmd ImmutableRootMetadata, err error) {
  1166  	md.log.CDebugf(ctx, "GetForTLFByTime %s %s", id, serverTime)
  1167  	defer func() {
  1168  		if err == nil {
  1169  			md.log.CDebugf(ctx, "GetForTLFByTime %s %s done: %d",
  1170  				id, serverTime, irmd.Revision())
  1171  		} else {
  1172  			md.log.CDebugf(ctx, "GetForTLFByTime %s %s done: %+v",
  1173  				id, serverTime, err)
  1174  		}
  1175  	}()
  1176  	mdserv, err := md.mdserver(ctx)
  1177  	if err != nil {
  1178  		return ImmutableRootMetadata{}, err
  1179  	}
  1180  	rmds, err := mdserv.GetForTLFByTime(ctx, id, serverTime)
  1181  	if err != nil {
  1182  		return ImmutableRootMetadata{}, err
  1183  	}
  1184  
  1185  	return md.processSignedMD(ctx, id, kbfsmd.NullBranchID, rmds)
  1186  }
  1187  
  1188  // GetUnmergedForTLF implements the MDOps interface for MDOpsStandard.
  1189  func (md *MDOpsStandard) GetUnmergedForTLF(
  1190  	ctx context.Context, id tlf.ID, bid kbfsmd.BranchID) (
  1191  	ImmutableRootMetadata, error) {
  1192  	return md.getForTLF(ctx, id, bid, kbfsmd.Unmerged, nil)
  1193  }
  1194  
  1195  func (md *MDOpsStandard) processRange(ctx context.Context, id tlf.ID,
  1196  	bid kbfsmd.BranchID, rmdses []*RootMetadataSigned) (
  1197  	[]ImmutableRootMetadata, error) {
  1198  	if len(rmdses) == 0 {
  1199  		return nil, nil
  1200  	}
  1201  
  1202  	eg, groupCtx := errgroup.WithContext(ctx)
  1203  
  1204  	// Parallelize the MD decryption, because it could involve
  1205  	// fetching blocks to get unembedded block changes.
  1206  	rmdsChan := make(chan *RootMetadataSigned, len(rmdses))
  1207  	irmdChan := make(chan ImmutableRootMetadata, len(rmdses))
  1208  	var getRangeLock sync.Mutex
  1209  	worker := func() error {
  1210  		for rmds := range rmdsChan {
  1211  			extra, err := md.getExtraMD(groupCtx, rmds.MD)
  1212  			if err != nil {
  1213  				return err
  1214  			}
  1215  			bareHandle, err := rmds.MD.MakeBareTlfHandle(extra)
  1216  			if err != nil {
  1217  				return err
  1218  			}
  1219  			handle, err := tlfhandle.MakeHandleWithTlfID(
  1220  				groupCtx, bareHandle, rmds.MD.TlfID().Type(), md.config.KBPKI(),
  1221  				md.config.KBPKI(), id, md.config.OfflineAvailabilityForID(id))
  1222  			if err != nil {
  1223  				return err
  1224  			}
  1225  			irmd, err := md.processMetadataWithID(groupCtx, id, bid,
  1226  				handle, rmds, extra, &getRangeLock)
  1227  			if err != nil {
  1228  				return err
  1229  			}
  1230  			irmdChan <- irmd
  1231  		}
  1232  		return nil
  1233  	}
  1234  
  1235  	numWorkers := len(rmdses)
  1236  	if numWorkers > maxMDsAtATime {
  1237  		numWorkers = maxMDsAtATime
  1238  	}
  1239  	for i := 0; i < numWorkers; i++ {
  1240  		eg.Go(worker)
  1241  	}
  1242  
  1243  	// Do this first, since processMetadataWithID consumes its
  1244  	// rmds argument.
  1245  	startRev := rmdses[0].MD.RevisionNumber()
  1246  	rmdsCount := len(rmdses)
  1247  
  1248  	for _, rmds := range rmdses {
  1249  		rmdsChan <- rmds
  1250  	}
  1251  	close(rmdsChan)
  1252  	err := eg.Wait()
  1253  	if err != nil {
  1254  		return nil, err
  1255  	}
  1256  	close(irmdChan)
  1257  
  1258  	// Sort into slice based on revision.
  1259  	irmds := make([]ImmutableRootMetadata, rmdsCount)
  1260  	numExpected := kbfsmd.Revision(len(irmds))
  1261  	for irmd := range irmdChan {
  1262  		i := irmd.Revision() - startRev
  1263  		if i < 0 || i >= numExpected {
  1264  			return nil, errors.Errorf("Unexpected revision %d; expected "+
  1265  				"something between %d and %d inclusive", irmd.Revision(),
  1266  				startRev, startRev+numExpected-1)
  1267  		} else if irmds[i] != (ImmutableRootMetadata{}) {
  1268  			return nil, errors.Errorf("Got revision %d twice", irmd.Revision())
  1269  		}
  1270  		irmds[i] = irmd
  1271  	}
  1272  
  1273  	// Now that we have all the immutable RootMetadatas, verify that
  1274  	// the given MD objects form a valid sequence.
  1275  	var prevIRMD ImmutableRootMetadata
  1276  	for _, irmd := range irmds {
  1277  		if prevIRMD != (ImmutableRootMetadata{}) {
  1278  			err = prevIRMD.CheckValidSuccessor(
  1279  				prevIRMD.mdID, irmd.ReadOnlyRootMetadata)
  1280  			if err != nil {
  1281  				return nil, MDMismatchError{
  1282  					prevIRMD.Revision(),
  1283  					irmd.GetTlfHandle().GetCanonicalPath(),
  1284  					prevIRMD.TlfID(), err,
  1285  				}
  1286  			}
  1287  		}
  1288  		prevIRMD = irmd
  1289  	}
  1290  
  1291  	// TODO: in the case where lastRoot == MdID{}, should we verify
  1292  	// that the starting PrevRoot points back to something that's
  1293  	// actually a valid part of this history?  If the MD signature is
  1294  	// indeed valid, this probably isn't a huge deal, but it may let
  1295  	// the server rollback or truncate unmerged history...
  1296  
  1297  	return irmds, nil
  1298  }
  1299  
  1300  func (md *MDOpsStandard) getRange(ctx context.Context, id tlf.ID,
  1301  	bid kbfsmd.BranchID, mStatus kbfsmd.MergeStatus, start, stop kbfsmd.Revision,
  1302  	lockBeforeGet *keybase1.LockID) ([]ImmutableRootMetadata, error) {
  1303  	mdserv, err := md.mdserver(ctx)
  1304  	if err != nil {
  1305  		return nil, err
  1306  	}
  1307  	rmds, err := mdserv.GetRange(
  1308  		ctx, id, bid, mStatus, start, stop, lockBeforeGet)
  1309  	if err != nil {
  1310  		return nil, err
  1311  	}
  1312  	rmd, err := md.processRange(ctx, id, bid, rmds)
  1313  	if err != nil {
  1314  		return nil, err
  1315  	}
  1316  	return rmd, nil
  1317  }
  1318  
  1319  // GetRange implements the MDOps interface for MDOpsStandard.
  1320  func (md *MDOpsStandard) GetRange(ctx context.Context, id tlf.ID,
  1321  	start, stop kbfsmd.Revision, lockBeforeGet *keybase1.LockID) (
  1322  	[]ImmutableRootMetadata, error) {
  1323  	return md.getRange(
  1324  		ctx, id, kbfsmd.NullBranchID, kbfsmd.Merged, start, stop, lockBeforeGet)
  1325  }
  1326  
  1327  // GetUnmergedRange implements the MDOps interface for MDOpsStandard.
  1328  func (md *MDOpsStandard) GetUnmergedRange(ctx context.Context, id tlf.ID,
  1329  	bid kbfsmd.BranchID, start, stop kbfsmd.Revision) (
  1330  	[]ImmutableRootMetadata, error) {
  1331  	return md.getRange(ctx, id, bid, kbfsmd.Unmerged, start, stop, nil)
  1332  }
  1333  
  1334  func (md *MDOpsStandard) put(ctx context.Context, rmd *RootMetadata,
  1335  	verifyingKey kbfscrypto.VerifyingKey, lockContext *keybase1.LockContext,
  1336  	priority keybase1.MDPriority, bps data.BlockPutState) (
  1337  	ImmutableRootMetadata, error) {
  1338  	session, err := md.config.KBPKI().GetCurrentSession(ctx)
  1339  	if err != nil {
  1340  		return ImmutableRootMetadata{}, err
  1341  	}
  1342  
  1343  	// Ensure that the block changes are properly unembedded.
  1344  	if !rmd.IsWriterMetadataCopiedSet() &&
  1345  		rmd.data.Changes.Info.BlockPointer == data.ZeroPtr &&
  1346  		!md.config.BlockSplitter().ShouldEmbedData(
  1347  			rmd.data.Changes.SizeEstimate()) {
  1348  		return ImmutableRootMetadata{},
  1349  			errors.New("MD has embedded block changes, but shouldn't")
  1350  	}
  1351  
  1352  	err = encryptMDPrivateData(
  1353  		ctx, md.config.Codec(), md.config.Crypto(),
  1354  		md.config.Crypto(), md.config.KeyManager(), session.UID, rmd)
  1355  	if err != nil {
  1356  		return ImmutableRootMetadata{}, err
  1357  	}
  1358  
  1359  	rmds, err := SignBareRootMetadata(
  1360  		ctx, md.config.Codec(), md.config.Crypto(), md.config.Crypto(),
  1361  		rmd.bareMd, time.Time{})
  1362  	if err != nil {
  1363  		return ImmutableRootMetadata{}, err
  1364  	}
  1365  
  1366  	mdserv, err := md.mdserver(ctx)
  1367  	if err != nil {
  1368  		return ImmutableRootMetadata{}, err
  1369  	}
  1370  	err = mdserv.Put(ctx, rmds, rmd.extra, lockContext, priority)
  1371  	if err != nil {
  1372  		return ImmutableRootMetadata{}, err
  1373  	}
  1374  
  1375  	mdID, err := kbfsmd.MakeID(md.config.Codec(), rmds.MD)
  1376  	if err != nil {
  1377  		return ImmutableRootMetadata{}, err
  1378  	}
  1379  
  1380  	rmd, err = rmd.loadCachedBlockChanges(
  1381  		ctx, bps, md.log, md.vlog, md.config.Codec())
  1382  	if err != nil {
  1383  		return ImmutableRootMetadata{}, err
  1384  	}
  1385  	irmd := MakeImmutableRootMetadata(
  1386  		rmd, verifyingKey, mdID, md.config.Clock().Now(), true)
  1387  	// Revisions created locally should always override anything else
  1388  	// in the cache.
  1389  	err = md.config.MDCache().Replace(irmd, irmd.BID())
  1390  	if err != nil {
  1391  		return ImmutableRootMetadata{}, err
  1392  	}
  1393  	md.log.CDebugf(ctx, "Put MD rev=%d id=%s", rmd.Revision(), mdID)
  1394  
  1395  	return irmd, nil
  1396  }
  1397  
  1398  // Put implements the MDOps interface for MDOpsStandard.
  1399  func (md *MDOpsStandard) Put(ctx context.Context, rmd *RootMetadata,
  1400  	verifyingKey kbfscrypto.VerifyingKey, lockContext *keybase1.LockContext,
  1401  	priority keybase1.MDPriority, bps data.BlockPutState) (
  1402  	ImmutableRootMetadata, error) {
  1403  	if rmd.MergedStatus() == kbfsmd.Unmerged {
  1404  		return ImmutableRootMetadata{}, UnexpectedUnmergedPutError{}
  1405  	}
  1406  	return md.put(ctx, rmd, verifyingKey, lockContext, priority, bps)
  1407  }
  1408  
  1409  // PutUnmerged implements the MDOps interface for MDOpsStandard.
  1410  func (md *MDOpsStandard) PutUnmerged(
  1411  	ctx context.Context, rmd *RootMetadata,
  1412  	verifyingKey kbfscrypto.VerifyingKey, bps data.BlockPutState) (
  1413  	ImmutableRootMetadata, error) {
  1414  	rmd.SetUnmerged()
  1415  	if rmd.BID() == kbfsmd.NullBranchID {
  1416  		// new branch ID
  1417  		bid, err := md.config.Crypto().MakeRandomBranchID()
  1418  		if err != nil {
  1419  			return ImmutableRootMetadata{}, err
  1420  		}
  1421  		rmd.SetBranchID(bid)
  1422  	}
  1423  	return md.put(ctx, rmd, verifyingKey, nil, keybase1.MDPriorityNormal, bps)
  1424  }
  1425  
  1426  // PruneBranch implements the MDOps interface for MDOpsStandard.
  1427  func (md *MDOpsStandard) PruneBranch(
  1428  	ctx context.Context, id tlf.ID, bid kbfsmd.BranchID) error {
  1429  	mdserv, err := md.mdserver(ctx)
  1430  	if err != nil {
  1431  		return err
  1432  	}
  1433  	return mdserv.PruneBranch(ctx, id, bid)
  1434  }
  1435  
  1436  // ResolveBranch implements the MDOps interface for MDOpsStandard.
  1437  func (md *MDOpsStandard) ResolveBranch(
  1438  	ctx context.Context, id tlf.ID, bid kbfsmd.BranchID, _ []kbfsblock.ID,
  1439  	rmd *RootMetadata, verifyingKey kbfscrypto.VerifyingKey,
  1440  	bps data.BlockPutState) (ImmutableRootMetadata, error) {
  1441  	// Put the MD first.
  1442  	irmd, err := md.Put(
  1443  		ctx, rmd, verifyingKey, nil, keybase1.MDPriorityNormal, bps)
  1444  	if err != nil {
  1445  		return ImmutableRootMetadata{}, err
  1446  	}
  1447  
  1448  	// Prune the branch ia the journal, if there is one.  If the
  1449  	// client fails before this is completed, we'll need to check for
  1450  	// resolutions on the next restart (see KBFS-798).
  1451  	err = md.PruneBranch(ctx, id, bid)
  1452  	if err != nil {
  1453  		return ImmutableRootMetadata{}, err
  1454  	}
  1455  	return irmd, nil
  1456  }
  1457  
  1458  // GetLatestHandleForTLF implements the MDOps interface for MDOpsStandard.
  1459  func (md *MDOpsStandard) GetLatestHandleForTLF(ctx context.Context, id tlf.ID) (
  1460  	tlf.Handle, error) {
  1461  	mdserv, err := md.mdserver(ctx)
  1462  	if err != nil {
  1463  		return tlf.Handle{}, err
  1464  	}
  1465  	// TODO: Verify this mapping using a Merkle tree.
  1466  	return mdserv.GetLatestHandleForTLF(ctx, id)
  1467  }
  1468  
  1469  // ValidateLatestHandleNotFinal implements the MDOps interface for
  1470  // MDOpsStandard.
  1471  func (md *MDOpsStandard) ValidateLatestHandleNotFinal(
  1472  	ctx context.Context, h *tlfhandle.Handle) (bool, error) {
  1473  	if h.IsFinal() || h.TlfID() == tlf.NullID {
  1474  		return false, nil
  1475  	}
  1476  
  1477  	// First check the cache to avoid a costly RTT to the mdserver.
  1478  	// If the handle associated with the TLF has really become
  1479  	// finalized, then the cache entry should have been updated.
  1480  	mdcache := md.config.MDCache()
  1481  	id, err := mdcache.GetIDForHandle(h)
  1482  	switch errors.Cause(err).(type) {
  1483  	case NoSuchTlfIDError:
  1484  		// Do the server-based lookup below.
  1485  	case nil:
  1486  		return id == h.TlfID(), nil
  1487  	default:
  1488  		return false, err
  1489  	}
  1490  
  1491  	md.log.CDebugf(ctx, "Checking the latest handle for %s; "+
  1492  		"curr handle is %s", h.TlfID(), h.GetCanonicalName())
  1493  	latestHandle, err := md.GetLatestHandleForTLF(ctx, h.TlfID())
  1494  	switch errors.Cause(err).(type) {
  1495  	case kbfsmd.ServerErrorUnauthorized:
  1496  		// The server sends this in the case that it doesn't know
  1497  		// about the TLF ID.  If the server didn't have the mapping,
  1498  		// we're likely dealing with an implicit team TLF.  Trust what
  1499  		// is in the sigchain in that case.  (If the error happens
  1500  		// because we really looked up a TLF we are unauthorized for,
  1501  		// earlier calls to the server should have failed before we
  1502  		// even got access to the TLF ID.)
  1503  		md.log.CDebugf(ctx,
  1504  			"Assuming unauthorized error implies implicit team TLF: %+v", err)
  1505  		return true, nil
  1506  	case nil:
  1507  		if latestHandle.IsFinal() {
  1508  			md.log.CDebugf(ctx,
  1509  				"Latest handle is finalized, so ID is incorrect")
  1510  			return false, nil
  1511  		}
  1512  		err = mdcache.PutIDForHandle(h, h.TlfID())
  1513  		if err != nil {
  1514  			return false, err
  1515  		}
  1516  		return true, nil
  1517  	default:
  1518  		return false, err
  1519  	}
  1520  }
  1521  
  1522  func (md *MDOpsStandard) getExtraMD(ctx context.Context, brmd kbfsmd.RootMetadata) (
  1523  	extra kbfsmd.ExtraMetadata, err error) {
  1524  	wkbID, rkbID := brmd.GetTLFWriterKeyBundleID(), brmd.GetTLFReaderKeyBundleID()
  1525  	if (wkbID == kbfsmd.TLFWriterKeyBundleID{}) || (rkbID == kbfsmd.TLFReaderKeyBundleID{}) {
  1526  		// Pre-v3 metadata embed key bundles and as such won't set any IDs.
  1527  		return nil, nil
  1528  	}
  1529  	mdserv, err := md.mdserver(ctx)
  1530  	if err != nil {
  1531  		return nil, err
  1532  	}
  1533  	kbcache := md.config.KeyBundleCache()
  1534  	tlf := brmd.TlfID()
  1535  	// Check the cache.
  1536  	wkb, err2 := kbcache.GetTLFWriterKeyBundle(wkbID)
  1537  	if err2 != nil {
  1538  		md.log.CDebugf(ctx, "Error fetching writer key bundle %s from cache for TLF %s: %s",
  1539  			wkbID, tlf, err2)
  1540  	}
  1541  	rkb, err2 := kbcache.GetTLFReaderKeyBundle(rkbID)
  1542  	if err2 != nil {
  1543  		md.log.CDebugf(ctx, "Error fetching reader key bundle %s from cache for TLF %s: %s",
  1544  			rkbID, tlf, err2)
  1545  	}
  1546  	if wkb != nil && rkb != nil {
  1547  		return kbfsmd.NewExtraMetadataV3(*wkb, *rkb, false, false), nil
  1548  	}
  1549  	switch {
  1550  	case wkb != nil:
  1551  		// Don't need the writer bundle.
  1552  		_, rkb, err = mdserv.GetKeyBundles(ctx, tlf, kbfsmd.TLFWriterKeyBundleID{}, rkbID)
  1553  	case rkb != nil:
  1554  		// Don't need the reader bundle.
  1555  		wkb, _, err = mdserv.GetKeyBundles(ctx, tlf, wkbID, kbfsmd.TLFReaderKeyBundleID{})
  1556  	default:
  1557  		// Need them both.
  1558  		wkb, rkb, err = mdserv.GetKeyBundles(ctx, tlf, wkbID, rkbID)
  1559  	}
  1560  	if err != nil {
  1561  		return nil, err
  1562  	}
  1563  	// Cache the results.
  1564  	kbcache.PutTLFWriterKeyBundle(wkbID, *wkb)
  1565  	kbcache.PutTLFReaderKeyBundle(rkbID, *rkb)
  1566  	return kbfsmd.NewExtraMetadataV3(*wkb, *rkb, false, false), nil
  1567  }