An important aspect of software security is protection against unauthorized software modifications and alterations during application updating and loading new versions. In order to achieve that, various signing and authorisation mechanisms are available.
Nowadays, most embedded devices allow downloading updated software versions and data. The new software can be loaded into the device by using an application called a boot loader. Boot loaders are programs that are stored in the device memory and are able to download data from outside and flash the device.
Usually, the software stored in the device consists of a boot loader, which is kept in the read-only memory, and the operating system or another main application, which is stored in the reprogrammable (often flash) memory. Such an approach makes it possible to modify the executable code and data, and to update or patch the applications. The protection must be provided against unauthorised modification of sensitive code.
Whereas users will be able to modify most of the memory and software functionalities, a boot loader application and a software digest must be kept in a separate, secure memory area, that may be read but cannot be overwritten. Usually Read-Only Memory (ROM), Write-Once Read-Many (WORM) memory, or internal microcontroller flash memory (EEPROM) are used for that purpose. They are initialized by the manufacturer during the production process. At the same time, most of the device functionality and its applications can be modified and debugged freely, by using normal development tools.
Signing the software prevents it from being further modified without detection. Also, a secure digest allows to authenticate the producer (or, at least, the approver) of the application version, thus making sure that no malicious third party application is executed.
The software stored in the device should be executed only if it was successfully validated during the boot process. Digital signatures are used most often to confirm the software authenticity.
In order to sign the software, the first step it to use a hash function (for example, one of the SHA algorithms) to calculate a short and unique software digest. The digest has a fixed, relatively short (comparing to the size of the full firmware) length.
The digest should be then encrypted, by using an asymmetric cipher and a private key, which is known only to the manufacturer. RSA is one of the most popular ciphers used for digest encryption. The encrypted digest is stored in the device read-only memory. Once flashed, it cannot be changed anymore.
A corresponding public key should be saved in the same (read-only) area, next to the encrypted digest. Public keys are often contained in signed digital certificates. During device start-up, a program should check if the stored digest value is correct. First, it should decrypt the digest, by using the public key. Then, it has to calculate a second digest value by itself, by using the same hash function, as it was used originally. Finally, the two values should be compared. If they are not the same, then one should assume that the code was modified after being signed. The program execution should stop, and the device should turn off.
It is crucial to highlight that this checking should take place at the beginning of the software flow, when the processor still operates in the read-only memory, and the control didn't reach the larger, writeable memory area.
In general, every secure microcontroller should start executing software from an internal, immutable memory. All the software verification procedures should be stored in that read-only, initially executed memory. Such a location is often called trusted, and the device starting point of execution is called the root of trust.
Some more complex schemes of signing could be used to protect the code. The digest may be signed by multiple entities, for example by the producer and the external validation authority. It is also possible to add intermediate keys to introduce more sophisticated security mechanisms.
When a new software version is being loaded into the device, it should be tested and checked, to make sure that no unauthorised modifications were applied.
Generally, during manufacturing, the code that was developed and prepared for a device is then signed using a proper private key and stored (together with the digest) in a secure database. Asymmetric cipher algorithms mentioned above, are also most often used in this procedure.
During programming the device, the flashing application downloads the software and the corresponding digest. After boot loader authentication, the secured software (obtained earlier from the database) is sent to the device.
The boot loader decrypts the received signature, and calculates the software digest. If both digest values are the same, then the boot loader program should accept the new application version.
Secure software flashing is implemented in numerous applications, operating in many areas, especially in telecommunication, aeronautical, and automotive industries. It is particularly useful if the software systems are distributed and consist of many, semi-independent devices.
Due to the fact, that a lot of small embedded devices have relatively little computational power, special care should be taken when using complex hash and encryption algorithms. It is recommended to configure the asymmetric ciphers in a way, that will make the public-key decryption procedure as cheap as possible. For example, in case of the RSA cipher, the public key component should be as small as possible (say, 3) to make computation faster.