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 }