@node Client part
@section Client part
-Except for common @code{-mtu}, @code{-stats} options client has the
-following ones:
+Except for common @code{-mtu}, @code{-stats}, @code{-egd} options client
+has the following ones:
@table @code
--- /dev/null
+@node EGD
+@section EGD
+
+Overall security mainly depends on client side:
+@ref{PAKE, good passphrase} and cryprographically good pseudo random
+number generator.
+
+Some operating systems do not have good enough quality PRNG, bad
+@code{/dev/urandom}. You should use separate PRNG with them. GoVPN
+communicates with them using Entropy Gathering Daemon protocol.
+
+To switch using EGD-compatible daemons instead of @code{crypto/rand}
+library you provide @code{-egd PATH} command line option, where
+@code{PATH} is either host:port or path to the domain socket.
+
+@example
+% ./govpn-server [...] -egd /var/run/egd.sock
+@end example
exchange, EKE, Diffie-Hellman, DH, DH-EKE, Augmented EKE, A-EKE,
security, encrypted key exchange, 128-bit margin, DPI, censorship,
resistance, free software, GPLv3+, reviewability, easy, simple,
-Curve25519, Ed25519, Elligator, SHA-512, Salsa20, Poly1305, AEAD, XTEA, PBKDF2,
-PRP, signatures, asymmetric cryptography, zero-knowledge password proof,
-PAKE, password, passphrase, password authenticated key exchange, perfect
-forward secrecy, PFS, MAC, nonce, verifier, rehandshake, heartbeat,
-replay attack, MiTM, length hiding, timestamps hiding, noise, constant
-traffic, constant packet rate, CPR, TAP, TAP, VPN, GNU, Linux, FreeBSD,
-IPv6, dictionary attack, mutual authentication, simultaneous clients,
-JSON, HTTP-server, statistics, PRNG, traffic analysis, Go, golang.
+Curve25519, Ed25519, Elligator, SHA-512, Salsa20, Poly1305, AEAD, XTEA,
+PBKDF2, PRP, signatures, asymmetric cryptography, zero-knowledge
+password proof, PAKE, password, passphrase, password authenticated key
+exchange, perfect forward secrecy, PFS, MAC, nonce, verifier,
+rehandshake, heartbeat, replay attack, MiTM, length hiding, timestamps
+hiding, noise, constant traffic, constant packet rate, CPR, EGD,
+entropy, TAP, TAP, VPN, GNU, Linux, FreeBSD, IPv6, dictionary attack,
+mutual authentication, simultaneous clients, JSON, HTTP-server,
+statistics, PRNG, traffic analysis, Go, golang.
@table @strong
+@item Release 3.4
+@itemize @bullet
+@item Ability to use external @ref{EGD}-compatible PRNGs. Now you are
+able to use GoVPN even on systems with the bad @code{/dev/random},
+providing higher quality entropy from external sources.
+@end itemize
+
@item Release 3.3
@itemize @bullet
@item Compatibility with an old GNU Make 3.x. Previously only BSD Make
@node Precautions
@unnumbered Precautions
-The very important precaution is the @strong{cryptographically good}
-pseudo random number generator. GoVPN uses native operating system PRNG
-as entropy source. You have no way to check its quality in closed
-source code operating systems, so it is recommended not to use them if
-you really needs security. Moreover it is possible that those OS leaks
-information about possible PRNG states. And at least Apple OS X and
-Microsoft Windows are already known to have weak CSPRNGs.
-
-GoVPN could use its own PRNG implementation like
-@url{https://www.schneier.com/fortuna.html, Fortuna}, but it is
-much easier to use the right OS, to use free software.
-
-Also you should @strong{never} use one key for multiple clients. Salsa20
-encryption is randomized in each session, but it depends again on PRNG.
-If it fails, produces equal values at least once, then all you traffic
-related to that key could be decrypted.
-
+@enumerate
+@item
We use password (passphrase) authentication, so overall security fully
depends on its strength. So you should use long, high-entropy
-passphrases. Also remember to keep passphrase on temporary file as
-described in @ref{Verifier}.
+passphrases. Also remember to keep passphrase on temporary file and read
+it securely as described in @ref{Verifier}.
+
+@item
+You must @strong{never} use one key for multiple clients.
+If so, then all security is ruined and transmitted data can
+be decrypted.
+
+@item
+You must use @strong{cryptographically good} pseudo random number
+generator. By default we use default @code{crypto/rand} library that
+reads @code{/dev/urandom} source. Some GNU/Linux and FreeBSD systems
+are rather good with this entropy source. Closed proprietary ones are
+always not and you must use optional @ref{EGD} feature with them.
+@end enumerate
@node Server part
@section Server part
-Except for common @code{-mtu}, @code{-stats} options server has the
-following ones:
+Except for common @code{-mtu}, @code{-stats}, @code{-egd} options server
+has the following ones:
@table @code
@item -bind
@unnumbered TODO
@itemize
-@item Ability to use EGD.
@item Replace -noncediff with in-memory storage of previously seen nonces.
@item Ability to tunnel only specified TCP connections, without full
featured VPN solution. Similar to ssh -R.
automate it using up and down shell scripts.
@menu
+* EGD:: Entropy gathering daemon
* Identity::
* PAKE:: Password Authenticated Key Agreement
* Timeout::
* Example usage::
@end menu
+@include egd.texi
@include identity.texi
@include pake.texi
@include timeout.texi
timeoutP = flag.Int("timeout", 60, "Timeout seconds")
noisy = flag.Bool("noise", false, "Enable noise appending")
cpr = flag.Int("cpr", 0, "Enable constant KiB/sec out traffic rate")
+ egdPath = flag.String("egd", "", "Optional path to EGD socket")
)
func main() {
log.Fatalln(err)
}
+ if *egdPath != "" {
+ log.Println("Using", *egdPath, "EGD")
+ govpn.EGDInit(*egdPath)
+ }
+
pub, priv := govpn.NewVerifier(id, govpn.StringFromFile(*keyPath))
conf := &govpn.PeerConf{
Id: id,
peersPath = flag.String("peers", "peers", "Path to peers keys directory")
stats = flag.String("stats", "", "Enable stats retrieving on host:port")
mtu = flag.Int("mtu", 1452, "MTU for outgoing packets")
+ egdPath = flag.String("egd", "", "Optional path to EGD socket")
)
type PeerReadyEvent struct {
govpn.MTU = *mtu
govpn.PeersInit(*peersPath)
+ if *egdPath != "" {
+ log.Println("Using", *egdPath, "EGD")
+ govpn.EGDInit(*egdPath)
+ }
+
bind, err := net.ResolveUDPAddr("udp", *bindAddr)
if err != nil {
log.Fatalln("Can not resolve bind address:", err)
--- /dev/null
+/*
+GoVPN -- simple secure free software virtual private network daemon
+Copyright (C) 2014-2015 Sergey Matveev <stargrave@stargrave.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+package govpn
+
+import (
+ "errors"
+ "net"
+)
+
+var (
+ egdPath string
+)
+
+func EGDInit(path string) {
+ egdPath = path
+}
+
+// Read n bytes from EGD, blocking mode.
+func EGDRead(b []byte) error {
+ c, err := net.Dial("unix", egdPath)
+ if err != nil {
+ return err
+ }
+ defer c.Close()
+ c.Write([]byte{0x02, byte(len(b))})
+ r, err := c.Read(b)
+ if err != nil {
+ return err
+ }
+ if r != len(b) {
+ return errors.New("Got less bytes than expected from EGD")
+ }
+ return nil
+}
return nonce
}
+func randRead(b []byte) error {
+ var err error
+ if egdPath == "" {
+ _, err = rand.Read(b)
+ } else {
+ err = EGDRead(b)
+ }
+ return err
+}
+
func dhKeypairGen() (*[32]byte, *[32]byte) {
priv := new([32]byte)
pub := new([32]byte)
repr := new([32]byte)
reprFound := false
for !reprFound {
- if _, err := rand.Read(priv[:]); err != nil {
+ if err := randRead(priv[:]); err != nil {
log.Fatalln("Error reading random for DH private key:", err)
}
reprFound = extra25519.ScalarBaseMult(pub, repr, priv)
state.dhPriv, dhPubRepr = dhKeypairGen()
state.rNonce = new([RSize]byte)
- if _, err := rand.Read(state.rNonce[:]); err != nil {
+ if err := randRead(state.rNonce[:]); err != nil {
log.Fatalln("Error reading random for nonce:", err)
}
enc := make([]byte, 32)
// Generate R* and encrypt them
h.rServer = new([RSize]byte)
- if _, err := rand.Read(h.rServer[:]); err != nil {
+ if err := randRead(h.rServer[:]); err != nil {
log.Fatalln("Error reading random for R:", err)
}
h.sServer = new([SSize]byte)
- if _, err := rand.Read(h.sServer[:]); err != nil {
+ if err := randRead(h.sServer[:]); err != nil {
log.Fatalln("Error reading random for S:", err)
}
encRs := make([]byte, RSize+SSize)
// Generate R* and signature and encrypt them
h.rClient = new([RSize]byte)
- if _, err := rand.Read(h.rClient[:]); err != nil {
+ if err := randRead(h.rClient[:]); err != nil {
log.Fatalln("Error reading random for R:", err)
}
h.sClient = new([SSize]byte)
- if _, err := rand.Read(h.sClient[:]); err != nil {
+ if err := randRead(h.sClient[:]); err != nil {
log.Fatalln("Error reading random for S:", err)
}
sign := ed25519.Sign(h.Conf.DSAPriv, h.key[:])