github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/teams/appkeys.go (about)

     1  package teams
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/keybase/client/go/libkb"
     8  	"github.com/keybase/client/go/protocol/keybase1"
     9  )
    10  
    11  func AllApplicationKeys(mctx libkb.MetaContext, team Teamer,
    12  	application keybase1.TeamApplication, latestGen keybase1.PerTeamKeyGeneration) (res []keybase1.TeamApplicationKey, err error) {
    13  	defer mctx.Trace("teams.AllApplicationKeys", &err)()
    14  	for gen := keybase1.PerTeamKeyGeneration(1); gen <= latestGen; gen++ {
    15  		appKey, err := ApplicationKeyAtGeneration(mctx, team, application, gen)
    16  		if err != nil {
    17  			return res, err
    18  		}
    19  		res = append(res, appKey)
    20  	}
    21  	return res, nil
    22  
    23  }
    24  
    25  func AllApplicationKeysWithKBFS(mctx libkb.MetaContext, team Teamer,
    26  	application keybase1.TeamApplication, latestGen keybase1.PerTeamKeyGeneration) (res []keybase1.TeamApplicationKey, err error) {
    27  	teamKeys, err := AllApplicationKeys(mctx, team, application, latestGen)
    28  	if err != nil {
    29  		return res, err
    30  	}
    31  	var kbfsKeys []keybase1.CryptKey
    32  	if team.MainChain() != nil {
    33  		kbfsKeys = team.MainChain().TlfCryptKeys[application]
    34  	}
    35  	if len(kbfsKeys) > 0 {
    36  		latestKBFSGen := kbfsKeys[len(kbfsKeys)-1].Generation()
    37  		for _, k := range kbfsKeys {
    38  			res = append(res, keybase1.TeamApplicationKey{
    39  				Application:   application,
    40  				KeyGeneration: keybase1.PerTeamKeyGeneration(k.KeyGeneration),
    41  				Key:           k.Key,
    42  			})
    43  		}
    44  		for _, tk := range teamKeys {
    45  			res = append(res, keybase1.TeamApplicationKey{
    46  				Application:   application,
    47  				KeyGeneration: keybase1.PerTeamKeyGeneration(tk.Generation() + latestKBFSGen),
    48  				Key:           tk.Key,
    49  			})
    50  		}
    51  	} else {
    52  		res = teamKeys
    53  	}
    54  	return res, nil
    55  }
    56  
    57  func ApplicationKeyAtGeneration(mctx libkb.MetaContext, team Teamer,
    58  	application keybase1.TeamApplication, generation keybase1.PerTeamKeyGeneration) (res keybase1.TeamApplicationKey, err error) {
    59  
    60  	item, err := GetAndVerifyPerTeamKey(mctx, team, generation)
    61  	if err != nil {
    62  		return res, err
    63  	}
    64  
    65  	var rkm *keybase1.ReaderKeyMask
    66  	if UseRKMForApp(application) {
    67  		rkmReal, err := readerKeyMask(team.MainChain(), application, generation)
    68  		if err != nil {
    69  			return res, err
    70  		}
    71  		rkm = &rkmReal
    72  	} else {
    73  		var zeroMask [32]byte
    74  		zeroRKM := keybase1.ReaderKeyMask{
    75  			Application: application,
    76  			Generation:  generation,
    77  			Mask:        zeroMask[:],
    78  		}
    79  		rkm = &zeroRKM
    80  	}
    81  
    82  	return applicationKeyForMask(*rkm, item.Seed)
    83  }
    84  
    85  func ApplicationKeyAtGenerationWithKBFS(mctx libkb.MetaContext, team Teamer,
    86  	application keybase1.TeamApplication, generation keybase1.PerTeamKeyGeneration) (res keybase1.TeamApplicationKey, err error) {
    87  
    88  	var kbfsKeys []keybase1.CryptKey
    89  	if team.MainChain() != nil {
    90  		kbfsKeys = team.MainChain().TlfCryptKeys[application]
    91  	}
    92  	if len(kbfsKeys) > 0 {
    93  		latestKBFSGen := keybase1.PerTeamKeyGeneration(kbfsKeys[len(kbfsKeys)-1].Generation())
    94  		for _, k := range kbfsKeys {
    95  			if k.Generation() == int(generation) {
    96  				return keybase1.TeamApplicationKey{
    97  					Application:   application,
    98  					KeyGeneration: generation,
    99  					Key:           k.Key,
   100  				}, nil
   101  			}
   102  		}
   103  		if res, err = ApplicationKeyAtGeneration(mctx, team, application, generation-latestKBFSGen); err != nil {
   104  			return res, err
   105  		}
   106  		res.KeyGeneration += latestKBFSGen
   107  		return res, nil
   108  	}
   109  	return ApplicationKeyAtGeneration(mctx, team, application, generation)
   110  }
   111  
   112  func UseRKMForApp(application keybase1.TeamApplication) bool {
   113  	switch application {
   114  	case keybase1.TeamApplication_SEITAN_INVITE_TOKEN:
   115  		// Seitan tokens do not use RKMs because implicit admins have all the privileges of explicit members.
   116  		return false
   117  	default:
   118  		return true
   119  	}
   120  }
   121  
   122  func applicationKeyForMask(mask keybase1.ReaderKeyMask, secret keybase1.PerTeamKeySeed) (keybase1.TeamApplicationKey, error) {
   123  	if secret.IsZero() {
   124  		return keybase1.TeamApplicationKey{}, errors.New("nil shared secret in Team#applicationKeyForMask")
   125  	}
   126  	var derivationString string
   127  	switch mask.Application {
   128  	case keybase1.TeamApplication_KBFS:
   129  		derivationString = libkb.TeamKBFSDerivationString
   130  	case keybase1.TeamApplication_CHAT:
   131  		derivationString = libkb.TeamChatDerivationString
   132  	case keybase1.TeamApplication_SALTPACK:
   133  		derivationString = libkb.TeamSaltpackDerivationString
   134  	case keybase1.TeamApplication_GIT_METADATA:
   135  		derivationString = libkb.TeamGitMetadataDerivationString
   136  	case keybase1.TeamApplication_SEITAN_INVITE_TOKEN:
   137  		derivationString = libkb.TeamSeitanTokenDerivationString
   138  	case keybase1.TeamApplication_STELLAR_RELAY:
   139  		derivationString = libkb.TeamStellarRelayDerivationString
   140  	case keybase1.TeamApplication_KVSTORE:
   141  		derivationString = libkb.TeamKVStoreDerivationString
   142  	default:
   143  		return keybase1.TeamApplicationKey{}, fmt.Errorf("unrecognized application id: %v", mask.Application)
   144  	}
   145  
   146  	key := keybase1.TeamApplicationKey{
   147  		Application:   mask.Application,
   148  		KeyGeneration: mask.Generation,
   149  	}
   150  
   151  	if len(mask.Mask) != 32 {
   152  		return keybase1.TeamApplicationKey{}, fmt.Errorf("mask length: %d, expected 32", len(mask.Mask))
   153  	}
   154  
   155  	secBytes := make([]byte, len(mask.Mask))
   156  	n := libkb.XORBytes(secBytes, derivedSecret(secret, derivationString), mask.Mask)
   157  	if n != 32 {
   158  		return key, errors.New("invalid derived secret xor mask size")
   159  	}
   160  	copy(key.Key[:], secBytes)
   161  
   162  	return key, nil
   163  }
   164  
   165  func readerKeyMask(teamData *keybase1.TeamData,
   166  	application keybase1.TeamApplication, generation keybase1.PerTeamKeyGeneration) (res keybase1.ReaderKeyMask, err error) {
   167  
   168  	if teamData == nil {
   169  		return res, NewKeyMaskNotFoundErrorForApplication(application)
   170  	}
   171  
   172  	m2, ok := teamData.ReaderKeyMasks[application]
   173  	if !ok {
   174  		return res, NewKeyMaskNotFoundErrorForApplication(application)
   175  	}
   176  	mask, ok := m2[generation]
   177  	if !ok {
   178  		return res, NewKeyMaskNotFoundErrorForApplicationAndGeneration(application, generation)
   179  	}
   180  	return keybase1.ReaderKeyMask{
   181  		Application: application,
   182  		Generation:  generation,
   183  		Mask:        mask,
   184  	}, nil
   185  }