1// Copyright 2015 Keybase, Inc. All rights reserved. Use of
2// this source code is governed by the included BSD license.
3
4package engine
5
6import (
7	"errors"
8	"fmt"
9
10	"github.com/keybase/client/go/kbcrypto"
11	"github.com/keybase/client/go/libkb"
12	keybase1 "github.com/keybase/client/go/protocol/keybase1"
13)
14
15type DeviceKeygenArgs struct {
16	Me              *libkb.User
17	DeviceID        keybase1.DeviceID
18	DeviceName      string
19	DeviceType      keybase1.DeviceTypeV2
20	Lks             *libkb.LKSec
21	IsEldest        bool
22	IsSelfProvision bool
23	PerUserKeyring  *libkb.PerUserKeyring
24	EkReboxer       *ephemeralKeyReboxer
25
26	// Used in tests for reproducible key generation
27	naclSigningKeyPair    libkb.NaclKeyPair
28	naclEncryptionKeyPair libkb.NaclKeyPair
29}
30
31// DeviceKeygenPushArgs determines how the push will run.  There are
32// currently three different paths it can take:
33//
34// 1. this device is the eldest device:  pushes eldest signing
35// key, encryption subkey. (IsEldest => true)
36//
37// 2. this device is a sibling (but we're not in a key exchange
38// scenario):  pushes sibkey signing key, encryption subkey.
39// (IsEldest => False, SkipSignerPush => false, Signer != nil,
40// EldestKID != nil)
41//
42// 3. this device is a sibling, but another device pushed
43// the signing key, so skip that part.
44// (IsEldest => False, SkipSignerPush => true, Signer != nil,
45// EldestKID != nil)
46//
47// The User argument is optional, but it is necessary if the
48// user's sigchain changes between key generation and key push.
49//
50type DeviceKeygenPushArgs struct {
51	SkipSignerPush bool
52	Signer         libkb.GenericKey
53	EldestKID      keybase1.KID
54	User           *libkb.User // optional
55}
56
57type DeviceKeygen struct {
58	args *DeviceKeygenArgs
59
60	runErr  error
61	pushErr error
62
63	naclSignGen *libkb.NaclKeyGen
64	naclEncGen  *libkb.NaclKeyGen
65
66	// can be nil
67	perUserKeySeed *libkb.PerUserKeySeed
68
69	libkb.Contextified
70}
71
72// NewDeviceKeygen creates a DeviceKeygen engine.
73func NewDeviceKeygen(g *libkb.GlobalContext, args *DeviceKeygenArgs) *DeviceKeygen {
74	return &DeviceKeygen{
75		args:         args,
76		Contextified: libkb.NewContextified(g),
77	}
78}
79
80// Name is the unique engine name.
81func (e *DeviceKeygen) Name() string {
82	return "DeviceKeygen"
83}
84
85// GetPrereqs returns the engine prereqs.
86func (e *DeviceKeygen) Prereqs() Prereqs {
87	return Prereqs{TemporarySession: true}
88}
89
90// RequiredUIs returns the required UIs.
91func (e *DeviceKeygen) RequiredUIs() []libkb.UIKind {
92	return []libkb.UIKind{
93		libkb.LogUIKind,
94	}
95}
96
97// SubConsumers returns the other UI consumers for this engine.
98func (e *DeviceKeygen) SubConsumers() []libkb.UIConsumer {
99	return nil
100}
101
102// Run starts the engine.
103func (e *DeviceKeygen) Run(m libkb.MetaContext) (err error) {
104	defer m.Trace("DeviceKeygen#Run", &err)()
105
106	e.setup(m)
107	e.generate(m)
108	e.localSave(m)
109	return e.runErr
110}
111
112func (e *DeviceKeygen) SigningKeyPublic() (kbcrypto.NaclSigningKeyPublic, error) {
113	s, ok := e.naclSignGen.GetKeyPair().(libkb.NaclSigningKeyPair)
114	if !ok {
115		return kbcrypto.NaclSigningKeyPublic{}, kbcrypto.BadKeyError{Msg: fmt.Sprintf("invalid key type %T", e.naclSignGen.GetKeyPair())}
116	}
117	return s.Public, nil
118
119}
120
121func (e *DeviceKeygen) SigningKey() libkb.NaclKeyPair {
122	return e.naclSignGen.GetKeyPair()
123}
124
125func (e *DeviceKeygen) EncryptionKey() libkb.NaclDHKeyPair {
126	return e.naclEncGen.GetKeyPair().(libkb.NaclDHKeyPair)
127}
128
129// Push pushes the generated keys to the api server and stores the
130// local key security server half on the api server as well.
131func (e *DeviceKeygen) Push(m libkb.MetaContext, pargs *DeviceKeygenPushArgs) (err error) {
132	var encSigner libkb.GenericKey
133	eldestKID := pargs.EldestKID
134
135	ds := []libkb.Delegator{}
136
137	m.Debug("DeviceKeygen#Push PUK(upgrade:%v)", m.G().Env.GetUpgradePerUserKey())
138
139	var pukBoxes = []keybase1.PerUserKeyBox{}
140	if e.G().Env.GetUpgradePerUserKey() && e.args.IsEldest {
141		if e.perUserKeySeed == nil {
142			return errors.New("missing new per user key")
143		}
144		// Encrypt the new per-user-key for this eldest device.
145		pukBox, err := libkb.NewPerUserKeyBox(
146			*e.perUserKeySeed, // inner key to be encrypted
147			e.EncryptionKey(), // receiver key (device enc key)
148			e.EncryptionKey(), // sender key   (device enc key)
149			keybase1.PerUserKeyGeneration(1))
150		if err != nil {
151			return err
152		}
153		pukBoxes = append(pukBoxes, pukBox)
154	}
155	if !e.args.IsEldest || e.args.IsSelfProvision {
156		boxes, err := e.preparePerUserKeyBoxFromProvisioningKey(m)
157		if err != nil {
158			return err
159		}
160		pukBoxes = append(pukBoxes, boxes...)
161	}
162
163	// append the signing key
164	if e.args.IsEldest {
165		ds = e.appendEldest(m, ds, pargs)
166		encSigner = e.naclSignGen.GetKeyPair()
167		eldestKID = encSigner.GetKID()
168	} else if !pargs.SkipSignerPush {
169		ds = e.appendSibkey(m, ds, pargs)
170		encSigner = e.naclSignGen.GetKeyPair()
171	} else {
172		encSigner = pargs.Signer
173	}
174
175	ds = e.appendEncKey(m, ds, encSigner, eldestKID, pargs.User)
176
177	var userEKReboxArg *keybase1.UserEkReboxArg
178	if e.args.IsSelfProvision {
179		userEKReboxArg, err = e.reboxUserEK(m, encSigner)
180		if err != nil {
181			return err
182		}
183	}
184
185	var pukSigProducer libkb.AggSigProducer // = nil
186	// PerUserKey does not use Delegator.
187	if e.G().Env.GetUpgradePerUserKey() && e.args.IsEldest {
188		// Sign in the new per-user-key
189		if e.perUserKeySeed == nil {
190			return errors.New("missing new per user key")
191		}
192
193		pukSigProducer = func() (libkb.JSONPayload, keybase1.Seqno, libkb.LinkID, error) {
194			gen := keybase1.PerUserKeyGeneration(1)
195			rev, err := libkb.PerUserKeyProofReverseSigned(m, e.args.Me, *e.perUserKeySeed, gen, encSigner)
196			if err != nil {
197				return nil, 0, nil, err
198			}
199			return rev.Payload, rev.Seqno, rev.LinkID, nil
200		}
201	}
202
203	e.pushErr = libkb.DelegatorAggregator(m, ds, pukSigProducer, pukBoxes, nil, userEKReboxArg)
204
205	// push the LKS server half
206	e.pushLKS(m)
207
208	return e.pushErr
209}
210
211func (e *DeviceKeygen) setup(m libkb.MetaContext) {
212	defer m.Trace("DeviceKeygen#setup", &e.runErr)()
213	if e.runErr != nil {
214		return
215	}
216
217	e.naclSignGen = e.newNaclKeyGen(m, func() (libkb.NaclKeyPair, error) {
218		if e.args.naclSigningKeyPair != nil {
219			return e.args.naclSigningKeyPair, nil
220		}
221		kp, err := libkb.GenerateNaclSigningKeyPair()
222		if err != nil {
223			return nil, err
224		}
225		return kp, nil
226	}, e.device(), libkb.NaclEdDSAExpireIn)
227
228	e.naclEncGen = e.newNaclKeyGen(m, func() (libkb.NaclKeyPair, error) {
229		if e.args.naclEncryptionKeyPair != nil {
230			return e.args.naclEncryptionKeyPair, nil
231		}
232		kp, err := libkb.GenerateNaclDHKeyPair()
233		if err != nil {
234			return nil, err
235		}
236		return kp, nil
237	}, e.device(), libkb.NaclDHExpireIn)
238}
239
240func (e *DeviceKeygen) generate(m libkb.MetaContext) {
241	defer m.Trace("DeviceKeygen#generate", &e.runErr)()
242	if e.runErr != nil {
243		return
244	}
245
246	if e.runErr = e.naclSignGen.Generate(); e.runErr != nil {
247		return
248	}
249
250	if e.runErr = e.naclEncGen.Generate(); e.runErr != nil {
251		return
252	}
253
254	if e.G().Env.GetUpgradePerUserKey() && e.args.IsEldest {
255		seed, err := libkb.GeneratePerUserKeySeed()
256		if err != nil {
257			e.runErr = err
258			return
259		}
260		e.perUserKeySeed = &seed
261	}
262
263}
264
265func (e *DeviceKeygen) localSave(m libkb.MetaContext) {
266	defer m.Trace("DeviceKeygen#localSave", &e.runErr)()
267	if e.runErr != nil {
268		return
269	}
270	if e.args.DeviceType == keybase1.DeviceTypeV2_PAPER {
271		m.Debug("Not writing out paper key to local storage")
272		return
273	}
274	if e.runErr = e.naclSignGen.SaveLKS(m, e.args.Lks); e.runErr != nil {
275		return
276	}
277	if e.runErr = e.naclEncGen.SaveLKS(m, e.args.Lks); e.runErr != nil {
278		return
279	}
280}
281
282func (e *DeviceKeygen) reboxUserEK(m libkb.MetaContext, signingKey libkb.GenericKey) (reboxArg *keybase1.UserEkReboxArg, err error) {
283	defer m.Trace("DeviceKeygen#reboxUserEK", &err)()
284	ekKID, err := e.args.EkReboxer.getDeviceEKKID(m)
285	if err != nil {
286		return nil, err
287	}
288	userEKBox, err := makeUserEKBoxForProvisionee(m, ekKID)
289	if err != nil {
290		return nil, err
291	}
292	return e.args.EkReboxer.getReboxArg(m, userEKBox, e.args.DeviceID, signingKey)
293}
294
295func (e *DeviceKeygen) appendEldest(m libkb.MetaContext, ds []libkb.Delegator, pargs *DeviceKeygenPushArgs) []libkb.Delegator {
296	defer m.Trace("DeviceKeygen#appendEldest", &e.pushErr)()
297	if e.pushErr != nil {
298		return ds
299	}
300
301	var d libkb.Delegator
302	d, e.pushErr = e.naclSignGen.Push(m, true)
303	if e.pushErr == nil {
304		return append(ds, d)
305	}
306
307	return ds
308}
309
310func (e *DeviceKeygen) appendSibkey(m libkb.MetaContext, ds []libkb.Delegator, pargs *DeviceKeygenPushArgs) []libkb.Delegator {
311	defer m.Trace("DeviceKeygen#appendSibkey", &e.pushErr)()
312	if e.pushErr != nil {
313		return ds
314	}
315
316	var d libkb.Delegator
317
318	e.naclSignGen.UpdateArg(pargs.Signer, pargs.EldestKID, libkb.DelegationTypeSibkey, pargs.User)
319	d, e.pushErr = e.naclSignGen.Push(m, true)
320	if e.pushErr == nil {
321		return append(ds, d)
322	}
323
324	return ds
325}
326
327func (e *DeviceKeygen) appendEncKey(m libkb.MetaContext, ds []libkb.Delegator, signer libkb.GenericKey, eldestKID keybase1.KID, user *libkb.User) []libkb.Delegator {
328	defer m.Trace("DeviceKeygen#appendEncKey", &e.pushErr)()
329	if e.pushErr != nil {
330		return ds
331	}
332
333	e.naclEncGen.UpdateArg(signer, eldestKID, libkb.DelegationTypeSubkey, user)
334
335	var d libkb.Delegator
336	d, e.pushErr = e.naclEncGen.Push(m, true)
337	if e.pushErr == nil {
338		return append(ds, d)
339	}
340
341	return ds
342}
343
344func (e *DeviceKeygen) generateClientHalfRecovery(m libkb.MetaContext) (ctext string, kid keybase1.KID, err error) {
345	defer m.Trace("DeviceKeygen#generateClientHalfRecovery", &err)()
346	key := e.naclEncGen.GetKeyPair()
347	kid = key.GetKID()
348	ctext, err = e.args.Lks.EncryptClientHalfRecovery(key)
349	return ctext, kid, err
350}
351
352func (e *DeviceKeygen) pushLKS(m libkb.MetaContext) {
353	defer m.Trace("DeviceKeygen#pushLKS", &e.pushErr)()
354
355	if e.pushErr != nil {
356		return
357	}
358
359	if e.args.Lks == nil {
360		e.pushErr = errors.New("no local key security set")
361		return
362	}
363
364	serverHalf := e.args.Lks.GetServerHalf()
365	if serverHalf.IsNil() {
366		e.pushErr = errors.New("LKS server half is empty, and should not be")
367		return
368	}
369
370	var chr string
371	var chrk keybase1.KID
372	if chr, chrk, e.pushErr = e.generateClientHalfRecovery(m); e.pushErr != nil {
373		return
374	}
375
376	e.pushErr = libkb.PostDeviceLKS(m, e.args.DeviceID, e.args.DeviceType, serverHalf, e.args.Lks.Generation(), chr, chrk)
377	if e.pushErr != nil {
378		return
379	}
380}
381
382func (e *DeviceKeygen) newNaclKeyGen(m libkb.MetaContext, gen libkb.NaclGenerator, device *libkb.Device, expire int) *libkb.NaclKeyGen {
383	return libkb.NewNaclKeyGen(libkb.NaclKeyGenArg{
384		Generator: gen,
385		Device:    device,
386		Me:        e.args.Me,
387		ExpireIn:  expire,
388	})
389}
390
391func (e *DeviceKeygen) device() *libkb.Device {
392	s := libkb.DeviceStatusActive
393	return &libkb.Device{
394		ID:          e.args.DeviceID,
395		Description: &e.args.DeviceName,
396		Type:        e.args.DeviceType,
397		Status:      &s,
398	}
399}
400
401// Can return no boxes if there are no per-user-keys.
402func (e *DeviceKeygen) preparePerUserKeyBoxFromProvisioningKey(m libkb.MetaContext) ([]keybase1.PerUserKeyBox, error) {
403	// Assuming this is a paperkey or self provision.
404
405	upak := e.args.Me.ExportToUserPlusAllKeys()
406	if len(upak.Base.PerUserKeys) == 0 {
407		m.Debug("DeviceKeygen skipping per-user-keys, none exist")
408		return nil, nil
409	}
410
411	pukring := e.args.PerUserKeyring
412	if pukring == nil {
413		return nil, errors.New("missing PerUserKeyring")
414	}
415
416	provisioningKey := m.ActiveDevice().ProvisioningKey(m)
417	var provisioningSigKey, provisioningEncKeyGeneric libkb.GenericKey
418	if provisioningKey != nil {
419		provisioningSigKey = provisioningKey.SigningKey()
420		provisioningEncKeyGeneric = provisioningKey.EncryptionKey()
421	}
422
423	if provisioningSigKey == nil && provisioningEncKeyGeneric == nil {
424		// GPG provisioning is not supported when the user has per-user-keys.
425		// This is the error that manifests. See CORE-4960
426		return nil, errors.New("missing provisioning key in login context")
427	}
428	if provisioningSigKey == nil {
429		return nil, errors.New("missing provisioning sig key")
430	}
431	if provisioningEncKeyGeneric == nil {
432		return nil, errors.New("missing provisioning enc key")
433	}
434	provisioningEncKey, ok := provisioningEncKeyGeneric.(libkb.NaclDHKeyPair)
435	if !ok {
436		return nil, errors.New("Unexpected encryption key type")
437	}
438
439	provisioningDeviceID, err := upak.GetDeviceID(provisioningSigKey.GetKID())
440	if err != nil {
441		return nil, err
442	}
443	err = pukring.SyncAsProvisioningKey(m, &upak, provisioningDeviceID, provisioningEncKey)
444	if err != nil {
445		return nil, err
446	}
447	if !pukring.HasAnyKeys() {
448		return nil, nil
449	}
450	pukBox, err := pukring.PrepareBoxForNewDevice(m,
451		e.EncryptionKey(),  // receiver key: provisionee enc
452		provisioningEncKey, // sender key: provisioning key enc
453	)
454	return []keybase1.PerUserKeyBox{pukBox}, err
455}
456