/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/pgp_import_key.go
452 строки
11 KB
chrisnojima-zoom
Version 670 - clean2 (#29122)
08 июн 2026, 19:31
Не верифицирован
08 июн 2026, 19:31
1943197
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package engine // // engine.PGPKeyImportEngine is a class for optionally generating PGP keys, // and pushing them into the keybase sigchain via the Delegator. // import ( "bytes" "errors" "strings" "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" ) type PGPKeyImportEngine struct { me *libkb.User bundle *libkb.PGPKeyBundle arg PGPKeyImportEngineArg epk string del *libkb.Delegator libkb.Contextified } type PGPKeyImportEngineArg struct { Gen *libkb.PGPGenArg Pregen *libkb.PGPKeyBundle SigningKey libkb.GenericKey Me *libkb.User Lks *libkb.LKSec NoSave bool PushSecret bool OnlySave bool AllowMulti bool DoExport bool // export to GPG keychain? ExportEncrypted bool // encrypt secret key before exporting to GPG? DoUnlock bool GPGFallback bool PreloadTsec libkb.Triplesec PreloadStreamGen libkb.PassphraseGeneration } func NewPGPKeyImportEngineFromBytes(g *libkb.GlobalContext, key []byte, pushPrivate bool) (eng *PGPKeyImportEngine, err error) { var bundle *libkb.PGPKeyBundle var w *libkb.Warnings if libkb.IsArmored(key) { bundle, w, err = libkb.ReadPrivateKeyFromString(string(key)) } else { bundle, w, err = libkb.ReadOneKeyFromBytes(key) } if err != nil { return } w.Warn(g) arg := PGPKeyImportEngineArg{ Pregen: bundle, PushSecret: pushPrivate, AllowMulti: true, DoExport: false, DoUnlock: true, } eng = NewPGPKeyImportEngine(g, arg) return } func (e *PGPKeyImportEngine) loadMe(m libkb.MetaContext) (err error) { if e.me = e.arg.Me; e.me != nil { return } e.me, err = libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m).WithPublicKeyOptional()) return err } func (e *PGPKeyImportEngine) generateKey(m libkb.MetaContext) (err error) { gen := e.arg.Gen if err = gen.CreatePGPIDs(); err != nil { return } e.bundle, err = libkb.GeneratePGPKeyBundle(m.G(), *gen, m.UIs().LogUI) return } func (e *PGPKeyImportEngine) saveLKS(m libkb.MetaContext) (err error) { defer m.Trace("PGPKeyImportEngine::saveLKS", &err)() lks := e.arg.Lks if lks == nil { lks, err = libkb.NewLKSecForEncrypt(m, m.UIs().SecretUI, e.me.GetUID()) if err != nil { return err } } _, err = libkb.WriteLksSKBToKeyring(m, e.bundle, lks) return } var ErrKeyGenArgNoDefNoCustom = errors.New("invalid args: NoDefPGPUid set, but no custom PGPUids") func NewPGPKeyImportEngine(g *libkb.GlobalContext, arg PGPKeyImportEngineArg) *PGPKeyImportEngine { return &PGPKeyImportEngine{arg: arg, Contextified: libkb.NewContextified(g)} } func (e *PGPKeyImportEngine) Name() string { return "PGPKeyImportEngine" } func (e *PGPKeyImportEngine) Prereqs() Prereqs { return Prereqs{} } func (e *PGPKeyImportEngine) RequiredUIs() []libkb.UIKind { return []libkb.UIKind{ libkb.LogUIKind, libkb.SecretUIKind, } } func (e *PGPKeyImportEngine) SubConsumers() []libkb.UIConsumer { return nil } func (e *PGPKeyImportEngine) init() (err error) { if e.arg.Gen != nil { err = e.arg.Gen.Init() } return err } func (e *PGPKeyImportEngine) testExisting() (err error) { return PGPCheckMulti(e.me, e.arg.AllowMulti) } // checkPregenPrivate makes sure that the pregenerated key is a // private key. func (e *PGPKeyImportEngine) checkPregenPrivate() error { if e.arg.Pregen == nil { return nil } if e.arg.Pregen.HasSecretKey() || e.arg.GPGFallback { return nil } return libkb.NoSecretKeyError{} } func (e *PGPKeyImportEngine) checkExistingKey(m libkb.MetaContext) error { // Check if we have a public key that matches pgps := e.me.GetActivePGPKeys(false) for _, key := range pgps { if e.GetKID() != key.GetKID() { continue } e.G().Log.Info("Key %s already exists. Only importing the private key.", e.GetKID()) e.arg.OnlySave = true break } return nil } func (e *PGPKeyImportEngine) Run(m libkb.MetaContext) (err error) { defer m.Trace("PGPKeyImportEngine::Run", &err)() if err = e.init(); err != nil { return err } if err = e.loadMe(m); err != nil { switch err.(type) { case libkb.SelfNotFoundError: return libkb.LoginRequiredError{} default: return err } } if e.arg.PushSecret { if err = e.checkRandomPassword(m); err != nil { return err } } if err = e.checkPregenPrivate(); err != nil { return err } if !e.arg.OnlySave { if err = e.testExisting(); err != nil { return err } if err = e.loadDelegator(m); err != nil { switch err.(type) { case libkb.NoUsernameError: return libkb.LoginRequiredError{} default: return err } } } if err = e.generate(m); err != nil { return err } if err = e.unlock(m); err != nil { return err } if err := e.checkExistingKey(m); err != nil { return err } if err = e.saveKey(m); err != nil { return err } if !e.arg.OnlySave { if err = e.push(m); err != nil { return err } if err = e.exportToGPG(m); err != nil { return GPGExportingError{err, true /* inPGPGen */} } } else if e.arg.PushSecret { if err = e.pushSecretOnly(m); err != nil { return err } } return nil } func (e *PGPKeyImportEngine) checkRandomPassword(mctx libkb.MetaContext) error { passphraseState, err := libkb.LoadPassphraseState(mctx) if err != nil { return err } if passphraseState == keybase1.PassphraseState_RANDOM { return libkb.NewPushSecretWithoutPasswordError("You need to set your password first before uploading secret keys") } return nil } // clonePGPKeyBundle returns an approximate deep copy of PGPKeyBundle // by exporting and re-importing PGPKeyBundle. If PGP key contains // something that is not supported by either go-crypto exporter or // importer, that information will be lost. func clonePGPKeyBundle(bundle *libkb.PGPKeyBundle) (*libkb.PGPKeyBundle, error) { var buf bytes.Buffer if err := bundle.SerializePrivate(&buf); err != nil { return nil, err } res, _, err := libkb.ReadOneKeyFromBytes(buf.Bytes()) if err != nil { return nil, err } return res, nil } func (e *PGPKeyImportEngine) exportToGPG(m libkb.MetaContext) (err error) { if !e.arg.DoExport || e.arg.Pregen != nil { m.Debug("| Skipping export to GPG") return nil } gpg := e.G().GetGpgClient() ok, err := gpg.CanExec(m) if err != nil { m.Debug("Not saving new key to GPG. Error in gpg.CanExec(): %s", err) // libkb/util_*.go:canExec() can return generic errors, just ignore them // in this situation since export to gpg is on by default in the client // pgp gen command. return nil } if !ok { m.Debug("Not saving new key to GPG since no gpg install was found") return nil } exportedBundle := e.bundle if e.arg.ExportEncrypted { m.Debug("Encrypting key with passphrase before exporting") desc := "Exporting key to GPG keychain. Enter passphrase to protect the key. Secure passphrases have at least 8 characters." pRes, err := GetPGPExportPassphrase(m, m.UIs().SecretUI, desc) if err != nil { return err } // Avoid mutating e.bundle. if exportedBundle, err = clonePGPKeyBundle(e.bundle); err != nil { return err } if err = libkb.EncryptPGPKey(exportedBundle.Entity, pRes.Passphrase); err != nil { return err } } // If key is encrypted, use batch mode in gpg so it does not ask // for passphrase to re-encrypt to its internal representation. err = gpg.ExportKey(m, *exportedBundle, true /* private */, e.arg.ExportEncrypted /* batch */) if err == nil { m.UIs().LogUI.Info("Exported new key to the local GPG keychain") } return err } func (e *PGPKeyImportEngine) unlock(m libkb.MetaContext) (err error) { defer m.Trace("PGPKeyImportEngine::unlock", &err)() if e.arg.Pregen == nil || !e.arg.DoUnlock || !e.arg.Pregen.HasSecretKey() { m.Debug("| short circuit unlock function") } else { err = e.arg.Pregen.Unlock(m, "import into private keychain", m.UIs().SecretUI) } return err } func (e *PGPKeyImportEngine) loadDelegator(m libkb.MetaContext) (err error) { e.del = &libkb.Delegator{ ExistingKey: e.arg.SigningKey, Me: e.me, Expire: libkb.KeyExpireIn, DelegationType: libkb.DelegationTypeSibkey, Contextified: libkb.NewContextified(e.G()), } return e.del.LoadSigningKey(m, m.UIs().SecretUI) } func (e *PGPKeyImportEngine) generate(m libkb.MetaContext) (err error) { defer m.Trace("PGP::Generate", &err)() m.Debug("| GenerateKey") if e.arg.Pregen != nil { e.bundle = e.arg.Pregen } else if e.arg.Gen == nil { err = libkb.InternalError{Msg: "PGPKeyImportEngine: need either Gen or Pregen"} return } else if err = e.generateKey(m); err != nil { return } return } func (e *PGPKeyImportEngine) saveKey(m libkb.MetaContext) (err error) { defer m.Trace("PGP::saveKey", &err)() m.Debug("| WriteKey (hasSecret = %v)", e.bundle.HasSecretKey()) if !e.arg.NoSave && e.bundle.HasSecretKey() { if err = e.saveLKS(m); err != nil { return } } if e.arg.PushSecret { if err = e.prepareSecretPush(m); err != nil { return } } return } func (e *PGPKeyImportEngine) prepareSecretPush(m libkb.MetaContext) error { var tsec libkb.Triplesec var gen libkb.PassphraseGeneration if e.arg.PreloadTsec != nil && e.arg.PreloadStreamGen > 0 { tsec = e.arg.PreloadTsec gen = e.arg.PreloadStreamGen } else { var err error tsec, gen, err = libkb.GetTriplesecMaybePrompt(m) if err != nil { return err } } skb, err := e.bundle.ToServerSKB(m.G(), tsec, gen) if err != nil { return err } e.epk, err = skb.ArmoredEncode() return err } func (e *PGPKeyImportEngine) push(m libkb.MetaContext) (err error) { defer m.Trace("PGP#Push", &err)() if e.arg.GPGFallback { e.bundle.GPGFallbackKey = libkb.NewGPGKey( m.G(), e.bundle.GetFingerprintP(), e.bundle.GetKID(), m.UIs().GPGUI, m.UIs().ClientType) } e.del.NewKey = e.bundle e.del.EncodedPrivateKey = e.epk if err = e.del.Run(m); err != nil { return err } m.UIs().LogUI.Info("Generated new PGP key:") d := e.bundle.VerboseDescription() for line := range strings.SplitSeq(d, "\n") { m.UIs().LogUI.Info(" %s", line) } return nil } func (e *PGPKeyImportEngine) pushSecretOnly(m libkb.MetaContext) (err error) { defer m.Trace("PGP#PushSecretOnly", &err)() m.UIs().LogUI.Info("Only pushing encrypted private key to Keybase server") hargs := libkb.HTTPArgs{ "private_key": libkb.S{Val: e.epk}, } arg := libkb.APIArg{ Endpoint: "key/add", SessionType: libkb.APISessionTypeREQUIRED, Args: hargs, } _, err = m.G().API.Post(m, arg) if err != nil { return err } m.UIs().LogUI.Info("Success! Pushed encrypted private key") return nil } func PGPCheckMulti(me *libkb.User, allowMulti bool) (err error) { if allowMulti { return } if pgps := me.GetActivePGPKeys(false); len(pgps) > 0 { err = libkb.KeyExistsError{Key: pgps[0].GetFingerprintP()} } return } func (e *PGPKeyImportEngine) GetKID() (kid keybase1.KID) { if e.bundle == nil { return kid } return e.bundle.GetKID() }