Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/core/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (c *Core) AccountExport(pw []byte, host string) (*Account, error) {
if err != nil {
return nil, codedError(passwordErr, err)
}
defer crypter.Close()
host, err = addrHost(host)
if err != nil {
return nil, newError(addressParseErr, "error parsing address: %w", err)
Expand Down
13 changes: 13 additions & 0 deletions client/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -1440,6 +1440,7 @@ func (c *Core) encryptionKey(pw []byte) (encrypt.Crypter, error) {
if err != nil {
return nil, fmt.Errorf("outer key deserialization error: %w", err)
}
defer outerCrypter.Close()
innerKey, err := outerCrypter.Decrypt(creds.EncInnerKey)
if err != nil {
return nil, fmt.Errorf("inner key decryption error: %w", err)
Expand Down Expand Up @@ -1711,6 +1712,7 @@ func (c *Core) CreateWallet(appPW, walletPW []byte, form *WalletForm) error {
if err != nil {
return err
}
defer crypter.Close()

walletDef, err := walletDefinition(assetID, form.Type)
if err != nil {
Expand Down Expand Up @@ -1821,6 +1823,7 @@ func (c *Core) createSeededWallet(assetID uint32, crypter encrypt.Crypter, form
if err != nil {
return nil, err
}
defer encode.ClearBytes(seed)

c.log.Infof("Initializing a built-in %s wallet", unbip(assetID))
if err = asset.CreateWallet(assetID, &asset.CreateWalletParams{
Expand Down Expand Up @@ -2052,6 +2055,7 @@ func (c *Core) OpenWallet(assetID uint32, appPW []byte) error {
if err != nil {
return err
}
defer crypter.Close()
wallet, err := c.connectedWallet(assetID)
if err != nil {
return fmt.Errorf("OpenWallet: wallet not found for %d -> %s: %w", assetID, unbip(assetID), err)
Expand Down Expand Up @@ -2173,6 +2177,7 @@ func (c *Core) ReconfigureWallet(appPW, newWalletPW []byte, form *WalletForm) er
if err != nil {
return newError(authErr, "ReconfigureWallet password error: %w", err)
}
defer crypter.Close()
assetID := form.AssetID
walletDef, err := walletDefinition(assetID, form.Type)
if err != nil {
Expand Down Expand Up @@ -2395,6 +2400,7 @@ func (c *Core) SetWalletPassword(appPW []byte, assetID uint32, newPW []byte) err
if err != nil {
return newError(authErr, "SetWalletPassword password error: %w", err)
}
defer crypter.Close()

// Check that the specified wallet exists.
c.walletMtx.Lock()
Expand Down Expand Up @@ -2685,6 +2691,7 @@ func (c *Core) DiscoverAccount(dexAddr string, appPW []byte, certI interface{})
if err != nil {
return nil, false, codedError(passwordErr, err)
}
defer crypter.Close()

var ready bool
dc, err := c.tempDexConnection(host, certI)
Expand Down Expand Up @@ -2781,6 +2788,7 @@ func (c *Core) Register(form *RegisterForm) (*RegisterResult, error) {
if err != nil {
return nil, codedError(passwordErr, err)
}
defer crypter.Close()
if form.Addr == "" {
return nil, newError(emptyHostErr, "no dex address specified")
}
Expand Down Expand Up @@ -3190,6 +3198,7 @@ func (c *Core) ExportSeed(pw []byte) ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("ExportSeed password error: %w", err)
}
defer crypter.Close()

creds := c.creds()
if creds == nil {
Expand Down Expand Up @@ -3230,6 +3239,7 @@ func (c *Core) generateCredentials(pw, seed []byte) (encrypt.Crypter, *db.Primar
} else if len(seed) != seedLen {
return nil, nil, fmt.Errorf("invalid seed length %d. expected %d", len(seed), seedLen)
}
defer encode.ClearBytes(seed)

encSeed, err := innerCrypter.Encrypt(seed)
if err != nil {
Expand Down Expand Up @@ -3273,6 +3283,7 @@ func (c *Core) Login(pw []byte) (*LoginResult, error) {
if err != nil {
return nil, err
}
defer crypter.Close()

// Attempt to connect to and retrieve balance from all known wallets. It is
// not an error if we can't connect, unless we need the wallet for active
Expand Down Expand Up @@ -3886,6 +3897,7 @@ func (c *Core) Withdraw(pw []byte, assetID uint32, value uint64, address string)
if err != nil {
return nil, fmt.Errorf("Withdraw password error: %w", err)
}
defer crypter.Close()
if value == 0 {
return nil, fmt.Errorf("cannot withdraw zero %s", unbip(assetID))
}
Expand Down Expand Up @@ -4046,6 +4058,7 @@ func (c *Core) Trade(pw []byte, form *TradeForm) (*Order, error) {
if err != nil {
return nil, fmt.Errorf("Trade password error: %w", err)
}
defer crypter.Close()
dc, err := c.connectedDEX(form.Host)
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions client/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,7 @@ func (a *dexAccount) setupCryptoV2(creds *db.PrimaryCredentials, crypter encrypt
if err != nil {
return fmt.Errorf("seed decryption error: %w", err)
}
defer encode.ClearBytes(seed)

dexPkB := a.dexPubKey.SerializeCompressed()
// And because I'm neurotic.
Expand Down
13 changes: 3 additions & 10 deletions client/rpcserver/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,7 @@ func handleInit(s *RPCServer, params *RawParams) *msgjson.ResponsePayload {
}
defer func() {
appPass.Clear()
if len(seed) > 0 {
seed.Clear()
}
Comment thread
chappjc marked this conversation as resolved.
seed.Clear()
}()
if err := s.core.InitializeClient(appPass, seed); err != nil {
errMsg := fmt.Sprintf("unable to initialize client: %v", err)
Expand Down Expand Up @@ -206,9 +204,9 @@ func handleOpenWallet(s *RPCServer, params *RawParams) *msgjson.ResponsePayload
if err != nil {
return usage(openWalletRoute, err)
}
defer form.appPass.Clear()

err = s.core.OpenWallet(form.assetID, form.appPass)
form.appPass.Clear() // AppPass not needed after this, clear
if err != nil {
errMsg := fmt.Sprintf("error unlocking %s wallet: %v",
dex.BipIDSymbol(form.assetID), err)
Expand Down Expand Up @@ -609,19 +607,14 @@ func handleAppSeed(s *RPCServer, params *RawParams) *msgjson.ResponsePayload {
}
defer appPass.Clear()
seed, err := s.core.ExportSeed(appPass)
defer encode.ClearBytes(seed)
if err != nil {
errMsg := fmt.Sprintf("unable to retrieve app seed: %v", err)
resErr := msgjson.NewError(msgjson.RPCExportSeedError, errMsg)
return createResponse(appSeedRoute, nil, resErr)
}
// Zero seed and hex representation after use.
seedHex := fmt.Sprintf("%x", seed[:])
defer func() {
for i := range seed {
seed[i] = 0
}
seedHex = ""
}()

return createResponse(appSeedRoute, seedHex, nil)
}
Expand Down
28 changes: 23 additions & 5 deletions client/webserver/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ import (
"decred.org/dcrdex/dex/encode"
)

var zero = encode.ClearBytes

// apiDiscoverAccount is the handler for the '/discoveracct' API request.
func (s *WebServer) apiDiscoverAccount(w http.ResponseWriter, r *http.Request) {
form := new(registrationForm)
defer form.Password.Clear()
if !readPost(w, r, form) {
return
}
Expand All @@ -29,6 +32,7 @@ func (s *WebServer) apiDiscoverAccount(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
exchangeInfo, paid, err := s.core.DiscoverAccount(form.Addr, pass, cert)
if err != nil {
s.writeAPIError(w, err)
Expand Down Expand Up @@ -111,6 +115,7 @@ func (s *WebServer) apiRegister(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
_, err = s.core.Register(&core.RegisterForm{
Addr: reg.Addr,
Cert: []byte(reg.Cert),
Expand All @@ -131,10 +136,8 @@ func (s *WebServer) apiRegister(w http.ResponseWriter, r *http.Request) {
// apiNewWallet is the handler for the '/newwallet' API request.
func (s *WebServer) apiNewWallet(w http.ResponseWriter, r *http.Request) {
form := new(newWalletForm)
defer func() {
form.AppPW.Clear()
form.Pass.Clear()
}()
defer form.AppPW.Clear()
defer form.Pass.Clear()
if !readPost(w, r, form) {
return
}
Expand All @@ -148,6 +151,7 @@ func (s *WebServer) apiNewWallet(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
// Wallet does not exist yet. Try to create it.
err = s.core.CreateWallet(pass, form.Pass, &core.WalletForm{
AssetID: form.AssetID,
Expand Down Expand Up @@ -206,6 +210,7 @@ func (s *WebServer) apiOpenWallet(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
err = s.core.OpenWallet(form.AssetID, pass)
if err != nil {
s.writeAPIError(w, fmt.Errorf("error unlocking %s wallet: %w", unbip(form.AssetID), err))
Expand Down Expand Up @@ -275,6 +280,7 @@ func (s *WebServer) apiTrade(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
ord, err := s.core.Trade(pass, form.Order)
if err != nil {
s.writeAPIError(w, fmt.Errorf("error placing order: %w", err))
Expand Down Expand Up @@ -304,6 +310,7 @@ func (s *WebServer) apiAccountExport(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
account, err := s.core.AccountExport(pass, form.Host)
if err != nil {
s.writeAPIError(w, fmt.Errorf("error exporting account: %w", err))
Expand All @@ -325,6 +332,7 @@ func (s *WebServer) apiExportSeed(w http.ResponseWriter, r *http.Request) {
form := &struct {
Pass encode.PassBytes `json:"pass"`
}{}
defer form.Pass.Clear()
if !readPost(w, r, form) {
return
}
Expand All @@ -334,6 +342,7 @@ func (s *WebServer) apiExportSeed(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("error exporting seed: %w", err))
return
}
defer zero(seed)
writeJSON(w, &struct {
OK bool `json:"ok"`
Seed dex.Bytes `json:"seed"`
Expand All @@ -356,6 +365,7 @@ func (s *WebServer) apiAccountImport(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
err = s.core.AccountImport(pass, form.Account)
if err != nil {
s.writeAPIError(w, fmt.Errorf("error importing account: %w", err))
Expand All @@ -375,6 +385,7 @@ func (s *WebServer) apiAccountDisable(w http.ResponseWriter, r *http.Request) {

// Disable account.
err := s.core.AccountDisable(form.Pass, form.Host)
zero(form.Pass)
if err != nil {
s.writeAPIError(w, fmt.Errorf("error disabling account: %w", err))
return
Expand All @@ -395,6 +406,7 @@ func (s *WebServer) apiCancel(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
err = s.core.Cancel(pass, form.OrderID)
if err != nil {
s.writeAPIError(w, fmt.Errorf("error cancelling order %s: %w", form.OrderID, err))
Expand Down Expand Up @@ -424,6 +436,7 @@ func (s *WebServer) apiCloseWallet(w http.ResponseWriter, r *http.Request) {
func (s *WebServer) apiInit(w http.ResponseWriter, r *http.Request) {
init := new(initForm)
defer init.Pass.Clear()
defer zero(init.Seed)
if !readPost(w, r, init) {
return
}
Expand Down Expand Up @@ -646,6 +659,7 @@ func (s *WebServer) apiChangeAppPass(w http.ResponseWriter, r *http.Request) {
log.Errorf("unable to cache password: %w", err)
clearCookie(pwKeyCK, w)
} else {
zero(key)
setCookie(pwKeyCK, hex.EncodeToString(key), w)
}
}
Expand Down Expand Up @@ -675,6 +689,7 @@ func (s *WebServer) apiReconfig(w http.ResponseWriter, r *http.Request) {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
}
defer zero(pass)
// Update wallet settings.
err = s.core.ReconfigureWallet(pass, form.NewWalletPW, &core.WalletForm{
AssetID: form.AssetID,
Expand Down Expand Up @@ -790,9 +805,11 @@ func (s *WebServer) apiPreOrder(w http.ResponseWriter, r *http.Request) {
writeJSON(w, resp, s.indent)
}

// apiActuallyLogin logs the user in.
// apiActuallyLogin logs the user in. login form private data is expected to be
// cleared by the caller.
func (s *WebServer) actuallyLogin(w http.ResponseWriter, r *http.Request, login *loginForm) {
pass, err := s.resolvePass(login.Pass, r)
defer zero(pass)
if err != nil {
s.writeAPIError(w, fmt.Errorf("password error: %w", err))
return
Expand All @@ -814,6 +831,7 @@ func (s *WebServer) actuallyLogin(w http.ResponseWriter, r *http.Request, login
return
}
setCookie(pwKeyCK, hex.EncodeToString(key), w)
zero(key)
} else {
// If dexc was shutdown and restarted, the old pw key cookie might
// need to be cleared.
Expand Down
2 changes: 2 additions & 0 deletions client/webserver/webserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ func (s *WebServer) authorize() string {
b := make([]byte, 32)
rand.Read(b)
token := hex.EncodeToString(b)
zero(b)
s.authMtx.Lock()
s.authTokens[token] = true
s.authMtx.Unlock()
Expand Down Expand Up @@ -589,6 +590,7 @@ func (s *WebServer) getCachedPasswordUsingRequest(r *http.Request) ([]byte, erro
func (s *WebServer) cacheAppPassword(appPW []byte, authToken string) ([]byte, error) {
key := encode.RandomBytes(16)
crypter := encrypt.NewCrypter(key)
defer crypter.Close()
encryptedPass, err := crypter.Encrypt(appPW)
if err != nil {
return nil, fmt.Errorf("error encrypting password: %v", err)
Expand Down