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 }