1package libkb
2
3import (
4	"fmt"
5	"io/ioutil"
6
7	"github.com/buger/jsonparser"
8	"github.com/keybase/client/go/jsonparserw"
9	keybase1 "github.com/keybase/client/go/protocol/keybase1"
10)
11
12func LoadUPAKLite(arg LoadUserArg) (ret *keybase1.UPKLiteV1AllIncarnations, err error) {
13	uid := arg.uid
14	m := arg.m
15
16	user, err := LoadUserFromServer(m, uid, nil)
17	if err != nil {
18		return nil, err
19	}
20	leaf, err := lookupMerkleLeaf(m, uid, false, nil, MerkleOpts{NoServerPolling: false})
21	if err != nil {
22		return nil, err
23	}
24	loader := NewHighSigChainLoader(m, user, leaf)
25	highChain, err := loader.Load()
26	if err != nil {
27		return nil, err
28	}
29	return buildUPKLiteAllIncarnations(m, user, leaf, highChain)
30}
31
32type HighSigChainLoader struct {
33	MetaContextified
34	user      *User
35	leaf      *MerkleUserLeaf
36	chain     *HighSigChain
37	chainType *ChainType
38	ckf       ComputedKeyFamily
39	dirtyTail *MerkleTriple
40}
41
42type HighSigChain struct {
43	MetaContextified
44	uid        keybase1.UID
45	username   NormalizedUsername
46	chainLinks ChainLinks
47	// for a locally delegated key
48	localCki *ComputedKeyInfos
49	// For a user who has never done a reset, this is 1.
50	currentSubchainStart keybase1.Seqno
51	prevSubchains        []ChainLinks
52}
53
54const UPKLiteMinorVersionCurrent = keybase1.UPKLiteMinorVersion_V0
55
56func NewHighSigChainLoader(m MetaContext, user *User, leaf *MerkleUserLeaf) *HighSigChainLoader {
57	hsc := HighSigChain{
58		MetaContextified: NewMetaContextified(m),
59		uid:              user.GetUID(),
60		username:         user.GetNormalizedName(),
61	}
62	loader := HighSigChainLoader{
63		user:             user,
64		leaf:             leaf,
65		chain:            &hsc,
66		chainType:        PublicChain,
67		MetaContextified: NewMetaContextified(m),
68	}
69	loader.ckf.kf = user.GetKeyFamily()
70	return &loader
71}
72
73func (l *HighSigChainLoader) Load() (ret *HighSigChain, err error) {
74	// request new links (and the unverified tail) from the server
75	// and put them into the highSigChain
76	err = l.LoadFromServer()
77	if err != nil {
78		return nil, err
79	}
80	// verify the chain
81	err = l.chain.VerifyChain(l.M())
82	if err != nil {
83		return nil, err
84	}
85	// compute keys
86	err = l.VerifySigsAndComputeKeys()
87	if err != nil {
88		return nil, err
89	}
90	return l.chain, nil
91}
92
93func (l *HighSigChainLoader) selfUID() (uid keybase1.UID) {
94	// for now let's always assume this isn't applicable, because there's
95	// no distinction for loading yourself
96	return uid
97}
98
99func (l *HighSigChainLoader) LoadFromServer() (err error) {
100	srv := l.GetMerkleTriple()
101	l.dirtyTail, err = l.chain.LoadFromServer(l.M(), srv, l.selfUID())
102	return err
103}
104
105func (hsc *HighSigChain) LoadFromServer(m MetaContext, t *MerkleTriple, selfUID keybase1.UID) (dirtyTail *MerkleTriple, err error) {
106	// get the high sigs from the server
107	// ------------------
108	m, tbs := m.WithTimeBuckets()
109
110	apiArg := APIArg{
111		Endpoint:    "sig/get_high",
112		SessionType: APISessionTypeOPTIONAL,
113		Args: HTTPArgs{
114			"uid": S{Val: hsc.uid.String()},
115			"c3":  I{Val: int(sigCompression3Unstubbed)},
116		},
117	}
118	resp, finisher, err := m.G().API.GetResp(m, apiArg)
119	if err != nil {
120		return nil, err
121	}
122	defer finisher()
123	recordFin := tbs.Record("HighSigChain.LoadFromServer.ReadAll")
124	body, err := ioutil.ReadAll(resp.Body)
125	if err != nil {
126		recordFin()
127		return nil, err
128	}
129	recordFin()
130
131	// parse the response
132	// ------------------
133	if val, err := jsonparserw.GetInt(body, "status", "code"); err == nil {
134		if keybase1.StatusCode(val) == keybase1.StatusCode_SCDeleted {
135			return nil, UserDeletedError{}
136		}
137	}
138	var links ChainLinks
139	var lastLink *ChainLink
140
141	_, err = jsonparserw.ArrayEach(body, func(value []byte, dataType jsonparser.ValueType, offset int, inErr error) {
142		var link *ChainLink
143
144		parentSigChain := &SigChain{} // because we don't want the cache to use these
145		link, err = ImportLinkFromServer(m, parentSigChain, value, selfUID)
146		if err != nil {
147			m.Debug("Error importing link: %s", err.Error())
148		}
149		links = append(links, link)
150		lastLink = link
151	}, "sigs")
152	if err != nil {
153		return nil, err
154	}
155
156	foundTail, err := lastLink.checkAgainstMerkleTree(t)
157	if err != nil {
158		return nil, err
159	}
160	if !foundTail {
161		err = fmt.Errorf("Last link is not the tail")
162		return nil, err
163	}
164	dirtyTail = lastLink.ToMerkleTriple()
165
166	hsc.chainLinks = links
167	return dirtyTail, err
168}
169
170func (hsc *HighSigChain) VerifyChain(m MetaContext) (err error) {
171	defer m.Trace("HighSigChain.VerifyChain", &err)()
172
173	for i := len(hsc.chainLinks) - 1; i >= 0; i-- {
174		curr := hsc.chainLinks[i]
175		m.VLogf(VLog1, "| verify high chain link %d (%s)", curr.GetSeqno(), curr.id)
176		if err = curr.VerifyLink(); err != nil {
177			return err
178		}
179		var expectedPrevID LinkID
180		var expectedPrevSeqno keybase1.Seqno
181		if curr.GetHighSkip() != nil {
182			expectedPrevSeqno = curr.GetHighSkip().Seqno
183			expectedPrevID = curr.GetHighSkip().Hash
184		} else {
185			// fallback to normal prevs if the link doesn't have a high_skip
186			expectedPrevSeqno = curr.GetSeqno() - 1
187			expectedPrevID = curr.GetPrev()
188		}
189		if i == 0 && (expectedPrevSeqno != 0 || expectedPrevID != nil) {
190			return ChainLinkPrevHashMismatchError{
191				fmt.Sprintf("The first link should have 0,nil for it's expected previous. It had %d, %s", expectedPrevSeqno, expectedPrevID),
192			}
193		}
194		if i > 0 {
195			prev := hsc.chainLinks[i-1]
196			if !prev.id.Eq(expectedPrevID) {
197				return ChainLinkPrevHashMismatchError{fmt.Sprintf("Chain mismatch at seqno=%d", curr.GetSeqno())}
198			}
199			if prev.GetSeqno() != expectedPrevSeqno {
200				return ChainLinkWrongSeqnoError{fmt.Sprintf("Chain seqno mismatch at seqno=%d (previous=%d)", curr.GetSeqno(), prev.GetSeqno())}
201			}
202		}
203		if err = curr.CheckNameAndID(hsc.username, hsc.uid); err != nil {
204			return err
205		}
206		// this isn't being used for anything right now, but it might be useful
207		// if we ever want to do caching, especially as it can be distinguished
208		// from the other field, chainVerified
209		curr.highChainVerified = true
210	}
211	return nil
212}
213
214func (l *HighSigChainLoader) VerifySigsAndComputeKeys() (err error) {
215	_, err = l.chain.VerifySigsAndComputeKeys(l.M(), l.leaf.eldest, &l.ckf)
216	return err
217}
218
219func (hsc *HighSigChain) verifySigsAndComputeKeysCurrent(m MetaContext, eldest keybase1.KID, ckf *ComputedKeyFamily) (linksConsumed int, err error) {
220	// this is the case immediately after a reset
221	if ckf.kf == nil || eldest.IsNil() {
222		m.VLogf(VLog1, "UPAKLite short-circuit verifySigsAndComputeKeysCurrent, since no Key available")
223		hsc.localCki = NewComputedKeyInfos(hsc.G())
224		ckf.cki = hsc.localCki
225		return 0, err
226	}
227
228	var links ChainLinks
229	links, err = cropToRightmostSubchain(m, hsc.chainLinks, eldest, hsc.uid)
230	if err != nil {
231		return 0, err
232	}
233	if len(links) == 0 {
234		// actually, not sure how this can happen without eldest being nil
235		m.VLogf(VLog1, "Empty chain after we limited to eldest %s", eldest)
236		hsc.localCki = NewComputedKeyInfos(hsc.G())
237		ckf.cki = hsc.localCki
238		return 0, nil
239	}
240
241	hsc.currentSubchainStart = links[0].GetSeqno()
242	m.VLogf(VLog1, "UPAKLite verifying current chain starting at %d", int(hsc.currentSubchainStart))
243	_, ckf.cki, err = verifySubchain(m, hsc.username, *ckf.kf, links)
244	return len(links), err
245}
246
247func (hsc *HighSigChain) VerifySigsAndComputeKeys(m MetaContext, eldest keybase1.KID, ckf *ComputedKeyFamily) (cached bool, err error) {
248	username := hsc.username
249	uid := hsc.uid
250	hsc.currentSubchainStart = 0
251
252	// current
253	linksConsumed, err := hsc.verifySigsAndComputeKeysCurrent(m, eldest, ckf)
254	if err != nil || ckf.kf == nil {
255		return false, err
256	}
257
258	//historical
259	historicalLinks := hsc.chainLinks.omittingNRightmostLinks(linksConsumed)
260	if len(historicalLinks) > 0 {
261		m.VLogf(VLog1, "After consuming %d links, there are %d historical links left",
262			linksConsumed, len(historicalLinks))
263		// errors are ignored from this method in full sigchain loads also, because we'd rather
264		// not block current behavior from a failure in here.
265		_, prevSubchains, _ := verifySigsAndComputeKeysHistorical(m, uid, username, historicalLinks, *ckf.kf)
266		hsc.prevSubchains = prevSubchains
267	}
268
269	return false, nil
270}
271
272func (l *HighSigChainLoader) GetMerkleTriple() (ret *MerkleTriple) {
273	// leaf is what the server said was the leaf for the user
274	if l.leaf != nil {
275		ret = l.chainType.GetMerkleTriple(l.leaf)
276	}
277	return ret
278}
279
280func extractDeviceKeys(cki *ComputedKeyInfos) *map[keybase1.KID]keybase1.PublicKeyV2NaCl {
281	deviceKeys := make(map[keybase1.KID]keybase1.PublicKeyV2NaCl)
282	if cki != nil {
283		for kid := range cki.Infos {
284			if !KIDIsPGP(kid) {
285				deviceKeys[kid] = cki.exportDeviceKeyV2(kid)
286			}
287		}
288	}
289	return &deviceKeys
290}
291
292func buildUPKLiteAllIncarnations(m MetaContext, user *User, leaf *MerkleUserLeaf, hsc *HighSigChain) (ret *keybase1.UPKLiteV1AllIncarnations, err error) {
293	// build the current UPKLiteV1
294	uid := user.GetUID()
295	name := user.GetName()
296	status := user.GetStatus()
297	eldestSeqno := hsc.currentSubchainStart
298	deviceKeys := extractDeviceKeys(hsc.GetComputedKeyInfos())
299	currentUpk := keybase1.UPKLiteV1{
300		Uid:         uid,
301		Username:    name,
302		EldestSeqno: eldestSeqno,
303		Status:      status,
304		DeviceKeys:  *deviceKeys,
305		Reset:       nil,
306	}
307
308	// build the historical (aka PastIncarnations) UPKLiteV1s
309	var previousUpks []keybase1.UPKLiteV1
310	resetMap := make(map[int](*keybase1.ResetSummary))
311	if resets := leaf.resets; resets != nil {
312		for _, l := range resets.chain {
313			tmp := l.Summarize()
314			resetMap[int(l.ResetSeqno)] = &tmp
315		}
316	}
317	for idx, subchain := range hsc.prevSubchains {
318		latestLink := subchain[len(subchain)-1]
319		eldestSeqno = subchain[0].GetSeqno()
320		reset := resetMap[idx+1]
321		if reset != nil {
322			reset.EldestSeqno = eldestSeqno
323		}
324		prevDeviceKeys := extractDeviceKeys(latestLink.cki)
325		prevUpk := keybase1.UPKLiteV1{
326			Uid:         uid,
327			Username:    name,
328			EldestSeqno: eldestSeqno,
329			Status:      status,
330			DeviceKeys:  *prevDeviceKeys,
331			Reset:       reset,
332		}
333		previousUpks = append(previousUpks, prevUpk)
334	}
335
336	// Collect the link IDs (that is, the hashes of the signature inputs) from all chainlinks.
337	linkIDs := map[keybase1.Seqno]keybase1.LinkID{}
338	for _, link := range hsc.chainLinks {
339		linkIDs[link.GetSeqno()] = link.LinkID().Export()
340	}
341
342	final := keybase1.UPKLiteV1AllIncarnations{
343		Current:          currentUpk,
344		PastIncarnations: previousUpks,
345		SeqnoLinkIDs:     linkIDs,
346		MinorVersion:     UPKLiteMinorVersionCurrent,
347	}
348	ret = &final
349	return ret, err
350}
351
352func (hsc HighSigChain) GetComputedKeyInfos() (cki *ComputedKeyInfos) {
353	cki = hsc.localCki
354	if cki == nil {
355		if l := last(hsc.chainLinks); l != nil {
356			if l.cki == nil {
357				hsc.G().Log.Debug("GetComputedKeyInfos: l.cki is nil")
358			}
359			cki = l.cki
360		}
361	}
362	return cki
363}
364