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

Hardware ID and Release Counter (Resolved Merge Conflicts, Cleaner Code and Tests) #157

Open
wants to merge 4 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
71 changes: 69 additions & 2 deletions demo/demo_director.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ def clean_slate(use_new_keys=False):

print(LOG_PREFIX + 'Signing and hosting initial repository metadata')

add_target_to_director(uptane.WORKING_DIR + '/demo/images/INFO1.0.txt',
'INFO1.0.txt', vin, 'INFO' + vin, hardware_id='info', release_counter=0)
add_target_to_director(uptane.WORKING_DIR + '/demo/images/TCU1.0.txt',
'TCU1.0.txt', vin, 'TCU' + vin, hardware_id='tcu', release_counter=0)
add_target_to_director(uptane.WORKING_DIR + '/demo/images/TCU1.1.txt',
'TCU1.1.txt', vin, 'TCU' + vin, hardware_id='tcu', release_counter=1)
add_target_to_director(uptane.WORKING_DIR + '/demo/images/TCU1.2.txt',
'TCU1.2.txt', vin, 'TCU' + vin, hardware_id='tcu', release_counter=2)
add_target_to_director(uptane.WORKING_DIR + '/demo/images/BCU1.0.txt',
'BCU1.0.txt', vin, 'BCU' + vin, hardware_id='bcu', release_counter=0)
add_target_to_director(uptane.WORKING_DIR + '/demo/images/BCU1.1.txt',
'BCU1.1.txt', vin, 'BCU' + vin, hardware_id='bcu', release_counter=0)
add_target_to_director(uptane.WORKING_DIR + '/demo/images/BCU1.2.txt',
'BCU1.2.txt', vin, 'BCU' + vin, hardware_id='bcu', release_counter=0)

write_to_live()

host()
Expand Down Expand Up @@ -590,7 +605,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, release_counter):
"""
For use in attacks and more specific demonstration.

Expand All @@ -615,6 +631,12 @@ 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
#TODO

release_counter
#TODO

"""
uptane.formats.VIN_SCHEMA.check_match(vin)
uptane.formats.ECU_SERIAL_SCHEMA.check_match(ecu_serial)
Expand All @@ -640,7 +662,8 @@ 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=hardware_id,
release_counter=release_counter)



Expand Down Expand Up @@ -1234,3 +1257,47 @@ def kill_server():
str(repo_server_process.pid))
repo_server_process.kill()
repo_server_process = None




def image_rollback_attack(firmware_fname, ecu_serial = '22222',
vin = '111', release_counter = 0, hardware_id = "SecondaryECU101"):
"""
Tries to install an image with a lower release counter on the ecu. Should be stopped.
Default release counter of our ECUs is set to 1.
"""
print("ATTACK: IMAGE ROLLBACK ATTACK, an attempt to install a firmware with lower release counter than that of the ECU")
filepath_in_repo = firmware_fname
add_target_to_director(firmware_fname, filepath_in_repo, vin, ecu_serial, hardware_id, release_counter)
write_to_live(vin_to_update = vin)





def confused_bundle_attack(firmware_fname, ecu_serial = '22222', vin = '111', release_counter = 0, hardware_id = "SecondaryECU101"):
"""
Assumes a compromised director.
Tries to install images with release counters that don't match the other image repositories.
"""
print("ATTACK: confused_bundle_attack, "
"an attempt to install a compromised image with a "
"release_counter that doesn't match that of other repositories.")
filepath_in_repo = firmware_fname
add_target_to_director(firmware_fname, filepath_in_repo, vin, ecu_serial, hardware_id, release_counter)
write_to_live(vin_to_update = vin)





def sneaky_director_attack(firmware_fname, ecu_serial = '22222', vin = '111', release_counter = 3, hardware_id = "NotARealSecondaryECU101"):
"""
Assumes a compromised director.
Tries to install an image on an ECU that is not meant for that particular ECU through leveraging the ECU serial.
"""
print("ATTACK: SNEAKY DIRECTOR ATTACK. Tries to install an image on an ECU that is not meant for that particular ECU through leveraging the ECU serial.")
filepath_in_repo = firmware_fname
add_target_to_director(firmware_fname, filepath_in_repo, vin, ecu_serial, hardware_id, release_counter)
write_to_live(vin_to_update = vin)
105 changes: 95 additions & 10 deletions demo/demo_image_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,20 @@ 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',
hardware_id='info', release_counter=0)
add_target_to_imagerepo('demo/images/TCU1.0.txt', 'TCU1.0.txt',
hardware_id='tcu', release_counter=0)
add_target_to_imagerepo('demo/images/TCU1.1.txt', 'TCU1.1.txt',
hardware_id='tcu', release_counter=1)
add_target_to_imagerepo('demo/images/TCU1.2.txt', 'TCU1.2.txt',
hardware_id='tcu', release_counter=2)
add_target_to_imagerepo('demo/images/BCU1.0.txt', 'BCU1.0.txt',
hardware_id='bcu', release_counter=0)
add_target_to_imagerepo('demo/images/BCU1.1.txt', 'BCU1.1.txt',
hardware_id='bcu', release_counter=0)
add_target_to_imagerepo('demo/images/BCU1.2.txt', 'BCU1.2.txt',
hardware_id='bcu', release_counter=0)

print(LOG_PREFIX + 'Signing and hosting initial repository metadata')

Expand Down Expand Up @@ -172,7 +178,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,
release_counter):
"""
For use in attacks and more specific demonstration.

Expand All @@ -191,7 +198,21 @@ 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 unique identifier for an ECU through it's hardware ID.
Conforms to uptane.formats.HARDWARE_ID_SCHEMA.
This is used to prevent a compromised director
from causing an ECU to download an image not intended for it.

release_counter
An integer to track the version number of the image installed.
Conforms to uptane.formats.RELEASE_COUNTER_SCHEMA.
This is used to prevent a compromised director from
causing an ECU to download an outdated image or an older
one with known vulnerabilities.

"""
global repo

tuf.formats.RELPATH_SCHEMA.check_match(target_fname)
Expand All @@ -203,6 +224,14 @@ def add_target_to_imagerepo(target_fname, filepath_in_repo):

shutil.copy(target_fname, destination_filepath)

custom = {}
custom['hardware_id'] = hardware_id
custom['release_counter'] = release_counter

# If custom is empty, pass None, which is what TUF expects instead of {}.
repo.targets.add_target(
destination_filepath, custom=custom if custom else None)

repo.targets.add_target(destination_filepath)


Expand Down Expand Up @@ -472,6 +501,62 @@ def undo_keyed_arbitrary_package_attack(target_filepath):



def image_rollback_attack(firmware_fname, release_counter = 0,
hardware_id = "SecondaryPotato101"):
"""
Assumes a compromised director.
Tries to install an image with a lower release counter on the ecu. Should be stopped.
Default release counter of our ECUs is set to 1.
"""
print("ATTACK: IMAGE ROLLBACK ATTACK, an attempt to install a firmware "
"with lower release counter than that of the ECU")
filepath_in_repo = firmware_fname
open(firmware_fname, 'w').write('Fresh firmware image')
add_target_to_imagerepo(firmware_fname, filepath_in_repo, release_counter, hardware_id)
write_to_live()





def confused_bundle_attack(firmware_fname, release_counter = 3,
hardware_id = "SecondaryPotato101"):
"""
Assumes a compromised director.
Tries to install images with release counters that don't match the other
image repositories.
"""
print("ATTACK: confused_bundle_attack, an attempt to install a compromised "
"image with a release_counter that doesn't match that of other "
"repositories.")
filepath_in_repo = firmware_fname
open(firmware_fname, 'w').write('Fresh firmware image')
add_target_to_imagerepo(firmware_fname, filepath_in_repo, release_counter, hardware_id)
write_to_live()





def sneaky_director_attack(firmware_fname, release_counter = 3,
hardware_id = "SecondaryPotato101"):
"""
Assumes a compromised director.
Tries to install an image on an ECU that is not meant
for that particular ECU through its ECU.
"""
print("ATTACK: SNEAKY DIRECTOR ATTACK. Tries to install an image on an ECU "
"that is not meant for that particular ECU through "
"leveraging the ECU serial.")
filepath_in_repo = firmware_fname
open(firmware_fname, 'w').write('Fresh firmware image')
add_target_to_imagerepo(firmware_fname, filepath_in_repo, release_counter, hardware_id)
write_to_live()





def add_target_and_write_to_live(filename, file_content):
"""
High-level version of add_target_to_imagerepo() that creates the target
Expand Down
25 changes: 24 additions & 1 deletion 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 = 'Infotainment101'
_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
_release_counter = release_counter
_hardware_id = hardware_id

# if client_directory_name is not None:
# CLIENT_DIRECTORY = client_directory_name
Expand Down Expand Up @@ -139,6 +147,8 @@ def clean_slate(
vin=_vin,
ecu_serial=_ecu_serial,
primary_key=ecu_key,
hardware_id = _hardware_id,
release_counter = _release_counter,
time=clock,
timeserver_public_key=key_timeserver_pub)

Expand Down Expand Up @@ -306,6 +316,19 @@ def update_cycle():
else:
raise

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.


Expand Down
24 changes: 21 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 = 'SecondaryInfotainment111'
_release_counter = 0
_primary_host = demo.PRIMARY_SERVER_HOST
_primary_port = demo.PRIMARY_SERVER_DEFAULT_PORT
firmware_filename = 'secondary_firmware.txt'
Expand All @@ -79,7 +81,9 @@ 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):
"""
"""

Expand All @@ -91,6 +95,8 @@ def clean_slate(
global nonce
global CLIENT_DIRECTORY
global attacks_detected
global _hardware_id
global _release_counter

_vin = vin
_ecu_serial = ecu_serial
Expand Down Expand Up @@ -152,6 +158,8 @@ def clean_slate(
vin=_vin,
ecu_serial=_ecu_serial,
ecu_key=ecu_key,
hardware_id = _hardware_id,
release_counter= _release_counter,
time=clock,
firmware_fileinfo=factory_firmware_fileinfo,
timeserver_public_key=key_timeserver_pub)
Expand Down Expand Up @@ -329,8 +337,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.ImageRollBack:
print_banner(BANNER_DEFENDED, color=WHITE+DARK_BLUE_BG,
text='The Director has instructed us to download an image'
' that has a lower release counter. This image has'
' been rejected.', sound=TADA)
generate_signed_ecu_manifest()
submit_ecu_manifest_to_primary()
return

# As part of the process_metadata call, the secondary will have saved
# validated target info for targets intended for it in
Expand Down Expand Up @@ -483,6 +499,8 @@ def update_cycle():
# 2. Set the fileinfo in the secondary_ecu object to the target info for the
# new firmware.
secondary_ecu.firmware_fileinfo = expected_target_info
secondary_ecu.update_release_counter(
expected_target_info['fileinfo']['custom']['release_counter'])


with open(current_firmware_filepath, 'rb') as file_object:
Expand Down
Loading