github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/kbfsmd/key_bundle_v2.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 kbfsmd
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/keybase/client/go/kbfs/kbfscodec"
    11  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    12  	"github.com/keybase/client/go/protocol/keybase1"
    13  	"github.com/keybase/go-codec/codec"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // EPubKeyLocationV2 represents the location of a user's ephemeral
    18  // public key. Note that for V2, a reader ePubKey can be in either the
    19  // writers array (if rekeyed normally) or the readers array (if
    20  // rekeyed by a reader), but a writer ePubKey can be in either array
    21  // also; if a reader whose ePubKey is in the readers array is
    22  // promoted, then the reader becomes a writer whose ePubKey is still
    23  // in the readers array.
    24  type EPubKeyLocationV2 int
    25  
    26  const (
    27  	// WriterEPubKeys means the ephemeral public key is in the
    28  	// writers array.
    29  	WriterEPubKeys EPubKeyLocationV2 = 1
    30  	// ReaderEPubKeys means the ephemeral public key is in the
    31  	// writers array.
    32  	ReaderEPubKeys EPubKeyLocationV2 = 2
    33  )
    34  
    35  func (t EPubKeyLocationV2) String() string {
    36  	switch t {
    37  	case WriterEPubKeys:
    38  		return "WriterEPubKeys"
    39  	case ReaderEPubKeys:
    40  		return "ReaderEPubKeys"
    41  	default:
    42  		return fmt.Sprintf("EPubKeyLocationV2(%d)", t)
    43  	}
    44  }
    45  
    46  // GetEphemeralPublicKeyInfoV2 encapsulates all the ugly logic needed to
    47  // deal with the "negative hack" from
    48  // RootMetadataV2.UpdateKeyGeneration.
    49  func GetEphemeralPublicKeyInfoV2(info TLFCryptKeyInfo,
    50  	wkb TLFWriterKeyBundleV2, rkb TLFReaderKeyBundleV2) (
    51  	keyLocation EPubKeyLocationV2, index int,
    52  	ePubKey kbfscrypto.TLFEphemeralPublicKey, err error) {
    53  	var publicKeys kbfscrypto.TLFEphemeralPublicKeys
    54  	if info.EPubKeyIndex >= 0 {
    55  		index = info.EPubKeyIndex
    56  		publicKeys = wkb.TLFEphemeralPublicKeys
    57  		keyLocation = WriterEPubKeys
    58  	} else {
    59  		index = -1 - info.EPubKeyIndex
    60  		publicKeys = rkb.TLFReaderEphemeralPublicKeys
    61  		keyLocation = ReaderEPubKeys
    62  	}
    63  	keyCount := len(publicKeys)
    64  	if index >= keyCount {
    65  		return EPubKeyLocationV2(0),
    66  			0, kbfscrypto.TLFEphemeralPublicKey{},
    67  			fmt.Errorf("Invalid key in %s with index %d >= %d",
    68  				keyLocation, index, keyCount)
    69  	}
    70  
    71  	return keyLocation, index, publicKeys[index], nil
    72  }
    73  
    74  // DeviceKeyInfoMapV2 is a map from a user devices (identified by the
    75  // KID of the corresponding device CryptPublicKey) to the
    76  // TLF's symmetric secret key information.
    77  type DeviceKeyInfoMapV2 map[keybase1.KID]TLFCryptKeyInfo
    78  
    79  func (dkimV2 DeviceKeyInfoMapV2) fillInDeviceInfos(
    80  	uid keybase1.UID, tlfCryptKey kbfscrypto.TLFCryptKey,
    81  	ePrivKey kbfscrypto.TLFEphemeralPrivateKey, ePubIndex int,
    82  	updatedDeviceKeys DevicePublicKeys) (
    83  	serverHalves DeviceKeyServerHalves, err error) {
    84  	serverHalves = make(DeviceKeyServerHalves, len(updatedDeviceKeys))
    85  	// TODO: parallelize
    86  	for k := range updatedDeviceKeys {
    87  		// Skip existing entries, and only fill in new ones.
    88  		if _, ok := dkimV2[k.KID()]; ok {
    89  			continue
    90  		}
    91  
    92  		clientInfo, serverHalf, err := splitTLFCryptKey(
    93  			uid, tlfCryptKey, ePrivKey, ePubIndex, k)
    94  		if err != nil {
    95  			return nil, err
    96  		}
    97  
    98  		dkimV2[k.KID()] = clientInfo
    99  		serverHalves[k] = serverHalf
   100  	}
   101  
   102  	return serverHalves, nil
   103  }
   104  
   105  func (dkimV2 DeviceKeyInfoMapV2) toPublicKeys() DevicePublicKeys {
   106  	publicKeys := make(DevicePublicKeys, len(dkimV2))
   107  	for kid := range dkimV2 {
   108  		publicKeys[kbfscrypto.MakeCryptPublicKey(kid)] = true
   109  	}
   110  	return publicKeys
   111  }
   112  
   113  // UserDeviceKeyInfoMapV2 maps a user's keybase UID to their
   114  // DeviceKeyInfoMapV2.
   115  type UserDeviceKeyInfoMapV2 map[keybase1.UID]DeviceKeyInfoMapV2
   116  
   117  // ToPublicKeys converts this object to a UserDevicePublicKeys object.
   118  func (udkimV2 UserDeviceKeyInfoMapV2) ToPublicKeys() UserDevicePublicKeys {
   119  	publicKeys := make(UserDevicePublicKeys, len(udkimV2))
   120  	for u, dkimV2 := range udkimV2 {
   121  		publicKeys[u] = dkimV2.toPublicKeys()
   122  	}
   123  	return publicKeys
   124  }
   125  
   126  // RemoveDevicesNotIn removes any info for any device that is not
   127  // contained in the given map of users and devices.
   128  func (udkimV2 UserDeviceKeyInfoMapV2) RemoveDevicesNotIn(
   129  	updatedUserKeys UserDevicePublicKeys) ServerHalfRemovalInfo {
   130  	removalInfo := make(ServerHalfRemovalInfo)
   131  	for uid, dkim := range udkimV2 {
   132  		userRemoved := false
   133  		deviceServerHalfIDs := make(DeviceServerHalfRemovalInfo)
   134  		if deviceKeys, ok := updatedUserKeys[uid]; ok {
   135  			for kid, info := range dkim {
   136  				key := kbfscrypto.MakeCryptPublicKey(kid)
   137  				if !deviceKeys[key] {
   138  					delete(dkim, kid)
   139  					deviceServerHalfIDs[key] = append(
   140  						deviceServerHalfIDs[key],
   141  						info.ServerHalfID)
   142  				}
   143  			}
   144  
   145  			if len(deviceServerHalfIDs) == 0 {
   146  				continue
   147  			}
   148  		} else {
   149  			// The user was completely removed, which
   150  			// shouldn't happen but might as well make it
   151  			// work just in case.
   152  			userRemoved = true
   153  			for kid, info := range dkim {
   154  				key := kbfscrypto.MakeCryptPublicKey(kid)
   155  				deviceServerHalfIDs[key] = append(
   156  					deviceServerHalfIDs[key],
   157  					info.ServerHalfID)
   158  			}
   159  
   160  			delete(udkimV2, uid)
   161  		}
   162  
   163  		removalInfo[uid] = UserServerHalfRemovalInfo{
   164  			UserRemoved:         userRemoved,
   165  			DeviceServerHalfIDs: deviceServerHalfIDs,
   166  		}
   167  	}
   168  
   169  	return removalInfo
   170  }
   171  
   172  // FillInUserInfos fills in this map from the given info.
   173  func (udkimV2 UserDeviceKeyInfoMapV2) FillInUserInfos(
   174  	newIndex int, updatedUserKeys UserDevicePublicKeys,
   175  	ePrivKey kbfscrypto.TLFEphemeralPrivateKey,
   176  	tlfCryptKey kbfscrypto.TLFCryptKey) (
   177  	serverHalves UserDeviceKeyServerHalves, err error) {
   178  	serverHalves = make(UserDeviceKeyServerHalves, len(updatedUserKeys))
   179  	for u, updatedDeviceKeys := range updatedUserKeys {
   180  		if _, ok := udkimV2[u]; !ok {
   181  			udkimV2[u] = DeviceKeyInfoMapV2{}
   182  		}
   183  
   184  		deviceServerHalves, err := udkimV2[u].fillInDeviceInfos(
   185  			u, tlfCryptKey, ePrivKey, newIndex,
   186  			updatedDeviceKeys)
   187  		if err != nil {
   188  			return nil, err
   189  		}
   190  		if len(deviceServerHalves) > 0 {
   191  			serverHalves[u] = deviceServerHalves
   192  		}
   193  	}
   194  	return serverHalves, nil
   195  }
   196  
   197  // All section references below are to https://keybase.io/docs/crypto/kbfs
   198  // (version 1.8).
   199  
   200  // TLFWriterKeyBundleV2 is a bundle of all the writer keys for a top-level
   201  // folder.
   202  type TLFWriterKeyBundleV2 struct {
   203  	// Maps from each writer to their crypt key bundle.
   204  	WKeys UserDeviceKeyInfoMapV2
   205  
   206  	// M_f as described in § 4.1.1.
   207  	TLFPublicKey kbfscrypto.TLFPublicKey `codec:"pubKey"`
   208  
   209  	// M_e as described in § 4.1.1.  Because devices can be added
   210  	// into the key generation after it is initially created (so
   211  	// those devices can get access to existing data), we track
   212  	// multiple ephemeral public keys; the one used by a
   213  	// particular device is specified by EPubKeyIndex in its
   214  	// TLFCryptoKeyInfo struct.
   215  	TLFEphemeralPublicKeys kbfscrypto.TLFEphemeralPublicKeys `codec:"ePubKey"`
   216  
   217  	codec.UnknownFieldSetHandler
   218  }
   219  
   220  // IsWriter returns true if the given user device is in the writer set.
   221  func (wkb TLFWriterKeyBundleV2) IsWriter(user keybase1.UID, deviceKey kbfscrypto.CryptPublicKey) bool {
   222  	_, ok := wkb.WKeys[user][deviceKey.KID()]
   223  	return ok
   224  }
   225  
   226  // TLFWriterKeyGenerationsV2 stores a slice of TLFWriterKeyBundleV2,
   227  // where the last element is the current generation.
   228  type TLFWriterKeyGenerationsV2 []TLFWriterKeyBundleV2
   229  
   230  // LatestKeyGeneration returns the current key generation for this TLF.
   231  func (wkg TLFWriterKeyGenerationsV2) LatestKeyGeneration() KeyGen {
   232  	return KeyGen(len(wkg))
   233  }
   234  
   235  // IsWriter returns whether or not the user+device is an authorized writer
   236  // for the latest generation.
   237  func (wkg TLFWriterKeyGenerationsV2) IsWriter(user keybase1.UID, deviceKey kbfscrypto.CryptPublicKey) bool {
   238  	keyGen := wkg.LatestKeyGeneration()
   239  	if keyGen < 1 {
   240  		return false
   241  	}
   242  	return wkg[keyGen-1].IsWriter(user, deviceKey)
   243  }
   244  
   245  // ToTLFWriterKeyBundleV3 converts a TLFWriterKeyGenerationsV2 to a TLFWriterKeyBundleV3.
   246  func (wkg TLFWriterKeyGenerationsV2) ToTLFWriterKeyBundleV3(
   247  	codec kbfscodec.Codec,
   248  	tlfCryptKeyGetter func() ([]kbfscrypto.TLFCryptKey, error)) (
   249  	TLFWriterKeyBundleV2, TLFWriterKeyBundleV3, error) {
   250  	keyGen := wkg.LatestKeyGeneration()
   251  	if keyGen < FirstValidKeyGen {
   252  		return TLFWriterKeyBundleV2{}, TLFWriterKeyBundleV3{},
   253  			errors.New("No key generations to convert")
   254  	}
   255  
   256  	// Copy the latest UserDeviceKeyInfoMap.
   257  	wkbV2 := wkg[keyGen-FirstValidKeyGen]
   258  	ePubKeyCount := len(wkbV2.TLFEphemeralPublicKeys)
   259  	udkimV3, err := writerUDKIMV2ToV3(codec, wkbV2.WKeys, ePubKeyCount)
   260  	if err != nil {
   261  		return TLFWriterKeyBundleV2{}, TLFWriterKeyBundleV3{}, err
   262  	}
   263  	wkbV3 := TLFWriterKeyBundleV3{
   264  		Keys: udkimV3,
   265  		TLFEphemeralPublicKeys: make(
   266  			kbfscrypto.TLFEphemeralPublicKeys, ePubKeyCount),
   267  		TLFPublicKey: wkbV2.TLFPublicKey,
   268  	}
   269  	// Copy all of the TLFEphemeralPublicKeys at this generation.
   270  	copy(wkbV3.TLFEphemeralPublicKeys[:], wkbV2.TLFEphemeralPublicKeys)
   271  
   272  	if keyGen > FirstValidKeyGen {
   273  		// Fetch all of the TLFCryptKeys.
   274  		keys, err := tlfCryptKeyGetter()
   275  		if err != nil {
   276  			return TLFWriterKeyBundleV2{}, TLFWriterKeyBundleV3{}, err
   277  		}
   278  		// Sanity check.
   279  		if len(keys) != int(keyGen) {
   280  			return TLFWriterKeyBundleV2{}, TLFWriterKeyBundleV3{},
   281  				fmt.Errorf("expected %d keys, found %d", keyGen, len(keys))
   282  		}
   283  		// Save the current key.
   284  		currKey := keys[len(keys)-1]
   285  		// Get rid of the most current generation as that's in the UserDeviceKeyInfoMap already.
   286  		keys = keys[:len(keys)-1]
   287  		// Encrypt the historic keys with the current key.
   288  		wkbV3.EncryptedHistoricTLFCryptKeys, err = kbfscrypto.EncryptTLFCryptKeys(codec, keys, currKey)
   289  		if err != nil {
   290  			return TLFWriterKeyBundleV2{}, TLFWriterKeyBundleV3{}, err
   291  		}
   292  	}
   293  
   294  	return wkbV2, wkbV3, nil
   295  }
   296  
   297  // TLFReaderKeyBundleV2 stores all the reader keys with reader
   298  // permissions on a TLF.
   299  type TLFReaderKeyBundleV2 struct {
   300  	RKeys UserDeviceKeyInfoMapV2
   301  
   302  	// M_e as described in § 4.1.1. Because devices can be added
   303  	// into the key generation after it is initially created (so
   304  	// those devices can get access to existing data), we track
   305  	// multiple ephemeral public keys; the one used by a
   306  	// particular device is specified by EPubKeyIndex in its
   307  	// TLFCryptoKeyInfo struct.  This list is needed so a reader
   308  	// rekey doesn't modify the writer metadata.
   309  	TLFReaderEphemeralPublicKeys kbfscrypto.TLFEphemeralPublicKeys `codec:"readerEPubKey,omitempty"`
   310  
   311  	codec.UnknownFieldSetHandler
   312  }
   313  
   314  // IsReader returns true if the given user device is in the reader set.
   315  func (trb TLFReaderKeyBundleV2) IsReader(user keybase1.UID, deviceKey kbfscrypto.CryptPublicKey) bool {
   316  	_, ok := trb.RKeys[user][deviceKey.KID()]
   317  	return ok
   318  }
   319  
   320  // TLFReaderKeyGenerationsV2 stores a slice of TLFReaderKeyBundleV2,
   321  // where the last element is the current generation.
   322  type TLFReaderKeyGenerationsV2 []TLFReaderKeyBundleV2
   323  
   324  // LatestKeyGeneration returns the current key generation for this TLF.
   325  func (rkg TLFReaderKeyGenerationsV2) LatestKeyGeneration() KeyGen {
   326  	return KeyGen(len(rkg))
   327  }
   328  
   329  // IsReader returns whether or not the user+device is an authorized reader
   330  // for the latest generation.
   331  func (rkg TLFReaderKeyGenerationsV2) IsReader(user keybase1.UID, deviceKey kbfscrypto.CryptPublicKey) bool {
   332  	keyGen := rkg.LatestKeyGeneration()
   333  	if keyGen < 1 {
   334  		return false
   335  	}
   336  	return rkg[keyGen-1].IsReader(user, deviceKey)
   337  }
   338  
   339  // ToTLFReaderKeyBundleV3 converts a TLFReaderKeyGenerationsV2 to a TLFReaderkeyBundleV3.
   340  func (rkg TLFReaderKeyGenerationsV2) ToTLFReaderKeyBundleV3(
   341  	codec kbfscodec.Codec, wkb TLFWriterKeyBundleV2) (
   342  	TLFReaderKeyBundleV3, error) {
   343  	keyGen := rkg.LatestKeyGeneration()
   344  	if keyGen < FirstValidKeyGen {
   345  		return TLFReaderKeyBundleV3{}, errors.New("No key generations to convert")
   346  	}
   347  
   348  	rkbV3 := TLFReaderKeyBundleV3{
   349  		Keys: make(UserDeviceKeyInfoMapV3),
   350  	}
   351  
   352  	// Copy the latest UserDeviceKeyInfoMap.
   353  	rkb := rkg[keyGen-FirstValidKeyGen]
   354  
   355  	// Copy all of the TLFReaderEphemeralPublicKeys.
   356  	rkbV3.TLFEphemeralPublicKeys = make(kbfscrypto.TLFEphemeralPublicKeys,
   357  		len(rkb.TLFReaderEphemeralPublicKeys))
   358  	copy(rkbV3.TLFEphemeralPublicKeys[:], rkb.TLFReaderEphemeralPublicKeys)
   359  
   360  	// Track a mapping of old writer ephemeral pubkey index to new
   361  	// reader ephemeral pubkey index.
   362  	pubKeyIndicesMap := make(map[int]int)
   363  
   364  	// We need to copy these in a slightly annoying way to work around
   365  	// the negative index hack. In V3 readers always have their ePubKey
   366  	// in the TLFReaderEphemeralPublicKeys list. In V2 they only do if
   367  	// the index is negative. Otherwise it's in the writer's list.
   368  	for uid, dkim := range rkb.RKeys {
   369  		dkimV3 := make(DeviceKeyInfoMapV3)
   370  		for kid, info := range dkim {
   371  			var infoCopy TLFCryptKeyInfo
   372  			err := kbfscodec.Update(codec, &infoCopy, info)
   373  			if err != nil {
   374  				return TLFReaderKeyBundleV3{}, err
   375  			}
   376  
   377  			keyLocation, index, ePubKey, err :=
   378  				GetEphemeralPublicKeyInfoV2(info, wkb, rkb)
   379  			if err != nil {
   380  				return TLFReaderKeyBundleV3{}, err
   381  			}
   382  
   383  			switch keyLocation {
   384  			case WriterEPubKeys:
   385  				// Map the old index in the writer list to a new index
   386  				// at the end of the reader list.
   387  				newIndex, ok := pubKeyIndicesMap[index]
   388  				if !ok {
   389  					rkbV3.TLFEphemeralPublicKeys =
   390  						append(rkbV3.TLFEphemeralPublicKeys, ePubKey)
   391  					// TODO: This index depends on
   392  					// map iteration order, which
   393  					// varies. Impose a consistent
   394  					// order on these indices.
   395  					newIndex = len(rkbV3.TLFEphemeralPublicKeys) - 1
   396  					pubKeyIndicesMap[index] = newIndex
   397  				}
   398  				infoCopy.EPubKeyIndex = newIndex
   399  			case ReaderEPubKeys:
   400  				// Use the real index in the reader list.
   401  				infoCopy.EPubKeyIndex = index
   402  			default:
   403  				return TLFReaderKeyBundleV3{}, fmt.Errorf("Unknown key location %s", keyLocation)
   404  			}
   405  			dkimV3[kbfscrypto.MakeCryptPublicKey(kid)] = infoCopy
   406  		}
   407  		rkbV3.Keys[uid] = dkimV3
   408  	}
   409  	return rkbV3, nil
   410  }