1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package libkb
5
6import (
7	"bytes"
8	"crypto/sha256"
9	"encoding/hex"
10	"encoding/json"
11	"errors"
12	"fmt"
13	"strconv"
14	"time"
15
16	"github.com/buger/jsonparser"
17	"github.com/keybase/client/go/jsonparserw"
18	"github.com/keybase/client/go/msgpack"
19	pkgerrors "github.com/pkg/errors"
20
21	keybase1 "github.com/keybase/client/go/protocol/keybase1"
22	jsonw "github.com/keybase/go-jsonw"
23)
24
25const (
26	LinkIDLen = 32
27)
28
29type LinkID []byte
30
31func GetLinkID(w *jsonw.Wrapper) (LinkID, error) {
32	if w.IsNil() {
33		return nil, nil
34	}
35	s, err := w.GetString()
36	if err != nil {
37		return nil, err
38	}
39	ret, err := LinkIDFromHex(s)
40	return ret, err
41}
42
43func ImportLinkID(i keybase1.LinkID) (LinkID, error) {
44	return LinkIDFromHex(string(i))
45}
46
47func GetLinkIDVoid(w *jsonw.Wrapper, l *LinkID, e *error) {
48	ret, err := GetLinkID(w)
49	if err != nil {
50		*e = err
51	} else {
52		*l = ret
53	}
54}
55
56func (l *LinkID) UnmarshalJSON(b []byte) error {
57	lid, err := LinkIDFromHex(keybase1.Unquote(b))
58	if err != nil {
59		return err
60	}
61	*l = make([]byte, len(lid))
62	copy((*l)[:], lid[:])
63	return nil
64}
65
66func (l *LinkID) MarshalJSON() ([]byte, error) {
67	return keybase1.Quote(l.String()), nil
68}
69
70func LinkIDFromHex(s string) (LinkID, error) {
71	bv, err := hex.DecodeString(s)
72	if err == nil && len(bv) != LinkIDLen {
73		err = fmt.Errorf("Bad link ID; wrong length: %d", len(bv))
74		bv = nil
75	}
76	var ret LinkID
77	if bv != nil {
78		ret = LinkID(bv)
79	}
80	return ret, err
81}
82
83func (l LinkID) String() string {
84	return hex.EncodeToString(l)
85}
86
87func (l LinkID) Eq(i2 LinkID) bool {
88	if l == nil && i2 == nil {
89		return true
90	} else if l == nil || i2 == nil {
91		return false
92	} else {
93		return FastByteArrayEq(l[:], i2[:])
94	}
95}
96
97type ChainLinkUnpacked struct {
98	prev                               LinkID
99	seqno                              keybase1.Seqno
100	highSkip                           *HighSkip
101	seqType                            keybase1.SeqType
102	ignoreIfUnsupported                SigIgnoreIfUnsupported
103	payloadLocal                       []byte // local track payloads
104	payloadV2                          []byte
105	ctime, etime                       int64
106	pgpFingerprint                     *PGPFingerprint
107	kid                                keybase1.KID
108	eldestKID                          keybase1.KID
109	sig                                string
110	sigID                              keybase1.SigID
111	uid                                keybase1.UID
112	username                           string
113	typ                                string
114	proofText                          string
115	outerLinkV2                        *OuterLinkV2WithMetadata
116	sigVersion                         SigVersion // what the server hints is the sig version (must be verified)
117	stubbed                            bool
118	firstAppearedMerkleSeqnoUnverified keybase1.Seqno
119	payloadHash                        []byte
120	sigDropped                         bool
121	hasRevocations                     bool
122	merkleSeqno                        keybase1.Seqno
123	merkleHashMeta                     keybase1.HashMeta
124}
125
126// A template for some of the reasons in badChainLinks below.
127const badAkalin = "Link %d of akalin's sigchain, which was accidentally added by an old client in development on 23 Mar 2015 20:02 GMT."
128const badJamGregory = "Link %d of jamgregory's sigchain, which had a bad PGP keypin"
129const badDens = "Link 8 of dens's sigchain, which signs in a revoked PGP key"
130const badAjar = "Link 98 of ajar's sigchain allowed a PGP update with a broken PGP key"
131const badJaccarmac = "Link 46 of jaccarmac's sigchain, which signs in a revoked PGP key (key later removed in link 46)"
132
133const akalin = keybase1.UID("ebbe1d99410ab70123262cf8dfc87900")
134const jamGregory = keybase1.UID("e8767e19a3ed9c7350847b7b040de319")
135const dens = keybase1.UID("ca9e948f6f7a4a19e02058ad626f6c19")
136const ajar = keybase1.UID("d1d94b3131e493dfee738802843f7719")
137const jaccarmac = keybase1.UID("bfd01fc0a2d5ee0462aaa3c598210b00")
138
139type SpecialChainLink struct {
140	UID    keybase1.UID
141	Seqno  keybase1.Seqno
142	Reason string
143}
144
145// A map from SigIDs of bad chain links that should be ignored to the
146// reasons why they're ignored.
147var badChainLinks = map[keybase1.LinkID]SpecialChainLink{
148	// Links 22-25 of akalin's sigchain, which was accidentally
149	// added by an old client in development on 3/23/2015, 9:02am.
150	// Links 17-19 of jamGregory's sigchain, which referred to a corrupted
151	// PGP key. See https://github.com/keybase/client/issues/1908
152	// Link 8 of dens's sigchain is to a revoked PGP key, which wasn't
153	// properly checked for on the server side.
154	// See: https://github.com/keybase/client/issues/4754
155	// Link 98 of ajar's sigchain is a PGP update with a broken PGP key,
156	// that doesn't have a valid cross-sig on a signing key. It was a server
157	// bug to allow it be uploaded.
158	// Link 46 of jaccarmac's sigchain is a PGP delegation with a revoked PGP
159	// key. The self signature is invalid (revoked key signs over itself, and
160	// that signature cannot be verified, because the key is revoked). That
161	// wasn't properly rejected on the server because of the same bug as in
162	// "Link 8 of den's sigchain".
163	// See: https://github.com/keybase/client/issues/24176
164	"694ed7166cee72449964e97bcd4be58243877718425c4dc655d2d80832bd5cdf": {UID: akalin, Seqno: keybase1.Seqno(22), Reason: fmt.Sprintf(badAkalin, 22)},
165	"27bc88059a768a82b1a21dcc1c46f7fc61c2d2b80c445eb2d18fed3a5bb42e49": {UID: akalin, Seqno: keybase1.Seqno(23), Reason: fmt.Sprintf(badAkalin, 23)},
166	"12b594e44d9289349283f8b14a6f83ad144a17a3025a758e17d4eca70fbdc923": {UID: akalin, Seqno: keybase1.Seqno(24), Reason: fmt.Sprintf(badAkalin, 24)},
167	"ce162011e380c954de15f30db28f8b7b358866d2721143d9d0d4424166ce5ed8": {UID: akalin, Seqno: keybase1.Seqno(25), Reason: fmt.Sprintf(badAkalin, 25)},
168	"bf914e6d4cf9b4eb7c88c2a8a6f5650e969ade9a97cf1605c1eb8cae97d5d278": {UID: jamGregory, Seqno: keybase1.Seqno(17), Reason: fmt.Sprintf(badJamGregory, 17)},
169	"e56f492c1b519905d04ce51368e87794963906dd6dacb63fbeab7ad23596af29": {UID: jamGregory, Seqno: keybase1.Seqno(18), Reason: fmt.Sprintf(badJamGregory, 18)},
170	"51e46dad8b71a1a7204368f9cb4931257a32eed92cf3b97a08190c12912739dd": {UID: jamGregory, Seqno: keybase1.Seqno(19), Reason: fmt.Sprintf(badJamGregory, 19)},
171	"6d527d776cb28ea980c6e0474286fe745377e116fd5d07b44928d165ae4b7c97": {UID: dens, Seqno: keybase1.Seqno(8), Reason: badDens},
172	"9b3b3a3d973449ca3238bf59b7407186dc80242b917c158cba5e374595257dd0": {UID: ajar, Seqno: keybase1.Seqno(98), Reason: badAjar},
173	"496b0328664a7c8115449f3fb17d137990c52712797730ede9c4b8ceb942e6ea": {UID: jaccarmac, Seqno: keybase1.Seqno(46), Reason: badJaccarmac},
174}
175
176// Some chainlinks are broken and need a small whitespace addition to match their payload
177// hash in subsequent chainlinks.  Caused by bad code on 15 Sep 2015.
178const whitespaceIssue20150915 = "Bad whitespace stripping on 15 Sep 2015"
179
180var badWhitespaceChainLinks = map[keybase1.LinkID]string{
181	"ac3ecaa2aa1d638867026f0c54a1d895777f366d02bfef37403275aa0d4f8322": whitespaceIssue20150915,
182	"94fde9d49c29cba59c949b35dd424de3a0daccf8a04ba443833e3328d495b9d8": whitespaceIssue20150915,
183	"b9f188d0c6638e3bef3dfc3476c04078bb2aef2a9249cc77b6f009692967388a": whitespaceIssue20150915,
184	"f5f324e91a94c073fdc936b50d56250133dc19415ae592d2c7cb99db9e980e1b": whitespaceIssue20150915,
185	"03fb1e2c0e61e3715c41515045d89d2f788dbcc7eb671b94ac12ee5f805bbe70": whitespaceIssue20150915,
186	"e449b1cd1d6f2a86a0f800c47e7d1ad26bbb6c76b983bd78154972c51f77e960": whitespaceIssue20150915,
187	"d380d18672da3c18f0804baf6b28f5efda76d64220a152c000f2b3f9af8b6603": whitespaceIssue20150915,
188	"5957f583bec18cc6f381355843c21f903fe47d584a9816e072f3f102f1f488be": whitespaceIssue20150915,
189	"2c11a140d8f231af6d69543474138a503191486ae6b5739892c5e0c6c0c4c348": whitespaceIssue20150915,
190	"6f3d73ddf575f2033a48268a564575e40edbb5111cc057984f51f463d4e8ed58": whitespaceIssue20150915,
191	"b23dfd34e58a814543e1f8368b9d07922abec213afca6d2b76722825794acffa": whitespaceIssue20150915,
192	"2efe839231d6b03f85ab3c542e870e7062329a8c5e384f1289b00be7c7afb8ab": whitespaceIssue20150915,
193	"18688c45cbe05ee2b72567acc696b3856f9876dff0ec3ea927ad7632a3f48fe6": whitespaceIssue20150915,
194	"2cf8b9ffa500089b6db873acbabdba771e8e897c0a899a01f8967a7280cfd0da": whitespaceIssue20150915,
195	"acf150b2d57a3aa65574bc2bb97e224413ce3f5344fd24fc7c3282da48cc2f3d": whitespaceIssue20150915,
196	"371f9ae63d56ec853fa53941e79d29abbb4cd11aa926715d354d18d687b0ca71": whitespaceIssue20150915,
197	"4948115615d7dceb90bcdd818f69b66b5899339a2b747b5e6dc0f6987abbcbd0": whitespaceIssue20150915,
198	"4c3f7855eb307aa5620962e15de84b2cfe3f728a9722c43906b12e0f3082cb87": whitespaceIssue20150915,
199	"9db59496652a1587ed56ec6ae15917b6d0ef4ac9a14dda97bfa4d2427a80e2b8": whitespaceIssue20150915,
200	"43f21601ffaeae70eca2f585949f42c67e85e93cf2a6847d6c20ffd81a9ff890": whitespaceIssue20150915,
201	"7560f896c19457365225f48be0217b8a00519f1daccefee4c097dd1b4594dd66": whitespaceIssue20150915,
202	"09527db7672bf23a9681ac86c70826cdc01ed1e467252a76ca4bf4ad0964efd7": whitespaceIssue20150915,
203	"3803be27ec0c61b3fdcd8b9b7c78de3df73766736ef00727267858d34a039c7d": whitespaceIssue20150915,
204	"740f9140a7901defaaaec10042722b30d2fee457337b7ae8e9de3b9fc05d109f": whitespaceIssue20150915,
205	"32f5dd2643eabf3828f7f03ccded07d8d8a29e352df6130c3a4232104398d819": whitespaceIssue20150915,
206	"7d97355e5917c5bcc14ba3a1994398b3fa36416768b663c1454069de84a4fca2": whitespaceIssue20150915,
207	"720b80b7c15cb9a3d21a2eec228bceb5db6f0ef54df2d0aef08aec5ed1632257": whitespaceIssue20150915,
208	"12c9203c98fe0b1c80a551f8933b2c870fcc3754a8ea05591e43a4d528fadc68": whitespaceIssue20150915,
209	"9644d4db6a4928ad1075a22b4473d1efa47c99a1a2a779450d4cd67d9115b9ba": whitespaceIssue20150915,
210	"605525686fef18180be692df6106c13dae39abb2799dc9e8bed1e2bb64e9b886": whitespaceIssue20150915,
211	"374f1da46fd8238ab9f288183cb78f3c6a59732f4b19705763c9d6ac356015ef": whitespaceIssue20150915,
212	"893567013c77f45755279bf1138fecbb54cd3a55bf5814504cf0406acbe4bfeb": whitespaceIssue20150915,
213	"3ca5ef6a6115a8a86d7d94cb3565f43f05f7975d66015455dd6cc32b73936177": whitespaceIssue20150915,
214	"3cdd165df44ba7f8331b89213f213dab36482ef513d023c5d2b0f6bfd11d5678": whitespaceIssue20150915,
215	"36328ab1cf15cc3dd2ba4c771ca1066b2d44714780ad8e83894611e2a2642003": whitespaceIssue20150915,
216	"61e9f4b437fccac8abd396acfc96b17558c9c355b57f4a5f2f3698e78f19532f": whitespaceIssue20150915,
217	"14ef90159164e19228ff21c909b764e239f27f0fff49f86414a2dde9b719845f": whitespaceIssue20150915,
218	"b74b420f49b771ec04e656101f86c9729cf328b0fd32f5082d04d3c39f8ccea7": whitespaceIssue20150915,
219	"7772c99774570202a2c5ac017eefc8296f613e64c8d4adff4ba7991b553431f5": whitespaceIssue20150915,
220	"d7ae76e4fdae7034b07e515d5684adcd51afea5a22b8520d2c61d31f5028fc6e": whitespaceIssue20150915,
221	"33a61f19c0ca52257214f97524ef10441cf85215ff171868f53561dfd7b14c81": whitespaceIssue20150915,
222	"616d9710b3a594ab00292d3d414e6e141929935a133bfa9a25ec4a155a403e5c": whitespaceIssue20150915,
223	"8d7c1a0c99186f972afc5d3624aca2f88ddc3a5dbf84e826ef0b520c31a78aa3": whitespaceIssue20150915,
224	"9f8c0a29a6ba3a521db2cd4d3e2ae15223dbcd5d5d1201e33ebb2dee1b61342f": whitespaceIssue20150915,
225	"a9efa00bc479cb40ac0521749520f5a7a38a4ba4e698ee03355a85a8464b3840": whitespaceIssue20150915,
226	"f1509495f4f1d46e43dcdd341156b975f7ad19aefeb250a80fd2b236c517a891": whitespaceIssue20150915,
227	"da99975f9ae8cdeb9e3a42a1166617dbf6afbcf841919dcf05145a73a7026cc2": whitespaceIssue20150915,
228}
229
230type ChainLink struct {
231	Contextified
232	parent            *SigChain
233	id                LinkID
234	diskVersion       int
235	hashVerified      bool
236	sigVerified       bool
237	payloadVerified   bool
238	chainVerified     bool
239	highChainVerified bool
240	storedLocally     bool
241	revoked           bool
242	dirty             bool
243	revocationsCache  *[]keybase1.SigID
244	computedHighSkip  *HighSkip
245
246	unpacked *ChainLinkUnpacked
247	cki      *ComputedKeyInfos
248
249	typed                  TypedChainLink
250	isOwnNewLinkFromServer bool
251}
252
253// See NCC-KB2018-006
254func (c ChainLink) checkSpecialLinksTable(tab map[keybase1.LinkID]SpecialChainLink, uid keybase1.UID, why string) (found bool, reason string, err error) {
255	var scl SpecialChainLink
256
257	// The truthiness of hashVerified should ensure that this link
258	// is only considered here after all prevs have been successfully checked.
259	if !c.canTrustID() {
260		return false, "", ChainLinkError{fmt.Sprintf("cannot check if a link is %q without a verified link ID (linkID=%s, uid=%s, hash=%v, chain=%v, diskVersion=%d)", why, c.id, uid, c.hashVerified, c.chainVerified, c.diskVersion)}
261	}
262
263	scl, found = tab[c.LinkID().Export()]
264	if !found {
265		return false, "", nil
266	}
267	if !c.GetSeqno().Eq(scl.Seqno) {
268		return false, "", NewChainLinkWrongSeqnoError(fmt.Sprintf("malicious bad link in from server has wrong seqno in %q check: %d != %d", why, c.GetSeqno(), scl.Seqno))
269	}
270	if !scl.UID.Equal(uid) {
271		return false, "", NewUIDMismatchError(fmt.Sprintf("malicious bad link from server in %q check; UID %s != %s", why, scl.UID, uid))
272	}
273	return true, scl.Reason, nil
274}
275
276func (c *ChainLink) IsBad() (isBad bool, reason string, err error) {
277	return c.checkSpecialLinksTable(badChainLinks, c.parent.uid, "bad chain links")
278}
279
280func (c *ChainLink) Parent() *SigChain {
281	return c.parent
282}
283
284func (c *ChainLink) SetParent(parent *SigChain) {
285	if c.parent != nil {
286		c.G().Log.Warning("changing ChainLink parent")
287	}
288	c.parent = parent
289}
290
291func (c *ChainLink) getPrevFromPayload() LinkID {
292	return c.unpacked.prev
293}
294
295func (c *ChainLink) getSeqTypeFromPayload() keybase1.SeqType {
296	return c.unpacked.seqType
297}
298
299func (c *ChainLink) getIgnoreIfUnsupportedFromPayload() SigIgnoreIfUnsupported {
300	return c.unpacked.ignoreIfUnsupported
301}
302
303func (c *ChainLink) GetIgnoreIfSupported() SigIgnoreIfUnsupported {
304	return c.getIgnoreIfUnsupportedFromPayload()
305}
306
307func (c *ChainLink) getHighSkipFromPayload() *HighSkip {
308	return c.unpacked.highSkip
309}
310
311func (c *ChainLink) IsStubbed() bool {
312	return c.unpacked.stubbed
313}
314
315func (c *ChainLink) IsEldest() bool {
316	if c.unpacked == nil {
317		return false
318	}
319	if c.unpacked.outerLinkV2 != nil {
320		return c.unpacked.outerLinkV2.LinkType == SigchainV2TypeEldest
321	}
322	if c.unpacked.typ == string(DelegationTypeEldest) {
323		return true
324	}
325	return false
326}
327
328func (c *ChainLink) GetPrev() LinkID {
329	return c.unpacked.prev
330}
331
332func (c *ChainLink) GetCTime() time.Time {
333	if c.IsStubbed() {
334		return time.Time{}
335	}
336
337	return time.Unix(c.unpacked.ctime, 0)
338}
339
340func (c *ChainLink) GetETime() time.Time {
341	if c.IsStubbed() {
342		return time.Time{}
343	}
344	return UnixToTimeMappingZero(c.unpacked.etime)
345}
346
347func (c *ChainLink) GetFirstAppearedMerkleSeqnoUnverified() keybase1.Seqno {
348	if c.IsStubbed() {
349		return keybase1.Seqno(0)
350	}
351	return c.unpacked.firstAppearedMerkleSeqnoUnverified
352}
353
354func (c *ChainLink) GetUID() keybase1.UID {
355	return c.unpacked.uid
356}
357
358func (c *ChainLink) UnmarshalPayloadJSON() *jsonw.Wrapper {
359	jw, err := c.G().PayloadCache.GetOrPrime(c)
360	if err != nil {
361		// Any unmarshal error here would already have
362		// happened in Unpack
363		return nil
364	}
365	return jw
366}
367
368func (c *ChainLink) ToSigChainLocation() keybase1.SigChainLocation {
369	return keybase1.SigChainLocation{
370		Seqno: c.GetSeqno(),
371		// This code is meant only for user chains
372		SeqType: keybase1.SeqType_PUBLIC,
373	}
374}
375
376const chainLinkDiskVersion = 1
377
378func (c *ChainLink) canTrustID() bool {
379	return c.hashVerified || (c.storedLocally && c.diskVersion < 2)
380}
381
382func (c *ChainLink) Pack() (*jsonw.Wrapper, error) {
383	p := jsonw.NewDictionary()
384
385	if c.IsStubbed() {
386		err := p.SetKey("s2", jsonw.NewString(c.unpacked.outerLinkV2.EncodeStubbed()))
387		if err != nil {
388			return nil, err
389		}
390	} else {
391		// store the payload for v2 links and local tracks
392		if c.unpacked.sigVersion == KeybaseSignatureV2 {
393			err := p.SetKey("payload_json", jsonw.NewString(string(c.unpacked.payloadV2)))
394			if err != nil {
395				return nil, err
396			}
397		} else if len(c.unpacked.payloadLocal) > 0 {
398			err := p.SetKey("payload_json", jsonw.NewString(string(c.unpacked.payloadLocal)))
399			if err != nil {
400				return nil, err
401			}
402		}
403
404		err := p.SetKey("sig", jsonw.NewString(c.unpacked.sig))
405		if err != nil {
406			return nil, err
407		}
408		err = p.SetKey("sig_id", jsonw.NewString(string(c.unpacked.sigID)))
409		if err != nil {
410			return nil, err
411		}
412		err = p.SetKey("kid", c.unpacked.kid.ToJsonw())
413		if err != nil {
414			return nil, err
415		}
416		err = p.SetKey("ctime", jsonw.NewInt64(c.unpacked.ctime))
417		if err != nil {
418			return nil, err
419		}
420		if c.unpacked.pgpFingerprint != nil {
421			err := p.SetKey("fingerprint", jsonw.NewString(c.unpacked.pgpFingerprint.String()))
422			if err != nil {
423				return nil, err
424			}
425		}
426		err = p.SetKey("sig_verified", jsonw.NewBool(c.sigVerified))
427		if err != nil {
428			return nil, err
429		}
430		err = p.SetKey("chain_verified", jsonw.NewBool(c.chainVerified))
431		if err != nil {
432			return nil, err
433		}
434		err = p.SetKey("hash_verified", jsonw.NewBool(c.hashVerified))
435		if err != nil {
436			return nil, err
437		}
438		err = p.SetKey("payload_verified", jsonw.NewBool(c.payloadVerified))
439		if err != nil {
440			return nil, err
441		}
442		err = p.SetKey("proof_text_full", jsonw.NewString(c.unpacked.proofText))
443		if err != nil {
444			return nil, err
445		}
446		err = p.SetKey("sig_version", jsonw.NewInt(int(c.unpacked.sigVersion)))
447		if err != nil {
448			return nil, err
449		}
450		err = p.SetKey("merkle_seqno", jsonw.NewInt64(int64(c.unpacked.firstAppearedMerkleSeqnoUnverified)))
451		if err != nil {
452			return nil, err
453		}
454		err = p.SetKey("disk_version", jsonw.NewInt(chainLinkDiskVersion))
455		if err != nil {
456			return nil, err
457		}
458	}
459
460	if c.cki != nil {
461		err := p.SetKey("computed_key_infos", jsonw.NewWrapper(*c.cki))
462		if err != nil {
463			return nil, err
464		}
465	}
466
467	return p, nil
468}
469
470func (c *ChainLink) GetMerkleSeqno() keybase1.Seqno {
471	if c.IsStubbed() {
472		return 0
473	}
474	return c.unpacked.merkleSeqno
475}
476
477func (c *ChainLink) GetMerkleHashMeta() (keybase1.HashMeta, error) {
478	if c.IsStubbed() {
479		return nil, nil
480	}
481	return c.unpacked.merkleHashMeta, nil
482}
483
484func (c *ChainLink) HasRevocations() bool {
485	if c.IsStubbed() {
486		return false
487	}
488	if c.unpacked != nil {
489		return c.unpacked.hasRevocations
490	}
491	return false
492}
493
494func (tmp *ChainLinkUnpacked) HasRevocations(payload []byte) bool {
495	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "sig_id"); err == nil {
496		return true
497	}
498	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "sig_ids", "[0]"); err == nil {
499		return true
500	}
501	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "kid"); err == nil {
502		return true
503	}
504	if _, _, _, err := jsonparserw.Get(payload, "body", "revoke", "kids", "[0]"); err == nil {
505		return true
506	}
507	return false
508}
509
510func (c *ChainLink) GetRevocations() []keybase1.SigID {
511	if c.IsStubbed() {
512		return nil
513	}
514	if c.revocationsCache != nil {
515		return *c.revocationsCache
516	}
517	payload, err := c.unpacked.Payload()
518	if err != nil {
519		return nil
520	}
521	var ret []keybase1.SigID
522	if !bytes.Contains(payload, []byte("revoke")) {
523		c.revocationsCache = &ret
524		return nil
525	}
526	if s, err := jsonparserw.GetString(payload, "body", "revoke", "sig_id"); err == nil {
527		if sigID, err := keybase1.SigIDFromString(s); err == nil {
528			ret = append(ret, sigID)
529		}
530	}
531
532	_, _ = jsonparserw.ArrayEach(payload, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
533		if s, err := keybase1.SigIDFromString(string(value)); err == nil {
534			ret = append(ret, s)
535		}
536	}, "body", "revoke", "sig_ids")
537
538	c.revocationsCache = &ret
539	return ret
540}
541
542func (c *ChainLink) GetRevokeKids() []keybase1.KID {
543	if c.IsStubbed() {
544		return nil
545	}
546
547	payload, err := c.unpacked.Payload()
548	if err != nil {
549		return nil
550	}
551	var ret []keybase1.KID
552	if s, err := jsonparserw.GetString(payload, "body", "revoke", "kid"); err == nil {
553		ret = append(ret, keybase1.KIDFromString(s))
554	}
555
556	_, _ = jsonparserw.ArrayEach(payload, func(value []byte, dataType jsonparser.ValueType, offset int, err error) {
557		ret = append(ret, keybase1.KIDFromString(string(value)))
558	}, "body", "revoke", "kids")
559
560	return ret
561}
562
563func (c *ChainLink) checkAgainstMerkleTree(t *MerkleTriple) (found bool, err error) {
564	if c.IsStubbed() {
565		return false, ChainLinkError{"cannot check stubbed link against the merkle tree"}
566	}
567	found = false
568	if t != nil && c.GetSeqno() == t.Seqno {
569		c.G().Log.Debug("| Found chain tail advertised in Merkle tree @%d", int(t.Seqno))
570		found = true
571		if !c.id.Eq(t.LinkID) {
572			err = fmt.Errorf("Bad chain ID at seqno=%d", int(t.Seqno))
573		}
574	}
575	return
576}
577
578func getSigVersionFromPayload(payload []byte) (SigVersion, error) {
579	var err error
580	var i int64
581	if i, err = jsonparserw.GetInt(payload, "body", "version"); err != nil {
582		return KeybaseNullSigVersion, ChainLinkError{"link is missing a version field"}
583	}
584	return SigVersion(int(i)), nil
585}
586
587func (tmp *ChainLinkUnpacked) parseHighSkipFromPayload(payload []byte) (*HighSkip, error) {
588	hs, dataType, _, err := jsonparserw.Get(payload, "high_skip")
589	// high_skip is optional, but must be an object if it exists
590	if err != nil {
591		switch pkgerrors.Cause(err) {
592		case jsonparser.KeyPathNotFoundError:
593			return nil, nil
594		default:
595			return nil, err
596		}
597	}
598
599	if dataType != jsonparser.Object {
600		return nil, ChainLinkError{fmt.Sprintf("When provided, expected high_skip to be a JSON object, was %v.", dataType)}
601	}
602
603	highSkipSeqnoInt, err := jsonparserw.GetInt(hs, "seqno")
604	if err != nil {
605		return nil, err
606	}
607
608	// highSkipHash can either be null (zero-value of a LinkID) or a hexstring.
609	// We call GetString first instead of Get so we only parse the value
610	// twice for the first link.
611	highSkipHashStr, err := jsonparserw.GetString(hs, "hash")
612	var highSkipHash LinkID
613	if err != nil {
614		// If there was an error parsing as a string, make sure the value is null.
615		_, dataType, _, getErr := jsonparserw.Get(hs, "hash")
616		if getErr != nil {
617			return nil, getErr
618		}
619		if dataType != jsonparser.Null {
620			return nil, ChainLinkError{
621				fmt.Sprintf("high_skip.hash was neither a valid string (%v) nor null.", err.Error()),
622			}
623		}
624	} else {
625		highSkipHash, err = LinkIDFromHex(highSkipHashStr)
626		if err != nil {
627			return nil, err
628		}
629	}
630
631	highSkip := NewHighSkip(keybase1.Seqno(highSkipSeqnoInt), highSkipHash)
632	return &highSkip, nil
633}
634
635func (tmp *ChainLinkUnpacked) unpackPayloadJSON(g *GlobalContext, payload []byte, linkID LinkID) error {
636
637	if !isJSONObject(payload, linkID) {
638		return ChainLinkError{"chain link is not a valid JSON object as expected; found leading junk"}
639	}
640
641	if s, err := jsonparserw.GetString(payload, "body", "key", "fingerprint"); err == nil {
642		if tmp.pgpFingerprint, err = PGPFingerprintFromHex(s); err != nil {
643			return err
644		}
645	}
646	if s, err := jsonparserw.GetString(payload, "body", "key", "kid"); err == nil {
647		tmp.kid = keybase1.KIDFromString(s)
648	}
649	if s, err := jsonparserw.GetString(payload, "body", "key", "eldest_kid"); err == nil {
650		tmp.eldestKID = keybase1.KIDFromString(s)
651	}
652
653	var err error
654	tmp.username, err = jsonparserw.GetString(payload, "body", "key", "username")
655	if err != nil {
656		return err
657	}
658	suid, err := jsonparserw.GetString(payload, "body", "key", "uid")
659	if err != nil {
660		return err
661	}
662	if tmp.uid, err = UIDFromHex(suid); err != nil {
663		return err
664	}
665
666	if prev, err := jsonparserw.GetString(payload, "prev"); err == nil {
667		tmp.prev, err = LinkIDFromHex(prev)
668		if err != nil {
669			return err
670		}
671	}
672
673	highSkip, err := tmp.parseHighSkipFromPayload(payload)
674	if err != nil {
675		return err
676	}
677	tmp.highSkip = highSkip
678
679	tmp.typ, err = jsonparserw.GetString(payload, "body", "type")
680	if err != nil {
681		return err
682	}
683
684	tmp.ctime, err = jsonparserw.GetInt(payload, "ctime")
685	if err != nil {
686		return err
687	}
688
689	seqno, err := jsonparserw.GetInt(payload, "seqno")
690	if err != nil {
691		return err
692	}
693	tmp.seqno = keybase1.Seqno(seqno)
694
695	if tmp.HasRevocations(payload) {
696		tmp.hasRevocations = true
697	}
698
699	// Assume public unless its a number
700	tmp.seqType = keybase1.SeqType_PUBLIC
701	if seqTypeInt, err := jsonparserw.GetInt(payload, "seq_type"); err == nil {
702		tmp.seqType = keybase1.SeqType(seqTypeInt)
703	}
704
705	// Assume false if unsupported
706	tmp.ignoreIfUnsupported = SigIgnoreIfUnsupported(false)
707	if ignore, err := jsonparserw.GetBoolean(payload, "ignore_if_unsupported"); err == nil {
708		tmp.ignoreIfUnsupported = SigIgnoreIfUnsupported(ignore)
709	}
710
711	// Due to an earlier error, it's possible for the merkle root that we signed over
712	// to be in one of two places, so check both.
713	if i, err := jsonparserw.GetInt(payload, "body", "merkle_root", "seqno"); err == nil {
714		tmp.merkleSeqno = keybase1.Seqno(i)
715	} else if i, err := jsonparserw.GetInt(payload, "merkle_root", "seqno"); err == nil {
716		tmp.merkleSeqno = keybase1.Seqno(i)
717	}
718
719	// Hash meta was only ever in the correct place (within body)
720	if s, err := jsonparserw.GetString(payload, "body", "merkle_root", "hash_meta"); err == nil {
721		tmp.merkleHashMeta, err = keybase1.HashMetaFromString(s)
722		if err != nil {
723			return err
724		}
725	}
726
727	ei, err := jsonparserw.GetInt(payload, "expire_in")
728	if err != nil {
729		return err
730	}
731
732	tmp.etime = tmp.ctime + ei
733
734	tmp.payloadHash = fixAndHashPayload(g, payload, linkID)
735
736	if tmp.sigVersion == KeybaseSignatureV2 {
737		tmp.payloadV2 = payload
738	}
739
740	return nil
741}
742
743func (c *ChainLink) UnpackLocal(payload []byte) (err error) {
744	tmp := ChainLinkUnpacked{}
745	err = tmp.unpackPayloadJSON(c.G(), payload, c.id)
746	if err == nil {
747		tmp.payloadLocal = payload
748		c.unpacked = &tmp
749	}
750	return
751}
752
753func (c *ChainLink) UnpackComputedKeyInfos(data []byte) error {
754	if data == nil {
755		return nil
756	}
757	var tmp ComputedKeyInfos
758	tmp.SetGlobalContext(c.G())
759	if err := json.Unmarshal(data, &tmp); err == nil {
760		c.cki = &tmp
761	} else {
762		return err
763	}
764	return nil
765}
766
767func (c *ChainLink) unpackStubbed(raw string) error {
768	ol, err := DecodeStubbedOuterLinkV2(raw)
769	if err != nil {
770		return err
771	}
772	if ol.SeqType == 0 {
773		// Assume public if unset
774		ol.SeqType = keybase1.SeqType_PUBLIC
775	}
776
777	if !ol.IgnoreIfUnsupported.Bool() && !ol.LinkType.IsSupportedType() {
778		return ChainLinkStubbedUnsupportedError{fmt.Sprintf("Stubbed link with type %d is unknown and not marked with IgnoreIfUnsupported", ol.LinkType)}
779	}
780
781	c.id = ol.LinkID()
782
783	// Because the outer link does not have a highSkip parent object, we check
784	// for the nullity of highSkipSeqno to see if highSkip should be set, since
785	// a null highSkipHash is valid when specifying highSkip=0.
786	var highSkipPtr *HighSkip
787	if ol.HighSkipSeqno != nil {
788		highSkip := NewHighSkip(*ol.HighSkipSeqno, *ol.HighSkipHash)
789		highSkipPtr = &highSkip
790	}
791
792	c.unpacked = &ChainLinkUnpacked{
793		prev:                ol.Prev,
794		seqno:               ol.Seqno,
795		seqType:             ol.SeqType,
796		ignoreIfUnsupported: ol.IgnoreIfUnsupported,
797		highSkip:            highSkipPtr,
798		sigVersion:          ol.Version,
799		outerLinkV2:         ol,
800		stubbed:             true,
801	}
802	return nil
803}
804
805func (c *ChainLink) unpackFromLocalStorage(m MetaContext, selfUID keybase1.UID, packed []byte) error {
806	if s, err := jsonparserw.GetString(packed, "s2"); err == nil {
807		return c.unpackStubbed(s)
808	}
809
810	tmp := ChainLinkUnpacked{}
811	var err error
812	tmp.sig, err = jsonparserw.GetString(packed, "sig")
813	if err != nil {
814		return err
815	}
816
817	// Beware that this is server-untrusted data at this point. We'll have to check it
818	// before we can exit without error (see below).
819	tmp.sigVersion = KeybaseSignatureV1
820	if sv, err := jsonparserw.GetInt(packed, "sig_version"); err == nil {
821		tmp.sigVersion = SigVersion(int(sv))
822		if tmp.sigVersion != KeybaseSignatureV1 && tmp.sigVersion != KeybaseSignatureV2 {
823			return ChainLinkError{fmt.Sprintf("Bad sig_version: expected 1 or 2 but got %d", tmp.sigVersion)}
824		}
825	}
826
827	if i, err := jsonparserw.GetInt(packed, "merkle_seqno"); err == nil {
828		tmp.firstAppearedMerkleSeqnoUnverified = keybase1.Seqno(i)
829	}
830
831	var payload []byte
832	switch tmp.sigVersion {
833	case KeybaseSignatureV1:
834		// Use the payload from the signature here, since we always get the full signature with
835		// the attached payload for V1 signatures. Note that we redundantly check that the payload
836		// matches the sig in verifyPayloadV1() on the way out of this Unpack function.
837		payload, err = tmp.Payload()
838		if err != nil {
839			return err
840		}
841	case KeybaseSignatureV2:
842		// use the payload in payload_json
843		data, _, _, err := jsonparserw.Get(packed, "payload_json")
844		if err != nil {
845			return err
846		}
847
848		// unquote it
849		sdata, err := strconv.Unquote(`"` + string(data) + `"`)
850		if err != nil {
851			return err
852		}
853		payload = []byte(sdata)
854	default:
855		err = ChainLinkError{fmt.Sprintf("unhandled signature version %d", tmp.sigVersion)}
856		return err
857	}
858
859	// unpack the payload
860	if err := tmp.unpackPayloadJSON(c.G(), payload, c.id); err != nil {
861		m.Debug("unpack payload json err: %s", err)
862		return err
863	}
864
865	// We previously took the server's word on what version we wanted, but now
866	// we're going to check that it matches what we actually sign over -- what's
867	// in the JSON payload. If it doesn't match, the we error out right here.
868	if err := tmp.assertPayloadSigVersionMatchesHint(payload); err != nil {
869		return err
870	}
871
872	var sigKID, serverKID, payloadKID keybase1.KID
873
874	if tmp.sigVersion == KeybaseSignatureV2 {
875		var ol2 *OuterLinkV2WithMetadata
876		ol2, err = DecodeOuterLinkV2(tmp.sig)
877		if err != nil {
878			return err
879		}
880		if ol2.SeqType == 0 {
881			// Assume public if unset
882			ol2.SeqType = keybase1.SeqType_PUBLIC
883		}
884		tmp.outerLinkV2 = ol2
885		sigKID = ol2.kid
886	}
887
888	payloadKID = tmp.kid
889
890	if kid, err := jsonparserw.GetString(packed, "kid"); err == nil {
891		serverKID = keybase1.KIDFromString(kid)
892	}
893
894	if !payloadKID.IsNil() && !serverKID.IsNil() && !payloadKID.Equal(serverKID) {
895		return ChainLinkKIDMismatchError{
896			fmt.Sprintf("Payload KID (%s) doesn't match server KID (%s).",
897				payloadKID, serverKID),
898		}
899	}
900
901	if !payloadKID.IsNil() && !sigKID.IsNil() && !payloadKID.Equal(sigKID) {
902		return ChainLinkKIDMismatchError{
903			fmt.Sprintf("Payload KID (%s) doesn't match sig KID (%s).",
904				payloadKID, sigKID),
905		}
906	}
907
908	if !serverKID.IsNil() && !sigKID.IsNil() && !serverKID.Equal(sigKID) {
909		return ChainLinkKIDMismatchError{
910			fmt.Sprintf("Server KID (%s) doesn't match sig KID (%s).",
911				serverKID, sigKID),
912		}
913	}
914
915	if tmp.kid.IsNil() && !sigKID.IsNil() {
916		tmp.kid = sigKID
917	}
918	if tmp.kid.IsNil() && !serverKID.IsNil() {
919		tmp.kid = serverKID
920	}
921
922	// Note, we can still be in a situation in which don't know any kids!
923	// That would be bad *if* we need to verify the signature for this link.
924
925	// only unpack the proof_text_full if owner of this link
926	if tmp.uid.Equal(selfUID) {
927		if pt, err := jsonparserw.GetString(packed, "proof_text_full"); err == nil {
928			tmp.proofText = pt
929		}
930	}
931
932	c.unpacked = &tmp
933
934	// IF we're loaded from *trusted* storage, like our local
935	// DB, then we can skip verification later
936	if b, err := jsonparserw.GetBoolean(packed, "sig_verified"); err == nil && b {
937		c.sigVerified = true
938		m.VLogf(VLog1, "| Link is marked as 'sig_verified'")
939		if ckidata, _, _, err := jsonparserw.Get(packed, "computed_key_infos"); err == nil {
940			if uerr := c.UnpackComputedKeyInfos(ckidata); uerr != nil {
941				m.Warning("Problem unpacking computed key infos: %s", uerr)
942			}
943		}
944	}
945	if b, err := jsonparserw.GetBoolean(packed, "hash_verified"); err == nil && b {
946		c.hashVerified = true
947	}
948	if b, err := jsonparserw.GetBoolean(packed, "chain_verified"); err == nil && b {
949		c.chainVerified = true
950	}
951	if b, err := jsonparserw.GetBoolean(packed, "payload_verified"); err == nil && b {
952		c.payloadVerified = true
953	}
954	if i, err := jsonparserw.GetInt(packed, "disk_version"); err == nil {
955		c.diskVersion = int(i)
956	}
957
958	// It is not acceptable to digest sig_id from the server, but we do derive it
959	// as we unpack the server reply (see VerifyLink), and it is acceptable to
960	// read it out of a locally-stored chainlink. Note this field is required,
961	// and if we don't have it, there has been a major problem.
962	s, err := jsonparserw.GetString(packed, "sig_id")
963	if err != nil {
964		return err
965	}
966	c.unpacked.sigID, err = keybase1.SigIDFromString(s)
967	if err != nil {
968		return err
969	}
970
971	// sigID is set as a side effect of verifying the link. Make sure we do that
972	// on the way out of this function, before we return success. But it's not
973	// needed in the cased of a stubbed V2 link.
974	err = c.VerifyLink()
975	if err != nil {
976		return err
977	}
978
979	c.G().VDL.Log(VLog1, "| Unpacked Link %s", c.id)
980
981	return nil
982}
983
984func (tmp *ChainLinkUnpacked) Payload() ([]byte, error) {
985	// local track payloads are stored in ChainLinkUnpacked.
986	// if anything there, use it:
987	if len(tmp.payloadLocal) > 0 {
988		return tmp.payloadLocal, nil
989	}
990
991	switch tmp.sigVersion {
992	case KeybaseSignatureV1:
993		// v1 links have the payload inside the sig
994		sigPayload, _, _, err := SigExtractPayloadAndKID(tmp.sig)
995		return sigPayload, err
996	case KeybaseSignatureV2:
997		// v2 links have the payload in ChainLinkUnpacked
998		return tmp.payloadV2, nil
999	default:
1000		return nil, ChainLinkError{msg: fmt.Sprintf("unexpected signature version: %d", tmp.sigVersion)}
1001	}
1002}
1003
1004func (tmp *ChainLinkUnpacked) assertPayloadSigVersionMatchesHint(payload []byte) error {
1005	payloadVersion, err := getSigVersionFromPayload(payload)
1006	if err != nil {
1007		return err
1008	}
1009	if tmp.sigVersion != payloadVersion {
1010		return ChainLinkError{msg: fmt.Sprintf("Big sigchain version hint from server: %d != %d", tmp.sigVersion, payloadVersion)}
1011	}
1012	return nil
1013}
1014
1015func (c *ChainLink) CheckNameAndID(s NormalizedUsername, i keybase1.UID) error {
1016
1017	// We can't check name and ID if we have compacted chain link with no
1018	// payload JSON
1019	if c.IsStubbed() {
1020		return nil
1021	}
1022
1023	if c.unpacked.uid.NotEqual(i) {
1024		return UIDMismatchError{
1025			fmt.Sprintf("UID mismatch %s != %s in Link %s", c.unpacked.uid, i, c.id),
1026		}
1027	}
1028	if !s.Eq(NewNormalizedUsername(c.unpacked.username)) {
1029		return NewBadUsernameErrorWithFullMessage(
1030			fmt.Sprintf("Username mismatch %s != %s in Link %s",
1031				c.unpacked.username, s, c.id))
1032	}
1033	return nil
1034
1035}
1036
1037func ComputeLinkID(d []byte) LinkID {
1038	h := sha256.Sum256(d)
1039	return LinkID(h[:])
1040}
1041
1042func (c *ChainLink) getPayloadHash() LinkID {
1043	if c.unpacked == nil {
1044		return nil
1045	}
1046	return c.unpacked.payloadHash
1047}
1048
1049func (c *ChainLink) verifyHashV2() error {
1050	if c.hashVerified {
1051		return nil
1052	}
1053	ol := c.unpacked.outerLinkV2
1054	if ol == nil {
1055		return fmt.Errorf("nil outer link V2 unpacking")
1056	}
1057	if h := ol.LinkID(); !FastByteArrayEq(h, c.id) {
1058		return SigchainV2MismatchedHashError{}
1059	}
1060	c.hashVerified = true
1061	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.hashVerified = true })
1062	return nil
1063}
1064
1065func (c *ChainLink) verifyHashV1() error {
1066	if c.hashVerified {
1067		return nil
1068	}
1069	h := c.getPayloadHash()
1070	if !FastByteArrayEq(h[:], c.id) {
1071		return fmt.Errorf("hash mismatch in verifyHashV1")
1072	}
1073	c.hashVerified = true
1074	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.hashVerified = true })
1075	return nil
1076}
1077
1078func (c *ChainLink) markChainVerified() {
1079	c.chainVerified = true
1080	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.chainVerified = true })
1081}
1082
1083// getFixedPayload usually just returns c.unpacked.Payload(), but sometimes
1084// it adds extra whitespace to work around server-side bugs.
1085func (c ChainLink) getFixedPayload() []byte {
1086	payload, err := c.unpacked.Payload()
1087	if err != nil {
1088		return nil
1089	}
1090	return c.fixPayload(payload, c.id)
1091}
1092
1093func (c *ChainLink) fixPayload(payload []byte, linkID LinkID) []byte {
1094	if s, ok := badWhitespaceChainLinks[linkID.Export()]; ok {
1095		if payload[len(payload)-1] != '\n' {
1096			c.G().Log.Debug("Fixing payload by adding newline on link '%s': %s", linkID.Export(), s)
1097
1098			// Careful not to mutate the passed in payload via append. So make
1099			// a copy first.
1100			ret := make([]byte, len(payload))
1101			copy(ret, payload)
1102			ret = append(ret, '\n')
1103
1104			return ret
1105		}
1106	}
1107	return payload
1108}
1109
1110// fixAndHashPayload does the inverse of ChainLink#fixPayload. It strips off a trailing
1111// newline for buggy signature payloads, and then computes the hash of the result. This is
1112// necessary now that we are computing chain link IDs from signature bodies.
1113func fixAndHashPayload(g *GlobalContext, payload []byte, linkID LinkID) []byte {
1114	toHash := payload
1115	if s, ok := badWhitespaceChainLinks[linkID.Export()]; ok {
1116		last := len(payload) - 1
1117		if payload[last] == '\n' {
1118			g.Log.Debug("Fixing payload hash by stripping newline on link '%s': %s", linkID.Export(), s)
1119			toHash = payload[0:last]
1120		}
1121	}
1122	ret := sha256.Sum256(toHash)
1123	return ret[:]
1124}
1125
1126// two chainlinks in the database have leading padding via space characters
1127// or newline characters. In these two cases, we strip off leading space
1128// before checking if they are JSON objects. In all other cases, the first
1129// character must be '{'
1130var paddedChainLinks = map[keybase1.LinkID]bool{
1131	"ebcf3fab043970beee1198f16098f411331b7dbaa865a285908d82fc58df1577": true,
1132	"c094f59c77da5e7d4023025744f8c533a098b2136f2113dc02b0745568c2faa3": true,
1133}
1134
1135func stripPadding(in []byte) []byte {
1136	for i, b := range in {
1137		if b != ' ' && b != '\n' {
1138			return in[i:]
1139		}
1140	}
1141	return []byte{}
1142}
1143
1144func isPadded(in []byte) bool {
1145	return len(in) > 0 && (in[0] == ' ' || in[0] == '\n')
1146}
1147
1148func isJSONObject(payload []byte, linkID LinkID) bool {
1149	if isPadded(payload) && paddedChainLinks[linkID.Export()] {
1150		payload = stripPadding(payload)
1151	}
1152	return msgpack.IsJSONObject(payload)
1153}
1154
1155func inferSigVersion(payload []byte, linkID LinkID) SigVersion {
1156
1157	// Version 1 payloads are JSON and must start with an opening '{'
1158	if isJSONObject(payload, linkID) {
1159		return KeybaseSignatureV1
1160	}
1161
1162	// Version 2 payloads are Msgpack and must be arrays, so they must
1163	// fit the following requirements. The case where b == 0xdc or
1164	// b = 0xdd are far-fetched, since that would mean a large or very
1165	// large packing. But still, allow any valid array up front.
1166	if msgpack.IsEncodedMsgpackArray(payload) {
1167		return KeybaseSignatureV2
1168	}
1169
1170	// We didn't find anything useful, so mark it a "none"
1171	return KeybaseNullSigVersion
1172}
1173
1174func assertCorrectSigVersion(expected SigVersion, payload []byte, linkID LinkID) error {
1175	vInferred := inferSigVersion(payload, linkID)
1176	if vInferred != expected {
1177		return ChainLinkError{msg: fmt.Sprintf("chainlink in wrong format; expected version=%d but payload was %d", expected, vInferred)}
1178	}
1179	return nil
1180}
1181
1182func (c *ChainLink) getSigPayload() ([]byte, error) {
1183	if c.IsStubbed() {
1184		return nil, ChainLinkError{"Cannot verify sig with nil outer link v2"}
1185	}
1186	v := c.unpacked.sigVersion
1187	var ret []byte
1188	switch v {
1189	case KeybaseSignatureV1:
1190		ret = c.getFixedPayload()
1191	case KeybaseSignatureV2:
1192		ret = c.unpacked.outerLinkV2.raw
1193	default:
1194		return nil, ChainLinkError{msg: fmt.Sprintf("unexpected signature version: %d", c.unpacked.sigVersion)}
1195	}
1196
1197	err := assertCorrectSigVersion(v, ret, c.id)
1198	if err != nil {
1199		return nil, err
1200	}
1201	return ret, nil
1202}
1203
1204func (c *ChainLink) verifyPayloadV2() error {
1205
1206	if c.payloadVerified {
1207		return nil
1208	}
1209
1210	ol := c.unpacked.outerLinkV2
1211
1212	if ol == nil {
1213		return ChainLinkError{"no outer V2 structure available"}
1214	}
1215
1216	version := KeybaseSignatureV2
1217	seqno := c.getSeqnoFromPayload()
1218	prev := c.getPrevFromPayload()
1219	curr := c.getPayloadHash()
1220	innerVersion := c.unpacked.sigVersion
1221	if innerVersion != version {
1222		return ChainLinkError{fmt.Sprintf("In chainlink v2, expected inner link to match; got %d", innerVersion)}
1223	}
1224	ignoreIfUnsupported := c.getIgnoreIfUnsupportedFromPayload()
1225	linkType, err := c.GetSigchainV2TypeFromInner(ignoreIfUnsupported)
1226	if err != nil {
1227		return err
1228	}
1229	seqType := c.getSeqTypeFromPayload()
1230	highSkip := c.getHighSkipFromPayload()
1231
1232	if err := ol.AssertFields(version, seqno, prev, curr, linkType, seqType, ignoreIfUnsupported, highSkip); err != nil {
1233		return err
1234	}
1235
1236	c.markPayloadVerified(ol.sigID)
1237	return nil
1238}
1239
1240func (c *ChainLink) markPayloadVerified(sigid keybase1.SigID) {
1241	if c.unpacked != nil {
1242		c.unpacked.sigID = sigid
1243	}
1244	c.payloadVerified = true
1245	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.payloadVerified = true })
1246}
1247
1248func (c *ChainLink) verifyPayloadV1() error {
1249	if c.payloadVerified {
1250		return nil
1251	}
1252	sigid, err := SigAssertPayload(c.unpacked.sig, c.getFixedPayload())
1253	if err != nil {
1254		return err
1255	}
1256	params := keybase1.SigIDSuffixParametersFromTypeAndVersion(c.unpacked.typ, keybase1.SigVersion(1))
1257	c.markPayloadVerified(sigid.ToSigID(params))
1258	return nil
1259}
1260
1261func (c *ChainLink) getSeqnoFromPayload() keybase1.Seqno {
1262	if c.unpacked != nil {
1263		return c.unpacked.seqno
1264	}
1265	return keybase1.Seqno(-1)
1266}
1267
1268func (c *ChainLink) GetSeqno() keybase1.Seqno {
1269	return c.unpacked.seqno
1270}
1271
1272func (c *ChainLink) GetHighSkip() *HighSkip {
1273	return c.unpacked.highSkip
1274}
1275
1276func (c *ChainLink) GetSigID() keybase1.SigID {
1277	return c.unpacked.sigID
1278}
1279
1280func (c *ChainLink) GetSigCheckCache() (cki *ComputedKeyInfos) {
1281	if c.sigVerified && c.cki != nil {
1282		cki = c.cki
1283	}
1284	return cki
1285}
1286
1287func (c *ChainLink) PutSigCheckCache(cki *ComputedKeyInfos) {
1288	c.G().Log.Debug("Caching SigCheck for link %s (version: %d)", c.id, cki.Version)
1289	c.sigVerified = true
1290	c.dirty = true
1291	c.cki = cki
1292	c.G().LinkCache().Mutate(c.id, func(c *ChainLink) { c.cki = cki })
1293}
1294
1295func (c *ChainLink) VerifySigWithKeyFamily(ckf ComputedKeyFamily) (err error) {
1296	var key GenericKey
1297	var verifyKID keybase1.KID
1298	var sigIDBase keybase1.SigIDBase
1299	var params keybase1.SigIDSuffixParameters
1300
1301	if c.IsStubbed() {
1302		return ChainLinkError{"cannot verify signature -- none available; is this a stubbed out link?"}
1303	}
1304
1305	if c.unpacked != nil && c.unpacked.sigDropped {
1306		return ChainLinkError{"cannot verify signature -- none available; sig dropped intentionally."}
1307	}
1308
1309	verifyKID, err = c.checkServerSignatureMetadata(ckf)
1310	if err != nil {
1311		return err
1312	}
1313
1314	if key, _, err = ckf.FindActiveSibkeyAtTime(verifyKID, c.GetCTime()); err != nil {
1315		return err
1316	}
1317
1318	if err = c.VerifyLink(); err != nil {
1319		return err
1320	}
1321
1322	var sigPayload []byte
1323	sigPayload, err = c.getSigPayload()
1324	if err != nil {
1325		return err
1326	}
1327
1328	if sigIDBase, err = key.VerifyString(c.G().Log, c.unpacked.sig, sigPayload); err != nil {
1329		return BadSigError{err.Error()}
1330	}
1331	params = keybase1.SigIDSuffixParametersFromTypeAndVersion(c.unpacked.typ, keybase1.SigVersion(c.unpacked.sigVersion))
1332	c.unpacked.sigID = sigIDBase.ToSigID(params)
1333
1334	return nil
1335}
1336
1337func putLinkToCache(m MetaContext, link *ChainLink) {
1338	m.G().LinkCache().Put(m, link.id, link.Copy())
1339}
1340
1341func NewChainLink(g *GlobalContext, parent *SigChain, id LinkID) *ChainLink {
1342	return &ChainLink{
1343		Contextified: NewContextified(g),
1344		parent:       parent,
1345		id:           id,
1346	}
1347}
1348
1349func ImportLinkFromStorage(m MetaContext, id LinkID, selfUID keybase1.UID) (*ChainLink, error) {
1350	link, ok := m.G().LinkCache().Get(id)
1351	if ok {
1352		link.Contextified = NewContextified(m.G())
1353		return &link, nil
1354	}
1355
1356	var ret *ChainLink
1357	data, _, err := m.G().LocalDb.GetRaw(DbKey{Typ: DBLink, Key: id.String()})
1358	if err == nil && data != nil {
1359		// May as well recheck onload (maybe revisit this)
1360		ret = NewChainLink(m.G(), nil, id)
1361		if err = ret.unpackFromLocalStorage(m, selfUID, data); err != nil {
1362			return nil, err
1363		}
1364		ret.storedLocally = true
1365
1366		m.G().LinkCache().Put(m, id, ret.Copy())
1367	}
1368	return ret, err
1369}
1370
1371func (c *ChainLink) VerifyLink() error {
1372	v := c.unpacked.sigVersion
1373	switch v {
1374	case 1:
1375		return c.verifyLinkV1()
1376	case 2:
1377		return c.verifyLinkV2()
1378	default:
1379		return ChainLinkError{msg: fmt.Sprintf("unexpected signature version: %d", v)}
1380	}
1381}
1382
1383func (c *ChainLink) verifyLinkV1() error {
1384	if err := c.verifyHashV1(); err != nil {
1385		return err
1386	}
1387	return c.verifyPayloadV1()
1388}
1389
1390func (c *ChainLink) verifyLinkV2() error {
1391	if err := c.verifyHashV2(); err != nil {
1392		return err
1393	}
1394
1395	// We might not have an unpacked payload at all, if it's a V2 link
1396	// without a body (for BW savings)
1397	if c.IsStubbed() {
1398		return nil
1399	}
1400
1401	return c.verifyPayloadV2()
1402}
1403
1404func (c *ChainLink) GetSigchainV2TypeFromInner(ignoreIfUnsupported SigIgnoreIfUnsupported) (SigchainV2Type, error) {
1405	if c.unpacked == nil || c.unpacked.typ == "" {
1406		return SigchainV2TypeNone, errors.New("chain link not unpacked")
1407	}
1408	return SigchainV2TypeFromV1TypeAndRevocations(c.unpacked.typ, SigHasRevokes(c.HasRevocations()), ignoreIfUnsupported)
1409}
1410
1411func (c *ChainLink) GetSigchainV2TypeFromV2Shell() (SigchainV2Type, error) {
1412	if c.unpacked == nil {
1413		return SigchainV2TypeNone, errors.New("GetSigchainV2TypeFromV2Shell: chain link not unpacked")
1414	}
1415	if c.unpacked.outerLinkV2 == nil {
1416		return SigchainV2TypeNone, errors.New("GetSigchainV2TypeFromV2Shell: chain link has no v2 shell")
1417	}
1418	return c.unpacked.outerLinkV2.LinkType, nil
1419}
1420
1421// GetSigchainV2Type is a helper function for getting a ChainLink's type. If it
1422// is a v2 link (that may or may not be stubbed), return the type from the
1423// outer link, otherwise from the inner link.
1424func (c *ChainLink) GetSigchainV2Type() (SigchainV2Type, error) {
1425	if c.unpacked == nil {
1426		return SigchainV2TypeNone, errors.New("chain link is not unpacked")
1427	}
1428	if c.unpacked.outerLinkV2 == nil && c.unpacked.typ == "" {
1429		return SigchainV2TypeNone, errors.New("chain inner link type is not unpacked, and has no v2 shell")
1430	}
1431	if c.unpacked.outerLinkV2 != nil {
1432		return c.GetSigchainV2TypeFromV2Shell()
1433	}
1434	return c.GetSigchainV2TypeFromInner(c.GetIgnoreIfSupported())
1435}
1436
1437func (c *ChainLink) checkServerSignatureMetadata(ckf ComputedKeyFamily) (ret keybase1.KID, err error) {
1438	var serverKID, linkKID, verifyKID keybase1.KID
1439
1440	// PC: I'm not sure what exactly this was trying to do since
1441	// c.packed.kid can only be equal to c.unpacked.kid at this point.
1442	// The following two lines result in the least changes below:
1443	serverKID = c.unpacked.kid
1444	linkKID = c.unpacked.kid
1445
1446	if linkKID.Exists() && serverKID.Exists() && linkKID.NotEqual(serverKID) {
1447		// Check the KID. This is actually redundant of a check we do in Unpack(),
1448		// but I'm keeping it here in case we change the way we unpack in the
1449		// future.  --jacko
1450		return ret, ChainLinkKIDMismatchError{
1451			fmt.Sprintf("Payload KID (%s) doesn't match server KID (%s).",
1452				linkKID, serverKID),
1453		}
1454	}
1455
1456	if serverKID.Exists() {
1457		verifyKID = serverKID
1458	}
1459
1460	if linkKID.Exists() {
1461		verifyKID = linkKID
1462	}
1463
1464	if verifyKID.IsNil() {
1465		return ret, ChainLinkError{"cannot verify signature without a KID"}
1466	}
1467
1468	serverKey, err := ckf.FindKeyWithKIDUnsafe(verifyKID)
1469	if err != nil {
1470		return ret, err
1471	}
1472
1473	// Check the fingerprint.
1474	if c.unpacked.pgpFingerprint != nil {
1475		payloadFingerprintStr := c.unpacked.pgpFingerprint.String()
1476		serverFingerprintStr := ""
1477		if fp := GetPGPFingerprintFromGenericKey(serverKey); fp != nil {
1478			serverFingerprintStr = fp.String()
1479		}
1480		if payloadFingerprintStr != serverFingerprintStr {
1481			return ret, ChainLinkFingerprintMismatchError{
1482				fmt.Sprintf("Payload fingerprint (%s) did not match server key (%s).",
1483					payloadFingerprintStr, serverFingerprintStr),
1484			}
1485		}
1486	}
1487	return verifyKID, nil
1488}
1489
1490func (c *ChainLink) Store(m MetaContext) (didStore bool, err error) {
1491
1492	m.VLogf(VLog1, "| Storing Link %s...", c.id)
1493	if c.storedLocally && !c.dirty {
1494		m.VLogf(VLog1, "| Bailed on link %s since wasn't dirty...", c.id)
1495		return didStore, nil
1496	}
1497
1498	if err = c.VerifyLink(); err != nil {
1499		return false, err
1500	}
1501
1502	if !c.hashVerified || (!c.IsStubbed() && !c.payloadVerified) || !c.chainVerified {
1503		err = fmt.Errorf("Internal error; should have been verified in Store(); hashVerified=%v, isStubbed=%v, payloadVerified=%v, chainVerified=%v",
1504			c.hashVerified, c.IsStubbed(), c.payloadVerified, c.chainVerified)
1505		return false, err
1506	}
1507
1508	packed, err := c.Pack()
1509	if err != nil {
1510		return false, err
1511	}
1512
1513	key := DbKey{Typ: DBLink, Key: c.id.String()}
1514
1515	// Don't write with any aliases
1516	if err = m.G().LocalDb.Put(key, nil, packed); err != nil {
1517		return false, err
1518	}
1519	m.VLogf(VLog1, "| Store Link %s", c.id)
1520
1521	c.storedLocally = true
1522	c.dirty = false
1523	return true, nil
1524}
1525
1526func (c *ChainLink) GetPGPFingerprint() *PGPFingerprint {
1527	return c.unpacked.pgpFingerprint
1528}
1529func (c *ChainLink) GetKID() keybase1.KID {
1530	return c.unpacked.kid
1531}
1532
1533func (c *ChainLink) MatchFingerprint(fp PGPFingerprint) bool {
1534	return c.unpacked.pgpFingerprint != nil && fp.Eq(*c.unpacked.pgpFingerprint)
1535}
1536
1537func (c *ChainLink) ToEldestKID() keybase1.KID {
1538	if !c.unpacked.eldestKID.IsNil() {
1539		return c.unpacked.eldestKID
1540	}
1541	// For links that don't explicitly specify an eldest KID, it's implied
1542	// that we're starting a new subchain, so the signing KID is the
1543	// eldest.
1544	return c.GetKID()
1545}
1546
1547// ToLinkSummary converts a ChainLink into a MerkleTriple object.
1548func (c ChainLink) ToMerkleTriple() *MerkleTriple {
1549	if c.IsStubbed() {
1550		return nil
1551	}
1552	return &MerkleTriple{
1553		Seqno:  c.GetSeqno(),
1554		LinkID: c.id,
1555		SigID:  c.GetSigID().StripSuffix(),
1556	}
1557}
1558
1559//=========================================================================
1560// IsInCurrentFamily checks to see if the given chainlink
1561// was signed by a key in the current family.
1562func (c *ChainLink) IsInCurrentFamily(u *User) bool {
1563	eldest := u.GetEldestKID()
1564	if eldest.IsNil() {
1565		return false
1566	}
1567	return eldest.Equal(c.ToEldestKID())
1568}
1569
1570//=========================================================================
1571
1572func (c *ChainLink) Typed() TypedChainLink {
1573	return c.typed
1574}
1575
1576func (c *ChainLink) Copy() ChainLink {
1577	var unpacked ChainLinkUnpacked
1578	if c.unpacked != nil {
1579		unpacked = *c.unpacked
1580	}
1581
1582	r := *c
1583	r.SetGlobalContext(nil)
1584	r.parent = nil
1585	r.chainVerified = c.chainVerified
1586	r.hashVerified = c.hashVerified
1587	r.payloadVerified = c.payloadVerified
1588	r.unpacked = &unpacked
1589
1590	if c.cki != nil {
1591		r.cki = c.cki.ShallowCopy()
1592	}
1593
1594	return r
1595}
1596
1597func (c ChainLink) LinkID() LinkID {
1598	return c.id
1599}
1600
1601func (c ChainLink) AllowStubbing() bool {
1602	if c.unpacked.outerLinkV2 == nil {
1603		return false
1604	}
1605	return c.unpacked.outerLinkV2.LinkType.AllowStubbing()
1606}
1607
1608// IsHighUserLink determines whether a chainlink counts as "high" in a user's chain,
1609// which is defined as an Eldest link, a link with seqno=1, a link that is Sibkey,
1610// PGPUpdate, Revoke, or any link that is revoking.
1611func (c ChainLink) IsHighUserLink(mctx MetaContext, uid keybase1.UID) (bool, error) {
1612	v2Type, err := c.GetSigchainV2Type()
1613	if err != nil {
1614		return false, err
1615	}
1616
1617	hardcodedEldest := false
1618	if c.GetSeqno() > 1 {
1619		prevLink := c.parent.GetLinkFromSeqno(c.GetSeqno() - 1)
1620		if prevLink == nil {
1621			return false, ChainLinkWrongSeqnoError{}
1622		}
1623		hardcodedEldest, err = isSubchainStart(mctx, &c, prevLink, uid)
1624		if err != nil {
1625			return false, err
1626		}
1627	}
1628
1629	isFirstLink := v2Type == SigchainV2TypeEldest || c.GetSeqno() == 1 || hardcodedEldest
1630	isNewHighLink := isFirstLink ||
1631		v2Type == SigchainV2TypeRevoke ||
1632		v2Type == SigchainV2TypeWebServiceBindingWithRevoke ||
1633		v2Type == SigchainV2TypeCryptocurrencyWithRevoke ||
1634		v2Type == SigchainV2TypeSibkey ||
1635		v2Type == SigchainV2TypeWotVouchWithRevoke ||
1636		v2Type == SigchainV2TypePGPUpdate
1637	return isNewHighLink, nil
1638}
1639
1640// ExpectedNextHighSkip returns the expected highSkip of the immediately
1641// subsequent link in the chain (which may not exist yet). This function can
1642// only be called after VerifyChain has processed the chainLink, and set
1643// c.computedHighSkip.
1644func (c ChainLink) ExpectedNextHighSkip(mctx MetaContext, uid keybase1.UID) (HighSkip, error) {
1645	isHigh, err := c.IsHighUserLink(mctx, uid)
1646	if err != nil {
1647		return HighSkip{}, err
1648	}
1649	if isHigh {
1650		return NewHighSkip(c.GetSeqno(), c.id), nil
1651	}
1652	if c.computedHighSkip == nil {
1653		return HighSkip{}, NewUserReverifyNeededError("Expected to have already computed this link's HighSkip, but it was not computed.")
1654	}
1655	return *c.computedHighSkip, nil
1656}
1657