aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md6
-rw-r--r--cmd/faucet/faucet.go4
-rw-r--r--cmd/geth/accountcmd.go123
-rw-r--r--cmd/geth/accountcmd_test.go16
-rw-r--r--cmd/puppeth/ssh.go49
-rw-r--r--cmd/puppeth/wizard.go14
-rw-r--r--cmd/puppeth/wizard_genesis.go2
-rw-r--r--cmd/puppeth/wizard_intro.go9
-rw-r--r--cmd/puppeth/wizard_netstats.go4
-rw-r--r--cmd/puppeth/wizard_network.go18
-rw-r--r--cmd/utils/flags.go32
-rw-r--r--cmd/wnode/main.go38
-rw-r--r--consensus/ethash/ethash.go6
-rw-r--r--console/bridge.go9
-rw-r--r--eth/backend.go6
-rw-r--r--eth/config.go2
-rw-r--r--eth/downloader/downloader.go4
-rw-r--r--eth/gen_config.go4
-rw-r--r--eth/handler.go6
-rw-r--r--eth/helper_test.go2
-rw-r--r--eth/peer.go8
-rw-r--r--eth/protocol.go2
-rw-r--r--eth/protocol_test.go4
-rw-r--r--ethstats/ethstats.go4
-rw-r--r--internal/ethapi/api.go4
-rw-r--r--internal/web3ext/web3ext.go101
-rw-r--r--les/backend.go6
-rw-r--r--les/handler.go6
-rw-r--r--les/peer.go8
-rw-r--r--mobile/geth.go6
-rw-r--r--node/node.go1
-rw-r--r--rpc/http.go5
-rw-r--r--vendor/golang.org/x/crypto/curve25519/cswap_amd64.s131
-rw-r--r--vendor/golang.org/x/crypto/curve25519/curve25519.go23
-rw-r--r--vendor/golang.org/x/crypto/ssh/certs.go2
-rw-r--r--vendor/golang.org/x/crypto/ssh/client.go56
-rw-r--r--vendor/golang.org/x/crypto/ssh/client_auth.go45
-rw-r--r--vendor/golang.org/x/crypto/ssh/common.go14
-rw-r--r--vendor/golang.org/x/crypto/ssh/doc.go3
-rw-r--r--vendor/golang.org/x/crypto/ssh/handshake.go53
-rw-r--r--vendor/golang.org/x/crypto/ssh/keys.go90
-rw-r--r--vendor/golang.org/x/crypto/ssh/server.go33
-rw-r--r--vendor/golang.org/x/crypto/ssh/streamlocal.go115
-rw-r--r--vendor/golang.org/x/crypto/ssh/tcpip.go198
-rw-r--r--vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go63
-rw-r--r--vendor/vendor.json66
-rw-r--r--whisper/mailserver/server_test.go13
-rw-r--r--whisper/whisperv5/api.go85
-rw-r--r--whisper/whisperv5/api_test.go32
-rw-r--r--whisper/whisperv5/benchmarks_test.go20
-rw-r--r--whisper/whisperv5/doc.go16
-rw-r--r--whisper/whisperv5/envelope.go27
-rw-r--r--whisper/whisperv5/filter_test.go39
-rw-r--r--whisper/whisperv5/message.go133
-rw-r--r--whisper/whisperv5/message_test.go140
-rw-r--r--whisper/whisperv5/peer.go21
-rw-r--r--whisper/whisperv5/peer_test.go10
-rw-r--r--whisper/whisperv5/whisper.go55
-rw-r--r--whisper/whisperv5/whisper_test.go15
59 files changed, 1340 insertions, 667 deletions
diff --git a/README.md b/README.md
index 34522fc06..a516ec0ad 100644
--- a/README.md
+++ b/README.md
@@ -161,6 +161,12 @@ and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`)
```json
{
+ "config": {
+ "chainId": 0,
+ "homesteadBlock": 0,
+ "eip155Block": 0,
+ "eip158Block": 0
+ },
"alloc" : {},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go
index f87cfdb72..1c5c43edc 100644
--- a/cmd/faucet/faucet.go
+++ b/cmd/faucet/faucet.go
@@ -61,7 +61,7 @@ var (
apiPortFlag = flag.Int("apiport", 8080, "Listener port for the HTTP API connection")
ethPortFlag = flag.Int("ethport", 30303, "Listener port for the devp2p connection")
bootFlag = flag.String("bootnodes", "", "Comma separated bootnode enode URLs to seed with")
- netFlag = flag.Int("network", 0, "Network ID to use for the Ethereum protocol")
+ netFlag = flag.Uint64("network", 0, "Network ID to use for the Ethereum protocol")
statsFlag = flag.String("ethstats", "", "Ethstats network monitoring auth string")
netnameFlag = flag.String("faucet.name", "", "Network name to assign to the faucet")
@@ -179,7 +179,7 @@ type faucet struct {
lock sync.RWMutex // Lock protecting the faucet's internals
}
-func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network int, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) {
+func newFaucet(genesis *core.Genesis, port int, enodes []*discv5.Node, network uint64, stats string, ks *keystore.KeyStore, index []byte) (*faucet, error) {
// Assemble the raw devp2p protocol stack
stack, err := node.New(&node.Config{
Name: "geth",
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go
index 90f79a47e..1a3c63da9 100644
--- a/cmd/geth/accountcmd.go
+++ b/cmd/geth/accountcmd.go
@@ -31,41 +31,33 @@ import (
var (
walletCommand = cli.Command{
- Name: "wallet",
- Usage: "Manage Ethereum presale wallets",
- ArgsUsage: "",
- Category: "ACCOUNT COMMANDS",
+ Name: "wallet",
+ Usage: "Import Ethereum presale wallets",
+ Action: utils.MigrateFlags(importWallet),
+ Category: "ACCOUNT COMMANDS",
+ Flags: []cli.Flag{
+ utils.DataDirFlag,
+ utils.KeyStoreDirFlag,
+ utils.PasswordFileFlag,
+ utils.LightKDFFlag,
+ },
Description: `
- geth wallet import /path/to/my/presale.wallet
+ geth wallet [options] /path/to/my/presale.wallet
-will prompt for your password and imports your ether presale account.
-It can be used non-interactively with the --password option taking a
-passwordfile as argument containing the wallet password in plaintext.
+ will prompt for your password and imports your ether presale account.
+ It can be used non-interactively with the --password option taking a
+ passwordfile as argument containing the wallet password in plaintext.
-`,
- Subcommands: []cli.Command{
- {
- Action: importWallet,
- Name: "import",
- Usage: "Import Ethereum presale wallet",
- ArgsUsage: "<keyFile>",
- Description: `
-TODO: Please write this
-`,
- },
- },
+ `,
}
accountCommand = cli.Command{
- Action: accountList,
- Name: "account",
- Usage: "Manage accounts",
- ArgsUsage: "",
- Category: "ACCOUNT COMMANDS",
+ Name: "account",
+ Usage: "Manage accounts",
+ Category: "ACCOUNT COMMANDS",
Description: `
-Manage accounts lets you create new accounts, list all existing accounts,
-import a private key into a new account.
-' help' shows a list of subcommands or help for one subcommand.
+Manage accounts, list all existing accounts, import a private key into a new
+account, create a new account or update an existing account.
It supports interactive mode, when you are prompted for password as well as
non-interactive mode where passwords are supplied via a given password file.
@@ -80,36 +72,34 @@ Note that exporting your key in unencrypted format is NOT supported.
Keys are stored under <DATADIR>/keystore.
It is safe to transfer the entire directory or the individual keys therein
between ethereum nodes by simply copying.
-Make sure you backup your keys regularly.
-In order to use your account to send transactions, you need to unlock them using
-the '--unlock' option. The argument is a space separated list of addresses or
-indexes. If used non-interactively with a passwordfile, the file should contain
-the respective passwords one per line. If you unlock n accounts and the password
-file contains less than n entries, then the last password is meant to apply to
-all remaining accounts.
-
-And finally. DO NOT FORGET YOUR PASSWORD.
-`,
+Make sure you backup your keys regularly.`,
Subcommands: []cli.Command{
{
- Action: accountList,
- Name: "list",
- Usage: "Print account addresses",
- ArgsUsage: " ",
+ Name: "list",
+ Usage: "Print summary of existing accounts",
+ Action: utils.MigrateFlags(accountList),
+ Flags: []cli.Flag{
+ utils.DataDirFlag,
+ utils.KeyStoreDirFlag,
+ },
Description: `
-TODO: Please write this
-`,
+Print a short summary of all accounts`,
},
{
- Action: accountCreate,
- Name: "new",
- Usage: "Create a new account",
- ArgsUsage: " ",
+ Name: "new",
+ Usage: "Create a new account",
+ Action: utils.MigrateFlags(accountCreate),
+ Flags: []cli.Flag{
+ utils.DataDirFlag,
+ utils.KeyStoreDirFlag,
+ utils.PasswordFileFlag,
+ utils.LightKDFFlag,
+ },
Description: `
geth account new
-Creates a new account. Prints the address.
+Creates a new account and prints the address.
The account is saved in encrypted format, you are prompted for a passphrase.
@@ -117,17 +107,20 @@ You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the --password flag:
- geth --password <passwordfile> account new
-
Note, this is meant to be used for testing only, it is a bad idea to save your
password to file or expose in any other way.
`,
},
{
- Action: accountUpdate,
Name: "update",
Usage: "Update an existing account",
+ Action: utils.MigrateFlags(accountUpdate),
ArgsUsage: "<address>",
+ Flags: []cli.Flag{
+ utils.DataDirFlag,
+ utils.KeyStoreDirFlag,
+ utils.LightKDFFlag,
+ },
Description: `
geth account update <address>
@@ -141,16 +134,22 @@ format to the newest format or change the password for an account.
For non-interactive use the passphrase can be specified with the --password flag:
- geth --password <passwordfile> account update <address>
+ geth account update [options] <address>
Since only one password can be given, only format update can be performed,
changing your password is only possible interactively.
`,
},
{
- Action: accountImport,
- Name: "import",
- Usage: "Import a private key into a new account",
+ Name: "import",
+ Usage: "Import a private key into a new account",
+ Action: utils.MigrateFlags(accountImport),
+ Flags: []cli.Flag{
+ utils.DataDirFlag,
+ utils.KeyStoreDirFlag,
+ utils.PasswordFileFlag,
+ utils.LightKDFFlag,
+ },
ArgsUsage: "<keyFile>",
Description: `
geth account import <keyfile>
@@ -166,7 +165,7 @@ You must remember this passphrase to unlock your account in the future.
For non-interactive use the passphrase can be specified with the -password flag:
- geth --password <passwordfile> account import <keyfile>
+ geth account import [options] <keyfile>
Note:
As you can directly copy your encrypted accounts to another ethereum instance,
@@ -298,10 +297,12 @@ func accountUpdate(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx)
ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
- account, oldPassword := unlockAccount(ctx, ks, ctx.Args().First(), 0, nil)
- newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
- if err := ks.Update(account, oldPassword, newPassword); err != nil {
- utils.Fatalf("Could not update the account: %v", err)
+ for _, addr := range ctx.Args() {
+ account, oldPassword := unlockAccount(ctx, ks, addr, 0, nil)
+ newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
+ if err := ks.Update(account, oldPassword, newPassword); err != nil {
+ utils.Fatalf("Could not update the account: %v", err)
+ }
}
return nil
}
diff --git a/cmd/geth/accountcmd_test.go b/cmd/geth/accountcmd_test.go
index adcb72454..5f9f67677 100644
--- a/cmd/geth/accountcmd_test.go
+++ b/cmd/geth/accountcmd_test.go
@@ -43,13 +43,13 @@ func tmpDatadirWithKeystore(t *testing.T) string {
}
func TestAccountListEmpty(t *testing.T) {
- geth := runGeth(t, "account")
+ geth := runGeth(t, "account", "list")
geth.expectExit()
}
func TestAccountList(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
- geth := runGeth(t, "--datadir", datadir, "account")
+ geth := runGeth(t, "account", "list", "--datadir", datadir)
defer geth.expectExit()
if runtime.GOOS == "windows" {
geth.expect(`
@@ -67,7 +67,7 @@ Account #2: {289d485d9771714cce91d3393d764e1311907acc} keystore://{{.Datadir}}/k
}
func TestAccountNew(t *testing.T) {
- geth := runGeth(t, "--lightkdf", "account", "new")
+ geth := runGeth(t, "account", "new", "--lightkdf")
defer geth.expectExit()
geth.expect(`
Your new account is locked with a password. Please give a password. Do not forget this password.
@@ -79,7 +79,7 @@ Repeat passphrase: {{.InputLine "foobar"}}
}
func TestAccountNewBadRepeat(t *testing.T) {
- geth := runGeth(t, "--lightkdf", "account", "new")
+ geth := runGeth(t, "account", "new", "--lightkdf")
defer geth.expectExit()
geth.expect(`
Your new account is locked with a password. Please give a password. Do not forget this password.
@@ -92,9 +92,9 @@ Fatal: Passphrases do not match
func TestAccountUpdate(t *testing.T) {
datadir := tmpDatadirWithKeystore(t)
- geth := runGeth(t,
+ geth := runGeth(t, "account", "update",
"--datadir", datadir, "--lightkdf",
- "account", "update", "f466859ead1932d743d622cb74fc058882e8648a")
+ "f466859ead1932d743d622cb74fc058882e8648a")
defer geth.expectExit()
geth.expect(`
Unlocking account f466859ead1932d743d622cb74fc058882e8648a | Attempt 1/3
@@ -107,7 +107,7 @@ Repeat passphrase: {{.InputLine "foobar2"}}
}
func TestWalletImport(t *testing.T) {
- geth := runGeth(t, "--lightkdf", "wallet", "import", "testdata/guswallet.json")
+ geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.expectExit()
geth.expect(`
!! Unsupported terminal, password will be echoed.
@@ -122,7 +122,7 @@ Address: {d4584b5f6229b7be90727b0fc8c6b91bb427821f}
}
func TestWalletImportBadPassword(t *testing.T) {
- geth := runGeth(t, "--lightkdf", "wallet", "import", "testdata/guswallet.json")
+ geth := runGeth(t, "wallet", "import", "--lightkdf", "testdata/guswallet.json")
defer geth.expectExit()
geth.expect(`
!! Unsupported terminal, password will be echoed.
diff --git a/cmd/puppeth/ssh.go b/cmd/puppeth/ssh.go
index 34fbc566d..93668945c 100644
--- a/cmd/puppeth/ssh.go
+++ b/cmd/puppeth/ssh.go
@@ -17,6 +17,8 @@
package main
import (
+ "bufio"
+ "bytes"
"errors"
"fmt"
"io/ioutil"
@@ -37,18 +39,26 @@ import (
type sshClient struct {
server string // Server name or IP without port number
address string // IP address of the remote server
+ pubkey []byte // RSA public key to authenticate the server
client *ssh.Client
logger log.Logger
}
// dial establishes an SSH connection to a remote node using the current user and
-// the user's configured private RSA key.
-func dial(server string) (*sshClient, error) {
+// the user's configured private RSA key. If that fails, password authentication
+// is fallen back to. The caller may override the login user via user@server:port.
+func dial(server string, pubkey []byte) (*sshClient, error) {
// Figure out a label for the server and a logger
label := server
if strings.Contains(label, ":") {
label = label[:strings.Index(label, ":")]
}
+ login := ""
+ if strings.Contains(server, "@") {
+ login = label[:strings.Index(label, "@")]
+ label = label[strings.Index(label, "@")+1:]
+ server = server[strings.Index(server, "@")+1:]
+ }
logger := log.New("server", label)
logger.Debug("Attempting to establish SSH connection")
@@ -56,6 +66,9 @@ func dial(server string) (*sshClient, error) {
if err != nil {
return nil, err
}
+ if login == "" {
+ login = user.Username
+ }
// Configure the supported authentication methods (private key and password)
var auths []ssh.AuthMethod
@@ -71,7 +84,7 @@ func dial(server string) (*sshClient, error) {
}
}
auths = append(auths, ssh.PasswordCallback(func() (string, error) {
- fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", user.Username, server)
+ fmt.Printf("What's the login password for %s at %s? (won't be echoed)\n> ", login, server)
blob, err := terminal.ReadPassword(int(syscall.Stdin))
fmt.Println()
@@ -86,11 +99,36 @@ func dial(server string) (*sshClient, error) {
return nil, errors.New("no IPs associated with domain")
}
// Try to dial in to the remote server
- logger.Trace("Dialing remote SSH server", "user", user.Username, "key", path)
+ logger.Trace("Dialing remote SSH server", "user", login)
if !strings.Contains(server, ":") {
server += ":22"
}
- client, err := ssh.Dial("tcp", server, &ssh.ClientConfig{User: user.Username, Auth: auths})
+ keycheck := func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+ // If no public key is known for SSH, ask the user to confirm
+ if pubkey == nil {
+ fmt.Printf("The authenticity of host '%s (%s)' can't be established.\n", hostname, remote)
+ fmt.Printf("SSH key fingerprint is %s [MD5]\n", ssh.FingerprintLegacyMD5(key))
+ fmt.Printf("Are you sure you want to continue connecting (yes/no)? ")
+
+ text, err := bufio.NewReader(os.Stdin).ReadString('\n')
+ switch {
+ case err != nil:
+ return err
+ case strings.TrimSpace(text) == "yes":
+ pubkey = key.Marshal()
+ return nil
+ default:
+ return fmt.Errorf("unknown auth choice: %v", text)
+ }
+ }
+ // If a public key exists for this SSH server, check that it matches
+ if bytes.Compare(pubkey, key.Marshal()) == 0 {
+ return nil
+ }
+ // We have a mismatch, forbid connecting
+ return errors.New("ssh key mismatch, readd the machine to update")
+ }
+ client, err := ssh.Dial("tcp", server, &ssh.ClientConfig{User: login, Auth: auths, HostKeyCallback: keycheck})
if err != nil {
return nil, err
}
@@ -98,6 +136,7 @@ func dial(server string) (*sshClient, error) {
c := &sshClient{
server: label,
address: addr[0],
+ pubkey: pubkey,
client: client,
logger: logger,
}
diff --git a/cmd/puppeth/wizard.go b/cmd/puppeth/wizard.go
index 92d7962a0..9687d5e0d 100644
--- a/cmd/puppeth/wizard.go
+++ b/cmd/puppeth/wizard.go
@@ -44,14 +44,24 @@ type config struct {
bootLight []string // Bootnodes to always connect to by light nodes
ethstats string // Ethstats settings to cache for node deploys
- Servers []string `json:"servers,omitempty"`
+ Servers map[string][]byte `json:"servers,omitempty"`
+}
+
+// servers retrieves an alphabetically sorted list of servers.
+func (c config) servers() []string {
+ servers := make([]string, 0, len(c.Servers))
+ for server := range c.Servers {
+ servers = append(servers, server)
+ }
+ sort.Strings(servers)
+
+ return servers
}
// flush dumps the contents of config to disk.
func (c config) flush() {
os.MkdirAll(filepath.Dir(c.path), 0755)
- sort.Strings(c.Servers)
out, _ := json.MarshalIndent(c, "", " ")
if err := ioutil.WriteFile(c.path, out, 0644); err != nil {
log.Warn("Failed to save puppeth configs", "file", c.path, "err", err)
diff --git a/cmd/puppeth/wizard_genesis.go b/cmd/puppeth/wizard_genesis.go
index a67812e92..705e01031 100644
--- a/cmd/puppeth/wizard_genesis.go
+++ b/cmd/puppeth/wizard_genesis.go
@@ -120,7 +120,7 @@ func (w *wizard) makeGenesis() {
// Query the user for some custom extras
fmt.Println()
fmt.Println("Specify your chain/network ID if you want an explicit one (default = random)")
- genesis.Config.ChainId = big.NewInt(int64(w.readDefaultInt(rand.Intn(65536))))
+ genesis.Config.ChainId = new(big.Int).SetUint64(uint64(w.readDefaultInt(rand.Intn(65536))))
fmt.Println()
fmt.Println("Anything fun to embed into the genesis block? (max 32 bytes)")
diff --git a/cmd/puppeth/wizard_intro.go b/cmd/puppeth/wizard_intro.go
index 46383bb54..c3eaf5324 100644
--- a/cmd/puppeth/wizard_intro.go
+++ b/cmd/puppeth/wizard_intro.go
@@ -31,7 +31,10 @@ import (
// makeWizard creates and returns a new puppeth wizard.
func makeWizard(network string) *wizard {
return &wizard{
- network: network,
+ network: network,
+ conf: config{
+ Servers: make(map[string][]byte),
+ },
servers: make(map[string]*sshClient),
services: make(map[string][]string),
in: bufio.NewReader(os.Stdin),
@@ -77,9 +80,9 @@ func (w *wizard) run() {
} else if err := json.Unmarshal(blob, &w.conf); err != nil {
log.Crit("Previous configuration corrupted", "path", w.conf.path, "err", err)
} else {
- for _, server := range w.conf.Servers {
+ for server, pubkey := range w.conf.Servers {
log.Info("Dialing previously configured server", "server", server)
- client, err := dial(server)
+ client, err := dial(server, pubkey)
if err != nil {
log.Error("Previous server unreachable", "server", server, "err", err)
}
diff --git a/cmd/puppeth/wizard_netstats.go b/cmd/puppeth/wizard_netstats.go
index c2a933a55..1225abb75 100644
--- a/cmd/puppeth/wizard_netstats.go
+++ b/cmd/puppeth/wizard_netstats.go
@@ -41,14 +41,14 @@ func (w *wizard) networkStats(tips bool) {
stats.SetHeader([]string{"Server", "IP", "Status", "Service", "Details"})
stats.SetColWidth(128)
- for _, server := range w.conf.Servers {
+ for server, pubkey := range w.conf.Servers {
client := w.servers[server]
logger := log.New("server", server)
logger.Info("Starting remote server health-check")
// If the server is not connected, try to connect again
if client == nil {
- conn, err := dial(server)
+ conn, err := dial(server, pubkey)
if err != nil {
logger.Error("Failed to establish remote connection", "err", err)
stats.Append([]string{server, "", err.Error(), "", ""})
diff --git a/cmd/puppeth/wizard_network.go b/cmd/puppeth/wizard_network.go
index 001d4e5b4..0455e1ef3 100644
--- a/cmd/puppeth/wizard_network.go
+++ b/cmd/puppeth/wizard_network.go
@@ -28,7 +28,9 @@ import (
func (w *wizard) manageServers() {
// List all the servers we can disconnect, along with an entry to connect a new one
fmt.Println()
- for i, server := range w.conf.Servers {
+
+ servers := w.conf.servers()
+ for i, server := range servers {
fmt.Printf(" %d. Disconnect %s\n", i+1, server)
}
fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1)
@@ -40,14 +42,14 @@ func (w *wizard) manageServers() {
}
// If the user selected an existing server, drop it
if choice <= len(w.conf.Servers) {
- server := w.conf.Servers[choice-1]
+ server := servers[choice-1]
client := w.servers[server]
delete(w.servers, server)
if client != nil {
client.Close()
}
- w.conf.Servers = append(w.conf.Servers[:choice-1], w.conf.Servers[choice:]...)
+ delete(w.conf.Servers, server)
w.conf.flush()
log.Info("Disconnected existing server", "server", server)
@@ -73,14 +75,14 @@ func (w *wizard) makeServer() string {
// Read and fial the server to ensure docker is present
input := w.readString()
- client, err := dial(input)
+ client, err := dial(input, nil)
if err != nil {
log.Error("Server not ready for puppeth", "err", err)
return ""
}
// All checks passed, start tracking the server
w.servers[input] = client
- w.conf.Servers = append(w.conf.Servers, input)
+ w.conf.Servers[input] = client.pubkey
w.conf.flush()
return input
@@ -93,7 +95,9 @@ func (w *wizard) selectServer() string {
// List the available server to the user and wait for a choice
fmt.Println()
fmt.Println("Which server do you want to interact with?")
- for i, server := range w.conf.Servers {
+
+ servers := w.conf.servers()
+ for i, server := range servers {
fmt.Printf(" %d. %s\n", i+1, server)
}
fmt.Printf(" %d. Connect another server\n", len(w.conf.Servers)+1)
@@ -105,7 +109,7 @@ func (w *wizard) selectServer() string {
}
// If the user requested connecting to a new server, go for it
if choice <= len(w.conf.Servers) {
- return w.conf.Servers[choice-1]
+ return servers[choice-1]
}
return w.makeServer()
}
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index af9585bd0..9e80bba60 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -52,7 +52,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
- whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
+ whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
"gopkg.in/urfave/cli.v1"
)
@@ -148,7 +148,7 @@ var (
Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
Value: eth.DefaultConfig.EthashDatasetsOnDisk,
}
- NetworkIdFlag = cli.IntFlag{
+ NetworkIdFlag = cli.Uint64Flag{
Name: "networkid",
Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)",
Value: eth.DefaultConfig.NetworkId,
@@ -647,7 +647,7 @@ func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
}
}
-// MakePasswordList reads password lines from the file specified by --password.
+// MakePasswordList reads password lines from the file specified by the global --password flag.
func MakePasswordList(ctx *cli.Context) []string {
path := ctx.GlobalString(PasswordFileFlag.Name)
if path == "" {
@@ -806,7 +806,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name)
}
if ctx.GlobalIsSet(NetworkIdFlag.Name) {
- cfg.NetworkId = ctx.GlobalInt(NetworkIdFlag.Name)
+ cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
}
// Ethereum needs to know maxPeers to calculate the light server peer ratio.
@@ -979,3 +979,27 @@ func MakeConsolePreloads(ctx *cli.Context) []string {
}
return preloads
}
+
+// MigrateFlags sets the global flag from a local flag when it's set.
+// This is a temporary function used for migrating old command/flags to the
+// new format.
+//
+// e.g. geth account new --keystore /tmp/mykeystore --lightkdf
+//
+// is equivalent after calling this method with:
+//
+// geth --keystore /tmp/mykeystore --lightkdf account new
+//
+// This allows the use of the existing configuration functionality.
+// When all flags are migrated this function can be removed and the existing
+// configuration functionality must be changed that is uses local flags
+func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
+ return func(ctx *cli.Context) error {
+ for _, name := range ctx.FlagNames() {
+ if ctx.IsSet(name) {
+ ctx.GlobalSet(name, ctx.String(name))
+ }
+ }
+ return action(ctx)
+ }
+}
diff --git a/cmd/wnode/main.go b/cmd/wnode/main.go
index 23b180487..f18025dff 100644
--- a/cmd/wnode/main.go
+++ b/cmd/wnode/main.go
@@ -65,7 +65,7 @@ var (
pub *ecdsa.PublicKey
asymKey *ecdsa.PrivateKey
nodeid *ecdsa.PrivateKey
- topic []byte
+ topic whisper.TopicType
asymKeyID string
filterID string
symPass string
@@ -84,7 +84,7 @@ var (
testMode = flag.Bool("test", false, "use of predefined parameters for diagnostics")
echoMode = flag.Bool("echo", false, "echo mode: prints some arguments for diagnostics")
- argVerbosity = flag.Int("verbosity", int(log.LvlWarn), "log verbosity level")
+ argVerbosity = flag.Int("verbosity", int(log.LvlError), "log verbosity level")
argTTL = flag.Uint("ttl", 30, "time-to-live for messages in seconds")
argWorkTime = flag.Uint("work", 5, "work time in seconds")
argMaxSize = flag.Int("maxsize", whisper.DefaultMaxMessageLength, "max size of message")
@@ -129,7 +129,7 @@ func processArgs() {
if err != nil {
utils.Fatalf("Failed to parse the topic: %s", err)
}
- topic = x
+ topic = whisper.BytesToTopic(x)
}
if *asymmetricMode && len(*argPub) > 0 {
@@ -183,7 +183,7 @@ func initialize() {
if *testMode {
symPass = "wwww" // ascii code: 0x77777777
- msPassword = "mail server test password"
+ msPassword = "wwww"
}
if *bootstrapMode {
@@ -307,7 +307,11 @@ func configureNode() {
if *asymmetricMode {
if len(*argPub) == 0 {
s := scanLine("Please enter the peer's public key: ")
- pub = crypto.ToECDSAPub(common.FromHex(s))
+ b := common.FromHex(s)
+ if b == nil {
+ utils.Fatalf("Error: can not convert hexadecimal string")
+ }
+ pub = crypto.ToECDSAPub(b)
if !isKeyValid(pub) {
utils.Fatalf("Error: invalid public key")
}
@@ -326,7 +330,7 @@ func configureNode() {
if !*asymmetricMode && !*forwarderMode {
if len(symPass) == 0 {
- symPass, err = console.Stdin.PromptPassword("Please enter the password: ")
+ symPass, err = console.Stdin.PromptPassword("Please enter the password for symmetric encryption: ")
if err != nil {
utils.Fatalf("Failed to read passphrase: %v", err)
}
@@ -343,6 +347,8 @@ func configureNode() {
if len(*argTopic) == 0 {
generateTopic([]byte(symPass))
}
+
+ fmt.Printf("Filter is configured for the topic: %x \n", topic)
}
if *mailServerMode {
@@ -354,18 +360,17 @@ func configureNode() {
filter := whisper.Filter{
KeySym: symKey,
KeyAsym: asymKey,
- Topics: [][]byte{topic},
+ Topics: [][]byte{topic[:]},
AllowP2P: p2pAccept,
}
filterID, err = shh.Subscribe(&filter)
if err != nil {
utils.Fatalf("Failed to install filter: %s", err)
}
- fmt.Printf("Filter is configured for the topic: %x \n", topic)
}
func generateTopic(password []byte) {
- x := pbkdf2.Key(password, password, 8196, 128, sha512.New)
+ x := pbkdf2.Key(password, password, 4096, 128, sha512.New)
for i := 0; i < len(x); i++ {
topic[i%whisper.TopicLength] ^= x[i]
}
@@ -485,16 +490,15 @@ func sendMsg(payload []byte) common.Hash {
Dst: pub,
KeySym: symKey,
Payload: payload,
- Topic: whisper.BytesToTopic(topic),
+ Topic: topic,
TTL: uint32(*argTTL),
PoW: *argPoW,
WorkTime: uint32(*argWorkTime),
}
- msg := whisper.NewSentMessage(&params)
- if msg == nil {
- fmt.Printf("failed to create new message (OS level error)")
- os.Exit(0)
+ msg, err := whisper.NewSentMessage(&params)
+ if err != nil {
+ utils.Fatalf("failed to create new message: %s", err)
}
envelope, err := msg.Wrap(&params)
if err != nil {
@@ -624,9 +628,9 @@ func requestExpiredMessagesLoop() {
params.Src = nodeid
params.WorkTime = 5
- msg := whisper.NewSentMessage(&params)
- if msg == nil {
- utils.Fatalf("failed to create new message (OS level error)")
+ msg, err := whisper.NewSentMessage(&params)
+ if err != nil {
+ utils.Fatalf("failed to create new message: %s", err)
}
env, err := msg.Wrap(&params)
if err != nil {
diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go
index b028f50e6..94a9ea332 100644
--- a/consensus/ethash/ethash.go
+++ b/consensus/ethash/ethash.go
@@ -467,8 +467,9 @@ func (ethash *Ethash) cache(block uint64) []uint32 {
future = &cache{epoch: epoch + 1}
ethash.fcache = future
}
+ // New current cache, set its initial timestamp
+ current.used = time.Now()
}
- current.used = time.Now()
ethash.lock.Unlock()
// Wait for generation finish, bump the timestamp and finalize the cache
@@ -529,8 +530,9 @@ func (ethash *Ethash) dataset(block uint64) []uint32 {
future = &dataset{epoch: epoch + 1}
ethash.fdataset = future
}
+ // New current dataset, set its initial timestamp
+ current.used = time.Now()
}
- current.used = time.Now()
ethash.lock.Unlock()
// Wait for generation finish, bump the timestamp and finalize the cache
diff --git a/console/bridge.go b/console/bridge.go
index 6db54eb21..75be68188 100644
--- a/console/bridge.go
+++ b/console/bridge.go
@@ -20,6 +20,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "strings"
"time"
"github.com/ethereum/go-ethereum/log"
@@ -240,17 +241,19 @@ func (b *bridge) Send(call otto.FunctionCall) (response otto.Value) {
throwJSException(err.Error())
}
var (
- rawReq = []byte(reqVal.String())
+ rawReq = reqVal.String()
+ dec = json.NewDecoder(strings.NewReader(rawReq))
reqs []jsonrpcCall
batch bool
)
+ dec.UseNumber() // avoid float64s
if rawReq[0] == '[' {
batch = true
- json.Unmarshal(rawReq, &reqs)
+ dec.Decode(&reqs)
} else {
batch = false
reqs = make([]jsonrpcCall, 1)
- json.Unmarshal(rawReq, &reqs[0])
+ dec.Decode(&reqs[0])
}
// Execute the requests.
diff --git a/eth/backend.go b/eth/backend.go
index 03c2e38e5..f864b1d88 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -80,7 +80,7 @@ type Ethereum struct {
MinerThreads int
etherbase common.Address
- netVersionId int
+ networkId uint64
netRPCService *ethapi.PublicNetAPI
}
@@ -118,7 +118,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
engine: CreateConsensusEngine(ctx, config, chainConfig, chainDb),
shutdownChan: make(chan bool),
stopDbUpgrade: stopDbUpgrade,
- netVersionId: config.NetworkId,
+ networkId: config.NetworkId,
etherbase: config.Etherbase,
MinerThreads: config.MinerThreads,
}
@@ -347,7 +347,7 @@ func (s *Ethereum) Engine() consensus.Engine { return s.engine }
func (s *Ethereum) ChainDb() ethdb.Database { return s.chainDb }
func (s *Ethereum) IsListening() bool { return true } // Always listening
func (s *Ethereum) EthVersion() int { return int(s.protocolManager.SubProtocols[0].Version) }
-func (s *Ethereum) NetVersion() int { return s.netVersionId }
+func (s *Ethereum) NetVersion() uint64 { return s.networkId }
func (s *Ethereum) Downloader() *downloader.Downloader { return s.protocolManager.downloader }
// Protocols implements node.Service, returning all the currently configured
diff --git a/eth/config.go b/eth/config.go
index 7049940d3..a09ca76f3 100644
--- a/eth/config.go
+++ b/eth/config.go
@@ -72,7 +72,7 @@ type Config struct {
Genesis *core.Genesis `toml:",omitempty"`
// Protocol options
- NetworkId int // Network ID to use for selecting peers to connect to
+ NetworkId uint64 // Network ID to use for selecting peers to connect to
SyncMode downloader.SyncMode
// Light client options
diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go
index d26995782..839969f03 100644
--- a/eth/downloader/downloader.go
+++ b/eth/downloader/downloader.go
@@ -1491,6 +1491,10 @@ func (d *Downloader) qosTuner() {
func (d *Downloader) qosReduceConfidence() {
// If we have a single peer, confidence is always 1
peers := uint64(d.peers.Len())
+ if peers == 0 {
+ // Ensure peer connectivity races don't catch us off guard
+ return
+ }
if peers == 1 {
atomic.StoreUint64(&d.rttConfidence, 1000000)
return
diff --git a/eth/gen_config.go b/eth/gen_config.go
index 56fba1d89..955facf8f 100644
--- a/eth/gen_config.go
+++ b/eth/gen_config.go
@@ -15,7 +15,7 @@ import (
func (c Config) MarshalTOML() (interface{}, error) {
type Config struct {
Genesis *core.Genesis `toml:",omitempty"`
- NetworkId int
+ NetworkId uint64
SyncMode downloader.SyncMode
LightServ int `toml:",omitempty"`
LightPeers int `toml:",omitempty"`
@@ -72,7 +72,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
type Config struct {
Genesis *core.Genesis `toml:",omitempty"`
- NetworkId *int
+ NetworkId *uint64
SyncMode *downloader.SyncMode
LightServ *int `toml:",omitempty"`
LightPeers *int `toml:",omitempty"`
diff --git a/eth/handler.go b/eth/handler.go
index fb8a0fd57..16e371227 100644
--- a/eth/handler.go
+++ b/eth/handler.go
@@ -60,7 +60,7 @@ func errResp(code errCode, format string, v ...interface{}) error {
}
type ProtocolManager struct {
- networkId int
+ networkId uint64
fastSync uint32 // Flag whether fast sync is enabled (gets disabled if we already have blocks)
acceptTxs uint32 // Flag whether we're considered synchronised (enables transaction processing)
@@ -96,7 +96,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
-func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
+func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkId uint64, maxPeers int, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
// Create the protocol manager with the base fields
manager := &ProtocolManager{
networkId: networkId,
@@ -733,7 +733,7 @@ func (self *ProtocolManager) txBroadcastLoop() {
// EthNodeInfo represents a short summary of the Ethereum sub-protocol metadata known
// about the host peer.
type EthNodeInfo struct {
- Network int `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3)
+ Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3)
Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain
Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block
Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block
diff --git a/eth/helper_test.go b/eth/helper_test.go
index 21ac3724e..0260b9d77 100644
--- a/eth/helper_test.go
+++ b/eth/helper_test.go
@@ -173,7 +173,7 @@ func newTestPeer(name string, version int, pm *ProtocolManager, shake bool) (*te
func (p *testPeer) handshake(t *testing.T, td *big.Int, head common.Hash, genesis common.Hash) {
msg := &statusData{
ProtocolVersion: uint32(p.version),
- NetworkId: uint32(DefaultConfig.NetworkId),
+ NetworkId: DefaultConfig.NetworkId,
TD: td,
CurrentBlock: head,
GenesisBlock: genesis,
diff --git a/eth/peer.go b/eth/peer.go
index 6884fee8e..42ead5396 100644
--- a/eth/peer.go
+++ b/eth/peer.go
@@ -230,7 +230,7 @@ func (p *peer) RequestReceipts(hashes []common.Hash) error {
// Handshake executes the eth protocol handshake, negotiating version number,
// network IDs, difficulties, head and genesis blocks.
-func (p *peer) Handshake(network int, td *big.Int, head common.Hash, genesis common.Hash) error {
+func (p *peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis common.Hash) error {
// Send out own handshake in a new thread
errc := make(chan error, 2)
var status statusData // safe to read after two values have been received from errc
@@ -238,7 +238,7 @@ func (p *peer) Handshake(network int, td *big.Int, head common.Hash, genesis com
go func() {
errc <- p2p.Send(p.rw, StatusMsg, &statusData{
ProtocolVersion: uint32(p.version),
- NetworkId: uint32(network),
+ NetworkId: network,
TD: td,
CurrentBlock: head,
GenesisBlock: genesis,
@@ -263,7 +263,7 @@ func (p *peer) Handshake(network int, td *big.Int, head common.Hash, genesis com
return nil
}
-func (p *peer) readStatus(network int, status *statusData, genesis common.Hash) (err error) {
+func (p *peer) readStatus(network uint64, status *statusData, genesis common.Hash) (err error) {
msg, err := p.rw.ReadMsg()
if err != nil {
return err
@@ -281,7 +281,7 @@ func (p *peer) readStatus(network int, status *statusData, genesis common.Hash)
if status.GenesisBlock != genesis {
return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", status.GenesisBlock[:8], genesis[:8])
}
- if int(status.NetworkId) != network {
+ if status.NetworkId != network {
return errResp(ErrNetworkIdMismatch, "%d (!= %d)", status.NetworkId, network)
}
if int(status.ProtocolVersion) != p.version {
diff --git a/eth/protocol.go b/eth/protocol.go
index 40997da7a..4bc8bee72 100644
--- a/eth/protocol.go
+++ b/eth/protocol.go
@@ -105,7 +105,7 @@ type txPool interface {
// statusData is the network packet for the status message.
type statusData struct {
ProtocolVersion uint32
- NetworkId uint32
+ NetworkId uint64
TD *big.Int
CurrentBlock common.Hash
GenesisBlock common.Hash
diff --git a/eth/protocol_test.go b/eth/protocol_test.go
index 74180bedd..2056ee0a8 100644
--- a/eth/protocol_test.go
+++ b/eth/protocol_test.go
@@ -55,7 +55,7 @@ func testStatusMsgErrors(t *testing.T, protocol int) {
wantError: errResp(ErrNoStatusMsg, "first msg has code 2 (!= 0)"),
},
{
- code: StatusMsg, data: statusData{10, uint32(DefaultConfig.NetworkId), td, currentBlock, genesis},
+ code: StatusMsg, data: statusData{10, DefaultConfig.NetworkId, td, currentBlock, genesis},
wantError: errResp(ErrProtocolVersionMismatch, "10 (!= %d)", protocol),
},
{
@@ -63,7 +63,7 @@ func testStatusMsgErrors(t *testing.T, protocol int) {
wantError: errResp(ErrNetworkIdMismatch, "999 (!= 1)"),
},
{
- code: StatusMsg, data: statusData{uint32(protocol), uint32(DefaultConfig.NetworkId), td, currentBlock, common.Hash{3}},
+ code: StatusMsg, data: statusData{uint32(protocol), DefaultConfig.NetworkId, td, currentBlock, common.Hash{3}},
wantError: errResp(ErrGenesisBlockMismatch, "0300000000000000 (!= %x)", genesis[:8]),
},
}
diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go
index c16163ace..8765da8fa 100644
--- a/ethstats/ethstats.go
+++ b/ethstats/ethstats.go
@@ -323,10 +323,10 @@ func (s *Service) login(conn *websocket.Conn) error {
var network, protocol string
if info := infos.Protocols["eth"]; info != nil {
- network = strconv.Itoa(info.(*eth.EthNodeInfo).Network)
+ network = fmt.Sprintf("%d", info.(*eth.EthNodeInfo).Network)
protocol = fmt.Sprintf("eth/%d", eth.ProtocolVersions[0])
} else {
- network = strconv.Itoa(infos.Protocols["les"].(*eth.EthNodeInfo).Network)
+ network = fmt.Sprintf("%d", infos.Protocols["les"].(*eth.EthNodeInfo).Network)
protocol = fmt.Sprintf("les/%d", les.ProtocolVersions[0])
}
auth := &authMsg{
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index f0bc3aa4b..f9eed8797 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -1435,11 +1435,11 @@ func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) {
// PublicNetAPI offers network related RPC methods
type PublicNetAPI struct {
net *p2p.Server
- networkVersion int
+ networkVersion uint64
}
// NewPublicNetAPI creates a new net API instance.
-func NewPublicNetAPI(net *p2p.Server, networkVersion int) *PublicNetAPI {
+func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI {
return &PublicNetAPI{net, networkVersion}
}
diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go
index c9cac125d..e35d74ae1 100644
--- a/internal/web3ext/web3ext.go
+++ b/internal/web3ext/web3ext.go
@@ -525,7 +525,105 @@ web3._extend({
const Shh_JS = `
web3._extend({
property: 'shh',
- methods: [],
+ methods: [
+ new web3._extend.Method({
+ name: 'info',
+ call: 'shh_info'
+ }),
+ new web3._extend.Method({
+ name: 'setMaxMessageLength',
+ call: 'shh_setMaxMessageLength',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'setMinimumPoW',
+ call: 'shh_setMinimumPoW',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'allowP2PMessagesFromPeer',
+ call: 'shh_allowP2PMessagesFromPeer',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'hasKeyPair',
+ call: 'shh_hasKeyPair',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'deleteKeyPair',
+ call: 'shh_deleteKeyPair',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'newKeyPair',
+ call: 'shh_newKeyPair'
+ }),
+ new web3._extend.Method({
+ name: 'getPublicKey',
+ call: 'shh_getPublicKey',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'getPrivateKey',
+ call: 'shh_getPrivateKey',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'generateSymmetricKey',
+ call: 'shh_generateSymmetricKey',
+ }),
+ new web3._extend.Method({
+ name: 'addSymmetricKeyDirect',
+ call: 'shh_addSymmetricKeyDirect',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'addSymmetricKeyFromPassword',
+ call: 'shh_addSymmetricKeyFromPassword',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'hasSymmetricKey',
+ call: 'shh_hasSymmetricKey',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'getSymmetricKey',
+ call: 'shh_getSymmetricKey',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'deleteSymmetricKey',
+ call: 'shh_deleteSymmetricKey',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'subscribe',
+ call: 'shh_subscribe',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'unsubscribe',
+ call: 'shh_unsubscribe',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'getNewSubscriptionMessages',
+ call: 'shh_getNewSubscriptionMessages',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'getFloatingMessages',
+ call: 'shh_getFloatingMessages',
+ params: 1
+ }),
+ new web3._extend.Method({
+ name: 'post',
+ call: 'shh_post',
+ params: 1
+ })
+ ],
properties:
[
new web3._extend.Property({
@@ -536,6 +634,7 @@ web3._extend({
]
});
`
+
const SWARMFS_JS = `
web3._extend({
property: 'swarmfs',
diff --git a/les/backend.go b/les/backend.go
index 783e6e94e..646c81a7b 100644
--- a/les/backend.go
+++ b/les/backend.go
@@ -61,7 +61,7 @@ type LightEthereum struct {
engine consensus.Engine
accountManager *accounts.Manager
- netVersionId int
+ networkId uint64
netRPCService *ethapi.PublicNetAPI
}
@@ -87,7 +87,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
accountManager: ctx.AccountManager,
engine: eth.CreateConsensusEngine(ctx, config, chainConfig, chainDb),
shutdownChan: make(chan bool),
- netVersionId: config.NetworkId,
+ networkId: config.NetworkId,
}
if eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.engine, eth.eventMux); err != nil {
return nil, err
@@ -187,7 +187,7 @@ func (s *LightEthereum) Protocols() []p2p.Protocol {
// Ethereum protocol implementation.
func (s *LightEthereum) Start(srvr *p2p.Server) error {
log.Warn("Light client mode is an experimental feature")
- s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.netVersionId)
+ s.netRPCService = ethapi.NewPublicNetAPI(srvr, s.networkId)
s.protocolManager.Start(srvr)
return nil
}
diff --git a/les/handler.go b/les/handler.go
index fbb9e9906..64023af0f 100644
--- a/les/handler.go
+++ b/les/handler.go
@@ -95,7 +95,7 @@ type ProtocolManager struct {
lightSync bool
txpool txPool
txrelay *LesTxRelay
- networkId int
+ networkId uint64
chainConfig *params.ChainConfig
blockchain BlockChain
chainDb ethdb.Database
@@ -128,7 +128,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
-func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, engine consensus.Engine, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
+func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId uint64, mux *event.TypeMux, engine consensus.Engine, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
// Create the protocol manager with the base fields
manager := &ProtocolManager{
lightSync: lightSync,
@@ -310,7 +310,7 @@ func (pm *ProtocolManager) Stop() {
log.Info("Light Ethereum protocol stopped")
}
-func (pm *ProtocolManager) newPeer(pv, nv int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
+func (pm *ProtocolManager) newPeer(pv int, nv uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
return newPeer(pv, nv, p, newMeteredMsgWriter(rw))
}
diff --git a/les/peer.go b/les/peer.go
index f45605593..ab55bafe3 100644
--- a/les/peer.go
+++ b/les/peer.go
@@ -48,8 +48,8 @@ type peer struct {
rw p2p.MsgReadWriter
- version int // Protocol version negotiated
- network int // Network ID being on
+ version int // Protocol version negotiated
+ network uint64 // Network ID being on
id string
@@ -69,7 +69,7 @@ type peer struct {
fcCosts requestCostTable
}
-func newPeer(version, network int, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
+func newPeer(version int, network uint64, p *p2p.Peer, rw p2p.MsgReadWriter) *peer {
id := p.ID()
return &peer{
@@ -384,7 +384,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, headNum uint64, genesis
if rGenesis != genesis {
return errResp(ErrGenesisBlockMismatch, "%x (!= %x)", rGenesis[:8], genesis[:8])
}
- if int(rNetwork) != p.network {
+ if rNetwork != p.network {
return errResp(ErrNetworkIdMismatch, "%d (!= %d)", rNetwork, p.network)
}
if int(rVersion) != p.version {
diff --git a/mobile/geth.go b/mobile/geth.go
index be04e4603..f254d39bb 100644
--- a/mobile/geth.go
+++ b/mobile/geth.go
@@ -34,7 +34,7 @@ import (
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/params"
- whisper "github.com/ethereum/go-ethereum/whisper/whisperv2"
+ whisper "github.com/ethereum/go-ethereum/whisper/whisperv5"
)
// NodeConfig represents the collection of configuration values to fine tune the Geth
@@ -54,7 +54,7 @@ type NodeConfig struct {
// EthereumNetworkID is the network identifier used by the Ethereum protocol to
// decide if remote peers should be accepted or not.
- EthereumNetworkID int
+ EthereumNetworkID int64 // uint64 in truth, but Java can't handle that...
// EthereumGenesis is the genesis JSON to use to seed the blockchain with. An
// empty genesis state is equivalent to using the mainnet's state.
@@ -148,7 +148,7 @@ func NewNode(datadir string, config *NodeConfig) (stack *Node, _ error) {
ethConf := eth.DefaultConfig
ethConf.Genesis = genesis
ethConf.SyncMode = downloader.LightSync
- ethConf.NetworkId = config.EthereumNetworkID
+ ethConf.NetworkId = uint64(config.EthereumNetworkID)
ethConf.DatabaseCache = config.EthereumDatabaseCache
if err := rawStack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return les.New(ctx, &ethConf)
diff --git a/node/node.go b/node/node.go
index dc2ff0701..a372b1c25 100644
--- a/node/node.go
+++ b/node/node.go
@@ -536,6 +536,7 @@ func (n *Node) Stop() error {
func (n *Node) Wait() {
n.lock.RLock()
if n.server == nil {
+ n.lock.RUnlock()
return
}
stop := n.stop
diff --git a/rpc/http.go b/rpc/http.go
index 022f9ce8f..6bab02ab6 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -162,6 +162,11 @@ func (srv *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
func newCorsHandler(srv *Server, allowedOrigins []string) http.Handler {
+ // disable CORS support if user has not specified a custom CORS configuration
+ if len(allowedOrigins) == 0 {
+ return srv
+ }
+
c := cors.New(cors.Options{
AllowedOrigins: allowedOrigins,
AllowedMethods: []string{"POST", "GET"},
diff --git a/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
index 45484d1b5..cd793a5b5 100644
--- a/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
+++ b/vendor/golang.org/x/crypto/curve25519/cswap_amd64.s
@@ -2,87 +2,64 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// This code was translated into a form compatible with 6a from the public
-// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
-
// +build amd64,!gccgo,!appengine
-// func cswap(inout *[5]uint64, v uint64)
+// func cswap(inout *[4][5]uint64, v uint64)
TEXT ·cswap(SB),7,$0
MOVQ inout+0(FP),DI
MOVQ v+8(FP),SI
- CMPQ SI,$1
- MOVQ 0(DI),SI
- MOVQ 80(DI),DX
- MOVQ 8(DI),CX
- MOVQ 88(DI),R8
- MOVQ SI,R9
- CMOVQEQ DX,SI
- CMOVQEQ R9,DX
- MOVQ CX,R9
- CMOVQEQ R8,CX
- CMOVQEQ R9,R8
- MOVQ SI,0(DI)
- MOVQ DX,80(DI)
- MOVQ CX,8(DI)
- MOVQ R8,88(DI)
- MOVQ 16(DI),SI
- MOVQ 96(DI),DX
- MOVQ 24(DI),CX
- MOVQ 104(DI),R8
- MOVQ SI,R9
- CMOVQEQ DX,SI
- CMOVQEQ R9,DX
- MOVQ CX,R9
- CMOVQEQ R8,CX
- CMOVQEQ R9,R8
- MOVQ SI,16(DI)
- MOVQ DX,96(DI)
- MOVQ CX,24(DI)
- MOVQ R8,104(DI)
- MOVQ 32(DI),SI
- MOVQ 112(DI),DX
- MOVQ 40(DI),CX
- MOVQ 120(DI),R8
- MOVQ SI,R9
- CMOVQEQ DX,SI
- CMOVQEQ R9,DX
- MOVQ CX,R9
- CMOVQEQ R8,CX
- CMOVQEQ R9,R8
- MOVQ SI,32(DI)
- MOVQ DX,112(DI)
- MOVQ CX,40(DI)
- MOVQ R8,120(DI)
- MOVQ 48(DI),SI
- MOVQ 128(DI),DX
- MOVQ 56(DI),CX
- MOVQ 136(DI),R8
- MOVQ SI,R9
- CMOVQEQ DX,SI
- CMOVQEQ R9,DX
- MOVQ CX,R9
- CMOVQEQ R8,CX
- CMOVQEQ R9,R8
- MOVQ SI,48(DI)
- MOVQ DX,128(DI)
- MOVQ CX,56(DI)
- MOVQ R8,136(DI)
- MOVQ 64(DI),SI
- MOVQ 144(DI),DX
- MOVQ 72(DI),CX
- MOVQ 152(DI),R8
- MOVQ SI,R9
- CMOVQEQ DX,SI
- CMOVQEQ R9,DX
- MOVQ CX,R9
- CMOVQEQ R8,CX
- CMOVQEQ R9,R8
- MOVQ SI,64(DI)
- MOVQ DX,144(DI)
- MOVQ CX,72(DI)
- MOVQ R8,152(DI)
- MOVQ DI,AX
- MOVQ SI,DX
+ SUBQ $1, SI
+ NOTQ SI
+ MOVQ SI, X15
+ PSHUFD $0x44, X15, X15
+
+ MOVOU 0(DI), X0
+ MOVOU 16(DI), X2
+ MOVOU 32(DI), X4
+ MOVOU 48(DI), X6
+ MOVOU 64(DI), X8
+ MOVOU 80(DI), X1
+ MOVOU 96(DI), X3
+ MOVOU 112(DI), X5
+ MOVOU 128(DI), X7
+ MOVOU 144(DI), X9
+
+ MOVO X1, X10
+ MOVO X3, X11
+ MOVO X5, X12
+ MOVO X7, X13
+ MOVO X9, X14
+
+ PXOR X0, X10
+ PXOR X2, X11
+ PXOR X4, X12
+ PXOR X6, X13
+ PXOR X8, X14
+ PAND X15, X10
+ PAND X15, X11
+ PAND X15, X12
+ PAND X15, X13
+ PAND X15, X14
+ PXOR X10, X0
+ PXOR X10, X1
+ PXOR X11, X2
+ PXOR X11, X3
+ PXOR X12, X4
+ PXOR X12, X5
+ PXOR X13, X6
+ PXOR X13, X7
+ PXOR X14, X8
+ PXOR X14, X9
+
+ MOVOU X0, 0(DI)
+ MOVOU X2, 16(DI)
+ MOVOU X4, 32(DI)
+ MOVOU X6, 48(DI)
+ MOVOU X8, 64(DI)
+ MOVOU X1, 80(DI)
+ MOVOU X3, 96(DI)
+ MOVOU X5, 112(DI)
+ MOVOU X7, 128(DI)
+ MOVOU X9, 144(DI)
RET
diff --git a/vendor/golang.org/x/crypto/curve25519/curve25519.go b/vendor/golang.org/x/crypto/curve25519/curve25519.go
index 6918c47fc..2d14c2a78 100644
--- a/vendor/golang.org/x/crypto/curve25519/curve25519.go
+++ b/vendor/golang.org/x/crypto/curve25519/curve25519.go
@@ -8,6 +8,10 @@
package curve25519
+import (
+ "encoding/binary"
+)
+
// This code is a port of the public domain, "ref10" implementation of
// curve25519 from SUPERCOP 20130419 by D. J. Bernstein.
@@ -50,17 +54,11 @@ func feCopy(dst, src *fieldElement) {
//
// Preconditions: b in {0,1}.
func feCSwap(f, g *fieldElement, b int32) {
- var x fieldElement
b = -b
- for i := range x {
- x[i] = b & (f[i] ^ g[i])
- }
-
for i := range f {
- f[i] ^= x[i]
- }
- for i := range g {
- g[i] ^= x[i]
+ t := b & (f[i] ^ g[i])
+ f[i] ^= t
+ g[i] ^= t
}
}
@@ -75,12 +73,7 @@ func load3(in []byte) int64 {
// load4 reads a 32-bit, little-endian value from in.
func load4(in []byte) int64 {
- var r int64
- r = int64(in[0])
- r |= int64(in[1]) << 8
- r |= int64(in[2]) << 16
- r |= int64(in[3]) << 24
- return r
+ return int64(binary.LittleEndian.Uint32(in))
}
func feFromBytes(dst *fieldElement, src *[32]byte) {
diff --git a/vendor/golang.org/x/crypto/ssh/certs.go b/vendor/golang.org/x/crypto/ssh/certs.go
index 6331c94d5..67600e240 100644
--- a/vendor/golang.org/x/crypto/ssh/certs.go
+++ b/vendor/golang.org/x/crypto/ssh/certs.go
@@ -268,7 +268,7 @@ type CertChecker struct {
// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
// public key that is not a certificate. It must implement host key
// validation or else, if nil, all such keys are rejected.
- HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
+ HostKeyFallback HostKeyCallback
// IsRevoked is called for each certificate so that revocation checking
// can be implemented. It should return true if the given certificate
diff --git a/vendor/golang.org/x/crypto/ssh/client.go b/vendor/golang.org/x/crypto/ssh/client.go
index c97f2978e..a7e3263bc 100644
--- a/vendor/golang.org/x/crypto/ssh/client.go
+++ b/vendor/golang.org/x/crypto/ssh/client.go
@@ -5,6 +5,7 @@
package ssh
import (
+ "bytes"
"errors"
"fmt"
"net"
@@ -13,7 +14,7 @@ import (
)
// Client implements a traditional SSH client that supports shells,
-// subprocesses, port forwarding and tunneled dialing.
+// subprocesses, TCP port/streamlocal forwarding and tunneled dialing.
type Client struct {
Conn
@@ -59,6 +60,7 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
conn.forwards.closeAll()
}()
go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-tcpip"))
+ go conn.forwards.handleChannels(conn.HandleChannelOpen("forwarded-streamlocal@openssh.com"))
return conn
}
@@ -68,6 +70,11 @@ func NewClient(c Conn, chans <-chan NewChannel, reqs <-chan *Request) *Client {
func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
fullConf := *config
fullConf.SetDefaults()
+ if fullConf.HostKeyCallback == nil {
+ c.Close()
+ return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
+ }
+
conn := &connection{
sshConn: sshConn{conn: c},
}
@@ -173,6 +180,13 @@ func Dial(network, addr string, config *ClientConfig) (*Client, error) {
return NewClient(c, chans, reqs), nil
}
+// HostKeyCallback is the function type used for verifying server
+// keys. A HostKeyCallback must return nil if the host key is OK, or
+// an error to reject it. It receives the hostname as passed to Dial
+// or NewClientConn. The remote address is the RemoteAddr of the
+// net.Conn underlying the the SSH connection.
+type HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+
// A ClientConfig structure is used to configure a Client. It must not be
// modified after having been passed to an SSH function.
type ClientConfig struct {
@@ -188,10 +202,12 @@ type ClientConfig struct {
// be used during authentication.
Auth []AuthMethod
- // HostKeyCallback, if not nil, is called during the cryptographic
- // handshake to validate the server's host key. A nil HostKeyCallback
- // implies that all host keys are accepted.
- HostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+ // HostKeyCallback is called during the cryptographic
+ // handshake to validate the server's host key. The client
+ // configuration must supply this callback for the connection
+ // to succeed. The functions InsecureIgnoreHostKey or
+ // FixedHostKey can be used for simplistic host key checks.
+ HostKeyCallback HostKeyCallback
// ClientVersion contains the version identification string that will
// be used for the connection. If empty, a reasonable default is used.
@@ -209,3 +225,33 @@ type ClientConfig struct {
// A Timeout of zero means no timeout.
Timeout time.Duration
}
+
+// InsecureIgnoreHostKey returns a function that can be used for
+// ClientConfig.HostKeyCallback to accept any host key. It should
+// not be used for production code.
+func InsecureIgnoreHostKey() HostKeyCallback {
+ return func(hostname string, remote net.Addr, key PublicKey) error {
+ return nil
+ }
+}
+
+type fixedHostKey struct {
+ key PublicKey
+}
+
+func (f *fixedHostKey) check(hostname string, remote net.Addr, key PublicKey) error {
+ if f.key == nil {
+ return fmt.Errorf("ssh: required host key was nil")
+ }
+ if !bytes.Equal(key.Marshal(), f.key.Marshal()) {
+ return fmt.Errorf("ssh: host key mismatch")
+ }
+ return nil
+}
+
+// FixedHostKey returns a function for use in
+// ClientConfig.HostKeyCallback to accept only a specific host key.
+func FixedHostKey(key PublicKey) HostKeyCallback {
+ hk := &fixedHostKey{key}
+ return hk.check
+}
diff --git a/vendor/golang.org/x/crypto/ssh/client_auth.go b/vendor/golang.org/x/crypto/ssh/client_auth.go
index fd1ec5dda..b882da086 100644
--- a/vendor/golang.org/x/crypto/ssh/client_auth.go
+++ b/vendor/golang.org/x/crypto/ssh/client_auth.go
@@ -179,31 +179,26 @@ func (cb publicKeyCallback) method() string {
}
func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand io.Reader) (bool, []string, error) {
- // Authentication is performed in two stages. The first stage sends an
- // enquiry to test if each key is acceptable to the remote. The second
- // stage attempts to authenticate with the valid keys obtained in the
- // first stage.
+ // Authentication is performed by sending an enquiry to test if a key is
+ // acceptable to the remote. If the key is acceptable, the client will
+ // attempt to authenticate with the valid key. If not the client will repeat
+ // the process with the remaining keys.
signers, err := cb()
if err != nil {
return false, nil, err
}
- var validKeys []Signer
+ var methods []string
for _, signer := range signers {
- if ok, err := validateKey(signer.PublicKey(), user, c); ok {
- validKeys = append(validKeys, signer)
- } else {
- if err != nil {
- return false, nil, err
- }
+ ok, err := validateKey(signer.PublicKey(), user, c)
+ if err != nil {
+ return false, nil, err
+ }
+ if !ok {
+ continue
}
- }
- // methods that may continue if this auth is not successful.
- var methods []string
- for _, signer := range validKeys {
pub := signer.PublicKey()
-
pubKey := pub.Marshal()
sign, err := signer.Sign(rand, buildDataSignedForAuth(session, userAuthRequestMsg{
User: user,
@@ -236,13 +231,29 @@ func (cb publicKeyCallback) auth(session []byte, user string, c packetConn, rand
if err != nil {
return false, nil, err
}
- if success {
+
+ // If authentication succeeds or the list of available methods does not
+ // contain the "publickey" method, do not attempt to authenticate with any
+ // other keys. According to RFC 4252 Section 7, the latter can occur when
+ // additional authentication methods are required.
+ if success || !containsMethod(methods, cb.method()) {
return success, methods, err
}
}
+
return false, methods, nil
}
+func containsMethod(methods []string, method string) bool {
+ for _, m := range methods {
+ if m == method {
+ return true
+ }
+ }
+
+ return false
+}
+
// validateKey validates the key provided is acceptable to the server.
func validateKey(key PublicKey, user string, c packetConn) (bool, error) {
pubKey := key.Marshal()
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index 8656d0f85..dc39e4d23 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -9,6 +9,7 @@ import (
"crypto/rand"
"fmt"
"io"
+ "math"
"sync"
_ "crypto/sha1"
@@ -40,7 +41,7 @@ var supportedKexAlgos = []string{
kexAlgoDH14SHA1, kexAlgoDH1SHA1,
}
-// supportedKexAlgos specifies the supported host-key algorithms (i.e. methods
+// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
// of authenticating servers) in preference order.
var supportedHostKeyAlgos = []string{
CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01,
@@ -186,7 +187,7 @@ type Config struct {
// The maximum number of bytes sent or received after which a
// new key is negotiated. It must be at least 256. If
- // unspecified, 1 gigabyte is used.
+ // unspecified, a size suitable for the chosen cipher is used.
RekeyThreshold uint64
// The allowed key exchanges algorithms. If unspecified then a
@@ -230,11 +231,12 @@ func (c *Config) SetDefaults() {
}
if c.RekeyThreshold == 0 {
- // RFC 4253, section 9 suggests rekeying after 1G.
- c.RekeyThreshold = 1 << 30
- }
- if c.RekeyThreshold < minRekeyThreshold {
+ // cipher specific default
+ } else if c.RekeyThreshold < minRekeyThreshold {
c.RekeyThreshold = minRekeyThreshold
+ } else if c.RekeyThreshold >= math.MaxInt64 {
+ // Avoid weirdness if somebody uses -1 as a threshold.
+ c.RekeyThreshold = math.MaxInt64
}
}
diff --git a/vendor/golang.org/x/crypto/ssh/doc.go b/vendor/golang.org/x/crypto/ssh/doc.go
index d6be89466..67b7322c0 100644
--- a/vendor/golang.org/x/crypto/ssh/doc.go
+++ b/vendor/golang.org/x/crypto/ssh/doc.go
@@ -14,5 +14,8 @@ others.
References:
[PROTOCOL.certkeys]: http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.certkeys?rev=HEAD
[SSH-PARAMETERS]: http://www.iana.org/assignments/ssh-parameters/ssh-parameters.xml#ssh-parameters-1
+
+This package does not fall under the stability promise of the Go language itself,
+so its API may be changed when pressing needs arise.
*/
package ssh // import "golang.org/x/crypto/ssh"
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
index 8de650644..932ce8393 100644
--- a/vendor/golang.org/x/crypto/ssh/handshake.go
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -74,7 +74,7 @@ type handshakeTransport struct {
startKex chan *pendingKex
// data for host key checking
- hostKeyCallback func(hostname string, remote net.Addr, key PublicKey) error
+ hostKeyCallback HostKeyCallback
dialAddress string
remoteAddr net.Addr
@@ -107,6 +107,8 @@ func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion,
config: config,
}
+ t.resetReadThresholds()
+ t.resetWriteThresholds()
// We always start with a mandatory key exchange.
t.requestKex <- struct{}{}
@@ -237,6 +239,17 @@ func (t *handshakeTransport) requestKeyExchange() {
}
}
+func (t *handshakeTransport) resetWriteThresholds() {
+ t.writePacketsLeft = packetRekeyThreshold
+ if t.config.RekeyThreshold > 0 {
+ t.writeBytesLeft = int64(t.config.RekeyThreshold)
+ } else if t.algorithms != nil {
+ t.writeBytesLeft = t.algorithms.w.rekeyBytes()
+ } else {
+ t.writeBytesLeft = 1 << 30
+ }
+}
+
func (t *handshakeTransport) kexLoop() {
write:
@@ -285,12 +298,8 @@ write:
t.writeError = err
t.sentInitPacket = nil
t.sentInitMsg = nil
- t.writePacketsLeft = packetRekeyThreshold
- if t.config.RekeyThreshold > 0 {
- t.writeBytesLeft = int64(t.config.RekeyThreshold)
- } else if t.algorithms != nil {
- t.writeBytesLeft = t.algorithms.w.rekeyBytes()
- }
+
+ t.resetWriteThresholds()
// we have completed the key exchange. Since the
// reader is still blocked, it is safe to clear out
@@ -344,6 +353,17 @@ write:
// key exchange itself.
const packetRekeyThreshold = (1 << 31)
+func (t *handshakeTransport) resetReadThresholds() {
+ t.readPacketsLeft = packetRekeyThreshold
+ if t.config.RekeyThreshold > 0 {
+ t.readBytesLeft = int64(t.config.RekeyThreshold)
+ } else if t.algorithms != nil {
+ t.readBytesLeft = t.algorithms.r.rekeyBytes()
+ } else {
+ t.readBytesLeft = 1 << 30
+ }
+}
+
func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
p, err := t.conn.readPacket()
if err != nil {
@@ -391,12 +411,7 @@ func (t *handshakeTransport) readOnePacket(first bool) ([]byte, error) {
return nil, err
}
- t.readPacketsLeft = packetRekeyThreshold
- if t.config.RekeyThreshold > 0 {
- t.readBytesLeft = int64(t.config.RekeyThreshold)
- } else {
- t.readBytesLeft = t.algorithms.r.rekeyBytes()
- }
+ t.resetReadThresholds()
// By default, a key exchange is hidden from higher layers by
// translating it into msgIgnore.
@@ -574,7 +589,9 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
}
result.SessionID = t.sessionID
- t.conn.prepareKeyChange(t.algorithms, result)
+ if err := t.conn.prepareKeyChange(t.algorithms, result); err != nil {
+ return err
+ }
if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
return err
}
@@ -614,11 +631,9 @@ func (t *handshakeTransport) client(kex kexAlgorithm, algs *algorithms, magics *
return nil, err
}
- if t.hostKeyCallback != nil {
- err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
- if err != nil {
- return nil, err
- }
+ err = t.hostKeyCallback(t.dialAddress, t.remoteAddr, hostKey)
+ if err != nil {
+ return nil, err
}
return result, nil
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go
index f38de9898..cf6853232 100644
--- a/vendor/golang.org/x/crypto/ssh/keys.go
+++ b/vendor/golang.org/x/crypto/ssh/keys.go
@@ -824,7 +824,7 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
// Implemented based on the documentation at
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
-func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
+func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) {
magic := append([]byte("openssh-key-v1"), 0)
if !bytes.Equal(magic, key[0:len(magic)]) {
return nil, errors.New("ssh: invalid openssh private key format")
@@ -844,14 +844,15 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
return nil, err
}
+ if w.KdfName != "none" || w.CipherName != "none" {
+ return nil, errors.New("ssh: cannot decode encrypted private keys")
+ }
+
pk1 := struct {
Check1 uint32
Check2 uint32
Keytype string
- Pub []byte
- Priv []byte
- Comment string
- Pad []byte `ssh:"rest"`
+ Rest []byte `ssh:"rest"`
}{}
if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil {
@@ -862,24 +863,75 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
return nil, errors.New("ssh: checkint mismatch")
}
- // we only handle ed25519 keys currently
- if pk1.Keytype != KeyAlgoED25519 {
- return nil, errors.New("ssh: unhandled key type")
- }
+ // we only handle ed25519 and rsa keys currently
+ switch pk1.Keytype {
+ case KeyAlgoRSA:
+ // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773
+ key := struct {
+ N *big.Int
+ E *big.Int
+ D *big.Int
+ Iqmp *big.Int
+ P *big.Int
+ Q *big.Int
+ Comment string
+ Pad []byte `ssh:"rest"`
+ }{}
+
+ if err := Unmarshal(pk1.Rest, &key); err != nil {
+ return nil, err
+ }
- for i, b := range pk1.Pad {
- if int(b) != i+1 {
- return nil, errors.New("ssh: padding not as expected")
+ for i, b := range key.Pad {
+ if int(b) != i+1 {
+ return nil, errors.New("ssh: padding not as expected")
+ }
}
- }
- if len(pk1.Priv) != ed25519.PrivateKeySize {
- return nil, errors.New("ssh: private key unexpected length")
- }
+ pk := &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: key.N,
+ E: int(key.E.Int64()),
+ },
+ D: key.D,
+ Primes: []*big.Int{key.P, key.Q},
+ }
- pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
- copy(pk, pk1.Priv)
- return &pk, nil
+ if err := pk.Validate(); err != nil {
+ return nil, err
+ }
+
+ pk.Precompute()
+
+ return pk, nil
+ case KeyAlgoED25519:
+ key := struct {
+ Pub []byte
+ Priv []byte
+ Comment string
+ Pad []byte `ssh:"rest"`
+ }{}
+
+ if err := Unmarshal(pk1.Rest, &key); err != nil {
+ return nil, err
+ }
+
+ if len(key.Priv) != ed25519.PrivateKeySize {
+ return nil, errors.New("ssh: private key unexpected length")
+ }
+
+ for i, b := range key.Pad {
+ if int(b) != i+1 {
+ return nil, errors.New("ssh: padding not as expected")
+ }
+ }
+
+ pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
+ copy(pk, key.Priv)
+ return &pk, nil
+ default:
+ return nil, errors.New("ssh: unhandled key type")
+ }
}
// FingerprintLegacyMD5 returns the user presentation of the key's
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
index 77c84d165..8e95acc6a 100644
--- a/vendor/golang.org/x/crypto/ssh/server.go
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -45,6 +45,12 @@ type ServerConfig struct {
// authenticating.
NoClientAuth bool
+ // MaxAuthTries specifies the maximum number of authentication attempts
+ // permitted per connection. If set to a negative number, the number of
+ // attempts are unlimited. If set to zero, the number of attempts are limited
+ // to 6.
+ MaxAuthTries int
+
// PasswordCallback, if non-nil, is called when a user
// attempts to authenticate using a password.
PasswordCallback func(conn ConnMetadata, password []byte) (*Permissions, error)
@@ -141,6 +147,10 @@ type ServerConn struct {
// Request and NewChannel channels must be serviced, or the connection
// will hang.
func NewServerConn(c net.Conn, config *ServerConfig) (*ServerConn, <-chan NewChannel, <-chan *Request, error) {
+ if config.MaxAuthTries == 0 {
+ config.MaxAuthTries = 6
+ }
+
fullConf := *config
fullConf.SetDefaults()
s := &connection{
@@ -267,8 +277,23 @@ func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, err
var cache pubKeyCache
var perms *Permissions
+ authFailures := 0
+
userAuthLoop:
for {
+ if authFailures >= config.MaxAuthTries && config.MaxAuthTries > 0 {
+ discMsg := &disconnectMsg{
+ Reason: 2,
+ Message: "too many authentication failures",
+ }
+
+ if err := s.transport.writePacket(Marshal(discMsg)); err != nil {
+ return nil, err
+ }
+
+ return nil, discMsg
+ }
+
var userAuthReq userAuthRequestMsg
if packet, err := s.transport.readPacket(); err != nil {
return nil, err
@@ -289,6 +314,11 @@ userAuthLoop:
if config.NoClientAuth {
authErr = nil
}
+
+ // allow initial attempt of 'none' without penalty
+ if authFailures == 0 {
+ authFailures--
+ }
case "password":
if config.PasswordCallback == nil {
authErr = errors.New("ssh: password auth not configured")
@@ -360,6 +390,7 @@ userAuthLoop:
if isQuery {
// The client can query if the given public key
// would be okay.
+
if len(payload) > 0 {
return nil, parseError(msgUserAuthRequest)
}
@@ -409,6 +440,8 @@ userAuthLoop:
break userAuthLoop
}
+ authFailures++
+
var failureMsg userAuthFailureMsg
if config.PasswordCallback != nil {
failureMsg.Methods = append(failureMsg.Methods, "password")
diff --git a/vendor/golang.org/x/crypto/ssh/streamlocal.go b/vendor/golang.org/x/crypto/ssh/streamlocal.go
new file mode 100644
index 000000000..a2dccc64c
--- /dev/null
+++ b/vendor/golang.org/x/crypto/ssh/streamlocal.go
@@ -0,0 +1,115 @@
+package ssh
+
+import (
+ "errors"
+ "io"
+ "net"
+)
+
+// streamLocalChannelOpenDirectMsg is a struct used for SSH_MSG_CHANNEL_OPEN message
+// with "direct-streamlocal@openssh.com" string.
+//
+// See openssh-portable/PROTOCOL, section 2.4. connection: Unix domain socket forwarding
+// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL#L235
+type streamLocalChannelOpenDirectMsg struct {
+ socketPath string
+ reserved0 string
+ reserved1 uint32
+}
+
+// forwardedStreamLocalPayload is a struct used for SSH_MSG_CHANNEL_OPEN message
+// with "forwarded-streamlocal@openssh.com" string.
+type forwardedStreamLocalPayload struct {
+ SocketPath string
+ Reserved0 string
+}
+
+// streamLocalChannelForwardMsg is a struct used for SSH2_MSG_GLOBAL_REQUEST message
+// with "streamlocal-forward@openssh.com"/"cancel-streamlocal-forward@openssh.com" string.
+type streamLocalChannelForwardMsg struct {
+ socketPath string
+}
+
+// ListenUnix is similar to ListenTCP but uses a Unix domain socket.
+func (c *Client) ListenUnix(socketPath string) (net.Listener, error) {
+ m := streamLocalChannelForwardMsg{
+ socketPath,
+ }
+ // send message
+ ok, _, err := c.SendRequest("streamlocal-forward@openssh.com", true, Marshal(&m))
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ return nil, errors.New("ssh: streamlocal-forward@openssh.com request denied by peer")
+ }
+ ch := c.forwards.add(&net.UnixAddr{Name: socketPath, Net: "unix"})
+
+ return &unixListener{socketPath, c, ch}, nil
+}
+
+func (c *Client) dialStreamLocal(socketPath string) (Channel, error) {
+ msg := streamLocalChannelOpenDirectMsg{
+ socketPath: socketPath,
+ }
+ ch, in, err := c.OpenChannel("direct-streamlocal@openssh.com", Marshal(&msg))
+ if err != nil {
+ return nil, err
+ }
+ go DiscardRequests(in)
+ return ch, err
+}
+
+type unixListener struct {
+ socketPath string
+
+ conn *Client
+ in <-chan forward
+}
+
+// Accept waits for and returns the next connection to the listener.
+func (l *unixListener) Accept() (net.Conn, error) {
+ s, ok := <-l.in
+ if !ok {
+ return nil, io.EOF
+ }
+ ch, incoming, err := s.newCh.Accept()
+ if err != nil {
+ return nil, err
+ }
+ go DiscardRequests(incoming)
+
+ return &chanConn{
+ Channel: ch,
+ laddr: &net.UnixAddr{
+ Name: l.socketPath,
+ Net: "unix",
+ },
+ raddr: &net.UnixAddr{
+ Name: "@",
+ Net: "unix",
+ },
+ }, nil
+}
+
+// Close closes the listener.
+func (l *unixListener) Close() error {
+ // this also closes the listener.
+ l.conn.forwards.remove(&net.UnixAddr{Name: l.socketPath, Net: "unix"})
+ m := streamLocalChannelForwardMsg{
+ l.socketPath,
+ }
+ ok, _, err := l.conn.SendRequest("cancel-streamlocal-forward@openssh.com", true, Marshal(&m))
+ if err == nil && !ok {
+ err = errors.New("ssh: cancel-streamlocal-forward@openssh.com failed")
+ }
+ return err
+}
+
+// Addr returns the listener's network address.
+func (l *unixListener) Addr() net.Addr {
+ return &net.UnixAddr{
+ Name: l.socketPath,
+ Net: "unix",
+ }
+}
diff --git a/vendor/golang.org/x/crypto/ssh/tcpip.go b/vendor/golang.org/x/crypto/ssh/tcpip.go
index 6151241ff..acf17175d 100644
--- a/vendor/golang.org/x/crypto/ssh/tcpip.go
+++ b/vendor/golang.org/x/crypto/ssh/tcpip.go
@@ -20,12 +20,20 @@ import (
// addr. Incoming connections will be available by calling Accept on
// the returned net.Listener. The listener must be serviced, or the
// SSH connection may hang.
+// N must be "tcp", "tcp4", "tcp6", or "unix".
func (c *Client) Listen(n, addr string) (net.Listener, error) {
- laddr, err := net.ResolveTCPAddr(n, addr)
- if err != nil {
- return nil, err
+ switch n {
+ case "tcp", "tcp4", "tcp6":
+ laddr, err := net.ResolveTCPAddr(n, addr)
+ if err != nil {
+ return nil, err
+ }
+ return c.ListenTCP(laddr)
+ case "unix":
+ return c.ListenUnix(addr)
+ default:
+ return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
}
- return c.ListenTCP(laddr)
}
// Automatic port allocation is broken with OpenSSH before 6.0. See
@@ -116,7 +124,7 @@ func (c *Client) ListenTCP(laddr *net.TCPAddr) (net.Listener, error) {
}
// Register this forward, using the port number we obtained.
- ch := c.forwards.add(*laddr)
+ ch := c.forwards.add(laddr)
return &tcpListener{laddr, c, ch}, nil
}
@@ -131,7 +139,7 @@ type forwardList struct {
// forwardEntry represents an established mapping of a laddr on a
// remote ssh server to a channel connected to a tcpListener.
type forwardEntry struct {
- laddr net.TCPAddr
+ laddr net.Addr
c chan forward
}
@@ -139,16 +147,16 @@ type forwardEntry struct {
// arguments to add/remove/lookup should be address as specified in
// the original forward-request.
type forward struct {
- newCh NewChannel // the ssh client channel underlying this forward
- raddr *net.TCPAddr // the raddr of the incoming connection
+ newCh NewChannel // the ssh client channel underlying this forward
+ raddr net.Addr // the raddr of the incoming connection
}
-func (l *forwardList) add(addr net.TCPAddr) chan forward {
+func (l *forwardList) add(addr net.Addr) chan forward {
l.Lock()
defer l.Unlock()
f := forwardEntry{
- addr,
- make(chan forward, 1),
+ laddr: addr,
+ c: make(chan forward, 1),
}
l.entries = append(l.entries, f)
return f.c
@@ -176,44 +184,69 @@ func parseTCPAddr(addr string, port uint32) (*net.TCPAddr, error) {
func (l *forwardList) handleChannels(in <-chan NewChannel) {
for ch := range in {
- var payload forwardedTCPPayload
- if err := Unmarshal(ch.ExtraData(), &payload); err != nil {
- ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
- continue
+ var (
+ laddr net.Addr
+ raddr net.Addr
+ err error
+ )
+ switch channelType := ch.ChannelType(); channelType {
+ case "forwarded-tcpip":
+ var payload forwardedTCPPayload
+ if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
+ ch.Reject(ConnectionFailed, "could not parse forwarded-tcpip payload: "+err.Error())
+ continue
+ }
+
+ // RFC 4254 section 7.2 specifies that incoming
+ // addresses should list the address, in string
+ // format. It is implied that this should be an IP
+ // address, as it would be impossible to connect to it
+ // otherwise.
+ laddr, err = parseTCPAddr(payload.Addr, payload.Port)
+ if err != nil {
+ ch.Reject(ConnectionFailed, err.Error())
+ continue
+ }
+ raddr, err = parseTCPAddr(payload.OriginAddr, payload.OriginPort)
+ if err != nil {
+ ch.Reject(ConnectionFailed, err.Error())
+ continue
+ }
+
+ case "forwarded-streamlocal@openssh.com":
+ var payload forwardedStreamLocalPayload
+ if err = Unmarshal(ch.ExtraData(), &payload); err != nil {
+ ch.Reject(ConnectionFailed, "could not parse forwarded-streamlocal@openssh.com payload: "+err.Error())
+ continue
+ }
+ laddr = &net.UnixAddr{
+ Name: payload.SocketPath,
+ Net: "unix",
+ }
+ raddr = &net.UnixAddr{
+ Name: "@",
+ Net: "unix",
+ }
+ default:
+ panic(fmt.Errorf("ssh: unknown channel type %s", channelType))
}
-
- // RFC 4254 section 7.2 specifies that incoming
- // addresses should list the address, in string
- // format. It is implied that this should be an IP
- // address, as it would be impossible to connect to it
- // otherwise.
- laddr, err := parseTCPAddr(payload.Addr, payload.Port)
- if err != nil {
- ch.Reject(ConnectionFailed, err.Error())
- continue
- }
- raddr, err := parseTCPAddr(payload.OriginAddr, payload.OriginPort)
- if err != nil {
- ch.Reject(ConnectionFailed, err.Error())
- continue
- }
-
- if ok := l.forward(*laddr, *raddr, ch); !ok {
+ if ok := l.forward(laddr, raddr, ch); !ok {
// Section 7.2, implementations MUST reject spurious incoming
// connections.
ch.Reject(Prohibited, "no forward for address")
continue
}
+
}
}
// remove removes the forward entry, and the channel feeding its
// listener.
-func (l *forwardList) remove(addr net.TCPAddr) {
+func (l *forwardList) remove(addr net.Addr) {
l.Lock()
defer l.Unlock()
for i, f := range l.entries {
- if addr.IP.Equal(f.laddr.IP) && addr.Port == f.laddr.Port {
+ if addr.Network() == f.laddr.Network() && addr.String() == f.laddr.String() {
l.entries = append(l.entries[:i], l.entries[i+1:]...)
close(f.c)
return
@@ -231,12 +264,12 @@ func (l *forwardList) closeAll() {
l.entries = nil
}
-func (l *forwardList) forward(laddr, raddr net.TCPAddr, ch NewChannel) bool {
+func (l *forwardList) forward(laddr, raddr net.Addr, ch NewChannel) bool {
l.Lock()
defer l.Unlock()
for _, f := range l.entries {
- if laddr.IP.Equal(f.laddr.IP) && laddr.Port == f.laddr.Port {
- f.c <- forward{ch, &raddr}
+ if laddr.Network() == f.laddr.Network() && laddr.String() == f.laddr.String() {
+ f.c <- forward{newCh: ch, raddr: raddr}
return true
}
}
@@ -262,7 +295,7 @@ func (l *tcpListener) Accept() (net.Conn, error) {
}
go DiscardRequests(incoming)
- return &tcpChanConn{
+ return &chanConn{
Channel: ch,
laddr: l.laddr,
raddr: s.raddr,
@@ -277,7 +310,7 @@ func (l *tcpListener) Close() error {
}
// this also closes the listener.
- l.conn.forwards.remove(*l.laddr)
+ l.conn.forwards.remove(l.laddr)
ok, _, err := l.conn.SendRequest("cancel-tcpip-forward", true, Marshal(&m))
if err == nil && !ok {
err = errors.New("ssh: cancel-tcpip-forward failed")
@@ -293,29 +326,52 @@ func (l *tcpListener) Addr() net.Addr {
// Dial initiates a connection to the addr from the remote host.
// The resulting connection has a zero LocalAddr() and RemoteAddr().
func (c *Client) Dial(n, addr string) (net.Conn, error) {
- // Parse the address into host and numeric port.
- host, portString, err := net.SplitHostPort(addr)
- if err != nil {
- return nil, err
- }
- port, err := strconv.ParseUint(portString, 10, 16)
- if err != nil {
- return nil, err
- }
- // Use a zero address for local and remote address.
- zeroAddr := &net.TCPAddr{
- IP: net.IPv4zero,
- Port: 0,
- }
- ch, err := c.dial(net.IPv4zero.String(), 0, host, int(port))
- if err != nil {
- return nil, err
+ var ch Channel
+ switch n {
+ case "tcp", "tcp4", "tcp6":
+ // Parse the address into host and numeric port.
+ host, portString, err := net.SplitHostPort(addr)
+ if err != nil {
+ return nil, err
+ }
+ port, err := strconv.ParseUint(portString, 10, 16)
+ if err != nil {
+ return nil, err
+ }
+ ch, err = c.dial(net.IPv4zero.String(), 0, host, int(port))
+ if err != nil {
+ return nil, err
+ }
+ // Use a zero address for local and remote address.
+ zeroAddr := &net.TCPAddr{
+ IP: net.IPv4zero,
+ Port: 0,
+ }
+ return &chanConn{
+ Channel: ch,
+ laddr: zeroAddr,
+ raddr: zeroAddr,
+ }, nil
+ case "unix":
+ var err error
+ ch, err = c.dialStreamLocal(addr)
+ if err != nil {
+ return nil, err
+ }
+ return &chanConn{
+ Channel: ch,
+ laddr: &net.UnixAddr{
+ Name: "@",
+ Net: "unix",
+ },
+ raddr: &net.UnixAddr{
+ Name: addr,
+ Net: "unix",
+ },
+ }, nil
+ default:
+ return nil, fmt.Errorf("ssh: unsupported protocol: %s", n)
}
- return &tcpChanConn{
- Channel: ch,
- laddr: zeroAddr,
- raddr: zeroAddr,
- }, nil
}
// DialTCP connects to the remote address raddr on the network net,
@@ -332,7 +388,7 @@ func (c *Client) DialTCP(n string, laddr, raddr *net.TCPAddr) (net.Conn, error)
if err != nil {
return nil, err
}
- return &tcpChanConn{
+ return &chanConn{
Channel: ch,
laddr: laddr,
raddr: raddr,
@@ -366,26 +422,26 @@ type tcpChan struct {
Channel // the backing channel
}
-// tcpChanConn fulfills the net.Conn interface without
+// chanConn fulfills the net.Conn interface without
// the tcpChan having to hold laddr or raddr directly.
-type tcpChanConn struct {
+type chanConn struct {
Channel
laddr, raddr net.Addr
}
// LocalAddr returns the local network address.
-func (t *tcpChanConn) LocalAddr() net.Addr {
+func (t *chanConn) LocalAddr() net.Addr {
return t.laddr
}
// RemoteAddr returns the remote network address.
-func (t *tcpChanConn) RemoteAddr() net.Addr {
+func (t *chanConn) RemoteAddr() net.Addr {
return t.raddr
}
// SetDeadline sets the read and write deadlines associated
// with the connection.
-func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
+func (t *chanConn) SetDeadline(deadline time.Time) error {
if err := t.SetReadDeadline(deadline); err != nil {
return err
}
@@ -396,12 +452,14 @@ func (t *tcpChanConn) SetDeadline(deadline time.Time) error {
// A zero value for t means Read will not time out.
// After the deadline, the error from Read will implement net.Error
// with Timeout() == true.
-func (t *tcpChanConn) SetReadDeadline(deadline time.Time) error {
+func (t *chanConn) SetReadDeadline(deadline time.Time) error {
+ // for compatibility with previous version,
+ // the error message contains "tcpChan"
return errors.New("ssh: tcpChan: deadline not supported")
}
// SetWriteDeadline exists to satisfy the net.Conn interface
// but is not implemented by this type. It always returns an error.
-func (t *tcpChanConn) SetWriteDeadline(deadline time.Time) error {
+func (t *chanConn) SetWriteDeadline(deadline time.Time) error {
return errors.New("ssh: tcpChan: deadline not supported")
}
diff --git a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
index 07eb5edd7..a2e1b57dc 100644
--- a/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
+++ b/vendor/golang.org/x/crypto/ssh/terminal/util_solaris.go
@@ -14,14 +14,12 @@ import (
// State contains the state of a terminal.
type State struct {
- termios syscall.Termios
+ state *unix.Termios
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd int) bool {
- // see: http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libbc/libc/gen/common/isatty.c
- var termio unix.Termio
- err := unix.IoctlSetTermio(fd, unix.TCGETA, &termio)
+ _, err := unix.IoctlGetTermio(fd, unix.TCGETA)
return err == nil
}
@@ -71,3 +69,60 @@ func ReadPassword(fd int) ([]byte, error) {
return ret, nil
}
+
+// MakeRaw puts the terminal connected to the given file descriptor into raw
+// mode and returns the previous state of the terminal so that it can be
+// restored.
+// see http://cr.illumos.org/~webrev/andy_js/1060/
+func MakeRaw(fd int) (*State, error) {
+ oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+ if err != nil {
+ return nil, err
+ }
+ oldTermios := *oldTermiosPtr
+
+ newTermios := oldTermios
+ newTermios.Iflag &^= syscall.IGNBRK | syscall.BRKINT | syscall.PARMRK | syscall.ISTRIP | syscall.INLCR | syscall.IGNCR | syscall.ICRNL | syscall.IXON
+ newTermios.Oflag &^= syscall.OPOST
+ newTermios.Lflag &^= syscall.ECHO | syscall.ECHONL | syscall.ICANON | syscall.ISIG | syscall.IEXTEN
+ newTermios.Cflag &^= syscall.CSIZE | syscall.PARENB
+ newTermios.Cflag |= syscall.CS8
+ newTermios.Cc[unix.VMIN] = 1
+ newTermios.Cc[unix.VTIME] = 0
+
+ if err := unix.IoctlSetTermios(fd, unix.TCSETS, &newTermios); err != nil {
+ return nil, err
+ }
+
+ return &State{
+ state: oldTermiosPtr,
+ }, nil
+}
+
+// Restore restores the terminal connected to the given file descriptor to a
+// previous state.
+func Restore(fd int, oldState *State) error {
+ return unix.IoctlSetTermios(fd, unix.TCSETS, oldState.state)
+}
+
+// GetState returns the current state of a terminal which may be useful to
+// restore the terminal after a signal.
+func GetState(fd int) (*State, error) {
+ oldTermiosPtr, err := unix.IoctlGetTermios(fd, unix.TCGETS)
+ if err != nil {
+ return nil, err
+ }
+
+ return &State{
+ state: oldTermiosPtr,
+ }, nil
+}
+
+// GetSize returns the dimensions of the given terminal.
+func GetSize(fd int) (width, height int, err error) {
+ ws, err := unix.IoctlGetWinsize(fd, unix.TIOCGWINSZ)
+ if err != nil {
+ return 0, 0, err
+ }
+ return int(ws.Col), int(ws.Row), nil
+}
diff --git a/vendor/vendor.json b/vendor/vendor.json
index d79c80a67..607f193a3 100644
--- a/vendor/vendor.json
+++ b/vendor/vendor.json
@@ -384,92 +384,92 @@
{
"checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=",
"path": "golang.org/x/crypto/cast5",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
- "checksumSHA1": "C1KKOxFoW7/W/NFNpiXK+boguNo=",
+ "checksumSHA1": "nAu0XmCeC6WnUySyI8R7w4cxAqU=",
"path": "golang.org/x/crypto/curve25519",
- "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
- "revisionTime": "2017-03-17T13:29:17Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "wGb//LjBPNxYHqk+dcLo7BjPXK8=",
"path": "golang.org/x/crypto/ed25519",
- "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
- "revisionTime": "2017-03-17T13:29:17Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "LXFcVx8I587SnWmKycSDEq9yvK8=",
"path": "golang.org/x/crypto/ed25519/internal/edwards25519",
- "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
- "revisionTime": "2017-03-17T13:29:17Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "IIhFTrLlmlc6lEFSitqi4aw2lw0=",
"path": "golang.org/x/crypto/openpgp",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "olOKkhrdkYQHZ0lf1orrFQPQrv4=",
"path": "golang.org/x/crypto/openpgp/armor",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "eo/KtdjieJQXH7Qy+faXFcF70ME=",
"path": "golang.org/x/crypto/openpgp/elgamal",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "rlxVSaGgqdAgwblsErxTxIfuGfg=",
"path": "golang.org/x/crypto/openpgp/errors",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "LWdaR8Q9yn6eBCcnGl0HvJRDUBE=",
"path": "golang.org/x/crypto/openpgp/packet",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "s2qT4UwvzBSkzXuiuMkowif1Olw=",
"path": "golang.org/x/crypto/openpgp/s2k",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=",
"path": "golang.org/x/crypto/pbkdf2",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "y/oIaxq2d3WPizRZfVjo8RCRYTU=",
"path": "golang.org/x/crypto/ripemd160",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "E8pDMGySfy5Mw+jzXOkOxo35bww=",
"path": "golang.org/x/crypto/scrypt",
- "revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
- "revisionTime": "2017-02-08T20:51:15Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
- "checksumSHA1": "fsrFs762jlaILyqqQImS1GfvIvw=",
+ "checksumSHA1": "8sVsMTphul+B0sI0qAv4TE1ZxUk=",
"path": "golang.org/x/crypto/ssh",
- "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
- "revisionTime": "2017-03-17T13:29:17Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
- "checksumSHA1": "xiderUuvye8Kpn7yX3niiJg32bE=",
+ "checksumSHA1": "ZaU56svwLgiJD0y8JOB3+/mpYBA=",
"path": "golang.org/x/crypto/ssh/terminal",
- "revision": "459e26527287adbc2adcc5d0d49abff9a5f315a7",
- "revisionTime": "2017-03-17T13:29:17Z"
+ "revision": "c7af5bf2638a1164f2eb5467c39c6cffbd13a02e",
+ "revisionTime": "2017-04-25T18:31:00Z"
},
{
"checksumSHA1": "Y+HGqEkYM15ir+J93MEaHdyFy0c=",
diff --git a/whisper/mailserver/server_test.go b/whisper/mailserver/server_test.go
index 15652ea4a..64dbcd783 100644
--- a/whisper/mailserver/server_test.go
+++ b/whisper/mailserver/server_test.go
@@ -58,15 +58,19 @@ func TestDBKey(t *testing.T) {
}
func generateEnvelope(t *testing.T) *whisper.Envelope {
+ h := crypto.Keccak256Hash([]byte("test sample data"))
params := &whisper.MessageParams{
- KeySym: []byte("test key"),
+ KeySym: h[:],
Topic: whisper.TopicType{},
Payload: []byte("test payload"),
PoW: powRequirement,
WorkTime: 2,
}
- msg := whisper.NewSentMessage(params)
+ msg, err := whisper.NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
@@ -188,7 +192,10 @@ func createRequest(t *testing.T, p *ServerTestParams) *whisper.Envelope {
Src: p.key,
}
- msg := whisper.NewSentMessage(params)
+ msg, err := whisper.NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed to wrap with seed %d: %s.", seed, err)
diff --git a/whisper/whisperv5/api.go b/whisper/whisperv5/api.go
index 579efba9e..1a4e4d879 100644
--- a/whisper/whisperv5/api.go
+++ b/whisper/whisperv5/api.go
@@ -214,7 +214,6 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
}
filter := Filter{
- Src: crypto.ToECDSAPub(common.FromHex(args.SignedWith)),
PoW: args.MinPoW,
Messages: make(map[common.Hash]*ReceivedMessage),
AllowP2P: args.AllowP2P,
@@ -232,9 +231,14 @@ func (api *PublicWhisperAPI) Subscribe(args WhisperFilterArgs) (string, error) {
return "", errors.New("subscribe: " + err.Error())
}
- if len(args.SignedWith) > 0 {
+ if len(args.Sig) > 0 {
+ sb := common.FromHex(args.Sig)
+ if sb == nil {
+ return "", errors.New("subscribe: sig parameter is invalid")
+ }
+ filter.Src = crypto.ToECDSAPub(sb)
if !ValidatePublicKey(filter.Src) {
- return "", errors.New("subscribe: invalid 'SignedWith' field")
+ return "", errors.New("subscribe: invalid 'sig' field")
}
}
@@ -269,9 +273,10 @@ func (api *PublicWhisperAPI) Unsubscribe(id string) {
api.whisper.Unsubscribe(id)
}
-// GetSubscriptionMessages retrieves all the new messages matched by a filter since the last retrieval.
-func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*WhisperMessage {
- f := api.whisper.GetFilter(filterId)
+// GetSubscriptionMessages retrieves all the new messages matched by the corresponding
+// subscription filter since the last retrieval.
+func (api *PublicWhisperAPI) GetNewSubscriptionMessages(id string) []*WhisperMessage {
+ f := api.whisper.GetFilter(id)
if f != nil {
newMail := f.Retrieve()
return toWhisperMessages(newMail)
@@ -279,10 +284,10 @@ func (api *PublicWhisperAPI) GetSubscriptionMessages(filterId string) []*Whisper
return toWhisperMessages(nil)
}
-// GetMessages retrieves all the floating messages that match a specific filter.
+// GetMessages retrieves all the floating messages that match a specific subscription filter.
// It is likely to be called once per session, right after Subscribe call.
-func (api *PublicWhisperAPI) GetMessages(filterId string) []*WhisperMessage {
- all := api.whisper.Messages(filterId)
+func (api *PublicWhisperAPI) GetFloatingMessages(id string) []*WhisperMessage {
+ all := api.whisper.Messages(id)
return toWhisperMessages(all)
}
@@ -314,8 +319,8 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
return errors.New("post: key is missing")
}
- if len(args.SignWith) > 0 {
- params.Src, err = api.whisper.GetPrivateKey(args.SignWith)
+ if len(args.Sig) > 0 {
+ params.Src, err = api.whisper.GetPrivateKey(args.Sig)
if err != nil {
return err
}
@@ -345,7 +350,11 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
return errors.New("post: topic is missing for symmetric encryption")
}
} else if args.Type == "asym" {
- params.Dst = crypto.ToECDSAPub(common.FromHex(args.Key))
+ kb := common.FromHex(args.Key)
+ if kb == nil {
+ return errors.New("post: public key for asymmetric encryption is invalid")
+ }
+ params.Dst = crypto.ToECDSAPub(kb)
if !ValidatePublicKey(params.Dst) {
return errors.New("post: public key for asymmetric encryption is invalid")
}
@@ -354,9 +363,9 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
}
// encrypt and send
- message := NewSentMessage(&params)
- if message == nil {
- return errors.New("post: failed create new message, probably due to failed rand function (OS level)")
+ message, err := NewSentMessage(&params)
+ if err != nil {
+ return err
}
envelope, err := message.Wrap(&params)
if err != nil {
@@ -382,8 +391,8 @@ func (api *PublicWhisperAPI) Post(args PostArgs) error {
type PostArgs struct {
Type string `json:"type"` // "sym"/"asym" (symmetric or asymmetric)
TTL uint32 `json:"ttl"` // time-to-live in seconds
- SignWith string `json:"signWith"` // id of the signing key
- Key string `json:"key"` // id of encryption key
+ Sig string `json:"sig"` // id of the signing key
+ Key string `json:"key"` // key id (in case of sym) or public key (in case of asym)
Topic hexutil.Bytes `json:"topic"` // topic (4 bytes)
Padding hexutil.Bytes `json:"padding"` // optional padding bytes
Payload hexutil.Bytes `json:"payload"` // payload to be encrypted
@@ -393,12 +402,12 @@ type PostArgs struct {
}
type WhisperFilterArgs struct {
- Symmetric bool // encryption type
- Key string // id of the key to be used for decryption
- SignedWith string // public key of the sender to be verified
- MinPoW float64 // minimal PoW requirement
- Topics [][]byte // list of topics (up to 4 bytes each) to match
- AllowP2P bool // indicates wheather direct p2p messages are allowed for this filter
+ Symmetric bool // encryption type
+ Key string // id of the key to be used for decryption
+ Sig string // public key of the sender to be verified
+ MinPoW float64 // minimal PoW requirement
+ Topics [][]byte // list of topics (up to 4 bytes each) to match
+ AllowP2P bool // indicates wheather direct p2p messages are allowed for this filter
}
// UnmarshalJSON implements the json.Unmarshaler interface, invoked to convert a
@@ -406,12 +415,12 @@ type WhisperFilterArgs struct {
func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
// Unmarshal the JSON message and sanity check
var obj struct {
- Type string `json:"type"`
- Key string `json:"key"`
- SignedWith string `json:"signedWith"`
- MinPoW float64 `json:"minPoW"`
- Topics []interface{} `json:"topics"`
- AllowP2P bool `json:"allowP2P"`
+ Type string `json:"type"`
+ Key string `json:"key"`
+ Sig string `json:"sig"`
+ MinPoW float64 `json:"minPoW"`
+ Topics []interface{} `json:"topics"`
+ AllowP2P bool `json:"allowP2P"`
}
if err := json.Unmarshal(b, &obj); err != nil {
return err
@@ -427,7 +436,7 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
}
args.Key = obj.Key
- args.SignedWith = obj.SignedWith
+ args.Sig = obj.Sig
args.MinPoW = obj.MinPoW
args.AllowP2P = obj.AllowP2P
@@ -463,7 +472,7 @@ type WhisperMessage struct {
Topic string `json:"topic"`
Payload string `json:"payload"`
Padding string `json:"padding"`
- Src string `json:"signedWith"`
+ Src string `json:"sig"`
Dst string `json:"recipientPublicKey"`
Timestamp uint32 `json:"timestamp"`
TTL uint32 `json:"ttl"`
@@ -474,7 +483,6 @@ type WhisperMessage struct {
// NewWhisperMessage converts an internal message into an API version.
func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
msg := WhisperMessage{
- Topic: common.ToHex(message.Topic[:]),
Payload: common.ToHex(message.Payload),
Padding: common.ToHex(message.Padding),
Timestamp: message.Sent,
@@ -483,11 +491,20 @@ func NewWhisperMessage(message *ReceivedMessage) *WhisperMessage {
Hash: common.ToHex(message.EnvelopeHash.Bytes()),
}
+ if len(message.Topic) == TopicLength {
+ msg.Topic = common.ToHex(message.Topic[:])
+ }
if message.Dst != nil {
- msg.Dst = common.ToHex(crypto.FromECDSAPub(message.Dst))
+ b := crypto.FromECDSAPub(message.Dst)
+ if b != nil {
+ msg.Dst = common.ToHex(b)
+ }
}
if isMessageSigned(message.Raw[0]) {
- msg.Src = common.ToHex(crypto.FromECDSAPub(message.SigToPubKey()))
+ b := crypto.FromECDSAPub(message.SigToPubKey())
+ if b != nil {
+ msg.Src = common.ToHex(b)
+ }
}
return &msg
}
diff --git a/whisper/whisperv5/api_test.go b/whisper/whisperv5/api_test.go
index 9207c6f10..a6d82d850 100644
--- a/whisper/whisperv5/api_test.go
+++ b/whisper/whisperv5/api_test.go
@@ -43,7 +43,7 @@ func TestBasic(t *testing.T) {
t.Fatalf("wrong version: %d.", ver)
}
- mail := api.GetSubscriptionMessages("non-existent-id")
+ mail := api.GetNewSubscriptionMessages("non-existent-id")
if len(mail) != 0 {
t.Fatalf("failed GetFilterChanges: premature result")
}
@@ -173,7 +173,7 @@ func TestUnmarshalFilterArgs(t *testing.T) {
s := []byte(`{
"type":"sym",
"key":"0x70c87d191324e6712a591f304b4eedef6ad9bb9d",
- "signedWith":"0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
+ "sig":"0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
"minPoW":2.34,
"topics":["0x00000000", "0x007f80ff", "0xff807f00", "0xf26e7779"],
"allowP2P":true
@@ -191,8 +191,8 @@ func TestUnmarshalFilterArgs(t *testing.T) {
if f.Key != "0x70c87d191324e6712a591f304b4eedef6ad9bb9d" {
t.Fatalf("wrong key: %s.", f.Key)
}
- if f.SignedWith != "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83" {
- t.Fatalf("wrong SignedWith: %s.", f.SignedWith)
+ if f.Sig != "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83" {
+ t.Fatalf("wrong sig: %s.", f.Sig)
}
if f.MinPoW != 2.34 {
t.Fatalf("wrong MinPoW: %f.", f.MinPoW)
@@ -229,7 +229,7 @@ func TestUnmarshalPostArgs(t *testing.T) {
s := []byte(`{
"type":"sym",
"ttl":12345,
- "signWith":"0x70c87d191324e6712a591f304b4eedef6ad9bb9d",
+ "sig":"0x70c87d191324e6712a591f304b4eedef6ad9bb9d",
"key":"0x9b2055d370f73ec7d8a03e965129118dc8f5bf83",
"topic":"0xf26e7779",
"padding":"0x74686973206973206D79207465737420737472696E67",
@@ -251,8 +251,8 @@ func TestUnmarshalPostArgs(t *testing.T) {
if a.TTL != 12345 {
t.Fatalf("wrong ttl: %d.", a.TTL)
}
- if a.SignWith != "0x70c87d191324e6712a591f304b4eedef6ad9bb9d" {
- t.Fatalf("wrong From: %s.", a.SignWith)
+ if a.Sig != "0x70c87d191324e6712a591f304b4eedef6ad9bb9d" {
+ t.Fatalf("wrong From: %s.", a.Sig)
}
if a.Key != "0x9b2055d370f73ec7d8a03e965129118dc8f5bf83" {
t.Fatalf("wrong Key: %s.", a.Key)
@@ -282,7 +282,7 @@ func waitForMessages(api *PublicWhisperAPI, id string, target int) []*WhisperMes
// timeout: 2 seconds
result := make([]*WhisperMessage, 0, target)
for i := 0; i < 100; i++ {
- mail := api.GetSubscriptionMessages(id)
+ mail := api.GetNewSubscriptionMessages(id)
if len(mail) > 0 {
for _, m := range mail {
result = append(result, m)
@@ -347,7 +347,7 @@ func TestIntegrationAsym(t *testing.T) {
var f WhisperFilterArgs
f.Symmetric = false
f.Key = key
- f.SignedWith = sigPubKey.String()
+ f.Sig = sigPubKey.String()
f.Topics = make([][]byte, 2)
f.Topics[0] = topics[0][:]
f.Topics[1] = topics[1][:]
@@ -362,7 +362,7 @@ func TestIntegrationAsym(t *testing.T) {
var p PostArgs
p.Type = "asym"
p.TTL = 2
- p.SignWith = sig
+ p.Sig = sig
p.Key = dstPubKey.String()
p.Padding = []byte("test string")
p.Payload = []byte("extended test string")
@@ -448,8 +448,8 @@ func TestIntegrationSym(t *testing.T) {
f.Topics = make([][]byte, 2)
f.Topics[0] = topics[0][:]
f.Topics[1] = topics[1][:]
- f.MinPoW = 0.324
- f.SignedWith = sigPubKey.String()
+ f.MinPoW = DefaultMinimumPoW / 2
+ f.Sig = sigPubKey.String()
f.AllowP2P = false
id, err := api.Subscribe(f)
@@ -461,7 +461,7 @@ func TestIntegrationSym(t *testing.T) {
p.Type = "sym"
p.TTL = 1
p.Key = symKeyID
- p.SignWith = sig
+ p.Sig = sig
p.Padding = []byte("test string")
p.Payload = []byte("extended test string")
p.PowTarget = DefaultMinimumPoW
@@ -546,8 +546,8 @@ func TestIntegrationSymWithFilter(t *testing.T) {
f.Topics = make([][]byte, 2)
f.Topics[0] = topics[0][:]
f.Topics[1] = topics[1][:]
- f.MinPoW = 0.324
- f.SignedWith = sigPubKey.String()
+ f.MinPoW = DefaultMinimumPoW / 2
+ f.Sig = sigPubKey.String()
f.AllowP2P = false
id, err := api.Subscribe(f)
@@ -559,7 +559,7 @@ func TestIntegrationSymWithFilter(t *testing.T) {
p.Type = "sym"
p.TTL = 1
p.Key = symKeyID
- p.SignWith = sigKeyID
+ p.Sig = sigKeyID
p.Padding = []byte("test string")
p.Payload = []byte("extended test string")
p.PowTarget = DefaultMinimumPoW
diff --git a/whisper/whisperv5/benchmarks_test.go b/whisper/whisperv5/benchmarks_test.go
index 417b2881b..dcfbcb56d 100644
--- a/whisper/whisperv5/benchmarks_test.go
+++ b/whisper/whisperv5/benchmarks_test.go
@@ -28,12 +28,6 @@ func BenchmarkDeriveKeyMaterial(b *testing.B) {
}
}
-func BenchmarkDeriveOneTimeKey(b *testing.B) {
- for i := 0; i < b.N; i++ {
- DeriveOneTimeKey([]byte("test value 1"), []byte("test value 2"), 0)
- }
-}
-
func BenchmarkEncryptionSym(b *testing.B) {
InitSingleTest()
@@ -43,7 +37,7 @@ func BenchmarkEncryptionSym(b *testing.B) {
}
for i := 0; i < b.N; i++ {
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
_, err := msg.Wrap(params)
if err != nil {
b.Errorf("failed Wrap with seed %d: %s.", seed, err)
@@ -68,7 +62,7 @@ func BenchmarkEncryptionAsym(b *testing.B) {
params.Dst = &key.PublicKey
for i := 0; i < b.N; i++ {
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
_, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -83,7 +77,7 @@ func BenchmarkDecryptionSymValid(b *testing.B) {
if err != nil {
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -105,7 +99,7 @@ func BenchmarkDecryptionSymInvalid(b *testing.B) {
if err != nil {
b.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -134,7 +128,7 @@ func BenchmarkDecryptionAsymValid(b *testing.B) {
f := Filter{KeyAsym: key}
params.KeySym = nil
params.Dst = &key.PublicKey
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -161,7 +155,7 @@ func BenchmarkDecryptionAsymInvalid(b *testing.B) {
}
params.KeySym = nil
params.Dst = &key.PublicKey
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
env, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -203,7 +197,7 @@ func BenchmarkPoW(b *testing.B) {
for i := 0; i < b.N; i++ {
increment(params.Payload)
- msg := NewSentMessage(params)
+ msg, _ := NewSentMessage(params)
_, err := msg.Wrap(params)
if err != nil {
b.Fatalf("failed Wrap with seed %d: %s.", seed, err)
diff --git a/whisper/whisperv5/doc.go b/whisper/whisperv5/doc.go
index d60868f67..768291a16 100644
--- a/whisper/whisperv5/doc.go
+++ b/whisper/whisperv5/doc.go
@@ -49,18 +49,16 @@ const (
paddingMask = byte(3)
signatureFlag = byte(4)
- TopicLength = 4
- signatureLength = 65
- aesKeyLength = 32
- saltLength = 12
- AESNonceMaxLength = 12
- keyIdSize = 32
+ TopicLength = 4
+ signatureLength = 65
+ aesKeyLength = 32
+ AESNonceLength = 12
+ keyIdSize = 32
DefaultMaxMessageLength = 1024 * 1024
- DefaultMinimumPoW = 1.0 // todo: review after testing.
+ DefaultMinimumPoW = 0.2
- padSizeLimitLower = 128 // it can not be less - we don't want to reveal the absence of signature
- padSizeLimitUpper = 256 // just an arbitrary number, could be changed without losing compatibility
+ padSizeLimit = 256 // just an arbitrary number, could be changed without breaking the protocol (must not exceed 2^24)
messageQueueLimit = 1024
expirationCycle = time.Second
diff --git a/whisper/whisperv5/envelope.go b/whisper/whisperv5/envelope.go
index dffa7b286..d95fcab75 100644
--- a/whisper/whisperv5/envelope.go
+++ b/whisper/whisperv5/envelope.go
@@ -40,7 +40,6 @@ type Envelope struct {
Expiry uint32
TTL uint32
Topic TopicType
- Salt []byte
AESNonce []byte
Data []byte
EnvNonce uint64
@@ -50,15 +49,25 @@ type Envelope struct {
// Don't access hash directly, use Hash() function instead.
}
+// size returns the size of envelope as it is sent (i.e. public fields only)
+func (e *Envelope) size() int {
+ return 20 + len(e.Version) + len(e.AESNonce) + len(e.Data)
+}
+
+// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
+func (e *Envelope) rlpWithoutNonce() []byte {
+ res, _ := rlp.EncodeToBytes([]interface{}{e.Version, e.Expiry, e.TTL, e.Topic, e.AESNonce, e.Data})
+ return res
+}
+
// NewEnvelope wraps a Whisper message with expiration and destination data
// included into an envelope for network forwarding.
-func NewEnvelope(ttl uint32, topic TopicType, salt []byte, aesNonce []byte, msg *SentMessage) *Envelope {
+func NewEnvelope(ttl uint32, topic TopicType, aesNonce []byte, msg *SentMessage) *Envelope {
env := Envelope{
Version: make([]byte, 1),
Expiry: uint32(time.Now().Add(time.Second * time.Duration(ttl)).Unix()),
TTL: ttl,
Topic: topic,
- Salt: salt,
AESNonce: aesNonce,
Data: msg.Raw,
EnvNonce: 0,
@@ -126,10 +135,6 @@ func (e *Envelope) Seal(options *MessageParams) error {
return nil
}
-func (e *Envelope) size() int {
- return len(e.Data) + len(e.Version) + len(e.AESNonce) + len(e.Salt) + 20
-}
-
func (e *Envelope) PoW() float64 {
if e.pow == 0 {
e.calculatePoW(0)
@@ -159,12 +164,6 @@ func (e *Envelope) powToFirstBit(pow float64) int {
return int(bits)
}
-// rlpWithoutNonce returns the RLP encoded envelope contents, except the nonce.
-func (e *Envelope) rlpWithoutNonce() []byte {
- res, _ := rlp.EncodeToBytes([]interface{}{e.Expiry, e.TTL, e.Topic, e.Salt, e.AESNonce, e.Data})
- return res
-}
-
// Hash returns the SHA3 hash of the envelope, calculating it if not yet done.
func (e *Envelope) Hash() common.Hash {
if (e.hash == common.Hash{}) {
@@ -210,7 +209,7 @@ func (e *Envelope) OpenAsymmetric(key *ecdsa.PrivateKey) (*ReceivedMessage, erro
// OpenSymmetric tries to decrypt an envelope, potentially encrypted with a particular key.
func (e *Envelope) OpenSymmetric(key []byte) (msg *ReceivedMessage, err error) {
msg = &ReceivedMessage{Raw: e.Data}
- err = msg.decryptSymmetric(key, e.Salt, e.AESNonce)
+ err = msg.decryptSymmetric(key, e.AESNonce)
if err != nil {
msg = nil
}
diff --git a/whisper/whisperv5/filter_test.go b/whisper/whisperv5/filter_test.go
index ae21d1739..dd4ab9e8d 100644
--- a/whisper/whisperv5/filter_test.go
+++ b/whisper/whisperv5/filter_test.go
@@ -68,7 +68,7 @@ func generateFilter(t *testing.T, symmetric bool) (*Filter, error) {
f.Src = &key.PublicKey
if symmetric {
- f.KeySym = make([]byte, 12)
+ f.KeySym = make([]byte, aesKeyLength)
mrand.Read(f.KeySym)
f.SymKeyHash = crypto.Keccak256Hash(f.KeySym)
} else {
@@ -179,7 +179,10 @@ func TestMatchEnvelope(t *testing.T) {
params.Topic[0] = 0xFF // ensure mismatch
// mismatch with pseudo-random data
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -197,7 +200,10 @@ func TestMatchEnvelope(t *testing.T) {
i := mrand.Int() % 4
fsym.Topics[i] = params.Topic[:]
fasym.Topics[i] = params.Topic[:]
- msg = NewSentMessage(params)
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err = msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
@@ -245,7 +251,10 @@ func TestMatchEnvelope(t *testing.T) {
}
params.KeySym = nil
params.Dst = &key.PublicKey
- msg = NewSentMessage(params)
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err = msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap() with seed %d: %s.", seed, err)
@@ -323,12 +332,14 @@ func TestMatchMessageSym(t *testing.T) {
params.KeySym = f.KeySym
params.Topic = BytesToTopic(f.Topics[index])
- sentMessage := NewSentMessage(params)
+ sentMessage, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := sentMessage.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
-
msg := env.Open(f)
if msg == nil {
t.Fatalf("failed Open with seed %d.", seed)
@@ -419,12 +430,14 @@ func TestMatchMessageAsym(t *testing.T) {
keySymOrig := params.KeySym
params.KeySym = nil
- sentMessage := NewSentMessage(params)
+ sentMessage, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := sentMessage.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
-
msg := env.Open(f)
if msg == nil {
t.Fatalf("failed to open with seed %d.", seed)
@@ -506,7 +519,10 @@ func generateCompatibeEnvelope(t *testing.T, f *Filter) *Envelope {
params.KeySym = f.KeySym
params.Topic = BytesToTopic(f.Topics[2])
- sentMessage := NewSentMessage(params)
+ sentMessage, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := sentMessage.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -678,7 +694,10 @@ func TestVariableTopics(t *testing.T) {
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
diff --git a/whisper/whisperv5/message.go b/whisper/whisperv5/message.go
index 9b9c389a6..4ef469b51 100644
--- a/whisper/whisperv5/message.go
+++ b/whisper/whisperv5/message.go
@@ -23,14 +23,14 @@ import (
"crypto/cipher"
"crypto/ecdsa"
crand "crypto/rand"
- "crypto/sha256"
+ "encoding/binary"
"errors"
+ "strconv"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/log"
- "golang.org/x/crypto/pbkdf2"
)
// Options specifies the exact way a message should be wrapped into an Envelope.
@@ -86,58 +86,76 @@ func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
return msg.Dst != nil
}
-func DeriveOneTimeKey(key []byte, salt []byte, version uint64) ([]byte, error) {
- if version == 0 {
- derivedKey := pbkdf2.Key(key, salt, 8, aesKeyLength, sha256.New)
- return derivedKey, nil
- } else {
- return nil, unknownVersionError(version)
- }
-}
-
// NewMessage creates and initializes a non-signed, non-encrypted Whisper message.
-func NewSentMessage(params *MessageParams) *SentMessage {
+func NewSentMessage(params *MessageParams) (*SentMessage, error) {
msg := SentMessage{}
- msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Payload)+signatureLength+padSizeLimitUpper)
+ msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
msg.Raw[0] = 0 // set all the flags to zero
err := msg.appendPadding(params)
if err != nil {
- log.Error("failed to create NewSentMessage", "err", err)
- return nil
+ return nil, err
}
msg.Raw = append(msg.Raw, params.Payload...)
- return &msg
+ return &msg, nil
+}
+
+// getSizeOfLength returns the number of bytes necessary to encode the entire size padding (including these bytes)
+func getSizeOfLength(b []byte) (sz int, err error) {
+ sz = intSize(len(b)) // first iteration
+ sz = intSize(len(b) + sz) // second iteration
+ if sz > 3 {
+ err = errors.New("oversized padding parameter")
+ }
+ return sz, err
+}
+
+// sizeOfIntSize returns minimal number of bytes necessary to encode an integer value
+func intSize(i int) (s int) {
+ for s = 1; i >= 256; s++ {
+ i /= 256
+ }
+ return s
}
// appendPadding appends the pseudorandom padding bytes and sets the padding flag.
// The last byte contains the size of padding (thus, its size must not exceed 256).
func (msg *SentMessage) appendPadding(params *MessageParams) error {
- total := len(params.Payload) + 1
+ rawSize := len(params.Payload) + 1
if params.Src != nil {
- total += signatureLength
+ rawSize += signatureLength
}
- padChunk := padSizeLimitUpper
- if total <= padSizeLimitLower {
- padChunk = padSizeLimitLower
- }
- odd := total % padChunk
- if odd > 0 {
- padSize := padChunk - odd
- if padSize > 255 {
- // this algorithm is only valid if padSizeLimitUpper <= 256.
- // if padSizeLimitUpper will ever change, please fix the algorithm
- // (for more information see ReceivedMessage.extractPadding() function).
+ odd := rawSize % padSizeLimit
+
+ if len(params.Padding) != 0 {
+ padSize := len(params.Padding)
+ padLengthSize, err := getSizeOfLength(params.Padding)
+ if err != nil {
+ return err
+ }
+ totalPadSize := padSize + padLengthSize
+ buf := make([]byte, 8)
+ binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
+ buf = buf[:padLengthSize]
+ msg.Raw = append(msg.Raw, buf...)
+ msg.Raw = append(msg.Raw, params.Padding...)
+ msg.Raw[0] |= byte(padLengthSize) // number of bytes indicating the padding size
+ } else if odd != 0 {
+ totalPadSize := padSizeLimit - odd
+ if totalPadSize > 255 {
+ // this algorithm is only valid if padSizeLimit < 256.
+ // if padSizeLimit will ever change, please fix the algorithm
+ // (please see also ReceivedMessage.extractPadding() function).
panic("please fix the padding algorithm before releasing new version")
}
- buf := make([]byte, padSize)
+ buf := make([]byte, totalPadSize)
_, err := crand.Read(buf[1:])
if err != nil {
return err
}
- buf[0] = byte(padSize)
- if params.Padding != nil {
- copy(buf[1:], params.Padding)
+ if totalPadSize > 6 && !validateSymmetricKey(buf) {
+ return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
}
+ buf[0] = byte(totalPadSize)
msg.Raw = append(msg.Raw, buf...)
msg.Raw[0] |= byte(0x1) // number of bytes indicating the padding size
}
@@ -178,46 +196,31 @@ func (msg *SentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
// encryptSymmetric encrypts a message with a topic key, using AES-GCM-256.
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
-func (msg *SentMessage) encryptSymmetric(key []byte) (salt []byte, nonce []byte, err error) {
+func (msg *SentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
if !validateSymmetricKey(key) {
- return nil, nil, errors.New("invalid key provided for symmetric encryption")
- }
-
- salt = make([]byte, saltLength)
- _, err = crand.Read(salt)
- if err != nil {
- return nil, nil, err
- } else if !validateSymmetricKey(salt) {
- return nil, nil, errors.New("crypto/rand failed to generate salt")
+ return nil, errors.New("invalid key provided for symmetric encryption")
}
- derivedKey, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
- if err != nil {
- return nil, nil, err
- }
- if !validateSymmetricKey(derivedKey) {
- return nil, nil, errors.New("failed to derive one-time key")
- }
- block, err := aes.NewCipher(derivedKey)
+ block, err := aes.NewCipher(key)
if err != nil {
- return nil, nil, err
+ return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
- return nil, nil, err
+ return nil, err
}
// never use more than 2^32 random nonces with a given key
nonce = make([]byte, aesgcm.NonceSize())
_, err = crand.Read(nonce)
if err != nil {
- return nil, nil, err
+ return nil, err
} else if !validateSymmetricKey(nonce) {
- return nil, nil, errors.New("crypto/rand failed to generate nonce")
+ return nil, errors.New("crypto/rand failed to generate nonce")
}
msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
- return salt, nonce, nil
+ return nonce, nil
}
// Wrap bundles the message into an Envelope to transmit over the network.
@@ -231,11 +234,11 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
return nil, err
}
}
- var salt, nonce []byte
+ var nonce []byte
if options.Dst != nil {
err = msg.encryptAsymmetric(options.Dst)
} else if options.KeySym != nil {
- salt, nonce, err = msg.encryptSymmetric(options.KeySym)
+ nonce, err = msg.encryptSymmetric(options.KeySym)
} else {
err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
}
@@ -244,7 +247,7 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
return nil, err
}
- envelope = NewEnvelope(options.TTL, options.Topic, salt, nonce, msg)
+ envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
err = envelope.Seal(options)
if err != nil {
return nil, err
@@ -254,13 +257,8 @@ func (msg *SentMessage) Wrap(options *MessageParams) (envelope *Envelope, err er
// decryptSymmetric decrypts a message with a topic key, using AES-GCM-256.
// nonce size should be 12 bytes (see cipher.gcmStandardNonceSize).
-func (msg *ReceivedMessage) decryptSymmetric(key []byte, salt []byte, nonce []byte) error {
- derivedKey, err := DeriveOneTimeKey(key, salt, msg.EnvelopeVersion)
- if err != nil {
- return err
- }
-
- block, err := aes.NewCipher(derivedKey)
+func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
+ block, err := aes.NewCipher(key)
if err != nil {
return err
}
@@ -323,7 +321,8 @@ func (msg *ReceivedMessage) Validate() bool {
// can be successfully decrypted.
func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
paddingSize := 0
- sz := int(msg.Raw[0] & paddingMask) // number of bytes containing the entire size of padding, could be zero
+ sz := int(msg.Raw[0] & paddingMask) // number of bytes indicating the entire size of padding (including these bytes)
+ // could be zero -- it means no padding
if sz != 0 {
paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
if paddingSize < sz || paddingSize+1 > end {
diff --git a/whisper/whisperv5/message_test.go b/whisper/whisperv5/message_test.go
index 1ed7250d3..aa82a02f3 100644
--- a/whisper/whisperv5/message_test.go
+++ b/whisper/whisperv5/message_test.go
@@ -31,9 +31,9 @@ func copyFromBuf(dst []byte, src []byte, beg int) int {
}
func generateMessageParams() (*MessageParams, error) {
- // set all the parameters except p.Dst
+ // set all the parameters except p.Dst and p.Padding
- buf := make([]byte, 1024)
+ buf := make([]byte, 4)
mrand.Read(buf)
sz := mrand.Intn(400)
@@ -42,14 +42,10 @@ func generateMessageParams() (*MessageParams, error) {
p.WorkTime = 1
p.TTL = uint32(mrand.Intn(1024))
p.Payload = make([]byte, sz)
- p.Padding = make([]byte, padSizeLimitUpper)
p.KeySym = make([]byte, aesKeyLength)
-
- var b int
- b = copyFromBuf(p.Payload, buf, b)
- b = copyFromBuf(p.Padding, buf, b)
- b = copyFromBuf(p.KeySym, buf, b)
- p.Topic = BytesToTopic(buf[b:])
+ mrand.Read(p.Payload)
+ mrand.Read(p.KeySym)
+ p.Topic = BytesToTopic(buf)
var err error
p.Src, err = crypto.GenerateKey()
@@ -77,11 +73,12 @@ func singleMessageTest(t *testing.T, symmetric bool) {
}
text := make([]byte, 0, 512)
- steg := make([]byte, 0, 512)
text = append(text, params.Payload...)
- steg = append(steg, params.Padding...)
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -102,10 +99,6 @@ func singleMessageTest(t *testing.T, symmetric bool) {
t.Fatalf("failed to validate with seed %d.", seed)
}
- padsz := len(decrypted.Padding)
- if !bytes.Equal(steg[:padsz], decrypted.Padding) {
- t.Fatalf("failed with seed %d: compare padding.", seed)
- }
if !bytes.Equal(text, decrypted.Payload) {
t.Fatalf("failed with seed %d: compare payload.", seed)
}
@@ -140,7 +133,10 @@ func TestMessageWrap(t *testing.T) {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.TTL = 1
params.WorkTime = 12
params.PoW = target
@@ -155,7 +151,10 @@ func TestMessageWrap(t *testing.T) {
}
// set PoW target too high, expect error
- msg2 := NewSentMessage(params)
+ msg2, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.TTL = 1000000
params.WorkTime = 1
params.PoW = 10000000.0
@@ -175,14 +174,15 @@ func TestMessageSeal(t *testing.T) {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.TTL = 1
aesnonce := make([]byte, 12)
- salt := make([]byte, 12)
mrand.Read(aesnonce)
- mrand.Read(salt)
- env := NewEnvelope(params.TTL, params.Topic, salt, aesnonce, msg)
+ env := NewEnvelope(params.TTL, params.Topic, aesnonce, msg)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
}
@@ -236,11 +236,12 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
}
text := make([]byte, 0, 512)
- steg := make([]byte, 0, 512)
text = append(text, params.Payload...)
- steg = append(steg, params.Padding...)
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -252,10 +253,6 @@ func singleEnvelopeOpenTest(t *testing.T, symmetric bool) {
t.Fatalf("failed to open with seed %d.", seed)
}
- padsz := len(decrypted.Padding)
- if !bytes.Equal(steg[:padsz], decrypted.Padding) {
- t.Fatalf("failed with seed %d: compare padding.", seed)
- }
if !bytes.Equal(text, decrypted.Payload) {
t.Fatalf("failed with seed %d: compare payload.", seed)
}
@@ -291,21 +288,38 @@ func TestEncryptWithZeroKey(t *testing.T) {
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
-
- msg := NewSentMessage(params)
-
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.KeySym = make([]byte, aesKeyLength)
_, err = msg.Wrap(params)
if err == nil {
t.Fatalf("wrapped with zero key, seed: %d.", seed)
}
+ params, err = generateMessageParams()
+ if err != nil {
+ t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
+ }
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.KeySym = make([]byte, 0)
_, err = msg.Wrap(params)
if err == nil {
t.Fatalf("wrapped with empty key, seed: %d.", seed)
}
+ params, err = generateMessageParams()
+ if err != nil {
+ t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
+ }
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
params.KeySym = nil
_, err = msg.Wrap(params)
if err == nil {
@@ -320,7 +334,10 @@ func TestRlpEncode(t *testing.T) {
if err != nil {
t.Fatalf("failed generateMessageParams with seed %d: %s.", seed, err)
}
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("wrapped with zero key, seed: %d.", seed)
@@ -344,3 +361,60 @@ func TestRlpEncode(t *testing.T) {
t.Fatalf("Hashes are not equal: %x vs. %x", he, hd)
}
}
+
+func singlePaddingTest(t *testing.T, padSize int) {
+ params, err := generateMessageParams()
+ if err != nil {
+ t.Fatalf("failed generateMessageParams with seed %d and sz=%d: %s.", seed, padSize, err)
+ }
+ params.Padding = make([]byte, padSize)
+ params.PoW = 0.0000000001
+ pad := make([]byte, padSize)
+ _, err = mrand.Read(pad)
+ if err != nil {
+ t.Fatalf("padding is not generated (seed %d): %s", seed, err)
+ }
+ n := copy(params.Padding, pad)
+ if n != padSize {
+ t.Fatalf("padding is not copied (seed %d): %s", seed, err)
+ }
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
+ env, err := msg.Wrap(params)
+ if err != nil {
+ t.Fatalf("failed to wrap, seed: %d and sz=%d.", seed, padSize)
+ }
+ f := Filter{KeySym: params.KeySym}
+ decrypted := env.Open(&f)
+ if decrypted == nil {
+ t.Fatalf("failed to open, seed and sz=%d: %d.", seed, padSize)
+ }
+ if !bytes.Equal(pad, decrypted.Padding) {
+ t.Fatalf("padding is not retireved as expected with seed %d and sz=%d:\n[%x]\n[%x].", seed, padSize, pad, decrypted.Padding)
+ }
+}
+
+func TestPadding(t *testing.T) {
+ InitSingleTest()
+
+ for i := 1; i < 260; i++ {
+ singlePaddingTest(t, i)
+ }
+
+ lim := 256 * 256
+ for i := lim - 5; i < lim+2; i++ {
+ singlePaddingTest(t, i)
+ }
+
+ for i := 0; i < 256; i++ {
+ n := mrand.Intn(256*254) + 256
+ singlePaddingTest(t, n)
+ }
+
+ for i := 0; i < 256; i++ {
+ n := mrand.Intn(256*1024) + 256*256
+ singlePaddingTest(t, n)
+ }
+}
diff --git a/whisper/whisperv5/peer.go b/whisper/whisperv5/peer.go
index 184c4ebf8..179c93179 100644
--- a/whisper/whisperv5/peer.go
+++ b/whisper/whisperv5/peer.go
@@ -149,23 +149,22 @@ func (peer *Peer) expire() {
// broadcast iterates over the collection of envelopes and transmits yet unknown
// ones over the network.
func (p *Peer) broadcast() error {
- // Fetch the envelopes and collect the unknown ones
+ var cnt int
envelopes := p.host.Envelopes()
- transmit := make([]*Envelope, 0, len(envelopes))
for _, envelope := range envelopes {
if !p.marked(envelope) {
- transmit = append(transmit, envelope)
- p.mark(envelope)
+ err := p2p.Send(p.ws, messagesCode, envelope)
+ if err != nil {
+ return err
+ } else {
+ p.mark(envelope)
+ cnt++
+ }
}
}
- if len(transmit) == 0 {
- return nil
- }
- // Transmit the unknown batch (potentially empty)
- if err := p2p.Send(p.ws, messagesCode, transmit); err != nil {
- return err
+ if cnt > 0 {
+ log.Trace("broadcast", "num. messages", cnt)
}
- log.Trace("broadcast", "num. messages", len(transmit))
return nil
}
diff --git a/whisper/whisperv5/peer_test.go b/whisper/whisperv5/peer_test.go
index a79b6ad14..d3cd63b0b 100644
--- a/whisper/whisperv5/peer_test.go
+++ b/whisper/whisperv5/peer_test.go
@@ -265,7 +265,10 @@ func sendMsg(t *testing.T, expected bool, id int) {
opt.Payload = opt.Payload[1:]
}
- msg := NewSentMessage(&opt)
+ msg, err := NewSentMessage(&opt)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
envelope, err := msg.Wrap(&opt)
if err != nil {
t.Fatalf("failed to seal message: %s", err)
@@ -286,7 +289,10 @@ func TestPeerBasic(t *testing.T) {
}
params.PoW = 0.001
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d.", seed)
diff --git a/whisper/whisperv5/whisper.go b/whisper/whisperv5/whisper.go
index c4d5d04a7..f2aad08ef 100644
--- a/whisper/whisperv5/whisper.go
+++ b/whisper/whisperv5/whisper.go
@@ -262,24 +262,14 @@ func (w *Whisper) GetPrivateKey(id string) (*ecdsa.PrivateKey, error) {
// GenerateSymKey generates a random symmetric key and stores it under id,
// which is then returned. Will be used in the future for session key exchange.
func (w *Whisper) GenerateSymKey() (string, error) {
- const size = aesKeyLength * 2
- buf := make([]byte, size)
- _, err := crand.Read(buf)
+ key := make([]byte, aesKeyLength)
+ _, err := crand.Read(key)
if err != nil {
return "", err
- } else if !validateSymmetricKey(buf) {
+ } else if !validateSymmetricKey(key) {
return "", fmt.Errorf("error in GenerateSymKey: crypto/rand failed to generate random data")
}
- key := buf[:aesKeyLength]
- salt := buf[aesKeyLength:]
- derived, err := DeriveOneTimeKey(key, salt, EnvelopeVersion)
- if err != nil {
- return "", err
- } else if !validateSymmetricKey(derived) {
- return "", fmt.Errorf("failed to derive valid key")
- }
-
id, err := GenerateRandomID()
if err != nil {
return "", fmt.Errorf("failed to generate ID: %s", err)
@@ -291,7 +281,7 @@ func (w *Whisper) GenerateSymKey() (string, error) {
if w.symKeys[id] != nil {
return "", fmt.Errorf("failed to generate unique ID")
}
- w.symKeys[id] = derived
+ w.symKeys[id] = key
return id, nil
}
@@ -395,6 +385,9 @@ func (w *Whisper) Unsubscribe(id string) error {
// network in the coming cycles.
func (w *Whisper) Send(envelope *Envelope) error {
ok, err := w.add(envelope)
+ if err != nil {
+ return err
+ }
if !ok {
return fmt.Errorf("failed to add envelope")
}
@@ -469,21 +462,18 @@ func (wh *Whisper) runMessageLoop(p *Peer, rw p2p.MsgReadWriter) error {
log.Warn("unxepected status message received", "peer", p.peer.ID())
case messagesCode:
// decode the contained envelopes
- var envelopes []*Envelope
- if err := packet.Decode(&envelopes); err != nil {
+ var envelope Envelope
+ if err := packet.Decode(&envelope); err != nil {
log.Warn("failed to decode envelope, peer will be disconnected", "peer", p.peer.ID(), "err", err)
return errors.New("invalid envelope")
}
- // inject all envelopes into the internal pool
- for _, envelope := range envelopes {
- cached, err := wh.add(envelope)
- if err != nil {
- log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
- return errors.New("invalid envelope")
- }
- if cached {
- p.mark(envelope)
- }
+ cached, err := wh.add(&envelope)
+ if err != nil {
+ log.Warn("bad envelope received, peer will be disconnected", "peer", p.peer.ID(), "err", err)
+ return errors.New("invalid envelope")
+ }
+ if cached {
+ p.mark(&envelope)
}
case p2pCode:
// peer-to-peer message, sent directly to peer bypassing PoW checks, etc.
@@ -550,14 +540,11 @@ func (wh *Whisper) add(envelope *Envelope) (bool, error) {
return false, fmt.Errorf("oversized version [%x]", envelope.Hash())
}
- if len(envelope.AESNonce) > AESNonceMaxLength {
- // the standard AES GSM nonce size is 12,
- // but const gcmStandardNonceSize cannot be accessed directly
- return false, fmt.Errorf("oversized AESNonce [%x]", envelope.Hash())
- }
-
- if len(envelope.Salt) > saltLength {
- return false, fmt.Errorf("oversized salt [%x]", envelope.Hash())
+ aesNonceSize := len(envelope.AESNonce)
+ if aesNonceSize != 0 && aesNonceSize != AESNonceLength {
+ // the standard AES GCM nonce size is 12 bytes,
+ // but constant gcmStandardNonceSize cannot be accessed (not exported)
+ return false, fmt.Errorf("wrong size of AESNonce: %d bytes [env: %x]", aesNonceSize, envelope.Hash())
}
if envelope.PoW() < wh.minPoW {
diff --git a/whisper/whisperv5/whisper_test.go b/whisper/whisperv5/whisper_test.go
index d5668259e..225728c42 100644
--- a/whisper/whisperv5/whisper_test.go
+++ b/whisper/whisperv5/whisper_test.go
@@ -455,7 +455,10 @@ func TestExpiry(t *testing.T) {
}
params.TTL = 1
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -515,7 +518,10 @@ func TestCustomization(t *testing.T) {
params.Topic = BytesToTopic(f.Topics[2])
params.PoW = smallPoW
params.TTL = 3600 * 24 // one day
- msg := NewSentMessage(params)
+ msg, err := NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err := msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)
@@ -533,7 +539,10 @@ func TestCustomization(t *testing.T) {
}
params.TTL++
- msg = NewSentMessage(params)
+ msg, err = NewSentMessage(params)
+ if err != nil {
+ t.Fatalf("failed to create new message with seed %d: %s.", seed, err)
+ }
env, err = msg.Wrap(params)
if err != nil {
t.Fatalf("failed Wrap with seed %d: %s.", seed, err)