github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/engine/device_keygen.go (about)

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