// Performs handshake and returns a new authenticated SecretConnection. // Returns nil if error in handshake. // Caller should call conn.Close() // See docs/sts-final.pdf for more information. func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey acm.PrivKeyEd25519) (*SecretConnection, error) { locPubKey := locPrivKey.PubKey().(acm.PubKeyEd25519) // Generate ephemeral keys for perfect forward secrecy. locEphPub, locEphPriv := genEphKeys() // Write local ephemeral pubkey and receive one too. // NOTE: every 32-byte string is accepted as a Curve25519 public key // (see DJB's Curve25519 paper: http://cr.yp.to/ecdh/curve25519-20060209.pdf) remEphPub, err := shareEphPubKey(conn, locEphPub) if err != nil { return nil, err } // Compute common shared secret. shrSecret := computeSharedSecret(remEphPub, locEphPriv) // Sort by lexical order. loEphPub, hiEphPub := sort32(locEphPub, remEphPub) // Generate nonces to use for secretbox. recvNonce, sendNonce := genNonces(loEphPub, hiEphPub, locEphPub == loEphPub) // Generate common challenge to sign. challenge := genChallenge(loEphPub, hiEphPub) // Construct SecretConnection. sc := &SecretConnection{ conn: conn, recvBuffer: nil, recvNonce: recvNonce, sendNonce: sendNonce, shrSecret: shrSecret, } // Sign the challenge bytes for authentication. locSignature := signChallenge(challenge, locPrivKey) // Share (in secret) each other's pubkey & challenge signature authSigMsg, err := shareAuthSignature(sc, locPubKey, locSignature) if err != nil { return nil, err } remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig if !remPubKey.VerifyBytes(challenge[:], remSignature) { return nil, errors.New("Challenge verification failed") } // We've authorized. sc.remPubKey = remPubKey return sc, nil }
func makeNodeInfo(sw *p2p.Switch, privKey acm.PrivKeyEd25519, genesisRoot []byte) *types.NodeInfo { nodeInfo := &types.NodeInfo{ PubKey: privKey.PubKey().(acm.PubKeyEd25519), Moniker: config.GetString("moniker"), ChainID: config.GetString("chain_id"), Genesis: genesisRoot, Version: types.Versions{ Tendermint: Version, P2P: p2p.Version, RPC: rpc.Version, Wire: wire.Version, }, } // include git hash in the nodeInfo if available if rev, err := ReadFile(config.GetString("revision_file")); err == nil { nodeInfo.Version.Revision = string(rev) } if !sw.IsListening() { return nodeInfo } p2pListener := sw.Listeners()[0] p2pHost := p2pListener.ExternalAddress().IP.String() p2pPort := p2pListener.ExternalAddress().Port rpcListenAddr := config.GetString("rpc_laddr") _, rpcPortStr, _ := net.SplitHostPort(rpcListenAddr) rpcPort, err := strconv.Atoi(rpcPortStr) if err != nil { PanicSanity(Fmt("Expected numeric RPC.ListenAddr port but got %v", rpcPortStr)) } // We assume that the rpcListener has the same ExternalAddress. // This is probably true because both P2P and RPC listeners use UPnP, // except of course if the rpc is only bound to localhost nodeInfo.Host = p2pHost nodeInfo.P2PPort = p2pPort nodeInfo.RPCPort = uint16(rpcPort) return nodeInfo }
// Not goroutine safe. // NOTE: Overwrites sw.nodeInfo.PubKey func (sw *Switch) SetNodePrivKey(nodePrivKey acm.PrivKeyEd25519) { sw.nodePrivKey = nodePrivKey if sw.nodeInfo != nil { sw.nodeInfo.PubKey = nodePrivKey.PubKey().(acm.PubKeyEd25519) } }