Übersetzung des Medium Artikels von MicroEngineer, für ein besseres Verständnis, habe ich die Erklärung zu diversen Fachbegriffen zusätzlich verlinkt.
In diesem Artikel geht es auch um das kleine rote FPGA-Modul. Sicherheit ist kein einfaches Thema, denn die Sicherung muss auf der untersten Hardwareebene erfolgen, aber ich versuche, sie so gut wie möglich zu erklären.

Einer der Hauptaspekte des ICC-FPGA-Projekts (kurz für IOTA Crypto Core FPGA) war die Sicherheit. Im Gegensatz zu einem Server, der durch physikalische Maßnahmen gesichert ist – z.B. in einem geschlossenem Rechenzentrum – könnte das FPGA-Modul möglicherweise in der Öffentlichkeit und somit für jeden zugänglich eingesetzt und physikalischen Angriffen ausgesetzt werden. Stellen Sie sich das FPGA-Modul vor, das als Zahlungsprozessor in einem IOTA Warenautomaten verwendet wird, der Snacks oder Kaffee verkauft – es wäre katastrophal, wenn jemand den Automaten knacken oder stehlen könnte und so Zugang zu den Seeds erhält.
Wenn das FPGA-Modul als Co-Prozessor verwendet wird, muss der Hauptprozessor selbstverständlich genauso sicher sein wie das FPGA-Modul, aber die Stärke dieses Moduls ist, dass es auch als Hauptanwendungs-Prozessor verwendet werden kann, da Sie Ihren eigenen Code schreiben können, der auf dem gesicherten Modul läuft. Es gibt mehrere Sicherheitsaspekte, die ich erläutern möchte.
Soft-CPU und Speicher-Schutz-Einheit
Das folgende Bild zeigt, was sich auf dem FPGA-Modul befindet – insbesondere innerhalb des FPGAs. In der Mitte des Bildes befindet sich die RISC-V Soft-CPU, die mit Speichern, Peripheriegeräten (wie I2C, SPI,…) und dem Debugger verbunden ist.

Die CPU führt den im ROM befindlichen Code aus und verwendet das RAM (Random-Access Memory) als Speicherplatz für Daten. ROM steht für Read-only-Memory, aber in der Praxis haben FPGAs kein ROM, sie müssen ROM mit RAM emulieren, indem sie den Zugriff auf den Speicher beschränken. Standardmäßig unterscheidet die von mir verwendete RISC-V-Implementierung nicht wirklich zwischen ROM und RAM [i] , so dass es möglich gewesen wäre, Code von extern (z.B. über JSON-Api) einzubringen, indem man Programmierfehler ausnutzt und einen Pufferüberlauf verursacht hätte. Glücklicherweise konnte die VexRiscV problemlos um ein in Scala geschriebenes Speicherschutz-Plugin erweitert werden, das das Zugriffsmanagement auf die Speicher und den E/A-Bereich vorsieht.
Darüber hinaus unterstützt der RISC-V (er ist Teil des ISA) verschiedene Berechtigungsstufen. Es gibt den Maschinenmodus (höchste Berechtigungsstufe), den Supervisor-Modus und den Benutzermodus. Das Memory-Protection-Plugin unterscheidet auch zwischen diesen drei Modi und ermöglicht Speicher und Peripheriegeräte, die nur im Maschinen- und Supervisor-Modus zugänglich sind. RISC-V unterstützt auch SCALLs, d.h. Aufrufe von Code, die im Supervisor-Modus ausgeführt werden. Beispielsweise kann Code, der im Benutzermodus ausgeführt wird (niedrigste Berechtigungsstufen), Code aufrufen, der im Supervisor-Modus ausgeführt wird, um eine Transaktion zu signieren. Dieser privilegierte Code könnte auf den Seed zugreifen, eine Transaktion signieren und die signierte Transaktion an den im Benutzermodus laufenden Code zurückgeben.
Obwohl der Speicherschutz bereits eine recht gute Sicherheit bietet, wäre es nicht möglich, durch Ausnutzung von Schwachstellen auf den Seed zuzugreifen, da der implementierte Sicherheitsmechanismus auf der untersten Hardwareebene arbeitet und praktisch nicht umgangen werden kann (außer durch Ausnutzung von fehlerhaftem Supervisor-Code). Da der Speicherschutz auch den Zugriff auf Peripheriegeräte – wie z.B. I2C, das zur Kommunikation mit dem Secure Element verwendet wird – nur aus dem Supervisor-Modus ermöglicht, hätte der im User-Modus laufende Code nicht einmal Zugriff auf die Schnittstelle, an die das Secure Element angeschlossen ist.
Last but not least läuft die Debugging-Schnittstelle im Maschinen-Modus und kann zum Hochladen von Code in das ROM verwendet werden. Dies ist sehr praktisch, da es viel Zeit spart, da keine FPGA-Bitströme auf das FPGA erzeugt und hochgeladen werden müssen, da der Code (temporär) aktualisiert werden kann, indem er stattdessen in das ROM hochgeladen wird. Später, wenn die Entwicklung abgeschlossen ist, wird das FPGA-System in den Lockdown-Modus versetzt. Es wird nur das Setzen einer Variablen im Synthesetool benötigt, aber physikalisch würde alles, was Teil der Debugging-Schnittstelle ist, vollständig von der Hardware verschwinden, da es durch das Synthesetool vollständig optimiert würde.
Der beste Schutz gegen das Herumspielen mit der Debugging-Schnittstelle ist, überhaupt keine Debugging-Schnittstelle zu haben.
[i] Es gibt eine Standarderweiterung für eine Memory Management Unit (MMU), die hier nicht verwendet wurde, da kein virtueller Speicher benötigt wird. Aber es würde in einer Linux-fähigen Konfiguration des VexRiscV verwendet werden.
Secure-Element
Die meisten FPGAs haben keinen internen Flash-Speicher, der zur Datenspeicherung verwendet werden könnte. Dies muss extern erfolgen, wofür ein Secure Element (SE) verwendet werden kann. Solche Elemente sind wie Flash-Speicher (oft I2C-EEPROM pin-kompatibel), die vor allen Arten von physikalischen Angriffen geschützt sind. Das FPGA-Modul verfügt auch über ein solches Element auf der Leiterplatte, mit dem bis zu 8 Seeds sicher gespeichert werden können. Seeds werden von und in die SE mit Hilfe von gesetzten und rotierenden AES-Schlüsseln gelesen und geschrieben, die nicht nur die Kommunikation sichern, sondern auch vor Replay-Angriffen schützen.
Der Entschlüsselungsschlüssel zur SE kann in einem Speicherbereich gespeichert werden, auf den nur der Code im Supervisor-Modus Zugriff hat.
Bitstream-Verschlüsselung
Die meisten FPGAs sind nur SRAM-basiert und haben keinen Permanentspeicher, so dass sie ihre Konfiguration (Bitstream) von einem externen SPI-Flash bei jedem Einschaltvorgang erhalten. Es enthält alles wie die Hardware-Beschreibung selbst, Programmcode, Verschlüsselungs-Keys,…. Es ist wichtig, den Bitstream vor Angriffen zu schützen.
Xilinx FPGAs (in diesem Fall, aber Intel/Altera kann das Gleiche tun) können mit einem AES-Verschlüsselungsschlüssel fusioniert (fest programmiert) werden, der dann beim Start zur Entschlüsselung des Bitstroms verwendet wird. Kann der Bitstream nicht mit dem internen Schlüssel entschlüsselt werden, wird die Konfiguration abgelehnt und das FPGA nicht gestartet. Wenn der Hash des entschlüsselten Bitstreams falsch ist, wird das FPGA auch nicht booten.
Das hat erfreuliche Auswirkungen:
- Es ist nur möglich, Bitstreams mit dem richtigen AES-Schlüssel zu verwenden.
- Es ist nicht möglich, Daten aus dem Bitstream zu extrahieren (wie Schlüssel).
- Es ist nicht möglich, den Bitstream zu manipulieren (z.B. durch Austausch des ROM).
- aber es ist einfach und sicher, den Bitstream zu verteilen und das FPGA zu aktualisieren.
Zukünftige Arbeit
Im letzten Artikel habe ich über die Migration von Cortex M1 nach RISC-V geschrieben. Die neue Soft-CPU ist nicht nur schneller und vollständig Open-Source, sie hat auch einige Vorteile gegenüber der alten CPU – wie z.B. Speicherschutz oder die Möglichkeit, Code mit drei Berechtigungsstufen einzubinden. Der nächste Schritt besteht darin, den Code zu trennen, in dem Code, der im Benutzermodus läuft, und dem Code, der im Supervisor-Modus läuft, das Seed-Management in den Supervisor-Code zu verschieben und eine interne API zum Aufruf von Supervisor-Funktionen zu erstellen.
Zum Schluss noch ein paar nette Neuigkeiten: Die IOTA Foundation wird einige der FPGA-Module bestellen. Sie werden von einem professionellen PCBA-Dienst erstellt. Außerdem wird es ein Raspberry Pi HAT geben, das als Entwicklungsboard für Anwendungen auf dem FPGA-Modul verwendet werden kann.
Wer Thomas für seine wichtige Pionierarbeit ein Trinkgeld zukommen lassen möchte, der sollte dies über den Donate Button auf der IOTA-Ecosystem Webseite tun.