]> Cypherpunks.ru repositories - govpn.git/commitdiff
Ability to use EGD-compatible PRNGs
authorSergey Matveev <stargrave@stargrave.org>
Fri, 22 May 2015 20:43:03 +0000 (23:43 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Sun, 24 May 2015 06:55:35 +0000 (09:55 +0300)
Signed-off-by: Sergey Matveev <stargrave@stargrave.org>
12 files changed:
doc/client.texi
doc/egd.texi [new file with mode: 0644]
doc/keywords.texi
doc/news.texi
doc/precautions.texi
doc/server.texi
doc/todo.texi
doc/user.texi
src/govpn/cmd/govpn-client/main.go
src/govpn/cmd/govpn-server/main.go
src/govpn/egd.go [new file with mode: 0644]
src/govpn/handshake.go

index dfee4f19b68f9dc3c4c8f56490b0e1ca278c17a6..a6fc6b017602ffcb3cb9fac33dfbc98ec948c10d 100644 (file)
@@ -1,8 +1,8 @@
 @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
 
diff --git a/doc/egd.texi b/doc/egd.texi
new file mode 100644 (file)
index 0000000..6b6780e
--- /dev/null
@@ -0,0 +1,18 @@
+@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
index a513724a640648574277389211b6c56f4627447c..a365ce5fef119d61fdea85e55ca0f3929156f00c 100644 (file)
@@ -2,11 +2,12 @@ Some keywords describing this project: encryption, authentication, key
 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.
index 0ef3f82365c16d0475ad20abdc497f3ac134f64f..b0b64372755ffcbdcbfa6b57059092a2cfd5add3 100644 (file)
@@ -3,6 +3,13 @@
 
 @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
index cd759ea72708dd0503cb77fd01d3f226c0b6f3f5..f69d5341a04797b740d528ab4fab6ba481d9449f 100644 (file)
@@ -1,24 +1,22 @@
 @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
index c5f2eb29e8213190bbae74e3574d53b16e2acc10..810461ee5077016f6d2830e4cb5d0ca733ec5b8f 100644 (file)
@@ -1,8 +1,8 @@
 @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
index f480f7e3846d4e28f317bc41fd638ee8a9e079a7..8e912e3a704d823f5b106b624c98f4aa2a0b9b14 100644 (file)
@@ -2,7 +2,6 @@
 @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.
index 3080ce1f1ff3974939c64a568b061802936337cc..19e24e300b0cd204d6110d51d984f27474166c24 100644 (file)
@@ -10,6 +10,7 @@ IP-related network management is not touched by VPN at all. You can
 automate it using up and down shell scripts.
 
 @menu
+* EGD:: Entropy gathering daemon
 * Identity::
 * PAKE:: Password Authenticated Key Agreement
 * Timeout::
@@ -24,6 +25,7 @@ automate it using up and down shell scripts.
 * Example usage::
 @end menu
 
+@include egd.texi
 @include identity.texi
 @include pake.texi
 @include timeout.texi
index a951160a21d7ce737e01d53188b3fa4b70a272df..f21249061d4ed0e637f775beccca6c88291ed712 100644 (file)
@@ -43,6 +43,7 @@ var (
        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() {
@@ -58,6 +59,11 @@ 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,
index 0a127efa78104147f93b0a48e72853ba910ed21b..9fb7ae1edf7d9225c6504ee1d89da65515857f18 100644 (file)
@@ -37,6 +37,7 @@ var (
        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 {
@@ -83,6 +84,11 @@ func main() {
        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)
diff --git a/src/govpn/egd.go b/src/govpn/egd.go
new file mode 100644 (file)
index 0000000..08dff83
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+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
+}
index 7019148e899949f754435bdbad61c2042963350c..61b5b4f67dfe1f50fdb37d3c12ca032c62f8ce16 100644 (file)
@@ -101,13 +101,23 @@ func (h *Handshake) rNonceNext(count uint64) []byte {
        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)
@@ -157,7 +167,7 @@ func HandshakeStart(conf *PeerConf, conn *net.UDPConn, addr *net.UDPAddr) *Hands
        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)
@@ -201,11 +211,11 @@ func (h *Handshake) Server(conn *net.UDPConn, data []byte) *Peer {
 
                // 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)
@@ -287,11 +297,11 @@ func (h *Handshake) Client(conn *net.UDPConn, data []byte) *Peer {
 
                // 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[:])