@cryptotaxi247 / kubo / commits / 127c03255

secio: better error detection

The same keys + nonces in secio were being observed. As described in https://github.com/ipfs/go-ipfs/issues/1016 -- the handshake must be talking to itself. This can happen in an outgoing TCP dial with REUSEPORT on to the same address.

Juan Batiz-Benet committed Apr 13, 2015 at 21:52 UTC 127c03255a402d82c41b4c2d1317e2fc29bfbd32
2 files changed +16 -14
p2p/crypto/secio/al.go
+3 -3
@@ -91,11 +91,11 @@ func newBlockCipher(cipherT string, key []byte) (cipher.Block, error) {
91 // Determines which algorithm to use. Note: f(a, b) = f(b, a)
92 func selectBest(order int, p1, p2 string) (string, error) {
93 var f, s []string
94 - switch order {
95 - case -1:
94 + switch {
95 + case order < 0:
96 f = strings.Split(p2, ",")
97 s = strings.Split(p1, ",")
98 - case 1:
98 + case order > 0:
99 f = strings.Split(p1, ",")
100 s = strings.Split(p2, ",")
101 default: // Exact same preferences.
p2p/crypto/secio/protocol.go
+13 -11
@@ -24,6 +24,9 @@ var ErrUnsupportedKeyType = errors.New("unsupported key type")
24 // ErrClosed signals the closing of a connection.
25 var ErrClosed = errors.New("connection closed")
26
27 +// ErrEcho is returned when we're attempting to handshake with the same keys and nonces.
28 +var ErrEcho = errors.New("same keys and nonces. one side talking to self.")
29 +
30 // nonceSize is the size of our nonces (in bytes)
31 const nonceSize = 16
32
@@ -145,6 +148,10 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
148 oh1 := u.Hash(append(proposeIn.GetPubkey(), nonceOut...))
149 oh2 := u.Hash(append(myPubKeyBytes, proposeIn.GetRand()...))
150 order := bytes.Compare(oh1, oh2)
151 + if order == 0 {
152 + return ErrEcho // talking to self (same socket. must be reuseport + dialing self)
153 + }
154 +
155 s.local.curveT, err = selectBest(order, SupportedExchanges, proposeIn.GetExchanges())
156 if err != nil {
157 return err
@@ -242,19 +249,14 @@ func (s *secureSession) handshake(ctx context.Context, insecure io.ReadWriter) e
249 k1, k2 := ci.KeyStretcher(s.local.cipherT, s.local.hashT, s.sharedSecret)
250
251 // use random nonces to decide order.
245 - switch order {
246 - case 1:
247 - case -1:
252 + switch {
253 + case order > 0:
254 + // just break
255 + case order < 0:
256 k1, k2 = k2, k1 // swap
257 default:
250 - log.Error("WOAH: same keys (AND same nonce: 1/(2^128) chance!).")
251 - log.Errorf("k1: %v, k2: %v, insecure: %v, insecureM %v", k1, k2, s.insecure, s.insecureM)
252 -
253 - // this shouldn't happen. must determine order another way.
254 - // use the same keys but, make sure to copy underlying data!
255 - copy(k2.IV, k1.IV)
256 - copy(k2.MacKey, k1.MacKey)
257 - copy(k2.CipherKey, k1.CipherKey)
258 + // we should've bailed before this. but if not, bail here.
259 + return ErrEcho
260 }
261 s.local.keys = k1
262 s.remote.keys = k2