def check_cert_chain(testcase, cert_chain): """ Check that the AS's certificate chain can be verified with the issuer certificate. """ testcase.assertIsNotNone(cert_chain) leaf = cert_chain.certificate[1] leaf_pld = jws.decode_payload(leaf) testcase.assertEqual(leaf_pld["version"], cert_chain.version) testcase.assertEqual(leaf_pld["subject"], cert_chain.AS.isd_as_str()) issuer = leaf_pld["issuer"] issuer_ia = issuer["isd_as"] issuer_as = issuer_ia.split('-')[1] issuer_ver = issuer["certificate_version"] # Check that the issuer certificate in the chain is identical to the issuer cert in the DB: issuer_cert = Certificate.objects.get(type=Certificate.ISSUER, AS__as_id=issuer_as, version=issuer_ver) testcase.assertEqual(issuer_cert.certificate, cert_chain.certificate[0]) # Verify the signature issuer_pld = jws.decode_payload(issuer_cert.certificate) issuer_pub_key = issuer_pld["keys"]["issuing"]["key"] sig_valid = jws.verify(leaf["payload"], leaf["protected"], leaf["signature"], issuer_pub_key) testcase.assertTrue(sig_valid)
def check_trc(testcase, isd, expected_core_ases=None, expected_version=None): """ Check the ISD's latest TRC :param ISD isd: :param [str] expected_core_ases: optional, ISD-AS strings for all core ases :param int expected_version: optional, expected version for current TRC. """ if expected_core_ases is None: expected_core_ases = set(as_.as_id for as_ in isd.ases.filter(is_core=True)) trc = isd.trcs.latest_or_none() if len(expected_core_ases) > 0: testcase.assertIsNotNone(trc) if expected_version is not None: testcase.assertEqual(trc.version, expected_version) if trc is None: return trc_pld = jws.decode_payload(trc.trc) testcase.assertEqual(trc_pld['trc_version'], trc.version) testcase.assertEqual(set(trc_pld['primary_ases'].keys()), set(expected_core_ases)) if trc.version > 1: # Check that TRC update is valid prev_trc = isd.trcs.get(version=trc.version - 1) prev_trc_pld = jws.decode_payload(prev_trc.trc) # Minimal check: voters = set(trc_pld['votes'].keys()) allowed_voters = set(prev_trc_pld['primary_ases'].keys()) testcase.assertTrue(voters.issubset(allowed_voters)) testcase.assertGreaterEqual(len(trc_pld['votes']), prev_trc_pld['voting_quorum'])
def check_issuer_cert(testcase, issuer_cert, expected_trc_version=None): """ Check that the issuer certificate can be verified with a TRC. Check that the certificate is issued by the expected_trc_version, if set. """ testcase.assertIsNotNone(issuer_cert) cert = issuer_cert.certificate cert_pld = jws.decode_payload(cert) testcase.assertEqual(cert_pld["version"], issuer_cert.version) testcase.assertEqual(cert_pld["subject"], issuer_cert.AS.isd_as_str()) subject_ia = cert_pld["subject"] subject_as = subject_ia.split('-')[1] trc_version = cert_pld["issuer"]["trc_version"] if expected_trc_version is not None: testcase.assertEqual(trc_version, expected_trc_version) trc = TRC.objects.get(isd=issuer_cert.AS.isd, version=trc_version) trc_pld = jws.decode_payload(trc.trc) issuing_grant_pub_key = trc_pld["primary_ases"][subject_as]["keys"][ "issuing_grant"]["key"] sig_valid = jws.verify(cert["payload"], cert["protected"], cert["signature"], issuing_grant_pub_key) testcase.assertTrue(sig_valid)
def gen_trc_update(self, primary_ases, prev_trc, prev_voting_offline): """ Helper: create update TRC """ # decode prev payload to find next version number # we dont need to do this in production, but here it serves as a little sanity check for # the payload. prev = jws.decode_payload(prev_trc) prev_version = prev["trc_version"] self.assertGreaterEqual(1, prev_version) version = prev_version + 1 # define validity time with arbitrary time offset from previous validity start. # key lifetime is not extended, so validty end is the same # Just for "fun", not really relevant. prev_not_before = datetime.utcfromtimestamp( prev['validity']['not_before']) prev_not_after = datetime.utcfromtimestamp( prev['validity']['not_after']) not_before = prev_not_before + timedelta(days=31) not_after = prev_not_after trc = trcs.generate_trc(self.isd1, version, DEFAULT_TRC_GRACE_PERIOD, not_before, not_after, primary_ases, prev_trc, prev_voting_offline) return trc
def _decode_primary_ases(trc): payload = jws.decode_payload(trc) def _key_info(key_entry): return Key( version=key_entry['key_version'], priv_key=None, pub_key=key_entry['key'], ) def _core_keys(as_entry): return CoreKeys(**{ usage: _key_info(key_entry) for usage, key_entry in as_entry['keys'].items() }) return {as_id: _core_keys(as_entry) for as_id, as_entry in payload['primary_ases'].items()}