Show More
@@ -28,6 +28,7 b' import hmac' | |||
|
28 | 28 | import logging |
|
29 | 29 | import os |
|
30 | 30 | import pprint |
|
31 | import random | |
|
31 | 32 | import uuid |
|
32 | 33 | from datetime import datetime |
|
33 | 34 | |
@@ -310,8 +311,16 b' class Session(Configurable):' | |||
|
310 | 311 | self.auth = hmac.HMAC(new) |
|
311 | 312 | else: |
|
312 | 313 | self.auth = None |
|
314 | ||
|
313 | 315 | auth = Instance(hmac.HMAC) |
|
316 | ||
|
314 | 317 | digest_history = Set() |
|
318 | digest_history_size = Integer(2**16, config=True, | |
|
319 | help="""The maximum number of digests to remember. | |
|
320 | ||
|
321 | The digest history will be culled when it exceeds this value. | |
|
322 | """ | |
|
323 | ) | |
|
315 | 324 | |
|
316 | 325 | keyfile = Unicode('', config=True, |
|
317 | 326 | help="""path to file containing execution key.""") |
@@ -699,6 +708,30 b' class Session(Configurable):' | |||
|
699 | 708 | idents, msg_list = msg_list[:idx], msg_list[idx+1:] |
|
700 | 709 | return [m.bytes for m in idents], msg_list |
|
701 | 710 | |
|
711 | def _add_digest(self, signature): | |
|
712 | """add a digest to history to protect against replay attacks""" | |
|
713 | if self.digest_history_size == 0: | |
|
714 | # no history, never add digests | |
|
715 | return | |
|
716 | ||
|
717 | self.digest_history.add(signature) | |
|
718 | if len(self.digest_history) > self.digest_history_size: | |
|
719 | # threshold reached, cull 10% | |
|
720 | self._cull_digest_history() | |
|
721 | ||
|
722 | def _cull_digest_history(self): | |
|
723 | """cull the digest history | |
|
724 | ||
|
725 | Removes a randomly selected 10% of the digest history | |
|
726 | """ | |
|
727 | current = len(self.digest_history) | |
|
728 | n_to_cull = max(int(current // 10), current - self.digest_history_size) | |
|
729 | if n_to_cull >= current: | |
|
730 | self.digest_history = set() | |
|
731 | return | |
|
732 | to_cull = random.sample(self.digest_history, n_to_cull) | |
|
733 | self.digest_history.difference_update(to_cull) | |
|
734 | ||
|
702 | 735 | def unserialize(self, msg_list, content=True, copy=True): |
|
703 | 736 | """Unserialize a msg_list to a nested message dict. |
|
704 | 737 | |
@@ -734,8 +767,8 b' class Session(Configurable):' | |||
|
734 | 767 | if not signature: |
|
735 | 768 | raise ValueError("Unsigned Message") |
|
736 | 769 | if signature in self.digest_history: |
|
737 | raise ValueError("Duplicate Signature: %r"%signature) | |
|
738 |
self.digest |
|
|
770 | raise ValueError("Duplicate Signature: %r" % signature) | |
|
771 | self._add_digest(signature) | |
|
739 | 772 | check = self.sign(msg_list[1:5]) |
|
740 | 773 | if not signature == check: |
|
741 | 774 | raise ValueError("Invalid Signature: %r" % signature) |
@@ -204,4 +204,22 b' class TestSession(SessionTestCase):' | |||
|
204 | 204 | self.assertEqual(session.bsession, session.session.encode('ascii')) |
|
205 | 205 | self.assertEqual(b'stuff', session.bsession) |
|
206 | 206 | |
|
207 | def test_zero_digest_history(self): | |
|
208 | session = ss.Session(digest_history_size=0) | |
|
209 | for i in range(11): | |
|
210 | session._add_digest(uuid.uuid4().bytes) | |
|
211 | self.assertEqual(len(session.digest_history), 0) | |
|
212 | ||
|
213 | def test_cull_digest_history(self): | |
|
214 | session = ss.Session(digest_history_size=100) | |
|
215 | for i in range(100): | |
|
216 | session._add_digest(uuid.uuid4().bytes) | |
|
217 | self.assertTrue(len(session.digest_history) == 100) | |
|
218 | session._add_digest(uuid.uuid4().bytes) | |
|
219 | self.assertTrue(len(session.digest_history) == 91) | |
|
220 | for i in range(9): | |
|
221 | session._add_digest(uuid.uuid4().bytes) | |
|
222 | self.assertTrue(len(session.digest_history) == 100) | |
|
223 | session._add_digest(uuid.uuid4().bytes) | |
|
224 | self.assertTrue(len(session.digest_history) == 91) | |
|
207 | 225 |
General Comments 0
You need to be logged in to leave comments.
Login now