github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/puk_upkeep.go (about) 1 // Copyright 2017 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 // PerUserKeyUpkeep rolls the user's per-user-key if the last PUK 5 // was added by a now-revoked device. 6 // Does not add a first per-user-key. Use PerUserKeyUpgrade for that. 7 // This engine makes up for the fact that after a self-deprovision 8 // the latest PUK for a user was generated on the very machine they 9 // wanted to deprovision. 10 // This will not notice if a device revoked another device but neglected 11 // to roll the PUK. No clients should do that. 12 package engine 13 14 import ( 15 "errors" 16 17 "github.com/keybase/client/go/libkb" 18 "github.com/keybase/client/go/protocol/keybase1" 19 ) 20 21 // PerUserKeyUpkeep is an engine. 22 type PerUserKeyUpkeep struct { 23 libkb.Contextified 24 args *PerUserKeyUpkeepArgs 25 DidRollKey bool 26 } 27 28 type PerUserKeyUpkeepArgs struct{} 29 30 // NewPerUserKeyUpkeep creates a PerUserKeyUpkeep engine. 31 func NewPerUserKeyUpkeep(g *libkb.GlobalContext, args *PerUserKeyUpkeepArgs) *PerUserKeyUpkeep { 32 return &PerUserKeyUpkeep{ 33 args: args, 34 Contextified: libkb.NewContextified(g), 35 } 36 } 37 38 // Name is the unique engine name. 39 func (e *PerUserKeyUpkeep) Name() string { 40 return "PerUserKeyUpkeep" 41 } 42 43 // GetPrereqs returns the engine prereqs. 44 func (e *PerUserKeyUpkeep) Prereqs() Prereqs { 45 return Prereqs{ 46 Device: true, 47 } 48 } 49 50 // RequiredUIs returns the required UIs. 51 func (e *PerUserKeyUpkeep) RequiredUIs() []libkb.UIKind { 52 return []libkb.UIKind{} 53 } 54 55 // SubConsumers returns the other UI consumers for this engine. 56 func (e *PerUserKeyUpkeep) SubConsumers() []libkb.UIConsumer { 57 return []libkb.UIConsumer{} 58 } 59 60 // Run starts the engine. 61 func (e *PerUserKeyUpkeep) Run(m libkb.MetaContext) (err error) { 62 defer m.Trace("PerUserKeyUpkeep", &err)() 63 return e.inner(m) 64 } 65 66 func (e *PerUserKeyUpkeep) inner(m libkb.MetaContext) error { 67 m.Debug("PerUserKeyUpkeep load self") 68 69 uid := e.G().GetMyUID() 70 if uid.IsNil() { 71 return libkb.NoUIDError{} 72 } 73 74 loadArg := libkb.NewLoadUserArgWithMetaContext(m). 75 WithUID(uid). 76 WithSelf(true). 77 WithPublicKeyOptional() 78 upak, me, err := m.G().GetUPAKLoader().LoadV2(loadArg) 79 if err != nil { 80 return err 81 } 82 // `me` could be nil. 83 84 var shouldRollKey bool 85 shouldRollKey, err = e.shouldRollKey(m, uid, &upak.Current) 86 if err != nil { 87 return err 88 } 89 if !shouldRollKey { 90 m.Debug("PerUserKeyUpkeep skipping") 91 return nil 92 } 93 94 // Roll the key 95 m.Debug("PerUserKeyUpkeep rolling key") 96 arg := &PerUserKeyRollArgs{ 97 Me: me, 98 } 99 eng := NewPerUserKeyRoll(m.G(), arg) 100 err = RunEngine2(m, eng) 101 e.DidRollKey = eng.DidNewKey 102 return err 103 } 104 105 // Whether we should roll the per-user-key. 106 func (e *PerUserKeyUpkeep) shouldRollKey(m libkb.MetaContext, uid keybase1.UID, upak *keybase1.UserPlusKeysV2) (bool, error) { 107 108 if len(upak.PerUserKeys) == 0 { 109 m.Debug("PerUserKeyUpkeep has no per-user-key") 110 return false, nil 111 } 112 m.Debug("PerUserKeyUpkeep has %v per-user-keys", len(upak.PerUserKeys)) 113 114 lastPuk := upak.PerUserKeys[len(upak.PerUserKeys)-1] 115 if !lastPuk.SignedByKID.IsValid() { 116 return false, errors.New("latest per-user-key had invalid signed-by KID") 117 } 118 m.Debug("PerUserKeyUpkeep last key signed by KID: %v", lastPuk.SignedByKID.String()) 119 return !e.keyIsActiveSibkey(m, lastPuk.SignedByKID, upak), nil 120 } 121 122 func (e *PerUserKeyUpkeep) keyIsActiveSibkey(m libkb.MetaContext, kid keybase1.KID, upak *keybase1.UserPlusKeysV2) bool { 123 for _, dkey := range upak.DeviceKeys { 124 active := dkey.Base.Revocation == nil 125 if active && dkey.Base.IsSibkey && dkey.Base.Kid.Equal(kid) { 126 return true 127 } 128 } 129 return false 130 }