Skip to content
This repository has been archived by the owner on Mar 29, 2022. It is now read-only.

Implementation of Release Counters and Hardware Identifiers. #194

Open
wants to merge 13 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions demo/demo_director.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,8 @@ def undo_sign_with_compromised_keys_attack(vin=None):



def add_target_to_director(target_fname, filepath_in_repo, vin, ecu_serial):
def add_target_to_director(target_fname, filepath_in_repo, vin, ecu_serial,
hardware_id = None, release_counter = None ):
"""
For use in attacks and more specific demonstration.

Expand All @@ -615,6 +616,16 @@ def add_target_to_director(target_fname, filepath_in_repo, vin, ecu_serial):
The ECU to assign this target to in the targets metadata.
Complies with uptane.formats.ECU_SERIAL_SCHEMA

hardware_id
A uniques idetifier for ECU classifying the ECU based on the hardware
type. This may be used to prevent installation of images with is not
supported by the hardware type.

release_counter
An index to track the version number of the firmware of the ECU.
This is used to prevent the roll-back attack by a compromised
director.

"""
uptane.formats.VIN_SCHEMA.check_match(vin)
uptane.formats.ECU_SERIAL_SCHEMA.check_match(ecu_serial)
Expand All @@ -640,7 +651,7 @@ def add_target_to_director(target_fname, filepath_in_repo, vin, ecu_serial):

# This calls the appropriate vehicle repository.
director_service_instance.add_target_for_ecu(
vin, ecu_serial, destination_filepath)
vin, ecu_serial, destination_filepath, hardware_id, release_counter)



Expand Down Expand Up @@ -1191,7 +1202,8 @@ def clear_vehicle_targets(vin):



def add_target_and_write_to_live(filename, file_content, vin, ecu_serial):
def add_target_and_write_to_live(filename, file_content, vin, ecu_serial,
hardware_id = None, release_counter = None):
"""
High-level version of add_target_to_director() that creates 'filename'
and writes the changes to the live directory repository.
Expand All @@ -1207,7 +1219,7 @@ def add_target_and_write_to_live(filename, file_content, vin, ecu_serial):
# The path that will identify the file in the repository.
filepath_in_repo = filename

add_target_to_director(filename, filepath_in_repo, vin, ecu_serial)
add_target_to_director(filename, filepath_in_repo, vin, ecu_serial, hardware_id, release_counter)
write_to_live(vin_to_update=vin)


Expand Down
34 changes: 25 additions & 9 deletions demo/demo_image_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,13 @@ def clean_slate(use_new_keys=False):


# Add some starting image files, primarily for use with the web frontend.
add_target_to_imagerepo('demo/images/INFO1.0.txt', 'INFO1.0.txt')
add_target_to_imagerepo('demo/images/TCU1.0.txt', 'TCU1.0.txt')
add_target_to_imagerepo('demo/images/TCU1.1.txt', 'TCU1.1.txt')
add_target_to_imagerepo('demo/images/TCU1.2.txt', 'TCU1.2.txt')
add_target_to_imagerepo('demo/images/BCU1.0.txt', 'BCU1.0.txt')
add_target_to_imagerepo('demo/images/BCU1.1.txt', 'BCU1.1.txt')
add_target_to_imagerepo('demo/images/BCU1.2.txt', 'BCU1.2.txt')
add_target_to_imagerepo('demo/images/INFO1.0.txt', 'INFO1.0.txt', 'TYPE1', '0')
add_target_to_imagerepo('demo/images/TCU1.0.txt', 'TCU1.0.txt', 'TYPE2', '0')
add_target_to_imagerepo('demo/images/TCU1.1.txt', 'TCU1.1.txt', 'TYPE2', '1')
add_target_to_imagerepo('demo/images/TCU1.2.txt', 'TCU1.2.txt', 'TYPE2', '2')
add_target_to_imagerepo('demo/images/BCU1.0.txt', 'BCU1.0.txt', 'TYPE3', '0')
add_target_to_imagerepo('demo/images/BCU1.1.txt', 'BCU1.1.txt', 'TYPE3', '1')
add_target_to_imagerepo('demo/images/BCU1.2.txt', 'BCU1.2.txt', 'TYPE3', '2')


print(LOG_PREFIX + 'Signing and hosting initial repository metadata')
Expand Down Expand Up @@ -172,7 +172,8 @@ def write_to_live():



def add_target_to_imagerepo(target_fname, filepath_in_repo):
def add_target_to_imagerepo(target_fname, filepath_in_repo,
hardware_id = None, release_counter = None):
"""
For use in attacks and more specific demonstration.

Expand All @@ -191,6 +192,16 @@ def add_target_to_imagerepo(target_fname, filepath_in_repo):
This is the name that will identify the file in the repository, and
the filepath it will have relative to the root of the repository's
targets directory.

hardware_id
A uniques idetifier for ECU classifying the ECU based on the hardware
type. This may be used to prevent installation of images with is not
supported by the hardware type.

release_counter
An index to track the version number of the firmware of the ECU.
This is used to prevent the roll-back attack by a compromised
director.
"""
global repo

Expand All @@ -203,7 +214,12 @@ def add_target_to_imagerepo(target_fname, filepath_in_repo):

shutil.copy(target_fname, destination_filepath)

repo.targets.add_target(destination_filepath)
custom = {
'hardware_id': hardware_id,
'release_counter': release_counter
}

repo.targets.add_target(destination_filepath, custom = custom)



Expand Down
27 changes: 25 additions & 2 deletions demo/demo_primary.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@
#_client_directory_name = 'temp_primary' # name for this Primary's directory
_vin = 'democar'
_ecu_serial = 'INFOdemocar'
_hardware_id = 'TYEP1'
_release_counter = 0
# firmware_filename = 'infotainment_firmware.txt'


Expand All @@ -80,16 +82,22 @@ def clean_slate(
use_new_keys=False,
# client_directory_name=None,
vin=_vin,
ecu_serial=_ecu_serial):
ecu_serial=_ecu_serial,
hardware_id = _hardware_id,
release_counter = _release_counter):
"""
"""
global primary_ecu
global CLIENT_DIRECTORY
global _vin
global _ecu_serial
global _hardware_id
global _release_counter
global listener_thread
_vin = vin
_ecu_serial = ecu_serial
_hardware_id = hardware_id
_release_counter = release_counter

# if client_directory_name is not None:
# CLIENT_DIRECTORY = client_directory_name
Expand Down Expand Up @@ -138,6 +146,8 @@ def clean_slate(
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=_vin,
ecu_serial=_ecu_serial,
hardware_id = _hardware_id,
release_counter = _release_counter,
primary_key=ecu_key,
time=clock,
timeserver_public_key=key_timeserver_pub)
Expand Down Expand Up @@ -307,7 +317,20 @@ def update_cycle():
else:
raise

# All targets have now been downloaded.
except uptane.ImageRollBack:
print_banner(BANNER_DEFENDED, color=WHITE + DARK_BLUE_BG,
text='The Director has instructed us to download an image'
' that has a bad release counter and does not match with '
' other repositories. This image has'
' been rejected.', sound=TADA)
except uptane.HardwareIDMismatch:
print_banner(BANNER_DEFENDED, color=WHITE + DARK_BLUE_BG,
text='The Director has instructed us to download an image'
' that is not meant for the stated ECU. HardwareIDdoes not'
' match with other repositorie. This image has'
' been rejected.', sound=TADA)

# All targets have now been downloaded.


# Generate and submit vehicle manifest.
Expand Down
29 changes: 26 additions & 3 deletions demo/demo_secondary.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
CLIENT_DIRECTORY = None
_vin = 'democar'
_ecu_serial = 'TCUdemocar'
_hardware_id = 'TYPE2'
_release_counter = 0
_primary_host = demo.PRIMARY_SERVER_HOST
_primary_port = demo.PRIMARY_SERVER_DEFAULT_PORT
firmware_filename = 'secondary_firmware.txt'
Expand All @@ -79,13 +81,17 @@ def clean_slate(
vin=_vin,
ecu_serial=_ecu_serial,
primary_host=None,
primary_port=None):
primary_port=None,
hardware_id = _hardware_id,
release_counter = _release_counter):
"""
"""

global secondary_ecu
global _vin
global _ecu_serial
global _hardware_id
global _release_counter
global _primary_host
global _primary_port
global nonce
Expand All @@ -94,6 +100,8 @@ def clean_slate(

_vin = vin
_ecu_serial = ecu_serial
_hardware_id = hardware_id
_release_counter = release_counter

if primary_host is not None:
_primary_host = primary_host
Expand Down Expand Up @@ -154,7 +162,9 @@ def clean_slate(
ecu_key=ecu_key,
time=clock,
firmware_fileinfo=factory_firmware_fileinfo,
timeserver_public_key=key_timeserver_pub)
timeserver_public_key=key_timeserver_pub,
hardware_id = _hardware_id,
release_counter = _release_counter)



Expand Down Expand Up @@ -330,7 +340,16 @@ def update_cycle():

# Now tell the Secondary reference implementation code where the archive file
# is and let it expand and validate the metadata.
secondary_ecu.process_metadata(archive_fname)
try:
secondary_ecu.process_metadata(archive_fname)
except uptane.ImageRollBackAttempt:
print_banner(BANNER_DEFENDED, color=WHITE+DARK_BLUE_BG,
text='The director has instructed to download an image'
'that has a lower release conunter as that of the'
'already installed firmware. The image has been rejected.')
generate_signed_ecu_manifest()
submit_ecu_manifest_to_primary()
return


# As part of the process_metadata call, the secondary will have saved
Expand Down Expand Up @@ -514,6 +533,10 @@ def update_cycle():
print(open(os.path.join(CLIENT_DIRECTORY, image_fname)).read())
print('---------------------------------------------------------')

# Now hence the image is installed succesfully, update the release counter
secondary_ecu.update_release_counter(
expected_target_info['fileinfo']['custom']['release_counter']
)

# Submit info on what is currently installed back to the Primary.
generate_signed_ecu_manifest()
Expand Down
20 changes: 20 additions & 0 deletions tests/test_primary.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
NONCE = 5
VIN = 'democar'
PRIMARY_ECU_SERIAL = '00000'
PRIMARY_HARDWARE_IDENTIFIER = ''
PRIMARY_RELEASE_COUNTER = 0



Expand Down Expand Up @@ -176,6 +178,8 @@ def test_01_init(self):
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=5, # INVALID
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id = PRIMARY_HARDWARE_IDENTIFIER,
release_counter = PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key,
time=TestPrimary.initial_time,
timeserver_public_key=TestPrimary.key_timeserver_pub,
Expand All @@ -188,6 +192,8 @@ def test_01_init(self):
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=VIN,
ecu_serial=500, # INVALID
hardware_id=PRIMARY_HARDWARE_IDENTIFIER,
release_counter=PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key,
time=TestPrimary.initial_time,
timeserver_public_key=TestPrimary.key_timeserver_pub,
Expand All @@ -200,6 +206,8 @@ def test_01_init(self):
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=VIN,
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id=PRIMARY_HARDWARE_IDENTIFIER,
release_counter=PRIMARY_RELEASE_COUNTER,
primary_key={''}, # INVALID
time=TestPrimary.initial_time,
timeserver_public_key=TestPrimary.key_timeserver_pub,
Expand All @@ -212,6 +220,8 @@ def test_01_init(self):
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=VIN,
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id=PRIMARY_HARDWARE_IDENTIFIER,
release_counter=PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key,
time='invalid because this is not a time', # INVALID
timeserver_public_key=TestPrimary.key_timeserver_pub,
Expand All @@ -224,6 +234,8 @@ def test_01_init(self):
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=VIN,
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id = PRIMARY_HARDWARE_IDENTIFIER,
release_counter = PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key, time=TestPrimary.initial_time,
timeserver_public_key=TestPrimary.initial_time, # INVALID
my_secondaries=[])
Expand All @@ -235,6 +247,8 @@ def test_01_init(self):
director_repo_name=5, #INVALID
vin=VIN,
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id = PRIMARY_HARDWARE_IDENTIFIER,
release_counter = PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key, time=TestPrimary.initial_time,
timeserver_public_key = TestPrimary.key_timeserver_pub,
my_secondaries=[])
Expand All @@ -246,6 +260,8 @@ def test_01_init(self):
director_repo_name= "invalid", #INVALID
vin=VIN,
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id=PRIMARY_HARDWARE_IDENTIFIER,
release_counter=PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key, time=TestPrimary.initial_time,
timeserver_public_key = TestPrimary.key_timeserver_pub,
my_secondaries=[])
Expand All @@ -261,6 +277,8 @@ def test_01_init(self):
director_repo_name=demo.DIRECTOR_REPO_NAME,
vin=VIN,
ecu_serial=PRIMARY_ECU_SERIAL,
hardware_id=PRIMARY_HARDWARE_IDENTIFIER,
release_counter=PRIMARY_RELEASE_COUNTER,
primary_key=TestPrimary.ecu_key,
time=TestPrimary.initial_time,
timeserver_public_key=TestPrimary.key_timeserver_pub)
Expand All @@ -272,6 +290,8 @@ def test_01_init(self):
self.assertEqual([], TestPrimary.instance.nonces_sent)
self.assertEqual(VIN, TestPrimary.instance.vin)
self.assertEqual(PRIMARY_ECU_SERIAL, TestPrimary.instance.ecu_serial)
self.assertEqual(PRIMARY_HARDWARE_IDENTIFIER, TestPrimary.instance.hardware_id)
self.assertEqual(PRIMARY_RELEASE_COUNTER, TestPrimary.instance.release_counter)
self.assertEqual(TestPrimary.ecu_key, TestPrimary.instance.primary_key)
self.assertEqual(dict(), TestPrimary.instance.ecu_manifests)
self.assertEqual(
Expand Down
2 changes: 2 additions & 0 deletions tests/test_secondary.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ def test_01_init(self):
ecu_serial=ecu_serial,
ecu_key=TestSecondary.secondary_ecu_key,
time=TestSecondary.initial_time,
hardware_id= 'TYPE2',
release_counter = 0,
timeserver_public_key=TestSecondary.key_timeserver_pub,
firmware_fileinfo=factory_firmware_fileinfo,
director_public_key=None,
Expand Down
12 changes: 12 additions & 0 deletions uptane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ class FailedToEncodeASN1DER(Error):
"""
pass

class HardwareIDMismatch(Error):
"""
Recieved an instruction from director install an image that dosen't match the
hardware type of this ECU.
"""
pass

class ImageRollBackAttempt(Error):
"""
Recieved an instruction to install an image with the release counter value
lower than that of the image currently insatlled on the ECU.
"""

# Logging configuration

Expand Down
Loading