github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfsmd/root_metadata.go (about)

     1  // Copyright 2017 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 kbfsmd
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  
    11  	"github.com/davecgh/go-spew/spew"
    12  	"github.com/keybase/client/go/kbfs/kbfscodec"
    13  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    14  	"github.com/keybase/client/go/kbfs/tlf"
    15  	"github.com/keybase/client/go/protocol/keybase1"
    16  	"github.com/pkg/errors"
    17  )
    18  
    19  // RootMetadata is a read-only interface to the bare serializeable MD that
    20  // is signed by the reader or writer.
    21  type RootMetadata interface {
    22  	// TlfID returns the ID of the TLF this RootMetadata is for.
    23  	TlfID() tlf.ID
    24  	// TypeForKeying returns the keying type for this RootMetadata.
    25  	TypeForKeying() tlf.KeyingType
    26  	// KeyGenerationsToUpdate returns a range that has to be
    27  	// updated when rekeying. start is included, but end is not
    28  	// included. This range can be empty (i.e., start >= end), in
    29  	// which case there's nothing to update, i.e. the TLF is
    30  	// public, or there aren't any existing key generations.
    31  	KeyGenerationsToUpdate() (start KeyGen, end KeyGen)
    32  	// LatestKeyGeneration returns the most recent key generation in this
    33  	// RootMetadata, or PublicKeyGen if this TLF is public.
    34  	LatestKeyGeneration() KeyGen
    35  	// IsValidRekeyRequest returns true if the current block is a simple rekey wrt
    36  	// the passed block.
    37  	IsValidRekeyRequest(codec kbfscodec.Codec, prevMd RootMetadata,
    38  		user keybase1.UID, prevExtra, extra ExtraMetadata) (bool, error)
    39  	// MergedStatus returns the status of this update -- has it been
    40  	// merged into the main folder or not?
    41  	MergedStatus() MergeStatus
    42  	// IsRekeySet returns true if the rekey bit is set.
    43  	IsRekeySet() bool
    44  	// IsWriterMetadataCopiedSet returns true if the bit is set indicating
    45  	// the writer metadata was copied.
    46  	IsWriterMetadataCopiedSet() bool
    47  	// IsFinal returns true if this is the last metadata block for a given
    48  	// folder.  This is only expected to be set for folder resets.
    49  	IsFinal() bool
    50  	// IsWriter returns whether or not the user+device is an authorized writer.
    51  	IsWriter(ctx context.Context, user keybase1.UID,
    52  		cryptKey kbfscrypto.CryptPublicKey,
    53  		verifyingKey kbfscrypto.VerifyingKey,
    54  		teamMemChecker TeamMembershipChecker, extra ExtraMetadata,
    55  		offline keybase1.OfflineAvailability) (bool, error)
    56  	// IsReader returns whether or not the user+device is an authorized reader.
    57  	IsReader(ctx context.Context, user keybase1.UID,
    58  		cryptKey kbfscrypto.CryptPublicKey,
    59  		teamMemChecker TeamMembershipChecker, extra ExtraMetadata,
    60  		offline keybase1.OfflineAvailability) (bool, error)
    61  	// DeepCopy returns a deep copy of the underlying data structure.
    62  	DeepCopy(codec kbfscodec.Codec) (MutableRootMetadata, error)
    63  	// MakeSuccessorCopy returns a newly constructed successor
    64  	// copy to this metadata revision.  It differs from DeepCopy
    65  	// in that it can perform an up conversion to a new metadata
    66  	// version. tlfCryptKeyGetter should be a function that
    67  	// returns a list of TLFCryptKeys for all key generations in
    68  	// ascending order.
    69  	MakeSuccessorCopy(codec kbfscodec.Codec,
    70  		extra ExtraMetadata, latestMDVer MetadataVer,
    71  		tlfCryptKeyGetter func() ([]kbfscrypto.TLFCryptKey, error),
    72  		isReadableAndWriter bool) (mdCopy MutableRootMetadata,
    73  		extraCopy ExtraMetadata, err error)
    74  	// CheckValidSuccessor makes sure the given RootMetadata is a valid
    75  	// successor to the current one, and returns an error otherwise.
    76  	CheckValidSuccessor(currID ID, nextMd RootMetadata) error
    77  	// CheckValidSuccessorForServer is like CheckValidSuccessor but with
    78  	// server-specific error messages.
    79  	CheckValidSuccessorForServer(currID ID, nextMd RootMetadata) error
    80  	// MakeBareTlfHandle makes a tlf.Handle for this
    81  	// RootMetadata. Should be used only by servers and MDOps.
    82  	MakeBareTlfHandle(extra ExtraMetadata) (tlf.Handle, error)
    83  	// TlfHandleExtensions returns a list of handle extensions associated with the TLf.
    84  	TlfHandleExtensions() (extensions []tlf.HandleExtension)
    85  	// GetDevicePublicKeys returns the kbfscrypto.CryptPublicKeys
    86  	// for all known users and devices. Returns an error if the
    87  	// TLF is public.
    88  	GetUserDevicePublicKeys(extra ExtraMetadata) (
    89  		writers, readers UserDevicePublicKeys, err error)
    90  	// GetTLFCryptKeyParams returns all the necessary info to construct
    91  	// the TLF crypt key for the given key generation, user, and device
    92  	// (identified by its crypt public key), or false if not found. This
    93  	// returns an error if the TLF is public.
    94  	GetTLFCryptKeyParams(keyGen KeyGen, user keybase1.UID,
    95  		key kbfscrypto.CryptPublicKey, extra ExtraMetadata) (
    96  		kbfscrypto.TLFEphemeralPublicKey,
    97  		kbfscrypto.EncryptedTLFCryptKeyClientHalf,
    98  		kbfscrypto.TLFCryptKeyServerHalfID, bool, error)
    99  	// IsValidAndSigned verifies the RootMetadata, checks the
   100  	// writer signature, and returns an error if a problem was
   101  	// found. This should be the first thing checked on a BRMD
   102  	// retrieved from an untrusted source, and then the signing
   103  	// user and key should be validated, either by comparing to
   104  	// the current device key (using IsLastModifiedBy), or by
   105  	// checking with KBPKI.
   106  	IsValidAndSigned(ctx context.Context, codec kbfscodec.Codec,
   107  		teamMemChecker TeamMembershipChecker,
   108  		extra ExtraMetadata, writerVerifyingKey kbfscrypto.VerifyingKey,
   109  		offline keybase1.OfflineAvailability) error
   110  	// IsLastModifiedBy verifies that the RootMetadata is
   111  	// written by the given user and device (identified by the
   112  	// device verifying key), and returns an error if not.
   113  	IsLastModifiedBy(uid keybase1.UID, key kbfscrypto.VerifyingKey) error
   114  	// LastModifyingWriter return the UID of the last user to modify the writer metadata.
   115  	LastModifyingWriter() keybase1.UID
   116  	// LastModifyingUser return the UID of the last user to modify the any of the metadata.
   117  	GetLastModifyingUser() keybase1.UID
   118  	// RefBytes returns the number of newly referenced bytes of data blocks introduced by this revision of metadata.
   119  	RefBytes() uint64
   120  	// UnrefBytes returns the number of newly unreferenced bytes introduced by this revision of metadata.
   121  	UnrefBytes() uint64
   122  	// MDRefBytes returns the number of newly referenced bytes of MD blocks introduced by this revision of metadata.
   123  	MDRefBytes() uint64
   124  	// DiskUsage returns the estimated disk usage for the folder as of this revision of metadata.
   125  	DiskUsage() uint64
   126  	// MDDiskUsage returns the estimated MD disk usage for the folder as of this revision of metadata.
   127  	MDDiskUsage() uint64
   128  	// RevisionNumber returns the revision number associated with this metadata structure.
   129  	RevisionNumber() Revision
   130  	// BID returns the per-device branch ID associated with this metadata revision.
   131  	BID() BranchID
   132  	// GetPrevRoot returns the hash of the previous metadata revision.
   133  	GetPrevRoot() ID
   134  	// IsUnmergedSet returns true if the unmerged bit is set.
   135  	IsUnmergedSet() bool
   136  	// GetSerializedPrivateMetadata returns the serialized private metadata as a byte slice.
   137  	GetSerializedPrivateMetadata() []byte
   138  	// GetSerializedWriterMetadata serializes the underlying writer metadata and returns the result.
   139  	GetSerializedWriterMetadata(codec kbfscodec.Codec) ([]byte, error)
   140  	// Version returns the metadata version.
   141  	Version() MetadataVer
   142  	// GetCurrentTLFPublicKey returns the TLF public key for the
   143  	// current key generation.
   144  	GetCurrentTLFPublicKey(ExtraMetadata) (kbfscrypto.TLFPublicKey, error)
   145  	// GetUnresolvedParticipants returns any unresolved readers
   146  	// and writers present in this revision of metadata. The
   147  	// returned array should be safe to modify by the caller.
   148  	GetUnresolvedParticipants() []keybase1.SocialAssertion
   149  	// GetTLFWriterKeyBundleID returns the ID of the externally-stored writer key bundle, or the zero value if
   150  	// this object stores it internally.
   151  	GetTLFWriterKeyBundleID() TLFWriterKeyBundleID
   152  	// GetTLFReaderKeyBundleID returns the ID of the externally-stored reader key bundle, or the zero value if
   153  	// this object stores it internally.
   154  	GetTLFReaderKeyBundleID() TLFReaderKeyBundleID
   155  	// StoresHistoricTLFCryptKeys returns whether or not history keys are symmetrically encrypted; if not, they're
   156  	// encrypted per-device.
   157  	StoresHistoricTLFCryptKeys() bool
   158  	// GetHistoricTLFCryptKey attempts to symmetrically decrypt the key at the given
   159  	// generation using the current generation's TLFCryptKey.
   160  	GetHistoricTLFCryptKey(codec kbfscodec.Codec, keyGen KeyGen,
   161  		currentKey kbfscrypto.TLFCryptKey, extra ExtraMetadata) (
   162  		kbfscrypto.TLFCryptKey, error)
   163  }
   164  
   165  // MutableRootMetadata is a mutable interface to the bare serializeable MD that is signed by the reader or writer.
   166  type MutableRootMetadata interface {
   167  	RootMetadata
   168  
   169  	// SetRefBytes sets the number of newly referenced bytes of data blocks introduced by this revision of metadata.
   170  	SetRefBytes(refBytes uint64)
   171  	// SetUnrefBytes sets the number of newly unreferenced bytes introduced by this revision of metadata.
   172  	SetUnrefBytes(unrefBytes uint64)
   173  	// SetMDRefBytes sets the number of newly referenced bytes of MD blocks introduced by this revision of metadata.
   174  	SetMDRefBytes(mdRefBytes uint64)
   175  	// SetDiskUsage sets the estimated disk usage for the folder as of this revision of metadata.
   176  	SetDiskUsage(diskUsage uint64)
   177  	// SetMDDiskUsage sets the estimated MD disk usage for the folder as of this revision of metadata.
   178  	SetMDDiskUsage(mdDiskUsage uint64)
   179  	// AddRefBytes increments the number of newly referenced bytes of data blocks introduced by this revision of metadata.
   180  	AddRefBytes(refBytes uint64)
   181  	// AddUnrefBytes increments the number of newly unreferenced bytes introduced by this revision of metadata.
   182  	AddUnrefBytes(unrefBytes uint64)
   183  	// AddMDRefBytes increments the number of newly referenced bytes of MD blocks introduced by this revision of metadata.
   184  	AddMDRefBytes(mdRefBytes uint64)
   185  	// AddDiskUsage increments the estimated disk usage for the folder as of this revision of metadata.
   186  	AddDiskUsage(diskUsage uint64)
   187  	// AddMDDiskUsage increments the estimated MD disk usage for the folder as of this revision of metadata.
   188  	AddMDDiskUsage(mdDiskUsage uint64)
   189  	// ClearRekeyBit unsets any set rekey bit.
   190  	ClearRekeyBit()
   191  	// ClearWriterMetadataCopiedBit unsets any set writer metadata copied bit.
   192  	ClearWriterMetadataCopiedBit()
   193  	// ClearFinalBit unsets any final bit.
   194  	ClearFinalBit()
   195  	// SetUnmerged sets the unmerged bit.
   196  	SetUnmerged()
   197  	// SetBranchID sets the branch ID for this metadata revision.
   198  	SetBranchID(bid BranchID)
   199  	// SetPrevRoot sets the hash of the previous metadata revision.
   200  	SetPrevRoot(mdID ID)
   201  	// SetSerializedPrivateMetadata sets the serialized private metadata.
   202  	SetSerializedPrivateMetadata(spmd []byte)
   203  	// SignWriterMetadataInternally signs the writer metadata, for
   204  	// versions that store this signature inside the metadata.
   205  	SignWriterMetadataInternally(ctx context.Context,
   206  		codec kbfscodec.Codec, signer kbfscrypto.Signer) error
   207  	// SetLastModifyingWriter sets the UID of the last user to modify the writer metadata.
   208  	SetLastModifyingWriter(user keybase1.UID)
   209  	// SetLastModifyingUser sets the UID of the last user to modify any of the metadata.
   210  	SetLastModifyingUser(user keybase1.UID)
   211  	// SetRekeyBit sets the rekey bit.
   212  	SetRekeyBit()
   213  	// SetFinalBit sets the finalized bit.
   214  	SetFinalBit()
   215  	// SetWriterMetadataCopiedBit set the writer metadata copied bit.
   216  	SetWriterMetadataCopiedBit()
   217  	// SetRevision sets the revision number of the underlying metadata.
   218  	SetRevision(revision Revision)
   219  	// SetUnresolvedReaders sets the list of unresolved readers associated with this folder.
   220  	SetUnresolvedReaders(readers []keybase1.SocialAssertion)
   221  	// SetUnresolvedWriters sets the list of unresolved writers associated with this folder.
   222  	SetUnresolvedWriters(writers []keybase1.SocialAssertion)
   223  	// SetConflictInfo sets any conflict info associated with this metadata revision.
   224  	SetConflictInfo(ci *tlf.HandleExtension)
   225  	// SetFinalizedInfo sets any finalized info associated with this metadata revision.
   226  	SetFinalizedInfo(fi *tlf.HandleExtension)
   227  	// SetWriters sets the list of writers associated with this folder.
   228  	SetWriters(writers []keybase1.UserOrTeamID)
   229  	// ClearForV4Migration clears out data not needed for an upgrade
   230  	// to an implicit-team-backed TLF.  Note that `SetWriters` should
   231  	// also be called separately to set the new team ID as a writer.
   232  	ClearForV4Migration()
   233  	// SetTlfID sets the ID of the underlying folder in the metadata structure.
   234  	SetTlfID(tlf tlf.ID)
   235  
   236  	// AddKeyGeneration adds a new key generation to this revision
   237  	// of metadata. If StoresHistoricTLFCryptKeys is false, then
   238  	// currCryptKey must be zero. Otherwise, currCryptKey must be
   239  	// zero if there are no existing key generations, and non-zero
   240  	// for otherwise.
   241  	//
   242  	// AddKeyGeneration must only be called on metadata for
   243  	// private TLFs.
   244  	//
   245  	// Note that the TLFPrivateKey corresponding to privKey must
   246  	// also be stored in PrivateMetadata.
   247  	AddKeyGeneration(codec kbfscodec.Codec, currExtra ExtraMetadata,
   248  		updatedWriterKeys, updatedReaderKeys UserDevicePublicKeys,
   249  		ePubKey kbfscrypto.TLFEphemeralPublicKey,
   250  		ePrivKey kbfscrypto.TLFEphemeralPrivateKey,
   251  		pubKey kbfscrypto.TLFPublicKey,
   252  		currCryptKey, nextCryptKey kbfscrypto.TLFCryptKey) (
   253  		nextExtra ExtraMetadata,
   254  		serverHalves UserDeviceKeyServerHalves, err error)
   255  
   256  	// SetLatestKeyGenerationForTeamTLF sets the latest key generation
   257  	// number of a team TLF.  It is not valid to call this for
   258  	// anything but a team TLF.
   259  	SetLatestKeyGenerationForTeamTLF(keyGen KeyGen)
   260  
   261  	// UpdateKeyBundles ensures that every device for every writer
   262  	// and reader in the provided lists has complete TLF crypt key
   263  	// info, and uses the new ephemeral key pair to generate the
   264  	// info if it doesn't yet exist. tlfCryptKeys must contain an
   265  	// entry for each key generation in KeyGenerationsToUpdate(),
   266  	// in ascending order.
   267  	//
   268  	// updatedWriterKeys and updatedReaderKeys usually contains
   269  	// the full maps of writers to per-device crypt public keys,
   270  	// but for reader rekey, updatedWriterKeys will be empty and
   271  	// updatedReaderKeys will contain only a single entry.
   272  	//
   273  	// UpdateKeyBundles must only be called on metadata for
   274  	// private TLFs.
   275  	//
   276  	// An array of server halves to push to the server are
   277  	// returned, with each entry corresponding to each key
   278  	// generation in KeyGenerationsToUpdate(), in ascending order.
   279  	UpdateKeyBundles(codec kbfscodec.Codec, extra ExtraMetadata,
   280  		updatedWriterKeys, updatedReaderKeys UserDevicePublicKeys,
   281  		ePubKey kbfscrypto.TLFEphemeralPublicKey,
   282  		ePrivKey kbfscrypto.TLFEphemeralPrivateKey,
   283  		tlfCryptKeys []kbfscrypto.TLFCryptKey) (
   284  		[]UserDeviceKeyServerHalves, error)
   285  
   286  	// PromoteReaders converts the given set of users (which may
   287  	// be empty) from readers to writers.
   288  	PromoteReaders(readersToPromote map[keybase1.UID]bool,
   289  		extra ExtraMetadata) error
   290  
   291  	// RevokeRemovedDevices removes key info for any device not in
   292  	// the given maps, and returns a corresponding map of server
   293  	// halves to delete from the server.
   294  	//
   295  	// Note: the returned server halves may not be for all key
   296  	// generations, e.g. for MDv3 it's only for the latest key
   297  	// generation.
   298  	RevokeRemovedDevices(
   299  		updatedWriterKeys, updatedReaderKeys UserDevicePublicKeys,
   300  		extra ExtraMetadata) (ServerHalfRemovalInfo, error)
   301  
   302  	// FinalizeRekey must be called called after all rekeying work
   303  	// has been performed on the underlying metadata.
   304  	FinalizeRekey(codec kbfscodec.Codec, extra ExtraMetadata) error
   305  }
   306  
   307  // TODO: Wrap errors coming from RootMetadata.
   308  
   309  // MakeInitialRootMetadata creates a new MutableRootMetadata
   310  // instance of the given MetadataVer with revision
   311  // RevisionInitial, and the given TLF ID and handle. Note that
   312  // if the given ID/handle are private, rekeying must be done
   313  // separately.
   314  func MakeInitialRootMetadata(
   315  	ver MetadataVer, tlfID tlf.ID, h tlf.Handle) (
   316  	MutableRootMetadata, error) {
   317  	if ver < FirstValidMetadataVer {
   318  		return nil, InvalidMetadataVersionError{tlfID, ver}
   319  	}
   320  	if ver > ImplicitTeamsVer {
   321  		// Shouldn't be possible at the moment.
   322  		panic("Invalid metadata version")
   323  	}
   324  	if ver < ImplicitTeamsVer && tlfID.Type() != tlf.SingleTeam &&
   325  		h.TypeForKeying() == tlf.TeamKeying {
   326  		return nil, NewMetadataVersionError{tlfID, ImplicitTeamsVer}
   327  	}
   328  
   329  	if ver < SegregatedKeyBundlesVer {
   330  		return MakeInitialRootMetadataV2(tlfID, h)
   331  	}
   332  
   333  	// V3 and V4 MDs are data-compatible.
   334  	return MakeInitialRootMetadataV3(tlfID, h)
   335  }
   336  
   337  func makeMutableRootMetadataForDecode(codec kbfscodec.Codec, tlf tlf.ID,
   338  	ver, max MetadataVer, buf []byte) (MutableRootMetadata, error) {
   339  	if ver < FirstValidMetadataVer {
   340  		return nil, InvalidMetadataVersionError{TlfID: tlf, MetadataVer: ver}
   341  	} else if ver > max {
   342  		return nil, NewMetadataVersionError{tlf, ver}
   343  	}
   344  	if ver > ImplicitTeamsVer {
   345  		// Shouldn't be possible at the moment.
   346  		panic("Invalid metadata version")
   347  	}
   348  	if ver < SegregatedKeyBundlesVer {
   349  		return &RootMetadataV2{}, nil
   350  	}
   351  	return &RootMetadataV3{}, nil
   352  }
   353  
   354  // DecodeRootMetadata deserializes a metadata block into the specified
   355  // versioned structure.
   356  func DecodeRootMetadata(codec kbfscodec.Codec, tlfID tlf.ID,
   357  	ver, max MetadataVer, buf []byte) (MutableRootMetadata, error) {
   358  	rmd, err := makeMutableRootMetadataForDecode(codec, tlfID, ver, max, buf)
   359  	if err != nil {
   360  		return nil, err
   361  	}
   362  	if err := codec.Decode(buf, rmd); err != nil {
   363  		return nil, err
   364  	}
   365  	if ver < ImplicitTeamsVer && tlfID.Type() != tlf.SingleTeam &&
   366  		rmd.TypeForKeying() == tlf.TeamKeying {
   367  		return nil, errors.Errorf(
   368  			"Can't make an implicit teams TLF with version %s", ver)
   369  	}
   370  	return rmd, nil
   371  }
   372  
   373  // DumpConfig returns the *spew.ConfigState used by DumpRootMetadata
   374  // and related functions.
   375  func DumpConfig() *spew.ConfigState {
   376  	c := spew.NewDefaultConfig()
   377  	c.Indent = "  "
   378  	c.DisablePointerAddresses = true
   379  	c.DisableCapacities = true
   380  	c.SortKeys = true
   381  	return c
   382  }
   383  
   384  // DumpRootMetadata returns a detailed dump of the given
   385  // RootMetadata's contents.
   386  func DumpRootMetadata(
   387  	codec kbfscodec.Codec, rmd RootMetadata) (string, error) {
   388  	serializedRMD, err := codec.Encode(rmd)
   389  	if err != nil {
   390  		return "", err
   391  	}
   392  
   393  	// Make a copy so we can zero out SerializedPrivateMetadata.
   394  	rmdCopy, err := rmd.DeepCopy(codec)
   395  	if err != nil {
   396  		return "", err
   397  	}
   398  
   399  	rmdCopy.SetSerializedPrivateMetadata(nil)
   400  	s := fmt.Sprintf("MD revision: %s\n"+
   401  		"MD size: %d bytes\n"+
   402  		"Private MD size: %d bytes\n"+
   403  		"MD version: %s\n\n",
   404  		rmd.RevisionNumber(),
   405  		len(serializedRMD),
   406  		len(rmd.GetSerializedPrivateMetadata()),
   407  		rmd.Version())
   408  	s += DumpConfig().Sdump(rmdCopy)
   409  	return s, nil
   410  }