Research Project - Securing the In-Vehicle CAN Bus
Post
Cancel

# Research Project - Securing the In-Vehicle CAN Bus

An increasing number of external interfaces allows adversaries to virtually break into modern road vehicles. For this reason, researchers came up with multiple security frameworks for in-vehicle networks, in order to prevent intruders from imposing safety threats on passengers. In particular, authentication has been added to in-vehicle traffic, such that forged messages can be detected. Additionally, encryption is applied on specific message frames, if the passenger’s privacy were in danger. However, efficient means to distribute cryptographic keys on heterogeneous automotive systems are often missing. The goal of this project thus was to build an exemplary in-vehicle CAN network and provide a proof-of-concept implementation for implicit certificates for a CAN-bus based system.

Outcome of the project: While in the current state-of-art, any connected device on the CAN-bus would be able to issue requests to the car-control board, thus being able to control the speed, brakes, RPM etc. of the car, which could lead to devestating outcomes, my colleague and I managed to implement an efficient proof-of-concept to exclude such potential attackers from the CAN-bus based system by means of a smart key-distribution scheme and implicit certificates. In the short video on the top, it can be seen that the first device (valid network node) can successfully send valid data/messages to the car-control board. However, the second device’s messages (a device that connected after the network configuration and the system boot) are ignored, as it is recognized as an potential attacker.

The following documentation provides an overview of the project:

# Hardware Setup

## CAN-Bus

We connect all the nodes by means of a selfmade twisted pair wire. Both ends of the bus are terminated with one 120 Ohm resistor each. The connection is H-H-H and L-L-L (All CANH are connected and all CANL are connected).

In case nodes are intended to be designated the “end of the bus” nodes permanently, one can also solder a connection on the board to use an 120 Ohm resistor which already exists on all of the boards. This feature was not used in our implementation and is thus open for future use if wanted.

CAN Bus Setup using a breadboard and jumping wires. Further, two 120 Ohm resistors are needed at the end of each breadboard.

## Setup RaspberryPi with CAN/CAN-FD Shield

### General Raspbian Setup

1) Copy a raspbian image to an SD card 2) If SSH is not enabled by default, you can enable it by creating an empty text file called “ssh” in the raspbian boot directory on the SD card. 3) If HDMI is needed, you have to add following two lines in the /boot/config.txt:
 hdmi_force_hotplug=1 hdmi_drive=2  4) To enable static IP addresses modify the file /etc/dhcpcd.conf as follows:

1 2 3 4 interface eth0 static ip_address=<IP> static routers=<IP of router> [Optional] static domain_name_servers=<IP of DNS> [Optional] 

### CAN/CAN-FD Shield extensions for the Raspberry Pi

1) CAN Shield Raspberry Pi 3 B+ with a PiCAN-Shield

• Modify the /boot/config.txt file:  dtparam=spi=on dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=25 dtoverlay=spi-bcm2835-overlay 
• Afterwards put following line into the /etc/rc.local file to bring up the CAN interface automatically:
 sudo /sbin/ip link set can0 up type can bitrate 500000 

• Install CAN-Utils
• Reboot
• Test the installation:
• Send a single CAN-Frame
 cansend can0 7DF#0201050000000000 

• Listen on the CAN-Bus
1 candump can0 

2) CAN-FD Shield Raspberry Pi 3 B+ with a PiCAN-FD-Shield

• Download the kernel patch from https://www.dropbox.com/s/n0s31lvgfe8enb6/mcp2517fd-rasp1%2B2%2B3_working.tar?dl=0
• Copy the file to the root directory then untar the files:
• sudo cp mcp2517fd-rasp1+2+3_working.tar /
• cd /
• sudo tar –xf mcp2517fd-rasp1+2+3_ working.tar
• Modify the /boot/config.txt file:
1 2 3 4 5 6 7 8 core_freq=250 kernel=ms7/zImage device_tree=ms7/bcm2710-rpi-3-b.dtb overlay_prefix=ms7/overlays dtoverlay=mcp2517fd-can0 dtparam=interrupt=25 dtparam=oscillator=40000000 dtparam=i2c_arm=on 
• Afterwards put following line into the /etc/rc.local file to bring up the CAN interface automatically:
1 sudo /sbin/ip link set can0 up type can bitrate 500000 dbitrate 2000000 fd on sample-point .8 dsample-point .8 
• Install CAN-Utils
• Reboot
• Test the installation:
• Send a single CAN-FD-Frame
1 cansend can0 7df##05555555555555555 
• Listen on the CAN-FD-Bus
1 candump can0 
• IMPORTANT - When sending multiple CAN-FD messages, the linux kernel driver for the CAN-FD shield crashes, thus the CAN-interface won’t respond until you reboot the whole device. This makes the current state of the shield unusable for the project. The bug is currently under investigation.(Latest status can be found here: https://github.com/msperl/linux-rpi/issues/6)

## ESP Dependencies and Setup

This section describes how to get to run our hard and software.

### Install Software Dependencies

The Xtensa Toolchain and ESP-IDF are required in addition to a set of libraries and tools available in many Linux distributions.

On Ubuntu, one can do the following:

1 2 3 4 5 6 7 sudo apt install gcc git wget make libncurses-dev flex bison gperf python python-serial wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz tar xf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz git clone -b v3.1.1 --recursive https://github.com/espressif/esp-idf.git cd esp-idf git checkout a62cbfec9ab681bddf8f8e45d9949b1b1f67a2ec git submodule update 

### ESP32 USB Device Configuraiton

#### Step 1

It is recommended to make the boards available under a constant and recognizable name by using the supplied udev-rules (see seceng-can-implicit.rules for details).

To allow the current user to access USB devices directly, add the user to the dialout group, e.g. by using

1 $sudo adduser$(id -un) dialout 

#### Step 2

In order to work with upcomming commands/setup you must use the atalla USB 3.0 Hub with the devices plugged in from top to bottom.

First of all you need to execute the find_device_names.sh script. This will produce the following output:

1 2 3 4 5 6 7 $./find_device_names.sh | grep "USB" /dev/bus/usb/002/039 - 1a86_USB2.0-Serial /dev/ttyUSB1 - 1a86_USB2.0-Serial /dev/ttyUSB2 - 1a86_USB2.0-Serial /dev/bus/usb/002/040 - 1a86_USB2.0-Serial /dev/bus/usb/002/038 - 1a86_USB2.0-Serial /dev/ttyUSB0 - 1a86_USB2.0-Serial  Now you need to identifiy which of the usb devices matches your physical usb hub. In our case it’s the /dev/ttyUSB0, /dev/ttyUSB1, /dev/ttyUSB2, as we have plugged in three ESP32 devices. Afterwards you can get the needed information for setting up the udev-rules by executing following command: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33$ udevadm info --attribute-walk --name=/dev/ttyUSB0 looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.1': KERNELS=="2-3.1.1" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="ff" ATTRS{bDeviceProtocol}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="8" ATTRS{bMaxPower}=="98mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="0263" ATTRS{bmAttributes}=="80" ATTRS{busnum}=="2" ATTRS{configuration}=="" ATTRS{devnum}=="38" ATTRS{devpath}=="3.1.1" ATTRS{idProduct}=="7523" ATTRS{idVendor}=="1a86" ATTRS{ltm_capable}=="no" ATTRS{maxchild}=="0" ATTRS{product}=="USB2.0-Serial" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{rx_lanes}=="1" ATTRS{speed}=="12" ATTRS{tx_lanes}=="1" ATTRS{urbnum}=="13" ATTRS{version}==" 1.10" 

Inside of the output you need to look for the idProduct (7523) as well as the idVendor (1a86). Futhermore you need the devpath information for each single usb device. You can get this by executing the following commands:

1 2 3 4 $udevadm info --attribute-walk --name=/dev/ttyUSB0 | grep "looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.1/2-3.1.1:1.0/ttyUSB0': looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.1/2-3.1.1:1.0': looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.1':  1 2 3 4$ udevadm info --attribute-walk --name=/dev/ttyUSB1 | grep "looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.2/2-3.1.2:1.0/ttyUSB1': looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.2/2-3.1.2:1.0': looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.2': 
1 2 3 4 $udevadm info --attribute-walk --name=/dev/ttyUSB2 | grep "looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/" looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.3/2-3.1.3:1.0/ttyUSB2': looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.3/2-3.1.3:1.0': looking at parent device '/devices/pci0000:00/0000:00:14.0/usb2/2-3/2-3.1/2-3.1.3':  You can extract the dev path by looking at the last digit of the device’s output. With this information you can now create the udev-rules. ##### UDEV-Rules: (seceng-can-implicit.rules) 1 2 3 4 5 6 7 8 SUBSYSTEM=="tty", ATTRS{idProduct}=="7523", ATTRS{idVendor}=="1a86", \ ATTRS{devpath}=="*.1", SYMLINK+="seceng-can-implicit-b1" SUBSYSTEM=="tty", ATTRS{idProduct}=="7523", ATTRS{idVendor}=="1a86", \ ATTRS{devpath}=="*.2", SYMLINK+="seceng-can-implicit-b2" SUBSYSTEM=="tty", ATTRS{idProduct}=="7523", ATTRS{idVendor}=="1a86", \ ATTRS{devpath}=="*.3", SYMLINK+="seceng-can-implicit-b3"  After adjusting everything inside of the seceng-can-implicit.rules file you need to copy that into your local dev-rules: 1$ cp seceng-can-implicit.rules /etc/udev/rules.d 

Keep in mind that the device order in the usb hub must NOT be changed after configuring the udev-rules.

### Environment Variables

Edit config.mk and provide the variables PATH and IDF_PATH. If you downloaded the files like suggested above, the following might work:

1 2 PATH := $(PATH):./esp/xtensa-esp32-elf/bin IDF_PATH :=$(PATH):./esp-idf 

Alternatively, provide absolute paths as can be seen in the existing config.mk for our systems.

You should be able to call make export and see two export statements for defining the variable in the current shell if wanted.

### Optional: Test Compiling and Flashing with “Hello World”

The “Hello World” example supplied with ESP-IDF can be invoked by calling the two export statements from the previous section and continuing as follows:

### Timing

For the evaluation of the application, we’ve come up with several test-scenarios that show the impact of the setup variables on the duration of the group-key establishment protocol. The experiements were repeated 5 times for each setting (the number of measurements might seem pretty low for an evaluation but as we have dedicated test network for the experiments i.e no other communication, no other devices, no noise etc, we consider it to be sufficient). Afterwards, we computed the average of the results i.e the following measurement values within the tables are the average values of the respective timings in milliseconds (ms). In general we can say, that the measured values were very constant, so there is a low deviation.

#### Increasing the member number per group (1 Group, 2 Gateways, 5 Nodes)

Increasing the member number per group while having a constant number of groups (1), gateways (2) and participating devices (5). The results show that the group-key time increases linearly, which is quite obvious, as for every member of the group an additional request for the group-key input has to be sent. Furthermore, the CA has to send one additional message, containing the group key, for each additional member in the group.

Category 1 Member 2 Member 3 Member
Certificate Time 1269.2 1293.6 1295.0
Session Key Time 1111.8 1102.0 1103.3
Group Key Time 41.4 103.0 134.8
Total Time 2475.6 2573.8 2589.5

#### Increasing the number of groups (3 Members per group, 2 Gateways, 5 Nodes)

Increasing the number of groups while having a constant group member number (3), gateways (2) and participating devices (5). Our guess was, that the group-key time here also increases linearly, as for every additional group, the CA has to execute an additional round of group-key generation. The results confirm this thesis. Furthermore, our experiments have shown, that the ESP32 devices can handle at maximum 163 groups each with 3 members, before it runs out of memory.

Category 1 Group 2 Groups 5 Groups 10 Groups 50 Groups 100 Groups
Certificate Time 1295.0 1300.4 1299.8 1291.2 1274.6 1286.2
Session Key Time 1103.3 1118.8 1121.8 1114.6 1116.2 1152.8
Group Key Time 134.8 304.8 848.4 1691.4 8518.0 17255.8
Total Time 2589.5 2776.2 3324.6 4150.2 10961.4 39609.8

#### Measuring the network effect

In these test scenarios, we wanted to see whether the distribution of devices across multiple networks (in our case 2) had an impact on performance. Since additional communication messages are needed, e.g. if the YOUR_TURN message is sent to the next device via Ethernet instead of simply publishing it on the same CAN bus, we thought that this would have a drastic effect. However, the results have shown that it only has a minor impact on the performance. This means, that several CAN-Buses can be efficiently connected via Ethernet.

##### 1 Device (1 Member, 1 Group)
Category 1 Network (1 Device)
Certificate Time 425.0
Session Key Time 292.0
Group Key Time 43.0
Total Time 768.0
##### 2 Devices (2 Members, 1 Group)
Category 1 Network (2 Devices) 2 Networks (1 Device per Network)
Certificate Time 741.0 753.6
Session Key Time 598.0 608.0
Group Key Time 80.8 106.6
Total Time 1428.6 1504.2
##### 4 Devices (2 Members, 1 Group)
Category 1 Network (4 Devices) 2 Networks (2 Device per Network)
Certificate Time 1285.0 1302.4
Session Key Time 1107.6 1111.8
Group Key Time 83.2 110.0
Total Time 2486.4 2597.0

#### Increasing the number of devices

The last test-scenario is about measuring the impact on the performance when increasing the number of devices. The settings were set to 1 network, 2 group members, 1 group. Our results show, that the certificate time as well as the session key time increase linearly as the number of devices on the network is increased. This is due to the fact that the Cert and Session key establishment has to be done for every device i.e for each additional device, this process has to be executed an additional time. One now might ask why the group key time also changes when increasing from the number from 1 to 2 devices. Due to the outbreak of the coronavirus in Passau, we only had several measurements left. Therefore, our first measurement with 1 device has 1 member per group, while the other two measurements were done with 2 members per group. Usually, if the group member number is kept constant, the group key time is also constant.

Category 1 Device 2 Devices 4 Devices
Certificate Time 425.0 741.0 1285.0
Session Key Time 292.0 598.0 1107.6
Group Key Time 43.0 80.8 83.2
Total Time 768.0 1428.6 2486.4