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