Commit bbde1c0d authored by Johan Hugé's avatar Johan Hugé

Fix two issues related to handleHello

In some circumstances, the hello_protocol attribute could get modified
on the wrong peer, which would raise an AttributeError.
On reception of seqno 1 from a peer with protocol < 7, protocol could be
equal to zero which would cause handleHello to not return True, causing
the handshake to fail.
parent 85d77bd8
......@@ -384,14 +384,14 @@ class BaseTunnelManager(object):
peer = self._getPeer(prefix)
msg = peer.decode(msg)
if type(msg) is tuple:
real_seqno, msg = msg
def handleHello(peer, seqno, msg):
seqno, msg, protocol = msg
def handleHello(peer, seqno, msg, retry):
if seqno == 2:
i = len(msg) // 2
h = msg[:i]
try:
peer.verify(msg[i:], h)
peer.newSession(self.cert.decrypt(h))
peer.newSession(self.cert.decrypt(h), protocol)
except (AttributeError, crypto.Error, x509.NewSessionError,
subprocess.CalledProcessError):
logging.debug('ignored new session key from %r',
......@@ -412,7 +412,7 @@ class BaseTunnelManager(object):
if serial in self.cache.crl:
raise ValueError("revoked")
except (x509.VerifyError, ValueError), e:
if real_seqno and peer.hello_protocol:
if retry:
return True
logging.debug('ignored invalid certificate from %r (%s)',
address, e.args[-1])
......@@ -430,17 +430,17 @@ class BaseTunnelManager(object):
peer.stop_date = stop_date
self.selectTimeout(stop_date, self.invalidatePeers, False)
if seqno:
self._sendto(to, peer.hello(self.cert))
self._sendto(to, peer.hello(self.cert, protocol))
else:
msg = peer.hello0(self.cert.cert)
if msg and self._sendto(to, msg):
peer.hello0Sent()
if handleHello(peer, real_seqno, msg):
if handleHello(peer, seqno, msg, seqno):
# It is possible to reconstruct the original message because
# the serialization of the protocol version is always unique.
msg = utils.packInteger(peer.hello_protocol) + msg
peer.hello_protocol = 0
handleHello(peer, real_seqno, msg)
msg = utils.packInteger(protocol) + msg
protocol = 0
handleHello(peer, seqno, msg, False)
elif msg:
# We got a valid and non-empty message. Always reply
# something so that the sender knows we're still connected.
......
......@@ -241,26 +241,26 @@ class Peer(object):
def hello0Sent(self):
self._hello = time.time() + 60
def hello(self, cert):
def hello(self, cert, protocol):
key = self._key = newHmacSecret()
h = encrypt(crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert),
key)
self._i = self._j = 2
self._last = 0
self.protocol = self.hello_protocol
return ''.join(('\0\0\0\2', PACKED_PROTOCOL if self.protocol else '',
self.protocol = protocol
return ''.join(('\0\0\0\2', PACKED_PROTOCOL if protocol else '',
h, cert.sign(h)))
def _hmac(self, msg):
return hmac.HMAC(self._key, msg, hashlib.sha1).digest()
def newSession(self, key):
def newSession(self, key, protocol):
if key <= self._key:
raise NewSessionError(self._key, key)
self._key = key
self._i = self._j = 2
self._last = None
self.protocol = self.hello_protocol
self.protocol = protocol
def verify(self, sign, data):
crypto.verify(self.cert, sign, data, 'sha512')
......@@ -272,9 +272,11 @@ class Peer(object):
if seqno <= 2:
msg = msg[4:]
if seqno:
self.hello_protocol, n = utils.unpackInteger(msg) or (0, 0)
protocol, n = utils.unpackInteger(msg) or (0, 0)
msg = msg[n:]
return seqno, msg
else:
protocol = None
return seqno, msg, protocol
i = -utils.HMAC_LEN
if self._hmac(msg[:i]) == msg[i:] and self._i < seqno:
self._last = None
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment