github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/scankeys.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 "fmt" 8 "sync" 9 10 "github.com/keybase/client/go/libkb" 11 keybase1 "github.com/keybase/client/go/protocol/keybase1" 12 "github.com/keybase/go-crypto/openpgp" 13 "github.com/keybase/go-crypto/openpgp/packet" 14 ) 15 16 // ScanKeys finds pgp decryption keys in SKB and also if there is 17 // one stored on the server. It satisfies the openpgp.KeyRing 18 // interface. 19 // 20 // It also will find public pgp keys for signature verification. 21 // 22 // It is not an engine, but uses an engine and is used by engines, 23 // so has to be in the engine package. It is a UIConsumer. 24 type ScanKeys struct { 25 // keys openpgp.EntityList 26 skbs []*libkb.SKB // all skb blocks for local keys 27 keyOwners map[uint64]*libkb.User // user objects for owners of keys found, for convenience 28 me *libkb.User 29 sync.Mutex // protect keyOwners map 30 libkb.MetaContextified 31 } 32 33 const unlockReason = "PGP Decryption" 34 35 // enforce ScanKeys implements openpgp.KeyRing: 36 var _ openpgp.KeyRing = &ScanKeys{} 37 38 // NewScanKeys creates a ScanKeys type. If there is a login 39 // session, it will load the pgp keys for that user. 40 func NewScanKeys(m libkb.MetaContext) (sk *ScanKeys, err error) { 41 sk = &ScanKeys{ 42 keyOwners: make(map[uint64]*libkb.User), 43 MetaContextified: libkb.NewMetaContextified(m), 44 } 45 46 defer m.Trace("NewScanKeys", &err)() 47 48 var loggedIn bool 49 loggedIn, err = isLoggedInWithError(m) 50 if err != nil { 51 return nil, err 52 } 53 if !loggedIn { 54 return sk, nil 55 } 56 57 sk.me, err = libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m)) 58 if err != nil { 59 return nil, fmt.Errorf("loadme error: %s", err) 60 } 61 62 // if user provided, then load their local keys, and their synced secret keys: 63 synced, err := sk.me.GetSyncedSecretKeys(m) 64 if err != nil { 65 return nil, fmt.Errorf("getsyncedsecret err: %s", err) 66 } 67 68 ring, err := m.ActiveDevice().Keyring(m) 69 if err != nil { 70 return nil, err 71 } 72 err = sk.coalesceBlocks(m, ring, synced) 73 if err != nil { 74 return nil, err 75 } 76 return sk, nil 77 } 78 79 func (s *ScanKeys) Name() string { 80 return "ScanKeys" 81 } 82 83 func (s *ScanKeys) RequiredUIs() []libkb.UIKind { 84 return []libkb.UIKind{libkb.SecretUIKind} 85 } 86 87 func (s *ScanKeys) SubConsumers() []libkb.UIConsumer { 88 return []libkb.UIConsumer{ 89 &PGPKeyfinder{}, 90 } 91 } 92 93 // Count returns the number of local keys available. 94 func (s *ScanKeys) Count() int { 95 return len(s.skbs) 96 } 97 98 // KeysById returns the set of keys that have the given key id. 99 // It is only called during decryption by openpgp. 100 func (s *ScanKeys) KeysById(id uint64, fp []byte) []openpgp.Key { 101 m := s.M() 102 primaries := s.unlockByID(m, id) 103 memres := primaries.KeysById(id, fp) 104 m.Debug("ScanKeys:KeysById(%016x) => %d keys match in memory", id, len(memres)) 105 if len(memres) > 0 { 106 m.Debug("ScanKeys:KeysById(%016x) => owner == me (%s)", id, s.me.GetName()) 107 s.Lock() 108 s.keyOwners[id] = s.me 109 s.Unlock() 110 return memres 111 } 112 113 // KeysById is only used for decryption, so getting public keys from 114 // API server via s.scan(id) is pointless, so just returning nil. 115 return nil 116 } 117 118 // KeysByIdAndUsage returns the set of public keys with the given 119 // id that also meet the key usage given by requiredUsage. 120 // 121 // The requiredUsage is expressed as the bitwise-OR of 122 // packet.KeyFlag* values. 123 // 124 // It is only called during signature verification so therefore 125 // requiredUsage will only equal KeyFlagSign, thus only public 126 // keys are required. If this ever changes upstream in openpgp, 127 // this function will panic. 128 func (s *ScanKeys) KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) []openpgp.Key { 129 if requiredUsage != packet.KeyFlagSign { 130 panic(fmt.Sprintf("ScanKeys: unexpected requiredUsage flags set: %x", requiredUsage)) 131 } 132 133 m := s.M() 134 135 // check the local keys first. 136 primaries := s.publicByID(m, id) 137 memres := primaries.KeysByIdUsage(id, fp, requiredUsage) 138 m.Debug("ScanKeys#KeysByIdUsage(%016x, %x) => %d keys match in memory", id, requiredUsage, len(memres)) 139 if len(memres) > 0 { 140 m.Debug("ScanKeys#KeysByIdUsage(%016x) => owner == me (%s)", id, s.me.GetName()) 141 s.Lock() 142 s.keyOwners[id] = s.me 143 s.Unlock() 144 return memres 145 } 146 147 // no match, so now lookup the user on the api server by the key id. 148 list, err := s.scan(m, id) 149 if err != nil { 150 m.Debug("error finding keys for %016x: %s", id, err) 151 return nil 152 } 153 // use the list to find the keys correctly 154 m.Debug("ScanKeys#KeysByIdUsage(%d, %x) => %d keys found via api scan", id, requiredUsage, len(list)) 155 return list.KeysByIdUsage(id, fp, requiredUsage) 156 } 157 158 // DecryptionKeys returns all private keys that are valid for 159 // decryption. It is only used if there is no key id in the 160 // message. 161 func (s *ScanKeys) DecryptionKeys() []openpgp.Key { 162 m := s.M() 163 m.Debug("ScanKeys#DecryptionKeys() => %d keys available", s.Count()) 164 all := s.unlockAll(m) 165 return all.DecryptionKeys() 166 } 167 168 // KeyOwner returns the owner of the keys found by ScanKeys that were 169 // used in KeysById or KeysByIdUsage, indexed by keyID. 170 func (s *ScanKeys) KeyOwner(keyID uint64) *libkb.User { 171 s.Lock() 172 defer s.Unlock() 173 174 return s.keyOwners[keyID] 175 } 176 177 func (s *ScanKeys) KeyOwnerByEntity(entity *openpgp.Entity) *libkb.User { 178 s.Lock() 179 defer s.Unlock() 180 181 if entity == nil { 182 return nil 183 } 184 if u, found := s.keyOwners[entity.PrimaryKey.KeyId]; found { 185 return u 186 } 187 for _, subKey := range entity.Subkeys { 188 if u, found := s.keyOwners[subKey.PublicKey.KeyId]; found { 189 return u 190 } 191 } 192 return nil 193 } 194 195 // coalesceBlocks puts the synced pgp key block and all the pgp key 196 // blocks in ring into s.skbs. 197 func (s *ScanKeys) coalesceBlocks(m libkb.MetaContext, ring *libkb.SKBKeyringFile, synced []*libkb.SKB) (err error) { 198 defer m.Trace("ScanKeys#coalesceBlocks", &err)() 199 200 // We want keys in this order: first local keyring keys that are LKSec, and 201 // then server synced keys that are triplesec. In ScanKeys.KeysById, this 202 // allows us to prompt for passphrase once and get both passphrase stream 203 // cache and triplesec cache the moment first LKSec key is processed by 204 // SKB.UnlockSecretKey. 205 206 // If they were in different order and we got triplesec bundle first, we 207 // would prompt for passphrase to get triplesec stream, and then prompt 208 // again to get passphrase stream to unlock LKSec bundle, prompting twice 209 // in total (assuming someone has both a server-synced bundle and local 210 // one). 211 212 for _, b := range ring.Blocks { 213 if !libkb.IsPGPAlgo(b.Type) { 214 continue 215 } 216 // make sure uid set on each block: 217 b.SetUID(s.me.GetUID()) 218 s.skbs = append(s.skbs, b) 219 } 220 221 s.skbs = append(s.skbs, synced...) 222 223 return nil 224 } 225 226 // scan finds the user on the api server for the key id. Then it 227 // uses PGPKeyfinder to find the public pgp keys for the user. 228 func (s *ScanKeys) scan(m libkb.MetaContext, id uint64) (openpgp.EntityList, error) { 229 // lookup the user on the api server by the key id. 230 username, uid, err := s.apiLookup(m, id) 231 if err != nil { 232 return nil, err 233 } 234 m.Debug("key id %016x => %s, %s", id, id, username, uid) 235 if len(username) == 0 || len(uid) == 0 { 236 return nil, libkb.NoKeyError{} 237 } 238 239 // use PGPKeyfinder engine to get the pgp keys for the user 240 arg := &PGPKeyfinderArg{Usernames: []string{username}} 241 eng := NewPGPKeyfinder(m.G(), arg) 242 if err := RunEngine2(m, eng); err != nil { 243 return nil, err 244 } 245 uplus := eng.UsersPlusKeys() 246 if len(uplus) != 1 { 247 m.Warning("error getting user plus pgp key from %s", username) 248 return nil, err 249 } 250 // user found is the owner of the keys 251 m.Debug("scan(%016x) => owner of key = (%s)", id, uplus[0].User.GetName()) 252 s.Lock() 253 s.keyOwners[id] = uplus[0].User 254 s.Unlock() 255 256 // convert the bundles to an openpgp entity list 257 // (which implements the openpgp.KeyRing interface) 258 var list openpgp.EntityList 259 for _, k := range uplus[0].Keys { 260 list = append(list, k.Entity) 261 } 262 return list, nil 263 } 264 265 // apiLookup gets the username and uid from the api server for the 266 // key id. 267 func (s *ScanKeys) apiLookup(m libkb.MetaContext, id uint64) (username string, uid keybase1.UID, err error) { 268 return libkb.PGPLookup(m, id) 269 } 270 271 func (s *ScanKeys) publicByID(m libkb.MetaContext, id uint64) openpgp.EntityList { 272 var list openpgp.EntityList 273 for _, skb := range s.skbs { 274 pubkey, err := skb.GetPubKey() 275 if err != nil { 276 m.Warning("error getting pub key from skb: %s", err) 277 continue 278 } 279 bundle, ok := pubkey.(*libkb.PGPKeyBundle) 280 if !ok { 281 continue 282 } 283 if len(bundle.KeysById(id, nil)) == 0 { 284 // no match 285 continue 286 } 287 list = append(list, bundle.Entity) 288 } 289 return list 290 } 291 292 func (s *ScanKeys) unlockByID(m libkb.MetaContext, id uint64) openpgp.EntityList { 293 var list openpgp.EntityList 294 for _, skb := range s.skbs { 295 pubkey, err := skb.GetPubKey() 296 if err != nil { 297 m.Warning("error getting pub key from skb: %s", err) 298 continue 299 } 300 bundle, ok := pubkey.(*libkb.PGPKeyBundle) 301 if !ok { 302 continue 303 } 304 if len(bundle.KeysById(id, nil)) == 0 { 305 // no match 306 continue 307 } 308 309 // some key in the bundle matched, so unlock everything: 310 parg := libkb.SecretKeyPromptArg{ 311 Reason: unlockReason, 312 SecretUI: m.UIs().SecretUI, 313 } 314 secretStore := libkb.NewSecretStore(m, s.me.GetNormalizedName()) 315 unlocked, err := skb.PromptAndUnlock(m, parg, secretStore, s.me) 316 if err != nil { 317 m.Warning("error unlocking key: %s", err) 318 continue 319 } 320 unlockedBundle, ok := unlocked.(*libkb.PGPKeyBundle) 321 if !ok { 322 m.Warning("could not convert unlocked key to PGPKeyBundle") 323 continue 324 } 325 list = append(list, unlockedBundle.Entity) 326 } 327 return list 328 } 329 330 func (s *ScanKeys) unlockAll(m libkb.MetaContext) openpgp.EntityList { 331 var list openpgp.EntityList 332 for _, skb := range s.skbs { 333 parg := libkb.SecretKeyPromptArg{ 334 Reason: unlockReason, 335 SecretUI: m.UIs().SecretUI, 336 } 337 secretStore := libkb.NewSecretStore(m, s.me.GetNormalizedName()) 338 unlocked, err := skb.PromptAndUnlock(m, parg, secretStore, s.me) 339 if err != nil { 340 m.Warning("error unlocking key: %s", err) 341 continue 342 } 343 unlockedBundle, ok := unlocked.(*libkb.PGPKeyBundle) 344 if !ok { 345 m.Warning("could not convert unlocked key to PGPKeyBundle") 346 continue 347 } 348 list = append(list, unlockedBundle.Entity) 349 } 350 return list 351 }