From c5163f89529b794c69b636e23faad5fdd20f5087 Mon Sep 17 00:00:00 2001 From: fulder Date: Wed, 26 Aug 2020 16:45:29 +0200 Subject: [PATCH 1/4] Throw exception on algorithm signature parameter and dervice algorithm mismatch --- httpsig/verify.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/httpsig/verify.py b/httpsig/verify.py index 055a74a..7158c7b 100644 --- a/httpsig/verify.py +++ b/httpsig/verify.py @@ -90,6 +90,11 @@ def __init__(self, headers, secret, required_headers=None, method=None, self.path = path self.host = host + if 'algorithm' in self.auth_dict and self.auth_dict['algorithm'] != self.algorithm: + raise HttpSigException( + "Algorithm mismath, signature parameter algorithm was: {}, but algorithm dervice from key is: {}".format( + self.auth_dict['algorithm'], self.algorithm)) + if self.auth_dict['algorithm'] != DEFAULT_ALGORITHM: print("Algorithm: {} is deprecated please update to {}".format(self.auth_dict['algorithm'], DEFAULT_ALGORITHM)) elif self.auth_dict['algorithm'] == DEFAULT_ALGORITHM and sign_algorithm is None: From 912ff8594b6504cf223bd112f99be88b2c7132b7 Mon Sep 17 00:00:00 2001 From: fulder Date: Wed, 26 Aug 2020 17:02:28 +0200 Subject: [PATCH 2/4] Return false in verify on algorith mismatch --- httpsig/tests/test_verify.py | 14 ++++++++++++++ httpsig/verify.py | 14 ++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/httpsig/tests/test_verify.py b/httpsig/tests/test_verify.py index d5f9785..0e1ada6 100755 --- a/httpsig/tests/test_verify.py +++ b/httpsig/tests/test_verify.py @@ -242,3 +242,17 @@ def setUp(self): self.sign_secret = private_key self.verify_secret = public_key self.sign_algorithm = PSS(salt_length=0) + + def test_algorithm_mismatch(self): + unsigned = { + 'Date': self.header_date + } + + hs = HeaderSigner( + key_id="Test", secret=self.sign_secret, algorithm=self.algorithm, + sign_header=self.sign_header, sign_algorithm=self.sign_algorithm) + signed = hs.sign(unsigned) + + hv = HeaderVerifier( + headers=signed, secret=self.verify_secret, sign_header=self.sign_header, algorithm="rsa-sha256", sign_algorithm=self.sign_algorithm) + self.assertFalse(hv.verify()) \ No newline at end of file diff --git a/httpsig/verify.py b/httpsig/verify.py index 7158c7b..33cb2b2 100644 --- a/httpsig/verify.py +++ b/httpsig/verify.py @@ -51,7 +51,7 @@ class HeaderVerifier(Verifier): """ def __init__(self, headers, secret, required_headers=None, method=None, - path=None, host=None, sign_header='authorization', sign_algorithm=None): + path=None, host=None, sign_header='authorization', algorithm=None, sign_algorithm=None): """ Instantiate a HeaderVerifier object. @@ -70,6 +70,7 @@ def __init__(self, headers, secret, required_headers=None, method=None, header, if not supplied in :param:headers. :param sign_header: Optional. The header where the signature is. Default is 'authorization'. + :param algorithm: Algorithm derived from keyId (required for draft version >= 12) :param sign_algorithm: Required for 'hs2019' algorithm, specifies the digital signature algorithm (derived from keyId) to use. """ @@ -89,11 +90,7 @@ def __init__(self, headers, secret, required_headers=None, method=None, self.method = method self.path = path self.host = host - - if 'algorithm' in self.auth_dict and self.auth_dict['algorithm'] != self.algorithm: - raise HttpSigException( - "Algorithm mismath, signature parameter algorithm was: {}, but algorithm dervice from key is: {}".format( - self.auth_dict['algorithm'], self.algorithm)) + self.derived_algorithm = algorithm if self.auth_dict['algorithm'] != DEFAULT_ALGORITHM: print("Algorithm: {} is deprecated please update to {}".format(self.auth_dict['algorithm'], DEFAULT_ALGORITHM)) @@ -112,6 +109,11 @@ def verify(self): not found in the signature. Returns True or False. """ + if 'algorithm' in self.auth_dict and self.derived_algorithm is not None and self.auth_dict['algorithm'] != self.derived_algorithm: + print("Algorithm mismatch, signature parameter algorithm was: {}, but algorithm derived from key is: {}".format( + self.auth_dict['algorithm'], self.derived_algorithm)) + return False + auth_headers = self.auth_dict.get('headers', 'date').split(' ') if len(set(self.required_headers) - set(auth_headers)) > 0: From 822cad0879802effe8c2aee5da1303fcfd3d8a39 Mon Sep 17 00:00:00 2001 From: fulder Date: Wed, 26 Aug 2020 17:03:34 +0200 Subject: [PATCH 3/4] Add test for correct derived algorithm --- httpsig/tests/test_verify.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/httpsig/tests/test_verify.py b/httpsig/tests/test_verify.py index 0e1ada6..57fd562 100755 --- a/httpsig/tests/test_verify.py +++ b/httpsig/tests/test_verify.py @@ -255,4 +255,18 @@ def test_algorithm_mismatch(self): hv = HeaderVerifier( headers=signed, secret=self.verify_secret, sign_header=self.sign_header, algorithm="rsa-sha256", sign_algorithm=self.sign_algorithm) - self.assertFalse(hv.verify()) \ No newline at end of file + self.assertFalse(hv.verify()) + + def test_correct_derviced_algorithm(self): + unsigned = { + 'Date': self.header_date + } + + hs = HeaderSigner( + key_id="Test", secret=self.sign_secret, algorithm=self.algorithm, + sign_header=self.sign_header, sign_algorithm=self.sign_algorithm) + signed = hs.sign(unsigned) + + hv = HeaderVerifier( + headers=signed, secret=self.verify_secret, sign_header=self.sign_header, algorithm="hs2019", sign_algorithm=self.sign_algorithm) + self.assertTrue(hv.verify()) \ No newline at end of file From 251cce9be722662c166e9b2124c6f25e09389ccb Mon Sep 17 00:00:00 2001 From: fulder Date: Thu, 27 Aug 2020 10:16:39 +0200 Subject: [PATCH 4/4] Move algorithm checks to Signer --- httpsig/sign.py | 2 ++ httpsig/verify.py | 7 +------ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/httpsig/sign.py b/httpsig/sign.py index 0b1ec07..4a52645 100644 --- a/httpsig/sign.py +++ b/httpsig/sign.py @@ -30,6 +30,8 @@ def __init__(self, secret, algorithm=None, sign_algorithm=None): if algorithm != DEFAULT_ALGORITHM: print("Algorithm: {} is deprecated please update to {}".format(algorithm, DEFAULT_ALGORITHM)) + elif algorithm == DEFAULT_ALGORITHM and sign_algorithm is None: + raise HttpSigException("Required sign algorithm for {} algorithm not set".format(DEFAULT_ALGORITHM)) if isinstance(secret, six.string_types): secret = secret.encode("ascii") diff --git a/httpsig/verify.py b/httpsig/verify.py index 33cb2b2..4c1b4d3 100644 --- a/httpsig/verify.py +++ b/httpsig/verify.py @@ -92,13 +92,8 @@ def __init__(self, headers, secret, required_headers=None, method=None, self.host = host self.derived_algorithm = algorithm - if self.auth_dict['algorithm'] != DEFAULT_ALGORITHM: - print("Algorithm: {} is deprecated please update to {}".format(self.auth_dict['algorithm'], DEFAULT_ALGORITHM)) - elif self.auth_dict['algorithm'] == DEFAULT_ALGORITHM and sign_algorithm is None: - raise HttpSigException("Required sign algorithm for {} algorithm not set".format(DEFAULT_ALGORITHM)) - super(HeaderVerifier, self).__init__( - secret, algorithm=self.auth_dict['algorithm'], sign_algorithm=sign_algorithm) + secret, algorithm=self.auth_dict['algorithm'], sign_algorithm=sign_algorithm) def verify(self): """