1package sig3
2
3import (
4	"crypto/hmac"
5	"crypto/rand"
6	"crypto/sha256"
7	"encoding/base64"
8	"encoding/hex"
9	"github.com/keybase/client/go/kbcrypto"
10	"github.com/keybase/client/go/msgpack"
11	keybase1 "github.com/keybase/client/go/protocol/keybase1"
12	"github.com/keybase/go-crypto/ed25519"
13)
14
15// Generic sig3 wrapper class, should implement the following interface.
16type Generic interface {
17	Signer() *Signer
18	Prev() *LinkID
19	Seqno() Seqno
20	Outer() OuterLink
21	Inner() *InnerLink
22
23	// Inner methods for generic decoding of incoming sig3 links
24	outerPointer() *OuterLink
25
26	// setVerifiedBit is called once we've verified the outer signature over the whole
27	// link, and also any inner reverse signatures. If any verification fails, the bit
28	// will not get set. The bit also won't get set for stubbed links, since there isn't
29	// enough information to verify.
30	setVerifiedBit()
31	verify() error
32
33	// check this chainlink after parsing for type-specific properties
34	parseCheck() error
35}
36
37// Base struct for sig3 links that contains much of the raw material pulled down or off local storage.
38// Most implementations of sig3 links should include this base class.
39type Base struct {
40	verified bool // see message above for when this bit is set.
41	inner    *InnerLink
42	outerRaw []byte
43	outer    OuterLink
44	sig      *Sig
45}
46
47// RotateKey is a sig3 link type for a PTK rotation. Handles multiple PTK types being rotated in
48// one link.
49type RotateKey struct {
50	Base
51}
52
53// LinkFromFuture is a sig3 link type that we don't know how to decode, but it's ok to ignore.
54type LinkFromFuture struct {
55	Base
56}
57
58var _ Generic = (*Base)(nil)
59var _ Generic = (*RotateKey)(nil)
60var _ Generic = (*LinkFromFuture)(nil)
61
62// NewRotateKey makes a new rotate key given sig3 skeletons (Outer and Inner) and
63// also the PTKs that are going to be advertised in the sig3 link.
64func NewRotateKey(o OuterLink, i InnerLink, b RotateKeyBody) *RotateKey {
65	i.Body = &b
66	return &RotateKey{
67		Base: Base{
68			inner: &i,
69			outer: o,
70		},
71	}
72}
73
74// rkb returns the RotateKeyBody that we are expecting at r.Base.inner. It should never fail, if it does,
75// the program will crash.
76func (r *RotateKey) rkb() *RotateKeyBody {
77	ret, _ := r.Base.inner.Body.(*RotateKeyBody)
78	return ret
79}
80
81func (r *RotateKey) PTKs() []PerTeamKey {
82	return r.rkb().PTKs
83}
84
85func (r *RotateKey) ReaderKey() *PerTeamKey {
86	for _, k := range r.rkb().PTKs {
87		if k.PTKType == keybase1.PTKType_READER {
88			return &k
89		}
90	}
91	return nil
92}
93
94func (b *Base) setVerifiedBit() {
95	if b.inner != nil && b.sig != nil {
96		b.verified = true
97	}
98}
99
100func (b *Base) parseCheck() error {
101	return nil
102}
103
104// Outer returns a copy of the OuterLink in this base class
105func (b *Base) Outer() OuterLink {
106	return b.outer
107}
108
109func (b *Base) outerPointer() *OuterLink {
110	return &b.outer
111}
112
113// Inner returns a pointer to the InnerLink in this base class.
114func (b *Base) Inner() *InnerLink {
115	return b.inner
116}
117
118// Signer returns the (uid, eldest, KID) of the signer of this link if a sig was provided,
119// and it was successfully verified (as reported by the link itself). If not, then this will
120// return a nil.
121func (b *Base) Signer() *Signer {
122	if !b.verified {
123		return nil
124	}
125	if b.inner == nil {
126		return nil
127	}
128	return &b.inner.Signer
129}
130
131// Prev returns the LinkID of the previous link, or nil if none was provided.
132func (b *Base) Prev() *LinkID {
133	return b.outer.Prev
134}
135
136// Seqno returns the seqno of this link, as reported in the outer link itself.
137func (b *Base) Seqno() Seqno {
138	return b.outer.Seqno
139}
140
141func (b Base) verify() error {
142	if (b.sig == nil) != (b.inner == nil) {
143		return newSig3Error("need sig and inner, or neither, but can't have one and not the other (sig: %v, inner: %v)", (b.sig != nil), (b.inner != nil))
144	}
145	if b.sig == nil || b.inner == nil {
146		return nil
147	}
148	err := b.sig.verify(b.inner.Signer.KID, b.outerRaw)
149	if err != nil {
150		return err
151	}
152	return nil
153}
154
155func (i InnerLink) hash() (LinkID, error) {
156	return hashInterface(i)
157}
158
159func hashInterface(i interface{}) (LinkID, error) {
160	b, err := msgpack.Encode(i)
161	if err != nil {
162		return LinkID{}, err
163	}
164	return hash(b), nil
165}
166
167func (l LinkID) String() string {
168	return hex.EncodeToString(l[:])
169}
170
171func (o OuterLink) Hash() (LinkID, error) {
172	return hashInterface(o)
173}
174
175func (r RotateKey) verify() error {
176	err := r.Base.verify()
177	if err != nil {
178		return err
179	}
180	err = r.verifyReverseSig()
181	if err != nil {
182		return err
183	}
184	return nil
185}
186
187func (r RotateKey) verifyReverseSig() (err error) {
188	if r.inner == nil {
189		return nil
190	}
191
192	// First make a checkpoint of all of the previous sigs and the previous inner
193	// link, since we're going to mutate them as we verify
194	var reverseSigs []*Sig
195	for _, ptk := range r.rkb().PTKs {
196		reverseSigs = append(reverseSigs, ptk.ReverseSig)
197	}
198	innerLinkID := r.Base.outer.InnerLinkID
199
200	// Make sure to replace them on the way out of the function, even in an error.
201	defer func() {
202		for j, rs := range reverseSigs {
203			r.rkb().PTKs[j].ReverseSig = rs
204		}
205		r.Base.outer.InnerLinkID = innerLinkID
206	}()
207
208	// Verify signatures in the reverse order they were signed, nulling them out
209	// from back to front. We are not going middle-out.
210	for i := len(r.rkb().PTKs) - 1; i >= 0; i-- {
211		ptk := &r.rkb().PTKs[i]
212		revSig := ptk.ReverseSig
213		if revSig == nil {
214			return newSig3Error("rotate key link is missing a reverse sig")
215		}
216
217		ptk.ReverseSig = nil
218		r.Base.outer.InnerLinkID, err = r.Base.inner.hash()
219		if err != nil {
220			return err
221		}
222		b, err := msgpack.Encode(r.Base.outer)
223		if err != nil {
224			return err
225		}
226		err = revSig.verify(ptk.SigningKID, b)
227		if err != nil {
228			return newSig3Error("bad reverse signature: %s", err.Error())
229		}
230	}
231
232	return nil
233}
234
235func hash(b []byte) LinkID {
236	return LinkID(sha256.Sum256(b))
237}
238
239func (l LinkID) eq(m LinkID) bool {
240	return hmac.Equal(l[:], m[:])
241}
242
243func (s ExportJSON) parseSig() (*Base, error) {
244	var out Base
245	if s.Sig == "" {
246		return &out, nil
247	}
248	b, err := base64.StdEncoding.DecodeString(s.Sig)
249	if err != nil {
250		return nil, err
251	}
252	out.sig = &Sig{}
253	err = msgpack.Decode(&out.sig, b)
254	if err != nil {
255		return nil, err
256	}
257	return &out, nil
258}
259
260func (s ExportJSON) parseOuter(in Base) (*Base, error) {
261	if s.Outer == "" {
262		return nil, newParseError("outer cannot be nil")
263	}
264	b, err := base64.StdEncoding.DecodeString(s.Outer)
265	if err != nil {
266		return nil, err
267	}
268	in.outerRaw = b
269	if !msgpack.IsEncodedMsgpackArray(b) {
270		return nil, newParseError("need an encoded msgpack array (with no leading garbage)")
271	}
272	err = msgpack.Decode(&in.outer, b)
273	if err != nil {
274		return nil, err
275	}
276	if in.outer.Version != SigVersion3 {
277		return nil, newSig3Error("can only handle sig version 3 (got %d)", in.outer.Version)
278	}
279	if in.outer.ChainType != ChainTypeTeamPrivateHidden {
280		return nil, newSig3Error("can only handle type 17 (team private hidden)")
281	}
282	return &in, nil
283}
284
285func (r *RotateKey) parseCheck() error {
286	m := make(map[keybase1.PTKType]bool)
287	for _, k := range r.rkb().PTKs {
288		typ := k.PTKType
289		if m[typ] {
290			return newParseError("duplicated PTK type: %s", typ)
291		}
292		m[typ] = true
293	}
294	return nil
295}
296
297func (s *ExportJSON) parseInner(in Base) (Generic, error) {
298	var out Generic
299
300	if (s.Inner == "") != (in.sig == nil) {
301		return nil, newParseError("need a sig and an inner, or neither, but not one without the other (sig: %v, inner: %v)", (in.sig != nil), (s.Inner != ""))
302	}
303
304	if s.Inner == "" {
305		return &in, nil
306	}
307
308	b, err := base64.StdEncoding.DecodeString(s.Inner)
309	if err != nil {
310		return nil, err
311	}
312
313	if !hash(b).eq(in.outer.InnerLinkID) {
314		return nil, newSig3Error("inner link hash doesn't match inner")
315	}
316
317	in.inner = &InnerLink{}
318	switch in.outer.LinkType {
319	case LinkTypeRotateKey:
320		var rkb RotateKeyBody
321		in.inner.Body = &rkb
322		out = &RotateKey{Base: in}
323	default:
324		if !in.outer.IgnoreIfUnsupported {
325			return nil, newParseError("unknown link type %d", in.outer.LinkType)
326		}
327		// Make it seem like a stubbed link
328		out = &LinkFromFuture{Base: in}
329	}
330
331	err = msgpack.Decode(in.inner, b)
332	if err != nil {
333		return nil, err
334	}
335
336	err = out.parseCheck()
337	if err != nil {
338		return nil, err
339	}
340
341	return out, nil
342}
343
344func (s ExportJSON) parse() (out Generic, err error) {
345	var tmp *Base
346	tmp, err = s.parseSig()
347	if err != nil {
348		return nil, err
349	}
350	tmp, err = s.parseOuter(*tmp)
351	if err != nil {
352		return nil, err
353	}
354	out, err = s.parseInner(*tmp)
355	if err != nil {
356		return nil, err
357	}
358	return out, nil
359}
360
361// Import from ExportJSON format (as sucked down from the server) into a Generic link type,
362// that can be casted into the supported link types (like RotateKey). Returns an error if we
363// failed to parse the input data, or if signature validation failed.
364func (s ExportJSON) Import() (Generic, error) {
365	out, err := s.parse()
366	if err != nil {
367		return nil, err
368	}
369	err = out.verify()
370	if err != nil {
371		return nil, err
372	}
373	out.setVerifiedBit()
374	return out, nil
375}
376
377func (sig Sig) verify(kid KID, body []byte) error {
378	key := kbcrypto.KIDToNaclSigningKeyPublic([]byte(kid))
379	if key == nil {
380		return newSig3Error("failed to import public key")
381	}
382	msg := kbcrypto.SignaturePrefixSigchain3.Prefix(body)
383	if !ed25519.Verify(key[:], msg, sig[:]) {
384		return newSig3Error("signature verification failed")
385	}
386	return nil
387}
388
389type KeyPair struct {
390	priv kbcrypto.NaclSigningKeyPrivate
391	pub  KID
392}
393
394func NewKeyPair(priv kbcrypto.NaclSigningKeyPrivate, pub KID) *KeyPair {
395	return &KeyPair{priv, pub}
396}
397
398func genRandomBytes(i int) ([]byte, error) {
399	ret := make([]byte, i)
400	n, err := rand.Read(ret)
401	if err != nil {
402		return nil, err
403	}
404	if n != i {
405		return nil, newSig3Error("short random entropy read")
406	}
407	return ret, nil
408}
409
410// Sign the RotateKey structure, with the given user's keypair (outer), and with the new
411// PTKs (inner). Return a Sig3Bundle, which was the exportable information, that you can
412// export either to local storage or up to the server.
413func (r RotateKey) Sign(outer KeyPair, inners []KeyPair) (ret *Sig3Bundle, err error) {
414	i := r.Inner()
415	o := r.outerPointer()
416	if i == nil {
417		return nil, newSig3Error("cannot sign without an inner link")
418	}
419
420	o.Version = SigVersion3
421	o.LinkType = LinkTypeRotateKey
422	o.ChainType = ChainTypeTeamPrivateHidden
423	i.Signer.KID = outer.pub
424	if i.Entropy == nil {
425		i.Entropy, err = genRandomBytes(16)
426		if err != nil {
427			return nil, err
428		}
429	}
430
431	for j := range r.rkb().PTKs {
432		ptk := &r.rkb().PTKs[j]
433		ptk.ReverseSig = nil
434		ptk.SigningKID = inners[j].pub
435	}
436
437	for j := range r.rkb().PTKs {
438		ptk := &r.rkb().PTKs[j]
439		tmp, err := signGeneric(&r.Base, inners[j].priv)
440		if err != nil {
441			return nil, err
442		}
443		ptk.ReverseSig = tmp.Sig
444	}
445	return signGeneric(&r.Base, outer.priv)
446}
447
448func signGeneric(g Generic, privkey kbcrypto.NaclSigningKeyPrivate) (ret *Sig3Bundle, err error) {
449	o := g.Outer()
450	i := g.Inner()
451	if i == nil {
452		return nil, newSig3Error("cannot sign without an inner link")
453	}
454	o.InnerLinkID, err = i.hash()
455	if err != nil {
456		return nil, err
457	}
458	b, err := msgpack.Encode(o)
459	if err != nil {
460		return nil, err
461	}
462	var sig Sig
463	msg := kbcrypto.SignaturePrefixSigchain3.Prefix(b)
464	copy(sig[:], ed25519.Sign(privkey[:], msg))
465	return &Sig3Bundle{
466		Sig:   &sig,
467		Inner: i,
468		Outer: o,
469	}, nil
470}
471
472// Export a sig3 up to the server in base64'ed JSON format, as in a POST request.
473func (s Sig3Bundle) Export() (ret ExportJSON, err error) {
474	enc := func(i interface{}) (string, error) {
475		b, err := msgpack.Encode(i)
476		if err != nil {
477			return "", err
478		}
479		return base64.StdEncoding.EncodeToString(b), nil
480	}
481	ret.Outer, err = enc(s.Outer)
482	if err != nil {
483		return ret, err
484	}
485	if s.Inner != nil {
486		ret.Inner, err = enc(s.Inner)
487		if err != nil {
488			return ret, err
489		}
490	}
491	if s.Sig != nil {
492		ret.Sig, err = enc(s.Sig[:])
493		if err != nil {
494			return ret, nil
495		}
496	}
497	return ret, nil
498}
499
500func IsStubbed(g Generic) bool {
501	return g.Inner() == nil
502}
503
504func Hash(g Generic) (LinkID, error) {
505	return g.Outer().Hash()
506}
507
508func CheckLinkSequence(v []Generic) error {
509	if len(v) == 0 {
510		return nil
511	}
512	prev := v[0]
513	for _, link := range v[1:] {
514		if prev.Seqno()+keybase1.Seqno(1) != link.Seqno() {
515			return newSequenceError("seqno mismatch at link %d", link.Seqno())
516		}
517		hsh, err := Hash(prev)
518		if err != nil {
519			return newSequenceError("bad prev hash computation at %d: %s", link.Seqno(), err.Error())
520		}
521		if link.Prev() == nil {
522			return newSequenceError("bad nil prev at %d", link.Seqno())
523		}
524		if !hsh.eq(*link.Prev()) {
525			return newSequenceError("prev hash mismatch at %d", link.Seqno())
526		}
527		prev = link
528	}
529	return nil
530}
531