Den L4Re-Dienst ansprechen
Diese Anleitung zeigt, wie eine L4Re-Task über DataspaceEndpoint einen ML-DSA-Schlüssel erzeugen und
damit eine Nachricht signieren lässt. Die Beispiele sind C++, weil DataspaceEndpoint eine
C++-Klasse ist. Sie brauchen nur wvds_crypto.h und die Headerdatei von DataspaceEndpoint. Die
Funktionen build_…, die Nachrichten zusammensetzen, sind reines C und lassen sich unverändert in
C-Code übernehmen.
Voraussetzungen:
- Der Dienst läuft als eigene L4Re-Task; siehe Bauformen im Vergleich.
- Ihre Task hat Zugriff auf
DataspaceEndpointIhres Plattformlieferanten und richtet ihn nach dessen Vorgaben ein: Registry-Server als statische Variable, Konstruktor im Hauptthread, Server-Schleife am Ende vonmain.
1. Endpunkt anlegen
#include "wvds_crypto.h" #include "DataspaceEndpoint.h" static L4Re::Util::Registry_server<> server; int main() { DataspaceEndpoint ep(&server, "CRYPTO_CLI", // eigener Name, so erwartet ihn der Dienst "CRYPTO_SVC", // Name des Dienstes 64 * 1024, // Größe des Bereichs der Gegenseite 5000000, // Zeitlimit für die Gegenseite on_crypto_response); // Arbeits-Thread starten, der wait_for_initialization() aufruft und dann Anfragen sendet server.loop(); }
Die Namen sind im Dienst fest eingestellt. Eine Task mit anderem Namen findet er nicht.
2. Schlüssel erzeugen lassen
static size_t build_ml_dsa_keygen(uint8_t *buf, uint8_t level) { wvds_init_header((wvds_message_header_t *)buf, WVDS_REQ_ML_DSA_KEYGEN, 0, 1); WVDS_PAYLOAD_PTR(buf)[0] = level; return WVDS_MESSAGE_SIZE(1); } /* im Arbeits-Thread, nach wait_for_initialization() */ uint8_t *buf = (uint8_t *)ep.allocate_local_blocking(WVDS_MESSAGE_SIZE(1)); size_t len = build_ml_dsa_keygen(buf, WVDS_ML_DSA_65); ep.add_new_req(next_id++, WVDS_REQ_ML_DSA_KEYGEN, buf, len);
Die Antwort enthält die neue Kennung in den ersten 4 Byte der Nutzdaten und danach den öffentlichen Schlüssel, bei ML-DSA-65 1952 Byte.
3. Nachricht signieren lassen
static size_t build_ml_dsa_sign(uint8_t *buf, uint32_t key_id, const uint8_t *msg, uint32_t msg_len) { wvds_init_header((wvds_message_header_t *)buf, WVDS_REQ_ML_DSA_SIGN, key_id, 1 + msg_len); uint8_t *p = WVDS_PAYLOAD_PTR(buf); p[0] = WVDS_ML_DSA_65; /* wird nicht ausgewertet, die Stufe kommt vom Schlüssel */ memcpy(p + 1, msg, msg_len); return WVDS_MESSAGE_SIZE(1 + msg_len); }
Die ganze Anfrage, also 16 Byte Kopf, Stufenbyte und Nachricht, muss in den 64 KiB großen Bereich
passen, den der Dienst von Ihrer Task einblendet. Halten Sie Nachrichten deshalb deutlich unter 64 KiB
und signieren Sie bei größeren Daten einen Hashwert. Die Antwort ist die Signatur selbst, bei
ML-DSA-65 genau WVDS_ML_DSA_65_SIG_SIZE Byte.
4. Antworten auswerten
int on_crypto_response(DataspaceEndpoint *self, u_int64_t id, u_int8_t type, const u_int8_t *data, l4_size_t size) { wvds_message_header_t hdr; if (size >= sizeof hdr) { memcpy(&hdr, data, sizeof hdr); const uint8_t *payload = data + sizeof hdr; if (!wvds_validate_header(&hdr) || sizeof hdr + hdr.payload_len != size) { /* keine gültige Antwort des Dienstes */ } else if (wvds_is_error_response(data, size)) { uint32_t code; memcpy(&code, payload, sizeof code); /* wvds_error_name((wvds_error_code_t)code) liefert den Namen */ } else { /* Inhalt je nach offener Anfrage mit dieser id auswerten */ } } self->free_peer_req(id, type, data, size); /* immer freigeben */ return 0; }
Drei Punkte entscheiden über eine robuste Anbindung:
- Fehler stehen im Kopf. Der IPC-Typ einer Antwort ist immer
0x80. Ob es ein Fehler ist, sagt alleinreq_typeim Kopf;wvds_is_error_responseprüft genau das. - Immer freigeben. Rufen Sie
free_peer_reqfür jede Antwort auf, auch für ungültige. Sonst läuft der Bereich des Dienstes voll, und er kann nicht mehr antworten. - Zeitlimit vorsehen. Bei Überlast verwirft der Dienst Anfragen ohne Antwort. Merken Sie sich offene
id-Werte und geben Sie eine Anfrage nach einer Frist verloren.