Check that the date in the signature isn't too old.

This commit is contained in:
Adam Kelly 2020-05-20 15:26:01 +01:00
parent 52eeabc5bb
commit b1516f18be
2 changed files with 22 additions and 2 deletions

View File

@ -1,5 +1,6 @@
import hashlib import hashlib
from urllib.parse import urlparse from urllib.parse import urlparse
import datetime
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
from Crypto import Random from Crypto import Random
@ -7,6 +8,7 @@ from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15 #pylint: disable=no-name-in-module from Crypto.Signature import pkcs1_15 #pylint: disable=no-name-in-module
from Crypto.Hash import SHA256 from Crypto.Hash import SHA256
MAX_SIGNATURE_AGE = 300
def create_key_pair(): def create_key_pair():
random_generator = Random.new().read random_generator = Random.new().read
@ -77,6 +79,9 @@ class Signature:
def verify(self, public_key, request): def verify(self, public_key, request):
''' verify rsa signature ''' ''' verify rsa signature '''
if http_date_age(request.headers['date']) > MAX_SIGNATURE_AGE:
raise ValueError(
"Request too old: %s" % (request.headers['date'],))
public_key = RSA.import_key(public_key) public_key = RSA.import_key(public_key)
comparison_string = [] comparison_string = []
@ -99,3 +104,8 @@ class Signature:
# raises a ValueError if it fails # raises a ValueError if it fails
signer.verify(digest, self.signature) signer.verify(digest, self.signature)
def http_date_age(datestr):
parsed = datetime.datetime.strptime(datestr, '%a, %d %b %Y %H:%M:%S GMT')
delta = datetime.datetime.utcnow() - parsed
return delta.total_seconds()

View File

@ -1,3 +1,4 @@
import time
from collections import namedtuple from collections import namedtuple
from urllib.parse import urlsplit from urllib.parse import urlsplit
@ -51,8 +52,9 @@ class Signature(TestCase):
sender, sender,
signer=None, signer=None,
send_data=None, send_data=None,
digest=None): digest=None,
now = http_date() date=None):
now = date or http_date()
data = get_follow_data(sender, self.rat) data = get_follow_data(sender, self.rat)
signature = make_signature( signature = make_signature(
signer or sender, self.rat.inbox, now, digest or make_digest(data)) signer or sender, self.rat.inbox, now, digest or make_digest(data))
@ -105,3 +107,11 @@ class Signature(TestCase):
self.mouse, self.mouse,
digest='SHA-256=AAAAAAAAAAAAAAAAAA') digest='SHA-256=AAAAAAAAAAAAAAAAAA')
self.assertEqual(response.status_code, 401) self.assertEqual(response.status_code, 401)
def test_old_message(self):
'''Old messages should be rejected to prevent replay attacks.'''
response = self.send_test_request(
self.mouse,
date=http_date(time.time() - 301)
)
self.assertEqual(response.status_code, 401)