def check(self, content, use_emb_key=False, skip_nonce_check=False): """ validate message """ self.logger.debug('Message.check()') # disable signature check if paramter has been set if self.disable_dic['signature_check_disable']: self.logger.error( '**** SIGNATURE_CHECK_DISABLE!!! Severe security issue ****') skip_signature_check = True else: skip_signature_check = False # decode message (result, error_detail, protected, payload, _signature) = decode_message(self.logger, content) account_name = None if result: # decoding successful - check nonce for anti replay protection if skip_nonce_check or self.disable_dic['nonce_check_disable']: # nonce check can be skipped by configuration and in case of key-rollover if self.disable_dic['nonce_check_disable']: self.logger.error( '**** NONCE CHECK DISABLED!!! Severe security issue ****' ) else: self.logger.debug( 'skip nonce check of inner payload during keyrollover') code = 200 message = None detail = None else: (code, message, detail) = self.nonce.check(protected) if code == 200 and not skip_signature_check: # nonce check successful - check signature account_name = self._name_get(protected) signature = Signature(self.debug, self.server_name, self.logger) # we need the decoded protected header to grab a key to verify signature (sig_check, error, error_detail) = signature.check(account_name, content, use_emb_key, protected) if sig_check: code = 200 message = None detail = None else: code = 403 message = error detail = error_detail else: # message could not get decoded code = 400 message = 'urn:ietf:params:acme:error:malformed' detail = error_detail self.logger.debug('Message.check() ended with:{0}'.format(code)) return (code, message, detail, protected, payload, account_name)
def setUp(self): """ setup unittest """ models_mock = MagicMock() models_mock.acme.db_handler.DBstore.return_value = FakeDBStore modules = {'acme.db_handler': models_mock} patch.dict('sys.modules', modules).start() import logging logging.basicConfig(level=logging.CRITICAL) self.logger = logging.getLogger('test_a2c') from acme.signature import Signature self.signature = Signature(False, 'http://tester.local', self.logger)
def _eab_signature_verify(self, content, mac_key): """ verify inner signature """ self.logger.debug('Account._eab_signature_verify()') if content and mac_key: signature = Signature(None, self.server_name, self.logger) jwk_ = json.dumps({'k': mac_key, 'kty': 'oct'}) (sig_check, error) = signature.eab_check(json.dumps(content), jwk_) else: sig_check = False error = None self.logger.debug( 'Account._eab_signature_verify() ended with: {0}'.format( sig_check)) return (sig_check, error)
class TestACMEHandler(unittest.TestCase): """ test class for ACMEHandler """ acme = None def setUp(self): """ setup unittest """ models_mock = MagicMock() models_mock.acme.db_handler.DBstore.return_value = FakeDBStore modules = {'acme.db_handler': models_mock} patch.dict('sys.modules', modules).start() import logging logging.basicConfig(level=logging.CRITICAL) self.logger = logging.getLogger('test_a2c') from acme.signature import Signature self.signature = Signature(False, 'http://tester.local', self.logger) def test_001_signature__jwk_load(self): """ test jwk load """ self.signature.dbstore.jwk_load.return_value = 'foo' self.assertEqual('foo', self.signature._jwk_load(1)) def test_002_signature_check(self): """ test Signature.check() without having content """ self.assertEqual((False, 'urn:ietf:params:acme:error:malformed', None), self.signature.check('foo', None)) @patch('acme.signature.Signature._jwk_load') def test_003_signature_check(self, mock_jwk): """ test Signature.check() while pubkey lookup failed """ mock_jwk.return_value = {} self.assertEqual( (False, 'urn:ietf:params:acme:error:accountDoesNotExist', None), self.signature.check('foo', 1)) @patch('acme.signature.signature_check') @patch('acme.signature.Signature._jwk_load') def test_004_signature_check(self, mock_jwk, mock_sig): """ test successful Signature.check() """ mock_jwk.return_value = {'foo': 'bar'} mock_sig.return_value = (True, None) self.assertEqual((True, None, None), self.signature.check('foo', 1)) def test_005_signature_check(self): """ test successful Signature.check() without account_name and use_emb_key False""" self.assertEqual( (False, 'urn:ietf:params:acme:error:accountDoesNotExist', None), self.signature.check(None, 1, False)) def test_006_signature_check(self): """ test successful Signature.check() without account_name and use_emb_key True but having a corrupted protected header""" protected = {'foo': 'foo'} self.assertEqual( (False, 'urn:ietf:params:acme:error:accountDoesNotExist', None), self.signature.check(None, 1, True, protected)) @patch('acme.signature.signature_check') def test_007_signature_check(self, mock_sig): """ test successful Signature.check() with account_name and use_emb_key True, sigcheck returns something""" mock_sig.return_value = ('result', 'error') self.assertEqual(('result', 'error', None), self.signature.check('foo', 1, True)) @patch('acme.signature.signature_check') def test_008_signature_check(self, mock_sig): """ test successful Signature.check() without account_name and use_emb_key True, sigcheck returns something""" mock_sig.return_value = ('result', 'error') protected = {'url': 'url', 'jwk': 'jwk'} self.assertEqual(('result', 'error', None), self.signature.check(None, 1, True, protected)) def test_009_signature__jwk_load(self): """ test jwk load - dbstore.jwk_load() raises an exception""" self.signature.dbstore.jwk_load.side_effect = Exception( 'exc_sig_jw_load') with self.assertLogs('test_a2c', level='INFO') as lcm: self.signature._jwk_load(1) self.assertIn( 'CRITICAL:test_a2c:acme2certifier database error in Signature._hwk_load(): exc_sig_jw_load', lcm.output)