Ein Angebot von

Linux Secure Boot in der Praxis

| Autor / Redakteur: Dipl.-Ing. (FH) Holger Dengler * / Sebastian Gerstl

In modernen Embedded Systemen sollte Code-Integrität vom Reset bis in den Kernel des (Linux-)Systems selbst gewährleistet sein.
In modernen Embedded Systemen sollte Code-Integrität vom Reset bis in den Kernel des (Linux-)Systems selbst gewährleistet sein. (Bild: gemeinfrei / CC0)

Embedded Systeme sind zunehmenden Angriffen aus unterschiedlichen Quellen ausgesetzt.. Der auf diesen Systemen ausgeführte Code muss daher aus vertrauenswürdigen Quellen kommen. Zentrales Element ist hier die Code-Integritätsprüfung während des Boot-Vorgangs.

Waren serielle Schnittstellen vor 10 Jahren die einzigen Zugänge zu einem Steuerungssystem, so ist es heute nicht unüblich, dass ein Embedded System über mehr als eine Schnittstelle mit der Außenwelt kommunizieren kann, wie z.B. über Ethernet, Wi-Fi, Bluetooth, CAN, Modbus oder ZigBee. Dabei erhöht jede Schnittstelle auch die Angriffsfläche des Systems.

Wirksame Maßnahmen für den Schutz dieser Schnittstellen bieten mittlerweile viele Betriebssysteme wie z.B. Linux, die auf Embedded Systemen zum Einsatz kommen. Diese greifen aber nur, wenn auch die vom Hersteller zur Verfügung gestellte Software zum Einsatz kommt.

Der Bootvorgang

Der Bootvorgang ist hierbei von zentraler Bedeutung, da hier entschieden wird, welcher Linux-Kernel geladen wird. Da diese Aufgabe wiederum vom Bootloader übernommen wird, ist auch darauf zu achten, welcher Bootloader nach dem Reset eines Systems zum Einsatz kommt.

Auch wenn sich der Bootvorgang im Detail von Plattform zu Plattform leicht unterscheidet, so werden normalerweise die folgenden Schritte durchlaufen (siehe auch Bild 1). Bootloader und Linux-Kernel werden dazu aus nicht-flüchtigen Speicherbereichen (z.B. NOR- bzw. NAND-Flash) geladen.

  • 1. ROM Code: Initialisierung der CPU
  • 2. ROM Code: Laden des Bootloaders
  • 3. Bootloader: Ausführen des Bootloaders
  • 4. Bootloader: Laden/Konfigurieren des Linux-Kernels
  • 5. System: Ausführen des Linux-Kernel
  • 6. System: Ausführen der Applikationen

Bei diesem Vorgang ist meist einzig die Integrität des ROM Codes gesichert, da er aus einem read-only Speicher auf dem SystemOnChip (SoC ) selbst kommt. Viele Hersteller von Hardware für Embedded Systemen bieten in diesem ROM Code Mechanismen an, um schon beim Laden des Bootloaders dessen Integrität mit Hilfe einer kryptographischen Signatur zu überprüfen. Ebenso bieten alle aktuellen Bootloader Funktionen an, auch den Linux-Kernel und -Devicetree mit Hilfe einer solches Signatur zu überprüfen. Damit modifiziert sich die Ablauf beim Start eines Embedded Systems (Siehe auch Bild 2).

  • 1. ROM Code: Initialisierung der CPU
  • 2. ROM Code: Laden des Bootloaders
  • 3. ROM Code: Integritäts-Check des Bootloaders (falls Signatur korrekt)
  • 4. Bootloader: Ausführen des Bootloaders
  • 5. Bootloader: Laden des Linux-Kernels
  • 6. Bootloader: Integritäts-Check des Linux-Kernel/Devicetree
  • 7. System: Ausführen des Linux-Kernel (falls Signatur korrekt)

Mittels kryptographischer Verfahren sind nun neben dem ROM Code auch die Integrität des Bootloaders sowie des Linux Kernel/Devicetree gesichert. Je nach Konfiguration wird das Embedded System den Bootvorgang abbrechen, sobald einer dieser Integritätschecks fehlschlägt.

Integritätsprüfung des Bootloader

Wie in Bild 2 dargestellt, wird der Integritäts-Check des Bootloaders durch den ROM Loader sichergestellt. Da der ROM Code von SoC zu SoC unterschiedlich ist, ist es nun an der Zeit, an einem konkreten Beispiel einer Hardware, die Vorgänge und Abläufe darzulegen. Viele aktuelle SoCs bringen diese Features in der ein oder anderen Ausprägung aber ebenfalls mit und eignen sich für die Umsetzung ebenso.

Der i.mx7d von NXP bietet, als einer der Vertreter der i.mx-Familie, einen sogenannten High Assurance Boot, Version 4 (HABv4), mit dem die Integrität geladener Images schon vor der Ausführung des eigentlichen Bootloaders geprüft werden kann.

Die Basis der Integritätsprüfung ist dabei einer von bis zu vier SystemRoot-Keys (SRK), welche mit dem Image geladen werden. Damit dem Prozess nicht beliebige SRKs als „Root of Trust“ unter geschoben werden können, gibt es auf dem Chip eine One-Time-Programmable Area (OTP), in der der Hash, der für dieses Gerät gültigen SRKs abgelegt wird. Die Konfiguration dieser Hashes in den OTP-Fuses obliegt dem Hersteller. Er legt damit fest mit welchen Schlüsseln gültige Code-Signaturen für dieses Gerät erzeugt werden können (siehe auch Bild 3).

Im weiteren Verlauf werden nun ein CommandSequenceFileKey-Zertifikat (CSFK) und ein ImageKey-Zertifikat (IMGK) geladen. Beider Zertifikate müssen eine gültige Unterschrift des verwendeten SRKs haben. Der HABv4 lässt sich über ein Command-Sequence-File (CSF) parametrieren. Die darin enthaltenen Sequenzschritte sind durchaus sicherheits-relevant, weshalb auch die Integrität dieses CSF geschützt werden muss. Dazu wird der HAB die Signatur des CSF vor der Ausführung mit dem CSFK-Zertifikat prüfen. (siehe Bild 4)

Das Bootloader-Image wird durch den Hersteller ebenfalls signiert. Nach dem Laden des Images wird der HAB die Integrität des Bootloader-Images mit dem IMGK-Zertifikat prüfen, bevor er die Kontrolle als letzten Schritt an den Bootloader übergibt (Bild 5).

Integritätsprüfung des Kernel

Durch die drei Prüfschritte des HAB (SRK-Check, CSF-Ceck und Image-Check) ist nun die Code-Integrität des Bootloaders sichergestellt. Dieser kann nun, im weiteren Verlauf des Bootvorgangs, die Integrität von Linux-Kernel und Devicetree prüfen und damit sicherstellen. Das Verfahren hierzu wurde bereits im Beitrag „Linux Secured Integrity schützt vor Angriffen aus dem Netz“ (ESE-Kongress 2013, Holger Dengler) vorgestellt.

Schlüsselräume und „Root of Trust“

Wie Bild 3 zeigt, nutzt der HAB einen der zur Verfügung stehenden SRK als „Root of Trust“. Mithilfe dieser Basis müssen sich alle weiteren Zertifikate verifizieren lassen. Das heißt im Umkehrschluss, der Eigentümer der SRKs muss die Zertifikate für CSFK und IMGK signieren und gibt damit deren Verwendung im Ablauf des Boot-Prozesses frei.

Im Bootloader (z.B. u-boot) wird die Intigrität des Linux-Kernels ebenfalls mit Hilfe eines Zertifikats bzw. des darin enthaltenen Public Keys geprüft. Dieses Zertifikat muss nicht zwingend vom SRK oder den darunterliegenden CFSK oder IMGK signiert werden. Da der Public Key bei der Erzeugung des u-boot-Images ins Image integriert wird, kann dieses Zertifikat auch aus einem anderen Schlüsselraum stammen.

Äquivalent dazu verwendet auch der Linux-Kernel für Integritäts-Checks von Modules und ggf. Teile des Rootfilesystems einen eigenen Schlüssel als „Root of Trust“. Wie beim Bootloader, kann auch dieser Schlüssel aus einem anderen Schlüsselraum stammen, da seine Integrität mit der Integrität des gesamten Kernel-Images gewährleistet wird.

Das mag auf den ersten Blick verwirrend sein, bietet aber die maximale Flexibilität bei der Erstellung einer Trust Chain und der dazu notwendigen Public Key Infrastruktur. Wer diese Freiheit nicht nicht nutzen möchte bzw. eine einfachere Struktur, der Übersichtlichkeit halber vorzieht, kann durch Verwendung z.B. des IMGK im Bootloader und im Kernel Image diese Komplexität drastisch reduzieren (siehe auch Bild 6).

Fazit: Secure Boot durchs High-Assurance-Boot-Konzept

Das High Assurance Boot -Konzept von NXP und die Integritäts-Prüfungen von Bootloader (u-boot) und Linux-Kernel greifen Hand in Hand und ermöglichen eine lückenlose Integritätsprüfung vom Reset bis in den Linux-Userspace. Die dabei verwendeten Schlüsselräume können hierbei den jeweiligen Anforderungen und Gegebenheiten angepasst werden. Sollen Board-Hersteller, System-Anbieter und Endkunde getrennte Schlüssel nutzen können, so bietet dieses Konzept die notwendigen Freiräume. Soll zur Reduzierung der Komplexität das Setup auf einen Schlüsselraum eingeschränkt werden, so ist auch das ohne Probleme umsetzbar. Die Integritäts-Prüfung des Codes während des Bootvorgangs wird somit zum belastbaren, sicheren Rückgrat aller weiteren Security Bemühungen im Embedded System.

5 Regeln für sicheres Embedded-Design

Safety meets Security

5 Regeln für sicheres Embedded-Design

02.05.17 - Die offene Vernetzung von Embedded-Systemen dringt in Segmente wie Medizin, Automotive und Industrie vor. Für diese Systeme wird nicht nur die funktionale Sicherheit, sondern auch der Schutz gegen Cyber-Attacken wesentlich. Daneben müssen weitere Bedrohungen berücksichtigt werden. lesen

Ein Embedded-Echtzeit-Linux-System aufsetzen (Teil 1)

Ein Embedded-Echtzeit-Linux-System aufsetzen (Teil 1)

23.02.12 - Ein Embedded-Board, eine JTAG-Schnittstelle und freie Software – mehr braucht man nicht für ein fertiges Entwicklungssystem für Embedded-Echtzeit-Linux. Dieses Tutorial zeigt Ihnen, wie das geht. lesen

* Holger Dengler arbeitet seit 2012 bei linutronix GmbH, Uhldingen-Mühlhofen in den Schwerpunktbereichen Linux Security & Safety, Consulting und Training.

Kommentar zu diesem Artikel abgeben

Schreiben Sie uns hier Ihre Meinung ...
(nicht registrierter User)

Zur Wahrung unserer Interessen speichern wir zusätzlich zu den o.g. Informationen die IP-Adresse. Dies dient ausschließlich dem Zweck, dass Sie als Urheber des Kommentars identifiziert werden können. Rechtliche Grundlage ist die Wahrung berechtigter Interessen gem. Art 6 Abs 1 lit. f) DSGVO.
Kommentar abschicken
copyright

Dieser Beitrag ist urheberrechtlich geschützt. Sie wollen ihn für Ihre Zwecke verwenden? Infos finden Sie unter www.mycontentfactory.de (ID: 45160872 / Open Source)