/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/libkb/kbsig.go
1 265 строк
32 KB
zoom-ua
gofumpt (#28710)
17 дек 2025, 17:16
Не верифицирован
17 дек 2025, 17:16
cda510b
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. // Code used in populating JSON objects to generating Keybase-style // signatures. package libkb import ( "encoding/base64" "encoding/hex" "errors" "fmt" keybase1 "github.com/keybase/client/go/protocol/keybase1" stellar1 "github.com/keybase/client/go/protocol/stellar1" jsonw "github.com/keybase/go-jsonw" ) func clientInfo(m MetaContext) *jsonw.Wrapper { ret := jsonw.NewDictionary() _ = ret.SetKey("version", jsonw.NewString(Version)) _ = ret.SetKey("name", jsonw.NewString(GoClientID)) return ret } type KeySection struct { Key GenericKey EldestKID keybase1.KID ParentKID keybase1.KID HasRevSig bool RevSig string SigningUser UserBasic IncludePGPHash bool PerUserKeyGeneration keybase1.PerUserKeyGeneration } func LinkEntropy() (string, error) { entropyBytes, err := RandBytes(18) if err != nil { return "", fmt.Errorf("failed to generate entropy bytes: %v", err) } return base64.StdEncoding.EncodeToString(entropyBytes), nil } func (arg KeySection) ToJSON() (*jsonw.Wrapper, error) { ret := jsonw.NewDictionary() err := ret.SetKey("kid", jsonw.NewString(arg.Key.GetKID().String())) if err != nil { return nil, err } if arg.EldestKID != "" { err := ret.SetKey("eldest_kid", jsonw.NewString(arg.EldestKID.String())) if err != nil { return nil, err } } if arg.ParentKID != "" { err := ret.SetKey("parent_kid", jsonw.NewString(arg.ParentKID.String())) if err != nil { return nil, err } } if arg.HasRevSig { var revSig *jsonw.Wrapper if arg.RevSig != "" { revSig = jsonw.NewString(arg.RevSig) } else { revSig = jsonw.NewNil() } err := ret.SetKey("reverse_sig", revSig) if err != nil { return nil, err } } if arg.SigningUser != nil { err := ret.SetKey("host", jsonw.NewString(CanonicalHost)) if err != nil { return nil, err } err = ret.SetKey("uid", UIDWrapper(arg.SigningUser.GetUID())) if err != nil { return nil, err } err = ret.SetKey("username", jsonw.NewString(arg.SigningUser.GetName())) if err != nil { return nil, err } } if arg.PerUserKeyGeneration != 0 { err := ret.SetKey("generation", jsonw.NewInt(int(arg.PerUserKeyGeneration))) if err != nil { return nil, err } } if pgp, ok := arg.Key.(*PGPKeyBundle); ok { fingerprint := pgp.GetFingerprint() err := ret.SetKey("fingerprint", jsonw.NewString(fingerprint.String())) if err != nil { return nil, err } err = ret.SetKey("key_id", jsonw.NewString(fingerprint.ToKeyID())) if err != nil { return nil, err } if arg.IncludePGPHash { hash, err := pgp.FullHash() if err != nil { return nil, err } err = ret.SetKey("full_hash", jsonw.NewString(hash)) if err != nil { return nil, err } } } return ret, nil } func (u *User) ToTrackingStatementKey(errp *error) *jsonw.Wrapper { ret := jsonw.NewDictionary() if !u.HasActiveKey() { *errp = fmt.Errorf("User %s doesn't have an active key", u.GetName()) } else { kid := u.GetEldestKID() _ = ret.SetKey("kid", jsonw.NewString(kid.String())) ckf := u.GetComputedKeyFamily() if fingerprint, exists := ckf.kf.kid2pgp[kid]; exists { _ = ret.SetKey("key_fingerprint", jsonw.NewString(fingerprint.String())) } } return ret } func (u *User) ToTrackingStatementPGPKeys(errp *error) *jsonw.Wrapper { keys := u.GetActivePGPKeys(true) if len(keys) == 0 { return nil } ret := jsonw.NewArray(len(keys)) for i, k := range keys { kd := jsonw.NewDictionary() kid := k.GetKID() fp := k.GetFingerprintP() _ = kd.SetKey("kid", jsonw.NewString(kid.String())) if fp != nil { _ = kd.SetKey("key_fingerprint", jsonw.NewString(fp.String())) } _ = ret.SetIndex(i, kd) } return ret } func (u *User) ToTrackingStatementBasics(errp *error) *jsonw.Wrapper { ret := jsonw.NewDictionary() _ = ret.SetKey("username", jsonw.NewString(u.name)) if lastIDChange, err := u.basics.AtKey("last_id_change").GetInt(); err == nil { _ = ret.SetKey("last_id_change", jsonw.NewInt(lastIDChange)) } if idVersion, err := u.basics.AtKey("id_version").GetInt(); err == nil { _ = ret.SetKey("id_version", jsonw.NewInt(idVersion)) } return ret } func (u *User) ToTrackingStatementSeqTail() *jsonw.Wrapper { mul := u.GetPublicChainTail() if mul == nil { return jsonw.NewNil() } ret := jsonw.NewDictionary() _ = ret.SetKey("sig_id", jsonw.NewString(mul.SigID.ToSigIDLegacy().String())) _ = ret.SetKey("seqno", jsonw.NewInt(int(mul.Seqno))) _ = ret.SetKey("payload_hash", jsonw.NewString(mul.LinkID.String())) return ret } func (u *User) ToTrackingStatement(w *jsonw.Wrapper, outcome *IdentifyOutcome) (err error) { track := jsonw.NewDictionary() if u.HasActiveKey() { key := u.ToTrackingStatementKey(&err) if key != nil { _ = track.SetKey("key", key) } } if pgpkeys := u.ToTrackingStatementPGPKeys(&err); pgpkeys != nil { err := track.SetKey("pgp_keys", pgpkeys) if err != nil { return err } } err = track.SetKey("seq_tail", u.ToTrackingStatementSeqTail()) if err != nil { return err } err = track.SetKey("basics", u.ToTrackingStatementBasics(&err)) if err != nil { return err } err = track.SetKey("id", UIDWrapper(u.id)) if err != nil { return err } err = track.SetKey("remote_proofs", outcome.TrackingStatement()) if err != nil { return err } entropy, err := LinkEntropy() if err != nil { return err } err = track.SetKey("entropy", jsonw.NewString(entropy)) if err != nil { return err } return w.SetKey("track", track) } func (u *User) ToWotStatement() *jsonw.Wrapper { user := jsonw.NewDictionary() _ = user.SetKey("username", jsonw.NewString(u.GetNormalizedName().String())) _ = user.SetKey("uid", UIDWrapper(u.GetUID())) _ = user.SetKey("seq_tail", u.ToTrackingStatementSeqTail()) eldest := jsonw.NewDictionary() _ = eldest.SetKey("kid", jsonw.NewString(u.GetEldestKID().String())) _ = eldest.SetKey("seqno", jsonw.NewInt64(int64(u.GetCurrentEldestSeqno()))) _ = user.SetKey("eldest", eldest) return user } func (u *User) ToUntrackingStatementBasics() *jsonw.Wrapper { ret := jsonw.NewDictionary() _ = ret.SetKey("username", jsonw.NewString(u.name)) return ret } func (u *User) ToUntrackingStatement(w *jsonw.Wrapper) (err error) { untrack := jsonw.NewDictionary() err = untrack.SetKey("basics", u.ToUntrackingStatementBasics()) if err != nil { return err } err = untrack.SetKey("id", UIDWrapper(u.GetUID())) if err != nil { return err } entropy, err := LinkEntropy() if err != nil { return err } err = untrack.SetKey("entropy", jsonw.NewString(entropy)) if err != nil { return err } return w.SetKey("untrack", untrack) } func (g *GenericChainLink) BaseToTrackingStatement(state keybase1.ProofState) *jsonw.Wrapper { ret := jsonw.NewDictionary() _ = ret.SetKey("curr", jsonw.NewString(g.id.String())) _ = ret.SetKey("sig_id", jsonw.NewString(g.GetSigID().String())) rkp := jsonw.NewDictionary() _ = ret.SetKey("remote_key_proof", rkp) _ = rkp.SetKey("state", jsonw.NewInt(int(state))) prev := g.GetPrev() var prevVal *jsonw.Wrapper if prev == nil { prevVal = jsonw.NewNil() } else { prevVal = jsonw.NewString(prev.String()) } _ = ret.SetKey("prev", prevVal) _ = ret.SetKey("ctime", jsonw.NewInt64(g.unpacked.ctime)) _ = ret.SetKey("etime", jsonw.NewInt64(g.unpacked.etime)) return ret } func remoteProofToTrackingStatement(s RemoteProofChainLink, base *jsonw.Wrapper) { proofType := s.GetProofType() _ = base.AtKey("remote_key_proof").SetKey("proof_type", jsonw.NewInt(int(proofType))) _ = base.AtKey("remote_key_proof").SetKey("check_data_json", s.CheckDataJSON()) _ = base.SetKey("sig_type", jsonw.NewInt(SigTypeRemoteProof)) } type HighSkip struct { Seqno keybase1.Seqno Hash LinkID } func NewHighSkip(highSkipSeqno keybase1.Seqno, highSkipHash LinkID) HighSkip { return HighSkip{ Seqno: highSkipSeqno, Hash: highSkipHash, } } func NewInitialHighSkip() HighSkip { return NewHighSkip(keybase1.Seqno(0), nil) } func (h HighSkip) AssertEqualsExpected(expected HighSkip) error { if expected.Seqno != h.Seqno { return fmt.Errorf("Expected highSkip.Seqno %d, got %d.", expected.Seqno, h.Seqno) } if !expected.Hash.Eq(h.Hash) { return fmt.Errorf("Expected highSkip.Hash %s, got %s.", expected.Hash.String(), h.Hash.String()) } return nil } type ProofMetadata struct { Me *User SigningUser UserBasic Seqno keybase1.Seqno PrevLinkID LinkID LinkType LinkType SigningKey GenericKey Eldest keybase1.KID CreationTime int64 ExpireIn int IncludePGPHash bool SigVersion SigVersion SeqType keybase1.SeqType MerkleRoot *MerkleRoot IgnoreIfUnsupported SigIgnoreIfUnsupported // HighSkipFallback is used for teams to provide for a KEX-provisisonee to // provide the provisioner's information as the latest high link. HighSkipFallback *HighSkip } type ProofMetadataRes struct { J *jsonw.Wrapper Seqno keybase1.Seqno } func (arg ProofMetadata) merkleRootInfo(m MetaContext) (ret *jsonw.Wrapper) { if mr := arg.MerkleRoot; mr != nil { return mr.ToSigJSON() } if mc := m.G().MerkleClient; mc != nil { ret, _ = mc.LastRootToSigJSON(m) } return ret } func (arg ProofMetadata) ToJSON(m MetaContext) (*jsonw.Wrapper, error) { res, err := arg.ToJSON2(m) if err != nil { return nil, err } return res.J, nil } func (arg ProofMetadata) ToJSON2(m MetaContext) (ret *ProofMetadataRes, err error) { // if only Me exists, then that is the signing user too if arg.SigningUser == nil && arg.Me != nil { arg.SigningUser = arg.Me } var seqno keybase1.Seqno var prev *jsonw.Wrapper // sanity check the seqno and prev relationship if arg.Seqno > 1 && len(arg.PrevLinkID) == 0 { return nil, fmt.Errorf("can't have a seqno > 1 without a prev value") } if arg.Seqno > 0 { seqno = arg.Seqno if arg.Seqno == 1 { prev = jsonw.NewNil() } else { prev = jsonw.NewString(arg.PrevLinkID.String()) } } else { if arg.Me == nil { return nil, fmt.Errorf("missing self user object while signing") } lastSeqno := arg.Me.sigChain().GetLastKnownSeqno() lastLink := arg.Me.sigChain().GetLastKnownID() if lastLink == nil { seqno = 1 prev = jsonw.NewNil() } else { seqno = lastSeqno + 1 prev = jsonw.NewString(lastLink.String()) } } ctime := arg.CreationTime if ctime == 0 { ctime = m.G().Clock().Now().Unix() } ei := arg.ExpireIn if ei == 0 { ei = SigExpireIn } j := jsonw.NewDictionary() err = j.SetKey("tag", jsonw.NewString("signature")) if err != nil { return nil, err } err = j.SetKey("ctime", jsonw.NewInt64(ctime)) if err != nil { return nil, err } err = j.SetKey("expire_in", jsonw.NewInt(ei)) if err != nil { return nil, err } err = j.SetKey("seqno", jsonw.NewInt64(int64(seqno))) if err != nil { return nil, err } err = j.SetKey("prev", prev) if err != nil { return nil, err } var highSkip *HighSkip allowHighSkips := m.G().Env.GetFeatureFlags().HasFeature(EnvironmentFeatureAllowHighSkips) if allowHighSkips { if (arg.Me != nil) && (arg.HighSkipFallback != nil) { return nil, fmt.Errorf("arg.Me and arg.HighSkipFallback can't both be non-nil.") } else if arg.Me != nil { highSkipPre, err := arg.Me.GetExpectedNextHighSkip(m) if err != nil { return nil, err } highSkip = &highSkipPre } else if arg.HighSkipFallback != nil { highSkip = arg.HighSkipFallback } if highSkip != nil { highSkipObj := jsonw.NewDictionary() err := highSkipObj.SetKey("seqno", jsonw.NewInt64(int64(highSkip.Seqno))) if err != nil { return nil, err } if hash := highSkip.Hash; hash != nil { err := highSkipObj.SetKey("hash", jsonw.NewString(hash.String())) if err != nil { return nil, err } } else { err := highSkipObj.SetKey("hash", jsonw.NewNil()) if err != nil { return nil, err } } err = j.SetKey("high_skip", highSkipObj) if err != nil { return nil, err } } } if arg.IgnoreIfUnsupported { err := j.SetKey("ignore_if_unsupported", jsonw.NewBool(true)) if err != nil { return nil, err } } eldest := arg.Eldest if eldest == "" { if arg.Me == nil { return nil, fmt.Errorf("missing self user object while signing") } eldest = arg.Me.GetEldestKID() } body := jsonw.NewDictionary() if arg.SigVersion != 0 { err := body.SetKey("version", jsonw.NewInt(int(arg.SigVersion))) if err != nil { return nil, err } } else { err := body.SetKey("version", jsonw.NewInt(int(KeybaseSignatureV1))) if err != nil { return nil, err } } err = body.SetKey("type", jsonw.NewString(string(arg.LinkType))) if err != nil { return nil, err } key, err := KeySection{ Key: arg.SigningKey, EldestKID: eldest, SigningUser: arg.SigningUser, IncludePGPHash: arg.IncludePGPHash, }.ToJSON() if err != nil { return nil, err } err = body.SetKey("key", key) if err != nil { return nil, err } // Capture the most recent Merkle Root, inside of "body" // field. if mr := arg.merkleRootInfo(m); mr != nil { err := body.SetKey("merkle_root", mr) if err != nil { return nil, err } } err = j.SetKey("body", body) if err != nil { return nil, err } // Save what kind of client we're running. err = j.SetKey("client", clientInfo(m)) if err != nil { return nil, err } if arg.SeqType != 0 { err := j.SetKey("seq_type", jsonw.NewInt(int(arg.SeqType))) if err != nil { return nil, err } } return &ProofMetadataRes{ J: j, Seqno: seqno, }, nil } func (u *User) TrackingProofFor(m MetaContext, signingKey GenericKey, sigVersion SigVersion, u2 *User, outcome *IdentifyOutcome) (*ProofMetadataRes, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeTrack, SigningKey: signingKey, SigVersion: sigVersion, }.ToJSON2(m) if err == nil { err = u2.ToTrackingStatement(ret.J.AtKey("body"), outcome) } return ret, err } func (u *User) UntrackingProofFor(m MetaContext, signingKey GenericKey, sigVersion SigVersion, u2 *User) (*ProofMetadataRes, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeUntrack, SigningKey: signingKey, SigVersion: sigVersion, }.ToJSON2(m) if err == nil { err = u2.ToUntrackingStatement(ret.J.AtKey("body")) } return ret, err } // arg.Me user is used to get the last known seqno in ProofMetadata. // If arg.Me == nil, set arg.Seqno. func KeyProof(m MetaContext, arg Delegator) (*jsonw.Wrapper, error) { res, err := KeyProof2(m, arg) if err != nil { return nil, err } return res.J, nil } // arg.Me user is used to get the last known seqno in ProofMetadata. // If arg.Me == nil, set arg.Seqno. func KeyProof2(m MetaContext, arg Delegator) (ret *ProofMetadataRes, err error) { var kp *jsonw.Wrapper includePGPHash := false if arg.DelegationType == DelegationTypeEldest { includePGPHash = true } else if arg.NewKey != nil { keySection := KeySection{ Key: arg.NewKey, } switch arg.DelegationType { case DelegationTypePGPUpdate: keySection.IncludePGPHash = true case DelegationTypeSibkey: keySection.HasRevSig = true keySection.RevSig = arg.RevSig keySection.IncludePGPHash = true default: keySection.ParentKID = arg.ExistingKey.GetKID() } if kp, err = keySection.ToJSON(); err != nil { return nil, err } } // Only set the fallback for subkeys during KEX where arg.Me == nil; it is // otherwise updated using me.SigChainBump(). var highSkipFallback *HighSkip if arg.Me == nil && arg.DelegationType == DelegationTypeSubkey { highSkip := NewHighSkip(arg.Seqno-1, arg.PrevLinkID) highSkipFallback = &highSkip } ret, err = ProofMetadata{ Me: arg.Me, SigningUser: arg.SigningUser, LinkType: LinkType(arg.DelegationType), ExpireIn: arg.Expire, SigningKey: arg.GetSigningKey(), Eldest: arg.EldestKID, CreationTime: arg.Ctime, IncludePGPHash: includePGPHash, Seqno: arg.Seqno, HighSkipFallback: highSkipFallback, PrevLinkID: arg.PrevLinkID, MerkleRoot: arg.MerkleRoot, }.ToJSON2(m) if err != nil { return nil, err } body := ret.J.AtKey("body") if arg.Device != nil { device := *arg.Device device.Kid = arg.NewKey.GetKID() var dw *jsonw.Wrapper dw, err = device.Export(LinkType(arg.DelegationType)) if err != nil { return nil, err } err = body.SetKey("device", dw) if err != nil { return nil, err } } if kp != nil { err := body.SetKey(string(arg.DelegationType), kp) if err != nil { return nil, err } } return ret, nil } func (u *User) ServiceProof(m MetaContext, signingKey GenericKey, typ ServiceType, remotename string, sigVersion SigVersion) (*ProofMetadataRes, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeWebServiceBinding, SigningKey: signingKey, SigVersion: sigVersion, }.ToJSON2(m) if err != nil { return nil, err } service := typ.ToServiceJSON(remotename) entropy, err := LinkEntropy() if err != nil { return nil, err } err = service.SetKey("entropy", jsonw.NewString(entropy)) if err != nil { return nil, err } err = ret.J.AtKey("body").SetKey("service", service) if err != nil { return nil, err } return ret, nil } func (u *User) WotVouchProof(m MetaContext, signingKey GenericKey, sigVersion SigVersion, mac []byte, merkleRoot *MerkleRoot, sigIDToRevoke *keybase1.SigID) (*ProofMetadataRes, error) { md := ProofMetadata{ Me: u, LinkType: LinkTypeWotVouch, MerkleRoot: merkleRoot, SigningKey: signingKey, SigVersion: sigVersion, IgnoreIfUnsupported: true, } ret, err := md.ToJSON2(m) if err != nil { return nil, err } body := ret.J.AtKey("body") if err := body.SetKey("wot_vouch", jsonw.NewString(hex.EncodeToString(mac))); err != nil { return nil, err } if sigIDToRevoke != nil { revokeSection := jsonw.NewDictionary() err := revokeSection.SetKey("sig_id", jsonw.NewString(sigIDToRevoke.String())) if err != nil { return nil, err } err = body.SetKey("revoke", revokeSection) if err != nil { return nil, err } } return ret, nil } func (u *User) WotReactProof(m MetaContext, signingKey GenericKey, sigVersion SigVersion, mac []byte) (*ProofMetadataRes, error) { md := ProofMetadata{ Me: u, LinkType: LinkTypeWotReact, SigningKey: signingKey, SigVersion: sigVersion, IgnoreIfUnsupported: true, } ret, err := md.ToJSON2(m) if err != nil { return nil, err } body := ret.J.AtKey("body") if err := body.SetKey("wot_react", jsonw.NewString(hex.EncodeToString(mac))); err != nil { return nil, err } return ret, nil } // SimpleSignJson marshals the given Json structure and then signs it. func SignJSON(jw *jsonw.Wrapper, key GenericKey) (out string, id keybase1.SigIDBase, lid LinkID, err error) { var tmp []byte if tmp, err = jw.Marshal(); err != nil { return } out, id, err = key.SignToString(tmp) lid = ComputeLinkID(tmp) return } func GetDefaultSigVersion(g *GlobalContext) SigVersion { return KeybaseSignatureV2 } func MakeSig( m MetaContext, signingKey GenericKey, v1LinkType LinkType, innerLinkJSON []byte, hasRevokes SigHasRevokes, seqType keybase1.SeqType, ignoreIfUnsupported SigIgnoreIfUnsupported, me *User, sigVersion SigVersion, ) (sig string, sigID keybase1.SigID, linkID LinkID, err error) { switch sigVersion { case KeybaseSignatureV1: var sigIDBase keybase1.SigIDBase sig, sigIDBase, err = signingKey.SignToString(innerLinkJSON) linkID = ComputeLinkID(innerLinkJSON) params := keybase1.SigIDSuffixParametersFromTypeAndVersion(string(v1LinkType), keybase1.SigVersion(sigVersion)) sigID = sigIDBase.ToSigID(params) case KeybaseSignatureV2: prevSeqno := me.GetSigChainLastKnownSeqno() prevLinkID := me.GetSigChainLastKnownID() highSkip, highSkipErr := me.GetExpectedNextHighSkip(m) if highSkipErr != nil { return sig, sigID, linkID, highSkipErr } sig, sigID, linkID, err = MakeSigchainV2OuterSig( m, signingKey, v1LinkType, prevSeqno+1, innerLinkJSON, prevLinkID, hasRevokes, seqType, ignoreIfUnsupported, &highSkip, ) default: err = errors.New("Invalid Signature Version") } return sig, sigID, linkID, err } func (u *User) RevokeKeysProof(m MetaContext, key GenericKey, kidsToRevoke []keybase1.KID, deviceToDisable keybase1.DeviceID, merkleRoot *MerkleRoot, ) (*ProofMetadataRes, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeRevoke, SigningKey: key, MerkleRoot: merkleRoot, }.ToJSON2(m) if err != nil { return nil, err } body := ret.J.AtKey("body") revokeSection := jsonw.NewDictionary() err = revokeSection.SetKey("kids", jsonw.NewWrapper(kidsToRevoke)) if err != nil { return nil, err } err = body.SetKey("revoke", revokeSection) if err != nil { return nil, err } if deviceToDisable.Exists() { device, err := u.GetDevice(deviceToDisable) if err != nil { return nil, err } deviceSection := jsonw.NewDictionary() err = deviceSection.SetKey("id", jsonw.NewString(deviceToDisable.String())) if err != nil { return nil, err } err = deviceSection.SetKey("type", jsonw.NewString(device.Type.String())) if err != nil { return nil, err } err = deviceSection.SetKey("status", jsonw.NewInt(DeviceStatusDefunct)) if err != nil { return nil, err } err = body.SetKey("device", deviceSection) if err != nil { return nil, err } } return ret, nil } func (u *User) RevokeSigsProof(m MetaContext, key GenericKey, sigIDsToRevoke []keybase1.SigID, merkleRoot *MerkleRoot) (*ProofMetadataRes, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeRevoke, SigningKey: key, MerkleRoot: merkleRoot, }.ToJSON2(m) if err != nil { return nil, err } body := ret.J.AtKey("body") revokeSection := jsonw.NewDictionary() idsArray := jsonw.NewArray(len(sigIDsToRevoke)) for i, id := range sigIDsToRevoke { err := idsArray.SetIndex(i, jsonw.NewString(id.String())) if err != nil { return nil, err } } err = revokeSection.SetKey("sig_ids", idsArray) if err != nil { return nil, err } err = body.SetKey("revoke", revokeSection) if err != nil { return nil, err } return ret, nil } func (u *User) CryptocurrencySig(m MetaContext, key GenericKey, address string, typ CryptocurrencyType, sigToRevoke keybase1.SigID, merkleRoot *MerkleRoot, sigVersion SigVersion) (*ProofMetadataRes, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeCryptocurrency, SigningKey: key, MerkleRoot: merkleRoot, SigVersion: sigVersion, }.ToJSON2(m) if err != nil { return nil, err } body := ret.J.AtKey("body") currencySection := jsonw.NewDictionary() err = currencySection.SetKey("address", jsonw.NewString(address)) if err != nil { return nil, err } err = currencySection.SetKey("type", jsonw.NewString(typ.String())) if err != nil { return nil, err } entropy, err := LinkEntropy() if err != nil { return nil, err } err = currencySection.SetKey("entropy", jsonw.NewString(entropy)) if err != nil { return nil, err } err = body.SetKey("cryptocurrency", currencySection) if err != nil { return nil, err } if len(sigToRevoke) > 0 { revokeSection := jsonw.NewDictionary() err := revokeSection.SetKey("sig_id", jsonw.NewString(sigToRevoke.String())) if err != nil { return nil, err } err = body.SetKey("revoke", revokeSection) if err != nil { return nil, err } } return ret, nil } func (u *User) UpdatePassphraseProof(m MetaContext, key GenericKey, pwh string, ppGen PassphraseGeneration, pdpka5kid string) (*jsonw.Wrapper, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeUpdatePassphrase, SigningKey: key, }.ToJSON(m) if err != nil { return nil, err } body := ret.AtKey("body") pp := jsonw.NewDictionary() err = pp.SetKey("hash", jsonw.NewString(pwh)) if err != nil { return nil, err } err = pp.SetKey("pdpka5_kid", jsonw.NewString(pdpka5kid)) if err != nil { return nil, err } err = pp.SetKey("version", jsonw.NewInt(int(ClientTriplesecVersion))) if err != nil { return nil, err } err = pp.SetKey("passphrase_generation", jsonw.NewInt(int(ppGen))) if err != nil { return nil, err } err = body.SetKey("update_passphrase_hash", pp) if err != nil { return nil, err } return ret, nil } func (u *User) UpdateEmailProof(m MetaContext, key GenericKey, newEmail string) (*jsonw.Wrapper, error) { ret, err := ProofMetadata{ Me: u, LinkType: LinkTypeUpdateSettings, SigningKey: key, }.ToJSON(m) if err != nil { return nil, err } body := ret.AtKey("body") settings := jsonw.NewDictionary() err = settings.SetKey("email", jsonw.NewString(newEmail)) if err != nil { return nil, err } err = body.SetKey("update_settings", settings) if err != nil { return nil, err } return ret, nil } type SigMultiItem struct { Sig3 *Sig3 `json:"sig3,omitempty"` Sig string `json:"sig,omitempty"` SigningKID keybase1.KID `json:"signing_kid"` Type string `json:"type"` SeqType keybase1.SeqType `json:"seq_type"` SigInner string `json:"sig_inner"` TeamID keybase1.TeamID `json:"team_id,omitempty"` PublicKeys *SigMultiItemPublicKeys `json:"public_keys,omitempty"` Version SigVersion `json:"version"` Expansions *jsonw.Wrapper `json:"expansions,omitempty"` } type SigMultiItemPublicKeys struct { Encryption keybase1.KID `json:"encryption"` Signing keybase1.KID `json:"signing"` } type Sig3 struct { Inner string `json:"i,omitempty"` Outer string `json:"o,omitempty"` Sig string `json:"s,omitempty"` } // PerUserKeyProof creates a proof introducing a new per-user-key generation. // `signingKey` is the key signing in this new key. Not to be confused with the derived per-user-key signing key. func PerUserKeyProof(m MetaContext, me *User, pukSigKID keybase1.KID, pukEncKID keybase1.KID, generation keybase1.PerUserKeyGeneration, signingKey GenericKey, ) (*ProofMetadataRes, error) { if me == nil { return nil, fmt.Errorf("missing user object for proof") } ret, err := ProofMetadata{ Me: me, LinkType: LinkTypePerUserKey, SigningKey: signingKey, }.ToJSON2(m) if err != nil { return nil, err } pukSection := jsonw.NewDictionary() err = pukSection.SetKey("signing_kid", jsonw.NewString(pukSigKID.String())) if err != nil { return nil, err } err = pukSection.SetKey("encryption_kid", jsonw.NewString(pukEncKID.String())) if err != nil { return nil, err } err = pukSection.SetKey("generation", jsonw.NewInt(int(generation))) if err != nil { return nil, err } // The caller is responsible for overwriting reverse_sig after signing. err = pukSection.SetKey("reverse_sig", jsonw.NewNil()) if err != nil { return nil, err } body := ret.J.AtKey("body") err = body.SetKey("per_user_key", pukSection) if err != nil { return nil, err } return ret, nil } type UserLinkSignature struct { Payload JSONPayload Seqno keybase1.Seqno LinkID LinkID } // Make a per-user key proof with a reverse sig. // Modifies the User `me` with a sigchain bump and key delegation. // Returns a JSONPayload ready for use in "sigs" in sig/multi. func PerUserKeyProofReverseSigned(m MetaContext, me *User, perUserKeySeed PerUserKeySeed, generation keybase1.PerUserKeyGeneration, signer GenericKey, ) (*UserLinkSignature, error) { pukSigKey, err := perUserKeySeed.DeriveSigningKey() if err != nil { return nil, err } pukEncKey, err := perUserKeySeed.DeriveDHKey() if err != nil { return nil, err } // Make reverse sig forward, err := PerUserKeyProof(m, me, pukSigKey.GetKID(), pukEncKey.GetKID(), generation, signer) if err != nil { return nil, err } reverseSig, _, _, err := SignJSON(forward.J, pukSigKey) if err != nil { return nil, err } // Make sig jw := forward.J err = jw.SetValueAtPath("body.per_user_key.reverse_sig", jsonw.NewString(reverseSig)) if err != nil { return nil, err } sig, sigID, linkID, err := SignJSON(jw, signer) if err != nil { return nil, err } // Update the user locally me.SigChainBump(linkID, sigID.ToSigIDLegacy(), false) err = me.localDelegatePerUserKey(keybase1.PerUserKey{ Gen: int(generation), Seqno: me.GetSigChainLastKnownSeqno(), SigKID: pukSigKey.GetKID(), EncKID: pukEncKey.GetKID(), SignedByKID: signer.GetKID(), }) if err != nil { return nil, err } publicKeysEntry := make(JSONPayload) publicKeysEntry["signing"] = pukSigKey.GetKID().String() publicKeysEntry["encryption"] = pukEncKey.GetKID().String() payload := make(JSONPayload) payload["sig"] = sig payload["signing_kid"] = signer.GetKID().String() payload["type"] = LinkTypePerUserKey payload["public_keys"] = publicKeysEntry return &UserLinkSignature{ Payload: payload, Seqno: forward.Seqno, LinkID: linkID, }, nil } // StellarProof creates a proof of a stellar wallet. func StellarProof(m MetaContext, me *User, walletAddress stellar1.AccountID, signingKey GenericKey, ) (*ProofMetadataRes, error) { if me == nil { return nil, fmt.Errorf("missing user object for proof") } walletPubKey, err := MakeNaclSigningKeyPairFromStellarAccountID(walletAddress) if err != nil { return nil, err } walletKID := walletPubKey.GetKID() ret, err := ProofMetadata{ Me: me, LinkType: LinkTypeWalletStellar, SigningKey: signingKey, SigVersion: KeybaseSignatureV2, IgnoreIfUnsupported: SigIgnoreIfUnsupported(true), }.ToJSON2(m) if err != nil { return nil, err } walletSection := jsonw.NewDictionary() err = walletSection.SetKey("address", jsonw.NewString(walletAddress.String())) if err != nil { return nil, err } err = walletSection.SetKey("network", jsonw.NewString(string(WalletNetworkStellar))) if err != nil { return nil, err } // Inner links can be hidden. To prevent an attacker from figuring out the // contents from the hash of the inner link, add 18 random bytes. entropy, err := LinkEntropy() if err != nil { return nil, err } err = walletSection.SetKey("entropy", jsonw.NewString(entropy)) if err != nil { return nil, err } walletKeySection := jsonw.NewDictionary() err = walletKeySection.SetKey("kid", jsonw.NewString(walletKID.String())) if err != nil { return nil, err } // The caller is responsible for overwriting reverse_sig after signing. err = walletKeySection.SetKey("reverse_sig", jsonw.NewNil()) if err != nil { return nil, err } body := ret.J.AtKey("body") err = body.SetKey("wallet", walletSection) if err != nil { return nil, err } err = body.SetKey("wallet_key", walletKeySection) if err != nil { return nil, err } return ret, nil } // Make a stellar proof with a reverse sig. // Modifies the User `me` with a sigchain bump and key delegation. // Returns a JSONPayload ready for use in "sigs" in sig/multi. func StellarProofReverseSigned(m MetaContext, me *User, walletAddress stellar1.AccountID, stellarSigner stellar1.SecretKey, deviceSigner GenericKey, ) (*UserLinkSignature, error) { // Make reverse sig forward, err := StellarProof(m, me, walletAddress, deviceSigner) if err != nil { return nil, err } stellarSignerKey, err := MakeNaclSigningKeyPairFromStellarSecretKey(stellarSigner) if err != nil { return nil, err } reverseSig, _, _, err := SignJSON(forward.J, stellarSignerKey) if err != nil { return nil, err } // Make sig jw := forward.J err = jw.SetValueAtPath("body.wallet_key.reverse_sig", jsonw.NewString(reverseSig)) if err != nil { return nil, err } innerJSON, err := jw.Marshal() if err != nil { return nil, err } sig, sigID, linkID, err := MakeSig( m, deviceSigner, LinkTypeWalletStellar, innerJSON, SigHasRevokes(false), keybase1.SeqType_PUBLIC, SigIgnoreIfUnsupported(true), me, KeybaseSignatureV2, ) if err != nil { return nil, err } // Update the user locally me.SigChainBump(linkID, sigID, false) // TODO: do we need to locally do something like me.localDelegatePerUserKey? payload := make(JSONPayload) payload["sig"] = sig payload["sig_inner"] = string(innerJSON) payload["signing_kid"] = deviceSigner.GetKID().String() payload["public_key"] = stellarSignerKey.GetKID().String() payload["type"] = LinkTypeWalletStellar return &UserLinkSignature{ Payload: payload, Seqno: forward.Seqno, LinkID: linkID, }, nil }