Zum Hauptinhalt springen

4. Signaturobjekte

  1. Signaturobjekte

COSE unterstützt zwei verschiedene Signaturstrukturen. COSE_Sign ermöglicht es, eine oder mehrere Signaturen auf denselben Inhalt anzuwenden. COSE_Sign1 ist auf einen einzelnen Unterzeichner beschränkt. Die Strukturen können nicht ineinander konvertiert werden; da die Signaturberechnung einen Parameter enthält, der die verwendete Struktur identifiziert, schlägt die Validierung der Signatur bei der konvertierten Struktur fehl.

4.1. Signieren mit einem oder mehreren Unterzeichnern

Die COSE_Sign-Struktur ermöglicht es, eine oder mehrere Signaturen auf eine Nachrichtennutzlast anzuwenden. Header-Parameter, die sich auf den Inhalt beziehen, und Header-Parameter, die sich auf die Signatur beziehen, werden zusammen mit der Signatur selbst übertragen. Diese Header-Parameter können durch die Signatur authentifiziert werden oder einfach nur vorhanden sein. Ein Beispiel für einen Header-Parameter zum Inhalt ist der Inhaltstyp-Header-Parameter. Ein Beispiel für einen Header-Parameter zur Signatur wäre der Algorithmus und der Schlüssel, die zur Erstellung der Signatur verwendet wurden.

[RFC5652] gibt an, dass:

| Wenn mehr als eine Signatur vorhanden ist, wird die erfolgreiche Validierung einer Signatur, die einem bestimmten Unterzeichner zugeordnet ist, normalerweise als erfolgreiche Signatur durch diesen Unterzeichner behandelt. Es gibt jedoch einige Anwendungsumgebungen, in denen andere Regeln erforderlich sind. Eine Anwendung, die eine andere Regel als eine gültige Signatur für jeden Unterzeichner verwendet, muss diese Regeln spezifizieren. Auch wenn der einfache Abgleich des Unterzeichner-Identifikators nicht ausreicht, um festzustellen, ob die Signaturen vom selben Unterzeichner generiert wurden, muss die Anwendungsspezifikation beschreiben, wie bestimmt wird, welche Signaturen vom selben Unterzeichner generiert wurden. Die Unterstützung verschiedener Empfängergemeinschaften ist der Hauptgrund, warum Unterzeichner mehr als eine Signatur einschließen.

Beispielsweise könnte die COSE_Sign-Struktur Signaturen enthalten, die mit dem Edwards-curve Digital Signature Algorithm (EdDSA) [RFC8032] und dem Elliptic Curve Digital Signature Algorithm (ECDSA) [DSS] generiert wurden. Dies ermöglicht es den Empfängern, die Signatur zu verifizieren, die dem einen oder dem anderen Algorithmus zugeordnet ist. Detailliertere Informationen zu mehrfachen Signaturauswertungen finden sich in [RFC5752].

Die Signaturstruktur kann je nach Kontext, in dem sie verwendet wird, entweder als getaggt oder ungetaggt codiert werden. Eine getaggte COSE_Sign-Struktur wird durch das CBOR-Tag 98 identifiziert. Das CDDL-Fragment, das dies darstellt, ist:

COSE_Sign_Tagged = #6.98(COSE_Sign)

Eine COSE-signierte Nachricht ist in zwei Teilen definiert. Das CBOR-Objekt, das den Rumpf und Informationen über die Nachricht trägt, wird als COSE_Sign-Struktur bezeichnet. Das CBOR-Objekt, das die Signatur und Informationen über die Signatur trägt, wird als COSE_Signature-Struktur bezeichnet. Beispiele für COSE-signierte Nachrichten finden sich in Anhang C.1.

Die COSE_Sign-Struktur ist ein CBOR-Array. Die Felder des Arrays sind in der Reihenfolge:

protected (geschützt): Dies ist wie in Abschnitt 3 beschrieben.

unprotected (ungeschützt): Dies ist wie in Abschnitt 3 beschrieben.

payload (Nutzlast): Dieses Feld enthält den serialisierten Inhalt, der signiert werden soll. Wenn die Nutzlast in der Nachricht nicht vorhanden ist, muss die Anwendung die Nutzlast separat bereitstellen. Die Nutzlast wird in einen bstr verpackt, um sicherzustellen, dass sie ohne Änderungen transportiert wird. Wenn die Nutzlast separat transportiert wird ("detached content"), wird an dieser Stelle ein nil-CBOR-Objekt platziert, und es liegt in der Verantwortung der Anwendung sicherzustellen, dass sie ohne Änderungen transportiert wird.

  Hinweis: Wenn eine Signatur mit einem Nachrichtenwiederherstellungsalgorithmus verwendet wird (Abschnitt 8.1), ist die maximale Anzahl von Bytes, die wiederhergestellt werden können, die Länge der ursprünglichen Nutzlast. Die Größe der codierten Nutzlast wird um die Anzahl der Bytes reduziert, die wiederhergestellt werden. Wenn alle Bytes der ursprünglichen Nutzlast verbraucht sind, wird die übertragene Nutzlast als Byte-String der Länge Null codiert, anstatt als abwesend.

signatures (Signaturen): Dieses Feld ist ein Array von Signaturen. Jede Signatur wird als COSE_Signature-Struktur dargestellt.

Das CDDL-Fragment, das den obigen Text für COSE_Sign darstellt, folgt.

COSE_Sign = [ Headers, payload : bstr / nil, signatures : [+ COSE_Signature] ]

Die COSE_Signature-Struktur ist ein CBOR-Array. Die Felder des Arrays sind in der Reihenfolge:

protected (geschützt): Dies ist wie in Abschnitt 3 beschrieben.

unprotected (ungeschützt): Dies ist wie in Abschnitt 3 beschrieben.

signature (Signatur): Dieses Feld enthält den berechneten Signaturwert. Der Typ des Feldes ist ein bstr. Algorithmen MÜSSEN ein Padding angeben, wenn der Signaturwert kein Vielfaches von 8 Bits ist.

Das CDDL-Fragment, das den obigen Text für COSE_Signature darstellt, folgt.

COSE_Signature = [ Headers, signature : bstr ]

4.2. Signieren mit einem Unterzeichner

Die COSE_Sign1-Signaturstruktur wird verwendet, wenn nur eine Signatur auf einer Nachricht platziert werden soll. Die Header-Parameter, die sich mit dem Inhalt und der Signatur befassen, werden im selben Paar von Buckets platziert, anstatt die Trennung von COSE_Sign zu haben.

Die Struktur kann je nach Kontext, in dem sie verwendet wird, entweder als getaggt oder ungetaggt codiert werden. Eine getaggte COSE_Sign1-Struktur wird durch das CBOR-Tag 18 identifiziert. Das CDDL-Fragment, das dies darstellt, ist:

COSE_Sign1_Tagged = #6.18(COSE_Sign1)

Das CBOR-Objekt, das den Rumpf, die Signatur und die Informationen über den Rumpf und die Signatur trägt, wird als COSE_Sign1-Struktur bezeichnet. Beispiele für COSE_Sign1-Nachrichten finden sich in Anhang C.2.

Die COSE_Sign1-Struktur ist ein CBOR-Array. Die Felder des Arrays sind in der Reihenfolge:

protected (geschützt): Dies ist wie in Abschnitt 3 beschrieben.

unprotected (ungeschützt): Dies ist wie in Abschnitt 3 beschrieben.

payload (Nutzlast): Dies ist wie in Abschnitt 4.1 beschrieben.

signature (Signatur): Dieses Feld enthält den berechneten Signaturwert. Der Typ des Feldes ist ein bstr.

Das CDDL-Fragment, das den obigen Text für COSE_Sign1 darstellt, folgt.

COSE_Sign1 = [ Headers, payload : bstr / nil, signature : bstr ]

4.3. Extern bereitgestellte Daten

Eine der Funktionen, die in COSE angeboten werden, ist die Möglichkeit für Anwendungen, zusätzliche Daten bereitzustellen, die authentifiziert werden sollen, aber nicht als Teil des COSE-Objekts übertragen werden. Der Hauptgrund für die Unterstützung dieser Funktion lässt sich anhand der CoAP-Nachrichtenstruktur [RFC7252] erkennen, wo die Möglichkeit besteht, Optionen vor der Nutzlast zu übertragen. Beispiele für Daten, die an dieser Stelle platziert werden können, wären der CoAP-Code oder CoAP-Optionen. Wenn sich die Daten in den Headern der CoAP-Nachricht befinden, stehen sie Proxys zur Verfügung, um bei der Durchführung von Proxy-Operationen zu helfen. Beispielsweise kann die Accept-Option von einem Proxy verwendet werden, um festzustellen, ob ein geeigneter Wert im Cache des Proxys vorhanden ist. Der Sender kann die Funktionalität für zusätzliche Daten verwenden, um die Erkennung von Änderungen an der Menge der Accept-Werte durch einen Proxy oder einen Angreifer zu ermöglichen. Durch die Aufnahme des Feldes in die extern bereitgestellten Daten führt jede nachfolgende Änderung dazu, dass die Verarbeitung der Nachricht durch den Server fehlschlägt.

Dieses Dokument beschreibt den Prozess zur Verwendung eines Byte-Arrays von extern bereitgestellten authentifizierten Daten; die Methode zum Konstruieren des Byte-Arrays ist eine Funktion der Anwendung. Anwendungen, die diese Funktion verwenden, müssen definieren, wie die extern bereitgestellten authentifizierten Daten konstruiert werden sollen. Eine solche Konstruktion muss die folgenden Punkte berücksichtigen:

  • Wenn mehrere Elemente enthalten sind, müssen Anwendungen sicherstellen, dass derselbe Byte-String nicht erzeugt werden kann, wenn es unterschiedliche Eingaben gibt. Ein Beispiel dafür, wie das problematische Szenario entstehen könnte, wäre das Verketten der Textstrings "AB" und "CDE" oder das Verketten der Textstrings "ABC" und "DE". Dies wird normalerweise dadurch behoben, dass Felder eine feste Breite haben und/oder die Länge des Feldes als Teil der Ausgabe codiert wird. Wenn man Optionen von CoAP [RFC7252] als Beispiel nimmt, verwenden diese Felder eine TLV-Struktur, sodass sie ohne Probleme verkettet werden können.

  • Wenn mehrere Elemente enthalten sind, muss eine Reihenfolge für die Elemente definiert werden. Wenn man Optionen von CoAP als Beispiel nimmt, könnte eine Anwendung angeben, dass die Felder nach der Optionsnummer geordnet werden sollen.

  • Anwendungen müssen sicherstellen, dass der Byte-String auf beiden Seiten gleich sein wird. Die Verwendung von Optionen von CoAP könnte ein Problem darstellen, wenn dieselbe relative Nummerierung beibehalten wird. Ein Zwischenknoten könnte eine Option einfügen oder entfernen und so die Art und Weise ändern, wie die relative Nummerierung erfolgt. Eine Anwendung müsste spezifizieren, dass die relative Nummer neu codiert werden muss, um nur relativ zu den Optionen zu sein, die in den externen Daten enthalten sind.

4.4. Signatur- und Verifizierungsprozess

Um eine Signatur zu erstellen, wird ein wohldefinierter Byte-String benötigt. Die Sig_structure wird verwendet, um die kanonische Form zu erstellen. Dieser Signatur- und Verifizierungsprozess nimmt die Rumpfinformationen (COSE_Sign oder COSE_Sign1), die Unterzeichnerinformationen (COSE_Signature) und die Anwendungsdaten (externe Quelle) auf. Eine Sig_structure ist ein CBOR-Array. Die Felder der Sig_structure sind in der Reihenfolge:

  1. Ein Kontexttextstring, der den Kontext der Signatur identifiziert. Der Kontexttextstring ist:

    "Signature" für Signaturen, die die COSE_Signature-Struktur verwenden.

    "Signature1" für Signaturen, die die COSE_Sign1-Struktur verwenden.

  2. Die geschützten Attribute aus der Rumpfstruktur, codiert in einem bstr-Typ. Wenn keine geschützten Attribute vorhanden sind, wird ein Byte-String der Länge Null verwendet.

  3. Die geschützten Attribute aus der Unterzeichnerstruktur, codiert in einem bstr-Typ. Wenn keine geschützten Attribute vorhanden sind, wird ein Byte-String der Länge Null verwendet. Dieses Feld wird für die COSE_Sign1-Signaturstruktur weggelassen.

  4. Die extern bereitgestellten Daten von der Anwendung, codiert in einem bstr-Typ. Wenn dieses Feld nicht bereitgestellt wird, ist der Standardwert ein Byte-String der Länge Null. (Siehe Abschnitt 4.3 für Anleitungen zur Anwendung bei der Konstruktion dieses Feldes.)

  5. Die zu signierende Nutzlast, codiert in einem bstr-Typ. Hier wird die volle Nutzlast verwendet, unabhängig davon, wie sie transportiert wird.

Das CDDL-Fragment, das den obigen Text beschreibt, ist:

Sig_structure = [ context : "Signature" / "Signature1", body_protected : empty_or_serialized_map, ? sign_protected : empty_or_serialized_map, external_aad : bstr, payload : bstr ]

Wie eine Signatur berechnet wird:

  1. Erstellen Sie eine Sig_structure und füllen Sie sie mit den entsprechenden Feldern.

  2. Erstellen Sie den Wert ToBeSigned, indem Sie die Sig_structure unter Verwendung der in Abschnitt 9 beschriebenen Codierung in einen Byte-String codieren.

  3. Rufen Sie den Signaturerstellungsalgorithmus auf und übergeben Sie K (den Schlüssel zum Signieren), alg (den Algorithmus zum Signieren) und ToBeSigned (den zu signierenden Wert).

  4. Platzieren Sie den resultierenden Signaturwert an der richtigen Stelle. Dies ist das Feld "signature" der COSE_Signature- oder COSE_Sign1-Struktur.

Die Schritte zum Verifizieren einer Signatur sind:

  1. Erstellen Sie eine Sig_structure und füllen Sie sie mit den entsprechenden Feldern.

  2. Erstellen Sie den Wert ToBeSigned, indem Sie die Sig_structure unter Verwendung der in Abschnitt 9 beschriebenen Codierung in einen Byte-String codieren.

  3. Rufen Sie den Signaturverifizierungsalgorithmus auf und übergeben Sie K (den Schlüssel zum Verifizieren), alg (den zum Signieren verwendeten Algorithmus), ToBeSigned (den zu signierenden Wert) und sig (die zu verifizierende Signatur).

Zusätzlich zur Durchführung der Signaturverifizierung führt die Anwendung die entsprechenden Prüfungen durch, um sicherzustellen, dass der Schlüssel korrekt mit der signierenden Identität gekoppelt ist und dass die signierende Identität autorisiert ist, bevor Aktionen ausgeführt werden.