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 }