github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/revoke.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/libkb" 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 ) 13 14 type RevokeMode int 15 16 const ( 17 RevokeKey RevokeMode = iota 18 RevokeDevice 19 ) 20 21 type RevokeEngine struct { 22 libkb.Contextified 23 deviceID keybase1.DeviceID 24 kid keybase1.KID 25 mode RevokeMode 26 forceSelf bool 27 forceLast bool 28 skipUserEKForTesting bool // Set for testing 29 } 30 31 type RevokeDeviceEngineArgs struct { 32 ID keybase1.DeviceID 33 ForceSelf bool 34 ForceLast bool 35 SkipUserEKForTesting bool 36 } 37 38 func NewRevokeDeviceEngine(g *libkb.GlobalContext, args RevokeDeviceEngineArgs) *RevokeEngine { 39 return &RevokeEngine{ 40 deviceID: args.ID, 41 mode: RevokeDevice, 42 forceSelf: args.ForceSelf, 43 forceLast: args.ForceLast, 44 skipUserEKForTesting: args.SkipUserEKForTesting, 45 Contextified: libkb.NewContextified(g), 46 } 47 } 48 49 func NewRevokeKeyEngine(g *libkb.GlobalContext, kid keybase1.KID) *RevokeEngine { 50 return &RevokeEngine{ 51 kid: kid, 52 mode: RevokeKey, 53 Contextified: libkb.NewContextified(g), 54 } 55 } 56 57 func (e *RevokeEngine) Name() string { 58 return "Revoke" 59 } 60 61 func (e *RevokeEngine) Prereqs() Prereqs { 62 return Prereqs{ 63 Device: true, 64 } 65 } 66 67 func (e *RevokeEngine) RequiredUIs() []libkb.UIKind { 68 return []libkb.UIKind{ 69 libkb.LogUIKind, 70 libkb.SecretUIKind, 71 } 72 } 73 74 func (e *RevokeEngine) SubConsumers() []libkb.UIConsumer { 75 return []libkb.UIConsumer{} 76 } 77 78 func (e *RevokeEngine) getKIDsToRevoke(me *libkb.User) ([]keybase1.KID, error) { 79 if e.mode == RevokeDevice { 80 deviceKeys, err := me.GetComputedKeyFamily().GetAllActiveKeysForDevice(e.deviceID) 81 if err != nil { 82 return nil, err 83 } 84 if len(deviceKeys) == 0 { 85 return nil, fmt.Errorf("No active keys to revoke for device %s.", e.deviceID) 86 } 87 return deviceKeys, nil 88 } else if e.mode == RevokeKey { 89 kid := e.kid 90 key, err := me.GetComputedKeyFamily().FindKeyWithKIDUnsafe(kid) 91 if err != nil { 92 return nil, err 93 } 94 if !libkb.IsPGP(key) { 95 return nil, fmt.Errorf("Key %s is not a PGP key. To revoke device keys, use the `device remove` command.", e.kid) 96 } 97 for _, activePGPKey := range me.GetComputedKeyFamily().GetActivePGPKeys(false /* sibkeys only */) { 98 if activePGPKey.GetKID().Equal(kid) { 99 return []keybase1.KID{kid}, nil 100 } 101 } 102 return nil, fmt.Errorf("PGP key %s is not active", e.kid) 103 } else { 104 return nil, fmt.Errorf("Unknown revoke mode: %d", e.mode) 105 } 106 } 107 108 func (e *RevokeEngine) explicitOrImplicitDeviceID(me *libkb.User) keybase1.DeviceID { 109 if e.mode == RevokeDevice { 110 return e.deviceID 111 } 112 for deviceID, device := range me.GetComputedKeyInfos().Devices { 113 if device.Kid.Equal(e.kid) { 114 return deviceID 115 } 116 } 117 // If we're revoking a PGP key, it won't match any device. 118 return "" 119 } 120 121 func (e *RevokeEngine) Run(mctx libkb.MetaContext) (err error) { 122 defer mctx.Trace(fmt.Sprintf("RevokeEngine (mode:%v)", e.mode), &err)() 123 return retryOnEphemeralRace(mctx, e.run) 124 } 125 126 func (e *RevokeEngine) run(m libkb.MetaContext) error { 127 e.G().LocalSigchainGuard().Set(m.Ctx(), "RevokeEngine") 128 defer e.G().LocalSigchainGuard().Clear(m.Ctx(), "RevokeEngine") 129 130 me, err := libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m)) 131 if err != nil { 132 return err 133 } 134 135 currentDevice := m.G().Env.GetDeviceID() 136 var deviceID keybase1.DeviceID 137 if e.mode == RevokeDevice { 138 deviceID = e.deviceID 139 hasPGP := len(me.GetComputedKeyFamily().GetActivePGPKeys(false)) > 0 140 141 if len(me.GetComputedKeyFamily().GetAllActiveDevices()) == 1 { 142 passphraseState, err := libkb.LoadPassphraseState(m) 143 if err != nil { 144 return fmt.Errorf("could not load passphrase state: %s", err) 145 } 146 if passphraseState == keybase1.PassphraseState_RANDOM { 147 return libkb.RevokeLastDeviceError{NoPassphrase: true} 148 } 149 150 if hasPGP { 151 // even w/ forceLast, you cannot revoke your last device 152 // if you have a pgp key 153 return libkb.RevokeLastDevicePGPError{} 154 } 155 156 if !e.forceLast { 157 return libkb.RevokeLastDeviceError{} 158 } 159 } 160 161 if e.deviceID == currentDevice && !(e.forceSelf || e.forceLast) { 162 return libkb.RevokeCurrentDeviceError{} 163 } 164 165 } 166 167 kidsToRevoke, err := e.getKIDsToRevoke(me) 168 if err != nil { 169 return err 170 } 171 172 lease, merkleRoot, err := libkb.RequestDowngradeLeaseByKID(m.Ctx(), m.G(), kidsToRevoke) 173 if err != nil { 174 return err 175 } 176 177 m.UIs().LogUI.Info("Revoking KIDs:") 178 for _, kid := range kidsToRevoke { 179 m.UIs().LogUI.Info(" %s", kid) 180 } 181 182 sigKey, encKey, err := e.getDeviceSecretKeys(m, me) 183 if err != nil { 184 return err 185 } 186 187 if encKey == nil { 188 return errors.New("Missing encryption key") 189 } 190 191 var pukBoxes []keybase1.PerUserKeyBox 192 var pukPrev *libkb.PerUserKeyPrev 193 194 // Whether this run is creating a new per-user-key. Set later. 195 addingNewPUK := false 196 197 // Only used if addingNewPUK 198 var newPukGeneration keybase1.PerUserKeyGeneration 199 var newPukSeed *libkb.PerUserKeySeed 200 201 pukring, err := e.G().GetPerUserKeyring(m.Ctx()) 202 if err != nil { 203 return err 204 } 205 err = pukring.Sync(m) 206 if err != nil { 207 return err 208 } 209 if pukring.HasAnyKeys() { 210 addingNewPUK = true 211 newPukGeneration = pukring.CurrentGeneration() + 1 212 213 // Make a new per-user-key 214 newPukSeedInner, err := libkb.GeneratePerUserKeySeed() 215 if err != nil { 216 return err 217 } 218 newPukSeed = &newPukSeedInner 219 220 // Create a prev secretbox containing the previous generation seed 221 pukPrevInner, err := pukring.PreparePrev(m, *newPukSeed, newPukGeneration) 222 if err != nil { 223 return err 224 } 225 pukPrev = &pukPrevInner 226 227 // Get the receivers who will be able to decrypt the new per-user-key 228 pukReceivers, err := e.getPukReceivers(m, me, kidsToRevoke) 229 if err != nil { 230 return err 231 } 232 233 // Create boxes of the new per-user-key 234 pukBoxesInner, err := pukring.PrepareBoxesForDevices(m, 235 *newPukSeed, newPukGeneration, pukReceivers, encKey) 236 if err != nil { 237 return err 238 } 239 pukBoxes = pukBoxesInner 240 } 241 242 var sigsList []libkb.JSONPayload 243 244 // Push the per-user-key sig 245 246 // Seqno when the per-user-key will be signed in. 247 var newPukSeqno keybase1.Seqno 248 if addingNewPUK { 249 sig1, err := libkb.PerUserKeyProofReverseSigned(m, me, *newPukSeed, newPukGeneration, sigKey) 250 if err != nil { 251 return err 252 } 253 newPukSeqno = me.GetSigChainLastKnownSeqno() 254 sigsList = append(sigsList, sig1.Payload) 255 } 256 257 // Push the revoke sig 258 sig2, lastSeqno, lastLinkID, err := e.makeRevokeSig(m, me, sigKey, kidsToRevoke, deviceID, merkleRoot) 259 if err != nil { 260 return err 261 } 262 sigsList = append(sigsList, sig2) 263 264 payload := make(libkb.JSONPayload) 265 payload["sigs"] = sigsList 266 payload["downgrade_lease_id"] = lease.LeaseID 267 268 if addingNewPUK { 269 libkb.AddPerUserKeyServerArg(payload, newPukGeneration, pukBoxes, pukPrev) 270 } 271 272 var myUserEKBox *keybase1.UserEkBoxed 273 var newUserEKMetadata *keybase1.UserEkMetadata 274 ekLib := e.G().GetEKLib() 275 if !e.skipUserEKForTesting && addingNewPUK && ekLib != nil { 276 sig, boxes, newMetadata, myBox, err := ekLib.PrepareNewUserEK(m, *merkleRoot, *newPukSeed) 277 if err != nil { 278 return err 279 } 280 // The assembled set of boxes includes one for the device we're in the 281 // middle of revoking. Filter it out. 282 filteredBoxes := []keybase1.UserEkBoxMetadata{} 283 deviceIDToFilter := e.explicitOrImplicitDeviceID(me) 284 for _, boxMetadata := range boxes { 285 if !boxMetadata.RecipientDeviceID.Eq(deviceIDToFilter) { 286 filteredBoxes = append(filteredBoxes, boxMetadata) 287 } 288 } 289 // If there are no active deviceEKs, we can't publish this key. This 290 // should mostly only come up in tests. 291 if len(filteredBoxes) > 0 { 292 myUserEKBox = myBox 293 newUserEKMetadata = &newMetadata 294 userEKSection := make(libkb.JSONPayload) 295 userEKSection["sig"] = sig 296 userEKSection["boxes"] = filteredBoxes 297 payload["user_ek"] = userEKSection 298 } else { 299 m.Debug("skipping userEK publishing, there are no valid deviceEKs") 300 } 301 } 302 m.Debug("RevokeEngine#Run pukBoxes:%v pukPrev:%v for generation %v, userEKBox: %v", 303 len(pukBoxes), pukPrev != nil, newPukGeneration, myUserEKBox != nil) 304 305 _, err = m.G().API.PostJSON(m, libkb.APIArg{ 306 Endpoint: "key/multi", 307 SessionType: libkb.APISessionTypeREQUIRED, 308 JSONPayload: payload, 309 }) 310 if err != nil { 311 // Revoke failed, let's clear downgrade lease so it will not prevent us 312 // from trying again for given kids. 313 err2 := libkb.CancelDowngradeLease(m.Ctx(), m.G(), lease.LeaseID) 314 if err2 != nil { 315 m.Warning("Failed to cancel downgrade leases after a failed revoke: %s", err2) 316 return libkb.CombineErrors(err, err2) 317 } 318 return err 319 } 320 if err = libkb.MerkleCheckPostedUserSig(m, me.GetUID(), lastSeqno, lastLinkID); err != nil { 321 return err 322 } 323 324 if addingNewPUK { 325 err = pukring.AddKey(m, newPukGeneration, newPukSeqno, *newPukSeed) 326 if err != nil { 327 return err 328 } 329 } 330 331 // Add the new userEK box to local storage, if it was created above. 332 if myUserEKBox != nil { 333 err = e.G().GetUserEKBoxStorage().Put(m, newUserEKMetadata.Generation, *myUserEKBox) 334 if err != nil { 335 m.Warning("error while saving userEK box: %s", err) 336 } 337 } 338 339 e.G().UserChanged(m.Ctx(), me.GetUID()) 340 341 return nil 342 } 343 344 // Get the full keys for this device. 345 // Returns (sigKey, encKey, err) 346 func (e *RevokeEngine) getDeviceSecretKeys(m libkb.MetaContext, me *libkb.User) (libkb.GenericKey, libkb.GenericKey, error) { 347 skaSig := libkb.SecretKeyArg{ 348 Me: me, 349 KeyType: libkb.DeviceSigningKeyType, 350 } 351 sigKey, err := m.G().Keyrings.GetSecretKeyWithPrompt(m, m.SecretKeyPromptArg(skaSig, "to revoke another key")) 352 if err != nil { 353 return nil, nil, err 354 } 355 if err = sigKey.CheckSecretKey(); err != nil { 356 return nil, nil, err 357 } 358 359 skaEnc := libkb.SecretKeyArg{ 360 Me: me, 361 KeyType: libkb.DeviceEncryptionKeyType, 362 } 363 encKey, err := m.G().Keyrings.GetSecretKeyWithPrompt(m, m.SecretKeyPromptArg(skaEnc, "to revoke another key")) 364 if err != nil { 365 return nil, nil, err 366 } 367 if err = encKey.CheckSecretKey(); err != nil { 368 return nil, nil, err 369 } 370 371 return sigKey, encKey, err 372 } 373 374 func (e *RevokeEngine) makeRevokeSig(m libkb.MetaContext, me *libkb.User, sigKey libkb.GenericKey, 375 kidsToRevoke []keybase1.KID, deviceID keybase1.DeviceID, 376 merkleRoot *libkb.MerkleRoot) (libkb.JSONPayload, keybase1.Seqno, libkb.LinkID, error) { 377 proof, err := me.RevokeKeysProof(m, sigKey, kidsToRevoke, deviceID, merkleRoot) 378 if err != nil { 379 return nil, 0, nil, err 380 } 381 sig, _, linkID, err := libkb.SignJSON(proof.J, sigKey) 382 if err != nil { 383 return nil, 0, nil, err 384 } 385 386 sig1 := make(libkb.JSONPayload) 387 sig1["sig"] = sig 388 sig1["signing_kid"] = sigKey.GetKID().String() 389 sig1["type"] = libkb.LinkTypeRevoke 390 return sig1, proof.Seqno, linkID, nil 391 } 392 393 // Get the receivers of the new per-user-key boxes. 394 // Includes all device subkeys except any being revoked by this engine. 395 func (e *RevokeEngine) getPukReceivers(m libkb.MetaContext, me *libkb.User, exclude []keybase1.KID) (res []libkb.NaclDHKeyPair, err error) { 396 excludeMap := make(map[keybase1.KID]bool) 397 for _, kid := range exclude { 398 excludeMap[kid] = true 399 } 400 401 ckf := me.GetComputedKeyFamily() 402 403 for _, dev := range ckf.GetAllActiveDevices() { 404 keyGeneric, err := ckf.GetEncryptionSubkeyForDevice(dev.ID) 405 if err != nil { 406 return nil, err 407 } 408 if !excludeMap[keyGeneric.GetKID()] { 409 key, ok := keyGeneric.(libkb.NaclDHKeyPair) 410 if !ok { 411 return nil, fmt.Errorf("Unexpected encryption key type: %T", keyGeneric) 412 } 413 res = append(res, key) 414 } 415 } 416 return res, nil 417 }