]> git.ipfire.org Git - thirdparty/wireguard-go.git/commitdiff
Added last_minute_handshake_guard
authorMathias Hall-Andersen <mathias@hall-andersen.dk>
Wed, 20 Sep 2017 07:26:08 +0000 (09:26 +0200)
committerMathias Hall-Andersen <mathias@hall-andersen.dk>
Wed, 20 Sep 2017 07:26:08 +0000 (09:26 +0200)
- Added last_minute_handshake_guard and reverted keypair changes.
- Added comment explaining the state of Go in releation to handling
  cryptographic state in memory.
- Decreased logging level of netsh test

src/keypair.go
src/noise_protocol.go
src/peer.go
src/receive.go
src/send.go
src/tests/netns.sh
src/timers.go

index 644d040b9ba342ffc84384d375b9d034bfc1fdcf..7e5297b8e30b79c23090c9d9c300993c8ea0feed 100644 (file)
@@ -2,38 +2,20 @@ package main
 
 import (
        "crypto/cipher"
-       "golang.org/x/crypto/chacha20poly1305"
-       "reflect"
        "sync"
        "time"
 )
 
-type safeAEAD struct {
-       mutex sync.RWMutex
-       aead  cipher.AEAD
-}
-
-func (con *safeAEAD) clear() {
-       // TODO: improve handling of key material
-       con.mutex.Lock()
-       if con.aead != nil {
-               val := reflect.ValueOf(con.aead)
-               elm := val.Elem()
-               typ := elm.Type()
-               elm.Set(reflect.Zero(typ))
-               con.aead = nil
-       }
-       con.mutex.Unlock()
-}
-
-func (con *safeAEAD) setKey(key *[chacha20poly1305.KeySize]byte) {
-       // TODO: improve handling of key material
-       con.aead, _ = chacha20poly1305.New(key[:])
-}
+/* Due to limitations in Go and /x/crypto there is currently
+ * no way to ensure that key material is securely ereased in memory.
+ *
+ * Since this may harm the forward secrecy property,
+ * we plan to resolve this issue; whenever Go allows us to do so.
+ */
 
 type KeyPair struct {
-       send         safeAEAD
-       receive      safeAEAD
+       send         cipher.AEAD
+       receive      cipher.AEAD
        replayFilter ReplayFilter
        sendNonce    uint64
        isInitiator  bool
@@ -56,7 +38,5 @@ func (kp *KeyPairs) Current() *KeyPair {
 }
 
 func (device *Device) DeleteKeyPair(key *KeyPair) {
-       key.send.clear()
-       key.receive.clear()
        device.indices.Delete(key.localIndex)
 }
index a50e3dcb6b16ef727bc7076471d5329532e70985..9e5fdd8e3344a9295a226575db38727194cb0f3b 100644 (file)
@@ -502,8 +502,8 @@ func (peer *Peer) NewKeyPair() *KeyPair {
        // create AEAD instances
 
        keyPair := new(KeyPair)
-       keyPair.send.setKey(&sendKey)
-       keyPair.receive.setKey(&recvKey)
+       keyPair.send, _ = chacha20poly1305.New(sendKey[:])
+       keyPair.receive, _ = chacha20poly1305.New(recvKey[:])
 
        setZero(sendKey[:])
        setZero(recvKey[:])
@@ -530,30 +530,29 @@ func (peer *Peer) NewKeyPair() *KeyPair {
        // rotate key pairs
 
        kp := &peer.keyPairs
-       func() {
-               kp.mutex.Lock()
-               defer kp.mutex.Unlock()
-               // TODO: Adapt kernel behavior noise.c:161
-               if isInitiator {
-                       if kp.previous != nil {
-                               device.DeleteKeyPair(kp.previous)
-                               kp.previous = nil
-                       }
-
-                       if kp.next != nil {
-                               kp.previous = kp.next
-                               kp.next = keyPair
-                       } else {
-                               kp.previous = kp.current
-                               kp.current = keyPair
-                               signalSend(peer.signal.newKeyPair) // TODO: This more places (after confirming the key)
-                       }
+       kp.mutex.Lock()
 
-               } else {
+       // TODO: Adapt kernel behavior noise.c:161
+       if isInitiator {
+               if kp.previous != nil {
+                       device.DeleteKeyPair(kp.previous)
+                       kp.previous = nil
+               }
+
+               if kp.next != nil {
+                       kp.previous = kp.next
                        kp.next = keyPair
-                       kp.previous = nil // TODO: Discuss why
+               } else {
+                       kp.previous = kp.current
+                       kp.current = keyPair
+                       signalSend(peer.signal.newKeyPair) // TODO: This more places (after confirming the key)
                }
-       }()
+
+       } else {
+               kp.next = keyPair
+               kp.previous = nil
+       }
+       kp.mutex.Unlock()
 
        return keyPair
 }
index a4feb2f3319fdb3cf8cee5efad66c9c8b9182cfd..6fea82912faf7c3594b8f63b7ce1cd4e49ecd5d5 100644 (file)
@@ -39,6 +39,8 @@ type Peer struct {
                stop               chan struct{} // (size 0) : close to stop all goroutines for peer
        }
        timer struct {
+               // state related to WireGuard timers
+
                keepalivePersistent *time.Timer // set for persistent keepalives
                keepalivePassive    *time.Timer // set upon recieving messages
                newHandshake        *time.Timer // begin a new handshake (after Keepalive + RekeyTimeout)
@@ -49,7 +51,8 @@ type Peer struct {
                pendingNewHandshake     bool
                pendingZeroAllKeys      bool
 
-               needAnotherKeepalive bool
+               needAnotherKeepalive    bool
+               sendLastMinuteHandshake bool
        }
        queue struct {
                nonce    chan *QueueOutboundElement // nonce / pre-handshake queue
index 09fca77ec5c4351298c23885b5d8c6006b7b0df6..52c271803437a2c34a125b65097ad7a4aebf4086 100644 (file)
@@ -247,28 +247,20 @@ func (device *Device) RoutineDecryption() {
                        counter := elem.packet[MessageTransportOffsetCounter:MessageTransportOffsetContent]
                        content := elem.packet[MessageTransportOffsetContent:]
 
-                       // decrypt with key-pair
+                       // decrypt and release to consumer
 
+                       var err error
                        copy(nonce[4:], counter)
                        elem.counter = binary.LittleEndian.Uint64(counter)
-                       elem.keyPair.receive.mutex.RLock()
-                       if elem.keyPair.receive.aead == nil {
-                               // very unlikely (the key was deleted during queuing)
+                       elem.packet, err = elem.keyPair.receive.Open(
+                               elem.buffer[:0],
+                               nonce[:],
+                               content,
+                               nil,
+                       )
+                       if err != nil {
                                elem.Drop()
-                       } else {
-                               var err error
-                               elem.packet, err = elem.keyPair.receive.aead.Open(
-                                       elem.buffer[:0],
-                                       nonce[:],
-                                       content,
-                                       nil,
-                               )
-                               if err != nil {
-                                       elem.Drop()
-                               }
                        }
-
-                       elem.keyPair.receive.mutex.RUnlock()
                        elem.mutex.Unlock()
                }
        }
@@ -433,8 +425,6 @@ func (device *Device) RoutineHandshake() {
 
                case MessageResponseType:
 
-                       logDebug.Println("Process response")
-
                        // unmarshal
 
                        var msg MessageResponse
@@ -457,6 +447,8 @@ func (device *Device) RoutineHandshake() {
                                continue
                        }
 
+                       logDebug.Println("Received handshake initation from", peer)
+
                        peer.TimerEphemeralKeyCreated()
 
                        // update timers
index e9dfb54f9efcf515669aebc18105a5cff72c8632..5c88ead2ae664ac5637566c45ed11167ebe00edd 100644 (file)
@@ -303,27 +303,16 @@ func (device *Device) RoutineEncryption() {
                                }
                        }
 
-                       // encrypt content (append to header)
+                       // encrypt content and release to consumer
 
                        binary.LittleEndian.PutUint64(nonce[4:], elem.nonce)
-                       elem.keyPair.send.mutex.RLock()
-                       if elem.keyPair.send.aead == nil {
-                               // very unlikely (the key was deleted during queuing)
-                               elem.Drop()
-                       } else {
-                               elem.packet = elem.keyPair.send.aead.Seal(
-                                       header,
-                                       nonce[:],
-                                       elem.packet,
-                                       nil,
-                               )
-                       }
+                       elem.packet = elem.keyPair.send.Seal(
+                               header,
+                               nonce[:],
+                               elem.packet,
+                               nil,
+                       )
                        elem.mutex.Unlock()
-                       elem.keyPair.send.mutex.RUnlock()
-
-                       // refresh key if necessary
-
-                       elem.peer.KeepKeyFreshSending()
                }
        }
 }
index 9c10d36227cd3d59e48d65d4911bd369dd9abb2e..043da3e732395a594100a4c5fc0b7c993c52eaad 100755 (executable)
@@ -28,7 +28,7 @@ netns0="wg-test-$$-0"
 netns1="wg-test-$$-1"
 netns2="wg-test-$$-2"
 program="../wireguard-go"
-export LOG_LEVEL="debug"
+export LOG_LEVEL="error"
 
 pretty() { echo -e "\x1b[32m\x1b[1m[+] ${1:+NS$1: }${2}\x1b[0m" >&3; }
 pp() { pretty "" "$*"; "$@"; }
index ad8866f4ec4759a478fc85d8a876ff96bee63c18..99695ba59cb61fdd6e07a33b3a6aaf82caa82201 100644 (file)
@@ -27,9 +27,12 @@ func (peer *Peer) KeepKeyFreshSending() {
 \r
 /* Called when a new authenticated message has been recevied\r
  *\r
+ * NOTE: Not thread safe (called by sequential receiver)\r
  */\r
 func (peer *Peer) KeepKeyFreshReceiving() {\r
-       // TODO: Add a guard, clear on handshake complete (clear in TimerHandshakeComplete)\r
+       if peer.timer.sendLastMinuteHandshake {\r
+               return\r
+       }\r
        kp := peer.keyPairs.Current()\r
        if kp == nil {\r
                return\r
@@ -40,7 +43,9 @@ func (peer *Peer) KeepKeyFreshReceiving() {
        nonce := atomic.LoadUint64(&kp.sendNonce)\r
        send := nonce > RekeyAfterMessages || time.Now().Sub(kp.created) > RekeyAfterTimeReceiving\r
        if send {\r
+               // do a last minute attempt at initiating a new handshake\r
                signalSend(peer.signal.handshakeBegin)\r
+               peer.timer.sendLastMinuteHandshake = true\r
        }\r
 }\r
 \r
@@ -311,6 +316,7 @@ func (peer *Peer) RoutineHandshakeInitiator() {
 \r
                        case <-peer.signal.handshakeCompleted:\r
                                <-timeout.C\r
+                               peer.timer.sendLastMinuteHandshake = false\r
                                break AttemptHandshakes\r
 \r
                        case <-peer.signal.handshakeReset:\r