begann mit der Erforschung von Methoden und Wegen zur Gewährleistung der Informationssicherheit von ausführbarem Programmcode. Früher oder später stehen alle Softwareentwickler und Systemingenieure vor einer solchen Aufgabe, die in einem der Projekte von Altiriks Systems stattfand, in deren Rahmen die sichere Ausführung von Programmcode in einer bedingt ungeschützten Umgebung implementiert werden musste. Zu diesem Zweck wurde zusätzlich zu den bereits bekannten und beschriebenen Methoden und Mitteln zum Schutz von Informationen die Technologie Trusted Execution Environment (TEE) gewählt, die in russischen Projekten selten verwendet wird, oder, auf Russisch gesprochen, die Technologie vertrauenswürdiger Ausführungsumgebungen. Speziell in diesem Artikel haben wir uns entschlossen, ein praktisches Beispiel für die Verwendung von Intel-Prozessor-Enklaven für eine vertrauenswürdige Codeausführungsumgebung (Intel Software Guard Extensions oder SGX) zu beschreiben.
Vertrauenswürdige Laufzeiten werden nicht nur von Prozessoren eines bestimmten Herstellers unterstützt. Außerdem wird TEE von einer Reihe von AMD-Prozessoren (Secure Execution Environment, Secure Technology), ARM-Prozessoren (TrustZone) und RISC-V-Prozessoren unterstützt. Darüber hinaus wird TEE von modernen IBM Z-Mainframes unterstützt. Wir haben Intel SGX als Beispiel gewählt, da wir der Ansicht sind, dass Intel-Prozessoren zum Zeitpunkt dieses Schreibens (Sommer 2020) die beliebtesten und für Anfänger im postsowjetischen Raum verfügbaren sind. Eine vollständige Liste der Intel-Prozessormodelle, die Intel SGX unterstützen, finden Sie auf der Intel-Website unter Intel-Produktspezifikationen (ARK), indem Sie die entsprechende zu suchende Technologie auswählen. Und ja, nutzen Sie möglicherweise Intel SGX-Emulationen für Bildungs- oder Forschungszwecke.Die Arbeit mit mehreren dieser Emulationen ergab eine Reihe von Schwierigkeiten bei der Einrichtung. Sie müssen auch verstehen, dass für echte "Kampf" -Projekte natürlich keine Emulation von Technologie auf der Grundlage der Gerätefunktionalität akzeptabel ist.
Jedes Ihrer Rückmeldungen, insbesondere mit Kommentaren und Ergänzungen von Spezialisten, die bereits Erfahrung mit der Verwendung von TEE in ihren Projekten haben, oder mit Fragen von Personen, die gerade erst anfangen, sich mit dieser Technologie zu befassen, trägt zu einer detaillierteren Offenlegung dieses Themas in den folgenden Artikeln bei. Vielen Dank im Voraus!
Einführung
Die Hauptfrage, die wir zu Beginn der Erkundung vertrauenswürdiger Laufzeitumgebungen stellen, lautet: Können wir den Komponenten eines Computersystems vertrauen? Und wenn wir können, wie? Entwickler und insbesondere Intel-Ingenieure geben eine eindeutige Antwort auf diese Frage: Niemand außer Intel selbst. Was bedeutet das? Ich schlage vor, dies genauer zu verstehen.
Privileg klingelt
Aus Sicherheitsgründen sind die Systemkomponenten eines Computers in Berechtigungsstufen unterteilt. Alle modernen Systeme basieren auf Intel-Prozessoren und verfügen nicht nur über ein Privileg-Ring-System. Von extern zu intern gibt es eine Erweiterung der Berechtigung für den Code, der derzeit vom Prozessor verarbeitet wird.

Ring Nummer 3. Der äußere Ring enthält alle Benutzeranwendungen, die wir im Alltag auf dem Computer verwenden. Sie haben die niedrigste Zugriffsebene.
Ring Nr. 2 und Nr. 1. Betriebssysteme und Gerätetreiber befinden sich auf diesen Ebenen.
Rufnummer 0. Supervisor-Modus. Hier befinden sich der Betriebssystemkern (Peripherieverwaltung, Ressourcenzuweisung zwischen Prozessen) sowie Systemtreiber.
Ring Nummer 1. Hypervisor. Verantwortlich für die Zuweisung von Ressourcen für den Fall, dass mehrere Betriebssysteme gleichzeitig auf dem Computer ausgeführt werden, und verantwortlich für deren Isolierung.
Ring Nummer 2.Systemverwaltungsmodus (SMM - Systemverwaltungsmodus). Verwaltet die Stromversorgung des Systems und verwaltet Erweiterungskarten.
Wir können immer mehr Ringe bilden, um die Kräfte der Komponenten der Hierarchie zu begrenzen und ein zunehmend komplexeres und geladenes System zu schaffen. Dies erleichtert jedoch nur die Arbeit eines Angreifers: Je komplexer das System ist, desto einfacher ist es, Schwachstellen darin zu finden. Aber wie können Sie eine zusätzliche Sicherheitsebene bereitstellen, wo Sie sie benötigen? Die Antwort ist ein Wort.
Enklaven
Die Hauptaufgabe eines Angreifers besteht darin, eine Berechtigungsstufe zu erhalten, die ihm Zugriff auf die erforderlichen Systemressourcen verschafft. Wenn dies das Geheimnis der Opferanwendung ist, benötigt die böswillige Anwendung genau die Zugriffsebene, die für das Speichern von Geheimnissen im System verantwortlich ist. Dies legt die Schlussfolgerung nahe, dass die Verwaltung von Anwendungsgeheimnissen dem innersten Ring anvertraut werden sollte, da der Zugang dort am schwierigsten ist. Dieser Ansatz wurde jedoch etwas überdacht. Jetzt werden alle Geheimnisse auf derselben Ebene wie Benutzeranwendungen gespeichert, ebenso wie der Code, der diese Geheimnisse unter einer Bedingung verwaltet: Niemand, absolut niemand außer dem Prozessor kann darauf zugreifen. Das Programm und die Daten werden sozusagen in einen Speicher gepackt. In diesem Fall wird dieser Speicher als Enklave bezeichnet (Enklave - geschlossen, gesperrt).der Schlüssel, von dem nur der Prozessor hat.

Anwendungen, die mit einer vertrauenswürdigen Umgebung arbeiten
Je einfacher das System ist, je weniger Code es enthält, desto schwieriger ist es, es aufgrund von Sicherheitslücken zu öffnen (wir sprechen nicht von grundsätzlich ungeschützten Systemen). Wir erhalten ein bestimmtes Axiom: Der Code, der mit einem Geheimnis arbeitet, sollte so einfach und kurz wie möglich sein. Das Packen des gesamten Programmcodes in eine Enklave ist unpraktisch, daher sollte eine Anwendung, die Enklaven verwendet, in zwei Teile unterteilt werden: "vertrauenswürdig" und "nicht vertrauenswürdig". Der Vertrauenswürdige speichert Enklaven (möglicherweise mehrere) und der Nicht-Vertrauenswürdige den Hauptprogrammcode.
Der vertrauenswürdige Teil besteht aus einer Reihe von Funktionen und Prozeduren, die als ECALL (Enclave Call) bezeichnet werden. Die Signatur solcher Funktionen muss in eine spezielle Header-Datei geschrieben und in der Quellcodedatei implementiert werden. Im Allgemeinen ähnelt der Ansatz dem, was wir für das übliche Schreiben von Headern verwenden. In diesem Zusammenhang wird jedoch eine spezielle C-ähnliche EDL-Sprache (Enclave Definition Language) verwendet. Es ist auch notwendig, Prototypen jener Funktionen zu schreiben, die innerhalb der Enklave aufgerufen werden können. Solche Funktionen werden OCALL (Outside Call) genannt. Prototypen werden in denselben Header geschrieben, in dem sich ECALL-Funktionen befinden, und die Implementierung wird im Gegensatz zu ECALL im nicht vertrauenswürdigen Teil der Anwendung entsprechend geschrieben.
Vertrauenswürdiger und nicht vertrauenswürdiger Code sind durch die Zertifizierung nach dem Diffie-Hellman-Protokoll fest miteinander verbunden. Der Prozessor ist für den Signaturvorgang verantwortlich, bei dem der Informationsaustauschschlüssel gespeichert wird, der bei jedem Neustart des Systems aktualisiert wird. Der Inhalt der Enklaven wird im gemeinsam genutzten Speicher gespeichert, der von Benutzeranwendungen verwendet wird, der Speicher wird jedoch verschlüsselt. Nur der Prozessor kann den Inhalt entschlüsseln. In einer idealisierten Welt, in der der Enklavencode ohne einen einzigen Fehler geschrieben wird und die gesamte Hardware genau wie vom Hersteller beabsichtigt funktioniert und sonst nichts, würden wir ein universelles, vollständig sicheres System erhalten. Der Hauptvorteil dieses Systems ist die Ausführung des geheimen Teils auf demselben Prozessor, auf dem alle anderen Programme, einschließlich Benutzerprogramme, ausgeführt werden.
In den letzten Jahren ist jedoch eine große Anzahl von mikroarchitektonischen Schwachstellen moderner Prozessoren vor einem breiten Publikum aufgetreten, die den Zugriff auf das Innere der Enklave ermöglichen: Foreshadow (Schwachstelle der Spectre-Klasse), SGAxe, Zombieload, CacheOut und viele andere. Es gibt keine Garantie dafür, dass diese Liste nicht mit einer anderen schwerwiegenden Hardware-Sicherheitsanfälligkeit ergänzt wird, deren Software-Fix nicht als Software-Patch bezeichnet werden kann. Vielleicht werden wir die Zeit erleben, in der der Welt eine völlig neue Prozessorarchitektur vorgestellt wird, in der alle Mängel behoben werden, aber im Moment lohnt es sich, darüber zu sprechen, was wir zur Hand haben. Und wir haben ein vielseitiges, leistungsstarkes Tool zur Hand, das die Sicherheit heutiger Systeme erheblich erhöht. So viel aufziehendass es in der einen oder anderen Interpretation in Milliarden von Geräten auf der ganzen Welt implementiert ist: von Smartwatches über Smartphones bis hin zu riesigen Computerclustern.
Hallo Welt!
Gehen wir von der Theorie zur Praxis. Schreiben wir ein kleines Programm, das die bereits kanonische Aufgabe implementiert: Drucken Sie die Zeichenfolge "Hallo Welt!" In dieser Interpretation geben wir auch den Ort an, von dem aus die Nachricht gesendet wird.
Zunächst müssen Sie das SDK herunterladen und installieren, um mit SGX von der offiziellen Website arbeiten zu können. Zum Herunterladen müssen Sie ein einfaches Registrierungsverfahren durchlaufen. In der Installationsphase werden Sie aufgefordert, das Entwicklungspaket in die auf Ihrem Computer verfügbare VS-Version zu integrieren. Alles ist bereit für die erfolgreiche Implementierung Ihres ersten Projekts mit SGX.

Starten Sie VS und erstellen Sie ein Intel SGX-Projekt.

Wir wählen einen Namen für das Projekt und für die Lösung und warten auf "Weiter".
Als nächstes werden Sie aufgefordert, eine Projektkonfiguration auszuwählen, nichts zu ändern und die ursprünglich vorgeschlagenen Werte beizubehalten.

Fügen Sie dann der erstellten Lösung ein weiteres Projekt hinzu: eine reguläre C ++ - Konsolenanwendung.
Daher sollte im Projektdialogfeld das folgende Bild angezeigt werden:

Dann müssen Sie die Enklave mit dem nicht vertrauenswürdigen Teil verbinden. Klicken Sie mit der rechten Maustaste auf das Projekt "Nicht vertrauenswürdiger Teil".


Als Nächstes müssen Sie einige Eigenschaften von Projekten ändern.



Dies muss erfolgen, damit das Programm ordnungsgemäß funktioniert. Wir wiederholen die Schritte für beide Projekte.
Es ist auch notwendig, das Hauptprojekt in den Eigenschaften der Lösung anzugeben.

Das war's, unser Programm ist bereit für die Implementierung.
Dieses Programm enthält 3 Dateien, mit denen wir arbeiten werden: Enclave.edl (der gleiche Header), Enclave.cpp (die ECALL-Implementierung ist buchstabiert), Untrusted Part.cpp (die Hauptprojektdatei ist der nicht vertrauenswürdige Teil). Fügen wir den
folgenden Code in Dateien ein:
Untusted Part.cpp:
#define ENCLAVE_FILE "Enclave.signed.dll" //,
#include "sgx_urts.h" // ,
#include "Enclave_u.h" //
#include "stdio.h"
void print_string(char* buf) //OCALL -
{
printf("ocall output: %s\n", buf);
}
int main()
{
sgx_enclave_id_t eid; // id , , id
sgx_status_t ret = SGX_SUCCESS; //
sgx_launch_token_t token = { 0 }; //
int updated = 0; //
const int BUF_LEN = 30; // ,
ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &token, &updated, &eid, NULL); //
if (ret != SGX_SUCCESS)
{
printf("Failed to create enclave with error number: %#x\n", ret); //
return 0;
}
char buf[BUF_LEN]; // ,
enclaveChat(eid, buf, BUF_LEN); // ECALL
printf("\noutput form main(): %s\n", buf); //
}
Enclave.edl:
enclave {
from "sgx_tstdc.edl" import *;
trusted {
/* define ECALLs here. */
public void enclaveChat([out, size=len] char* str, size_t len);
/* , . OUT - ,
, out .
, ,
.
*/
};
untrusted {
/* define OCALLs here. */
void print_string([in, string] char* buf); // ,
};
};
Enclave.cpp:
#include "Enclave_t.h"
#include "sgx_trts.h"
#include <cstring>
void enclaveChat(char* str, size_t len)
{
char* secret = "Hello from better place"; //
memcpy(str, secret, len); // ,
print_string(secret); // OCALL-
}
Drücken Sie f7 - erstellen Sie die Lösung und drücken Sie dann Strg + f5, um sie auszuführen.
Wenn Sie einen Fehler wie diesen erhalten:

Stellen Sie sicher, dass Intel SGX im BIOS aktiviert ist: BIOS: Sicherheit / IntelSGX / Aktiviert.
Falls keine Fehler aufgetreten sind und vor dem Bildschirm der Konsole die folgenden Zeilen angezeigt wurden:

... herzlichen Glückwunsch, Ihr erstes Programm mit Intel SGX-Technologie ist fertig. Ich hoffe, die Kommentare im Code waren zum besseren Verständnis umfassend, ansonsten können Sie hier in den Kommentaren oder in privaten Nachrichten immer Fragen stellen.