github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/teams/sig.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 // Similar to libkb/kbsigs.go, but for teams sigs. 5 package teams 6 7 import ( 8 "encoding/hex" 9 "errors" 10 "fmt" 11 12 "golang.org/x/net/context" 13 14 "github.com/davecgh/go-spew/spew" 15 "github.com/keybase/client/go/libkb" 16 keybase1 "github.com/keybase/client/go/protocol/keybase1" 17 "github.com/keybase/client/go/sig3" 18 "github.com/keybase/client/go/teams/hidden" 19 jsonw "github.com/keybase/go-jsonw" 20 ) 21 22 // metaContext returns a GlobalContext + a TODO context, since we're not 23 // threading through contexts through this library. In the future, we should 24 // fix this. 25 func metaContext(g *libkb.GlobalContext) libkb.MetaContext { 26 return libkb.NewMetaContextTODO(g) 27 } 28 29 func TeamRootSig(g *libkb.GlobalContext, me libkb.UserForSignatures, key libkb.GenericKey, teamSection SCTeamSection, merkleRoot libkb.MerkleRoot) (*jsonw.Wrapper, error) { 30 ret, err := libkb.ProofMetadata{ 31 SigningUser: me, 32 Eldest: me.GetEldestKID(), 33 LinkType: libkb.LinkTypeTeamRoot, 34 SigningKey: key, 35 Seqno: 1, 36 SigVersion: libkb.KeybaseSignatureV2, 37 SeqType: seqTypeForTeamPublicness(teamSection.Public), 38 MerkleRoot: &merkleRoot, 39 }.ToJSON(metaContext(g)) 40 if err != nil { 41 return nil, err 42 } 43 44 teamSectionJSON, err := jsonw.WrapperFromObject(teamSection) 45 if err != nil { 46 return nil, err 47 } 48 err = teamSectionJSON.SetValueAtPath("per_team_key.reverse_sig", jsonw.NewNil()) 49 if err != nil { 50 return nil, err 51 } 52 53 body := ret.AtKey("body") 54 err = body.SetKey("team", teamSectionJSON) 55 if err != nil { 56 return nil, err 57 } 58 59 return ret, nil 60 } 61 62 func NewImplicitTeamName() (res keybase1.TeamName, err error) { 63 dat, err := libkb.RandBytes(keybase1.ImplicitSuffixLengthBytes) 64 if err != nil { 65 return res, err 66 } 67 res, err = keybase1.TeamNameFromString(fmt.Sprintf("%s%s", keybase1.ImplicitTeamPrefix, hex.EncodeToString(dat))) 68 return res, err 69 } 70 71 func NewSubteamSig(mctx libkb.MetaContext, me libkb.UserForSignatures, key libkb.GenericKey, parentTeam *TeamSigChainState, subteamName keybase1.TeamName, subteamID keybase1.TeamID, admin *SCTeamAdmin) (*jsonw.Wrapper, *hidden.Ratchet, error) { 72 g := mctx.G() 73 prevLinkID, err := libkb.ImportLinkID(parentTeam.GetLatestLinkID()) 74 if err != nil { 75 return nil, nil, err 76 } 77 ret, err := libkb.ProofMetadata{ 78 SigningUser: me, 79 Eldest: me.GetEldestKID(), 80 LinkType: libkb.LinkTypeNewSubteam, 81 SigningKey: key, 82 SigVersion: libkb.KeybaseSignatureV2, 83 SeqType: seqTypeForTeamPublicness(parentTeam.IsPublic()), // children are as public as their parent 84 Seqno: parentTeam.GetLatestSeqno() + 1, 85 PrevLinkID: prevLinkID, 86 }.ToJSON(metaContext(g)) 87 if err != nil { 88 return nil, nil, err 89 } 90 91 entropy, err := makeSCTeamEntropy() 92 if err != nil { 93 return nil, nil, err 94 } 95 96 ratchet, err := parentTeam.makeHiddenRatchet(mctx) 97 if err != nil { 98 return nil, nil, err 99 } 100 101 teamSection := SCTeamSection{ 102 ID: (SCTeamID)(parentTeam.GetID()), 103 Subteam: &SCSubteam{ 104 ID: (SCTeamID)(subteamID), 105 Name: (SCTeamName)(subteamName.String()), 106 }, 107 Admin: admin, 108 Entropy: entropy, 109 Ratchets: ratchet.ToTeamSection(), 110 } 111 teamSectionJSON, err := jsonw.WrapperFromObject(teamSection) 112 if err != nil { 113 return nil, nil, err 114 } 115 err = ret.SetValueAtPath("body.team", teamSectionJSON) 116 if err != nil { 117 return nil, nil, err 118 } 119 120 return ret, ratchet, nil 121 } 122 123 func SubteamHeadSig(g *libkb.GlobalContext, me libkb.UserForSignatures, key libkb.GenericKey, subteamTeamSection SCTeamSection, merkleRoot libkb.MerkleRoot) (*jsonw.Wrapper, error) { 124 ret, err := libkb.ProofMetadata{ 125 SigningUser: me, 126 Eldest: me.GetEldestKID(), 127 LinkType: libkb.LinkTypeSubteamHead, 128 SigningKey: key, 129 Seqno: 1, 130 SigVersion: libkb.KeybaseSignatureV2, 131 SeqType: seqTypeForTeamPublicness(subteamTeamSection.Public), 132 MerkleRoot: &merkleRoot, 133 }.ToJSON(metaContext(g)) 134 if err != nil { 135 return nil, err 136 } 137 138 // Note that the team section here is expected to have its Parent 139 // subsection filled out by the caller, unlike TeamRootSig. 140 teamSectionJSON, err := jsonw.WrapperFromObject(subteamTeamSection) 141 if err != nil { 142 return nil, err 143 } 144 err = teamSectionJSON.SetValueAtPath("per_team_key.reverse_sig", jsonw.NewNil()) 145 if err != nil { 146 return nil, err 147 } 148 149 body := ret.AtKey("body") 150 err = body.SetKey("team", teamSectionJSON) 151 if err != nil { 152 return nil, err 153 } 154 155 return ret, nil 156 } 157 158 func RenameSubteamSig(g *libkb.GlobalContext, me libkb.UserForSignatures, key libkb.GenericKey, parentTeam *TeamSigChainState, teamSection SCTeamSection) (*jsonw.Wrapper, error) { 159 prev, err := parentTeam.GetLatestLibkbLinkID() 160 if err != nil { 161 return nil, err 162 } 163 ret, err := libkb.ProofMetadata{ 164 SigningUser: me, 165 Eldest: me.GetEldestKID(), 166 LinkType: libkb.LinkTypeRenameSubteam, 167 SigningKey: key, 168 Seqno: parentTeam.GetLatestSeqno() + 1, 169 PrevLinkID: prev, 170 SigVersion: libkb.KeybaseSignatureV2, 171 SeqType: seqTypeForTeamPublicness(teamSection.Public), 172 }.ToJSON(metaContext(g)) 173 if err != nil { 174 return nil, err 175 } 176 177 teamSectionJSON, err := jsonw.WrapperFromObject(teamSection) 178 if err != nil { 179 return nil, err 180 } 181 182 body := ret.AtKey("body") 183 err = body.SetKey("team", teamSectionJSON) 184 if err != nil { 185 return nil, err 186 } 187 188 return ret, nil 189 } 190 191 func RenameUpPointerSig(g *libkb.GlobalContext, me libkb.UserForSignatures, key libkb.GenericKey, subteam *TeamSigChainState, teamSection SCTeamSection) (*jsonw.Wrapper, error) { 192 prev, err := subteam.GetLatestLibkbLinkID() 193 if err != nil { 194 return nil, err 195 } 196 ret, err := libkb.ProofMetadata{ 197 SigningUser: me, 198 Eldest: me.GetEldestKID(), 199 LinkType: libkb.LinkTypeRenameUpPointer, 200 SigningKey: key, 201 Seqno: subteam.GetLatestSeqno() + 1, 202 PrevLinkID: prev, 203 SigVersion: libkb.KeybaseSignatureV2, 204 SeqType: seqTypeForTeamPublicness(teamSection.Public), 205 }.ToJSON(metaContext(g)) 206 if err != nil { 207 return nil, err 208 } 209 210 teamSectionJSON, err := jsonw.WrapperFromObject(teamSection) 211 if err != nil { 212 return nil, err 213 } 214 215 body := ret.AtKey("body") 216 err = body.SetKey("team", teamSectionJSON) 217 if err != nil { 218 return nil, err 219 } 220 221 return ret, nil 222 } 223 224 // 15 random bytes, followed by the byte 0x25, encoded as hex 225 func NewSubteamID(public bool) keybase1.TeamID { 226 var useSuffix byte = keybase1.SUB_TEAMID_PRIVATE_SUFFIX 227 if public { 228 useSuffix = keybase1.SUB_TEAMID_PUBLIC_SUFFIX 229 } 230 idBytes, err := libkb.RandBytesWithSuffix(16, useSuffix) 231 if err != nil { 232 panic("RandBytes failed: " + err.Error()) 233 } 234 return keybase1.TeamID(hex.EncodeToString(idBytes)) 235 } 236 237 func NewInviteID() SCTeamInviteID { 238 b, err := libkb.RandBytesWithSuffix(16, libkb.InviteIDTag) 239 if err != nil { 240 panic("RandBytes failed: " + err.Error()) 241 } 242 return SCTeamInviteID(hex.EncodeToString(b)) 243 } 244 245 func ChangeSig(g *libkb.GlobalContext, me libkb.UserForSignatures, prev libkb.LinkID, seqno keybase1.Seqno, key libkb.GenericKey, teamSection SCTeamSection, 246 linkType libkb.LinkType, merkleRoot *libkb.MerkleRoot) (*jsonw.Wrapper, error) { 247 if teamSection.PerTeamKey != nil { 248 if teamSection.PerTeamKey.ReverseSig != "" { 249 return nil, errors.New("ChangeMembershipSig called with PerTeamKey.ReverseSig already set") 250 } 251 } 252 253 ret, err := libkb.ProofMetadata{ 254 LinkType: linkType, 255 SigningUser: me, 256 Eldest: me.GetEldestKID(), 257 SigningKey: key, 258 Seqno: seqno, 259 PrevLinkID: prev, 260 SigVersion: libkb.KeybaseSignatureV2, 261 SeqType: seqTypeForTeamPublicness(teamSection.Public), 262 MerkleRoot: merkleRoot, 263 }.ToJSON(metaContext(g)) 264 if err != nil { 265 return nil, err 266 } 267 268 teamSectionJSON, err := jsonw.WrapperFromObject(teamSection) 269 if err != nil { 270 return nil, err 271 } 272 273 body := ret.AtKey("body") 274 err = body.SetKey("team", teamSectionJSON) 275 if err != nil { 276 return nil, err 277 } 278 279 return ret, nil 280 } 281 282 func makeSCTeamEntropy() (SCTeamEntropy, error) { 283 entropy, err := libkb.LinkEntropy() 284 if err != nil { 285 return SCTeamEntropy(""), err 286 } 287 return SCTeamEntropy(entropy), nil 288 } 289 290 func seqTypeForTeamPublicness(public bool) keybase1.SeqType { 291 if public { 292 return keybase1.SeqType_PUBLIC 293 } 294 return keybase1.SeqType_SEMIPRIVATE 295 } 296 297 func precheckLinkToPost(ctx context.Context, g *libkb.GlobalContext, 298 sigMultiItem libkb.SigMultiItem, state *TeamSigChainState, 299 me keybase1.UserVersion) (err error) { 300 return precheckLinksToPost(ctx, g, []libkb.SigMultiItem{sigMultiItem}, state, me) 301 } 302 303 func appendChainLinkSig3(ctx context.Context, g *libkb.GlobalContext, 304 sig libkb.Sig3, state *TeamSigChainState, 305 me keybase1.UserVersion) (err error) { 306 307 mctx := libkb.NewMetaContext(ctx, g) 308 309 if len(sig.Outer) == 0 || len(sig.Sig) == 0 { 310 return NewPrecheckStructuralError("got a stubbed v3 link on post, which isn't allowed", nil) 311 } 312 313 hp := hidden.NewLoaderPackageForPrecheck(mctx, state.GetID(), state.hidden) 314 ex := sig3.ExportJSON{ 315 Inner: sig.Inner, 316 Outer: sig.Outer, 317 Sig: sig.Sig, 318 } 319 err = hp.Update(mctx, []sig3.ExportJSON{ex}, keybase1.Seqno(0)) 320 if err != nil { 321 return err 322 } 323 mctx.Debug("appendChainLinkSig3 success for %s", sig.Outer) 324 return nil 325 } 326 327 func precheckLinksToPost(ctx context.Context, g *libkb.GlobalContext, 328 sigMultiItems []libkb.SigMultiItem, state *TeamSigChainState, 329 me keybase1.UserVersion) (err error) { 330 _, err = precheckLinksToState(ctx, g, sigMultiItems, state, me) 331 return err 332 } 333 334 func precheckLinksToState(ctx context.Context, g *libkb.GlobalContext, 335 sigMultiItems []libkb.SigMultiItem, state *TeamSigChainState, 336 me keybase1.UserVersion) (newState *TeamSigChainState, err error) { 337 338 defer g.CTrace(ctx, "precheckLinksToState", &err)() 339 340 isAdmin := true 341 if state != nil { 342 role, err := state.GetUserRole(me) 343 if err != nil { 344 role = keybase1.TeamRole_NONE 345 } 346 isAdmin = role.IsAdminOrAbove() 347 348 // As an optimization, AppendChainLink consumes its state. 349 // We don't consume our state parameter. 350 // So clone state before we pass it along to be consumed. 351 state = state.DeepCopyToPtr() 352 } 353 354 signer := SignerX{ 355 signer: me, 356 implicitAdmin: !isAdmin, 357 } 358 359 for i, sigItem := range sigMultiItems { 360 361 if sigItem.Sig3 != nil { 362 err = appendChainLinkSig3(ctx, g, *sigItem.Sig3, state, me) 363 if err != nil { 364 g.Log.CDebugf(ctx, "precheckLinksToState: link (sig3) %v/%v rejected: %v", i+1, len(sigMultiItems), err) 365 return nil, NewPrecheckAppendError(err) 366 } 367 continue 368 } 369 370 outerLink, err := libkb.DecodeOuterLinkV2(sigItem.Sig) 371 if err != nil { 372 return nil, NewPrecheckStructuralError("unpack outer", err) 373 } 374 375 link1 := SCChainLink{ 376 Seqno: outerLink.Seqno, 377 Sig: sigItem.Sig, 378 Payload: sigItem.SigInner, 379 UID: me.Uid, 380 Version: 2, 381 } 382 link2, err := unpackChainLink(&link1) 383 if err != nil { 384 return nil, NewPrecheckStructuralError("unpack link", err) 385 } 386 387 if link2.isStubbed() { 388 return nil, NewPrecheckStructuralError("link missing inner", nil) 389 } 390 391 newState, err := AppendChainLink(ctx, g, me, state, link2, &signer) 392 if err != nil { 393 if link2.inner != nil && link2.inner.Body.Team != nil && link2.inner.Body.Team.Members != nil { 394 g.Log.CDebugf(ctx, "precheckLinksToState: link %v/%v rejected: %v", i+1, len(sigMultiItems), spew.Sprintf("%v", *link2.inner.Body.Team.Members)) 395 } else { 396 g.Log.CDebugf(ctx, "precheckLinksToState: link %v/%v rejected", i+1, len(sigMultiItems)) 397 } 398 return nil, NewPrecheckAppendError(err) 399 } 400 state = &newState 401 } 402 403 return state, nil 404 }