Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • fit-connect/docs
1 result
Show changes
......@@ -317,7 +317,7 @@ Wenn zum Beispiel die Version `1.0.0` im Zustellpunkt angeboten wird:
"identifier": "urn:de:fim:leika:leistung:99107004018000",
"submissionSchemas": [
{
"schemaUri": "https://schema.fitko.de/fim/s00000122_1.0.0.schema.json",
"schemaUri": "https://schema.fitko.de/fim/s00000121_1.0.schema.json",
"mimeType": "application/json"
}
],
......
......@@ -57,12 +57,97 @@ Eine Prüfung der Zertifikate kann in diesem Fall zu Testzwecken entfallen.
Weitere Informationen zur Gültigkeitsprüfung finden sich in der technischen Richtlinie [BSI TR-02103](https://www.bsi.bund.de/SharedDocs/Downloads/DE/BSI/Publikationen/TechnischeRichtlinien/TR02103/BSI-TR-02103.pdf?__blob=publicationFile&v=4) des BSI.
:::note Hinweis
An dieser Stelle werden noch detailliertere Informationen und konkrete Implementierungsbeispiele zur Prüfung der JSON Web Keys ergänzt.
:::
Der [folgende Code](https://git.fitko.de/fit-connect/examples/) kann zur Validierung der Schlüssel benutzt werden.
<Tabs
defaultValue="js"
values={[
{ label: 'JavaScript', value: 'js', },
{ label: 'Java', value: 'java', },
]}
>
<TabItem value="js">
```js
// Validierung des öffentlichen Schlüssels
var modulus = publicKey.algorithm.modulusLength
if(modulus < 4096){
throw new Error("Public key length is wrong. It should be at least 4096!")
}
if(publicKey.usages.length > 1 || publicKey.usages[0] != 'wrapKey'){
throw new Error("Keyops must be wrapKey!");
}
if(publicKey.algorithm.name != "RSA-OAEP"){
throw new Error("Wrong public key type! Only RSA is allowed");
}
if(publicKey.algorithm.hash.name != "SHA-256"){
throw new Error("Wrong hash algorithm! Only SHA-256 is allowed.");
}
if(publicKey.algorithm.publicExponent[0] != 1 ||
publicKey.algorithm.publicExponent[1] != 0 ||
publicKey.algorithm.publicExponent[2] != 1){
throw new Error("Public exponent must be AQAB!")
}
// Validierung des privaten Schlüssels
var modulus = privateKey.algorithm.modulusLength
if(modulus < 4096){
throw new Error("Private key length is wrong. It should be at least 4096!")
}
if(privateKey.algorithm.name != "RSA-OAEP"){
throw new Error("Wrong private key type! Only RSA is allowed");
}
if(privateKey.algorithm.hash.name != "SHA-256"){
throw new Error("Wrong hash algorithm! Only SHA-256 is allowed.");
}
if(privateKey.usages.length > 1 || privateKey.usages[0] != 'unwrapKey'){
throw new Error("Keyops must be unwrapKey!");
}
if(privateKey.algorithm.publicExponent[0] != 1 ||
privateKey.algorithm.publicExponent[1] != 0 ||
privateKey.algorithm.publicExponent[2] != 1){
throw new Error("Public exponent must be AQAB!")
}
```
</TabItem>
<TabItem value="java">
```java
public static void validateRSAKey(RSAKey RSAKey, boolean isPrivate){
validateTrueOrElseThrow((RSAKey.getModulus().decodeToBigInteger().bitLength() >= 4096), "JWK has wrong key length.");
if(isPrivate){
validateTrueOrElseThrow(RSAKey.getKeyOperations().size() == 1 &&
RSAKey.getKeyOperations().contains(KeyOperation.UNWRAP_KEY),
"The specified private key is not intended for 'unwrapKey' as specified through key operation.");
}
else{
validateTrueOrElseThrow(RSAKey.getKeyOperations().size() == 1 &&
RSAKey.getKeyOperations().contains(KeyOperation.WRAP_KEY),
"The specified public key is not intended for 'wrapKey' as specified through key operation.");
}
validateTrueOrElseThrow(RSAKey.getAlgorithm().equals(JWEAlgorithm.RSA_OAEP_256), "Key algorithm must be RSA-OAEP-256!");
validateTrueOrElseThrow(RSAKey.getPublicExponent().toString().equals("AQAB"), "Key must have e: \"AQAB\"");
}
private static void validateTrueOrElseThrow(boolean expression, String msg) {
if (!expression) {
throw new RuntimeException(msg);
}
}
```
</TabItem>
</Tabs>
## Nutzung des öffentlichen Schlüssels zur Verschlüsselung
<!-- https://git.fitko.de/fit-connect/examples/ -->
<Tabs
defaultValue="js"
values={[
......@@ -75,10 +160,10 @@ An dieser Stelle werden noch detailliertere Informationen und konkrete Implement
Die Umwandelung des JWK in eine Struktur, die für die Bibliothek [panva/jose](https://github.com/panva/jose) nutzbar ist, kann mithilfe einer Methode aus dieser Bibliothek durchgeführt werden.
```js
import { parseJwk } from "jose/jwk/parse"
import { CompactEncrypt } from "jose/jwe/compact/encrypt"
import { importJWK } from 'jose'
import { CompactEncrypt } from 'jose'
const publicKey = await parseJwk({
const publicKey = await importJWK({
"kty": "RSA",
"keyops": ["wrapKey"],
"x5c": [
......@@ -88,12 +173,12 @@ const publicKey = await parseJwk({
"alg": "RSA-OAEP-256",
"n": "sX2DX7rG5BoJd23A0...6ZqjRa1QcFnkq3_M4-tk",
"e": "AQAB"
})
}, "RSA-OAEP-256")
```
Mit dem zuvor eingelesenen Schlüssel können nun Zeichenketten und Binärdaten verschlüsselt werden.
Für die verschlüsselung von Zeichenketten (z.B. serialisierte JSON- oder XML-Objekte) kann die in Browser verfügbare [TextEncoder-API](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) verwendet werden, die den String UTF8-kodiert in ein `Uint8Array` umwandelt.
Für die Verschlüsselung von Zeichenketten (z.B. serialisierte JSON- oder XML-Objekte) kann die in Browser verfügbare [TextEncoder-API](https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder) verwendet werden, die den String UTF8-kodiert in ein `Uint8Array` umwandelt.
```js
const data = {
......@@ -103,7 +188,7 @@ const data = {
const encodedText = new TextEncoder().encode(JSON.stringify(data))
const encryptedText = await new CompactEncrypt(encodedText)
.setProtectedHeader({ alg: "RSA-OAEP-256", enc: "A256GCM", "zip": "DEF", "kid": publicKey.getKeyID(), "cty": "application/json" })
.setProtectedHeader({ alg: "RSA-OAEP-256", enc: "A256GCM" })
.encrypt(publicKey)
```
......@@ -115,7 +200,7 @@ Im Folgenden Beispiel wird eine Datei aus einem HTML-File-Input direkt heraus ve
// Verschlüsselung der ersten Datei aus einem Datei-Input: <input type="file" id="my-file-input" />
const buffer = await document.getElementById("my-file-input").files[0].arrayBuffer()
const encryptedText = await new CompactEncrypt(buffer)
.setProtectedHeader({ alg: "RSA-OAEP-256", enc: "A256GCM", "zip": "DEF", "kid": publicKey.getKeyID(), "cty": "application/pdf" }) // Format ("application/pdf") ggf. anpassen
.setProtectedHeader({ alg: "RSA-OAEP-256", enc: "A256GCM" })
.encrypt(publicKey)
```
......@@ -144,22 +229,22 @@ Mit diesem umgewandelten Schlüssel können nun Zeichenketten und Binärdaten ve
Über die [Payload-Klasse](https://www.javadoc.io/doc/com.nimbusds/nimbus-jose-jwt/latest/com/nimbusds/jose/Payload.html) können verschiedene Typen, wie `byte[]` oder `String`, verschlüsselt werden.
```java
// Schlüssel validieren
validateRSAKey(publicKey, false);
// Header erstellen und Header-Attribute gemäß kryptographischen Vorgaben setzen
JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM)
.keyID(keyId)
.compressionAlgorithm(CompressionAlgorithm.DEF)
.contentType("application/json") // anpassen, falls Daten in anderem Format übertragen werden (z.B. XML, PDF, etc.)
.build();
JWEHeader header = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM);
// Payload definieren - Option 1: Zeichenkette
Payload payload = new Payload("{ \"Hello\": \"World\"}");
// Payload definieren - Option 2: InputStream (z.B. für Datei)
Payload payload = new Payload(aFileInputStream.readAllBytes());
try {
// Payload definieren - Option 2: InputStream (z.B. für Datei)
Payload payload = new Payload(aFileInputStream.readAllBytes());
JWEObject jweObject = new JWEObject(header, payload);
JWEObject jweObject = new JWEObject(header, payload);
try {
jweObject.encrypt(new RSAEncrypter(publicKey));
String encrypted = jweObject.serialize();
......
......@@ -9,6 +9,11 @@ import TabItem from '@theme/TabItem'
## Eine neue Einreichung anlegen
Das Anlegen einer neuen Einreichung erfolgt über den Endpunkt <ApiLink api="submission-api" to="/v1/submissions" withMethod="post" /> der Submission API.
Hierbei legt das sendende System fest, an welchen Zustellpunkt der Einreichung versendet werden soll und welche Anlagen übermittelt werden sollen.
:::note Hinweis
Eine Übermittlung von Einreichungen an einen Zustellpunkt ist nur möglich, wenn sich dieser im [Status `active` befindet](../details/destination-management.mdx#statusmodell-eines-zustellpunktes).
:::
Anlagen werden dabei über UUIDs eindeutig identifiziert.
Die UUIDs der Anlagen müssen eindeutig sein und werden vom sendenden System festgelegt.
......@@ -16,16 +21,15 @@ Der Endpunkt erwartet folgende Parameter:
- Eine Destination-ID. Dies ist die eindeutige UUID des Zustellpunktes, an den die Einreichung vermittelt werden soll (`destinationId`). Im Artikel [Zustellpunkt Ermitteln](../responsibilities/get-destination.mdx) wird beschrieben wie diese ermittelt werden kann.
- Die Liste der angekündigten Anlagen (`announcedAttachments`). Dies ist eine Liste der Attachment-IDs aller Anlagen, die mit der Einreichung hochgeladen werden sollen. Die Liste enthält [eine UUIDv4](https://de.wikipedia.org/wiki/Universally_Unique_Identifier#(Pseudo)zuf%C3%A4llig_generierte_UUIDs_(Version_4)) für jedes Attachment. Die UUIDs müssen vom sendenden System selbst generiert werden. Für alle `announcedAttachments` muss anschließend das jeweilige Attachment hochgeladen werden (siehe [Anlagen hochladen](./attachments.mdx), bevor sich die Einreichung im Schritt [Einreichung versenden](submit.mdx) abschließen lässt.
- Außerdem wird ein Typ der Verwaltungsleistung erwartet (`serviceType`). Dies ist eine Beschreibung der Art der Verwaltungsleistung. Die angegebene Verwaltungsleistung muss der Verwaltungsleistung der Einreichung und einem der angebotenen Verwaltungsleistung des Zustellpunkts entsprechen. Für die jeweilige Verwaltungsleistung muss immer sowohl ein Name (`name`), als auch ein eindeutiger Identifier (`identifier`) angegeben werden. Der Identifier besteht aus einem einem Leistungsschlüssel und dem Präfix `urn:de:fim:leika:leistung:`. Ist für die gegebene Verwaltungsleistung kein Leistungsschlüssel vorhanden, kann die Verwaltungsleistung übergangsweise über die Angabe einer anderen eindeutigen Schema-URN beschrieben werden. Bestehende Leistungssschlüssel können [über das FIM-Portal](https://fimportal.de/) oder [über die LeiKa-Suche (inoffiziell)](https://opengovtech.de/leika/) ermittelt werden.
Optional kann hier auch ein Callback hinterlegt werden um Benachrichtigungen über neue Events der Einreichung zu erfahren. Näheres dazu wird im Artikel [Verwendung von Callbacks](../details/callbacks.mdx) beschrieben.
- Der Typ der Verwaltungsleistung (`serviceType`). Dies ist eine Beschreibung der Art der Verwaltungsleistung. Die angegebene Verwaltungsleistung muss der Verwaltungsleistung der Einreichung und einem der angebotenen Verwaltungsleistung des Zustellpunkts entsprechen. Für die jeweilige Verwaltungsleistung muss immer sowohl ein Name (`name`), als auch ein eindeutiger Identifier (`identifier`) angegeben werden. Der Identifier besteht aus einem einem Leistungsschlüssel und dem Präfix `urn:de:fim:leika:leistung:`. Ist für die gegebene Verwaltungsleistung kein Leistungsschlüssel vorhanden, kann die Verwaltungsleistung übergangsweise über die Angabe einer anderen eindeutigen Schema-URN beschrieben werden. Bestehende Leistungssschlüssel können [über das FIM-Portal](https://fimportal.de/) oder [über die LeiKa-Suche (inoffiziell)](https://opengovtech.de/leika/) ermittelt werden.
- Optional kann hier auch ein Callback hinterlegt werden, um Benachrichtigungen über neue Events der Einreichung zu erfahren. Näheres dazu wird im Artikel [Verwendung von Callbacks](../details/callbacks.mdx) beschrieben.
:::note Hinweis
Die für das Anlegen von Einreichungen notwendige Struktur von Einreichungen und die Referenzierung von Fachdatenschemata ist im Artikel [Aufbau einer Einreichung](../getting-started/submission/structure.mdx) näher beschrieben.
:::
:::note Hinweis
Die URL der Submission API findet sich im Artikel [Erste Schritte](../getting-started/first-steps.mdx#testing).
Die URL der Submission API findet sich im Artikel [Erste Schritte](../getting-started/get-started.mdx#testing).
:::
......
......@@ -7,9 +7,9 @@ module.exports = {
'status-and-error-codes',
{
type: 'category',
label: 'Grundlagen',
label: 'Infos für Entwickler:innen',
items: [
'getting-started/first-steps',
'getting-started/get-started',
'getting-started/account',
'getting-started/authentication',
{
......@@ -21,9 +21,34 @@ module.exports = {
'getting-started/submission/data',
]
},
'getting-started/notifications-and-deletion-deadlines',
'getting-started/schema-validation',
'getting-started/encryption',
{
type: 'category',
label: 'Versand von Einreichungen',
items: [
'sending/overview',
'sending/start-submission',
'sending/metadata',
'sending/encrypt',
'sending/attachments',
'sending/submit',
'sending/query-status',
'sending/accept-reject',
]
},
{
type: 'category',
label: 'Abruf von Einreichungen',
items: [
'receiving/overview',
'receiving/certificate',
'receiving/destination',
'receiving/notification',
'receiving/download-submission',
'receiving/decrypt',
'receiving/verification',
'receiving/process-and-acknowledge',
]
},
{
type: 'category',
label: 'Ereignisprotokoll',
......@@ -33,7 +58,10 @@ module.exports = {
'getting-started/event-log/set-creation',
'getting-started/event-log/set-validation',
]
},
},
'getting-started/notifications-and-deletion-deadlines',
'getting-started/schema-validation',
'getting-started/encryption',
'getting-started/rate-limiting',
],
},
......@@ -45,38 +73,12 @@ module.exports = {
'responsibilities/get-destination'
]
},
{
type: 'category',
label: 'Versand von Einreichungen',
items: [
'sending/overview',
'sending/start-submission',
'sending/metadata',
'sending/encrypt',
'sending/attachments',
'sending/submit',
'sending/query-status',
'sending/accept-reject',
]
},
{
type: 'category',
label: 'Abruf von Einreichungen',
items: [
'receiving/overview',
'receiving/certificate',
'receiving/destination',
'receiving/notification',
'receiving/download-submission',
'receiving/decrypt',
'receiving/verification',
'receiving/process-and-acknowledge',
]
},
{
type: 'category',
label: 'Weiterführende Informationen',
items: [
'details/ags',
'details/ars',
'details/callbacks',
'details/crypto',
'details/jwk-creation',
......
import React from 'react';
import {Redirect} from '@docusaurus/router';
export default function get_started() {
return (
<p>
<Redirect to="../../../docs/getting-started/get-started" />
</p>
);
}
\ No newline at end of file
......@@ -52,7 +52,7 @@ export default function ApiSpec(props) {
allow-spec-file-load="false"
allow-authentication={props.allowAuthentication || "true"}
info-description-headings-in-navbar="false"
allow-try="false"
allow-try={props.allowTry || "false"}
primary-color="#11171a"
allow-server-selection="false"
server-url=""
......
File added
static/images/roadmap/fitconnect_roadmap.png

920 KiB | W: 0px | H: 0px

static/images/roadmap/fitconnect_roadmap.png

397 KiB | W: 0px | H: 0px

static/images/roadmap/fitconnect_roadmap.png
static/images/roadmap/fitconnect_roadmap.png
static/images/roadmap/fitconnect_roadmap.png
static/images/roadmap/fitconnect_roadmap.png
  • 2-up
  • Swipe
  • Onion skin
static/images/roadmap/fitconnect_useage_scenario.png

76.7 KiB | W: 0px | H: 0px

static/images/roadmap/fitconnect_useage_scenario.png

118 KiB | W: 0px | H: 0px

static/images/roadmap/fitconnect_useage_scenario.png
static/images/roadmap/fitconnect_useage_scenario.png
static/images/roadmap/fitconnect_useage_scenario.png
static/images/roadmap/fitconnect_useage_scenario.png
  • 2-up
  • Swipe
  • Onion skin