github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/kbsig.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  // Code used in populating JSON objects to generating Keybase-style
     5  // signatures.
     6  package libkb
     7  
     8  import (
     9  	"encoding/base64"
    10  	"encoding/hex"
    11  	"errors"
    12  	"fmt"
    13  
    14  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    15  	stellar1 "github.com/keybase/client/go/protocol/stellar1"
    16  	jsonw "github.com/keybase/go-jsonw"
    17  )
    18  
    19  func clientInfo(m MetaContext) *jsonw.Wrapper {
    20  	ret := jsonw.NewDictionary()
    21  	_ = ret.SetKey("version", jsonw.NewString(Version))
    22  	_ = ret.SetKey("name", jsonw.NewString(GoClientID))
    23  	return ret
    24  }
    25  
    26  type KeySection struct {
    27  	Key                  GenericKey
    28  	EldestKID            keybase1.KID
    29  	ParentKID            keybase1.KID
    30  	HasRevSig            bool
    31  	RevSig               string
    32  	SigningUser          UserBasic
    33  	IncludePGPHash       bool
    34  	PerUserKeyGeneration keybase1.PerUserKeyGeneration
    35  }
    36  
    37  func LinkEntropy() (string, error) {
    38  	entropyBytes, err := RandBytes(18)
    39  	if err != nil {
    40  		return "", fmt.Errorf("failed to generate entropy bytes: %v", err)
    41  	}
    42  	return base64.StdEncoding.EncodeToString(entropyBytes), nil
    43  }
    44  
    45  func (arg KeySection) ToJSON() (*jsonw.Wrapper, error) {
    46  	ret := jsonw.NewDictionary()
    47  
    48  	err := ret.SetKey("kid", jsonw.NewString(arg.Key.GetKID().String()))
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	if arg.EldestKID != "" {
    54  		err := ret.SetKey("eldest_kid", jsonw.NewString(arg.EldestKID.String()))
    55  		if err != nil {
    56  			return nil, err
    57  		}
    58  	}
    59  
    60  	if arg.ParentKID != "" {
    61  		err := ret.SetKey("parent_kid", jsonw.NewString(arg.ParentKID.String()))
    62  		if err != nil {
    63  			return nil, err
    64  		}
    65  	}
    66  
    67  	if arg.HasRevSig {
    68  		var revSig *jsonw.Wrapper
    69  		if arg.RevSig != "" {
    70  			revSig = jsonw.NewString(arg.RevSig)
    71  		} else {
    72  			revSig = jsonw.NewNil()
    73  		}
    74  		err := ret.SetKey("reverse_sig", revSig)
    75  		if err != nil {
    76  			return nil, err
    77  		}
    78  	}
    79  
    80  	if arg.SigningUser != nil {
    81  		err := ret.SetKey("host", jsonw.NewString(CanonicalHost))
    82  		if err != nil {
    83  			return nil, err
    84  		}
    85  		err = ret.SetKey("uid", UIDWrapper(arg.SigningUser.GetUID()))
    86  		if err != nil {
    87  			return nil, err
    88  		}
    89  		err = ret.SetKey("username", jsonw.NewString(arg.SigningUser.GetName()))
    90  		if err != nil {
    91  			return nil, err
    92  		}
    93  	}
    94  
    95  	if arg.PerUserKeyGeneration != 0 {
    96  		err := ret.SetKey("generation", jsonw.NewInt(int(arg.PerUserKeyGeneration)))
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  	}
   101  
   102  	if pgp, ok := arg.Key.(*PGPKeyBundle); ok {
   103  		fingerprint := pgp.GetFingerprint()
   104  		err := ret.SetKey("fingerprint", jsonw.NewString(fingerprint.String()))
   105  		if err != nil {
   106  			return nil, err
   107  		}
   108  		err = ret.SetKey("key_id", jsonw.NewString(fingerprint.ToKeyID()))
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  		if arg.IncludePGPHash {
   113  			hash, err := pgp.FullHash()
   114  			if err != nil {
   115  				return nil, err
   116  			}
   117  
   118  			err = ret.SetKey("full_hash", jsonw.NewString(hash))
   119  			if err != nil {
   120  				return nil, err
   121  			}
   122  		}
   123  	}
   124  
   125  	return ret, nil
   126  }
   127  
   128  func (u *User) ToTrackingStatementKey(errp *error) *jsonw.Wrapper {
   129  	ret := jsonw.NewDictionary()
   130  
   131  	if !u.HasActiveKey() {
   132  		*errp = fmt.Errorf("User %s doesn't have an active key", u.GetName())
   133  	} else {
   134  		kid := u.GetEldestKID()
   135  		_ = ret.SetKey("kid", jsonw.NewString(kid.String()))
   136  		ckf := u.GetComputedKeyFamily()
   137  		if fingerprint, exists := ckf.kf.kid2pgp[kid]; exists {
   138  			_ = ret.SetKey("key_fingerprint", jsonw.NewString(fingerprint.String()))
   139  		}
   140  	}
   141  	return ret
   142  }
   143  
   144  func (u *User) ToTrackingStatementPGPKeys(errp *error) *jsonw.Wrapper {
   145  	keys := u.GetActivePGPKeys(true)
   146  	if len(keys) == 0 {
   147  		return nil
   148  	}
   149  
   150  	ret := jsonw.NewArray(len(keys))
   151  	for i, k := range keys {
   152  		kd := jsonw.NewDictionary()
   153  		kid := k.GetKID()
   154  		fp := k.GetFingerprintP()
   155  		_ = kd.SetKey("kid", jsonw.NewString(kid.String()))
   156  		if fp != nil {
   157  			_ = kd.SetKey("key_fingerprint", jsonw.NewString(fp.String()))
   158  		}
   159  		_ = ret.SetIndex(i, kd)
   160  	}
   161  	return ret
   162  }
   163  
   164  func (u *User) ToTrackingStatementBasics(errp *error) *jsonw.Wrapper {
   165  	ret := jsonw.NewDictionary()
   166  	_ = ret.SetKey("username", jsonw.NewString(u.name))
   167  	if lastIDChange, err := u.basics.AtKey("last_id_change").GetInt(); err == nil {
   168  		_ = ret.SetKey("last_id_change", jsonw.NewInt(lastIDChange))
   169  	}
   170  	if idVersion, err := u.basics.AtKey("id_version").GetInt(); err == nil {
   171  		_ = ret.SetKey("id_version", jsonw.NewInt(idVersion))
   172  	}
   173  	return ret
   174  }
   175  
   176  func (u *User) ToTrackingStatementSeqTail() *jsonw.Wrapper {
   177  	mul := u.GetPublicChainTail()
   178  	if mul == nil {
   179  		return jsonw.NewNil()
   180  	}
   181  	ret := jsonw.NewDictionary()
   182  	_ = ret.SetKey("sig_id", jsonw.NewString(mul.SigID.ToSigIDLegacy().String()))
   183  	_ = ret.SetKey("seqno", jsonw.NewInt(int(mul.Seqno)))
   184  	_ = ret.SetKey("payload_hash", jsonw.NewString(mul.LinkID.String()))
   185  	return ret
   186  }
   187  
   188  func (u *User) ToTrackingStatement(w *jsonw.Wrapper, outcome *IdentifyOutcome) (err error) {
   189  
   190  	track := jsonw.NewDictionary()
   191  	if u.HasActiveKey() {
   192  		key := u.ToTrackingStatementKey(&err)
   193  		if key != nil {
   194  			_ = track.SetKey("key", key)
   195  		}
   196  	}
   197  	if pgpkeys := u.ToTrackingStatementPGPKeys(&err); pgpkeys != nil {
   198  		err := track.SetKey("pgp_keys", pgpkeys)
   199  		if err != nil {
   200  			return err
   201  		}
   202  	}
   203  	err = track.SetKey("seq_tail", u.ToTrackingStatementSeqTail())
   204  	if err != nil {
   205  		return err
   206  	}
   207  	err = track.SetKey("basics", u.ToTrackingStatementBasics(&err))
   208  	if err != nil {
   209  		return err
   210  	}
   211  	err = track.SetKey("id", UIDWrapper(u.id))
   212  	if err != nil {
   213  		return err
   214  	}
   215  	err = track.SetKey("remote_proofs", outcome.TrackingStatement())
   216  	if err != nil {
   217  		return err
   218  	}
   219  
   220  	entropy, err := LinkEntropy()
   221  	if err != nil {
   222  		return err
   223  	}
   224  	err = track.SetKey("entropy", jsonw.NewString(entropy))
   225  	if err != nil {
   226  		return err
   227  	}
   228  
   229  	return w.SetKey("track", track)
   230  }
   231  
   232  func (u *User) ToWotStatement() *jsonw.Wrapper {
   233  	user := jsonw.NewDictionary()
   234  	_ = user.SetKey("username", jsonw.NewString(u.GetNormalizedName().String()))
   235  	_ = user.SetKey("uid", UIDWrapper(u.GetUID()))
   236  	_ = user.SetKey("seq_tail", u.ToTrackingStatementSeqTail())
   237  	eldest := jsonw.NewDictionary()
   238  	_ = eldest.SetKey("kid", jsonw.NewString(u.GetEldestKID().String()))
   239  	_ = eldest.SetKey("seqno", jsonw.NewInt64(int64(u.GetCurrentEldestSeqno())))
   240  	_ = user.SetKey("eldest", eldest)
   241  
   242  	return user
   243  }
   244  
   245  func (u *User) ToUntrackingStatementBasics() *jsonw.Wrapper {
   246  	ret := jsonw.NewDictionary()
   247  	_ = ret.SetKey("username", jsonw.NewString(u.name))
   248  	return ret
   249  }
   250  
   251  func (u *User) ToUntrackingStatement(w *jsonw.Wrapper) (err error) {
   252  	untrack := jsonw.NewDictionary()
   253  	err = untrack.SetKey("basics", u.ToUntrackingStatementBasics())
   254  	if err != nil {
   255  		return err
   256  	}
   257  	err = untrack.SetKey("id", UIDWrapper(u.GetUID()))
   258  	if err != nil {
   259  		return err
   260  	}
   261  
   262  	entropy, err := LinkEntropy()
   263  	if err != nil {
   264  		return err
   265  	}
   266  	err = untrack.SetKey("entropy", jsonw.NewString(entropy))
   267  	if err != nil {
   268  		return err
   269  	}
   270  
   271  	return w.SetKey("untrack", untrack)
   272  }
   273  
   274  func (g *GenericChainLink) BaseToTrackingStatement(state keybase1.ProofState) *jsonw.Wrapper {
   275  	ret := jsonw.NewDictionary()
   276  	_ = ret.SetKey("curr", jsonw.NewString(g.id.String()))
   277  	_ = ret.SetKey("sig_id", jsonw.NewString(g.GetSigID().String()))
   278  
   279  	rkp := jsonw.NewDictionary()
   280  	_ = ret.SetKey("remote_key_proof", rkp)
   281  	_ = rkp.SetKey("state", jsonw.NewInt(int(state)))
   282  
   283  	prev := g.GetPrev()
   284  	var prevVal *jsonw.Wrapper
   285  	if prev == nil {
   286  		prevVal = jsonw.NewNil()
   287  	} else {
   288  		prevVal = jsonw.NewString(prev.String())
   289  	}
   290  
   291  	_ = ret.SetKey("prev", prevVal)
   292  	_ = ret.SetKey("ctime", jsonw.NewInt64(g.unpacked.ctime))
   293  	_ = ret.SetKey("etime", jsonw.NewInt64(g.unpacked.etime))
   294  	return ret
   295  }
   296  
   297  func remoteProofToTrackingStatement(s RemoteProofChainLink, base *jsonw.Wrapper) {
   298  	proofType := s.GetProofType()
   299  	_ = base.AtKey("remote_key_proof").SetKey("proof_type", jsonw.NewInt(int(proofType)))
   300  	_ = base.AtKey("remote_key_proof").SetKey("check_data_json", s.CheckDataJSON())
   301  	_ = base.SetKey("sig_type", jsonw.NewInt(SigTypeRemoteProof))
   302  }
   303  
   304  type HighSkip struct {
   305  	Seqno keybase1.Seqno
   306  	Hash  LinkID
   307  }
   308  
   309  func NewHighSkip(highSkipSeqno keybase1.Seqno, highSkipHash LinkID) HighSkip {
   310  	return HighSkip{
   311  		Seqno: highSkipSeqno,
   312  		Hash:  highSkipHash,
   313  	}
   314  }
   315  
   316  func NewInitialHighSkip() HighSkip {
   317  	return NewHighSkip(keybase1.Seqno(0), nil)
   318  }
   319  
   320  func (h HighSkip) AssertEqualsExpected(expected HighSkip) error {
   321  	if expected.Seqno != h.Seqno {
   322  		return fmt.Errorf("Expected highSkip.Seqno %d, got %d.", expected.Seqno, h.Seqno)
   323  	}
   324  	if !expected.Hash.Eq(h.Hash) {
   325  		return fmt.Errorf("Expected highSkip.Hash %s, got %s.", expected.Hash.String(), h.Hash.String())
   326  	}
   327  	return nil
   328  }
   329  
   330  type ProofMetadata struct {
   331  	Me                  *User
   332  	SigningUser         UserBasic
   333  	Seqno               keybase1.Seqno
   334  	PrevLinkID          LinkID
   335  	LinkType            LinkType
   336  	SigningKey          GenericKey
   337  	Eldest              keybase1.KID
   338  	CreationTime        int64
   339  	ExpireIn            int
   340  	IncludePGPHash      bool
   341  	SigVersion          SigVersion
   342  	SeqType             keybase1.SeqType
   343  	MerkleRoot          *MerkleRoot
   344  	IgnoreIfUnsupported SigIgnoreIfUnsupported
   345  	// HighSkipFallback is used for teams to provide for a KEX-provisisonee to
   346  	// provide the provisioner's information as the latest high link.
   347  	HighSkipFallback *HighSkip
   348  }
   349  
   350  type ProofMetadataRes struct {
   351  	J     *jsonw.Wrapper
   352  	Seqno keybase1.Seqno
   353  }
   354  
   355  func (arg ProofMetadata) merkleRootInfo(m MetaContext) (ret *jsonw.Wrapper) {
   356  	if mr := arg.MerkleRoot; mr != nil {
   357  		return mr.ToSigJSON()
   358  	}
   359  	if mc := m.G().MerkleClient; mc != nil {
   360  		ret, _ = mc.LastRootToSigJSON(m)
   361  	}
   362  	return ret
   363  }
   364  
   365  func (arg ProofMetadata) ToJSON(m MetaContext) (*jsonw.Wrapper, error) {
   366  	res, err := arg.ToJSON2(m)
   367  	if err != nil {
   368  		return nil, err
   369  	}
   370  	return res.J, nil
   371  }
   372  
   373  func (arg ProofMetadata) ToJSON2(m MetaContext) (ret *ProofMetadataRes, err error) {
   374  	// if only Me exists, then that is the signing user too
   375  	if arg.SigningUser == nil && arg.Me != nil {
   376  		arg.SigningUser = arg.Me
   377  	}
   378  
   379  	var seqno keybase1.Seqno
   380  	var prev *jsonw.Wrapper
   381  
   382  	// sanity check the seqno and prev relationship
   383  	if arg.Seqno > 1 && len(arg.PrevLinkID) == 0 {
   384  		return nil, fmt.Errorf("can't have a seqno > 1 without a prev value")
   385  	}
   386  
   387  	if arg.Seqno > 0 {
   388  		seqno = arg.Seqno
   389  		if arg.Seqno == 1 {
   390  			prev = jsonw.NewNil()
   391  		} else {
   392  			prev = jsonw.NewString(arg.PrevLinkID.String())
   393  		}
   394  	} else {
   395  		if arg.Me == nil {
   396  			return nil, fmt.Errorf("missing self user object while signing")
   397  		}
   398  		lastSeqno := arg.Me.sigChain().GetLastKnownSeqno()
   399  		lastLink := arg.Me.sigChain().GetLastKnownID()
   400  		if lastLink == nil {
   401  			seqno = 1
   402  			prev = jsonw.NewNil()
   403  		} else {
   404  			seqno = lastSeqno + 1
   405  			prev = jsonw.NewString(lastLink.String())
   406  		}
   407  	}
   408  
   409  	ctime := arg.CreationTime
   410  	if ctime == 0 {
   411  		ctime = m.G().Clock().Now().Unix()
   412  	}
   413  
   414  	ei := arg.ExpireIn
   415  	if ei == 0 {
   416  		ei = SigExpireIn
   417  	}
   418  
   419  	j := jsonw.NewDictionary()
   420  	err = j.SetKey("tag", jsonw.NewString("signature"))
   421  	if err != nil {
   422  		return nil, err
   423  	}
   424  	err = j.SetKey("ctime", jsonw.NewInt64(ctime))
   425  	if err != nil {
   426  		return nil, err
   427  	}
   428  	err = j.SetKey("expire_in", jsonw.NewInt(ei))
   429  	if err != nil {
   430  		return nil, err
   431  	}
   432  	err = j.SetKey("seqno", jsonw.NewInt64(int64(seqno)))
   433  	if err != nil {
   434  		return nil, err
   435  	}
   436  	err = j.SetKey("prev", prev)
   437  	if err != nil {
   438  		return nil, err
   439  	}
   440  
   441  	var highSkip *HighSkip
   442  	allowHighSkips := m.G().Env.GetFeatureFlags().HasFeature(EnvironmentFeatureAllowHighSkips)
   443  	if allowHighSkips {
   444  		if (arg.Me != nil) && (arg.HighSkipFallback != nil) {
   445  			return nil, fmt.Errorf("arg.Me and arg.HighSkipFallback can't both be non-nil.")
   446  		} else if arg.Me != nil {
   447  			highSkipPre, err := arg.Me.GetExpectedNextHighSkip(m)
   448  			if err != nil {
   449  				return nil, err
   450  			}
   451  			highSkip = &highSkipPre
   452  		} else if arg.HighSkipFallback != nil {
   453  			highSkip = arg.HighSkipFallback
   454  		}
   455  
   456  		if highSkip != nil {
   457  			highSkipObj := jsonw.NewDictionary()
   458  			err := highSkipObj.SetKey("seqno", jsonw.NewInt64(int64(highSkip.Seqno)))
   459  			if err != nil {
   460  				return nil, err
   461  			}
   462  			if hash := highSkip.Hash; hash != nil {
   463  				err := highSkipObj.SetKey("hash", jsonw.NewString(hash.String()))
   464  				if err != nil {
   465  					return nil, err
   466  				}
   467  			} else {
   468  				err := highSkipObj.SetKey("hash", jsonw.NewNil())
   469  				if err != nil {
   470  					return nil, err
   471  				}
   472  			}
   473  			err = j.SetKey("high_skip", highSkipObj)
   474  			if err != nil {
   475  				return nil, err
   476  			}
   477  		}
   478  	}
   479  
   480  	if arg.IgnoreIfUnsupported {
   481  		err := j.SetKey("ignore_if_unsupported", jsonw.NewBool(true))
   482  		if err != nil {
   483  			return nil, err
   484  		}
   485  	}
   486  	eldest := arg.Eldest
   487  	if eldest == "" {
   488  		if arg.Me == nil {
   489  			return nil, fmt.Errorf("missing self user object while signing")
   490  		}
   491  		eldest = arg.Me.GetEldestKID()
   492  	}
   493  
   494  	body := jsonw.NewDictionary()
   495  
   496  	if arg.SigVersion != 0 {
   497  		err := body.SetKey("version", jsonw.NewInt(int(arg.SigVersion)))
   498  		if err != nil {
   499  			return nil, err
   500  		}
   501  	} else {
   502  		err := body.SetKey("version", jsonw.NewInt(int(KeybaseSignatureV1)))
   503  		if err != nil {
   504  			return nil, err
   505  		}
   506  	}
   507  
   508  	err = body.SetKey("type", jsonw.NewString(string(arg.LinkType)))
   509  	if err != nil {
   510  		return nil, err
   511  	}
   512  
   513  	key, err := KeySection{
   514  		Key:            arg.SigningKey,
   515  		EldestKID:      eldest,
   516  		SigningUser:    arg.SigningUser,
   517  		IncludePGPHash: arg.IncludePGPHash,
   518  	}.ToJSON()
   519  	if err != nil {
   520  		return nil, err
   521  	}
   522  	err = body.SetKey("key", key)
   523  	if err != nil {
   524  		return nil, err
   525  	}
   526  	// Capture the most recent Merkle Root, inside of "body"
   527  	// field.
   528  	if mr := arg.merkleRootInfo(m); mr != nil {
   529  		err := body.SetKey("merkle_root", mr)
   530  		if err != nil {
   531  			return nil, err
   532  		}
   533  	}
   534  
   535  	err = j.SetKey("body", body)
   536  	if err != nil {
   537  		return nil, err
   538  	}
   539  
   540  	// Save what kind of client we're running.
   541  	err = j.SetKey("client", clientInfo(m))
   542  	if err != nil {
   543  		return nil, err
   544  	}
   545  
   546  	if arg.SeqType != 0 {
   547  		err := j.SetKey("seq_type", jsonw.NewInt(int(arg.SeqType)))
   548  		if err != nil {
   549  			return nil, err
   550  		}
   551  	}
   552  
   553  	return &ProofMetadataRes{
   554  		J:     j,
   555  		Seqno: seqno,
   556  	}, nil
   557  }
   558  
   559  func (u *User) TrackingProofFor(m MetaContext, signingKey GenericKey, sigVersion SigVersion, u2 *User, outcome *IdentifyOutcome) (*ProofMetadataRes, error) {
   560  	ret, err := ProofMetadata{
   561  		Me:         u,
   562  		LinkType:   LinkTypeTrack,
   563  		SigningKey: signingKey,
   564  		SigVersion: sigVersion,
   565  	}.ToJSON2(m)
   566  	if err == nil {
   567  		err = u2.ToTrackingStatement(ret.J.AtKey("body"), outcome)
   568  	}
   569  	return ret, err
   570  }
   571  
   572  func (u *User) UntrackingProofFor(m MetaContext, signingKey GenericKey, sigVersion SigVersion, u2 *User) (*ProofMetadataRes, error) {
   573  	ret, err := ProofMetadata{
   574  		Me:         u,
   575  		LinkType:   LinkTypeUntrack,
   576  		SigningKey: signingKey,
   577  		SigVersion: sigVersion,
   578  	}.ToJSON2(m)
   579  	if err == nil {
   580  		err = u2.ToUntrackingStatement(ret.J.AtKey("body"))
   581  	}
   582  	return ret, err
   583  }
   584  
   585  // arg.Me user is used to get the last known seqno in ProofMetadata.
   586  // If arg.Me == nil, set arg.Seqno.
   587  func KeyProof(m MetaContext, arg Delegator) (*jsonw.Wrapper, error) {
   588  	res, err := KeyProof2(m, arg)
   589  	if err != nil {
   590  		return nil, err
   591  	}
   592  	return res.J, nil
   593  }
   594  
   595  // arg.Me user is used to get the last known seqno in ProofMetadata.
   596  // If arg.Me == nil, set arg.Seqno.
   597  func KeyProof2(m MetaContext, arg Delegator) (ret *ProofMetadataRes, err error) {
   598  	var kp *jsonw.Wrapper
   599  	includePGPHash := false
   600  
   601  	if arg.DelegationType == DelegationTypeEldest {
   602  		includePGPHash = true
   603  	} else if arg.NewKey != nil {
   604  		keySection := KeySection{
   605  			Key: arg.NewKey,
   606  		}
   607  		switch arg.DelegationType {
   608  		case DelegationTypePGPUpdate:
   609  			keySection.IncludePGPHash = true
   610  		case DelegationTypeSibkey:
   611  			keySection.HasRevSig = true
   612  			keySection.RevSig = arg.RevSig
   613  			keySection.IncludePGPHash = true
   614  		default:
   615  			keySection.ParentKID = arg.ExistingKey.GetKID()
   616  		}
   617  
   618  		if kp, err = keySection.ToJSON(); err != nil {
   619  			return nil, err
   620  		}
   621  	}
   622  
   623  	// Only set the fallback for subkeys during KEX where arg.Me == nil; it is
   624  	// otherwise updated using me.SigChainBump().
   625  	var highSkipFallback *HighSkip
   626  	if arg.Me == nil && arg.DelegationType == DelegationTypeSubkey {
   627  		highSkip := NewHighSkip(arg.Seqno-1, arg.PrevLinkID)
   628  		highSkipFallback = &highSkip
   629  	}
   630  
   631  	ret, err = ProofMetadata{
   632  		Me:               arg.Me,
   633  		SigningUser:      arg.SigningUser,
   634  		LinkType:         LinkType(arg.DelegationType),
   635  		ExpireIn:         arg.Expire,
   636  		SigningKey:       arg.GetSigningKey(),
   637  		Eldest:           arg.EldestKID,
   638  		CreationTime:     arg.Ctime,
   639  		IncludePGPHash:   includePGPHash,
   640  		Seqno:            arg.Seqno,
   641  		HighSkipFallback: highSkipFallback,
   642  		PrevLinkID:       arg.PrevLinkID,
   643  		MerkleRoot:       arg.MerkleRoot,
   644  	}.ToJSON2(m)
   645  	if err != nil {
   646  		return nil, err
   647  	}
   648  
   649  	body := ret.J.AtKey("body")
   650  
   651  	if arg.Device != nil {
   652  		device := *arg.Device
   653  		device.Kid = arg.NewKey.GetKID()
   654  		var dw *jsonw.Wrapper
   655  		dw, err = device.Export(LinkType(arg.DelegationType))
   656  		if err != nil {
   657  			return nil, err
   658  		}
   659  		err = body.SetKey("device", dw)
   660  		if err != nil {
   661  			return nil, err
   662  		}
   663  	}
   664  	if kp != nil {
   665  		err := body.SetKey(string(arg.DelegationType), kp)
   666  		if err != nil {
   667  			return nil, err
   668  		}
   669  	}
   670  	return ret, nil
   671  }
   672  
   673  func (u *User) ServiceProof(m MetaContext, signingKey GenericKey, typ ServiceType, remotename string, sigVersion SigVersion) (*ProofMetadataRes, error) {
   674  	ret, err := ProofMetadata{
   675  		Me:         u,
   676  		LinkType:   LinkTypeWebServiceBinding,
   677  		SigningKey: signingKey,
   678  		SigVersion: sigVersion,
   679  	}.ToJSON2(m)
   680  	if err != nil {
   681  		return nil, err
   682  	}
   683  	service := typ.ToServiceJSON(remotename)
   684  	entropy, err := LinkEntropy()
   685  	if err != nil {
   686  		return nil, err
   687  	}
   688  	err = service.SetKey("entropy", jsonw.NewString(entropy))
   689  	if err != nil {
   690  		return nil, err
   691  	}
   692  	err = ret.J.AtKey("body").SetKey("service", service)
   693  	if err != nil {
   694  		return nil, err
   695  	}
   696  	return ret, nil
   697  }
   698  
   699  func (u *User) WotVouchProof(m MetaContext, signingKey GenericKey, sigVersion SigVersion, mac []byte, merkleRoot *MerkleRoot, sigIDToRevoke *keybase1.SigID) (*ProofMetadataRes, error) {
   700  	md := ProofMetadata{
   701  		Me:                  u,
   702  		LinkType:            LinkTypeWotVouch,
   703  		MerkleRoot:          merkleRoot,
   704  		SigningKey:          signingKey,
   705  		SigVersion:          sigVersion,
   706  		IgnoreIfUnsupported: true,
   707  	}
   708  	ret, err := md.ToJSON2(m)
   709  	if err != nil {
   710  		return nil, err
   711  	}
   712  
   713  	body := ret.J.AtKey("body")
   714  	if err := body.SetKey("wot_vouch", jsonw.NewString(hex.EncodeToString(mac))); err != nil {
   715  		return nil, err
   716  	}
   717  
   718  	if sigIDToRevoke != nil {
   719  		revokeSection := jsonw.NewDictionary()
   720  		err := revokeSection.SetKey("sig_id", jsonw.NewString(sigIDToRevoke.String()))
   721  		if err != nil {
   722  			return nil, err
   723  		}
   724  		err = body.SetKey("revoke", revokeSection)
   725  		if err != nil {
   726  			return nil, err
   727  		}
   728  	}
   729  
   730  	return ret, nil
   731  }
   732  
   733  func (u *User) WotReactProof(m MetaContext, signingKey GenericKey, sigVersion SigVersion, mac []byte) (*ProofMetadataRes, error) {
   734  	md := ProofMetadata{
   735  		Me:                  u,
   736  		LinkType:            LinkTypeWotReact,
   737  		SigningKey:          signingKey,
   738  		SigVersion:          sigVersion,
   739  		IgnoreIfUnsupported: true,
   740  	}
   741  	ret, err := md.ToJSON2(m)
   742  	if err != nil {
   743  		return nil, err
   744  	}
   745  
   746  	body := ret.J.AtKey("body")
   747  	if err := body.SetKey("wot_react", jsonw.NewString(hex.EncodeToString(mac))); err != nil {
   748  		return nil, err
   749  	}
   750  
   751  	return ret, nil
   752  }
   753  
   754  // SimpleSignJson marshals the given Json structure and then signs it.
   755  func SignJSON(jw *jsonw.Wrapper, key GenericKey) (out string, id keybase1.SigIDBase, lid LinkID, err error) {
   756  	var tmp []byte
   757  	if tmp, err = jw.Marshal(); err != nil {
   758  		return
   759  	}
   760  	out, id, err = key.SignToString(tmp)
   761  	lid = ComputeLinkID(tmp)
   762  	return
   763  }
   764  
   765  func GetDefaultSigVersion(g *GlobalContext) SigVersion {
   766  	return KeybaseSignatureV2
   767  }
   768  
   769  func MakeSig(
   770  	m MetaContext,
   771  	signingKey GenericKey,
   772  	v1LinkType LinkType,
   773  	innerLinkJSON []byte,
   774  	hasRevokes SigHasRevokes,
   775  	seqType keybase1.SeqType,
   776  	ignoreIfUnsupported SigIgnoreIfUnsupported,
   777  	me *User,
   778  	sigVersion SigVersion) (sig string, sigID keybase1.SigID, linkID LinkID, err error) {
   779  
   780  	switch sigVersion {
   781  	case KeybaseSignatureV1:
   782  		var sigIDBase keybase1.SigIDBase
   783  		sig, sigIDBase, err = signingKey.SignToString(innerLinkJSON)
   784  		linkID = ComputeLinkID(innerLinkJSON)
   785  		params := keybase1.SigIDSuffixParametersFromTypeAndVersion(string(v1LinkType), keybase1.SigVersion(sigVersion))
   786  		sigID = sigIDBase.ToSigID(params)
   787  	case KeybaseSignatureV2:
   788  		prevSeqno := me.GetSigChainLastKnownSeqno()
   789  		prevLinkID := me.GetSigChainLastKnownID()
   790  		highSkip, highSkipErr := me.GetExpectedNextHighSkip(m)
   791  		if highSkipErr != nil {
   792  			return sig, sigID, linkID, highSkipErr
   793  		}
   794  		sig, sigID, linkID, err = MakeSigchainV2OuterSig(
   795  			m,
   796  			signingKey,
   797  			v1LinkType,
   798  			prevSeqno+1,
   799  			innerLinkJSON,
   800  			prevLinkID,
   801  			hasRevokes,
   802  			seqType,
   803  			ignoreIfUnsupported,
   804  			&highSkip,
   805  		)
   806  	default:
   807  		err = errors.New("Invalid Signature Version")
   808  	}
   809  	return sig, sigID, linkID, err
   810  }
   811  
   812  func (u *User) RevokeKeysProof(m MetaContext, key GenericKey, kidsToRevoke []keybase1.KID,
   813  	deviceToDisable keybase1.DeviceID, merkleRoot *MerkleRoot) (*ProofMetadataRes, error) {
   814  	ret, err := ProofMetadata{
   815  		Me:         u,
   816  		LinkType:   LinkTypeRevoke,
   817  		SigningKey: key,
   818  		MerkleRoot: merkleRoot,
   819  	}.ToJSON2(m)
   820  	if err != nil {
   821  		return nil, err
   822  	}
   823  	body := ret.J.AtKey("body")
   824  	revokeSection := jsonw.NewDictionary()
   825  	err = revokeSection.SetKey("kids", jsonw.NewWrapper(kidsToRevoke))
   826  	if err != nil {
   827  		return nil, err
   828  	}
   829  	err = body.SetKey("revoke", revokeSection)
   830  	if err != nil {
   831  		return nil, err
   832  	}
   833  	if deviceToDisable.Exists() {
   834  		device, err := u.GetDevice(deviceToDisable)
   835  		if err != nil {
   836  			return nil, err
   837  		}
   838  		deviceSection := jsonw.NewDictionary()
   839  		err = deviceSection.SetKey("id", jsonw.NewString(deviceToDisable.String()))
   840  		if err != nil {
   841  			return nil, err
   842  		}
   843  		err = deviceSection.SetKey("type", jsonw.NewString(device.Type.String()))
   844  		if err != nil {
   845  			return nil, err
   846  		}
   847  		err = deviceSection.SetKey("status", jsonw.NewInt(DeviceStatusDefunct))
   848  		if err != nil {
   849  			return nil, err
   850  		}
   851  		err = body.SetKey("device", deviceSection)
   852  		if err != nil {
   853  			return nil, err
   854  		}
   855  	}
   856  	return ret, nil
   857  }
   858  
   859  func (u *User) RevokeSigsProof(m MetaContext, key GenericKey, sigIDsToRevoke []keybase1.SigID, merkleRoot *MerkleRoot) (*ProofMetadataRes, error) {
   860  	ret, err := ProofMetadata{
   861  		Me:         u,
   862  		LinkType:   LinkTypeRevoke,
   863  		SigningKey: key,
   864  		MerkleRoot: merkleRoot,
   865  	}.ToJSON2(m)
   866  	if err != nil {
   867  		return nil, err
   868  	}
   869  	body := ret.J.AtKey("body")
   870  	revokeSection := jsonw.NewDictionary()
   871  	idsArray := jsonw.NewArray(len(sigIDsToRevoke))
   872  	for i, id := range sigIDsToRevoke {
   873  		err := idsArray.SetIndex(i, jsonw.NewString(id.String()))
   874  		if err != nil {
   875  			return nil, err
   876  		}
   877  	}
   878  	err = revokeSection.SetKey("sig_ids", idsArray)
   879  	if err != nil {
   880  		return nil, err
   881  	}
   882  	err = body.SetKey("revoke", revokeSection)
   883  	if err != nil {
   884  		return nil, err
   885  	}
   886  	return ret, nil
   887  }
   888  
   889  func (u *User) CryptocurrencySig(m MetaContext, key GenericKey, address string, typ CryptocurrencyType, sigToRevoke keybase1.SigID, merkleRoot *MerkleRoot, sigVersion SigVersion) (*ProofMetadataRes, error) {
   890  	ret, err := ProofMetadata{
   891  		Me:         u,
   892  		LinkType:   LinkTypeCryptocurrency,
   893  		SigningKey: key,
   894  		MerkleRoot: merkleRoot,
   895  		SigVersion: sigVersion,
   896  	}.ToJSON2(m)
   897  	if err != nil {
   898  		return nil, err
   899  	}
   900  	body := ret.J.AtKey("body")
   901  	currencySection := jsonw.NewDictionary()
   902  	err = currencySection.SetKey("address", jsonw.NewString(address))
   903  	if err != nil {
   904  		return nil, err
   905  	}
   906  	err = currencySection.SetKey("type", jsonw.NewString(typ.String()))
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  	entropy, err := LinkEntropy()
   911  	if err != nil {
   912  		return nil, err
   913  	}
   914  	err = currencySection.SetKey("entropy", jsonw.NewString(entropy))
   915  	if err != nil {
   916  		return nil, err
   917  	}
   918  	err = body.SetKey("cryptocurrency", currencySection)
   919  	if err != nil {
   920  		return nil, err
   921  	}
   922  	if len(sigToRevoke) > 0 {
   923  		revokeSection := jsonw.NewDictionary()
   924  		err := revokeSection.SetKey("sig_id", jsonw.NewString(sigToRevoke.String()))
   925  		if err != nil {
   926  			return nil, err
   927  		}
   928  		err = body.SetKey("revoke", revokeSection)
   929  		if err != nil {
   930  			return nil, err
   931  		}
   932  	}
   933  	return ret, nil
   934  }
   935  
   936  func (u *User) UpdatePassphraseProof(m MetaContext, key GenericKey, pwh string, ppGen PassphraseGeneration, pdpka5kid string) (*jsonw.Wrapper, error) {
   937  	ret, err := ProofMetadata{
   938  		Me:         u,
   939  		LinkType:   LinkTypeUpdatePassphrase,
   940  		SigningKey: key,
   941  	}.ToJSON(m)
   942  	if err != nil {
   943  		return nil, err
   944  	}
   945  	body := ret.AtKey("body")
   946  	pp := jsonw.NewDictionary()
   947  	err = pp.SetKey("hash", jsonw.NewString(pwh))
   948  	if err != nil {
   949  		return nil, err
   950  	}
   951  	err = pp.SetKey("pdpka5_kid", jsonw.NewString(pdpka5kid))
   952  	if err != nil {
   953  		return nil, err
   954  	}
   955  	err = pp.SetKey("version", jsonw.NewInt(int(ClientTriplesecVersion)))
   956  	if err != nil {
   957  		return nil, err
   958  	}
   959  	err = pp.SetKey("passphrase_generation", jsonw.NewInt(int(ppGen)))
   960  	if err != nil {
   961  		return nil, err
   962  	}
   963  	err = body.SetKey("update_passphrase_hash", pp)
   964  	if err != nil {
   965  		return nil, err
   966  	}
   967  	return ret, nil
   968  }
   969  
   970  func (u *User) UpdateEmailProof(m MetaContext, key GenericKey, newEmail string) (*jsonw.Wrapper, error) {
   971  	ret, err := ProofMetadata{
   972  		Me:         u,
   973  		LinkType:   LinkTypeUpdateSettings,
   974  		SigningKey: key,
   975  	}.ToJSON(m)
   976  	if err != nil {
   977  		return nil, err
   978  	}
   979  	body := ret.AtKey("body")
   980  	settings := jsonw.NewDictionary()
   981  	err = settings.SetKey("email", jsonw.NewString(newEmail))
   982  	if err != nil {
   983  		return nil, err
   984  	}
   985  	err = body.SetKey("update_settings", settings)
   986  	if err != nil {
   987  		return nil, err
   988  	}
   989  	return ret, nil
   990  }
   991  
   992  type SigMultiItem struct {
   993  	Sig3       *Sig3                   `json:"sig3,omitempty"`
   994  	Sig        string                  `json:"sig,omitempty"`
   995  	SigningKID keybase1.KID            `json:"signing_kid"`
   996  	Type       string                  `json:"type"`
   997  	SeqType    keybase1.SeqType        `json:"seq_type"`
   998  	SigInner   string                  `json:"sig_inner"`
   999  	TeamID     keybase1.TeamID         `json:"team_id,omitempty"`
  1000  	PublicKeys *SigMultiItemPublicKeys `json:"public_keys,omitempty"`
  1001  	Version    SigVersion              `json:"version"`
  1002  	Expansions *jsonw.Wrapper          `json:"expansions,omitempty"`
  1003  }
  1004  
  1005  type SigMultiItemPublicKeys struct {
  1006  	Encryption keybase1.KID `json:"encryption"`
  1007  	Signing    keybase1.KID `json:"signing"`
  1008  }
  1009  
  1010  type Sig3 struct {
  1011  	Inner string `json:"i,omitempty"`
  1012  	Outer string `json:"o,omitempty"`
  1013  	Sig   string `json:"s,omitempty"`
  1014  }
  1015  
  1016  // PerUserKeyProof creates a proof introducing a new per-user-key generation.
  1017  // `signingKey` is the key signing in this new key. Not to be confused with the derived per-user-key signing key.
  1018  func PerUserKeyProof(m MetaContext,
  1019  	me *User,
  1020  	pukSigKID keybase1.KID,
  1021  	pukEncKID keybase1.KID,
  1022  	generation keybase1.PerUserKeyGeneration,
  1023  	signingKey GenericKey) (*ProofMetadataRes, error) {
  1024  
  1025  	if me == nil {
  1026  		return nil, fmt.Errorf("missing user object for proof")
  1027  	}
  1028  
  1029  	ret, err := ProofMetadata{
  1030  		Me:         me,
  1031  		LinkType:   LinkTypePerUserKey,
  1032  		SigningKey: signingKey,
  1033  	}.ToJSON2(m)
  1034  	if err != nil {
  1035  		return nil, err
  1036  	}
  1037  
  1038  	pukSection := jsonw.NewDictionary()
  1039  	err = pukSection.SetKey("signing_kid", jsonw.NewString(pukSigKID.String()))
  1040  	if err != nil {
  1041  		return nil, err
  1042  	}
  1043  	err = pukSection.SetKey("encryption_kid", jsonw.NewString(pukEncKID.String()))
  1044  	if err != nil {
  1045  		return nil, err
  1046  	}
  1047  	err = pukSection.SetKey("generation", jsonw.NewInt(int(generation)))
  1048  	if err != nil {
  1049  		return nil, err
  1050  	}
  1051  	// The caller is responsible for overwriting reverse_sig after signing.
  1052  	err = pukSection.SetKey("reverse_sig", jsonw.NewNil())
  1053  	if err != nil {
  1054  		return nil, err
  1055  	}
  1056  
  1057  	body := ret.J.AtKey("body")
  1058  	err = body.SetKey("per_user_key", pukSection)
  1059  	if err != nil {
  1060  		return nil, err
  1061  	}
  1062  	return ret, nil
  1063  }
  1064  
  1065  type UserLinkSignature struct {
  1066  	Payload JSONPayload
  1067  	Seqno   keybase1.Seqno
  1068  	LinkID  LinkID
  1069  }
  1070  
  1071  // Make a per-user key proof with a reverse sig.
  1072  // Modifies the User `me` with a sigchain bump and key delegation.
  1073  // Returns a JSONPayload ready for use in "sigs" in sig/multi.
  1074  func PerUserKeyProofReverseSigned(m MetaContext, me *User, perUserKeySeed PerUserKeySeed, generation keybase1.PerUserKeyGeneration,
  1075  	signer GenericKey) (*UserLinkSignature, error) {
  1076  
  1077  	pukSigKey, err := perUserKeySeed.DeriveSigningKey()
  1078  	if err != nil {
  1079  		return nil, err
  1080  	}
  1081  
  1082  	pukEncKey, err := perUserKeySeed.DeriveDHKey()
  1083  	if err != nil {
  1084  		return nil, err
  1085  	}
  1086  
  1087  	// Make reverse sig
  1088  	forward, err := PerUserKeyProof(m, me, pukSigKey.GetKID(), pukEncKey.GetKID(), generation, signer)
  1089  	if err != nil {
  1090  		return nil, err
  1091  	}
  1092  	reverseSig, _, _, err := SignJSON(forward.J, pukSigKey)
  1093  	if err != nil {
  1094  		return nil, err
  1095  	}
  1096  
  1097  	// Make sig
  1098  	jw := forward.J
  1099  	err = jw.SetValueAtPath("body.per_user_key.reverse_sig", jsonw.NewString(reverseSig))
  1100  	if err != nil {
  1101  		return nil, err
  1102  	}
  1103  	sig, sigID, linkID, err := SignJSON(jw, signer)
  1104  	if err != nil {
  1105  		return nil, err
  1106  	}
  1107  
  1108  	// Update the user locally
  1109  	me.SigChainBump(linkID, sigID.ToSigIDLegacy(), false)
  1110  	err = me.localDelegatePerUserKey(keybase1.PerUserKey{
  1111  		Gen:         int(generation),
  1112  		Seqno:       me.GetSigChainLastKnownSeqno(),
  1113  		SigKID:      pukSigKey.GetKID(),
  1114  		EncKID:      pukEncKey.GetKID(),
  1115  		SignedByKID: signer.GetKID(),
  1116  	})
  1117  	if err != nil {
  1118  		return nil, err
  1119  	}
  1120  
  1121  	publicKeysEntry := make(JSONPayload)
  1122  	publicKeysEntry["signing"] = pukSigKey.GetKID().String()
  1123  	publicKeysEntry["encryption"] = pukEncKey.GetKID().String()
  1124  
  1125  	payload := make(JSONPayload)
  1126  	payload["sig"] = sig
  1127  	payload["signing_kid"] = signer.GetKID().String()
  1128  	payload["type"] = LinkTypePerUserKey
  1129  	payload["public_keys"] = publicKeysEntry
  1130  	return &UserLinkSignature{
  1131  		Payload: payload,
  1132  		Seqno:   forward.Seqno,
  1133  		LinkID:  linkID,
  1134  	}, nil
  1135  }
  1136  
  1137  // StellarProof creates a proof of a stellar wallet.
  1138  func StellarProof(m MetaContext, me *User, walletAddress stellar1.AccountID,
  1139  	signingKey GenericKey) (*ProofMetadataRes, error) {
  1140  	if me == nil {
  1141  		return nil, fmt.Errorf("missing user object for proof")
  1142  	}
  1143  	walletPubKey, err := MakeNaclSigningKeyPairFromStellarAccountID(walletAddress)
  1144  	if err != nil {
  1145  		return nil, err
  1146  	}
  1147  	walletKID := walletPubKey.GetKID()
  1148  
  1149  	ret, err := ProofMetadata{
  1150  		Me:                  me,
  1151  		LinkType:            LinkTypeWalletStellar,
  1152  		SigningKey:          signingKey,
  1153  		SigVersion:          KeybaseSignatureV2,
  1154  		IgnoreIfUnsupported: SigIgnoreIfUnsupported(true),
  1155  	}.ToJSON2(m)
  1156  	if err != nil {
  1157  		return nil, err
  1158  	}
  1159  
  1160  	walletSection := jsonw.NewDictionary()
  1161  	err = walletSection.SetKey("address", jsonw.NewString(walletAddress.String()))
  1162  	if err != nil {
  1163  		return nil, err
  1164  	}
  1165  	err = walletSection.SetKey("network", jsonw.NewString(string(WalletNetworkStellar)))
  1166  	if err != nil {
  1167  		return nil, err
  1168  	}
  1169  
  1170  	// Inner links can be hidden. To prevent an attacker from figuring out the
  1171  	// contents from the hash of the inner link, add 18 random bytes.
  1172  	entropy, err := LinkEntropy()
  1173  	if err != nil {
  1174  		return nil, err
  1175  	}
  1176  	err = walletSection.SetKey("entropy", jsonw.NewString(entropy))
  1177  	if err != nil {
  1178  		return nil, err
  1179  	}
  1180  
  1181  	walletKeySection := jsonw.NewDictionary()
  1182  	err = walletKeySection.SetKey("kid", jsonw.NewString(walletKID.String()))
  1183  	if err != nil {
  1184  		return nil, err
  1185  	}
  1186  	// The caller is responsible for overwriting reverse_sig after signing.
  1187  	err = walletKeySection.SetKey("reverse_sig", jsonw.NewNil())
  1188  	if err != nil {
  1189  		return nil, err
  1190  	}
  1191  
  1192  	body := ret.J.AtKey("body")
  1193  	err = body.SetKey("wallet", walletSection)
  1194  	if err != nil {
  1195  		return nil, err
  1196  	}
  1197  	err = body.SetKey("wallet_key", walletKeySection)
  1198  	if err != nil {
  1199  		return nil, err
  1200  	}
  1201  	return ret, nil
  1202  }
  1203  
  1204  // Make a stellar proof with a reverse sig.
  1205  // Modifies the User `me` with a sigchain bump and key delegation.
  1206  // Returns a JSONPayload ready for use in "sigs" in sig/multi.
  1207  func StellarProofReverseSigned(m MetaContext, me *User, walletAddress stellar1.AccountID,
  1208  	stellarSigner stellar1.SecretKey, deviceSigner GenericKey) (*UserLinkSignature, error) {
  1209  	// Make reverse sig
  1210  	forward, err := StellarProof(m, me, walletAddress, deviceSigner)
  1211  	if err != nil {
  1212  		return nil, err
  1213  	}
  1214  	stellarSignerKey, err := MakeNaclSigningKeyPairFromStellarSecretKey(stellarSigner)
  1215  	if err != nil {
  1216  		return nil, err
  1217  	}
  1218  	reverseSig, _, _, err := SignJSON(forward.J, stellarSignerKey)
  1219  	if err != nil {
  1220  		return nil, err
  1221  	}
  1222  
  1223  	// Make sig
  1224  	jw := forward.J
  1225  	err = jw.SetValueAtPath("body.wallet_key.reverse_sig", jsonw.NewString(reverseSig))
  1226  	if err != nil {
  1227  		return nil, err
  1228  	}
  1229  	innerJSON, err := jw.Marshal()
  1230  	if err != nil {
  1231  		return nil, err
  1232  	}
  1233  	sig, sigID, linkID, err := MakeSig(
  1234  		m,
  1235  		deviceSigner,
  1236  		LinkTypeWalletStellar,
  1237  		innerJSON,
  1238  		SigHasRevokes(false),
  1239  		keybase1.SeqType_PUBLIC,
  1240  		SigIgnoreIfUnsupported(true),
  1241  		me,
  1242  		KeybaseSignatureV2,
  1243  	)
  1244  	if err != nil {
  1245  		return nil, err
  1246  	}
  1247  
  1248  	// Update the user locally
  1249  	me.SigChainBump(linkID, sigID, false)
  1250  	// TODO: do we need to locally do something like me.localDelegatePerUserKey?
  1251  
  1252  	payload := make(JSONPayload)
  1253  	payload["sig"] = sig
  1254  	payload["sig_inner"] = string(innerJSON)
  1255  	payload["signing_kid"] = deviceSigner.GetKID().String()
  1256  	payload["public_key"] = stellarSignerKey.GetKID().String()
  1257  	payload["type"] = LinkTypeWalletStellar
  1258  	return &UserLinkSignature{
  1259  		Payload: payload,
  1260  		Seqno:   forward.Seqno,
  1261  		LinkID:  linkID,
  1262  	}, nil
  1263  }