Requirements
BSI-eRp-ePA
O.Arch_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_1 | „Security“ ist Bestandteil des Softwareentwicklungs- und Lebenszyklus. | „Security“ MUSS ein fester Bestandteil des Softwareentwicklungs- und Lebenszyklus‘ für die gesamte Anwendung sein (vgl. „iOS Security Framework”[iOSSF], beziehungsweise „Design for Safety“ [DfS]). | Der Evaluator prüft, ob der Quelltext und die Design-Dokumente auf die Verwendung aktueller „Best- Practices“ bei der Entwicklung schließen lassen. | CHECK |
Implementation
See external SSDLC documentation.
O.Arch_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_2 | Berücksichtigung der Verarbeitung sensibler Daten in der Design-Phase. | Bereits in der Designphase der Anwendung MUSS berücksichtigt werden, dass die Anwendung in der Produktivphase sensible Daten verarbeiten wird. Die Architektur der Anwendung MUSS dafür die sichere Erhebung, Verarbeitung, Speicherung und Löschung der sensiblen Daten in einem Datenlebenszyklus gewährleisten. | Der Evaluator prüft Design- und Architektur-Dokumente auf die Berücksichtigung der Verarbeitung sensibler Daten inkl. des Datenlebenszyklus. | CHECK |
Implementation
See external Data and Security concept.
O.Arch_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_3 | Dokumentation des Lebenszyklus von kryptographischem Material. | Der Lebenszyklus von kryptographischem Schlüsselmaterial MUSS einer ausgearbeiteten Richtlinie folgen, die Eigenschaften wie die Zufallszahlenquelle, detaillierte Angaben zur Aufgabentrennung von Schlüsseln, Ablauf von Schlüsselzertifikaten, Integritätssicherung durch Hash-Algorithmen etc., umfasst. Die Richtlinie SOLL auf anerkannten Standards wie [TR02102- 2] und [NIST80057] basieren. | Der Evaluator bewertet die ausgearbeitete Richtlinie des Herstellers und deren Berücksichtigung in der Risikobewertung. | CHECK |
Implementation
All cryptography is specified by gemSpec_Krypt in corporation with BSI
O.Arch_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_4 | Keine unverschlüsselten sensiblen Daten in Backups. | In Backups gespeicherte sensiblen Daten MÜSSEN gemäß dem aktuellen Stand der Technik verschlüsselt sein. | Der Evaluator prüft durch Quelltextanalyse und praktische Tests, ob sensible Daten unverschlüsselt in Backups vorhanden sind. | EXAMINE |
Implementation
All data is either stored encrypted within the keychain or excluded from system backup, which also excludes files from cloud backup.
../Sources/eRpLocalStorage/CoreDataController.swift:83
Database backup exclusion
// [REQ:BSI-eRp-ePA:O.Purp_8#4,O.Arch_4#2,O.Data_15#1] Database backup exclusion
if excludeFromBackup, let storeUrl = store.url {
../Sources/eRpApp/Session/KeychainStorage.swift:21
Implementation of data storage that is persisted via keychain
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
O.Arch_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_5 | Verteilte Implementierung von Sicherheitsfunktionen. | Sicherheitsfunktionen MÜSSEN immer auf allen Außenschnittstellen und API-Endpunkten implementiert werden. | Der Evaluator prüft das Vorhandensein und die Güte von Sicherheitsfunktionen durch Quelltextanalyse und praktische Tests. Als Sicherheitsfunktionen sind unter anderem Authentifizierung, Autorisierung, Input-Validierung und die Verwendung von Escape- Syntaxen zu verstehen. | EXAMINE |
Implementation
CAN and PIN verification is not done within the application but on the eGK chip. Actual authentication by confirming the eGK signature and validating the eGK certificate is done by the IDP. Authorization of users is done by the FD by validating the Access-Token signature. For Input-Validation and Escaping please see O.Source_1 and O.Source_2.
O.Arch_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_6 | Authentizitäts- und Integritätsschutz der Applikation. | Die Anwendung MUSS die Überprüfung der Integrität durch eine digitale Signatur ermöglichen. Die Authentizität der Anwendung ist durch die Vertrauenswürdigkeit der Bezugsquelle (s. A.Source) sichergestellt. | Der Evaluator prüft das Vorhandensein und die Güte des eingesetzten Authentizitäts- und Integritätsschutzes durch Quelltextanalyse und praktische Tests. Hierbei ist auf die Aktualität (siehe [TR02102-1]) der eingesetzten Signaturverfahren zu achten. Die Wirksamkeit gegen eine Manipulation der Applikation (siehe T.MemoryStructures ist in der Risikobewertung zu betrachten. | EXAMINE |
Implementation
Apple already implements this with a signed binary delivered to customers. An altered application can only run on a jailbroken device. If a user is using a jailbroken device, may it be known or unknown, we display a security alert so a user can make an informed decision to use or not use the application.
../Sources/eRpApp/Screens/Main/MainView.swift:95
trigger device security check
// [REQ:BSI-eRp-ePA:O.Arch_6#2,O.Resi_2#2,O.Plat_1#2] trigger device security check
store.send(.loadDeviceSecurityView)
../Sources/eRpApp/Session/Helper/DeviceSecurityManager.swift:58
calculate system risk for jailbreak and missing device pin
// [REQ:BSI-eRp-ePA:O.Arch_6#3,O.Resi_2#3,O.Plat_1#3] calculate system risk for jailbreak and missing device pin
var showSystemSecurityWarning: AnyPublisher<DeviceSecurityWarningType, Never> {
../Sources/eRpApp/Session/Helper/DeviceSecurityManager.swift:112
Jailbreak detection
// [REQ:BSI-eRp-ePA:O.Arch_6#4,O.Resi_2#4] Jailbreak detection
func informJailbreakDetected() -> Bool {
../Sources/eRpApp/Screens/Main/DeviceSecurity/DeviceSecurityRootedDevice/DeviceSecurityRootedDeviceView.swift:9
Jailbreak information view
// [REQ:BSI-eRp-ePA:O.Arch_6#5,O.Resi_2#5] Jailbreak information view
struct DeviceSecurityRootedDeviceView: View {
O.Arch_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_7 | Sichere Nutzung der Funktionen von Drittanbieter-Software. | Nutzt die Anwendung Drittanbieter-Software (etwa für Objektserialisierung), MUSS der Hersteller sicherstellen, dass nur solche Drittanbieter-Software zum Einsatz kommen, deren zu nutzenden Funktionen sicher genutzt werden können und dem Nutzer Informationen über den Nutzungsumfang und die eingesetzten Sicherheitsmechanismen klar darstellen. Die Anwendung MUSS diese Funktionen sicher nutzen. Der Hersteller MUSS darüber hinaus sicherstellen, dass ungenutzte Funktionen durch Dritte nicht aktiviert werden können. | Der Evaluator prüft, durch Quelltextanalyse und praktische Tests, dass Funktionalitäten sicher verwendet werden und ungenutzte Funktionalitäten nicht zugänglich sind. Darüber hinaus prüft er, ob der Nutzer ausreichend über die Verwendung von Drittanbieter- Software informiert wird. | EXAMINE |
Implementation
See Source/eRpApp/Resources/en.lproj/FOSS.html
for library usage purposes. We use Swift as our programming language. We do not use reflections for calling a businesslogic. That’s why we can be sure, that library code (that we do not use) cannot be executed.
O.Arch_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_8 | Zweckgebundener Zugriff auf verschlüsselte Speicher oder Nutzerdaten durch interpretierenden Code. | Interpretierter Code , der in möglichen Interaktionen mit Benutzereingaben steht (WebViews mit JavaScript), DARF KEINEN Zugriff auf verschlüsselte Speicher oder Nutzerdaten haben, sofern es für die Erfüllung des primären Zwecks der Anwendung nicht zwingend erforderlich ist. | Der Evaluator prüft durch Quelltextanalyse und praktische Tests, ob ein Zugriff auf verschlüsselte Speicher oder Nutzerdaten über interpretierten Code möglich ist. Falls dies der Fall ist, prüft er die Abwägungen des Herstellers zur zwingenden Notwendigkeit für die Erfüllung des primären Zwecks und die Berücksichtigung in der Risikobewertung. | EXAMINE |
Implementation
../Sources/eRpApp/Screens/Settings/TermsOfUse/TermsOfUseView.swift:12
Webview containing local html without javascript
// [REQ:BSI-eRp-ePA:O.Purp_3#2] Actual view for the Terms of Use display
// [REQ:BSI-eRp-ePA:O.Arch_8#1] Webview containing local html without javascript
struct TermsOfUseView: View {
../Sources/eRpApp/Screens/Settings/FOSS/FOSSView.swift:10
Webview containing local html without javascript
// [REQ:BSI-eRp-ePA:O.Arch_8#2] Webview containing local html without javascript
struct FOSSView: View {
../Sources/eRpApp/Screens/Settings/DataPrivacy/DataPrivacyView.swift:13
Webview containing local html without javascript
// [REQ:BSI-eRp-ePA:O.Purp_1#2] Actual View driving the display of `DataPrivacy.html`
// [REQ:BSI-eRp-ePA:O.Arch_8#3] Webview containing local html without javascript
// [REQ:gemSpec_eRp_FdV:A_19980#2] Actual View driving the display of `DataPrivacy.html`
struct DataPrivacyView: View {
O.Arch_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_9 | Barrierearme Möglichkeit zum Melden von Sicherheitsproblemen. | Der Hersteller MUSS dem Nutzer eine barrierearme Möglichkeit bereitstellen, um Sicherheitsprobleme zu melden. Die Kommunikation SOLL über einen verschlüsselten Kanal stattfinden. | Der Evaluator prüft, ob eine entsprechende Möglichkeit vorhanden ist. Falls kein verschlüsselter Kanal bereitgestellt wird, ist dies in der Risikobewertung zu berücksichtigen. | CHECK |
Implementation
Link within DataPrivacy.html to https://www.gematik.de/datensicherheit
../Sources/eRpApp/Screens/Onboarding/OnboardingContainer.swift:46
DataPrivacy display within Onboarding
// [REQ:BSI-eRp-ePA:O.Arch_9#2] DataPrivacy display within Onboarding
.sheet(isPresented: $store.showTermsOfPrivacy.sending(\.setShowPrivacy)) {
../Sources/eRpApp/Screens/Settings/SettingsLegalInfoView.swift:28
DataPrivacy display within Settings
// [REQ:BSI-eRp-ePA:O.Arch_9#3,O.Purp_1#4] DataPrivacy display within Settings
NavigationLink(
O.Arch_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_10 | Anwendung fragt Zwangsupdates vom Hintergrundsystem ab. | Die Anwendung SOLL beim Start auf verfügbare sicherheitsrelevante Updates prüfen. Wenn ein sicherheitsrelevantes Update verfügbar ist, DARF die Anwendung sensible Daten NICHT mehr verarbeiten, ohne dieses Update einzuspielen. Der Nutzer MUSS über die Möglichkeit eines Updates und über ein durchgeführtes Update informiert werden. | Der Evaluator prüft die Güte der Implementierung der entsprechenden Funktionalität in der Anwendung. Falls diese nicht vorhanden ist, prüft er die Abwägungen des Herstellers zu den Auswirkungen auf die Sicherheit der Anwendung. Dies ist in der Risikobewertung zu berücksichtigen. Falls die Funktionalität vorhanden ist, prüft der Evaluator mit praktischen Tests, ob das Blockieren einzelner Anfragen eine weitere Nutzung der Anwendung wirksam unterbindet. | EXAMINE |
Implementation
Implemented via APIKey usage against APOVZD and FD. All requests against the backends may respond with an 403 status code. The App stays usable, but only without any server connection. The user is informed, that an update is required.
../Sources/eRpApp/Screens/Main/MainView.swift:91
Trigger for the update check
// [REQ:BSI-eRp-ePA:O.Arch_10#2] Trigger for the update check
await store.send(.checkForForcedUpdates).finish()
../Sources/eRpApp/Screens/Main/MainDomain.swift:227
The actual business logic for the update check
// [REQ:BSI-eRp-ePA:O.Arch_10#3] The actual business logic for the update check
return .run(operation: { [updateChecked = state.updateChecked] send in
O.Arch_11
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_11 | Bereitstellung von Updates über einen eigenen App-Store. | Der Hersteller MUSS für die Veröffentlichung der Anwendung (und ihrer Updates) eine Quelle wählen, auf der die Anwendung gegen Manipulation durch Unbefugte geschützt ist und die einen vertrauenswürdigen Kanal zum Bezug der Anwendung zur Verfügung stellt. | Der Evaluator prüft, ob der Hersteller einen eigenen App-Store zur Verfügung stellt. Daraus resultierende Abwägungen und Auswirkungen auf die Sicherheit sind in der Risikobewertung zu berücksichtigen. | CHECK |
Implementation
Sole source for the app is the official Apple AppStore. Apple provides a secure ecosystem for downloading applications that incorporate signing and verification of the application. The app is only available in the AppStore and not in any other store.
O.Arch_12
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Arch_12 | Nutzung kryptographischer Maßnahmen bei alternativen Download- Quellen/Mechanismen. | Der Hersteller MUSS dem App-Nutzer einfach und sicher zugängliche Wege zum Bezug der Anwendung bereitstellen (z.B. in Form einer Link-Liste auf seiner Website, als individuell zugestellter QR-Code, o. Ä.). | Der Evaluator prüft durch Quelltextanalyse das Vorhandensein und die Güte der eingesetzten Verfahren. | CHECK |
Implementation
Not applicable as we are only using the official Apple AppStore.
O.Auth_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_1 | Herstellerkonzept zur Authentisierung , Autorisierung und Beenden von Anwendungssitzungen. | Der Hersteller MUSS ein Konzept zur Authentisierung auf angemessenem Vertrauensniveau (vgl. [TR03107-1]), zur Autorisierung (Rollenkonzept) und zum Beenden einer Anwendungssitzung dokumentieren. | Der Evaluator prüft das vom Hersteller bereitgestellt Konzept zur Authentisierung, Autorisierung und Beenden der Anwendungssitzung. Er bewertet die Güte der eingesetzten Verfahren Anhand des aktuellen Standes der Technik. Nach Einschätzung des BSI existieren aktuell keine Verbraucherendgeräte, die in einem unüberwachten Anwendungsszenario Biometrie zur Identifikation oder Authentisierung auf einem Vertrauensniveau „hoch“ einsetzen können. | CHECK |
Implementation
Our authentication concept is described in the following repository: https://github.com/gematik/api-erp/blob/master/docs/authentisieren.adoc. Roles in the scope of the IDP are defined in https://gemspec.gematik.de/docs/gemSpec/gemSpec_IDP_Dienst/latest/#3.1. As stated in O.Auth_14, we have no mechanism to invalidate tokens.
O.Auth_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_2 | Getrennte Realisierung von Authentifizierungsmechanismen und Autorisierungsfunktionen. | Die Anwendung SOLL Authentisierungsmechanismen und Autorisierungsfunktionen separat realisieren. Sind für die Anwendung verschiedene Rollen notwendig, MUSS eine Autorisierung bei jedem Datenzugriff separat realisiert werden. | Der Evaluator prüft und bewertet die getroffenen Maßnahmen zur Trennung von Autorisierungs- und Authentifizierungsmechanismen. Sollte keine Trennung der Mechanismen vorgenommen sein, sind die Abwägungen des Herstellers zu prüfen und in der Risikobewertung zu berücksichtigen. | EXAMINE |
Implementation
There is no client side separation of authentication and authorization.
O.Auth_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_3 | Zwei-Faktor-Authentisierung. | Jeder Authentifizierungsvorgang des Nutzers MUSS in Form einer Zwei-Faktor- Authentisierung umgesetzt werden. | Der Evaluator prüft durch Quelltextanalyse und praktische Tests das Vorhandensein und die Güte der Zwei-Faktor- Authentisierung. Insbesondere prüft er, ob die verwendeten Faktoren aus unterschiedlichen Kategorien stammen (Wissen und Besitz) und mit dem in O.Auth_1 beschriebenem Konzept übereinstimmen. | EXAMINE |
Implementation
One way to connect to the FD is to login by using the eGK. For that login, the physical card, as well as knowledge of the PIN is required. Login via gID (Gesundheits ID) is described in O.Auth_4.
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.swift:182
Implementation of eGK connection
// [REQ:BSI-eRp-ePA:O.Auth_3#2] Implementation of eGK connection
case let .signChallenge(challenge):
O.Auth_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_4 | Authentisierung über zusätzliche Verfahren, welche einem niedrigeren Sicherheitsniveau entsprechen. | Zusätzlich zu der in O.Auth_1 definierten Authentisierung auf einem angemessenen Vertrauensniveau, KANN der Hersteller dem Nutzer gemäß § 139e Abs. 10 SGB V, nach umfassender Information und Einwilligung, eine Authentisierungsmöglichkeit auf einem niedrigeren Vertrauensniveau anbieten. Dies schließt das Anbieten zusätzlicher Verfahren basierend auf den digitalen Identitäten im Gesundheitswesen gemäß § 291 Abs. 8 SGB V mit ein. | Der Evaluator prüft das Vorhandensein von Authentisierungsmöglichkeiten mit einem niedrigeren Sicherheitsniveau. Sollten solche Verfahren angeboten werden, prüft der Evaluator durch Quelltextanalyse und praktische Tests, ob diese eine angemessene Sicherheit bieten. Angemessene Sicherheitsanforderungen für niederschwellige Verfahren sind der jeweils aktuellen Version der „Spezifikation Sektoraler Identity Provider“ der gematik GmbH zu entnehmen [gemSpec_IDP_Sek]. Die Abwägungen des Herstellers, zum Bereitstellen zusätzlicher Authentisierungsmöglichkeiten und der gewählten Implementierung, sind in der Risikobewertung zu berücksichtigen. | EXAMINE |
Implementation
Authentication via gID (Gesundheits ID) is possible. To do that an inter-app flow is used that opens the insurance company app on the users device, and after successfull authentication there, jumps back into the E-Rezept-App.
../Sources/eRpApp/Screens/CardWall/Introduction/CardWallIntroductionView.swift:125
Button the user may use to start login via gID
// [REQ:BSI-eRp-ePA:O.Auth_4#2] Button the user may use to start login via gID
Button(action: {
../Sources/eRpApp/Screens/CardWall/Introduction/CardWallIntroductionDomain.swift:154
Present the gID flow for selecting the correct insurance company
// [REQ:BSI-eRp-ePA:O.Auth_4#3] Present the gID flow for selecting the correct insurance company
.extAuthTapped:
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionView.swift:12
View containing the list of insurance companies
// [REQ:BSI-eRp-ePA:O.Auth_4#4] View containing the list of insurance companies
struct CardWallExtAuthSelectionView: View {
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionView.swift:52
User selection of the insurance company
// [REQ:BSI-eRp-ePA:O.Auth_4#5] User selection of the insurance company
Button(action: {
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionDomain.swift:90
Business logic of user selecting the insurance company
// [REQ:BSI-eRp-ePA:O.Auth_4#6] Business logic of user selecting the insurance company
// [REQ:gemSpec_IDP_Frontend:A_22294-01] Select KK
state.selectedKK = entry
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionDomain.swift:93
Proceed to confirmation screen
// [REQ:BSI-eRp-ePA:O.Auth_4#7] Proceed to confirmation screen
case .confirmKK:
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationView.swift:10
Confirmation Dialog with brief explanation
// [REQ:BSI-eRp-ePA:O.Auth_4#8] Confirmation Dialog with brief explanation
struct CardWallExtAuthConfirmationView: View {
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationView.swift:72
User confirms the insurance company
// [REQ:BSI-eRp-ePA:O.Auth_4#8] User confirms the insurance company
PrimaryTextButton(text: L10n.cdwBtnExtauthConfirmSend,
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationDomain.swift:91
Start login via gID
// [REQ:gemSpec_IDP_Frontend:A_22294-01] Start login via gID
// [REQ:BSI-eRp-ePA:O.Auth_4#9,O.Plat_10#2] Start login via gID
return .publisher(
O.Auth_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_5 | Zusätzliche Informationen bei Bewertung des Authentifizierungsvorgangs einbeziehen. | Für die Bewertung eines Authentisierungsvorgangs SOLLEN zusätzliche Informationen (z. B. das verwendete Endgerät, der verwendete WiFi-Zugangsknoten oder die Zeit des Zugriffs) mit einbezogen werden. | Der Evaluator prüft das Vorhandensein und die Güte von zusätzlichen Informationen zur Bewertung eines Authentifizierungsvorgangs. Solche Informationen können beispielsweise über die Invalidierung/Löschung von Schlüsseln bei Änderung von Merkmalen biometrischer Systeme oder eine Prüfung auf Änderung von biometrischen Metadaten umgesetzt werden. Eine Prüfung auf Konformität zum Datenschutz der erhobenen Informationen ist im Rahmen der TR nicht erforderlich, eine zusätzliche Prüfung ist daher empfehlenswert. Werden keine zusätzlichen Informationen zur Bewertung verwendet, prüft der Evaluator die Abwägungen des Herstellers. Diese sind in der Risikobewertung zu berücksichtigen. | EXAMINE |
Implementation
If the registered biometric features get changed (within system settings), private keys for alternate authentication are deleted. For privacy reasons, neither the FD nor the application gather or store user data that is not crutial, e.g. the current WiFi.
../Sources/IDP/PrivateKeyContainer.swift:133
Key invalidates on changes of registered
// [REQ:gemSpec_IDP_Frontend:A_21586] invalidates biometry after changes
// [REQ:BSI-eRp-ePA:O.Auth_5#2] Key invalidates on changes of registered
// biometric features
.biometryCurrentSet], &error) else {
O.Auth_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_6 | Information des Benutzers über ungewöhnliche Anmeldeversuche. | Dem Nutzer SOLL eine Möglichkeit gegeben werden, sich über ungewöhnliche Anmeldevorgänge informieren zu lassen. | Der Evaluator prüft, ob dem Nutzer leicht zugänglich die Möglichkeit gegeben wird, Informationen zu Anmeldevorgängen nachzuvollziehen. Ist das nicht der Fall, sind die Abwägungen des Herstellers zu prüfen und in der Risikobewertung zu berücksichtigen. | CHECK |
Implementation
We increment a counter whenever the application is opened and an attempt to unlock the application fails. If the counter is greater than 0, the user is informed about that in a hint on the password/unlock screen. For remote logins, an Audit Log for every FD access is available in each user profile.
../Sources/eRpApp/Screens/Settings/Profiles/Edit/EditProfileView.swift:401
Actual Button to open the audit events
// [REQ:gemSpec_eRp_FdV:A_19177#2,A_19185#3] Actual Button to open the audit events
// [REQ:BSI-eRp-ePA:O.Auth_6#2] Actual Button to open the audit events
NavigationLink(item: $store.scope(state: \.destination?.auditEvents,
../Sources/eRpApp/Screens/Settings/Profiles/Protocol/AuditEventsView.swift:13
View displaying the audit events
// [REQ:gemSpec_eRp_FdV:A_19177#1,A_19185#2] View displaying the audit events
// [REQ:BSI-eRp-ePA:O.Auth_6#3] View displaying the audit events
struct AuditEventsView: View {
O.Auth_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_7 | Verhinderung des Ausprobierens von Login-Parametern. | Die Anwendung MUSS Maßnahmen umsetzen, die ein Ausprobieren von Login-Parametern (z. B. Passwörter) erschweren. | Der Evaluator validiert, dass ein Ausprobieren von Login- Parametern verhindert wird. Dies kann beispielsweise durch Verzögerung nachfolgender Login- Versuche oder den Einsatz von sogenannten Captchas erreicht werden. | CHECK |
Implementation
There are no passwords to guess for server login within our application. Only eGK login is directly available within the application. The users application password is not delayed, as any user with Device-PIN access would have access to the unencrypted file system as well.
../Sources/eRpApp/Screens/AppAuthentication/AppAuthenticationPassword/AppAuthenticationPasswordDomain.swift:8
Domain handling App Authentication
// [REQ:BSI-eRp-ePA:O.Auth_7#2] Domain handling App Authentication
@Reducer
O.Auth_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_8 | Erneute Authentifizierung bei unterbrochener Anwendung. | Wurde die Anwendung unterbrochen (in den Hintergrundbetrieb versetzt), MUSS nach Ablauf einer angemessenen Frist (Grace Period) eine erneute Authentisierung durchgeführt werden. | Der Evaluator validiert, dass nach einer der Anwendung angemessenen Zeit, in der sie in den Hintergrundmodus versetzt wurde, eine erneute Authentifizierung erfolgen muss. Die Güte der geforderten Authentifizierung muss dem Vertrauensniveau angemessen sein (vgl. O.Auth_3). | CHECK |
Implementation
The SceneDelegate
exchanges the active window with an authentication window, every time the app gains focus.
../Sources/eRpApp/SceneDelegate.swift:179
Present the authentication window
// [REQ:BSI-eRp-ePA:O.Auth_8#2] Present the authentication window
// [REQ:gemSpec_eRp_FdV:A_24857#2] Present the authentication window upon every startup
// dispatching necessary to prevents keyboard not showing on iOS 16
DispatchQueue.main.async { [weak self] in
O.Auth_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_9 | Erneute Authentifizierung nach angemessenen Zeit in der die Anwendung nicht aktiv verwendet wurde. | Die Anwendung MUSS nach einer angemessenen Zeit in der sie nicht aktiv verwendet wurde (idle time) eine erneute Authentisierung fordern. | Der Evaluator validiert, dass nach einer der Anwendung angemessenen Zeit, in der sie nicht aktiv verwendet wurde, eine erneute Authentifizierung erfolgen muss. Die Güte der geforderten Authentifizierung muss dem Vertrauensniveau angemessen sein (vgl. O.Auth_3). | CHECK |
Implementation
A Timer is used to measure the time a user is inactive. Every user interaction resets the timer.
../Sources/eRpApp/SceneDelegate.swift:337
The timer used to determine inactivity
// [REQ:BSI-eRp-ePA:O.Auth_9#2] The timer used to determine inactivity
self?.presentAppAuthenticationDomain(scene: scene)
../Sources/eRpApp/SceneDelegate.swift:318
The timer is reset on user interaction
// [REQ:BSI-eRp-ePA:O.Auth_9#3] The timer is reset on user interaction
self?.setupTimer(scene: scene)
../Sources/eRpApp/SceneDelegate.swift:347
User interaction is determined by using a higher order reducer watching all
// [REQ:BSI-eRp-ePA:O.Auth_9#4] User interaction is determined by using a higher order reducer watching all
// actions
NotificationCenter.default.post(name: .userInteractionDetected, object: nil, userInfo: nil)
../Sources/eRpApp/SceneDelegate.swift:47
Concat the user interaction reducer to the normal application reducer
// [REQ:BSI-eRp-ePA:O.Auth_9#5] Concat the user interaction reducer to the normal application reducer
reducer: AppStartDomain().analytics().notifyUserInteraction().prepareUITestsDependencies(),
O.Auth_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_10 | Erneute Authentifizierung nach angemessenen Zeit in der die Anwendung dauerhaft aktiv verwendet wurde. | Die Anwendung MUSS nach einer angemessenen Zeit in der sie aktiv verwendet wurde (active time) eine erneute Authentisierung zur Reaktivierung der Serversitzung fordern. | Der Evaluator validiert, dass nach einer der Anwendung angemessenen Zeit, in der sie dauerhaft aktiv verwendet wurde, eine erneute Authentifizierung erfolgen muss. Die Güte der geforderten Authentifizierung muss dem Vertrauensniveau angemessen sein (vgl. O.Auth_3). | EXAMINE |
Implementation
Token invalidation happens after 12 hours. If a user is still active, a re-authentication via eGK, Biometrics or Insurance App is necessary. Each meaning the possession and or knowledge of the needed user input.
../Sources/IDP/DefaultIDPSession.swift:784
The application is also checking for Access-Token expiration
// [REQ:BSI-eRp-ePA:O.Auth_10#2] The application is also checking for Access-Token expiration
guard token.expires > time() else {
O.Auth_11
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_11 | Ausreichende Authentifizierung des Nutzers für Änderung der Authentisierungsdaten. | Die Authentisierungsdaten DÜRFEN NICHT ohne eine erneute Authentifizierung des Nutzers geändert werden. | Der Evaluator prüft, ob er ohne angemessene Authentifizierung die Authentisierungsdaten verändern kann. Dies betrifft auch einen Ablauf zum Passwort zurücksetzen. Beruht dieser Ablauf bspw. auf Sicherheitsabfragen, darf die Antwort nicht einfach zu erraten oder gar aus möglicherweise öffentlichen Informationen ermittelbar sein (z.B. Mädchenname der Mutter). | EXAMINE |
Implementation
Authentication via eGK cannot be altered, as the physical card cannot be modified without authentication (e.g. PIN change). See gemSpec_COS for details. Adding a authentication key that is secured via biometrics (labeled as “save login” within the card wall) enforces a new authentication via eGK on server side. There is no other way to change existing login “credentials”, as there is no “password”.
O.Auth_12
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_12 | Authentifizierung an der Schnittstelle zwischen Anwendung und Hintergrundsystem. | Die Anwendung MUSS für die Anbindung eines Hintergrundsystems eine dem Stand der Technik entsprechende Authentifizierung verwenden. | Der Evaluator prüft, ob die Anwendung eine Authentifizierung des Hintergrundsystems unterstützt. | CHECK |
Implementation
We use TI Certificate Pinning and a Trust Store for VAU communication. See TrustStore and VAU Module for implementation.
O.Auth_13
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_13 | Schutz von Authentisierungsdaten. | Authentisierungsdaten, wie bspw. Session- Identifier bzw. Authentisierungstoken, MÜSSEN als sensible Daten geschützt werden. | Der Evaluator prüft, ob Authentisierungsdaten als sensible Daten gemäß den Anforderungen der TR behandelt werden. | CHECK |
Implementation
Session tokens and related data are stored within the keychain. We embrace a protocol specifically made for storing data that needs to be secured.
../Sources/eRpKit/SecureUserDataStore.swift:15
The protocol for storing secured data
/// Interface to access user specific data that should be kept private
/// sourcery: StreamWrapped
/// [REQ:BSI-eRp-ePA:O.Auth_13#2|11] The protocol for storing secured data
public protocol SecureUserDataStore: IDPStorage, SecureEGKCertificateStorage {
/// Set the CAN
///
/// - Parameter can: the CAN to set and save
func set(can: String?)
/// Wipe the whole storage and delete all user information
func wipe()
}
../Sources/eRpApp/Session/KeychainStorage.swift:22
Implementation of data storage that is persisted via keychain
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
O.Auth_14
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_14 | Invalidierung von Authentisierungsdaten durch den Anwender. | Die Anwendung MUSS es dem Nutzer ermöglichen einen oder alle zuvor ausgestellten Session-Identifier bzw. Authentisierungstoken zu invalidieren. | Der Evaluator prüft, ob die Anwendung dem Nutzer ermöglicht, ein oder alle zuvor ausgestellten Authentisierungsdaten ungültig zu machen. | CHECK |
Implementation
Our Authentication Tokens cannot be invalidated effectivley as they are stateless and no server stores active/valid tokens anywhere. Invalidating Authentication Tokens in our context means deleting them on client side. The client side invalidation can thus be done by manual logout or profile deletion. Logout is accessible within the Settings -> Specific User Profile -> Logout.
../Sources/eRpApp/Screens/Settings/Profiles/Edit/EditProfileView.swift:179
The user may use the logout button within each profile
// [REQ:BSI-eRp-ePA:O.Auth_14#2|5] The user may use the logout button within each profile
Button(action: {
store.send(.delegate(.logout))
}, label: {
Text(L10n.stgBtnEditProfileLogout)
})
../Sources/eRpApp/Screens/Settings/Profiles/Edit/EditProfileDomain.swift:252
The domain accepts the intent and wipes tokens and other login related data
// [REQ:BSI-eRp-ePA:O.Auth_14#3|6] The domain accepts the intent and wipes tokens and other login related data
case .delegate(.logout):
state.token = nil
// [REQ:gemSpec_IDP_Frontend:A_20499-01#1] Call the SSO_TOKEN removal upon manual logout
return .run { [profileId = state.profileId] _ in
try await profileSecureDataWiper.wipeSecureData(of: profileId).async()
}
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:43
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-01#2] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
// [REQ:BSI-eRp-ePA:O.Auth_14#4] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
storage.wipe()
../Sources/eRpApp/Session/KeychainStorage.swift:244
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:BSI-eRp-ePA:O.Auth_14#5|11] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
func wipe() {
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-1#3] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
set(can: nil)
set(token: nil)
set(discovery: nil)
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
set(certificate: nil)
// `keyIdentifier` is not wiped here because it's deletion is done asynchronously
// together with the secure enclave representative in `ProfileSecureDataWiper`
}
O.Auth_15
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Auth_15 | Benachrichtigung des Hintergrundsystems über beendete Anwendungssitzungen durch die Anwendung | Wird eine Anwendungssitzung ordnungsgemäß beendet, MUSS die Anwendung das Hintergrundsystem darüber informieren, sodass Session-Identifier bzw. Authentisierungstoken sicher gelöscht werden. Dies gilt sowohl für das aktive Beenden durch den Benutzer (log-out), als auch für das automatische Beenden durch die Anwendung (vgl. O.Arch_9 und O.Auth_10). | Der Evaluator prüft, ob das Hintergrundsystem bei einer ordnungsgemäßen Beendigung der Anwendungssitzung durch die Anwendung informiert wird. | CHECK |
Implementation
Our Authentication Tokens cannot be invalidated effectivley as they are stateless and no server stores active/valid tokens anywhere. Invalidating Authentication Tokens in our context means deleting them on client side. The client side invalidation can thus be done by manual logout or profile deletion. Logout is accessible within the Settings -> Specific User Profile -> Logout.
O.Cryp_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_1 | Keine fest einprogrammierten Schlüssel oder anderweitige Geheimnisse. | Beim Einsatz von Verschlüsselung in der Anwendung DÜRFEN KEINE fest einprogrammierten geheimen, bzw. privaten Schlüssel eingesetzt werden. | Der Evaluator prüft, ob fest einprogrammierte geheime, bzw. private Schlüssel eingesetzt werden. Ausgenommen sind Techniken, die den verwendeten Schlüssel stark vor Reverse Engineering nach aktuellem Stand der Technik verbergen (Stichwort: „White Box Cryptography“). Wird eine kaskadierte Verschlüsselung eingesetzt, soll mindestens eine Verschlüsselungsebene stark gegen Reverse Engineering geschützt sein und mindestens ein nicht-statischer Schlüssel eingesetzt werden. | EXAMINE |
Implementation
We use API-Keys for FD and APOVZD communication for legal reasons, not for security reasons. Besides that, private keys for encryption are either created and stored within the secure enclave or stored within the eGK. As encryption for Server communication is done ephemeral via ECDH-ES, no static private keys on client side are necessary. Usages of encryption include the following code pieces.
../Sources/IDP/Models/SignedChallenge.swift:36
Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_1#2] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#5] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/Models/SignedAuthenticationData.swift:27
Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_1#3] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#4] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/Models/RegistrationData.swift:108
Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_1#4] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#3] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/internal/JWT/JWE+Encryption.swift:20
Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_1#5] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#6] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/internal/TokenPayload.swift:180
Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_1#6] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#2] one time usage for JWE ECDH-ES Encryption
guard let jweHeader = try? JWE.Header(algorithm: JWE.Algorithm.ecdh_es(keyExchangeContext),
O.Cryp_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_2 | Nur bewährte Implementierungen bei kryptographischen Primitiven. | Die Anwendung MUSS auf bewährte Implementierungen zur Umsetzung kryptographischer Primitive und Protokolle zurückgreifen (vgl. [TR02102-2]). | Der Evaluator prüft die Liste der verwendeten Krypto- Implementierungen gegen den aktuellen Stand der Technik (vgl. [TR02102-2]). | EXAMINE |
Implementation
All cryptographic requirements are defined within gemSpec_Krypt
. The document was created together with BSI.
O.Cryp_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_3 | Passende Wahl der kryptographischen Primitive. | Die Wahl kryptographischer Primitive MUSS passend zum Anwendungsfall sein und dem aktuellen Stand der Technik (siehe [TR02102-1]) entsprechen. | Der Evaluator prüft die Abwägungen des Herstellers zur Wahl der kryptographischen Primitive und prüft, ob diese dem aktuellen Stand der Technik entsprechen (vgl. [TR02102-1]). | EXAMINE |
Implementation
All cryptographic requirements are defined within gemSpec_Krypt
. The document was created together with BSI.
../Sources/IDP/PrivateKeyContainer.swift:62
Secure Enclave Key generation
// Keychain Query
// [REQ:BSI-eRp-ePA:O.Cryp_3#2,O.Cryp_6#2] Secure Enclave Key generation
let query: [String: Any] = [kSecClass as String: kSecClassKey,
../Sources/IDP/internal/IDPCrypto.swift:45
Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#2] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:BSI-eRp-ePA:O.Cryp_3#3] Brainpool key generator
try BrainpoolP256r1.KeyExchange.generateKey()
../Sources/IDP/internal/JWT/JWE+KDF.swift:35
Brainpool key generator
// [REQ:BSI-eRp-ePA:O.Cryp_3#4] Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#4] Key pair generation delegated to OpenSSL
= { try BrainpoolP256r1.KeyExchange.generateKey() })
../Sources/VAUClient/internal/VAUCrypto.swift:101
Brainpool key generator
// [REQ:gemSpec_Krypt:GS-A_4357] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:BSI-eRp-ePA:O.Cryp_3#5] Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#5] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
let keyPairGenerator = { try BrainpoolP256r1.KeyExchange.generateKey() }
O.Cryp_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_4 | Zweckbindung kryptographischer Schlüssel. | Kryptographische Schlüssel DÜRFEN NICHT für mehr als genau einen Zweck eingesetzt werden. | Der Evaluator prüft die verwendeten kryptographischen Schlüssel auf ihre Zweckgebundenheit. Es wird der Zweck nach Schutz durch Verschlüsselung und Authentisierung unterschieden. | EXAMINE |
Implementation
All cryptographic requirements are defined within gemSpec_Krypt
. The document was created together with BSI.
../Sources/IDP/internal/TokenPayload.swift:181
one time usage for JWE ECDH-ES Encryption
// [REQ:BSI-eRp-ePA:O.Cryp_1#6] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#2] one time usage for JWE ECDH-ES Encryption
guard let jweHeader = try? JWE.Header(algorithm: JWE.Algorithm.ecdh_es(keyExchangeContext),
../Sources/IDP/Models/RegistrationData.swift:109
one time usage for JWE ECDH-ES Encryption
// [REQ:BSI-eRp-ePA:O.Cryp_1#4] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#3] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/Models/SignedAuthenticationData.swift:28
one time usage for JWE ECDH-ES Encryption
// [REQ:BSI-eRp-ePA:O.Cryp_1#3] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#4] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/Models/SignedChallenge.swift:37
one time usage for JWE ECDH-ES Encryption
// [REQ:BSI-eRp-ePA:O.Cryp_1#2] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#5] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/IDP/internal/JWT/JWE+Encryption.swift:21
one time usage for JWE ECDH-ES Encryption
// [REQ:BSI-eRp-ePA:O.Cryp_1#5] Signature via ecdh ephemeral-static
// [REQ:BSI-eRp-ePA:O.Cryp_4#6] one time usage for JWE ECDH-ES Encryption
let algorithm = JWE.Algorithm.ecdh_es(JWE.Algorithm.KeyExchangeContext.bpp256r1(
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:588
Signature creation with eGK with dedicated C.CH.AUT
// [REQ:BSI-eRp-ePA:O.Cryp_4#7|12] Signature creation with eGK with dedicated C.CH.AUT
func sign(message: Data) -> AnyPublisher<Data, Swift.Error> {
// [REQ:gemSpec_IDP_Frontend:A_20700-07] perform signature with OpenHealthCardKit
card.sign(data: message)
.tryMap { response in
if response.responseStatus == ResponseStatus.success, let signature = response.data {
return signature
} else {
throw NFCSignatureProviderError.signingFailure(.responseStatus(response.responseStatus))
}
}
.eraseToAnyPublisher()
}
O.Cryp_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_5 | Nutzung von starken kryptographischen Schlüsseln. | Die Stärke der kryptographischen Schlüssel MUSS dem aktuellen Stand der Technik entsprechen (siehe [TR02102-1]). | Der Evaluator prüft die Stärke der verwendeten Schlüssel gegen den aktuellen Stand der Technik (vgl. [TR02102-1]). | EXAMINE |
Implementation
We use Brainpool256R1 and ECSECPrimeRandom 256, see usages in O.Cryp_1 to O.Cryp_4
O.Cryp_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_6 | Manipulationsschutz kryptographischer Schlüssel durch Umgebung. | Alle kryptographischen Schlüssel SOLLEN in einer vor Manipulation und Offenlegung geschützten Umgebung liegen. | Der Evaluator prüft die Umgebung für die Ablage kryptographischer Schlüssel. Als sichere Umgebung gelten beispielsweise Secure Enclave, embedded Secure Element, Trusted Execution Environment etc. Hierbei ist der Betrieb auf allen zugelassenen Hardware-Plattformen zu berücksichtigen. Bei Nichteinhaltung prüft der Evaluator die Abwägungen des Herstellers zu den Auswirkungen auf die Sicherheit der Anwendungen bzw. diskutiert einen fehlenden Schutz in der Risikobewertung. | EXAMINE |
Implementation
Persisted cryptographic keys are created within the devices secure enclave. Temporal keys are discarded as soon as usage is no longer needed.
../Sources/IDP/PrivateKeyContainer.swift:62
Secure Enclave Key generation
// Keychain Query
// [REQ:BSI-eRp-ePA:O.Cryp_3#2,O.Cryp_6#2] Secure Enclave Key generation
let query: [String: Any] = [kSecClass as String: kSecClassKey,
O.Cryp_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Cryp_7 | Manipulationsschutz kryptographischer Operationen durch Umgebung. | Alle kryptographischen Operationen SOLLEN in einer vor Manipulation und Offenlegung geschützten Umgebung stattfinden. | Der Evaluator prüft die Umgebung für die Durchführung kryptographischer Operationen analog zu O.Cryp_6. Der Betrieb auf allen zugelassenen Hardware- Plattformen ist dabei zur berücksichtigen. | EXAMINE |
Implementation
As Brainpool256R1 is not available within secure enclave but enforced by BSI where possible, we use secure enclave encryption only for biometric authentication. Everywhere else, cryptographic operations are ephemeral or use the eGK as a secure execution environment.
../Sources/IDP/PrivateKeyContainer.swift:20
Container for private key operations using secure enclave private keys
/// Represents a (SecureEnclave) private key, namely `PrK_SE_AUT`, secured by iOS Biometrics.
///
/// [REQ:gemSpec_IDP_Frontend:A_21590] This is the container to represent biometric keys. Usage is limited to
/// authorization purposes
/// [REQ:BSI-eRp-ePA:O.Cryp_7#2] Container for private key operations using secure enclave private keys
public struct PrivateKeyContainer {
O.Data_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_1 | Maximale Sicherheit bei Werkseinstellung. | Die Werkseinstellung der Anwendung MUSS die maximale Sicherheit bieten. | Der Evaluator prüft die Standardeinstellungen der Anwendung bei ihrer Installation. Das umfasst unter anderem die Berechtigungen des Betriebssystems, welche die Anwendung einfordert. Die Berechtigungen müssen dem Zweck der Anwendung dienen und dürfen erst angefragt werden, sobald sie Verwendung finden. | CHECK |
Implementation
User preferences are asked without discrimination within the onboarding process. Application permissions are asked, whenever they are needed, e.g. location permission is only asked when the user is about to search for a pharmacy (see O.Plat_2). If a user chooses to not give the permission, features are still available, if possible.
O.Data_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_2 | Verschlüsselung aller sensiblen Daten. | Die Anwendung MUSS sensible Daten verschlüsselt speichern. Die betriebssystemeigene Verschlüsselung des Dateisystems genügt nicht. Das Schlüsselmaterial für diese Verschlüsselung DARF NICHT unverschlüsselt persistiert werden. Dies gilt sowohl für flüchtiges Ablegen (z. B. im Arbeitsspeicher), als auch für dauerhaftes Speichern (z. B. in einer Cloud- Umgebung). Eine hardwareunterstützte Schlüsselverwaltung der Plattform SOLL bevorzugt verwendet werden. | Der Evaluator validiert, dass sensible Daten (s. Anhang A) von der Anwendung nur verschlüsselt gespeichert werden können. Der Evaluator prüft weiterhin, ob eine hardwaregestützte Schlüsselverwaltung des Betriebssystems für die Speicherung der hierfür notwendigen Schlüssel verwendet wird. Ist ein hinreichender Schutz der Schlüssel durch die Plattform sichergestellt (z. B. in einem embedded Secure Element/Trusted Execution Environment), muss die Anwendung diese Schlüssel wirksam gegen Offenlegung schützen. Der Evaluator nimmt die Wirksamkeit gegenüber Reverse Engineering in die Risikobewertung auf. | EXAMINE |
Implementation
We use the OS Keychain to persist sensitive data. The keychain either stores or encrypts via SecureEnclave. Encrypting the database has disadvanteges that we discussed and decided to not yet implement additional database encryption. We are periodically evaluating solutions for this requirement.
../Sources/eRpApp/Session/KeychainStorage.swift:22
Implementation of data storage that is persisted via keychain
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
O.Data_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_3 | Ablage sensibler Daten. | Die Anwendung SOLL sensible Daten in einem vor Einsicht und Manipulation besonders geschützten Bereich ablegen. | Der Evaluator prüft, ob hardwaregestützte Maßnahmen (wie z.B. Trusted Execution Environment) zur Speicherung sensibler Daten verwendet werden. Sollte dies nicht der Fall sein, nimmt der Evaluator die Abwägungen der Wirksamkeit gegenüber Reverse Engineering in die Risikobewertung auf. | EXAMINE |
Implementation
Currently it is not possible to store data within the secure enclave on iOS. We store all data on the encrypted application container on the device. See eRpApp.entitlements
for NSFileProtectionCompleteUnlessOpen
usage.
O.Data_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_4 | Zugriff auf sensible Daten durch Dritte. | Die Anwendung DARF Ressourcen, die einen Zugriff auf sensible Daten ermöglichen, gegenüber Dritten NICHT verfügbar machen. | Der Evaluator prüft, ob die Anwendung Ressourcen zur Verfügung stellt, über die Dritte Zugriff auf sensible Daten erhalten können. Dies umfasst Daten in geteilten Speicherbereichen, Dienste oder Interfaces über die sensible Daten bereitgestellt werden. | EXAMINE |
Implementation
Everything we store, safe or send anywhere is both verified as in O.Resi_6 and or encrypted, such as Keychain or the application container.
O.Data_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_5 | Löschung aller erhobenen sensiblen Daten nach Abschluss der Verwendung durch die Anwendung. | A Alle erhobenen sensiblen Daten DÜRFEN NICHT über die Dauer ihrer jeweiligen Verarbeitung hinaus in der Anwendung gehalten werden. | Der Evaluator prüft, ob Daten über den Zeitraum ihrer Verarbeitung hinaus in der Anwendung gehalten werden. Daten, die nicht mehr genutzt werden, müssen sicher gelöscht werden. | CHECK |
Implementation
Ephemeral private keys are released as soon as they are no longer needed (see O.Source_5).
O.Data_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_6 | Erhebung, Speicherung und Verarbeitung von ausschließlich für den Zweck der Anwendung notwendigen Daten. | Die Anwendung MUSS die Grundsätze der Datensparsamkeit und Zweckbindung berücksichtigen. | Der Evaluator prüft, welche Daten von der Anwendung erhoben, gespeichert und verarbeitet werden und stellt diese dem Zweck der Anwendung gegenüber. | CHECK |
Implementation
Collected data is sparse and use case related as required.
../Sources/eRpApp/Screens/CardWall/CAN/CardWallCANView.swift:121
CAN is used for eGK connection
// [REQ:BSI-eRp-ePA:O.Purp_2#2,O.Data_6#2] CAN is used for eGK connection
CardWallCANInputView(
../Sources/eRpApp/Screens/CameraView/ErxTaskScannerView.swift:22
Scanning tasks contains purpose related data input
// [REQ:BSI-eRp-ePA:O.Purp_2#1,O.Data_6#3] Scanning tasks contains purpose related data input
// [REQ:BSI-eRp-ePA:O.Source_1#1] Scanning tasks starts with scanner callback
store.send(.analyse(scanOutput: $0))
../Sources/eRpApp/Screens/CardWall/PIN/CardWallPINView.swift:17
PIN is used for eGK Connection
// [REQ:BSI-eRp-ePA:O.Purp_2#3,O.Data_6#4] PIN is used for eGK Connection
PINView(store: store).padding()
../Sources/eRpApp/Screens/Pharmacy/Redeem/PharmacyContactView.swift:11
Contact information is collected when needed for redeeming
// [REQ:BSI-eRp-ePA:O.Purp_2#6,O.Data_6#5] Contact information is collected when needed for redeeming
struct PharmacyContactView: View {
../Sources/eRpApp/Tracking/AnalyticsReducer.swift:16
User interaction analytics trigger …
// [REQ:BSI-eRp-ePA:O.Purp_2#4,O.Purp_4#1,O.Data_6#6] User interaction analytics trigger ...
struct AnalyticsReducer<ContentReducer: Reducer>: Reducer
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:101
… records data only if user opt-in is given.
// [REQ:BSI-eRp-ePA:O.Purp_2#5,O.Purp_4#2,O.Data_6#7] ... records data only if user opt-in is given.
if optIn {
O.Data_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_7 | Speicherung und Verarbeitung von sensiblen Daten. | Sofern die Anwendung an ein Hintergrundsystem angebunden ist, SOLL die Speicherung und Verarbeitung von sensiblen Daten im Hintergrundsystem erfolgen. | Der Evaluator prüft, welche Daten die Anwendung permanent speichert bzw. verarbeitet. Er ermittelt das Risiko, das durch eine solche Speicherung und Verarbeitung in der Anwendung entsteht und nimmt es in die Risikobewertung mit auf. | CHECK |
Implementation
Private data is not initially created by the application. Only additional information, such as redeeming or deleting prescriptions create data. The created data is kept on the FD.
O.Data_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_8 | Entfernung von Metadaten mit Datenschutzrelevanz. | Bei der Verwendung von Aufnahmegeräten (z. B. Kamera) MÜSSEN sämtliche Metadaten mit Datenschutz-Relevanz, wie etwa Rückschlüsse auf die GPS-Koordinaten des Aufnahmeorts, eingesetzte Hardware etc., entfernt werden. | Der Evaluator prüft, ob die Anwendung Daten erheben kann, die Metadaten enthalten. In diesem Fall prüft der Evaluator, ob Metadaten mit Datenschutzrelevanz vor der Weiterverarbeitung, wie beispielsweise dem Transfer an das Hintergrundsystem, entfernt werden. | CHECK |
Implementation
The device camera is used optional for scanning prescriptions and for setting a profile avatar. Avatar image data never leaves the device.
../Sources/eRpApp/Screens/CameraView/AVScannerView.swift:40
This controller uses the camera as an input device. Frames are processed but never
// [REQ:BSI-eRp-ePA:O.Data_8#2] This controller uses the camera as an input device. Frames are processed but never
// stored, metadata is never created here.
class AVScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
../Sources/eRpApp/Screens/Main/Profile/ImagePicker/PhotoPicker.swift:47
Meta data is completely removed by converting to jpeg
// [REQ:BSI-eRp-ePA:O.Data_8#3,O.Data_9#2] Meta data is completely removed by converting to jpeg
guard let data = tempImage.jpegData(compressionQuality: 0.3) else {
O.Data_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_9 | Zugriffsbeschränkung bei der Erhebung von sensiblen Daten. | Bei der Erhebung von sensiblen Daten durch die Verwendung von Aufnahmegeräten (z. B. Kamera), MUSS vorgebeugt werden, dass andere Anwendungen darauf Zugriff erlangen könnten, etwa über eine Mediengalerie. | Der Evaluator prüft, ob erhobene sensible Daten anderen Anwendungen auf dem Gerät verfügbar gemacht werden oder Daten in öffentlichen Verzeichnissen gespeichert werden. | EXAMINE |
Implementation
The device camera is used for scanning prescriptions and for setting a profile avatar. Neither use-cases export data to the device photo library or export in any other way.
../Sources/eRpApp/Screens/Main/Profile/ImagePicker/PhotoPicker.swift:47
Meta data is completely removed by converting to jpeg
// [REQ:BSI-eRp-ePA:O.Data_8#3,O.Data_9#2] Meta data is completely removed by converting to jpeg
guard let data = tempImage.jpegData(compressionQuality: 0.3) else {
O.Data_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_10 | Keine Aufzeichnungen bei der Eingabe sensibler Daten über die Tastatur. | Bei der Eingabe sensibler Daten über die Tastatur SOLL die Anwendung unterbinden, dass Aufzeichnungen für Dritte erkennbar werden. | Der Evaluator prüft, ob sensible Daten über Softwaretastaturen des Betriebssystems oder von Drittanbietern eingegeben werden können. Dies schließt insbesondere Caches, Autokorrektur- und Autovervollständigungs-verfahren, Eingabegeräte von Drittanbietern und jegliche für Dritte auswertbare Speicherung, mit ein. Ist dies der Fall, prüft der Evaluator die Abwägungen des Herstellers und berücksichtigt diese in der Risikobewertung. | EXAMINE |
Implementation
Password fields are marked as such and thus disallow autocorrections. Search for SecureField
or SecureFieldWithReveal
for all usages.
../App/Sources/AppDelegate.swift:35
Keyboard extensions are disallowed
// [REQ:BSI-eRp-ePA:O.Data_10#2|10] Keyboard extensions are disallowed
func application(
_: UIApplication,
shouldAllowExtensionPointIdentifier extensionPointIdentifier: UIApplication.ExtensionPointIdentifier
) -> Bool {
// Disallow 3rd party keyboards to prevent leaking sensitive data
if extensionPointIdentifier == .keyboard {
return false
}
return true
}
../Sources/eRpApp/Components/Controls/SecureFieldWithReveal.swift:36
SecureFields
are used for password input.
// [REQ:BSI-eRp-ePA:O.Data_10#3] `SecureFields` are used for password input.
SecureField(text: $text) {
O.Data_11
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_11 | Kein Export sensibler Daten in die Zwischenablage. | Bei der Eingabe sensibler Daten SOLL der Export in die Zwischenablage unterbunden werden. Die Anwendung KANN alternativ eine eigene Zwischenablage implementieren, welche vor dem Zugriff durch andere Anwendungen geschützt ist. | Falls die Anwendung einen Export sensibler Daten in die Zwischenablage des Betriebssystems erlaubt, muss der Abfluss dieser Daten in der Risikobewertung berücksichtigt werden. | CHECK |
Implementation
We use default platform behavior for password fields. Pasting into password fields is allowed, copying is denied. In general the clipboard is only filled with any data, if the user triggers it.
O.Data_12
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_12 | Kein Export von sensiblen Daten aus der Quelle. | Sensible Daten wie biometrische Daten oder private Schlüssel DÜRFEN NICHT aus der Komponente, auf der sie erzeugt wurden, exportiert werden. | Der Evaluator prüft ob sensible Daten, bei denen keine Notwendigkeit für einen Export besteht, trotzdem exportierbar sind. Dies umfasst unter anderem biometrische Daten oder private kryptografische Schlüssel. | EXAMINE |
Implementation
There is no API from Apple that allows extraction of biometric or private key data from the secure enclave. Non ephemeral keys are only created within the secure enclave.
O.Data_13
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_13 | Keine Speicherung des Bildschirminhaltes oder Zugriff Dritter bei Anzeige sensibler Daten. | Die Anwendung MUSS Funktionen des Betriebssystems zur Unterbindung der Anzeige sensibler Daten und des Zugriffs für Dritte und der Speicherung des Bildschirms (z. B. Screenshots und Anzeigen für das App- Switching) nutzen. | Der Evaluator prüft, ob die Anwendung das Erzeugen von Screenshots verbietet. Dies umfasst sowohl das aktive, als auch das passive Erzeugen von Screenshots wie es beispielsweise für die Vorschau im Task-Manager durchgeführt wird. Der Evaluator prüft außerdem, ob sensible Daten nicht länger als notwendig in der Anwendung angezeigt werden. Das Restrisiko der Anzeige sensibler Daten wird in der Risikobewertung berücksichtigt. | CHECK |
Implementation
Suppressing Screenshots is not possible as of now.
../Sources/eRpApp/SceneDelegate.swift:246
Moving the application to the background blurs the application
// [REQ:BSI-eRp-ePA:O.Data_13#2,O.Plat_9#2] Moving the application to the background blurs the application
// window.
addBlurOverlayToWindow()
../Sources/eRpApp/SceneDelegate.swift:165
Moving the application to the foreground removes the blur.
// [REQ:BSI-eRp-ePA:O.Data_13#3,O.Plat_9#3] Moving the application to the foreground removes the blur.
removeBlurOverlayFromWindow()
O.Data_14
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_14 | Verschlüsselung aller sensiblen Daten im gesperrten Zustand. | Die Anwendung MUSS sicherstellen, dass im gesperrten Zustand des Endgeräts alle sensiblen Daten verschlüsselt sind. | Ältere Plattformversionen erlauben teilweise die Speicherung der Anwendung auf externen Speichermedien, die nicht der Speicherverschlüsselung unterliegen. Der Evaluator prüft, ob die Anwendung solche oder vergleichbare Vorgehensweisen untersagt. | EXAMINE |
Implementation
See eRpApp.entitlements
for NSFileProtectionCompleteUnlessOpen
usage.
O.Data_15
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_15 | Gerätebindung lokal gespeicherter Daten. | Die Anwendung MUSS lokal gespeicherte Daten verschlüsselt mit einer sicheren Gerätebindung versehen. | Der Evaluator prüft, ob Daten, die von der Anwendung gespeichert werden, auf anderen Geräten verarbeitet werden können. Von dieser Einschränkung ausgenommen sind Daten, die vom Nutzer explizit zur Verarbeitung auf anderen Geräten exportiert werden. | EXAMINE |
Implementation
Biometric keys are always bound to the device and cannot leave the secure enclave. Actual user data is excluded from backups and cannot be exported.
../Sources/eRpLocalStorage/CoreDataController.swift:83
Database backup exclusion
// [REQ:BSI-eRp-ePA:O.Purp_8#4,O.Arch_4#2,O.Data_15#1] Database backup exclusion
if excludeFromBackup, let storeUrl = store.url {
../Sources/IDP/PrivateKeyContainer.swift:126
prevents migration to other devices
// [REQ:gemSpec_IDP_Frontend:A_21586] prevents migration to other devices
// [REQ:BSI-eRp-ePA:O.Data_15#2] prevents migration to other devices
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
O.Data_16
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_16 | Enterfernen oder anderweitiges unzugänglich machen aller sensiblen Daten auf dem Endgerät bei Deinstallation der Anwendung. | Es MUSS vom Hersteller sichergestellt werden, dass bei der Deinstallation der Anwendung alle sensiblen Daten und anwendungsspezifischen Anmeldeinformationen auf dem Endgerät nicht mehr zugreifbar sind. | Der Evaluator prüft, ob nach der Deinstallation der Anwendung Daten auf dem Endgerät zurückbleiben. Ist dies der Fall, prüft der Evaluator weiterhin, ob diese Daten sensible Informationen beinhalten oder Rückschlüsse auf sensible Daten zulassen. | CHECK |
Implementation
Deletion is completely handled by the OS. We have no means of doing anything while deinstallation is running. All sensitive keychain data is tied to the user profile id and cannot be accessed after deinstallation. though technically the information still persists for a short period of time (<24h) after some kind of daily cleanup routine by the OS it will be removed. The user may choose to manually logout or delete profiles before app deletion.
O.Data_17
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_17 | Möglichkeit zum Löschen oder anderweitigen unzugänglich machen aller sensiblen Daten der Anwendung. | Die Anwendung MUSS dem Nutzer die Möglichkeit geben, dass alle sensiblen Daten und anwendungsspezifischen Anmeldeinformationen vollständig gelöscht bzw. unzugänglich gemacht werden. | Der Evaluator validiert, dass dem Nutzer die Möglichkeit gegeben wird alle sensiblen Daten vollständig zu löschen oder unzugänglich zu machen. Darüber hinaus prüft er die Wirksamkeit der getroffenen Maßnahmen durch praktische Tests. | EXAMINE |
Implementation
Deletion is completely handled by the OS. We have no means of doing anything while deinstallation is running. All sensitive keychain data is tied to the user profile id and cannot be accessed after deinstallation. though technically the information still persists for a short period of time (<24h) after some kind of daily cleanup routine by the OS it will be removed. The user may choose to manually logout or delete profiles before app deletion.
O.Data_18
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Data_18 | Sicheres Überschreiben von Nutzerdaten im Gerät, ausgelöst durch den Anwender. | Um dem Missbrauch von sensiblen Daten nach einem Geräteverlust entgegenzuwirken, KANN die Anwendung einen Kill-Switch realisieren, d. h. ein absichtliches, sicheres Überschreiben von Nutzerdaten im Gerät auf Anwendungsebene, ausgelöst durch das Hintergrundsystem. Der Hersteller MUSS die Auslösung des Kill-Switches durch den Anwender über das Hintergrundsystem durch starke Authentifizierungsmechanismen vor missbräuchlicher Nutzung schützen. | Der Evaluator führt eine Löschung der Daten über das Hintergrundsystem durch und validiert, dass keine Nutzerdaten mehr auf dem Gerät lesbar sind. | EXAMINE |
Implementation
Not applicable: no kill switch realized.
O.Ntwk_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_1 | Netzwerkkommunikation durchgängig mit gegenseitiger Authentisierung verschlüsselt | Jegliche Netzwerkkommunikation der Anwendung MUSS durchgängig mit gegenseitiger Authentisierung verschlüsselt (zum Beispiel mittels mTLS) werden. | Der Evaluator validiert, dass ausschließlich mit gegenseitiger Authentisierung verschlüsselte Kommunikation zwischen der Anwendung und anderen Komponenten möglich ist. | EXAMINE |
Implementation
No exceptions set in NSAppTransportSecurity
, HTTP via TLS is enforced (see also: Requirements for Connecting Using ATS); Certificate transparency ensures authenticity of the server side. User access tokens ensures client side authenticity.
O.Ntwk_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_2 | Konfiguration der verschlüsselten Verbindung gemäß aktuellem Stand der Technik. | Die Konfiguration der verschlüsselten Verbindungen MUSS dem aktuellen Stand der Technik entsprechen (vgl. [TR02102-2]). | Der Evaluator validiert, dass die in O.Ntwk_1 beschriebene Kommunikation dem Stand der Technik (siehe [TR02102-2]) entspricht. | EXAMINE |
Implementation
We use one wrapper around NSURLSession
for network communication that uses an ephemeral configuration only allowing TLS 1.2 or greater. Network communication security in general is specified within gemSpec_Krypt
and aggreed upon with BSI.
../Sources/HTTPClient/DefaultHTTPClient.swift:36
URLSession is used as Network Framework
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
O.Ntwk_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_3 | Sichere Kommunikationskanäle nur mit Betriebssystem- Funktionen oder sicherheitsüberprüfter Drittsoftware. | Die Anwendung MUSS sicherheitsüberprüfte Drittanbieter-Software verwenden, um sichere Kommunikationskanäle aufzubauen. Dies schließt die im Betriebssystem mitgelieferte Bibliothek mit ein. | Der Evaluator prüft, wie ein sicherer Kommunikationskanal aufgebaut wird. Wenn keine Betriebssystem- Funktionen verwendet werden, validiert der Evaluator, dass die Drittanbieter-Software, welche zum Verbindungsabbau verwendet wird, den in Kapitel 5.5.4 beschriebenen Anforderungen genügt. Eigene Implementierungen zum Aufbau sicherer Kommunikationskanäle sind nicht zulässig. Gemäß A.OperatingSystem werden die Funktionen zum Aufbau von sicheren Kommunikationskanäle im Betriebssystem als sicher angenommen. Sicherheitsüberprüft bedeutet, dass alle sicherheitsrelevanten Bereiche der Software durch eine weitere Partei auf ihre Sicherheitseigenschaften hinuntersucht worden sind. | EXAMINE |
Implementation
We use the system provided NSURLSession for network communication and no additional layer for TLS encryption. The iOS encryption is certified according to https://support.apple.com/de-de/guide/certifications/apc3fa917cb49/web
../Sources/HTTPClient/DefaultHTTPClient.swift:36
URLSession is used as Network Framework
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
O.Ntwk_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_4 | Unterstützung von Zertifikats- Pinning. | Die Anwendung MUSS Zertifikats-Pinning anwenden. | Der Evaluator validiert, dass die Anwendung Zertifikats-Pinning unterstützt und dieses wirksam umsetzt. | EXAMINE |
Implementation
We do not pin TLS Certificates, instead we pin TI PKI Certificates for FD and IDP communication. Since we got an agreement with the BSI regarding the usage of pinning, (TI PKI Pinning is enough) we remove the TLS pinning itself, in favor of certificate transparency + our second layer of TI Certificate pinning. If accessing the APOVZD, we don’t have such pinning. However, the need for pinning is due to high protection demand of the medical data. But the APOVZD does not hold such data, thus we interpret that pinning is not necessary there at all. Furthermore, we don’t see attack vectors regarding the APOVZD. It only required an API Key, but no authentication. Redeeming prescriptions directly with pharmacies, we encrypt the payload with an encryption certificate, that again is checked to be within TI PKI.
../Sources/eRpApp/AppConfiguration.swift:118
Gematik Root CA 3 as a trust anchor has to be set in the program code
// [REQ:gemSpec_Krypt:A_21218] Gematik Root CA 3 as a trust anchor has to be set in the program code
// [REQ:BSI-eRp-ePA:O.Ntwk_4#2|16] Gematik Root CA 3 as a trust anchor has to be set in the program code
// swiftlint:disable:next force_try
let TRUSTANCHOR_GemRootCa3 = try! TrustAnchor(withPEM: """
MIICaTCCAg+gAwIBAgIBATAKBggqhkjOPQQDAjBtMQswCQYDVQQGEwJERTEVMBMG
A1UECgwMZ2VtYXRpayBHbWJIMTQwMgYDVQQLDCtaZW50cmFsZSBSb290LUNBIGRl
ciBUZWxlbWF0aWtpbmZyYXN0cnVrdHVyMREwDwYDVQQDDAhHRU0uUkNBMzAeFw0x
NzEwMTcwNzEzMDNaFw0yNzEwMTUwNzEzMDNaMG0xCzAJBgNVBAYTAkRFMRUwEwYD
VQQKDAxnZW1hdGlrIEdtYkgxNDAyBgNVBAsMK1plbnRyYWxlIFJvb3QtQ0EgZGVy
IFRlbGVtYXRpa2luZnJhc3RydWt0dXIxETAPBgNVBAMMCEdFTS5SQ0EzMFowFAYH
KoZIzj0CAQYJKyQDAwIIAQEHA0IABFhZKSE0xvaeHzZB0A7sRYwIphEWYk/+uFw4
kOLnBt2kbP4P7L0lFOQfp6W0a2lCcmKk+k25VHrj7PCMyV/AVdqjgZ4wgZswHQYD
VR0OBBYEFN/DvnW+JesTMjAup1CFCJ83ENDoMEIGCCsGAQUFBwEBBDYwNDAyBggr
BgEFBQcwAYYmaHR0cDovL29jc3Aucm9vdC1jYS50aS1kaWVuc3RlLmRlL29jc3Aw
DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFQYDVR0gBA4wDDAKBggq
ghQATASBIzAKBggqhkjOPQQDAgNIADBFAiEAnOlHsQ5tQ2HPoKVngVQnbvVGteLy
MSEnNGbYegnfPFECIEUlFmjATBNklr35xvWQPZUMdIsy7SzUulwFDodpdGr/
-----END CERTIFICATE-----
""")
O.Ntwk_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_5 | Validierung des Server-Zertifikats des Hintergrundsystems. | Die Anwendung MUSS das Server-Zertifikat des Hintergrundsystems überprüfen. | Der Evaluator prüft, wie die Anwendung das Zertifikat des Hintergrundsystems validiert. | EXAMINE |
Implementation
We use NSURLSession
as the base for all our network requests. NSURLSession
uses ATS (App Transport Security) that enforces rules for TLS Certificates, such as authenticity. See https://support.apple.com/en-us/103214 and https://developer.apple.com/documentation/bundleresources/information_property_list/nsrequirescertificatetransparency# for additional information.
O.Ntwk_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_6 | Validierung der Integrität und Authentizität der Antworten des Hintergrundsystems. | Die Anwendung MUSS die Integrität und Authentizität der Antworten des Hintergrundsystems validieren. | Der Evaluator bestätigt, dass die Integrität und Authentizität der Nachrichten des Hintergrundsystems von der Anwendung validiert werden. | EXAMINE |
Implementation
The server uses extended validation certificates to ensure maximum authenticity. On top of TLS we also implement message authenticity by validating checksums and signatures. For IDP Communication see O.Resi_6, for FD communication see the following code.
../Sources/VAUClient/VAUInterceptor.swift:14
Interceptor implementing request and response encryption.
/// The VAU (trusted execution environment) http Interceptor to encrypt HTTP-Requests before sending them
/// and decrypting the received encrypted responses.
/// [REQ:BSI-eRp-ePA:O.Ntwk_6#2] Interceptor implementing request and response encryption.
class VAUInterceptor: Interceptor {
../Sources/VAUClient/internal/VAUCrypto.swift:111
Decrypting and verifying FD server messages
// [REQ:BSI-eRp-ePA:O.Ntwk_6#3|21] Decrypting and verifying FD server messages
func decrypt(data: Data) throws -> String {
// Steps according to gemSpec_Krypt A_20174
// [REQ:gemSpec_Krypt:A_20174#13] 3: Decrypt using AES symmetric key
guard let sealed = try? AES.GCM.SealedBox(combined: data),
let decrypted = try? AES.GCM.open(sealed, using: symmetricKey),
let utf8 = decrypted.utf8string
else {
throw VAUError.responseValidation
}
// [REQ:gemSpec_Krypt:A_20174#14] 4+5: Verify decrypted message. Expect: "1 <request id> <response header+body>"
let separated = utf8.split(separator: " ", maxSplits: 2).map { String($0) }
guard separated.count == 3,
separated[0] == "1",
separated[1] == requestId
else {
throw VAUError.responseValidation
}
return separated[2]
}
O.Ntwk_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_7 | Verwendung plattformspezifischer Optionen. | Plattformspezifische Optionen, wie beispielsweise „Cleartext Traffic Opt-out“ und „In-App Transport Security“ MÜSSEN verwendet werden. | Der Evaluator bestätigt, dass die plattformspezifischen Optionen zur Gewährleistung einer sicheren Kommunikation umgesetzt wurden. | EXAMINE |
Implementation
The system enforces ATS App Transport Security since the app uses the standard URL Loading System URLSession
which automatically negotiate the most secure connection available from the server. Also there are no exceptions configured in the eRpApp/Resources/Info.plist
thus insecure networt connections are disabled by default.
../Sources/HTTPClient/DefaultHTTPClient.swift:36
URLSession is used as Network Framework
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
O.Ntwk_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Ntwk_8 | Vorhaltung von vollständigen Log-Dateien für alle aufgebauten Verbindungen. | Die Anwendung MUSS für alle Verbindungen Log-Dateien vorhalten. Diese SOLLEN an das Hintergrundsystem übermittelt werden. | Der Evaluator überprüft die von dem Hersteller bereitgestellten Log- Dateien und validiert, dass die HTTP-Header vollständig miterfasst sind. Wenn kein Logging sicherheitsrelevanter Ereignisse auf dem Hintergrundsystem stattfindet, muss dieser Aspekt in der Risikobewertung berücksichtigt werden. | CHECK |
Implementation
Logging does not take place in the FdV for reasons of data minimization. Furthermore, it is not entirely clear who this log would be for. We have separate responsibilities divided between two different operators of the IDP and the specialized service, and gematik as the manufacturer of the e-prescription app. None of the backend systems have such a required endpoint. Moreover, the aforementioned questions would still arise.
O.Paid_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_1 | Anzeige kostenpflichtiger Leistungen und Ressourcen. | Die Anwendung MUSS für den Nutzer kenntlich machen, welche kostenpflichtigen Leistungen (z.B. Zusatzfunktionalitäten oder Premiumzugriffe) und welche kostenpflichtigen Ressourcen (z.B. SMS, Telefonate, mobile Daten) von der Anwendung angeboten oder verwendet werden. | Der Evaluator validiert, dass alle kostenpflichtigen Leistungen und Ressourcen eindeutig als solche erkennbar sind. | CHECK |
Implementation
The app does not offer any purchases. The only paid service, that is used by the app in some extent can be mobile data. The terms of use in the app states, that costs might occur using mobile data.
O.Paid_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_2 | Einverständnis des Nutzers vor dem Ausführen kostenpflichtiger Leistungen. | Die Anwendung MUSS vor der Verwendung kostenpflichtiger Leistungen das Einverständnis des Nutzers einholen. | Der Evaluator validiert, dass alle kostenpflichtigen Leistungen ausschließlich nach Bestätigung durch den Nutzer erbracht werden können. | CHECK |
Implementation
The app does not offer any purchases.
O.Paid_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_3 | Einverständnis des Nutzers vor einer Zugriffsanforderung auf kostenpflichtige Ressourcen. | Die Anwendung MUSS vor einer Zugriffsanforderung (z. B. Android- Berechtigungen) auf kostenpflichtige Ressourcen, das Einverständnis des Nutzers einholen. | Der Evaluator validiert, dass die Nutzung von Diensten, die zusätzliche Kosten für den Nutzer verursachen können (z.B. das Versenden von SMS), ausschließlich nach Abgabe einer Einverständniserklärung des Nutzers möglich ist. | CHECK |
Implementation
The app does not offer any purchases.
O.Paid_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_4 | Dauerhaftes Einverständnis des Nutzers auf häufig verwendete, kostenpflichtige Leistungen oder Ressourcen. | Die Anwendung KANN für den Zugriff auf häufig verwendete, kostenpflichtige Ressourcen oder kostenpflichtige Leistungen ein dauerhaftes Einverständnis des Nutzers einholen. | Falls die Anwendung ein dauerhaftes Einverständnis des Nutzers für den Zugriff auf kostenpflichtige Ressourcen fordert, prüft der Evaluator, ob dies für den primären Zweck der Anwendung erforderlich ist (vgl. O.Purp_1). | CHECK |
Implementation
The app does not offer any purchases.
O.Paid_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_5 | Entzug des Einverständnisses ermöglichen. | Die Anwendung MUSS den Nutzer in die Lage versetzen zuvor erteilte Einverständnisse zurückzuziehen. | Der Evaluator prüft, ob die Anwendung eine Liste mit allen vom Nutzer gegebenen Einverständniserklärungen anzeigt und diese nachträglich geändert werden kann. | CHECK |
Implementation
The app does not offer any purchases.
O.Paid_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_6 | Ablage der sensiblen Transaktionshistorie im Hintergrundsystem. | Die Anwendung SOLL die Transaktionshistorie von kostenpflichtigen Leistungen im Hintergrundsystem ablegen. Die Transaktionshistorie, einschließlich der Metadaten, MUSS als sensibles Datum gemäß O.Purp_8 behandelt werden. | Der Evaluator prüft über praktische Tests und Quelltextanalyse, ob eine Transaktionshistorie in der Anwendung vorgehalten wird. Die Transaktionshistorie sollte im Hintergrundsystem sicher gespeichert werden und aus der Anwendung einsehbar sein. Wenn die Transaktionshistorie in der Anwendung selber gespeichert wird, ist in einer Risikobewertung darzustellen, inwieweit die Sicherheit der gespeicherten Daten gewährleistet werden kann. | EXAMINE |
Implementation
The app does not offer any purchases.
O.Paid_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_7 | Profilbildung durch Nachverfolgung der Zahlungsströme durch Dritte. | Falls die Anwendung kostenpflichtige Leistungen anbietet, MUSS der Hersteller ein Konzept vorlegen, welches vorbeugt, dass Dritte die Zahlungsströme zur Nutzung von Anwendungsfunktionen zurückverfolgen können. | Der Evaluator prüft, ob über die Nachverfolgung von Zahlungsströmen Rückschlüsse auf die Eigenschaften oder das Verhalten des Nutzers möglich sind. Die Abwägungen des Herstellers bei potenziellen Rückschlüssen sind in der Risikobewertung zu berücksichtigen. | CHECK |
Implementation
The app does not offer any purchases.
O.Paid_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_8 | Anzeige der Übersicht der entstandenen Kosten. | Die Anwendung MUSS dem Nutzer eine Übersicht der entstandenen Kosten anbieten. Falls die Kosten aufgrund einzelner Zugriffe erfolgt sind, MUSS die Anwendung einen Überblick der Zugriffe aufführen. | Der Evaluator prüft, ob die Anwendung dem Nutzer eine Übersicht der entstandenen Kosten anbietet. Falls die Kosten aufgrund einzelner Zugriffe erfolgt sind, prüft der Evaluator, ob die Anwendung einen Überblick der Zugriffe aufführt. | CHECK |
Implementation
The app does not offer any purchases.
O.Paid_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_9 | Validierung von getätigten Bezahlvorgängen im Hintergrundsystem. | Die Validierung von getätigten Bezahlvorgängen SOLL im Hintergrundsystem vorgenommen werden. | Der Evaluator prüft durch Quelltextanalyse und praktische Tests, ob die Anwendung eigenständig Bezahlungen validiert und beispielsweise kostenpflichtige Funktionen freischalten kann. | EXAMINE |
Implementation
The app does not offer any purchases.
O.Paid_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Paid_10 | Anforderungen bei Zahlverfahren von Drittanbietern. | Zahlverfahren von Drittanbietern MÜSSEN die Anforderungen an Drittanbieter-Software erfüllen (vgl. Kapitel 5.5.4). | Der Evaluator prüft die Zahlverfahren durch Drittanbieter. Sowohl bei Drittanbieter-Software, als auch bei Web-Diensten wird geprüft, dass keine sensiblen Nutzerdaten an den Zahlungsdienstleister abfließen (z.B., dass der Titel der gebuchten Leistung keine sensiblen Informationen enthält). | CHECK |
Implementation
The app does not offer any purchases.
O.Pass_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Pass_1 | Durchsetzung starker Passwortrichtlinien. | Bei einer Authentisierung mittels Benutzername und Passwort MÜSSEN starke Passwortrichtlinien existieren. Diese SOLLEN sich am aktuellen Stand gängiger „Best- Practices“ orientieren. | Der Evaluator prüft, ob Passwortrichtlinien, welche dem aktuellen Stand der Technik entsprechen, eingesetzt werden. Andernfalls sind die Abwägungen des Herstellers zu prüfen und in der Risikobewertung zu berücksichtigen. | CHECK |
Implementation
We use zxcvbn-ios as a password strength indicator and enforcer for the application password.
../Sources/eRpApp/Helper/PasswordStrengthTester.swift:37
We use an additional german word list to check against common passwords
// [REQ:BSI-eRp-ePA:O.Pass_1#2,O.Pass_2#2] We use an additional german word list to check against common passwords
private(set) lazy var wordList: [String] = {
O.Pass_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Pass_2 | Anzeige der Stärke des verwendeten Passworts. | Für die Einrichtung der Authentisierung mittels Benutzername und Passwort KANN die Stärke des verwendeten Passworts dem Nutzer angezeigt werden. Informationen über die Stärke des gewählten Passworts DÜRFEN NICHT gespeichert werden. | Der Evaluator prüft, ob dem Nutzer die Stärke des verwendeten Passworts angezeigt wird. Ist dies der Fall, prüft er durch Quelltextanalyse und praktische Tests, ob dadurch Informationen über das Password oder dessen Güte im Anwendungsspeicher verbleiben. | EXAMINE |
Implementation
We use zxcvbn-ios as a password strength indicator and enforcer for the application password.
../Sources/eRpApp/Helper/PasswordStrengthTester.swift:37
We use an additional german word list to check against common passwords
// [REQ:BSI-eRp-ePA:O.Pass_1#2,O.Pass_2#2] We use an additional german word list to check against common passwords
private(set) lazy var wordList: [String] = {
../Sources/eRpApp/Screens/Onboarding/OnboardingRegisterAuthenticationView.swift:235
Password strength view within onboarding.
// [REQ:BSI-eRp-ePA:O.Pass_2#2] Password strength view within onboarding.
PasswordStrengthView(strength: store.passwordStrength,
../Sources/eRpApp/Screens/Onboarding/RegisterAuthenticationDomain.swift:175
Testing the acutal password strength
// [REQ:BSI-eRp-ePA:O.Pass_2#3] Testing the acutal password strength
state.passwordStrength = passwordStrengthTester.passwordStrength(for: state.passwordA)
../Sources/eRpApp/Screens/Settings/AppSecurity/CreatePasswordView.swift:80
Password strength view within settings.
// [REQ:BSI-eRp-ePA:O.Pass_2#4] Password strength view within settings.
PasswordStrengthView(strength: store.passwordStrength)
../Sources/eRpApp/Screens/Settings/AppSecurity/CreatePasswordDomain.swift:91
Testing the actual password strength while updating within settings
// [REQ:BSI-eRp-ePA:O.Pass_2#5] Testing the actual password strength while updating within settings
state.passwordStrength = passwordStrengthTester.passwordStrength(for: state.passwordA)
O.Pass_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Pass_3 | Möglichkeit zur Änderung des Passwortes. | Der Nutzer MUSS die Möglichkeit haben, sein Passwort zu ändern. | Der Evaluator prüft, ob der Nutzer die Möglichkeit hat, sein Passwort zu ändern und verifiziert, dass diese Funktionalität nicht zweckentfremdet werden kann. | CHECK |
Implementation
The user may change the app passwords within the settings.
../Sources/eRpApp/Screens/Settings/AppSecurity/CreatePasswordView.swift:10
View for changing the user password
// [REQ:BSI-eRp-ePA:O.Pass_3#2] View for changing the user password
struct CreatePasswordView: View {
O.Pass_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Pass_4 | Protokollierung und Information über Änderungen und Zurücksetzen von Passwörtern. | Wird die Anwendung zusammen mit einem Hintergrundsystem genutzt, MUSS das Ändern und Zurücksetzen von Passwörtern protokolliert werden. Das Hintergrundsystem SOLL den Nutzer über das Ändern und Zurücksetzen von Passwörtern informieren, dabei MUSS ein separater Kanal genutzt werden. | Der Evaluator prüft das Vorhandensein und die Güte von zusätzlichen Informationen zur Protokollierung von Änderungen und dem Zurücksetzen von Passwörtern. | CHECK |
Implementation
The application password is not used for the baackend. There is no protocol for the application password within the application, although we implement a counter for failed password attempts.
../Sources/eRpApp/Screens/AppAuthentication/AppAuthenticationView.swift:25
Display of failed login attempts counter
// [REQ:BSI-eRp-ePA:O.Pass_4#2] Display of failed login attempts counter
if store.failedAuthenticationsCount != 0 {
../Sources/eRpApp/Screens/AppAuthentication/AppAuthenticationDomain.swift:109
Increase failed attempts count on failed verification
// [REQ:BSI-eRp-ePA:O.Pass_4#3] Increase failed attempts count on failed verification
state.failedAuthenticationsCount += 1
O.Pass_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Pass_5 | Verwendung von kryptographisch sicheren Hashing-Algorithmen und Salts zur Speicherung der Passwörter. | Werden Passwörter gespeichert, MÜSSEN diese mit einer den aktuellen Sicherheitsstandards entsprechenden Hash-Funktion und unter Verwendung geeigneter Salts gehasht werden. | Der Evaluator prüft, ob Passwörter in der Anwendung gespeichert werden. Er verifiziert, dass die verwendeten Schutzmechanismen dem aktuellen Stand der Technik und den Anforderungen an Hash- Funktionen, Anzahl an Iterationen und Salts genügen (vgl. [TR02102-1]). In der Risikobewertung werden Maßnahmen, die Brute-Force- Angriffe verlangsamen, berücksichtigt. | EXAMINE |
Implementation
We use the keychain to persist the hashed app password and the corresponding salt. The salt is regenerated, whenever a new password is stored.
../Sources/eRpApp/Session/Helper/AppSecurityManager.swift:45
The salt is regenerated, whenever a new password is stored.
// [REQ:BSI-eRp-ePA:O.Pass_5#2|4] The salt is regenerated, whenever a new password is stored.
guard let data = password.data(using: .utf8),
let salt = try? randomGenerator(32) else {
throw AppSecurityManagerError.savePasswordFailed
}
../Sources/eRpApp/Session/Helper/AppSecurityManager.swift:51
Password is stored alongside hash within keychain.
// [REQ:BSI-eRp-ePA:O.Pass_5#3|8] Password is stored alongside hash within keychain.
do {
let hashedPassword = hash(data + salt)
guard try keychainAccess.setGenericPassword(salt, for: Self.passwordSaltIdentifier),
try keychainAccess.setGenericPassword(hashedPassword, for: Self.passwordHashIdentifier) else {
throw AppSecurityManagerError.savePasswordFailed
}
return true
} catch {
O.Plat_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_1 | Geräteschutz für die Nutzung der Anwendung erforderlich. | Für die Nutzung der Anwendung SOLL das Endgerät über einen aktivierten Geräteschutz (Passwort, Mustersperre, o. ä.) verfügen. Im Fall eines nicht aktivierten Geräteschutzes MUSS der Hersteller den Nutzer über die damit verbundenen Risiken aufklären. | Der Evaluator prüft, ob der Hersteller eine Nutzung ohne aktivierten Geräteschutz zulässt. Ist das der Fall, prüft der Evaluator, ob der Nutzer angemessen über die daraus resultierenden Risiken aufgeklärt wird, und er berücksichtigt die Abwägungen des Herstellers in der Risikobewertung. Gemäß A.OperatingSystem wird insbesondere angenommen, dass das Betriebssystem über Funktionen verfügt, die es der Anwendung ermöglichen, die Einstellung des Geräteschutzes abzufragen. | CHECK |
Implementation
We test for device pincode at startup and show a dialog if no pin is set.
../Sources/eRpApp/Screens/Main/MainView.swift:95
trigger device security check
// [REQ:BSI-eRp-ePA:O.Arch_6#2,O.Resi_2#2,O.Plat_1#2] trigger device security check
store.send(.loadDeviceSecurityView)
../Sources/eRpApp/Session/Helper/DeviceSecurityManager.swift:58
calculate system risk for jailbreak and missing device pin
// [REQ:BSI-eRp-ePA:O.Arch_6#3,O.Resi_2#3,O.Plat_1#3] calculate system risk for jailbreak and missing device pin
var showSystemSecurityWarning: AnyPublisher<DeviceSecurityWarningType, Never> {
../Sources/eRpApp/Session/Helper/DeviceSecurityManager.swift:68
Missing system pin detection
// [REQ:BSI-eRp-ePA:O.Plat_1#4] Missing system pin detection
var informMissingSystemPin: AnyPublisher<Bool, Never> {
O.Plat_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_2 | Nur Anforderung der für den primären Zweck notwendigen Berechtigungen. | Die Anwendung DARF Berechtigungen, die für die Erfüllung ihres primären Zwecks nicht notwendig sind, NICHT einfordern. | Der Evaluator prüft die von der Anwendung geforderten Berechtigungen und bestätigt, dass diese für die Erfüllung des primären Zwecks der Anwendung (O.Purp_1) erforderlich sind. | CHECK |
Implementation
The app ony configures entitlements that are used for it’s primary purpose. All configured entitlements are configured in eRpApp/Resources/Info.plist
and in eRpApp/Resources/eRpApp.entitlements
.
O.Plat_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_3 | Hinweis auf Zweck der Berechtigungen und Auswirkungen bei Nichterteilung. | Die Anwendung MUSS den Nutzer auf den Zweck der anzufragenden Berechtigungen und auf die Auswirkungen hinweisen, die eintreten, falls der Nutzer diese nicht gewährt. | Der Evaluator prüft, ob die Anwendung auf den Zweck der geforderten Berechtigungen hinweist. | CHECK |
Implementation
The platform enforces dialogs whenever accessing private data or sensors and user permission is not already given. Localizations can be found within InfoPlist.strings
O.Plat_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_4 | Keine sensiblen Daten in Meldungen oder Benachrichtigungen. | Die Anwendung DARF KEINE sensiblen Daten in Meldungen oder Benachrichtigungen, die nicht vom Benutzer explizit eingeschaltet wurden (siehe O.Plat_5), schreiben. | Der Evaluator prüft anhand von Quelltextanalyse und generierten Log-Nachrichten, ob die Anwendung sensible Daten in diese Nachrichten schreibt. Sollten die geloggten Daten Rückschlüsse auf den Nutzer zulassen, muss dieser Datenabfluss in der Risikobewertung berücksichtigt werden. | EXAMINE |
Implementation
We never show sensitive data as all errors are localized with custom descriptions (See LocalizedError
implementations). Some errors have localized parameters such as a failed PIN counter. Some errors are sent from the server, these messages show only generic information what went wrong. See O.Source_3 for reference.
O.Plat_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_5 | Option zur Anzeige von Meldungen/Benachrichtigungen mit sensiblen Daten. | Die Anwendung KANN dem Nutzer die Optionen bieten, Meldungen und Benachrichtigungen, ggf. auch mit sensiblen Daten, anzuzeigen. Bei Werkseinstellung MUSS diese deaktiviert sein. | Falls die Anwendung die Möglichkeit zur Anzeige von Meldungen mit sensiblen Daten bietet, prüft der Evaluator, ob diese standardmäßig deaktiviert sind. Weiterhin prüft er, ob der Nutzer bei Aktivierung dieser Option angemessen über die daraus resultierenden Risiken aufgeklärt wird. Die Abwägungen des Herstellers, solche Optionen anzubieten, sind in der Risikobewertung zu berücksichtigen. | CHECK |
Implementation
Not applicable: displaying of messages not realized.
O.Plat_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_6 | Zugriffsbeschränkungen auf sensible Daten. | Die Anwendung MUSS Zugriffsbeschränkungen auf sensible Daten realisieren. | Der Evaluator prüft, ob die Anwendung den Zugriff auf sämtliche Daten beschränkt, solange sie unter der Kontrolle der Anwendung sind. Dies schließt eine Beschränkung des Zugriffs auf vorgesehene Dateipfade zum Schutz sensibler Daten durch automatisches Speichern oder unbeabsichtigtes Speichern durch den Nutzer mit ein. Darüber hinaus ist zu validieren, dass die Anwendung keine Broadcast-Nachrichten verschicken kann, die von allen auf dem Gerät installierten Anwendungen gelesen werden können. Die Anwendung darf Nachrichten ausschließlich an autorisierte Anwendungen verschicken. Wenn die Anwendung diese Vorgabe nicht umsetzt, müssen die Abwägungen des Herstellers in die Risikobewertung mitaufgenommen werden. Gemäß A.OperatingSystem wird angenommen, dass das Betriebssystem über wirksame Funktionen verfügt, die einzelne Anwendungen untereinander und gegenüber dem Betriebssystem isolieren. Die Isolation muss durchgängig sein und mindestens die Prozessebene, | EXAMINE |
Implementation
Implemented by the OS Sandboxing.
O.Plat_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_7 | Nutzung von sensiblen Funktionalitäten über Interprozesskommunikation. | Die plattformspezifischen Mechanismen zu Interprozesskommunikation DÜRFEN NICHT zum Austausch von sensiblen Daten genutzt werden, sofern sie nicht zur Erfüllung des primären Zwecks der Anwendung erforderlich sind. | Bietet die Anwendung Schnittstellen an, berücksichtigt der TR-Prüfer deren Ausnutzbarkeit in der Risikoanalyse. Gemäß A.OperatingSystem wird insbesondere angenommen, dass für das Betriebssystem Funktionen zur Interprozesskommunikation bereitstehen, für die Regeln zur Isolation der Kommunikation gesetzt werden können. | CHECK |
Implementation
The only method we use for inter process communication is universal linking. Current outgoing use-cases are limited to login with insurance company apps. No sensitive data is transferred, the actual payload is decided by the server, as the universal links are created server side.
O.Plat_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_8 | Nutzung von Rendering Engines zum Nachladen aktiver Inhalte. | Verwendet die Anwendung für die Erfüllung ihres primären Zwecks eine Rendering Engine, MUSS sie diese so konfigurieren, dass aktive Inhalte nicht ausgeführt werden. Falls aktive Inhalte für die Realisierung der Anwendung unabdingbar sind, MUSS die Anwendung das Nachladen von Inhalten auf Quellen beschränken, die unter der Kontrolle des Herstellers sind oder durch den Hersteller autorisiert wurden. | Wenn die Anwendung Rendering Engines einsetzt, prüft der Evaluator, ob die Komponenten das Nachladen aktiver Inhalte unterbinden oder auf Quellen unter der Kontrolle des Herstellers beschränken. Die Auswahl der zugelassenen Quellen wird in der Risikoanalyse berücksichtigt. | CHECK |
Implementation
We only use native code and do not rely on any rendering engine, besides rendering some static HTML Pages (e.g. OSS-Licenses, Data Privacy, Terms of Use) that do not contain any scripts.
O.Plat_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_9 | Entfernung von sensiblen Daten bei Wechsel in den Hintergrundbetrieb. | Wechselt die Anwendung in den Hintergrundbetrieb, MUSS diese alle sensiblen Daten aus der aktuellen Ansicht („Views“ in iOS bzw. „Activities“ in Android) entfernen. | Der Evaluator prüft, ob die Anwendung sensible Daten aus den entsprechenden Anzeigeelementen der Anwendung entfernt. | EXAMINE |
Implementation
The content window is blurred upon leaving the application to not expose content to the system multitasking switcher.
../Sources/eRpApp/SceneDelegate.swift:246
Moving the application to the background blurs the application
// [REQ:BSI-eRp-ePA:O.Data_13#2,O.Plat_9#2] Moving the application to the background blurs the application
// window.
addBlurOverlayToWindow()
../Sources/eRpApp/SceneDelegate.swift:165
Moving the application to the foreground removes the blur.
// [REQ:BSI-eRp-ePA:O.Data_13#3,O.Plat_9#3] Moving the application to the foreground removes the blur.
removeBlurOverlayFromWindow()
O.Plat_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_10 | Deaktivierung nicht benötigter Protokoll-Handler in Rendering Engines. | Die Anwendung MUSS alle nicht benötigten Protokoll-Handler in Rendering-Engines deaktivieren. | Wenn die Anwendung Rendering Engines einsetzt, prüft der Evaluator, ob die Komponenten nicht benötigte Protokoll-Handler deaktivieren. | CHECK |
Implementation
Implemented using a WKWebViewDelegate
.
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationDomain.swift:91
Start login via gID
// [REQ:gemSpec_IDP_Frontend:A_22294-01] Start login via gID
// [REQ:BSI-eRp-ePA:O.Auth_4#9,O.Plat_10#2] Start login via gID
return .publisher(
../Sources/eRpApp/Screens/Settings/DataPrivacyTermsOfUseNavigationDelegate.swift:9
Delegate disables unused schemes
// [REQ:BSI-eRp-ePA:O.Plat_10#2] Delegate disables unused schemes
class DataPrivacyTermsOfUseNavigationDelegate: NSObject, WKNavigationDelegate {
../Sources/eRpApp/Screens/Settings/DataPrivacy/DataPrivacyView.swift:23
Usage of the delegate
// swiftlint:disable:next weak_delegate
// [REQ:BSI-eRp-ePA:O.Plat_10#3] Usage of the delegate
let navigationDelegate = DataPrivacyTermsOfUseNavigationDelegate()
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationDomain.swift:106
Follow redirect
// [REQ:gemSpec_IDP_Frontend:A_22299-01] Follow redirect
// [REQ:BSI-eRp-ePA:O.Plat_10#3] Follow redirect
guard environment.resourceHandler.canOpenURL(url) else {
../Sources/eRpApp/Screens/CardWall/Introduction/CardWallIntroductionDomain.swift:191
Follow redirect
// [REQ:gemSpec_IDP_Sek:A_22299] Follow redirect
// [REQ:BSI-eRp-ePA:O.Plat_10#3] Follow redirect
guard resourceHandler.canOpenURL(url) else {
../Sources/eRpApp/Screens/Settings/FOSS/FOSSView.swift:21
Usage of the delegate
// swiftlint:disable:next weak_delegate
// [REQ:BSI-eRp-ePA:O.Plat_10#4] Usage of the delegate
let navigationDelegate = DataPrivacyTermsOfUseNavigationDelegate()
../Sources/eRpApp/Screens/Settings/TermsOfUse/TermsOfUseView.swift:22
Usage of the delegate
// swiftlint:disable:next weak_delegate
// [REQ:BSI-eRp-ePA:O.Plat_10#5] Usage of the delegate
let navigationDelegate = DataPrivacyTermsOfUseNavigationDelegate()
O.Plat_11
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_11 | Löschen anwendungsspezifischer Cookies beim Beenden der Anwendung. | Die Anwendung MUSS vor dem ordnungsgemäßen Beenden das Löschen aller anwendungsspezifischen Sitzungsdaten (bspw. Cookies) bei der genutzten Rendering Engine anfordern. | Wenn die Anwendung Rendering Engines oder andere Arten zur Darstellung von Webinhalten einsetzt, prüft der Evaluator, ob anwendungsspezifische Sitzungsdaten nach Beenden der Anwendung gelöscht werden. | EXAMINE |
Implementation
WebViews only display local content that is delivered together with the application. Javascript is disabled, linking and loading other content is disabled. All other links to websites open the system browser. No cookies are created within the application or any webview that the application hosts.
../Sources/eRpApp/Screens/Settings/DataPrivacy/DataPrivacyView.swift:27
disabled javascript
// [REQ:BSI-eRp-ePA:O.Plat_11#2] disabled javascript
wkWebView.configuration.defaultWebpagePreferences.allowsContentJavaScript = false
../Sources/eRpApp/Screens/Settings/TermsOfUse/TermsOfUseView.swift:26
disabled javascript
// [REQ:BSI-eRp-ePA:O.Plat_11#3] disabled javascript
wkWebView.configuration.defaultWebpagePreferences.allowsContentJavaScript = false
../Sources/eRpApp/Screens/Settings/FOSS/FOSSView.swift:25
disabled javascript
// [REQ:BSI-eRp-ePA:O.Plat_11#4] disabled javascript
wkWebView.configuration.defaultWebpagePreferences.allowsContentJavaScript = false
O.Plat_12
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_12 | Überschreiben aller nutzerspezifischen Daten beim Beenden der Anwendung. | Die Anwendung SOLL nach Beenden alle nutzerspezifischen Daten im Arbeitsspeicher sicher überschrieben haben. | Die Anwendung darf sich bei der Beendigung nicht rein auf das Betriebssystem und den Garbage Collector der Laufzeitumgebung verlassen. Sensible Daten müssen aktiv gelöscht bzw. überschrieben werden. Der Evaluator ermittelt die Risiken für die einzelnen betroffenen Daten und berücksichtigt diese in der Risikobewertung. | EXAMINE |
Implementation
The app’s memory is subject to the operating system’s memory and therefore it has no control over the used memory. There is no technique known to overwrite memory in swift in a safe way, so that value types are deleted safely. The platform promises safety at process boundaries.
O.Plat_13
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_13 | Information des Nutzers über erforderliche Sicherheitsmaßnahmen zur Anwendung, Drittanbieter- Software und Plattformen. | Der Nutzer MUSS über Sicherheitsmaßnahmen informiert werden, sofern diese durch den Nutzer umsetzbar sind. | Der Evaluator prüft, ob der Nutzer über selbst durchführbare Sicherheitsmaßnahmen informiert und ggf. angeleitet wird. Der Evaluator bewertet, ob die Maßnahmen ausreichend sind, um Restrisiken zu begrenzen. | CHECK |
Implementation
During the onboarding process the user is forced to secure the access to the app either via a biometric trait or a strong password (or both). There is no additional security setting the user cannot set within the onbording.
O.Plat_14
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Plat_14 | Protokollierung bestimmter Sicherheitsereignisse. | Ein abgebrochener Start SOLL als Sicherheitsereignis protokolliert werden. Die Protokollierung SOLL im Hintergrundsystem stattfinden. | Der Evaluator überprüft die von dem Hersteller bereitgestellten Logdateien und validiert, dass ein abgebrochener Start und andere Sicherheitsereignisse der Anwendung protokolliert werden. Die Informationen dienen der Post- Mortem-Analyse von Sicherheitsvorfällen und sollten daher Informationen über alle ausgehenden Verbindungen enthalten, unter anderem Metainformationen über verwendete Proxys und überprüfte Server-Zertifikate. | CHECK |
Implementation
We do not log within the application. Though, logging is in place on FD and IDP and user data related events are logged into the audit events, that can be displayed within the application.
O.Purp_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_1 | Informationspflicht des Herstellers zum rechtmäßigen Zweck und Verarbeitung von personenbezogenen Daten. | Der Hersteller MUSS die rechtmäßigen Zwecke der Anwendung und die Verarbeitung von personenbezogenen Daten vor der Installation offenlegen (etwa in der Beschreibung des App- Stores; vgl. Anhang A) und den Nutzer mindestens bei der erstmaligen Inbetriebnahme darüber informieren. | Der Evaluator prüft, ob eine Beschreibung vorhanden ist und diese den rechtmäßigen Zwecken der Anwendung entspricht. Dabei werden die vom Hersteller definierten rechtmäßige Zwecke als Grundlage genutzt. Eine juristische Prüfung der Rechtmäßigkeit ist nicht erforderlich. | CHECK |
Implementation
The purpose is displayed as part of the Onboarding and can later be viewed from the settings.
../Sources/eRpApp/Screens/Onboarding/OnboardingLegalInfoView.swift:159
Display as part of the onboarding
// [REQ:BSI-eRp-ePA:O.Purp_1#1] Display as part of the onboarding
struct OnboardingPrivacyView: View {
../Sources/eRpApp/Screens/Settings/DataPrivacy/DataPrivacyView.swift:12
Actual View driving the display of DataPrivacy.html
// [REQ:BSI-eRp-ePA:O.Purp_1#2] Actual View driving the display of `DataPrivacy.html`
// [REQ:BSI-eRp-ePA:O.Arch_8#3] Webview containing local html without javascript
// [REQ:gemSpec_eRp_FdV:A_19980#2] Actual View driving the display of `DataPrivacy.html`
struct DataPrivacyView: View {
../Sources/eRpApp/Screens/Settings/SettingsLegalInfoView.swift:28
DataPrivacy display within Settings
// [REQ:BSI-eRp-ePA:O.Arch_9#3,O.Purp_1#4] DataPrivacy display within Settings
NavigationLink(
O.Purp_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_2 | Zweckgebundene Erhebung und Verarbeitung der Daten. | Die Anwendung DARF KEINE Daten erheben und verarbeiten, die nicht dem rechtmäßigen Zweck der Anwendung dienen. | Die Nutzung von Sensordaten ist nur soweit zulässig, wie sie etwa zur Erhebung des Seeds dient. Der Evaluator prüft anhand der Permisison-Policy, welche Daten in der Anwendung verarbeitet werden und ob diese den rechtmäßigen Zwecken der Anwendung entsprechen. Dabei werden die vom Hersteller definierten rechtmäßige Zwecke als Grundlage genutzt. Eine juristische Prüfung der Rechtmäßigkeit ist nicht erforderlich. | CHECK |
Implementation
../Sources/eRpApp/Screens/CameraView/ErxTaskScannerView.swift:22
Scanning tasks contains purpose related data input
// [REQ:BSI-eRp-ePA:O.Purp_2#1,O.Data_6#3] Scanning tasks contains purpose related data input
// [REQ:BSI-eRp-ePA:O.Source_1#1] Scanning tasks starts with scanner callback
store.send(.analyse(scanOutput: $0))
../Sources/eRpApp/Screens/CardWall/CAN/CardWallCANView.swift:121
CAN is used for eGK connection
// [REQ:BSI-eRp-ePA:O.Purp_2#2,O.Data_6#2] CAN is used for eGK connection
CardWallCANInputView(
../Sources/eRpApp/Screens/CardWall/PIN/CardWallPINView.swift:17
PIN is used for eGK Connection
// [REQ:BSI-eRp-ePA:O.Purp_2#3,O.Data_6#4] PIN is used for eGK Connection
PINView(store: store).padding()
../Sources/eRpApp/Tracking/AnalyticsReducer.swift:16
User interaction analytics trigger …
// [REQ:BSI-eRp-ePA:O.Purp_2#4,O.Purp_4#1,O.Data_6#6] User interaction analytics trigger ...
struct AnalyticsReducer<ContentReducer: Reducer>: Reducer
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:101
… records data only if user opt-in is given.
// [REQ:BSI-eRp-ePA:O.Purp_2#5,O.Purp_4#2,O.Data_6#7] ... records data only if user opt-in is given.
if optIn {
../Sources/eRpApp/Screens/Pharmacy/Redeem/PharmacyContactView.swift:11
Contact information is collected when needed for redeeming
// [REQ:BSI-eRp-ePA:O.Purp_2#6,O.Data_6#5] Contact information is collected when needed for redeeming
struct PharmacyContactView: View {
O.Purp_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_3 | Einholung einer Einwilligungserklärung des Nutzers. | Die Anwendung MUSS vor jeglicher Erfassung oder Verarbeitung personenbezogener Daten eine aktive und eindeutige Einwilligungserklärung des Nutzers einholen. | Der Evaluator prüft, ob ohne Zustimmung des Nutzers personenbezogene Daten verarbeitet werden können. | CHECK |
Implementation
../Sources/eRpApp/Screens/Onboarding/OnboardingContainer.swift:59
Terms of Use display is part of the onboarding
// [REQ:BSI-eRp-ePA:O.Purp_3#1] Terms of Use display is part of the onboarding
.sheet(isPresented: $store.showTermsOfUse.sending(\.setShowUse)) {
Terms of Use acceptance is required as part of the Onboarding.
../Sources/eRpApp/Screens/Settings/TermsOfUse/TermsOfUseView.swift:11
Actual view for the Terms of Use display
// [REQ:BSI-eRp-ePA:O.Purp_3#2] Actual view for the Terms of Use display
// [REQ:BSI-eRp-ePA:O.Arch_8#1] Webview containing local html without javascript
struct TermsOfUseView: View {
../Sources/eRpApp/Screens/Onboarding/OnboardingLegalInfoView.swift:72
User acceptance
// [REQ:BSI-eRp-ePA:O.Purp_3#3] User acceptance
OnboardingLegalInfoCheckmarkView(isAccepted: $isAllAccepted)
../Sources/eRpApp/Screens/Onboarding/OnboardingContainer.swift:39
Callback triggers tracking alert
// [REQ:BSI-eRp-ePA:O.Purp_3#4] Callback triggers tracking alert
store.send(.showTracking)
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:191
Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19088,A_19091-01#1,A_19092-01#2] Show comply route to display analytics usage within
// onboarding
// [REQ:BSI-eRp-ePA:O.Purp_3#5] Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19089-01#2] Show comply route to display analytics usage within onboarding
case .showTracking:
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:195
Accept usage analytics
// [REQ:gemSpec_eRp_FdV:A_19090-01,A_19091-01#2] User confirms the opt in within settings
// [REQ:BSI-eRp-ePA:O.Purp_3#6] Accept usage analytics
case .alert(.presented(.allowTracking)):
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:200
Deny usage analytics
// [REQ:gemSpec_eRp_FdV:A_19092-01#3] User may choose to not accept analytics, onboarding will still continue
// [REQ:BSI-eRp-ePA:O.Purp_3#7] Deny usage analytics
case .alert(.dismiss):
O.Purp_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_4 | Nutzung ausschließlich zugestimmter Daten. | Daten, deren Verarbeitung der Nutzer nicht ausdrücklich zugestimmt hat, DÜRFEN NICHT von der Anwendung oder dem Hintergrundsystem erfasst, erhalten oder genutzt werden. | Der Evaluator gleicht die in O.Purp_2 gewonnen Erkenntnisse mit den erteilten Zustimmungen ab. | CHECK |
Implementation
../Sources/eRpApp/Tracking/AnalyticsReducer.swift:16
User interaction analytics trigger …
// [REQ:BSI-eRp-ePA:O.Purp_2#4,O.Purp_4#1,O.Data_6#6] User interaction analytics trigger ...
struct AnalyticsReducer<ContentReducer: Reducer>: Reducer
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:101
… records data only if user opt-in is given.
// [REQ:BSI-eRp-ePA:O.Purp_2#5,O.Purp_4#2,O.Data_6#7] ... records data only if user opt-in is given.
if optIn {
O.Purp_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_5 | Entzug der Einwilligung ermöglichen. | Die Anwendung MUSS ermöglichen, dass der Nutzer eine bereits erteilte Einwilligung wieder entziehen kann. Der Nutzer MUSS vor der Einwilligung über die Möglichkeit des Widerrufs und die sich daraus ergebenden Veränderungen im Verhalten der Anwendung informiert werden. | Der Evaluator prüft, ob dem Nutzer die Möglichkeit gegeben wird erteilte Einwilligungen wieder zu entziehen. Darüber hinaus validiert er, dass der Nutzer beim Entzug von Einwilligungen auf die daraus resultierenden Konsequenzen hingewiesen wird. | CHECK |
Implementation
../Sources/eRpApp/Screens/Settings/SettingsView.swift:159
Toggle within Settings to enable and disable usage analytics
// [REQ:gemSpec_eRp_FdV:A_19097-01#2] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_5#1] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_6#1] Current Analytics state is inspectable by the user
// [REQ:gemSpec_eRp_FdV:A_19982#4] Opt out of analytics
Toggle(isOn: $store.trackerOptIn.sending(\.toggleTrackingTapped).animation()) {
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:156
Actual disabling of analytics
// Tracking
// [REQ:gemSpec_eRp_FdV:A_19088, A_19089-01#5, A_19092-01#4, A_19097-01#1] React to later opt-in or deactivation
// of usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_5#2] Actual disabling of analytics
// [REQ:gemSpec_eRp_FdV:A_19982#2] Opt out of analytics
case let .toggleTrackingTapped(optIn):
../Sources/eRpApp/Screens/Settings/SettingsView.swift:46
Show comply view for settings triggered analytics enabling
// Tracking comply sheet presentation
// [REQ:BSI-eRp-ePA:O.Purp_5#3] Show comply view for settings triggered analytics enabling
// [REQ:gemSpec_eRp_FdV:A_19982#3,A_19089-01#3] Show information dialog for analytics usage
Rectangle()
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:166
User confirms the opt in within settings
// [REQ:gemSpec_eRp_FdV:A_19090-01,A_19091-01#4] User confirms the opt in within settings
// [REQ:BSI-eRp-ePA:O.Purp_5#4] User confirms the opt in within settings
case .confirmedOptInTracking:
O.Purp_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_6 | Führen eines Verzeichnisses der Nutzereinwilligungen. | Der Hersteller MUSS ein Verzeichnis führen, welches erkennen lässt, welche Nutzereinwilligungen vorliegen. Der nutzerspezifische Teil des Verzeichnisses MUSS für den Nutzer automatisiert einsehbar sein. Es SOLL eine Historie dieses Verzeichnisses angefordert werden können. | Der Evaluator prüft das Vorhandensein, die Aktualität und die Vollständigkeit des Verzeichnisses. | CHECK |
Implementation
../Sources/eRpApp/Screens/Settings/SettingsView.swift:160
Current Analytics state is inspectable by the user
// [REQ:gemSpec_eRp_FdV:A_19097-01#2] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_5#1] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_6#1] Current Analytics state is inspectable by the user
// [REQ:gemSpec_eRp_FdV:A_19982#4] Opt out of analytics
Toggle(isOn: $store.trackerOptIn.sending(\.toggleTrackingTapped).animation()) {
As most of the user decisions are client side no history is available. Only the current state can be inspected.
O.Purp_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_7 | Nutzung nur erforderlicher Drittanbieter-Software. | Setzt die Anwendung Drittanbieter-Software ein, MÜSSEN alle verwendeten Funktionen für die rechtmäßigen Zwecke der Anwendung erforderlich sein. Die Anwendung SOLL anderweitige Funktionen sicher deaktivieren. Wird nur eine einzige oder sehr wenige Funktionen der Drittanbieter-Software benötigt, MUSS abgewogen werden, ob die Einbindung der gesamten Drittanbieter-Software im Verhältnis zur Vergrößerung der Angriffsoberfläche durch die verwendete Drittanbieter-Software steht. | Der Evaluator prüft die Abwägungen des Herstellers bei Funktionen, die nicht dem rechtmäßigen Zweck für die Anwendung dienen. So dürfte beispielsweise eine API für soziale Netzwerke nur verwendet werden, wenn dies mit dem rechtmäßigen Zweck der Anwendung vereinbar ist. Die Risikobewertung erfasst die Auswirkungen auf den Schutz der Gesundheitsdaten, beispielsweise bei dem für Dritte erkennbaren Nutzungsverhalten in Logging Frameworks. | CHECK |
Implementation
Most libraries are self written and cover only what is needed. Dependencies are only included if really necessary. We think about including only sub packages, but as most dependencies are very small, this is hardly used. Besides that, no means of removing unused dependency functionality is available for libraries of the platform.
O.Purp_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_8 | Weitergabe von sensiblen Daten nur für den primären oder rechtmäßigen Zweck. | Sofern es nicht für den vorgesehenen primären oder rechtmäßigen Zweck einer Anwendung erforderlich ist, DÜRFEN sensible Daten NICHT mit Dritten geteilt werden. Dies betrifft auch die Ablage dieser Daten in Teilen des Dateisystems, auf die auch andere Anwendungen Zugriff haben. Die Anwendung MUSS den Nutzer über die Konsequenzen einer eventuellen Weitergabe von Anwendungsdaten, die dem primären oder rechtmäßigen Zweck dienen, vollumfänglich informieren und sein Einverständnis einholen (OPT-IN). | Der Evaluator prüft die Abwägungen des Herstellers, ob die Weitergabe von sensiblen Daten an Dritte dem primären oder rechtmäßigen Zweck für die Anwendung dient. Darüber hinaus prüft er, ob die Weitergabe immer explizit durch den Nutzer erlaubt werden muss (Opt-In). Die Weitergabe an Dienste, deren primärer Zweck die Verarbeitung von Daten für Werbezwecke ist, ist generell verboten. Die Risikobewertung berücksichtigt, wie die Weitergabe von Daten an Dritte im Verhältnis zum Schutzbedarf der weitergeleiteten Informationen (Daten) und der daraus resultierenden Gefahr der Preisgabe von Informationen steht. | CHECK |
Implementation
Sharing of data is only for the primary purpose of the application e.g. sending presriptions to a pharmacy or sharing a prescription with a family member. We do not store data in shared containers in any way.
../Sources/eRpApp/Session/KeychainStorage.swift:21
Implementation of data storage that is persisted via keychain
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
../Sources/eRpLocalStorage/CoreDataControllerFactory.swift:32
CoreData databases are protected
// [REQ:BSI-eRp-ePA:O.Purp_8#2] CoreData databases are protected
self.fileProtection = fileProtection
../Sources/eRpLocalStorage/CoreDataController.swift:59
actual protection setting on file system level
// [REQ:BSI-eRp-ePA:O.Purp_8#3|4] actual protection setting on file system level
protectedStoreDescription.setOption(
fileProtectionType as NSObject,
forKey: NSPersistentStoreFileProtectionKey
)
../Sources/eRpLocalStorage/CoreDataController.swift:83
Database backup exclusion
// [REQ:BSI-eRp-ePA:O.Purp_8#4,O.Arch_4#2,O.Data_15#1] Database backup exclusion
if excludeFromBackup, let storeUrl = store.url {
O.Purp_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Purp_9 | Nur zweckgebundene Darstellung sensibler Daten auf dem Bildschirm. | Die Anwendung DARF sensible Daten NICHT auf dem Bildschirm darstellen, außer dies ist für den primären Zweck der Anwendung erforderlich. | Der Evaluator prüft die Abwägungen des Herstellers, ob die Darstellung von sensiblen Daten zum gegebenen Zeitpunkt für die Erfüllung des Zwecks der Anwendung erforderlich ist. Für die Risikobewertung ist zu berücksichtigen, wie die Anwendung den Nutzer davor schützt, sensible Daten anzuzeigen (vergleiche T.VisibleAsset). | CHECK |
Implementation
Sensitive data is only shown for the purpose of this application. This includes display of prescriptions, personal data and health data.
O.Rand_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Rand_1 | Erzeugung von Zufallswerten durch sicheren Zufallszahlengenerator. | Alle Zufallswerte MÜSSEN über einen starken kryptographischen Zufallszahlengenerator erzeugt werden, welcher mit ausreichend Entropie geseedet wurde (vgl. [TR02102-1]). | Der Evaluator prüft durch Quelltextanalyse und praktische Tests die Güte des kryptographischen Zufallszahlengenerators. Informationen zu ausreichend sicheren Zufallszahlengeneratoren sind [TR02102-1] Kapitel 10 zu entnehmen. Für die Nachbearbeitung der Zufallszahlen sind die vom BSI als ausreichend sicher angesehen Algorithmen (s.[AIS20], [TR03107-1] und [TR03116-4]) zu verwenden. | EXAMINE |
Implementation
We use the platform provided secure random generator. iOS is FIPS 140-2 certified. The operating system uses an entropy pool with different sources, including a true random number generator from the secure enclave, that is present on every device. Security certifcates can be found https://support.apple.com/de-li/guide/certifications/apc3fa917cb49/web, including FIPS 140-2 und Common Criteria.
../Sources/IDP/internal/SecKeyRandom.swift:21
Secure Random generator.
/// Generate random Data with given length
///
/// [REQ:gemSpec_Krypt:GS-A_4367]
/// [REQ:BSI-eRp-ePA:O.Rand_1#2] Secure Random generator.
///
/// - Parameters:
/// - length: the number of bytes to generate
/// - randomizer: the randomizer to be used. Default: kSecRandomDefault
/// - Returns: the random initialized Data
/// - Throws: `IDPError`
public func generateSecureRandom(length: Int, randomizer: SecRandomRef? = kSecRandomDefault) throws -> Data {
../Sources/VAUClient/internal/VAURandom.swift:22
Secure Random generator.
/// Generate random Data with given length
///
/// [REQ:gemSpec_Krypt:GS-A_4367]
/// [REQ:BSI-eRp-ePA:O.Rand_1#3] Secure Random generator.
///
/// - Parameters:
/// - length: the number of bytes to generate
/// - randomizer: the randomizer to be used. Default: kSecRandomDefault
/// - Returns: the random initialized Data
/// - Throws: `VAUError`
static func generateSecureRandom(length: Int, randomizer: SecRandomRef? = kSecRandomDefault) throws -> Data {
O.Resi_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_1 | Informationen zum sicheren Umgang mit der Anwendung. | Die Anwendung MUSS dem Nutzer barrierearme Best-Practice-Empfehlungen zum sicheren Umgang mit der Anwendung und ihrer Konfiguration bereitstellen. | Der Evaluator prüft, ob die Anwendung „Best-Practices“ bereitstellt. Er bestätigt, dass vorhandene „Best-Practices“ dem aktuellen Stand der Technik entsprechen. | CHECK |
Implementation
The onboarding contains defaults that are best practices, such as using biometrics for authentication. While using the Cardwall, selecting the “save login” option results in an dialog with additional information, to let the user make informed decisions. A missing device passcode results in a dialog that is recommending the setup of a device passcode.
../Sources/eRpApp/Screens/Onboarding/OnboardingRegisterAuthenticationView.swift:11
View containing onboarding authentication
// [REQ:BSI-eRp-ePA:O.Resi_1#2] View containing onboarding authentication
struct OnboardingRegisterAuthenticationView: View, KeyboardReadable {
../Sources/eRpApp/Screens/CardWall/Login/CardWallLoginOptionView.swift:95
View containing information regarding the login options.
// [REQ:gemSpec_IDP_Frontend:A_21574] Actual view
// [REQ:BSI-eRp-ePA:O.Resi_1#3] View containing information regarding the login options.
struct PrivacyWarningViewContainer: View {
../Sources/eRpApp/Screens/Main/DeviceSecurity/DeviceSecurityNoSystemPin/DeviceSecuritySystemPinView.swift:9
View containing the “no system pin” message.
// [REQ:BSI-eRp-ePA:O.Resi_1#4] View containing the "no system pin" message.
struct DeviceSecuritySystemPinView: View {
O.Resi_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_2 | Erkennung vom Betriebszustand des verwendeten Endgerätes. | Die Anwendung MUSS mittels Betriebssystem- Funktion abfragen, ob sich das Betriebssystem in einem Betriebszustand befindet, der den Anforderungen des Betriebssystemherstellers entspricht. Befindet sich das Betriebssystem in keinem vom Betriebssystemhersteller vorgesehenen Zustand, MUSS die Anwendung angemessen darauf reagieren. Die Anwendung MUSS dem Nutzer darstellen, welche Risiken für die Daten des Nutzers bei einer Fortsetzung der Anwendung bestehen (z. B., dass diese offengelegt werden könnten) oder die Fortsetzung unterbinden. | Der Evaluator überprüft durch praktische Tests die Wirksamkeit der Maßnahmen zur Erkennung, ob sich das Betriebssystem außerhalb eines Betriebszustand befindet, der den Anforderungen des Betriebssystemherstellers entspricht (z.B. Root-/Jailbreak-Erkennung). Weiterhin prüft er, ob die Anwendung angemessen auf das Erkennen reagiert. Dies kann beispielsweise eine Terminierung der Anwendung sein (vergleiche O.Resi_5). Gemäß A.OperatingSystem wird angenommen, dass das Betriebssystem Funktionen bereitstellt, mit denen eine Anwendung die Konformität des Betriebszustandes bezüglich der Anforderungen des Betriebssystemherstellers an das Betriebssystem abfragen kann. | EXAMINE |
Implementation
Jailbreak detection is done on startup of the application after the app authentication. If a jailbreak is detected, a information dialog is presented to the user.
../Sources/eRpApp/Screens/Main/MainView.swift:95
trigger device security check
// [REQ:BSI-eRp-ePA:O.Arch_6#2,O.Resi_2#2,O.Plat_1#2] trigger device security check
store.send(.loadDeviceSecurityView)
../Sources/eRpApp/Session/Helper/DeviceSecurityManager.swift:58
calculate system risk for jailbreak and missing device pin
// [REQ:BSI-eRp-ePA:O.Arch_6#3,O.Resi_2#3,O.Plat_1#3] calculate system risk for jailbreak and missing device pin
var showSystemSecurityWarning: AnyPublisher<DeviceSecurityWarningType, Never> {
../Sources/eRpApp/Session/Helper/DeviceSecurityManager.swift:112
Jailbreak detection
// [REQ:BSI-eRp-ePA:O.Arch_6#4,O.Resi_2#4] Jailbreak detection
func informJailbreakDetected() -> Bool {
../Sources/eRpApp/Screens/Main/DeviceSecurity/DeviceSecurityRootedDevice/DeviceSecurityRootedDeviceView.swift:9
Jailbreak information view
// [REQ:BSI-eRp-ePA:O.Arch_6#5,O.Resi_2#5] Jailbreak information view
struct DeviceSecurityRootedDeviceView: View {
O.Resi_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_3 | Erkennung und Unterbindung des Starts in einer Entwicklungs- /Debug-Umgebung. | Die Anwendung MUSS eigene Prüfmechanismen implementieren, die beim Start der Anwendung feststellen, ob sie in einer Entwicklungs-/Debug-Umgebung ausgeführt wird. Wenn die Anwendung feststellt, dass sie in einer Entwicklungs-/Debug-Umgebung ausgeführt wird, MUSS sie sich sofort beenden. | Der Evaluator prüft die Wirksamkeit der Debug-Erkennung durch praktische Tests. (vergleiche O.Resi_5). | CHECK |
Implementation
Starting within a debug environment is only possible on rooted/jailbroken devices. If that is the case, the user sees a dialog and can choose to continue or cancel using the application. See O.Resi_2 for jailbreak detection details.
O.Resi_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_4 | Abbruch des Starts der Anwendung bei ungewöhnlichen Benutzerrechten. | Die Anwendung MUSS eigene Prüfmechanismen implementieren, die beim Start der Anwendung feststellen, ob sie unter ungewöhnlichen Benutzerrechten gestartet ist. Wenn die Anwendung feststellt, dass dies der Fall ist, MUSS sie sich sofort beenden. | Der Evaluator prüft die Wirksamkeit der Erkennung durch praktische Tests (vergleiche O.Resi_5). | CHECK |
Implementation
Starting with unusal app rights is only possible on rooted/jailbroken devices. If that is the case, the user sees a dialog and can choose to continue or cancel using the application. See O.Resi_2 for jailbreak detection details.
O.Resi_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_5 | Überprüfung der Integrität des Endgeräts vor Verarbeitung sensibler Daten. | Die Anwendung SOLL die Integrität des Endgeräts sicherstellen , bevor sensible Daten verarbeitet werden. | Der Evaluator untersucht, welche Integritätsprüfung durch die Anwendung vorgenommen wird. Wenn die Prüfung durch externe Tools durchgeführt wird, zu dem der Evaluator keinen Quelltext besitzt, führt er einen Penetrationstest durch (vergleiche O.Resi_2 bis O.Resi_4). Ein Integritätscheck muss mindestens folgende Aspekte abdecken: • Einsatz von „custom firmware“. • Aktualität der Betriebssystemversion. • Vorhandensein von verdächtigen Werkzeugen oder Anwendungen auf dem Gerät. | EXAMINE |
Implementation
Device Integrity may only be compromised on jailbroken devices. If that is the case, the user sees a dialog and can choose to continue or cancel using the application. See O.Resi_2 for jailbreak detection details. We exclude very old and unsecure devices, by restricting the application to modern iOS Versions. That restriction is automatically restricting the range of devices it can run on. See options.deploymentTarget.iOS
path within project.yml
or the generated IPHONEOS_DEPLOYMENT_TARGET
within the project.pbxproj
file for the iOS Version restriction.
O.Resi_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_6 | Überprüfung der Authentizität des Hintergrundsystems vor Zugriff. | Die Anwendung MUSS vor dem Zugriff auf das Hintergrundsystem dessen Integrität überprüfen (siehe auch O.Ntwk_4). | Der Evaluator prüft die Wirksamkeit der Authentizitätsprüfung (beispielsweise Zertifikats-Pinning) durch praktische Tests. | EXAMINE |
Implementation
IDP Communication is secured by using TLS with pinned Certificates as well as JWEs with keys that are pinned using a TI specific trust anchor as well as OCSP. FD Communication is secured by using TLS and VAU encryption, again with pinned Certificates for both methods. APOVZD communication uses TLS with pinned certificates. The Pinned certificates fingerprints can be found within Sources/eRpApp/Resources/Info.plist
.
../Sources/IDP/DefaultIDPSession.swift:262
Implementation of loading the discovery document for fetching signature and
// [REQ:BSI-eRp-ePA:O.Resi_6#2] Implementation of loading the discovery document for fetching signature and
// encryption keys.
// [REQ:gemSpec_Krypt:A_21222#3] DiscoveryDocument is validated with the active trustStoreSession
private func loadDiscoveryDocument() -> AnyPublisher<DiscoveryDocument, IDPError> {
../Sources/IDP/DefaultIDPSession.swift:423
Discovery Document signature verification
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Signature verification
// [REQ:gemSpec_IDP_Frontend:A_23082#3] Signature verification
// [REQ:BSI-eRp-ePA:O.Resi_6#3] Discovery Document signature verification
guard try jwtContainer.verify(with: document.discKey) == true else {
../Sources/IDP/DefaultIDPSession.swift:291
Discovery Document signature verification
// Validate JWT/DiscoveryDocument signature
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02] Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4361-02] Assure that brainpoolP256r1 is used
// [REQ:BSI-eRp-ePA:O.Resi_6#4] Discovery Document signature verification
guard (try? fetchedDocument.backing.verify(with: fetchedDocument.discKey)) ?? false else {
../Sources/IDP/DefaultIDPSession.swift:757
Discovery Document signature verification
// [REQ:BSI-eRp-ePA:O.Resi_6#5|6] Discovery Document signature verification
validate(certificate: discoveryDocument.discKey)
// [REQ:gemSpec_IDP_Frontend:A_20625#3|4] `C.FD.SIG`-Certificate verification
.zip(validate(certificate: discoveryDocument.signingCert))
.map { isDiscKeyValid, isSigningCertValid -> Bool in
isDiscKeyValid && isSigningCertValid
}
O.Resi_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_7 | Integration von Härtungsmaßnahmen vor Verarbeitung sensibler Daten. | Die Anwendung SOLL Härtungsmaßnahmen, wie etwa eine Integritätsprüfung vor jeder Verarbeitung sensibler Daten innerhalb des Programmablaufs, realisieren. | Der Evaluator prüft, ob die Anwendung eine Integritätsprüfung bei jedem Programmstart oder bei sensiblen Operationen durchführt. Andernfalls werden die daraus resultierenden Restrisiken in der Risikobewertung berücksichtigt. | EXAMINE |
Implementation
Recent Jailbreaks force a reboot or restart of springboard. Thus the application will also be restarted in these cases. The check for hardening is done on app startup and should be sufficient.
O.Resi_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_8 | Umsetzung von Maßnahmen gegen Reverse Engineering. | Die Applikation MUSS starke Maßnahmen gegen Reverse Engineering umsetzen. | Der Evaluator prüft, ob starke Maßnehmen gegen Reverse Engineering getroffen werden. „Starke Maßnahmen“ müssen sämtliche Strings, Dateinamen und interne Namen von Klassen und Methoden innerhalb der Anwendung, die einem Angreifer Hinweise auf den Programmablauf geben können, verschleiern. Die Anwendung kann hierfür weitere Verschleierungsmaßnahmen, wie beispielsweise White-Box- Kryptographie oder den Einsatz von virtuellen Maschinen zurückgreifen. Der Evaluator prüft die Wirksamkeit des Schutzes vor Reverse Engineering durch praktische Tests und dokumentiert den Prozess. Der Evaluator bewertet die bestehenden Restrisiken der Implementierung unter anderem in Bezug auf T.MemoryStructures, T.InfoDisclosure und T.SensitiveData. | EXAMINE |
Implementation
The application source is available on github. Any measure of preventing reverse engineering would be pointless.
O.Resi_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_9 | Berücksichtigung von Plattformen und Versionen bei Zugriffskontrollmechanismen. | Die Anwendung MUSS unterschiedliche Ausprägungen einer Plattform (bspw. Android) bei unterschiedlichen Herstellern berücksichtigen. Sie muss so gebaut sein, dass solche unterschiedlichen Plattformen bzw. unterschiedliche Plattformversionen zu keinem Fehlverhalten führt. Insbesondere MUSS ein missbräuchlicher Zugriff auf Ressourcen durch unterschiedliche Ausprägungen einer Plattform ausgeschlossen werden. | Der Evaluator bestätigt, dass sich die Implementierung der Zugriffsmaßnahmen nicht allein auf das Betriebssystem verlässt und damit evtl. durch einen Downgrade- Angriff auf das Betriebssystem verwundbar ist. | EXAMINE |
Implementation
Data is not stored while moving between platforms or devices. Private keys are stored within the secure enclave an cannot leave the device. Downgrades are prohibited by the operating system and update mechanisms.
O.Resi_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Resi_10 | Robustheit gegenüber Störungen. | Die Anwendung MUSS robust gegenüber Störungen sein. | Der Evaluator prüft durch Quelltextanalyse und praktischen Tests, ob Störungen (z.B. in der Stromversorgung, Internetverbindung) oder Fehlbedienung zu einem Verlust der Daten führen können. | EXAMINE |
Implementation
Missing internet connection or other means of disruption use the same error mechanisms as every part of the app uses for normal errors. Data is only deleted where appropriate, e.g. invalid tokens are deleted. User Data is not deleted unless explicitly confirmed by the user.
O.Source_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_1 | Prüfung von Eingaben vor Verwendung. | Die Anwendung MUSS alle Eingaben vor deren Verarbeitung prüfen, um potenziell bösartige Werte vor der Verarbeitung herauszufiltern. | Der Evaluator prüft, ob für alle Eingaben aus nicht vertrauenswürdigen Quellen Sicherheitsfunktionen gemäß O.Arch_5 vorhanden sind. Eingaben meinen jegliche Art von Daten, die in die Anwendung hineinfließen. Das sind zum Beispiel Nutzereingaben, Eingaben aus Drittanbieterkomponenten etc. | CHECK |
Implementation
../Sources/eRpApp/Screens/CameraView/ErxTaskScannerView.swift:23
Scanning tasks starts with scanner callback
// [REQ:BSI-eRp-ePA:O.Purp_2#1,O.Data_6#3] Scanning tasks contains purpose related data input
// [REQ:BSI-eRp-ePA:O.Source_1#1] Scanning tasks starts with scanner callback
store.send(.analyse(scanOutput: $0))
We have two potential unknown inputs, one being the scanner, that scanns QR Codes or Data Matrix Codes. External interactions are managed through Universal Linking, with thorough validation of URL parameters to ensure only predefined variables are accepted.
../Sources/eRpApp/Screens/CameraView/ScannerDomain.swift:129
analyse the input
// [REQ:BSI-eRp-ePA:O.Source_1#2] analyse the input
let result = try CodeAnalyser.analyse(scanOutput: scanOutput, with: state.acceptedTaskBatches)
../Sources/eRpApp/Screens/CameraView/ScannerDomain+Helper.swift:16
validation
// [REQ:BSI-eRp-ePA:O.Source_1#3] validation
static func analyse(scanOutput: [ScanOutput],
../Sources/eRpKit/ScannedErxTask.swift:104
actual validation by decoding into predefined structure
// [REQ:gemSpec_eRp_FdV:A_19984] validate data matrix code structure
// [REQ:BSI-eRp-ePA:O.Source_1#4] actual validation by decoding into predefined structure
erxToken = try jsonDecoder.decode(ErxToken.self, from: jsonData)
../Sources/eRpApp/SceneDelegate.swift:250
External application calls via Universal Linking
// [REQ:BSI-eRp-ePA:O.Source_1#5] External application calls via Universal Linking
func scene(_: UIScene, continue userActivity: NSUserActivity) {
../Sources/eRpApp/Screens/AppStartDomain.swift:221
External application calls via Universal Linking
// [REQ:BSI-eRp-ePA:O.Source_1#6] External application calls via Universal Linking
case let .universalLink(url):
../Sources/eRpApp/Screens/Main/MainDomain.swift:257
redirect into correct domain
// [REQ:BSI-eRp-ePA:O.Source_1#7] redirect into correct domain
// [REQ:gemSpec_IDP_Frontend:A_22301-01#6|3] Redirect into ExtAuthPendingDomain
return .run { send in
../Sources/eRpApp/Screens/Main/ExtAuth/ExtAuthPendingDomain.swift:156
Validate data by parsing url and only allowing predefined variables as String
// [REQ:BSI-eRp-ePA:O.Source_1#8] Validate data by parsing url and only allowing predefined variables as String
// [REQ:gemSpec_IDP_Frontend:A_22301-01#7] Actual handling of the universal link, user feedback via dialogs e.g.
case let .externalLogin(url),
O.Source_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_2 | Nutzung einer Escape-Syntax bei strukturierten Daten. | Die Anwendung MUSS eingehende und ausgehende Daten maskieren beziehungsweise von potenziell schadhaften Zeichen bereinigen oder deren Verarbeitung ablehnen. | Der Evaluator prüft, ob eine Escape- Syntax von strukturierten Daten für alle Eingaben gemäß O.Arch_5 vorhanden ist. Schadhafte Zeichen sind kontextabhängig zu betrachten. Im Datenbank-Kontext sind beispielsweise Hochkommata oder Prozentzeichen gegebenenfalls schadhaft, während im Web/HTML Kontext eher Tag-Klammern (<) schadhaft sind. Grundsätzlich muss die Input-Validierung daher kontextbezogen stattfinden. Wird eine potenziell schädliche Eingabe erkannt, muss sie entweder bereinigt/maskiert oder abgelehnt/verworfen werden. Das Verwerfen sollte dem Bereinigen vorgezogen werden. Sofern vorher maskierte oder bereinigte Eingaben weitergegeben werden, müssen diese so maskiert oder enkodiert werden, dass sie im Kontext der Weitergabe keine schädlichen Effekte haben. | CHECK |
Implementation
Data escaping is managed by the operating system frameworks. We do not create SQL queries manually; instead, we utilize CoreData as an ORM. Queries are constructed using NSFetchRequests and NSPredicates, which automatically escape all manual input. Additionally, actual user data is transmitted via FHIR, with the escaping process handled by Apple’s provided FHIR library.
../Sources/eRpLocalStorage/Pharmacy/PharmacyCoreDataStore.swift:13
CoreDataStore adapter for PharmacyLocation
s
/// Store for fetching, creating, updating or deleting `PharmacyLocation`s on the provided `CoreDataController`
/// [REQ:BSI-eRp-ePA:O.Source_2#2] CoreDataStore adapter for `PharmacyLocation`s
public class PharmacyCoreDataStore: PharmacyLocalDataStore, CoreDataCrudable {
../Sources/eRpLocalStorage/Prescriptions/ErxTaskCoreDataStore.swift:20
CoreDataStore adapter for ErxTask
s
// tag::ErxTaskCoreDataStoreDescription[]
/// Store for fetching, creating, updating or deleting `ErxTask`s and it‘s underlying types. Access to most entities is
/// tied to the given profileId.
/// [REQ:BSI-eRp-ePA:O.Source_2#3] CoreDataStore adapter for `ErxTask`s
public class DefaultErxTaskCoreDataStore: ErxTaskCoreDataStore {
../Sources/eRpLocalStorage/Profiles/ProfileCoreDataStore.swift:13
CoreDataStore adapter for Profile
s
/// Store for fetching, creating, updating or deleting `Profile`s on the provided `CoreDataController`
/// [REQ:BSI-eRp-ePA:O.Source_2#4] CoreDataStore adapter for `Profile`s
public class ProfileCoreDataStore: ProfileDataStore, CoreDataCrudable {
../Sources/eRpLocalStorage/ShipmentInfo/ShipmentInfoCoreDataStore.swift:13
CoreDataStore adapter for ShipmentInfoEntity
s
/// Store for fetching, creating, updating or deleting `ShipmentInfoEntity`s on the provided `CoreDataController`
/// [REQ:BSI-eRp-ePA:O.Source_2#5] CoreDataStore adapter for `ShipmentInfoEntity`s
public class ShipmentInfoCoreDataStore: ShipmentInfoDataStore, CoreDataCrudable {
../Sources/eRpLocalStorage/AVSTransaction/AVSTransactionCoreDataStore.swift:13
CoreDataStore adapter for AVSTransactionEntity
s
/// Store for fetching, creating, updating or deleting `AVSTransactionEntity`s on the provided `CoreDataController`
/// [REQ:BSI-eRp-ePA:O.Source_2#6] CoreDataStore adapter for `AVSTransactionEntity`s
public class AVSTransactionCoreDataStore: AVSTransactionDataStore, CoreDataCrudable {
../Sources/Pharmacy/ModelsR4.Bundle+Location.swift:18
Extension containing all FHIR related parsing for Pharmacies
/// [REQ:BSI-eRp-ePA:O.Source_2#7] Extension containing all FHIR related parsing for Pharmacies
extension ModelsR4.Bundle {
See all files named ModelsR4.Bundles+<TypeName>
within eRpRemoteStorage
Package to find all references for FD related FHIR parsing. All other files within the Module are either helpers or provide support for creating FHIR objects that may be sent to the FD.
O.Source_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_3 | Keine sensiblen Daten in Meldungen. | Fehlermeldungen und Log-Dateien DÜRFEN KEINE sensiblen Daten (z. B. User Identifier) enthalten. | Der Evaluator prüft, ob sensible Daten über Fehlermeldungen oder Benachrichtigungen einsehbar werden. | CHECK |
Implementation
Error messages are localized using the Foundation.LocalizedError
protocol. Search for LocalizedError
to see all instances. Most errors are localized with static text, some errors contain server side error messages. User data is never used for error messages. Logging is only active on debug builds. See O.Plat_4 for reference.
O.Source_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_4 | Kontrollierte Behandlung und Dokumentation von Ausnahmen (Exceptions). | Potenzielle Ausnahmen im Programmablauf (Exceptions) MÜSSEN abgefangen, kontrolliert behandelt und dokumentiert werden. Technische Fehlerbeschreibungen (z.B. Stack Traces) DÜRFEN dem Nutzer NICHT angezeigt werden. | Der Evaluator prüft durch Quelltextanalyse und praktische Tests die kontrollierte Behandlung und Dokumentation von Exceptions. | EXAMINE |
Implementation
Exception handling in swift uses Errors to represent the exception. We use a custom protocol CodedError
that is autogenerated for all error messages. Together with LocalizedError
we create error messages that contain a user readable description as well as some technical identifiers to easily identify specific error scenarios and give better support. See CodedError.swift
and CodedError.generated.swift
for the protocol and the autogenerated implementations of it.
O.Source_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_5 | Abbruch des Zugriffs auf sensible Daten bei Exceptions. | Bei Ausnahmen im Programmablauf (Exceptions) SOLL die Anwendung Zugriffe auf sensible Daten abbrechen und diese im Speicher sicher löschen. | Der Evaluator prüft den Zugriff auf sensible Daten bei Ausnahmen im Programmablauf. Jeglicher identifizierte Zugriff muss in der Risikobewertung betrachtet werden. | EXAMINE |
Implementation
As exceptions and errors are kind of the same construct in swift, this aspect is hard to answer. If a server responds with 401/403 we delete tokens or other security measures, because they are no longer valid anyways. While logging in via biometrics we create temporary data containers for the user certificate and key identifier, that are deleted if the process is not completed properly and kept if the process completes.
../Sources/IDP/IDPInterceptor.swift:72
invalidate/delete unauthorized token
// [REQ:gemSpec_eRp_FdV:A_20167-02#5] invalidate/delete unauthorized token
// [REQ:BSI-eRp-ePA:O.Source_5#2] invalidate/delete unauthorized token
self.session.invalidateAccessToken()
../Sources/IDP/DefaultIDPSession.swift:107
Invalidation means deleting the token
// [REQ:BSI-eRp-ePA:O.Source_5#3] Invalidation means deleting the token
storage.set(token: nil)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:61
Creation of the pairing session
// [REQ:BSI-eRp-ePA:O.Source_5#4] Creation of the pairing session
pairingSession = try sessionProvider.signatureProvider(for: profileID).createPairingSession()
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:77
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:130
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:146
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
O.Source_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_6 | Nutzung von sicheren Funktionsalternativen beim Zugriff auf Speichersegmente. | Bei Programmumgebungen mit manueller Speicherverwaltung (d.h., die Anwendung kann selbst exakt festlegen, wann und wo Speicher gelesen und beschrieben wird) MUSS die Anwendung für lesende und schreibende Zugriffe auf Speichersegmente auf sichere Funktionsalternativen (z. B. printf_s statt printf) zurückgreifen. | Der Evaluator prüft durch Quelltextanalyse, ob die Anwendung auf unsichere Funktionen zum Zugriff auf den Speicher zurückgreift. Die Prüfung umfasst sämtlichen vom Hersteller implementierten Quelltext. Externe Drittanbieter-Software wird in den O.TrdP Testcharakteristiken behandelt. | EXAMINE |
Implementation
Swift uses Automatic Reference Counting that does not require active memory management. Raw memory access is possible but only used for swift-OpenSSL dependency that wraps the c library.
O.Source_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_7 | Sicheres Löschen von sensiblen Daten nach ihrer Verarbeitung. | Die Anwendung MUSS sicherstellen, dass alle sensiblen Daten unverzüglich nach der Erfüllung ihres Verarbeitungszwecks sicher gelöscht werden. | Der Evaluator prüft durch Quelltextanalyse und praktische Tests, ob alle sensiblen Daten, welche nicht durch O.Data_2 geschützt sind, unverzüglich nach ihrer Verarbeitung sicher gelöscht werden. „Sicheres Löschen“ erfordert ein Überschreiben der Daten im Speicher. Hier ist auch auf eventuelle Kopien der Daten zu achten. Dies beinhaltet bei Programmiersprachen ohne manuelle Speicherverwaltung unter anderem das Ersetzen von Strings durch Byte-Arrays. | EXAMINE |
Implementation
All sensitive data is handled via value types. After usage the swift runtime handles deletion of the in memory representation. There is no method known to securely overwrite value types. Security is ensured by operating system and process boundaries. Secure enclave encryption keys can never leave the secure enclave by design.
../Sources/eRpApp/Session/KeychainStorage.swift:22
Implementation of data storage that is persisted via keychain
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
O.Source_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_8 | Vollständige Entfernung von unterstützenden Entwicklungsoptionen und Debugmechanismen in der Produktiv-Version. | Alle Optionen zur Unterstützung der Entwicklung (z. B. Entwickler-URLs, Testmethoden, Überreste von Debugmechanismen etc.) MÜSSEN in der Produktiv-Version vollständig entfernt sein. | Der Evaluator überprüft die produktive Anwendung auf Rückstände von Optionen zur Unterstützung der Entwicklung sowie Rückstände von Zeichenketten, Debugmechanismen und Debuginformationen. | EXAMINE |
Implementation
We use swift macros to remove development code. Configuration of server Environments is done within AppConfiguration.swift
. A debug menu is available within settings, rooted within SettingsView.swift
. UI-Test Scenarios are placed within the application, but exclude for production builds.
../Sources/eRpApp/Screens/Settings/SettingsView.swift:21
Debug menu is only visible on debug builds
// [REQ:BSI-eRp-ePA:O.Source_8#3] Debug menu is only visible on debug builds
#if ENABLE_DEBUG_VIEW
../Sources/eRpApp/Screens/Settings/SettingsView.swift:187
DebugSectionView is only available on debug builds
// [REQ:BSI-eRp-ePA:O.Source_8#4] DebugSectionView is only available on debug builds
private struct DebugSectionView: View {
../Sources/eRpApp/Screens/DebugView/DebugView.swift:14
DebugView is only available on debug builds
// [REQ:BSI-eRp-ePA:O.Source_8#5] DebugView is only available on debug builds
struct DebugView: View {
O.Source_9
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_9 | Aktivierung von modernen Sicherheitsmechanismen der Entwicklungsumgebung. | Für den Bau der Anwendung SOLLEN moderne Sicherheitsmechanismen, wie beispielsweise Obfuskation und Stack-Protection aktiviert werden. | Der Evaluator prüft, ob auf moderne Sicherheitsmechanismen der Entwicklungsumgebungen zurückgegriffen wurde. Sollten entsprechende Sicherheitsmechanismen nicht umgesetzt werden können, muss dies in der Risikobewertung betrachtet werden. | CHECK |
Implementation
We use common defaults for all compiler security related settings. See Xcode build configuration for eRpApp Target using current Xcode for actual settings.
O.Source_10
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.Source_10 | Verwendung von Werkzeugen zur statischen Codeanalyse. | Für die Entwicklung der Anwendung SOLLEN Werkzeuge zur statischen Codeanalyse eingesetzt werden. | Der Evaluator prüft durch Quelltextanalyse und Befragung des Herstellers, ob bei der Entwicklung Werkzeuge zur statischen Codeanalyse eingesetzt wurden. Wurden keine Werkzeuge zur statischen Codeanalyse verwendet, muss dies in der Risikobewertung betrachtet werden. | CHECK |
Implementation
We use an external SAST and SCA tool that is run at least on every release build. See Jenkinsfile_SAST
for technical details. There is additional integration into our merge-reqeuest tooling.
O.TrdP_1
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_1 | Abhängigkeiten durch Drittanbieter-Software. | Der Anbieter MUSS eine zentrale und vollständige Liste von Abhängigkeiten durch Drittanbieter-Software führen. | Der Hersteller stellt eine Liste der eingesetzten Drittanbieter-Software inkl. der verwendeten Versionen bereit. Der Evaluator prüft die bereitgestellte Liste auf Vollständigkeit. | CHECK |
Implementation
Dependencies are handled with SPM. A technical description of all dependencies can be found within dependencies.yml
. In the future, a generated SBOM will replace the Package.resolved
for this purpose.
O.TrdP_2
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_2 | Verwendung der aktuellen Version bei Drittanbieter- Software. | Drittanbieter-Software MUSS in der neusten oder der ihr vorhergehenden, für die Veröffentlichung vorgesehenen Version verwendet werden | Der Evaluator prüft die in O.TrdP_1 bereitgestellte Liste auf Aktualität der verwendeten Drittanbieter- Software-Versionen. Diese Abwägungen zu den gewählten Versionen werden in der Risikobewertung berücksichtigt. | CHECK |
Implementation
Dependencies are updated regulary by an organizational process. Any dependency security issues raised by automatic checking are handled immediately. A list of all compiled dependencies can be found within dependencies.yml
.
O.TrdP_3
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_3 | Herstellerprüfung Drittanbieter- Software auf Schwachstellen. | Drittanbieter-Software MUSS durch den Hersteller regelmäßig (durch Auswertung öffentlich verfügbarer Informationen oder durch statische/dynamische Testmethoden) auf Schwachstellen überprüft werden. Überreste von Optionen zur Unterstützung der Entwicklung (vgl. O.Source_8) sind hierbei als Schwachstelle zu werten. Der Hersteller MUSS für alle öffentlich bekannten Schwachstellen analysieren, inwieweit die Schwachstelle die Sicherheit des Gesamtsystems beeinträchtigt. Software, bzw. Funktionen aus Drittanbieter- Software DARF bei bekannten Schwachstellen, die die Sicherheit des Gesamtsystems betreffen NICHT eingesetzt werden. | Der Hersteller stellt eine Übersicht der letzten Schwachstellenanalyse der eingesetzten Drittanbieter- Softwarebereit. Diese wird vom Evaluator geprüft und in der Risikobewertung berücksichtigt. Zusätzlich prüft der Evaluator, ob der Hersteller bei Auftreten von Schwachstellen eine Mitigationsstrategie im Rahmen einer angemessenen Grace-Period bereitstellt. | CHECK |
Implementation
SCA Scans are part of our release pipeline, see O.Source_10.
O.TrdP_4
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_4 | Sicherheitskonzept für zeitnahes Einspielen von Sicherheitsupdates für Drittanbieter-Software. | Sicherheitsupdates für Drittanbieter-Software MUSS zeitnah integriert und per Update dem Nutzer zur Verfügung gestellt werden. Der Hersteller MUSS ein Sicherheitskonzept vorlegen, das anhand der Kritikalität ausnutzbarer Schwachstellen die geduldete Weiternutzung für die Anwendung, bzw. das Hintergrundsystem festlegt. Nachdem die Übergangsfrist (Grace Period) abgelaufen ist, MUSS die Anwendung den Betrieb verweigern. | Der Evaluator prüft das Vorhandensein eines solchen Konzeptes. Eine inhaltliche Prüfung ist im Rahmen der TR nicht erforderlich. Zusätzlich prüft der Evaluator, ob der Hersteller eine Mitigationsstrategie bereitstellt. | CHECK |
Implementation
Library updates are done by a manual periodic process. If any security issues arise and no fix is expected to be provided, a manual fork of external libraries is implemented. In our documentation, we define a bug bar and a grace period depending on the criticality of the vulnerability. Our bug bar is set to “Low”, see scripts/sast
, lines including severity-threshold=low
.
O.TrdP_5
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_5 | Prüfung auf Vertrauenswürdigkeit der Quelle von Drittanbieter-Software. | Vor der Verwendung von Drittanbieter- Software MUSS deren Quelle auf Vertrauenswürdigkeit geprüft werden. | Der Evaluator prüft die Maßnahmen des Herstellers zur Verifikation der Vertrauenswürdigkeit von Drittanbietern. | CHECK |
Implementation
Actual dependencies can be found within eRp-App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
, containing pinned versions with corresponding hashes. Library updates always require manual interaction to update the *.resolved
files. We use very few providers of libraries and try to avoid any unnecessary dependency. Each providing party/dependency is evaluated by looking at GitHub metrics like open issues, stars and activity in general.
O.TrdP_6
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_6 | Keine Weitergabe von sensiblen Daten an Drittanbieter-Software. | Die Anwendung SOLL sensible Daten nicht an Drittanbieter-Software weitergeben. | Der Evaluator prüft durch eine Quelltextanalyse und praktische Tests, dass keine Weitergabe von sensiblen Daten an Drittanbieter- Software vorgenommen wird. Eine Ausnahme hierzu bietet die Weitergabe von Daten, die für den primären oder rechtmäßigen Zweck der Anwendung erforderlich ist (beispielsweise Drittanbieter- Software zur Transportverschlüsselung). Risiken, die aus einer Nichteinhaltung resultieren, sind in der Risikobewertung zu berücksichtigen. | EXAMINE |
Implementation
We do not share sensitive data with third parties. See data usages within O.Purp_8 and O.Arch_2.
O.TrdP_7
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_7 | Validierung eingehender Daten über Drittanbieter-Software. | Über Drittanbieter-Software eingehende Daten MÜSSEN validiert werden. | Der Evaluator prüft, ob eingehende Daten über Drittanbieter-Software gemäß O.Source_1 behandelt werden und Sicherheitsfunktionen gemäß O.Arch_5 vorhanden sind. | CHECK |
Implementation
See O.Source_1 and O.Arch_5.
O.TrdP_8
Original Requirement
Prüfaspekt | Kurzfassung des Prüfaspekts | Prüfaspekt | Anmerkungen für den Prüfer | Prüftiefe |
---|---|---|---|---|
O.TrdP_8 | Prüfung der Wartung von verwendeter Drittanbieter- Software. | Drittanbieter-Software, die nicht mehr gewartet wird, DARF NICHT verwendet werden. | Der Evaluator prüft, ob die verwendete Drittanbieter-Software vom Hersteller aktiv gepflegt wird. Eine Software gilt als nicht mehr gewartet, sofern sicherheitskritische Verwundbarkeiten bekannt sind, jedoch nicht innerhalb einer angemessenen Frist repariert worden sind. | CHECK |
Implementation
As most libraries are source code dependencies, these scans are part of SAST Scanning. Libraries that are not source code dependencies are the precompiled OpenSSL and OpenHealthCardKit (own library but different repository). All third party libraries are mirrored into internal repositories. If necessary we fork libraries to apply fixes.
gemSpec_FD_eRp
A_19145
Original Requirement
A_19145 - E-Rezept-Fachdienst - Statusprüfung Apotheker löscht Rezept
Der E-Rezept-Fachdienst MUSS das Löschen eines E-Rezepts über den mittels der <id> adressierten /Task/<id>/$abort verhindern und die Operation mit dem HTTP-Fehlercode 403 abweisen, wenn der Status des adressierten Tasks gleich “in-progress” ist und die Rolle des aufrufenden Nutzers einer der folgenden Rollen entspricht:
- oid_versicherter
- oid_arzt
- oid_zahnarzt
- oid_praxis_arzt
- oid_zahnarztpraxis
- oid_praxis_psychotherapeut
- oid_krankenhaus
Implementation
../Sources/eRpApp/Screens/Main/PrescriptionList/Model/Prescription.swift:220
prevent deletion while task is in progress
// [REQ:gemSpec_FD_eRp:A_19145] prevent deletion while task is in progress
return erxTask.status != .inProgress
A_21267
Original Requirement
Implementation
../Sources/eRpApp/Screens/Main/PrescriptionList/Model/Prescription.swift:30
direct assignment
// [REQ:gemSpec_FD_eRp:A_21267] direct assignment
var type: PrescriptionType = .regular
A_21360
Original Requirement
Implementation
../Sources/eRpApp/Screens/Main/PrescriptionList/Model/Prescription.swift:176
no redeem informations available for flowtype 169
// [REQ:gemSpec_FD_eRp:A_21360] no redeem informations available for flowtype 169
guard type != .directAssignment
A_22102
Original Requirement
Implementation
../Sources/eRpApp/Screens/Main/PrescriptionList/Model/Prescription.swift:212
prevent deletion of tasks with flowtype 169 while not completed
// [REQ:gemSpec_FD_eRp:A_22102] prevent deletion of tasks with flowtype 169 while not completed
guard type != .directAssignment
gemSpec_IDP_Dienst
A_21415
Original Requirement
A_21415 - Registrierungsfunktion des IdP-Dienstes: Datenformate und Syntax zur Kommunikation mit dem Authenticator-Modul
Die Registrierungsfunktion des IdP-Dienstes MUSS die folgenden Datentypen zur Kommunikation mit dem Authenticator-Modul verwenden:
- Device_Type
- Device_Information
- Pairing_Data
- Signed_Pairing_Data
- Registration_Data
- Encrypted_Registration_Data.
Implementation
Pairing_Data ../Sources/IDP/Models/PairingData.swift:12
/// Structure for registering a biometric key. See `SignedPairingData` for sigend representation.
/// [REQ:gemSpec_IDP_Dienst:A_21415:Pairing_Data]
public struct PairingData: Claims, Codable {
Registration_Data ../Sources/IDP/Models/RegistrationData.swift:13
/// Bundles data needed for creating and verifiying a pairing.
/// [REQ:gemSpec_IDP_Dienst:A_21415:Registration_Data]
/// [REQ:gemSpec_IDP_Frontend:A_21416] Data Structure
public struct RegistrationData: Claims, Codable {
Device_Information ../Sources/IDP/Models/RegistrationData.swift:39
/// [REQ:gemSpec_IDP_Dienst:A_21415:Device_Information]
public struct DeviceInformation: Codable {
Device_Type ../Sources/IDP/Models/RegistrationData.swift:56
/// [REQ:gemSpec_IDP_Dienst:A_21415:Device_Type]
/// [REQ:gemSpec_IDP_Frontend:A_21591]
public struct DeviceType: Codable {
Encrypted_Registration_Data ../Sources/IDP/Models/RegistrationData.swift:104
Returns JWE encrypted Registration_Data
/// [REQ:gemSpec_IDP_Dienst:A_21415:Encrypted_Registration_Data] Returns JWE encrypted Registration_Data
/// [REQ:gemSpec_IDP_Frontend:A_21416] Encryption
func encrypted(with publicKey: BrainpoolP256r1.KeyExchange.PublicKey,
Signed_Pairing_Data ../Sources/IDP/Models/SignedPairingData.swift:12
/// Signed (with eGK) version of `PairingData`.
/// [REQ:gemSpec_IDP_Dienst:A_21415:Signed_Pairing_Data]
public struct SignedPairingData {
A_21450
Original Requirement
A_21450 - Inspektions- und Deregistrierungsfunktion des IdP-Dienstes: Datenmodell und Syntax zur Kommunikation mit dem Authenticator-Modul
Die Inspektions- und Deregistrierungsfunktion des IdP-Dienstes MUSS die folgenden Datentypen zur Kommunikation mit dem Authenticator-Modul verwenden:
- Pairing_Entry
- Pairing_Entries.
Implementation
Pairing_Entry ../Sources/IDP/Models/PairingEntry.swift:12
/// Represents stored data within the idp.
/// [REQ:gemSpec_IDP_Dienst:A_21450:Pairing_Entry]
public struct PairingEntry: Equatable, Codable {
gemSpec_IDP_Frontend
A_19908-01
Original Requirement
A_19908-01 - Authenticator-Modul: Prüfung der Signatur des “CHALLENGE_TOKEN”
Das Authenticator-Modul MUSS die Signatur des CHALLENGE_TOKEN gegen den aktuellen öffentlichen Schlüssel des Authorization-Endpunktes PUK_AUTH prüfen. Liegt dem Authenticator-Modul der öffentliche Schlüssel des Authorization-Endpunktes noch nicht vor, MUSS es diesen vom Authorization Server gemäß den Angaben der Adresse PUK_URI_AUTH im Discovery Document abrufen. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:634
Signature check
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_IDP_Frontend:A_19908-01] Signature check
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let verified = try? challenge.challenge.verify(with: document.authentication.cert),
A_19937
Original Requirement
A_19937 - Fehlermeldungen des Token-Endpunktes Anzeige
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, in der Lage sein, die vom Token-Endpunkt übertragenen Fehlermeldungen anzuzeigen. [<=]
Implementation
../Sources/eRpApp/Common/ErrorLocalization/IDPError+Localization.swift:23
Localized description of server errors
// [REQ:gemSpec_IDP_Frontend:A_19937#1,A_20605,A_20085] Localized description of server errors
case let .internal(error: error): return error.localizedDescription
../Sources/IDP/internal/RealIDPClient.swift:506
Decoding server errors
// [REQ:gemSpec_IDP_Frontend:A_19937#2,A_20605] Decoding server errors
private static func responseError(for body: Data) -> IDPError {
../Sources/IDP/Models/IDPError.swift:85
Error formatting
// [REQ:gemSpec_IDP_Frontend:A_19937#3,A_20605,A_20085] Error formatting
public var description: String {
A_19938-01
Original Requirement
A_19938-01 - Annahme des ID_TOKEN
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, das vom Token-Endpunkt ausgegebene ID_TOKEN als HTTP/1.1-Statusmeldung 200 verarbeiten und mittels “Token-Key” entschlüsseln.
Das Anwendungsfrontend MUSS das ID_TOKEN ablehnen, wenn dieses außerhalb der mit dem Token-Endpunkt etablierten TLS-Verbindung übertragen wird oder nicht mit dem vorher übermittelten “Token-Key” verschlüsselt war.
[<=]
Implementation
We support the smartcard idp.
../Sources/IDP/internal/RealIDPClient.swift:259
2xx HTTPCodes are treated as tokens
// [REQ:gemSpec_IDP_Frontend:A_19938-01#2|3] 2xx HTTPCodes are treated as tokens
if status.isSuccessful {
return try JSONDecoder().decode(TokenPayload.self, from: body)
} else {
../Sources/IDP/DefaultIDPSession.swift:204
Decrypt, fails if wrong aes key
// [REQ:gemSpec_IDP_Frontend:A_19938-01#3|3,A_20283-01|3] Decrypt, fails if wrong aes key
guard let decrypted = try? token.decrypted(with: self.cryptoBox.aesKey) else {
return Fail(error: IDPError.decryption).eraseToAnyPublisher()
}
../Sources/IDP/DefaultIDPSession.swift:227
Usage
idToken: decrypted.idToken, // [REQ:gemSpec_IDP_Frontend:A_19938-01#4] Usage
ssoToken: exchange.sso,
A_20068-01
Original Requirement
A_20068-01 - Authenticator-Modul: Prüfung Internet-Zertifikate
Das Authenticator-Modul MUSS das Internet-seitige Zertifikat des IdP-Dienstes prüfen. Hierfür MUSS das Authenticator-Modul sowohl eine Signaturprüfung als auch eine Prüfung der zeitlichen Gültigkeit durchführen. Falls diese Prüfung negativ ausfällt, MUSS es das Zertifikat als “ungültig” bewerten.
Das Authenticator-Modul MUSS das Zertifikat anhand der Signaturprüfung auf ein CA-Zertifikat einer CA, die die “CA/Browser Forum Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates” (https://cabforum.org/baseline-requirements-documents/) erfüllt, zurückführen können. Ansonsten MUSS es das Zertifikat als “ungültig” bewerten. [<=]
Implementation
: Implemented by not deactivating ATS within Info.plist
, path: NSAppTransportSecurity
.
A_20079
Original Requirement
A_20079 - Ausfall der Fehlermeldung des Token-Endpunktes
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, im Falle eines Timeout selbständig eine Fehlermeldung generieren, wenn eine Fehlermeldung durch den Token-Endpunkt ausbleibt. [<=]
Implementation
../Sources/IDP/internal/RealIDPClient.swift:267
Network timeouts will traverse the queue as HTTPError
s.
// [REQ:gemSpec_IDP_Frontend:A_20079] Network timeouts will traverse the queue as `HTTPError`s.
$0.asIDPError()
A_20085
Original Requirement
A_20085 - Fehlermeldungen des Anwendungsfrontends
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, leicht verständliche Fehlermeldungen ausgeben. Eine exakte Form der Fehlermeldung ist nicht vorgegeben [RFC6749 # section-1.7]. [<=]
Implementation
../Sources/IDP/Models/IDPError.swift:85
Error formatting
// [REQ:gemSpec_IDP_Frontend:A_19937#3,A_20605,A_20085] Error formatting
public var description: String {
../Sources/eRpApp/Common/ErrorLocalization/IDPError+Localization.swift:13
Error localization is not done yet, this is the place to localize
// [REQ:gemSpec_IDP_Frontend:A_20085] Error localization is not done yet, this is the place to localize
// accordingly.
switch self {
../Sources/eRpApp/Common/ErrorLocalization/IDPError+Localization.swift:23
Localized description of server errors
// [REQ:gemSpec_IDP_Frontend:A_19937#1,A_20605,A_20085] Localized description of server errors
case let .internal(error: error): return error.localizedDescription
A_20283-01
Original Requirement
A_20283-01 - Annahme des “ACCESS_TOKEN”
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, das vom Token-Endpunkt ausgegebene ACCESS_TOKEN in der HTTP/1.1-Statusmeldung 200 verarbeiten und mittels “Token-Key” entschlüsseln.
Das Anwendungsfrontend MUSS das ACCESS_TOKEN ablehnen, wenn dieses außerhalb der mit dem Token-Endpunkt etablierten TLS-Verbindung übertragen wird oder nicht mit dem vorher übermittelten “Token-Key” verschlüsselt war.
[<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:225
Usage
accessToken: decrypted.accessToken, // [REQ:gemSpec_IDP_Frontend:A_20283-01] Usage
expires: self.time().addingTimeInterval(TimeInterval(token.expiresIn)),
A_20309
Original Requirement
A_20309 - Bildung von “CODE_VERIFIER” und “CODE_CHALLENGE”
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, zur Laufzeit einen CODE_VERIFIER (Zufallswert) gemäß [RFC7636 # section-4.1] bilden. Der CODE_VERIFIER muss eine Entropie von mindestens 43 und maximal 128 Zeichen enthalten. Das Anwendungsfrontend MUSS über den CODE_VERIFIER einen HASH-Wert, die sogenannte CODE_CHALLENGE, gemäß [RFC7636 # section-4.2] bilden. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:612
generation and hashing for codeChallenge
// Generate a verifierCode
// [REQ:gemSpec_IDP_Frontend:A_20309] generation and hashing for codeChallenge
guard let verifierCode = try? self.cryptoBox.generateRandomVerifier(),
../Sources/IDP/internal/IDPCrypto.swift:68
verifierLength is 32 bytes, encoded to base64 this results in 43 chars
// [REQ:gemSpec_IDP_Frontend:A_20309] verifierLength is 32 bytes, encoded to base64 this results in 43 chars
// (32 * 4 / 3 = 42,6)
try randomGenerator(verifierLength).encodeBase64urlsafe().utf8string
A_20483
Original Requirement
A_20483 - Formulierung und Inhalte der Anfrage zum “AUTHORIZATION_CODE” für einen “ACCESS_TOKEN”
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, über das Authenticator-Modul den Antrag zum AUTHORIZATION_CODE für einen ACCESS_TOKEN via Private-Use URI Scheme Redirection [RFC8252 # section-7.1] beim Authorization-Endpunkt in Form eines HTTP/1.1 GET-Request stellen und dabei die folgenden Attribute anführen:
- response_type
- scope
- client_id
- redirect_uri
-
code_challenge (Hashwert des code_verifier) [RFC7636 # section-4.2]
- code_challenge_method HASH-Algorithmus (S256) [RFC7636 # section-4.3]
Implementation
../Sources/IDP/DefaultIDPSession.swift:620
Requesting the challange for the session
// [REQ:gemSpec_IDP_Frontend:A_20483#2|8] Requesting the challange for the session
return self.client.requestChallenge(
codeChallenge: codeChallenge,
method: .sha256,
state: state,
nonce: nonce,
using: document,
redirect: redirect
)
../Sources/IDP/internal/RealIDPClient.swift:100
Fill all the values into the GET Request
// [REQ:gemSpec_IDP_Frontend:A_20483#3|15] Fill all the values into the GET Request
let queryItems = [
// [REQ:gemSpec_IDP_Frontend:A_20603,A_20601,A_20601-01] Transfer
URLQueryItem(name: "client_id", value: clientConfig.clientId.urlPercentEscapedString()),
URLQueryItem(name: "code_challenge", value: codeChallenge.urlPercentEscapedString()),
URLQueryItem(name: "code_challenge_method", value: method.rawValue.urlPercentEscapedString()),
URLQueryItem(name: "state", value: state.urlPercentEscapedString()),
URLQueryItem(name: "scope", value: clientConfig.scopes.joined(separator: " ").urlPercentEscapedString()),
URLQueryItem(name: "response_type", value: "code"),
URLQueryItem(name: "nonce", value: nonce.urlPercentEscapedString()),
URLQueryItem(
// [REQ:gemSpec_IDP_Frontend:A_20740] transfer
name: "redirect_uri",
value: (redirect ?? clientConfig.redirectURI.absoluteString).urlPercentEscapedString()
),
]
A_20499
Original Requirement
Implementation
Not applicable as authenticator module is within FdV, not 3rd party app.
../Sources/eRpApp/Session/KeychainStorage.swift:247
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-1#3] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
set(can: nil)
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:40
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-01#2] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
// [REQ:BSI-eRp-ePA:O.Auth_14#4] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
storage.wipe()
A_20499-01
Original Requirement
A_20499-01 - Authenticator-Modul: aktives Löschen von “SSO_TOKEN”
Das Authenticator-Modul MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, SSO_TOKEN löschen, wenn der Anwender einen aktiven Logout durchführt. Das Authenticator-Modul MUSS dazu dem Anwender eine auslösende Funktionalität anbieten.
[<=]
Implementation
../Sources/eRpApp/Screens/Settings/Profiles/Edit/EditProfileDomain.swift:255
Call the SSO_TOKEN removal upon manual logout
// [REQ:gemSpec_IDP_Frontend:A_20499-01#1] Call the SSO_TOKEN removal upon manual logout
return .run { [profileId = state.profileId] _ in
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:40
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-01#2] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
// [REQ:BSI-eRp-ePA:O.Auth_14#4] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
storage.wipe()
A_20499-1
Original Requirement
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:247
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-1#3] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
set(can: nil)
A_20512
Original Requirement
A_20512 - Regelmäßiges Einlesen des Discovery Document
Das Anwendungsfrontend MUSS das Discovery Document [RFC8414] löschen, wenn dieses 24 Stunden alt oder älter ist. Das Anwendungsfrontend MUSS das Discovery Document neu herunterladen, einlesen und auswerten und danach die darin aufgeführten URI zu den benötigten öffentlichen Schlüsseln (PUKs) und Diensten verwenden, wenn kein aktuelles Discovery Document vorliegt. [<=]
Implementation
../Sources/IDP/Models/DiscoveryDocument.swift:181
Validation by expiration date checking + maximum of 24h window
// [REQ:gemSpec_IDP_Frontend:A_20512#2|5] Validation by expiration date checking + maximum of 24h window
func isValid(on date: Date) -> Bool {
date <= expiresOn &&
date >= createdOn &&
date <= createdOn.addingTimeInterval(60 * 60 * 24)
}
../Sources/IDP/DefaultIDPSession.swift:278
Reset expired documents before loading a new one
// [REQ:gemSpec_IDP_Frontend:A_20512#3] Reset expired documents before loading a new one
self.storage.set(discovery: nil)
../Tests/IDPTests/DefaultIDPSessionTests.swift:122
Testing the implementation
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#10] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInitFailesWhenTrustStoreFailsValidation() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:147
Testing the implementation
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#11] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInitFailesWhenTrustStoreFailsValidation() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:172
Testing the implementation
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#12] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInitFailesWhenTrustStoreThrows() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:197
Testing the implementation
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#13] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInitFailesWhenTrustStoreThrows() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:222
Testing the implementation
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#14] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInit() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:246
Testing the implementation
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#15] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInit() {
A_20525
Original Requirement
A_20525 - Authenticator-Modul: Anzeige des “user_consent” und PIN-Abfrage
Das Authenticator-Modul MUSS im Zusammenhang mit der PIN-Abfrage für die Signatur des CHALLENGE_TOKEN durch die Smartcard im selben Dialog die Consent-Freigabe des user_consent durch den Nutzer einfordern, damit dieser durch die PIN-Eingabe seine Willenserklärung abgibt und der Verwendung seiner Daten in diesen Claims zustimmt. [<=]
Implementation
Not applicable as authenticator module is within FdV, not 3rd party app
Not applicable as authenticator module is within FdV. Consent is given by using the app.
A_20526-01
Original Requirement
A_20526-01 - Authenticator-Modul: Response auf das “CHALLENGE_TOKEN” des Authorization-Endpunktes
Das Authenticator-Modul MUSS das eingereichte CHALLENGE_TOKEN mittels JWS (JSON Web Signature) mit der Smartcard signieren, und das Authentifizierungszertifikat der verwendeten Smartcard als x5c Parameter einbetten. Dieses Objekt mittels JWE (JSON Web Encryption) mit dem öffentlichen Schlüssel des Authorization-Endpunktes PuK_IDP_ENC verschlüsseln und in Form eines HTTP-POST-Requests an den Authorization-Endpunkt senden.
[<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:153
Encryption with JWE
// [REQ:gemSpec_IDP_Frontend:A_20526-01] Encryption with JWE
guard let jwe = try? signedChallenge.encrypt(with: document.encryptionPublicKey,
../Sources/IDP/Models/IDPChallengeSession.swift:86
Embed certificate
// [REQ:gemSpec_IDP_Frontend:A_20526-01] Embed certificate
let header = JWT.Header(alg: alg, x5c: certificates, typ: "JWT", cty: "NJWT")
../Sources/IDP/internal/RealIDPClient.swift:147
Building and sending the request
// [REQ:gemSpec_IDP_Frontend:A_20526-01] Building and sending the request
var request = URLRequest(url: document.authentication.url, cachePolicy: .reloadIgnoringCacheData)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Profile.swift:76
sign and verify with idp
// [REQ:gemSpec_eRp_FdV:A_20172]
// [REQ:gemSpec_IDP_Frontend:A_20526-01] sign and verify with idp
func signChallengeWithNFCCard(
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Profile.swift:108
verify with idp
// [REQ:gemSpec_eRp_FdV:A_20172]
// [REQ:gemSpec_IDP_Frontend:A_20526-01] verify with idp
func verifyResultWithIDP(
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:268
sign
// [REQ:gemSpec_IDP_Frontend:A_20526-01] sign
// [REQ:gemSpec_IDP_Frontend:A_20700-07] sign
func sign(
A_20527
Original Requirement
A_20527 - Authenticator-Modul: Übertragung des “AUTHORIZATION_CODE” an das Anwendungsfrontend
Das Authenticator-Modul MUSS den vom Authorization-Endpunkt empfangenen AUTHORIZATION_CODE an das Anwendungsfrontend übertragen. [<=]
Implementation
Not directly applicable as authenticator module is within FdV, not 3rd party app. AUTHORIZATION_CODE will be used directly.
../Sources/IDP/DefaultIDPSession.swift:166
Returning the AUTHORIZATION_CODE
// [REQ:gemSpec_IDP_Frontend:A_20527] Returning the AUTHORIZATION_CODE
return Just(exchangeToken).setFailureType(to: IDPError.self).eraseToAnyPublisher()
A_20529-01
Original Requirement
A_20529-01 - Senden von “AUTHORIZATION_CODE” und “KEY_VERIFIER” an den Token-Endpunkt
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, den KEY_VERIFIER mittels JWE (JSON Web Encryption (JWE) [RFC7516 # section-3]) und PuK_IDP_ENC verschlüsseln und zusammen mit dem AUTHORIZATION_CODE TLS-gesichert als HTTP/1.1 POST Request an den Token-Endpunkt senden.
[<=]
Implementation
We support the smartcard idp.
../Sources/IDP/DefaultIDPSession.swift:184
Encrypting the KEY_VERIFIER
// [REQ:gemSpec_IDP_Frontend:A_20529-01#2|6] Encrypting the `KEY_VERIFIER`
// [REQ:gemSpec_IDP_Frontend:A_21323,A_21324#1|6] Crypto box contains `Token-Key`
guard let encryptedKeyVerifier = try? KeyVerifier(
with: self.cryptoBox.aesKey,
codeVerifier: challengeSession.verifierCode
).encrypted(with: document.encryptionPublicKey, using: self.cryptoBox) else {
return Fail(error: IDPError.encryption).eraseToAnyPublisher()
}
../Sources/IDP/DefaultIDPSession.swift:192
Sending encrypted KEY_VERIFIER
and AUTHORIZATION_CODE
.
// [REQ:gemSpec_IDP_Frontend:A_20529-01#3|7] Sending encrypted `KEY_VERIFIER` and `AUTHORIZATION_CODE`.
return self.client.exchange(
token: exchange,
verifier: challengeSession.verifierCode,
redirectURI: exchange.redirect,
encryptedKeyVerifier: encryptedKeyVerifier,
using: document
)
../Sources/IDP/internal/RealIDPClient.swift:243
Putting all parameters into the HTTP body
// [REQ:gemSpec_IDP_Frontend:A_20529-01#4|10] Putting all parameters into the HTTP body
let parameters = [
"key_verifier": keyVerifierJWEString,
"code": token.code,
"grant_type": "authorization_code",
// [REQ:gemSpec_IDP_Frontend:A_20740] transfer
"redirect_uri": redirectURI ?? clientConfig.redirectURI.absoluteString,
"code_verifier": verifier,
// [REQ:gemSpec_IDP_Frontend:A_20603] transfer
"client_id": clientConfig.clientId,
]
../Sources/IDP/internal/RealIDPClient.swift:256
Sending the Request with the default HTTPClient via TLS.
// [REQ:gemSpec_IDP_Frontend:A_20529-01#5] Sending the Request with the default HTTPClient via TLS.
return httpClient.send(request: request)
A_20600
Original Requirement
A_20600 - Authenticator-Modul: Annahme des “user_consent” und des “CHALLENGE_TOKEN”
Das Authenticator-Modul MUSS den user_consent und den CHALLENGE_TOKEN vom Authorization-Endpunkt des IDP-Dienstes entgegennehmen. [<=]
Implementation
../Sources/IDP/internal/RealIDPClient.swift:174
// [REQ:gemSpec_IDP_Frontend:A_20600]
return IDPExchangeToken(
../Sources/IDP/internal/RealIDPClient.swift:491
// [REQ:gemSpec_IDP_Frontend:A_20600]
return IDPExchangeToken(code: code,
A_20601
Original Requirement
A_20601 - Authenticator-Modul: Übergabe des Authorization-Request an den Authorization-Endpunkt
Das Authenticator-Modul MUSS den Authorization-Request, welchen dieses vom Anwendungsfrontend erhalten hat, an den Authorization-Server des IdP-Dienstes schicken. Der Authorization-Request MUSS folgende Parameter enthalten:
- “response_type”
- “scope”
- “client_id”
- “redirect_uri”
-
“code_challenge” (Hashwert des “code_verifier”) [RFC7636 # section-4.2]
- “code_challenge_method” HASH-Algorithmus (S256) [RFC7636 # section-4.3]
Implementation
../Sources/IDP/internal/RealIDPClient.swift:102
Transfer
// [REQ:gemSpec_IDP_Frontend:A_20603,A_20601,A_20601-01] Transfer
URLQueryItem(name: "client_id", value: clientConfig.clientId.urlPercentEscapedString()),
A_20601-01
Original Requirement
Implementation
../Sources/IDP/internal/RealIDPClient.swift:102
Transfer
// [REQ:gemSpec_IDP_Frontend:A_20603,A_20601,A_20601-01] Transfer
URLQueryItem(name: "client_id", value: clientConfig.clientId.urlPercentEscapedString()),
A_20602
Original Requirement
A_20602 - Einreichen des “ACCESS_TOKEN” beim Fachdienst
Das Anwendungsfrontend MUSS das ACCESS_TOKEN im Rahmen des entsprechenden fachlichen Aufrufs beim Fachdienst einreichen, um Zugang zu den angeforderten Daten zu erhalten. [<=]
Implementation
Authorization-Header setup of HTTP requests is done via interceptor pattern for every request.
../Sources/IDP/IDPInterceptor.swift:56
Setup Authorization-Header
.
// [REQ:gemSpec_IDP_Frontend:A_20602#2,A_21325#1] Setup `Authorization-Header`.
request.setValue("\(token.tokenType) \(token.accessToken)", forHTTPHeaderField: "Authorization")
A_20603
Original Requirement
Implementation
../Sources/IDP/internal/RealIDPClient.swift:102
Transfer
// [REQ:gemSpec_IDP_Frontend:A_20603,A_20601,A_20601-01] Transfer
URLQueryItem(name: "client_id", value: clientConfig.clientId.urlPercentEscapedString()),
../Sources/IDP/internal/RealIDPClient.swift:251
transfer
// [REQ:gemSpec_IDP_Frontend:A_20603] transfer
"client_id": clientConfig.clientId,
../Sources/eRpApp/AppConfiguration.swift:33
Actual ID
// [REQ:gemSpec_IDP_Frontend:A_20603] Actual ID
private static let defaultClientId: String = "eRezeptApp"
../Sources/eRpApp/AppConfiguration.swift:80
Actual ID
// clientId
// [REQ:gemSpec_IDP_Frontend:A_20603] Actual ID
let clientId: String = defaultClientId
A_20605
Original Requirement
A_20605 - Fehlermeldung des Token-Endpunktes Formatierung
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, den Inhalt der Fehlermeldungen sowie mögliche Hinweise zur Fehlervermeidung vom Token-Endpunkt übernehmen. [<=]
Implementation
../Sources/IDP/Models/IDPError.swift:85
Error formatting
// [REQ:gemSpec_IDP_Frontend:A_19937#3,A_20605,A_20085] Error formatting
public var description: String {
../Sources/IDP/internal/RealIDPClient.swift:506
Decoding server errors
// [REQ:gemSpec_IDP_Frontend:A_19937#2,A_20605] Decoding server errors
private static func responseError(for body: Data) -> IDPError {
../Sources/eRpApp/Common/ErrorLocalization/IDPError+Localization.swift:23
Localized description of server errors
// [REQ:gemSpec_IDP_Frontend:A_19937#1,A_20605,A_20085] Localized description of server errors
case let .internal(error: error): return error.localizedDescription
A_20606
Original Requirement
A_20606 - Anwendungsfrontend: Kommunikation über TLS-Verbindung
Das Anwendungsfrontend MUSS mit dem IDP-Dienst über TLS kommunizieren. [<=]
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application.
../Sources/HTTPClient/DefaultHTTPClient.swift:34
Setup of minimum TLS Version to use.
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
A_20607
Original Requirement
Implementation
no exceptions set in NSAppTransportSecurity, HTTP via TLS is enforced; OS will use system root certificates in combination with set pinned certificates. see also: Requirements for Connecting Using ATS
A_20608-01
Original Requirement
Implementation
: Implemented by not deactivating ATS within Info.plist
, path: NSAppTransportSecurity
.
A_20609
Original Requirement
A_20609 - Authenticator-Modul: Unzulässige TLS-Verbindungen ablehnen
Das Authenticator-Modul MUSS bei jedem Verbindungsaufbau den IDP-Dienst anhand seines TLS-Zertifikats authentifizieren und MUSS die Verbindung ablehnen, falls die Authentifizierung fehlschlägt. [<=]
Implementation
no exceptions set in NSAppTransportSecurity, HTTP via TLS is enforced; OS will use system root certificates in combination with set pinned certificates. see also: Requirements for Connecting Using ATS
: Implemented by not deactivating ATS within Info.plist
, path: NSAppTransportSecurity
.
A_20614
Original Requirement
A_20614 - Authenticator-Modul: Prüfung der Signatur des Discovery Document
Das Authenticator-Modul MUSS die Signatur des Discovery Document mathematisch prüfen und auf ein zeitlich gültiges C.FD.SIG-Zertifikat mit der Rollen-OID oid_idpd zurückführen können, welches von einer ihm bekannten Komponenten-PKI ausgestellt wurde. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:266
// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623,A_20614]
.validateOrNil(with: trustStoreSession, timeProvider: time)
A_20617-01
Original Requirement
A_20617-01 - Authenticator-Modul: Verpflichtende Zertifikatsprüfung
Das Authenticator-Modul MUSS aktiv verwendete Zertifikate (bspw. für den TLS-Verbindungsaufbau), welche auf Root-Zertifikaten aus der TSL basieren, gemäß “TUC_PKI_018” auf Integrität und Authentizität prüfen. Das Authenticator-Modul MUSS die von dem Zertifikat und den darin enthaltenen Attributen (bspw. öffentliche Schlüssel) abhängenden Arbeitsabläufe ablehnen, wenn die Prüfung kein positives Ergebnis (“gültig”) liefert. Das Authenticator-Modul MUSS alle öffentlichen Schlüssel, die es verwenden will, auf eine positiv verlaufene Zertifikatsprüfung zurückführen können. [<=]
Implementation
../Tests/IDPTests/DefaultIDPSessionTests.swift:244
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#15] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInit() {
../Sources/IDP/DefaultIDPSession.swift:299
// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623]
.validate(with: self.trustStoreSession, timeProvider: self.time)
../Sources/IDP/DefaultIDPSession.swift:696
/// Returns a Publisher that validates the input streams discoveryDocument against the given trustStoreSession. If
/// the validity cannot be verified, the publisher fails with an `IDPError.trustStore` error.
///
/// [REQ:gemSpec_IDP_Frontend:A_20617-01]
/// [REQ:gemSpec_IDP_Frontend:A_20623]
///
/// - Parameter trustStoreSession: `TrustStoreSession` that is used to check the validity and trust of the
/// discoveryDocument.
/// - Returns: An AnyPublisher of `DiscoveryDocument`and `IDPError`
func validate(with trustStoreSession: TrustStoreSession,
../Sources/IDP/DefaultIDPSession.swift:728
/// Returns a Publisher that validates the input streams discoveryDocument and returns nil if validity cannot be
/// checked. All Errors are caught and result in an empty discoveryDocument.
///
/// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623]
///
/// - Parameters:
/// - trustStoreSession: `TrustStoreSession` that is used to check the validity and trust of the disoveryDocument.
/// - time: Time provider to check the discovery document against.
/// - Returns: An AnyPublisher of `DiscoveryDocument`and `Never`.
func validateOrNil(with trustStoreSession: TrustStoreSession,
../Tests/IDPTests/DefaultIDPSessionTests.swift:120
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#10] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInitFailesWhenTrustStoreFailsValidation() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:145
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#11] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInitFailesWhenTrustStoreFailsValidation() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:170
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#12] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInitFailesWhenTrustStoreThrows() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:195
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#13] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInitFailesWhenTrustStoreThrows() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:220
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#14] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInit() {
../Sources/IDP/DefaultIDPSession.swift:266
// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623,A_20614]
.validateOrNil(with: trustStoreSession, timeProvider: time)
A_20618
Original Requirement
A_20618 - Authenticator-Modul: Unzulässige TLS-Verbindungen ablehnen
Das Authenticator-Modul MUSS bei jedem Verbindungsaufbau den IdP-Dienst anhand seines TLS-Zertifikats authentifizieren und MUSS die Verbindungen ablehnen, falls die Authentifizierung fehlschlägt. [<=]
Implementation
no exceptions set in NSAppTransportSecurity, HTTP via TLS is enforced; OS will use system root certificates in combination with set pinned certificates. see also: Requirements for Connecting Using ATS
: Implemented by not deactivating ATS within Info.plist
, path: NSAppTransportSecurity
.
A_20623
Original Requirement
A_20623 - Anwendungsfrontend: Prüfung der Signatur des Discovery Document
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, die Signatur des Discovery Document mathematisch prüfen und auf ein zeitlich gültiges C.FD.SIG-Zertifikat mit der Rollen-OID oid_idpd zurückführen können, welches rückführbar ist auf ein CA-Zertifikat aus einer authentischen, integren und zeitlich gültigen TSL. [<=]
Implementation
../Tests/IDPTests/DefaultIDPSessionTests.swift:245
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#15] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInit() {
../Sources/IDP/DefaultIDPSession.swift:299
// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623]
.validate(with: self.trustStoreSession, timeProvider: self.time)
../Sources/IDP/DefaultIDPSession.swift:697
/// Returns a Publisher that validates the input streams discoveryDocument against the given trustStoreSession. If
/// the validity cannot be verified, the publisher fails with an `IDPError.trustStore` error.
///
/// [REQ:gemSpec_IDP_Frontend:A_20617-01]
/// [REQ:gemSpec_IDP_Frontend:A_20623]
///
/// - Parameter trustStoreSession: `TrustStoreSession` that is used to check the validity and trust of the
/// discoveryDocument.
/// - Returns: An AnyPublisher of `DiscoveryDocument`and `IDPError`
func validate(with trustStoreSession: TrustStoreSession,
../Sources/IDP/DefaultIDPSession.swift:700
Validation call
// [REQ:gemSpec_IDP_Frontend:A_20623] Validation call
return trustStoreSession.validate(discoveryDocument: document)
../Sources/IDP/DefaultIDPSession.swift:728
/// Returns a Publisher that validates the input streams discoveryDocument and returns nil if validity cannot be
/// checked. All Errors are caught and result in an empty discoveryDocument.
///
/// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623]
///
/// - Parameters:
/// - trustStoreSession: `TrustStoreSession` that is used to check the validity and trust of the disoveryDocument.
/// - time: Time provider to check the discovery document against.
/// - Returns: An AnyPublisher of `DiscoveryDocument`and `Never`.
func validateOrNil(with trustStoreSession: TrustStoreSession,
../Sources/IDP/DefaultIDPSession.swift:758
Validation
/// Returns a publisher that checks a discoveryDocument against the trust store. The Stream contains an output
/// boolean for the plain check or an TrustStoreError in case the TrustStoreSession sub streams failed.
///
/// [REQ:gemSpec_IDP_Frontend:A_20623] Validation
///
/// - Parameter discoveryDocument: The DiscoveryDocument that needs to be checked.
/// - Returns: A publisher that contains an output with the check value or an failure if the check failed
/// due to an underlying error.
func validate(discoveryDocument: DiscoveryDocument) -> AnyPublisher<Bool, TrustStoreError> {
../Sources/TrustStore/X509TrustStore.swift:179
oid check
} else if eeCert.contains(oidBytes: .oidIdpd) { // [REQ:gemSpec_IDP_Frontend:A_20623,A_20625#4] oid check
return (vauCerts, idpCerts + [eeCert])
../Sources/TrustStore/X509TrustStore.swift:193
IDP oid
case oidErpVau // 1.2.276.0.76.4.258 == 0x06082A8214004C048202
// [REQ:gemSpec_IDP_Frontend:A_20623] IDP oid
case oidIdpd // 1.2.276.0.76.4.260 == 0x06082A8214004C048204
}
../Tests/IDPTests/DefaultIDPSessionTests.swift:121
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#10] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInitFailesWhenTrustStoreFailsValidation() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:146
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#11] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInitFailesWhenTrustStoreFailsValidation() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:171
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#12] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInitFailesWhenTrustStoreThrows() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:196
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#13] Testing the implementation
func testLoadDiscoveryDocumentFromRemoteOnInitFailesWhenTrustStoreThrows() {
../Tests/IDPTests/DefaultIDPSessionTests.swift:221
// [REQ:gemSpec_IDP_Frontend:A_20617-01]
// [REQ:gemSpec_IDP_Frontend:A_20623]
// [REQ:gemSpec_IDP_Frontend:A_20512#14] Testing the implementation
func testLoadDiscoveryDocumentFromStorageOnInit() {
../Sources/IDP/DefaultIDPSession.swift:266
// [REQ:gemSpec_IDP_Frontend:A_20617-01,A_20623,A_20614]
.validateOrNil(with: trustStoreSession, timeProvider: time)
A_20625
Original Requirement
A_20625 - Anwendungsfrontend: Prüfung der Signatur des ID_TOKEN
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, die Signatur des ID_TOKEN mathematisch prüfen und auf ein zeitlich gültiges C.FD.SIG-Zertifikat mit der Rollen-OID oid_idpd zurückführen können, welches rückführbar ist auf ein CA-Zertifikat aus einer authentischen, integren und zeitlich gültigen TSL. [<=]
Implementation
These checks are part of the DefaultIDPSession
as part for the response parsing. If they fail, an error will be thrown.
../Sources/IDP/DefaultIDPSession.swift:211
Validate ID_TOKEN
signature with C.FD.SIG
.
// [REQ:gemSpec_IDP_Frontend:A_20625#2|4] Validate `ID_TOKEN` signature with `C.FD.SIG`.
guard let jwt = try? JWT(from: decrypted.idToken),
(try? jwt.verify(with: document.signingCert)) ?? false else {
return Fail(error: IDPError.invalidSignature("ID_TOKEN")).eraseToAnyPublisher()
}
../Sources/IDP/DefaultIDPSession.swift:759
C.FD.SIG
-Certificate verification
// [REQ:gemSpec_IDP_Frontend:A_20625#3|4] `C.FD.SIG`-Certificate verification
.zip(validate(certificate: discoveryDocument.signingCert))
.map { isDiscKeyValid, isSigningCertValid -> Bool in
isDiscKeyValid && isSigningCertValid
}
../Sources/TrustStore/X509TrustStore.swift:179
oid check
} else if eeCert.contains(oidBytes: .oidIdpd) { // [REQ:gemSpec_IDP_Frontend:A_20623,A_20625#4] oid check
return (vauCerts, idpCerts + [eeCert])
A_20700-05
Original Requirement
Implementation
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:476
sign with C.CH.AUT
// [REQ:gemSpec_IDP_Frontend:A_20700-05,A_20700-07] sign with C.CH.AUT
let signedChallenge = try await idpChallengeSigner.sign(
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:522
sign with C.CH.AUT
// [REQ:gemSpec_IDP_Frontend:A_20700-05,A_20700-07] sign with C.CH.AUT
let signedChallenge = try await idpChallengeSigner.sign(
A_20700-07
Original Requirement
A_20700-07 - Authenticator-Modul: Signatur der “CHALLENGE”
Das Authenticator-Modul MUSS die vom Authorization-Endpunkt empfangene CHALLENGE_TOKEN mit dem Zertifikat C.CH.AUT aus der Smartcard des Nutzers signieren. Hierbei wird der über die CHALLENGE_TOKEN gebildete HASH-Wert zur Signatur überreicht (siehe Abschnitt in diesem Dokument).
Im Fall der Authentisierung mit einem alternativen Authentisierungsmittel signiert das Authenticator-Modul die folgenden Daten mithilfe des PrK_SE_AUT:
- das vom Authorization-Endpunkt bezogene CHALLENGE-TOKEN,
- das auf dem Gerät gespeicherte Authentifizierungszertifikat C.CH.AUT,
- den Key-Identifier für das Schlüsselpaar PrK_SE_AUT/PuK_SE_AUT,
- die aktuell erhobenen Geräteinformationen,
- die Art des vom Nutzer verwendeten, lokalen Authentisierungsmittels zur Freischaltung der Anwendung des Schlüssels PrK_SE_AUT.
Art | Authentication-Method-Reference (“amr”) |
---|---|
Biometrisch | [“mfa”,“hwk”,“generic-biometric”] |
PIN | [“mfa”,“hwk”,“kba”] |
Passwort | [“mfa”,“hwk”,“kba”] |
Muster | [“mfa”,“hwk”,“kba”] |
Implementation
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:127
Biometrics only, other modes currently not supported
// [REQ:gemSpec_IDP_Frontend:A_20700-07] Biometrics only, other modes currently not supported
amr: [
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:269
sign
// [REQ:gemSpec_IDP_Frontend:A_20526-01] sign
// [REQ:gemSpec_IDP_Frontend:A_20700-07] sign
func sign(
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:476
sign with C.CH.AUT
// [REQ:gemSpec_IDP_Frontend:A_20700-05,A_20700-07] sign with C.CH.AUT
let signedChallenge = try await idpChallengeSigner.sign(
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:522
sign with C.CH.AUT
// [REQ:gemSpec_IDP_Frontend:A_20700-05,A_20700-07] sign with C.CH.AUT
let signedChallenge = try await idpChallengeSigner.sign(
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:590
perform signature with OpenHealthCardKit
// [REQ:gemSpec_IDP_Frontend:A_20700-07] perform signature with OpenHealthCardKit
card.sign(data: message)
A_20740
Original Requirement
A_20740 - Bekanntgabe der Redirect-URI des Anwendungsfrontend
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, beim IdP-Dienst bei der Registrierung eine redirect_uri hinterlegen. [<=]
Implementation
../Sources/IDP/internal/RealIDPClient.swift:111
transfer
// [REQ:gemSpec_IDP_Frontend:A_20740] transfer
name: "redirect_uri",
../Sources/IDP/internal/RealIDPClient.swift:248
transfer
// [REQ:gemSpec_IDP_Frontend:A_20740] transfer
"redirect_uri": redirectURI ?? clientConfig.redirectURI.absoluteString,
../Sources/eRpApp/AppConfiguration.swift:82
Actual redirect uri
// [REQ:gemSpec_IDP_Frontend:A_20740] Actual redirect uri
let redirectUri = URL(string: "https://redirect.gematik.de/erezept")! // swiftlint:disable:this force_unwrapping
let extAuthRedirectUri = URL(
A_20741
Original Requirement
A_20741 - Speicherung des Downloadpunktes des Discovery Document im Anwendungsfrontend
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, den vom IdP-Dienst bei der Registrierung bekanntgegebenen Downloadpunkt des Discovery Document als konfigurierbaren Parameter speichern. [<=]
Implementation
Configuration within app-configuration.json
, organizational process as in A_20603
A_21322
Original Requirement
A_21322 - Authenticator-Modul: Sichere Speicherung des “SSO-TOKEN”
Das Authenticator-Modul MUSS empfangene SSO-Token gegen unberechtigten Zugriff schützen. [<=]
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:19
Storage implementation uses iOS Keychain
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
A_21323
Original Requirement
A_21323 - Erzeugung des “Token-Key”
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, vor dem Abrufen von ID_TOKEN und ACCESS_TOKEN einen zufälligen 256 Bit AES-Schlüssel (“Token-Key“) erzeugen. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:185
Crypto box contains Token-Key
// [REQ:gemSpec_IDP_Frontend:A_20529-01#2|6] Encrypting the `KEY_VERIFIER`
// [REQ:gemSpec_IDP_Frontend:A_21323,A_21324#1|6] Crypto box contains `Token-Key`
guard let encryptedKeyVerifier = try? KeyVerifier(
codeVerifier: challengeSession.verifierCode
).encrypted(with: document.encryptionPublicKey, using: self.cryptoBox) else {
return Fail(error: IDPError.encryption).eraseToAnyPublisher()
}
../Sources/IDP/internal/TokenPayload.swift:169
Encode into JSON object
// [REQ:gemSpec_IDP_Frontend:A_21323#2] Encode into JSON object
// [REQ:gemSpec_IDP_Frontend:A_21324#3] Encode into JSON object
guard let keyVerifierEncoded = try? KeyVerifier.jsonEncoder.encode(self) else {
../Sources/IDP/internal/IDPCrypto.swift:57
AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4389:1] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#3] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
// [REQ:gemSpec_IDP_Frontend:A_21323#4] AES key generation via CryptoKit
aesKey: SymmetricKey = SymmetricKey(size: SymmetricKeySize(bitCount: 256))
A_21324
Original Requirement
A_21324 - Erzeugen des "KEY_VERIFIER”
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, dem KEY_VERIFIER bilden, indem “Token-Key” und CODE_VERIFIER in einem JSON-Objekt kodiert werden.
[<=]
Implementation
Token-key and code-verifier are encoded into an JSON object.
../Sources/IDP/DefaultIDPSession.swift:185
Crypto box contains Token-Key
// [REQ:gemSpec_IDP_Frontend:A_20529-01#2|6] Encrypting the `KEY_VERIFIER`
// [REQ:gemSpec_IDP_Frontend:A_21323,A_21324#1|6] Crypto box contains `Token-Key`
guard let encryptedKeyVerifier = try? KeyVerifier(
codeVerifier: challengeSession.verifierCode
).encrypted(with: document.encryptionPublicKey, using: self.cryptoBox) else {
return Fail(error: IDPError.encryption).eraseToAnyPublisher()
}
../Sources/IDP/internal/TokenPayload.swift:140
Token-key and code-verifier are encoded into KeyVerifier.
// [REQ:gemSpec_IDP_Frontend:A_21324#2] Token-key and code-verifier are encoded into KeyVerifier.
public struct KeyVerifier: Codable {
../Sources/IDP/internal/TokenPayload.swift:170
Encode into JSON object
// [REQ:gemSpec_IDP_Frontend:A_21323#2] Encode into JSON object
// [REQ:gemSpec_IDP_Frontend:A_21324#3] Encode into JSON object
guard let keyVerifierEncoded = try? KeyVerifier.jsonEncoder.encode(self) else {
A_21325
Original Requirement
A_21325 - Verschlüsselte Übertragung zum Fachdienst
Das Anwendungsfrontend MUSS den entschlüsselten ACCESS_TOKEN, zusätzlich zur Übertragung mittels TLS, auf Anwendungsebene verschlüsselt zum Fachdienst übertragen. [<=]
Implementation
AccessToken is encyrpted for each network request to the Fachdienst via VAUClient module.
../Sources/IDP/IDPInterceptor.swift:56
Setup Authorization-Header
.
// [REQ:gemSpec_IDP_Frontend:A_20602#2,A_21325#1] Setup `Authorization-Header`.
request.setValue("\(token.tokenType) \(token.accessToken)", forHTTPHeaderField: "Authorization")
../Sources/VAUClient/internal/VAUCrypto.swift:86
Encryption of accessToken (here bearerToken)
// [REQ:gemSpec_IDP_Frontend:A_21325#2] Encryption of accessToken (here bearerToken)
func encrypt() throws -> Data {
../Sources/eRpApp/Session/StandardSessionContainer.swift:358
Interceptor order defines what is encrypted via VAU
// [REQ:gemSpec_IDP_Frontend:A_21325#2] Interceptor order defines what is encrypted via VAU
let interceptors: [Interceptor] = [
A_21326
Original Requirement
A_21326 - Löschung von “ACCESS_TOKEN”
Das Anwendungsfrontend MUSS ACCESS_TOKEN beim Beenden sowie nach Ablauf ihrer Gültigkeit sicher löschen. [<=]
Implementation
ACCESS_TOKEN information is managed by IDPToken structure. See O.Plat_12 regarding secure deletion.
../Sources/IDP/Models/IDPToken.swift:12
Structure holding ACCESS_TOKEN and ID_TOKEN information
/// IDPToken
///
/// [REQ:gemSpec_IDP_Frontend:A_21326#2,A_21327#2] Structure holding ACCESS_TOKEN and ID_TOKEN information
public struct IDPToken: Codable {
../Sources/IDP/DefaultIDPSession.swift:99
Triggered at every app start, profile change, pull to refresh
// [REQ:gemSpec_IDP_Frontend:A_21326#3,A_21327#3] Triggered at every app start, profile change, pull to refresh
autoRefreshedToken.map { token in
../Sources/IDP/DefaultIDPSession.swift:775
Triggered at every app start, profile change, pull to refresh
// [REQ:gemSpec_IDP_Frontend:A_21326#4,A_21327#4] Triggered at every app start, profile change, pull to refresh
func refreshIfExpired(session: DefaultIDPSession,
../Sources/IDP/DefaultIDPSession.swift:787
Either return a refreshed IDPToken
// [REQ:gemSpec_IDP_Frontend:A_21326#5,A_21327#5] Either return a refreshed IDPToken
// (or nil in case of error) to overwrite the current one
guard let session = session else {
A_21327
Original Requirement
A_21327 - Löschung von “ID_TOKEN”
Das Anwendungsfrontend MUSS ID_TOKEN beim Beenden sowie nach Ablauf ihrer Gültigkeit sicher löschen. [<=]
Implementation
ID_TOKEN information is managed by IDPToken structure. See O.Plat_12 regarding secure deletion.
../Sources/IDP/Models/IDPToken.swift:12
Structure holding ACCESS_TOKEN and ID_TOKEN information
/// IDPToken
///
/// [REQ:gemSpec_IDP_Frontend:A_21326#2,A_21327#2] Structure holding ACCESS_TOKEN and ID_TOKEN information
public struct IDPToken: Codable {
../Sources/IDP/DefaultIDPSession.swift:99
Triggered at every app start, profile change, pull to refresh
// [REQ:gemSpec_IDP_Frontend:A_21326#3,A_21327#3] Triggered at every app start, profile change, pull to refresh
autoRefreshedToken.map { token in
../Sources/IDP/DefaultIDPSession.swift:775
Triggered at every app start, profile change, pull to refresh
// [REQ:gemSpec_IDP_Frontend:A_21326#4,A_21327#4] Triggered at every app start, profile change, pull to refresh
func refreshIfExpired(session: DefaultIDPSession,
../Sources/IDP/DefaultIDPSession.swift:787
Either return a refreshed IDPToken
// [REQ:gemSpec_IDP_Frontend:A_21326#5,A_21327#5] Either return a refreshed IDPToken
// (or nil in case of error) to overwrite the current one
guard let session = session else {
A_21328
Original Requirement
A_21328 - Sichere Speicherung der Token
Das Anwendungsfrontend MUSS empfangene ID_TOKEN und ACCESS_TOKEN gegen unberechtigten Zugriff schützen. [<=]
Implementation
Keychain storage encrypts session tokens.
../Sources/eRpApp/Session/StandardSessionContainer.swift:90
Keychain storage encrypts session tokens
// [REQ:gemSpec_IDP_Frontend:A_21328#2] Keychain storage encrypts session tokens
// [REQ:gemSpec_eRp_FdV:A_20184] Keychain storage encrypts session/ssl tokens
storage: secureUserStore,
../Sources/eRpApp/Session/KeychainStorage.swift:124
KeychainStorage implementation
// [REQ:gemSpec_eRp_FdV:A_20184]
// [REQ:gemSpec_IDP_Frontend:A_21328#3] KeychainStorage implementation
let success: Bool
A_21414
Original Requirement
A_21414 - Authenticator-Modul: Umschlüsselung des “ACCESS_TOKEN” für Pairing-Endpunkt
Das Authenticator-Modul MUSS das zur Autorisierung und Authentifizierung des Nutzers verwendete ACCESS_TOKEN mit dem öffentlichen Schlüssel PuK_IDP_ENC aus dem Discovery Document verschlüsseln.
Dazu muss es vorher unter Verwendung des “Token-Key”, der dem Token-Endpunkt übermittelt wurde, entschlüsselt werden.
[<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:323
Encrypt ACCESS_TOKEN when requesting the pairing endpoint
// [REQ:gemSpec_IDP_Frontend:A_21414] Encrypt ACCESS_TOKEN when requesting the pairing endpoint
guard let tokenJWT = try? JWT(from: token.accessToken),
A_21416
Original Requirement
A_21416 - Authenticator-Modul: Einleiten der Registrierung
Das Authenticator-Modul MUSS Registrierungsdaten in Form eines “Registration_Data”-Objekts produzieren und diese mit dem PuK_IDP_ENC aus dem Discovery Document verschlüsseln. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:317
Encryption
/// [REQ:gemSpec_IDP_Frontend:A_21416] Encryption
guard let jwe = try? registrationData.encrypted(with: document.encryptionPublicKey,
../Sources/IDP/Models/RegistrationData.swift:14
Data Structure
/// Bundles data needed for creating and verifiying a pairing.
/// [REQ:gemSpec_IDP_Dienst:A_21415:Registration_Data]
/// [REQ:gemSpec_IDP_Frontend:A_21416] Data Structure
public struct RegistrationData: Claims, Codable {
../Sources/IDP/Models/RegistrationData.swift:105
Encryption
/// [REQ:gemSpec_IDP_Dienst:A_21415:Encrypted_Registration_Data] Returns JWE encrypted Registration_Data
/// [REQ:gemSpec_IDP_Frontend:A_21416] Encryption
func encrypted(with publicKey: BrainpoolP256r1.KeyExchange.PublicKey,
A_21431
Original Requirement
A_21431 - Authenticator-Modul: Übermittelung von Authentifizierungsdaten zur Verwendung von alternativen Authentisierungsmitteln
Das Authenticator-Modul MUSS die produzierte Signed_Authentication_Data-Struktur mit dem PuK_IDP_ENC aus dem Discovery Document verschlüsseln und an den Authorization-Endpunkt als Antwort auf die vom Authorization-Endpunkt empfangene Challenge übermitteln. Der Wert des Header-Claims exp der hierbei produzierten “Encrypted_Authentication_Data”-Struktur MUSS hierbei identisch mit dem gleichnamigen Claim aus den Body-Claims des empfangenen Challenge-Token belegt werden. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:397
Encryption
/// [REQ:gemSpec_IDP_Frontend:A_21431] Encryption
guard let jwe = try? signedChallenge.encrypted(with: document.encryptionPublicKey,
../Sources/IDP/Models/SignedAuthenticationData.swift:35
exp header
/// [REQ:gemSpec_IDP_Frontend:A_21431] exp header
expiry: originalChallenge.challenge.exp,
A_21443
Original Requirement
A_21443 - Inspektions- und Deregistrierungsfunktion des IdP-Dienstes: Verschlüsselung des ACCESS_TOKEN
Das zur Authentifizierung des Nutzers und Autorisierung des Authenticator-Moduls verwendete ACCESS_TOKEN MUSS vom Authenticator-Modul mit dem öffentlichen Schlüssel PuK_IDP_Enc aus dem Discovery Document verschlüsselt werden.
[<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:348
Encrypt ACCESS_TOKEN when requesting the unregister endpoint
// [REQ:gemSpec_IDP_Frontend:A_21443] Encrypt ACCESS_TOKEN when requesting the unregister endpoint
guard let tokenJWT = try? JWT(from: token.accessToken),
../Sources/IDP/DefaultIDPSession.swift:372
Encrypt ACCESS_TOKEN when requesting the list endpoint
// [REQ:gemSpec_IDP_Frontend:A_21443] Encrypt ACCESS_TOKEN when requesting the list endpoint
guard let tokenJWT = try? JWT(from: token.accessToken),
A_21574
Original Requirement
A_21574 - Warnhinweise an den Nutzer
Das Authenticator-Modul MUSS dem Nutzer Warnhinweise geben, dass die Sicherheit des Verfahrens bei der Verwendung von Folgendem beeinträchtigt werden kann:
- Geräten, bei denen ein sog. “Rooten” oder ein “Jailbreak” vollzogen wurde.
- Installationen, bei denen es sich um Simulationsumgebungen der eigentlichen Zielplattform handelt.
- Geräten, die gemeinschaftlich verwendet werden.
- Geräten, die einem Mobile-Device-Management unterliegen, z. B. bei Dienstgeräten im Rahmen von COPE (“Corporate Owned, Personally Enabled”)-Lösungen.
- Installationen innerhalb von Containerlösungen auf Mobilgeräten zur Abschottung von Unternehmensanwendungen im Rahmen von BYOD (“Bring-Your-Own-Device”)-Lösungen.
Implementation
../Sources/eRpApp/Screens/CardWall/Login/CardWallLoginOptionDomain.swift:101
Present user information
// [REQ:gemSpec_IDP_Frontend:A_21574] Present user information
return Effect.send(.presentSecurityWarning)
../Sources/eRpApp/Screens/CardWall/Login/CardWallLoginOptionView.swift:94
Actual view
// [REQ:gemSpec_IDP_Frontend:A_21574] Actual view
// [REQ:BSI-eRp-ePA:O.Resi_1#3] View containing information regarding the login options.
struct PrivacyWarningViewContainer: View {
A_21576
Original Requirement
A_21576 - Löschung bestehender alternativer Authentisierungsmittel
Sofern für das verwendete Gerät und Nutzer bereits ein alternatives Authentisierungsmittel registriert ist, MUSS das Authenticator-Modul den Nutzer zur Deregistrierung der Pairing-Daten auffordern. Der Nutzer MUSS jederzeit die Möglichkeit haben, ein von ihm registriertes alternatives Authentisierungsmittel zu erneuern. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:341
deletion call
// [REQ:gemSpec_IDP_Frontend:A_21576] deletion call
public func unregisterDevice(_ keyIdentifier: String, token: IDPToken) -> AnyPublisher<Bool, IDPError> {
A_21578
Original Requirement
A_21578 - Sicherstellung des Vorliegens einer geeigneten Umgebung zur Speicherung von biometrischen Referenzmerkmalen
Das Authenticator-Modul SOLL prüfen, ob biometrische Referenzmerkmale oder wissensbasierte Faktoren auf dem Gerät in einer gesicherten Umgebung gespeichert werden. Hierzu MÜSSEN über Betriebssystem-APIs bereitgestellte Informationen ausgewertet werden. [<=]
Implementation
iOS only allows Biometric access via secure enclave or higher order apis.
../Sources/IDP/PrivateKeyContainer.swift:145
Enforced via access attribute
// [REQ:gemSpec_IDP_Frontend:A_21578,A_21579,A_21580,A_21583] Enforced via access attribute
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
A_21579
Original Requirement
A_21579 - Sicherstellung des Vorliegens einer geeigneten Umgebung für Schlüsselerzeugung, Anwendung und Speicherung
Das Authenticator-Modul MUSS sicherstellen, dass die Erzeugung des Schlüsselpaares PrK_SE_AUT/PuK_SE_AUT, dessen Speicherung, Anwendung und die Löschung des PrK_SE_AUT ausschließlich durch eine gesonderte, vertrauenswürdige Ausführungsumgebung erfolgt, die
- den Zugriff auf den PrK_SE_AUT als Datenobjekt pauschal allen Anwendungen entzieht (hierbei eingeschlossen sind Geräte-Backups).
- die die Anwendung des Schlüssels auf Daten zum Zweck der Signaturbildung auf das Authenticator-Modul und denjenigen am Gerät authentifizierten Nutzer beschränkt, der den Schlüssel PrK_SE_AUT erzeugt hat.
Implementation
../Sources/IDP/PrivateKeyContainer.swift:145
Enforced via access attribute
// [REQ:gemSpec_IDP_Frontend:A_21578,A_21579,A_21580,A_21583] Enforced via access attribute
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
A_21580
Original Requirement
A_21580 - Ausschluss von Eigenimplementierungen zur Schlüsselverwaltung
Das Authenticator-Modul MUSS für die Schlüsselerzeugung des Schlüsselpaars PuK_SE_AUT/PrK_SE_AUT Mechanismen des Geräts verwenden. Es DARF kryptographische Schlüssel NICHT selbst erzeugen, innerhalb des ihm zur Verfügung stehenden Speicherbereichs speichern oder auf Daten anwenden. [<=]
Implementation
../Sources/IDP/PrivateKeyContainer.swift:145
Enforced via access attribute
// [REQ:gemSpec_IDP_Frontend:A_21578,A_21579,A_21580,A_21583] Enforced via access attribute
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
A_21581
Original Requirement
A_21581 - Verfügbarkeit von kryptographischen Algorithmen
Das Authenticator-Modul MUSS sicherstellen, dass die in der folgenden Tabelle genannten Algorithmen zur Anwendung des PrK_SE_AUT zur Verfügung stehen:
Schema | Algorithmus | Schlüssel |
---|---|---|
Signatur | ECDSA auf Basis der Kurve P-256 und SHA-256 | PrK_SE_AUT |
Implementation
../Sources/IDP/PrivateKeyContainer.swift:141
Algorithm selection
// [REQ:gemSpec_IDP_Frontend:A_21581,A_21589] Algorithm selection
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
A_21582
Original Requirement
A_21582 - Lokale Authentisierung des Nutzers vor Anwendung des PrK_SE_AUT zur Authentisierung
Das Authenticator-Modul MUSS dem Nutzer die Wahl einer lokal verfügbaren Authentisierungsmethode überlassen, die zur autorisierten Anwendung des PrK_SE_AUT verwendet wird, das Authenticator-Modul
- MUSS hierbei auf dem Gerät bereits unter dem Nutzeraccount registrierte Mittel anbieten. Der Nutzer MUSS hierbei eine Auswahl treffen können,
- MUSS dem Benutzer hierbei mindestens eine pauschale Gruppierung in biometrische oder wissensbasierte Faktoren anbieten. Zugelassen sind die in der folgenden Tabelle genannten Mittel,
- DARF den Nutzer zur Anlage solcher Mittel auffordern.
- auf Basis welcher der vom Nutzer gewählten Mittel die Anwendung des Schlüssels PrK_SE_AUT auf Daten durch den Nutzer autorisiert wird,
- dass die Anwendung des Schlüssels PrK_SE_AUT auf den zum Zeitpunkt der Erzeugung verwendeten Nutzeraccount beschränkt ist.
Art | Faktor | Zugelassen: |
---|---|---|
biometrisch | Finger | ja |
Stimme | ja | |
Gesicht | ja | |
Iris | ja | |
wissensbasiert | PIN | ja |
Passwort | ja | |
Muster | ja | |
Präsenz | Wischen | nein |
Kopplung mit einer Uhr | nein | |
Knopfdruck | nein | |
Körpersensoren | nein |
Implementation
../Sources/IDP/PrivateKeyContainer.swift:128
method selection
// [REQ:gemSpec_IDP_Frontend:A_21582] method selection
// [REQ:gemSpec_IDP_Frontend:A_21587] via `.privateKeyUsage`
[.privateKeyUsage,
A_21583
Original Requirement
A_21583 - Qualitative Anforderungen an lokale Authentisierungsmittel
Das Authenticator-Modul MUSS sicherherstellen, dass die von Gerät und Hardware realisierten Mechanismen zur biometrischen Authentisierung bzw. Authentifizierung von ausreichender Qualität sind. [<=]
Implementation
Secure Enclave is enforced with code attributes.
../Sources/IDP/PrivateKeyContainer.swift:145
Enforced via access attribute
// [REQ:gemSpec_IDP_Frontend:A_21578,A_21579,A_21580,A_21583] Enforced via access attribute
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
A_21584
Original Requirement
A_21584 - Verwendung von Geräte-eigenen Mechanismen zur Authentisierung des Nutzers
Das Authenticator-Modul MUSS sich zur Implementierung der Authentifizierungsverfahren zur autorisierten Anwendung des PrK_SE_AUT auf diejenigen Mechanismen beschränken, die durch die Kombination von Betriebssystem und Hardware zur Verfügung gestellt werden. Das Authenticator-Modul DARF hierbei ausschließlich die vom Betriebssystem zur Verfügung gestellte Information über eine erfolgreiche oder nicht-erfolgreiche Authentifizierung und deren Art verarbeiten. [<=]
Implementation
There is no API to allow or disallow an biometric authentication, iOS is handling the authorization process while using the private key for any cryptographic operation.
../Sources/IDP/PrivateKeyContainer.swift:236
private key usage triggers biometric unlock
// [REQ:gemSpec_IDP_Frontend:A_21584] private key usage triggers biometric unlock
guard let signature = SecKeyCreateSignature(privateKey,
A_21585
Original Requirement
A_21585 - Beschränkung der Nutzung des PrK_SE_AUT auf das Authenticator-Modul
Das Authenticator-Modul MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, die Parameter für die Erzeugung des Schlüsselpaars PrK_SE_AUT/PuK_SE_AUT so setzen, dass sichergestellt ist, dass der Schlüssel PrK_SE_AUT ausschließlich über das Authenticator-Modul auf Daten anwendbar ist. Eine App-übergreifende Nutzung MUSS ausgeschlossen werden. [<=]
Implementation
Default behavior for all apps when using private access group (https://developer.apple.com/documentation/security/keychain_services/keychain_items/sharing_access_to_keychain_items_among_a_collection_of_apps)
A_21586
Original Requirement
A_21586 - Löschung des PrK_SE_AUT als Reaktion auf Systemereignisse
Das Authenticator-Modul MUSS bei der Übergabe des Kommandos zur Schlüsselerzeugung an das Betriebssystem in den Parametern festlegen, dass bei folgenden Systemereignissen der private Schlüssel PrK_SE_AUT nicht mehr verwendbar ist:
- Löschung des lokalen Geräte-Accounts, innerhalb dessen der PrK_SE_AUT erzeugt wurde.
- Setzen von schwachen Authentifizierungsmethoden oder entfernen von Authentifizierungsmethoden des Geräte-Accounts.
- Reset des Gerätes oder Deinstallation von Betriebssystem-Updates.
- Re-Enrolment oder Löschung von biometrischen Referenzmerkmalen.
Implementation
iOS will delete all user related data after user-account reset. Key-Chain data is not being synced with iCloud since kSecAttrSynchronizable
is not applied
../Sources/IDP/PrivateKeyContainer.swift:125
prevents migration to other devices
// [REQ:gemSpec_IDP_Frontend:A_21586] prevents migration to other devices
// [REQ:BSI-eRp-ePA:O.Data_15#2] prevents migration to other devices
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
../Sources/IDP/PrivateKeyContainer.swift:132
invalidates biometry after changes
// [REQ:gemSpec_IDP_Frontend:A_21586] invalidates biometry after changes
// [REQ:BSI-eRp-ePA:O.Auth_5#2] Key invalidates on changes of registered
// biometric features
.biometryCurrentSet], &error) else {
A_21587
Original Requirement
A_21587 - Beschränkung des PrK_SE_AUT auf Signaturbildung
Das Authenticator-Modul MUSS die Parameter für die Erzeugung des Schlüsselpaars PrK_SE_AUT/PuK_SE_AUT so setzen, dass sichergestellt ist, dass der Schlüssel PrK_SE_AUT ausschließlich zum Zweck der Signaturbildung auf Daten angewendet werden kann. [<=]
Implementation
../Sources/IDP/PrivateKeyContainer.swift:129
via .privateKeyUsage
// [REQ:gemSpec_IDP_Frontend:A_21582] method selection
// [REQ:gemSpec_IDP_Frontend:A_21587] via `.privateKeyUsage`
[.privateKeyUsage,
A_21588
Original Requirement
A_21588 - Erzeugung eines Key-Identifiers für das Schlüsselpaar PrK_SE_AUT/PuK_SE_AUT gegenüber dem IdP-Dienst
Das Authenticator-Modul MUSS einen Key-Identifier zur Identifikation des Schlüsselpaars PrK_SE_AUT/PuK_SE_AUT gegenüber dem IdP-Dienst erzeugen. Der Key-Identifier MUSS so erzeugt werden, dass die Erzeugung ein und desselben Identifiers über verschiedene Geräte eines Nutzers mit hoher Wahrscheinlichkeit ausgeschlossen ist. Der Key-Identifier MUSS zufällig erzeugt werden. Er DARF NICHT aus Nutzer- oder Gerätedaten abgeleitet werden. Der zum IdP-Dienst übertragene Key-Identifier MUSS eine Länge von 32 Byte besitzen. Der Wert KANN zur Referenzierung des PrK_SE_AUT im lokalen Schlüsselspeicher verwendet werden. Der Key-Identifier selbst oder ein Datenobjekt, aus dem er abgeleitet werden kann, MUSS auf dem Endgerät gespeichert werden. Der Key-Identifier selbst oder das Datenobjekt MUSS gegen Löschung und anwendungsübergreifende Verwendung geschützt sein. [<=]
Implementation
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:13
key identfier generator, number of bytes 32
// [REQ:gemSpec_IDP_Frontend:A_21588] key identfier generator, number of bytes 32
keyIdentifierGenerator: @escaping (() throws -> Data) = { try generateSecureRandom(length: 32) },
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:36
Key generation
// [REQ:gemSpec_IDP_Frontend:A_21588] Key generation
let keyIdentifier = try keyIdentifierGenerator()
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:101
usage as base64 encoded string
// [REQ:gemSpec_IDP_Frontend:A_21588] usage as base64 encoded string
guard let someIdentifier = identifier,
A_21589
Original Requirement
A_21589 - Erzeugung des Schlüsselpaars PrK_SE_AUT/PuK_SE_AUT
Das Authenticator-Modul MUSS ein Schlüsselpaar PrK_SE_AUT/PuK_SE_AUT erzeugen. Das Schlüsselpaar MUSS für die Anwendung des Algorithmus ECDSA auf Basis der Kurve P-256 geeignet sein. Das Authenticator-Modul MUSS hierbei über die Betriebssystem-APIs die in Abschnitt [gemSpec_IDP_Frontend#Parameter für die Schlüsselerzeugung und Auswahl eines Schlüsselspeichers]
beschriebenen Parameter zur Durchsetzung der dort genannten Anforderungen und die Schlüssel innerhalb des dort identifizierten Schlüsselspeichers setzen. [<=]
Implementation
../Sources/IDP/PrivateKeyContainer.swift:141
Algorithm selection
// [REQ:gemSpec_IDP_Frontend:A_21581,A_21589] Algorithm selection
kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom,
../Sources/IDP/PrivateKeyContainer.swift:143
Key length
// [REQ:gemSpec_IDP_Frontend:A_21589] Key length
kSecAttrKeySizeInBits as String: 256,
A_21590
Original Requirement
A_21590 - Beschränkung der Nutzung des PrK_SE_AUT auf Authentisierung gegenüber dem IdP-Dienst
Das Authenticator-Modul MUSS, wenn es eine Authentifizierung über den Smartcard-IDP unterstützt, den Schlüssel PrK_SE_AUT ausschließlich zum Zweck der Authentifizierung gegenüber dem IdP-Dienst verwenden. Es darf dem Nutzer keine andere Option anbieten oder den Schlüssel anderweitig verwenden. [<=]
Implementation
References of SecureEnclaveSignatureProvider
is limited to registration and altVerify usage.
../Sources/IDP/PrivateKeyContainer.swift:18
This is the container to represent biometric keys. Usage is limited to
/// Represents a (SecureEnclave) private key, namely `PrK_SE_AUT`, secured by iOS Biometrics.
///
/// [REQ:gemSpec_IDP_Frontend:A_21590] This is the container to represent biometric keys. Usage is limited to
/// authorization purposes
/// [REQ:BSI-eRp-ePA:O.Cryp_7#2] Container for private key operations using secure enclave private keys
public struct PrivateKeyContainer {
A_21591
Original Requirement
A_21591 - Erhebung von Geräteinformationen
Das Authenticator-Modul MUSS die folgenden Informationen über das verwendete Gerät über Betriebssystem-APIs erheben:
- Name des Herstellers,
- Name des Produkts,
- Name des Modells,
- Name des Betriebssystems und
- Version des Betriebssystems.
Implementation
../Sources/IDP/Models/RegistrationData.swift:57
/// [REQ:gemSpec_IDP_Dienst:A_21415:Device_Type]
/// [REQ:gemSpec_IDP_Frontend:A_21591]
public struct DeviceType: Codable {
../Sources/IDP/UIDevice+Extension.swift:10
/// [REQ:gemSpec_IDP_Frontend:A_21591,A_21600]
func deviceInformation() -> RegistrationData.DeviceInformation {
../Sources/IDP/UIDevice+Extension.swift:43
/// [REQ:gemSpec_IDP_Frontend:A_21591,A_21600]
func deviceInformation() -> RegistrationData.DeviceInformation {
A_21595
Original Requirement
A_21595 - Lokale Speicherung des C.CH.AUT
Das Authenticator-Modul MUSS das Authentifizierungszertifikat C.CH.AUT nach erfolgreicher Registrierung für die Verwendung in weiteren Authentifizierungsvorgängen lokal auf dem Endgerät speichern. Die Speicherung MUSS so erfolgen, dass eine missbräuchliche Verwendung des Zertifikats durch andere Anwendungen in ausreichendem Maß verhindert wird. Das Authenticator-Modul DARF im Fall einer nicht erfolgreichen Registrierung das Authentifizierungszertifikat C.CH.AUT NICHT speichern. [<=]
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:231
Store within keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Store within keychain
success = try keychainHelper.setGenericPassword(keyIdentifier, for: idpBiometricKeyIdentifier)
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:51
Store pairing data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595,A_21595] Store pairing data
certificateStorage.set(certificate: certificate)
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:72
case deletion
// [REQ:gemSpec_IDP_Frontend:A_21595] case deletion
certificateStorage.set(certificate: nil)
../Sources/IDP/IDPStorage.swift:12
Storage Protocol
/// Interface to access an eGK Certificate that should be kept private
/// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Protocol
public protocol SecureEGKCertificateStorage {
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:76
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:129
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:145
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Session/KeychainStorage.swift:20
Storage Implementation
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
../Sources/eRpApp/Session/KeychainStorage.swift:204
Store within keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Store within keychain
_ = try? keychainHelper.setGenericPassword(derBytes, for: egkAuthCertIdentifier)
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:51
Store pairing data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595,A_21595] Store pairing data
certificateStorage.set(certificate: certificate)
A_21598
Original Requirement
A_21598 - Löschung von lokalen Daten bei Fehlschlag
Das Authenticator-Modul MUSS bei fehlschlagender Registrierung alle lokal erzeugten Daten (einschließlich der erzeugten kryptographischen Schlüssel) über die Betriebssystem-APIs des Geräts löschen. [<=]
Implementation
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:51
Store pairing data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595,A_21595] Store pairing data
certificateStorage.set(certificate: certificate)
../Sources/IDP/DefaultSecureEnclaveSignatureProvider.swift:69
Delete all stored keys/identifiers/certificate in case of an unsuccessful
// [REQ:gemSpec_IDP_Frontend:A_21598] Delete all stored keys/identifiers/certificate in case of an unsuccessful
// registration
public func abort(pairingSession: PairingSession) throws {
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:76
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:129
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Biometrics.swift:145
Failure will delete paring data
// [REQ:gemSpec_IDP_Frontend:A_21598,A_21595] Failure will delete paring data
// [REQ:BSI-eRp-ePA:O.Source_5#5] Failure will delete paring data
_ = try? sessionProvider.signatureProvider(for: profileID).abort(pairingSession: pairingSession)
A_21600
Original Requirement
A_21600 - Einholen von aktuellen Geräteinformationen
Das Authenticator-Modul MUSS aktuelle Geräteinformationen über die Betriebssystem-APIs einholen und dabei eine Device-Information-Struktur wie in [gemSpec_IDP_Dienst} Abschnitt C beschrieben konstruieren. [<=]
Implementation
../Sources/IDP/UIDevice+Extension.swift:10
/// [REQ:gemSpec_IDP_Frontend:A_21591,A_21600]
func deviceInformation() -> RegistrationData.DeviceInformation {
../Sources/IDP/UIDevice+Extension.swift:43
/// [REQ:gemSpec_IDP_Frontend:A_21591,A_21600]
func deviceInformation() -> RegistrationData.DeviceInformation {
A_21603
Original Requirement
A_21603 - Ermöglichung der Löschung von alternativen Authentisierungsmitteln und lokal gespeicherten Daten
Das Authenticator-Modul MUSS dem Nutzer die Möglichkeit geben, lokal gespeicherte Daten dauerhaft zu löschen und über Betriebssystem-APIs des Geräts eine Löschung des PrK_SE_AUT auszulösen. Die Löschung MUSS eventuell vorhandene SSO_TOKEN mit einbeziehen. [<=]
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:251
Certificate
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
set(certificate: nil)
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:42
Certificate
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-01#2] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
// [REQ:BSI-eRp-ePA:O.Auth_14#4] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
storage.wipe()
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:48
key identifier
// [REQ:gemSpec_IDP_Frontend:A_21603] key identifier
storage.set(keyIdentifier: nil)
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:55
PrK_SE_AUT/PuK_SE_AUT
// If deletion fails we cannot do anything
// [REQ:gemSpec_IDP_Frontend:A_21603] PrK_SE_AUT/PuK_SE_AUT
_ = try? PrivateKeyContainer.deleteExistingKey(for: identifier)
A_22294-01
Original Requirement
A_22294-01 - Ermöglichen der Nutzung von sektoralen Identity Providern zur Authentisierung
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, dem Nutzer die Option zur Verwendung von sektoralen Identity Providern zur Authentisierung ermöglichen. Hierzu müssen ihm die Namen “idp_name" der verfügbaren sektoralen Identity Provider, aus der zuvor heruntergeladenen Liste, in nachvollziehbarer Form auf der Benutzeroberfläche dargestellt und zur Auswahl angeboten werden. [<=]
Implementation
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationDomain.swift:90
Start login via gID
// [REQ:gemSpec_IDP_Frontend:A_22294-01] Start login via gID
// [REQ:BSI-eRp-ePA:O.Auth_4#9,O.Plat_10#2] Start login via gID
return .publisher(
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionDomain.swift:91
Select KK
// [REQ:BSI-eRp-ePA:O.Auth_4#6] Business logic of user selecting the insurance company
// [REQ:gemSpec_IDP_Frontend:A_22294-01] Select KK
state.selectedKK = entry
A_22295-01
Original Requirement
A_22295-01 - Anfrage zur Authentisierung bei einem sektoralen Identity Provider beim IDP-Dienst
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, bei der Auswahl eines sektoralen Identity Provider durch den Nutzer einen Authorization Request an den Third-Party Authorization Endpoint (idp_sek_2=false) oder den Federation Authorization Endpoint (idp_sek_2=true) des IDP-Dienstes senden. Der Authorization Request entspricht der in [gemSpec_IDP_Dienst#7.1] genannten Form, aber MUSS um einen weiteren Parameter idp_iss ergänzt werden, dessen Wert dem Identifikator entspricht, welcher zum vom Benutzer ausgewählten Namen (idp_name) gehört. Das Frontend muss sich den Wert idp_sek_2 zum Request speichern, um später die korrekte Zuordnung treffen zu können. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:452
Usage of kk_app_id
// [REQ:gemSpec_IDP_Frontend:A_22295-01] Usage of kk_app_id
let extAuth = IDPExtAuth(kkAppId: entry.identifier,
../Tests/IDPTests/DefaultIDPSessionTests.swift:986
Test
// [REQ:gemSpec_IDP_Frontend:A_22295-01] Test
// [REQ:gemSpec_IDP_Frontend:A_22299-01] Test
func testStartExtAuth() throws {
A_22296-01
Original Requirement
A_22296-01 - Einlesen und Prüfen der Liste der sektoralen Identity Provider
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, die Liste der bekannten alternativen Authentisierungsanwendungen unter der im Discovery Document des IDP-Dienstes unter "kk_app_list_uri” gefundenen Adresse beziehen und ihre Integrität prüfen.
Das Anwendungsfrontend MUSS die Signatur des unter “fed_idp_list_uri” heruntergeladenen JWS mathematisch prüfen und auf ein zeitlich gültiges C.FD.SIG-Zertifikat mit der Rollen-OID “oid_idpd” zurückführen, welches von einer dem Anwendungsfrontend bekannten CA der Komponenten-PKI ausgestellt wurde. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:421
Signature verification
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Signature verification
// [REQ:gemSpec_IDP_Frontend:A_23082#3] Signature verification
// [REQ:BSI-eRp-ePA:O.Resi_6#3] Discovery Document signature verification
guard try jwtContainer.verify(with: document.discKey) == true else {
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionDomain.swift:72
Load available apps
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Load available apps
// [REQ:gemSpec_IDP_Frontend:A_23082#2] Load available apps
return .publisher(
../Tests/IDPTests/DefaultIDPSessionTests.swift:953
Test
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Test
// [REQ:gemSpec_IDP_Frontend:A_23082#4] Test
func testLoadDirectoryKKAppsInvalidSignature() throws {
A_22299-01
Original Requirement
A_22299-01 - Weiterleitung des Authorization Request an einen sektoralen Identity Provider
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, den als Redirect erhaltenen Authorization Request des IDP-Dienstes an die in der target_url des redirect enthaltene URI weiterleiten und sich dabei den verwendeten state Parameter merken, um später erhaltene Antworten des sektoralen Identity Provider zuzuordnen. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:469
Remember State parameter for later verification
// [REQ:gemSpec_IDP_Frontend:A_22299-01] Remember State parameter for later verification
guard let components = URLComponents(url: redirectUrl, resolvingAgainstBaseURL: true),
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationDomain.swift:105
Follow redirect
// [REQ:gemSpec_IDP_Frontend:A_22299-01] Follow redirect
// [REQ:BSI-eRp-ePA:O.Plat_10#3] Follow redirect
guard environment.resourceHandler.canOpenURL(url) else {
../Tests/IDPTests/DefaultIDPSessionTests.swift:987
Test
// [REQ:gemSpec_IDP_Frontend:A_22295-01] Test
// [REQ:gemSpec_IDP_Frontend:A_22299-01] Test
func testStartExtAuth() throws {
A_22301-01
Original Requirement
A_22301-01 - Annahme des Authorization Code über App2App-Kommunikation
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, den Authorization Code AUTHORIZATION_CODE_IDP, den state Parameter sowie den optionalen Parameter kk_app_redirect_uri, welche mittels App2App-Kommunikation vom Authenticator-Modul des sektoralen Identity Provider übergeben werden, akzeptieren, wenn der state mit dem Wert einer kürzlich vom IDP-Dienst erhaltenen Anfrage übereinstimmt. [<=]
Implementation
../Sources/eRpApp/SceneDelegate.swift:227
If app needs reauthentication routing starts here.
// [REQ:gemSpec_IDP_Frontend:A_22301-01#2] If app needs reauthentication routing starts here.
self.routeTo(.universalLink(url))
../Sources/eRpApp/SceneDelegate.swift:260
If app is already started, routing starts here.
// [REQ:gemSpec_IDP_Frontend:A_22301-01#3] If app is already started, routing starts here.
routeTo(.universalLink(url))
../Sources/eRpApp/Screens/AppStartDomain.swift:224
App2App gID will trigger this case
// [REQ:gemSpec_IDP_Frontend:A_22301-01#4] App2App gID will trigger this case
case "/extauth":
../Sources/eRpApp/Screens/AppStartDomain.swift:234
set actual destination in main tab
// // [REQ:gemSpec_IDP_Frontend:A_22301-01#5] set actual destination in main tab
await send(.destination(.app(.main(action: .externalLogin(url)))))
../Sources/eRpApp/Screens/Main/MainDomain.swift:258
Redirect into ExtAuthPendingDomain
// [REQ:BSI-eRp-ePA:O.Source_1#7] redirect into correct domain
// [REQ:gemSpec_IDP_Frontend:A_22301-01#6|3] Redirect into ExtAuthPendingDomain
return .run { send in
}
case let .importTaskByUrl(url):
../Sources/eRpApp/Screens/Main/ExtAuth/ExtAuthPendingDomain.swift:157
Actual handling of the universal link, user feedback via dialogs e.g.
// [REQ:BSI-eRp-ePA:O.Source_1#8] Validate data by parsing url and only allowing predefined variables as String
// [REQ:gemSpec_IDP_Frontend:A_22301-01#7] Actual handling of the universal link, user feedback via dialogs e.g.
case let .externalLogin(url),
../Sources/eRpApp/Screens/Main/ExtAuth/ExtAuthPendingDomain.swift:169
Login part is handled by idpSesson
// [REQ:gemSpec_IDP_Frontend:A_22301-01#8|5] Login part is handled by idpSesson
environment.idpSession
.extAuthVerifyAndExchange(
url,
idTokenValidator: idTokenValidator.validate(idToken:)
)
../Sources/IDP/DefaultIDPSession.swift:490
Extract the components.
// [REQ:gemSpec_IDP_Frontend:A_22301-01#9|7] Extract the components.
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
let code = components.queryItemWithName("code")?.value,
let state = components.queryItemWithName("state")?.value else {
return Fail(
error: IDPError.internal(error: .extAuthVerifyAndExchangeMissingQueryItem)
).eraseToAnyPublisher()
}
../Sources/IDP/DefaultIDPSession.swift:501
Send authorization request
// [REQ:gemSpec_IDP_Frontend:A_22301-01#10] Send authorization request
return extAuthVerify(verify)
../Sources/IDP/DefaultIDPSession.swift:510
Check for existing challenge session
// [REQ:gemSpec_IDP_Frontend:A_22301-01#11] Check for existing challenge session
guard let challengeSession = extAuthRequestStorage.getExtAuthRequest(for: token.state) else {
../Sources/IDP/DefaultIDPSession.swift:477
The challenge session has been set here.
// [REQ:gemSpec_IDP_Frontend:A_22301-01#12] The challenge session has been set here.
self.extAuthRequestStorage.setExtAuthRequest(challengeSession, for: storageIdentifier)
../Tests/IDPTests/DefaultIDPSessionTests.swift:1088
Negative Test
// [REQ:gemSpec_IDP_Frontend:A_22301-01#20] Negative Test
func testExtAuthVerifyAndExchangeFailesWithoutReferenceStateGID() throws {
A_22302-01
Original Requirement
A_22302-01 - Weiterleitung des Authorization Code an den IDP-Dienst
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, den empfangenen Authorization Code AUTHORIZATION_CODE_IDP abhängig vom für den ausgehenden Request gespeicherten Parameter verarbeiten:
- Ist idp_sek_2=false sendet es den AUTHORIZATION_CODE_IDP, den state Parameter sowie den optionalen Parameter kk_app_redirect_uri als HTTP-POST an den im Discovery Document referenzierten Third-Party Authorization Endpoint des IDP-Dienstes.
- Ist idp_sek_2=true sendet es den AUTHORIZATION_CODE_IDP und den state Parameter als HTTP-POST an den im Discovery Document referenzierten Federation Authorization Endpoint des IDP-Dienstes.
Implementation
As of now idp_sek_2
can only be true, as the false
case is no longer allowed. Thus only the true
case is implemented in the following code places.
../Sources/IDP/internal/RealIDPClient.swift:461
Sending the required data as POST to the backend.
// [REQ:gemSpec_IDP_Frontend:A_22302-01#2] Sending the required data as POST to the backend.
func extAuthVerify(_ verify: IDPExtAuthVerify,
A_22313-01
Original Requirement
A_22313-01 - Absicherung des Aufrufs zu Authenticator-Modulen von sektoralen Identity Providern
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, für Aufrufe zu Authenticator-Modulen sektoraler Identity Provider die Verifikationsmechanismen des Betriebssystems verwenden. Die folgenden Parameter müssen gesetzt sein:
Android: Keine weiteren.
iOS: .universalLinksOnly:false [<=]
Implementation
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthConfirmationDomain.swift:111
Universal link options
// [REQ:gemSpec_IDP_Frontend:A_22313-01] Universal link options
environment.resourceHandler.open(url, options: [.universalLinksOnly: false]) { result in
A_23082
Original Requirement
A_23082 - Abruf und Anzeige der IDP Liste
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, sofern nicht anderweitig ein sektoraler Identity Provider zuvor gemerkt oder festgelegt wurde, die IDP-Liste vom Authorization-Server herunterladen, auf Integrität prüfen und (bei erfolgreicher Prüfung) dem Benutzer zur Auswahl anzeigen. [<=]
Implementation
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionDomain.swift:73
Load available apps
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Load available apps
// [REQ:gemSpec_IDP_Frontend:A_23082#2] Load available apps
return .publisher(
../Sources/IDP/DefaultIDPSession.swift:422
Signature verification
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Signature verification
// [REQ:gemSpec_IDP_Frontend:A_23082#3] Signature verification
// [REQ:BSI-eRp-ePA:O.Resi_6#3] Discovery Document signature verification
guard try jwtContainer.verify(with: document.discKey) == true else {
../Tests/IDPTests/DefaultIDPSessionTests.swift:954
Test
// [REQ:gemSpec_IDP_Frontend:A_22296-01] Test
// [REQ:gemSpec_IDP_Frontend:A_23082#4] Test
func testLoadDirectoryKKAppsInvalidSignature() throws {
../Sources/eRpApp/Screens/CardWall/ExtAuth/CardWallExtAuthSelectionView.swift:48
Display of KK apps
// [REQ:gemSpec_IDP_Frontend:A_23082#5] Display of KK apps
if !store.filteredKKList.apps.isEmpty {
gemSpec_IDP_Sek
A_22299
Original Requirement
Implementation
../Sources/eRpApp/Screens/CardWall/Introduction/CardWallIntroductionDomain.swift:190
Follow redirect
// [REQ:gemSpec_IDP_Sek:A_22299] Follow redirect
// [REQ:BSI-eRp-ePA:O.Plat_10#3] Follow redirect
guard resourceHandler.canOpenURL(url) else {
A_22313-01
Original Requirement
A_22313-01 - Absicherung des Aufrufs zu Authenticator-Modulen von sektoralen Identity Providern
Das Anwendungsfrontend MUSS, wenn es eine Authentifizierung über den sektoralen IDP unterstützt, für Aufrufe zu Authenticator-Modulen sektoraler Identity Provider die Verifikationsmechanismen des Betriebssystems verwenden. Die folgenden Parameter müssen gesetzt sein:
Android: Keine weiteren.
iOS: .universalLinksOnly:false [<=]
Implementation
../Sources/eRpApp/Screens/CardWall/Introduction/CardWallIntroductionDomain.swift:196
Remember State parameter for later verification
// [REQ:gemSpec_IDP_Sek:A_22313-01] Remember State parameter for later verification
resourceHandler.open(url, options: [:]) { result in
gemSpec_Krypt
A_17124
Original Requirement
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application, see also: Requirements for Connecting Using ATS
A_17205
Original Requirement
A_17205 - Signatur der TSL: Signieren und Prüfen (ECC-Migration)
Alle Produkttypen, die die TSL(ECC-RSA) signieren oder prüfen, MÜSSEN dafür das Signaturverfahren ECDSA [BSI-TR-03111] auf Basis der Domainparameter brainpoolP256r1 verwenden mit dem XMLDSig-Identifier „ http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256“ [XMLDSig]. Als Hashfunktion (Messagedigest) MUSS SHA-256 [FIPS-180-4] verwendet werden.
[<=]
Implementation
The app does not use the TSL. All TSL related parts are handled within the eRp-FD.
A_17207
Original Requirement
A_17207 - Signaturen binärer Daten (ECC-Migration)
Alle Produkttypen, die (nicht-XML-)Signaturen von Daten auf Basis eines ECC-Schlüssels erzeugen oder prüfen, MÜSSEN dafür das Signaturverfahren ECDSA [BSI-TR-03111] auf Basis der Domainparameter brainpoolP256r1 verwenden (vgl. [RFC-5753] und [RFC-6090]). Als Hashfunktion (Messagedigest) MÜSSEN sie SHA-256 [FIPS-180-4] verwenden.
[<=]
Implementation
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:605
Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
var alg: JWT.Algorithm? {
../Sources/IDP/DefaultIDPSession.swift:288
Only implemented for brainpoolP256r1
// Validate JWT/DiscoveryDocument signature
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02] Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4361-02] Assure that brainpoolP256r1 is used
// [REQ:BSI-eRp-ePA:O.Resi_6#4] Discovery Document signature verification
guard (try? fetchedDocument.backing.verify(with: fetchedDocument.discKey)) ?? false else {
../Sources/IDP/DefaultIDPSession.swift:633
Only implemented for brainpoolP256r1
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_IDP_Frontend:A_19908-01] Signature check
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let verified = try? challenge.challenge.verify(with: document.authentication.cert),
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:23
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02]
public func verify(signature raw: Data, message: Data) throws -> Bool {
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:33
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let key = brainpoolP256r1VerifyPublicKey() else {
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:472
Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
let alg: JWT.Algorithm = .bp256r1
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:517
Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let alg = autCertificateResponse.info.algorithm.alg
BrainpoolP256r1 parameter spec is used for creating/verifying key for signature usage; exception: Biometric use case uses secp256r1 (This is considered in its respective specification.)
A_17322
Original Requirement
A_17322 - TLS-Verbindungen nur zulässige Ciphersuiten und TLS-Versionen (ECC-Migration)
Alle Produkttypen, die Übertragungen mittels TLS durchführen, MÜSSEN sicherstellen, dass sie nur (durch andere Anforderungen) zugelassene TLS-Ciphersuiten bzw. TLS-Versionen anbieten bzw. verwenden.
[<=]
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application, see also: Requirements for Connecting Using ATS
A_17359
Original Requirement
A_17359 - Signaturen binärer Daten (Dokumente) (ECC-Migration)
Alle Produkttypen, die (nicht-XML-)Signaturen von Dokumenten auf Basis eines ECC-Schlüssels erzeugen oder prüfen, MÜSSEN dabei die Vorgaben aus A_17207 umsetzen und die Signatur nach [ETSI-CAdES] (interoperables Container-Format) bei der Erzeugung kodieren bzw. bei der Prüfung auswerten.
[<=]
Implementation
Not applicable, since there is no exchange of CAdES-encoded documents signed by a ECC key in our system. Generally the created signatures adhere to A_17207 if not stated otherwise in the respective specifications.
A_17775
Original Requirement
A_17775 - TLS-Verbindungen Reihenfolge Ciphersuiten (ECC-Migration)
Alle Produkttypen, die Übertragungen mittels TLS durchführen und in der Rolle TLS-Server agieren, SOLLEN die Reihenfolge der Ciphersuiten in der Liste “cipher_suites” aus dem TLS-ClientHello bei der Auswahl der Ciphersuite befolgen.
[<=]Implementation
We cannot interfere with cipher suite lists, see Requirements for Connecting Using ATS for actual order.
A_18464
Original Requirement
A_18464 - TLS-Verbindungen, nicht Version 1.1
Alle Produkttypen, die Übertragungen mittels TLS durchführen, DÜRFEN NICHT die TLS-Version 1.1 [RFC-4346] unterstützen. [<=]
Implementation
../Sources/HTTPClient/DefaultHTTPClient.swift:33
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
A_18467
Original Requirement
A_18467 - TLS-Verbindungen, Version 1.3
Alle Produkttypen, die Übertragungen mittels TLS durchführen, KÖNNEN die TLS-Version 1.3 [RFC-8446] unterstützen, falls sie
- dabei nur nach [BSI-TR-02102-2] empfohlene Verbindungskonfigurationen (Handshake-Modi, (EC)DH-Gruppen, Signaturverfahren, Ciphersuiten etc.) verwenden, und
- mindestens die Ciphersuite “TLS_AES_128_GCM_SHA256” dabei unterstützen.
Implementation
../Sources/HTTPClient/DefaultHTTPClient.swift:33
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
A_19215
Original Requirement
Implementation
We use https only, see DefaultHTTPClient.swift
. ATS forbids other connections.
A_20161-01
Original Requirement
A_20161-01 - E-Rezept-Client, Request-Erstellung
Ein E-Rezept-Client MUSS, falls ihm noch kein gültiges E-Rezept-VAU-Zertifikat vorliegt, ein solches nach den fachlichen Vorgaben von A_20160-* beziehen (/VAUCertificate).
Ein E-Rezept-Client MUSS sicherstellen, dass gültige Sperrinformation (OCSP-Response mit Sperrstatus “good”) für das Zertifikat vorliegen, die maximal 12 Stunden alt sind. Liegen diese nicht vor so MUSS der Client ein Verbindungsaufbau auf VAU-Protokoll-Ebene ablehnen/unterbinden.
Ein E-Rezept-Client MUSS bei der Request-Erstellung folgende Schritte durchführen.
- Er erzeugt einen HTTP-Request, den er an die VAU senden möchte, als Datenstruktur (vgl. Beispiele nach dieser Anforderung).
- Er erzeugt zufällig eine 128-Bit lange hexadezimalkodierte Request-ID (also 32 Zeichen, Buchstaben a-f kleingeschrieben).
- Er erzeugt zufällig einen 128-Bit AES-Schlüssel (im Weiteren auch Antwortschlüssel genannt), den er hexadezimal kodiert (also 32 Zeichen, Buchstaben a-f kleingeschrieben).
- Er MUSS die Request-ID und den AES-Schlüssel für jeden HTTP-Request an die VAU zufällig neu erzeugen.
- Er erzeugt die folgende Zeichenkette p mit
p=“1” + “ ” + JWT-Authentisierungstoken + “ ” + Request-ID + “ ” + AES-Schlüssel + “ ” + Datenstruktur aus Schritt 1. - Die Zeichenkette p MUSS mittels des ECIES-Verfahrens [SEC1-2009] und mit folgenden Vorgaben verschlüsselt werden:
-
- Er MUSS ein ephemeres ECDH-Schlüsselpaar erzeugen und mit diesem und dem VAU-Schlüssel aus A_20160-* ein ECDH gemäß [NIST-800-56-A] durchgeführen. Das somit erzeugte gemeinsame Geheimnis ist Grundlage für die folgende Schlüsselableitung.
- Als Schlüsselableitungsfunktion MUSS er die HKDF nach [RFC-5869] auf Basis von SHA-256 verwenden.
- Dabei MUSS er den Ableitungsvektor “ecies-vau-transport” verwenden, d. h. in der Fomulierung von [RFC-5869] info=“ecies-vau-transport” .
- Er MUSS mit dieser Schlüsselableitung einen AES-128-Bit Content-Encryption-Key für die Verwendung von AES/GCM ableiten.
- Er MUSS für Verschlüsselung mittels AES/GCM einen 96 Bit langen IV zufällig erzeugen.
- Er MUSS mit dem CEK und dem IV mittels AES/GCM p verschlüsseln, wobei dabei ein 128 Bit langer Authentication-Tag zu verwenden ist.
- Er MUSS das Ergebnis wie folgt kodieren: chr(0x01) || <32 Byte X-Koordinate von öffentlichen Schlüssel aus (a) > || <32 Byte Y-Koordinate> || <12 Byte IV> || <AES-GCM-Chiffrat> || <16 Byte AuthenticationTag> (vgl. auch Tab_KRYPT_ERP und folgende die Beispielverschlüsselung).
Die Koordinaten sind (wie üblich) vorne mit chr(0) zu padden solange bis sie eine Kodierungslänge von 32 Byte erreichen.
- Er erzeugt einen HTTPS-Request an den FD mit der POST-Methode und dem Pfad /VAU/<Nutzerpseudonym>[/optional-beliebiger-weiterer-URL-Pfadteil] mit dem Content-Type ‘application/octet-stream’ und sendet diesen an die Webschnittstelle des FD.
“Nutzerpseudonym” MUSS eine ggf. aus der vorherigen (zeitlich letzten) Antwort des FD dem Nutzer übergebene URL-sichere Zeichenkette sein (bspw. ein 128 Byte langer Hexadezimal-Kode).
Falls dem Client kein Nutzerpseudonym vorliegt so MUSS er “0” als Nutzerpseudonym verwenden.
Implementation
../Sources/VAUClient/internal/VAUCrypto.swift:26
Encryption interface
/// Perform encryption of the data that the implementing instance has been initialized with
/// in order to send it to a VAU service endpoint. See: gemSpec_Krypt A_20161-01
///
/// [REQ:gemSpec_Krypt:A_20161-01#2] Encryption interface
///
/// - Returns: Encrypted HTTPRequest as specified to be sent to a VAU endpoint
/// - Throws: `VAUError` in case of encryption failure
func encrypt() throws -> Data
../Sources/VAUClient/VAUInterceptor.swift:48
Encapsulate “real” HTTPRequest into VAU envelop
// Prepare outer request (encrypt original request and embed it into a new one)
// [REQ:gemSpec_Krypt:A_20161-01#3] Encapsulate "real" HTTPRequest into VAU envelop
.processToVauRequest(urlRequest: request, vauCryptoProvider: vauCryptoProvider)
../Sources/VAUClient/VAUInterceptor.swift:65
Encapsulate “real” HTTPRequest into VAU envelop
// Prepare outer request (encrypt original request and embed it into a new one)
// [REQ:gemSpec_Krypt:A_20161-01#4] Encapsulate "real" HTTPRequest into VAU envelop
func processToVauRequest(
../Sources/VAUClient/internal/URLRequest+Serialize.swift:14
1:
/// Serialize the request into a String that can be interpreted by the VAU server
/// - Note: A HTTP body is only included into the string representation when it is UTF-8 encoded.
/// [REQ:gemSpec_Krypt:A_20161-01#11] 1:
func encodeToRawString() throws -> String {
../Sources/VAUClient/internal/VAUCrypto.swift:45
2: Request-ID Generator
// [REQ:gemSpec_Krypt:A_20161-01#12] 2: Request-ID Generator
let requestIdGenerator = { try VAURandom.generateSecureRandom(length: 16).hexStringLowerCase }
../Sources/VAUClient/internal/VAUCrypto.swift:47
3: AES-Key Generator
// [REQ:gemSpec_Krypt:A_20161-01#13] 3: AES-Key Generator
let symmetricKeyGenerator = { SymmetricKey(size: SymmetricKeySize(bitCount: 128)) }
../Sources/VAUClient/VAUInterceptor.swift:92
4: vauCrypto is generating new entity and thus a new request/id everytime
// [REQ:gemSpec_Krypt:A_20161-01#14|5] 4: vauCrypto is generating new entity and thus a new request/id everytime
let vauCrypto = try vauCryptoProvider.provide(
for: stringEncodedRequest,
vauCertificate: vauCertificate,
bearerToken: bearerToken
)
../Sources/VAUClient/internal/VAUCrypto.swift:90
5:
// [REQ:gemSpec_Krypt:A_20161-01#15] 5:
guard let payload = "1 \(bearerToken) \(requestId) \(symKeyHex) \(message)".data(using: .utf8) else {
../Sources/VAUClient/internal/VAUCrypto.swift:138
6a-g
/// Perform Elliptic Curve Integrated Encryption Scheme [SEC1-2009] on some payload
/// [REQ:gemSpec_Krypt:A_20161-01#16] 6a-g
static func encrypt(
../Sources/VAUClient/internal/VAUEndpointHandler.swift:17
7: VAU-Endpoint respects userpseudonym if present
// [REQ:gemSpec_Krypt:A_20161-01#17|10] 7: VAU-Endpoint respects userpseudonym if present
var vauEndpoint: AnyPublisher<URL, VAUError> {
vauStorage.userPseudonym
.map { userPseudonym in
// If the client has yet not been assigned a user pseudonym, then default to "0".
let userPseudonymPathComponent = userPseudonym ?? "0"
return self.vauEndpoint(withLastComponent: userPseudonymPathComponent)
}
.setFailureType(to: VAUError.self)
.eraseToAnyPublisher()
}
A_20163
Original Requirement
A_20163 - E-Rezept-VAU, Nutzeranfrage, Ent- und Verschlüsselung
Die E-Rezept-VAU MUSS das Folgende sicherstellen und im Falle eines Fehlschlagens die Abarbeitung des Requests mit einer entsprechenden Fehlermeldung an die sie aufrufende Webschnittstelle abbrechen.
- Die E-Rezept-VAU MUSS einen verschlüsselten Nutzer-Request von der Webschnittstelle entgegennehmen.
- Die E-Rezept-VAU MUSS einen verschlüsselten Nutzer-Request nach den kryptographischen Vorgaben aus A_20161-* und mit dem privaten Schlüssel aus A_20160-* versuchen zu entschlüsseln.
- Die E-Rezept-VAU MUSS den erhaltenden Klartext p auf den Strukturaufbau aus A_20160-* prüfen.
- Die E-Rezept-VAU MUSS das JWT-Authentisierungstoken auf Gültigkeit prüfen.
- Die E-Rezept-VAU MUSS den in p kodieren HTTP-Request abarbeiten.
- Die E-Rezept-VAU MUSS einen 128-Bit-AES-CMAC-Schlüssel zufällig erzeugen und mindestens alle 10 Tage wechseln.
- Die E-Rezept-VAU MUSS aus dem “sub”-Feld-Wert mittels des CMAC-Schlüssels den 128 Bit langen CMAC-Wert berechnen und hexadezimal kodieren (32 Byte lang). Dies sei das Prenutzerpseudonym (PNP).
- Die Antwort “a” auf den HTTP-Request aus p MUSS wie folgt kodiert werden:
a=“1" + ” “ + Request-ID-aus-p + ” “ + Response-Header-und-Body. - Die E-Rezept-VAU MUSS a mittels des 128-Bit langen AES-Schlüssels aus p und AES/GCM (96 Bit zufällig erzeugter IV, 128 Authentication Tag) verschlüsseln und erhält c’.
- Die E-Rezept-VAU MUSS c’ und das PNP an die Webschnittstelle als Antwort übergeben.
Implementation
../Sources/VAUClient/internal/VAUCrypto.swift:34
/// Perform decryption and validation of given data with the secret key material the implementing instance holds.
///
/// [REQ:gemSpec_Krypt:A_20163]
///
/// - Parameter data: Data to be decrypted
/// - Returns: Decrypted UTF8 string representation of the given data
/// - Throws: `VAUError` in case of decryption failure or when the decrypted data could not be validated
func decrypt(data: Data) throws -> String
A_20174
Original Requirement
A_20174 - E-Rezept-Client, Response-Auswertung
Ein E-Rezept-Client MUSS bei der Response-Auswertung (vgl. vorgehenden Client-Request aus A_20161-*) folgende Schritte durchführen. Dabei MUSS der Client bei Fehlschlagens im Folgenden aufgeführten Prüfungen die Analyse der Response abbrechen, und er MUSS die Request-ID und den AES-Antwortschlüssel sicher löschen.
- Er MUSS prüfen, ob der Content-Type der Response ‘application/octet-stream’ ist.
- Wenn im Response-Header die Variable "Userpseudonym” vorhanden ist, so MUSS er den Wert von “Userpseudonym” als NP für den nächsten Request an die VAU verwenden. (Der Client MUSS einen ggf. vorhandenen alten Wert des NP im Client überschrieben.)
- Er MUSS das Antwort-Chiffrat mit den Vorgaben aus A_20163 (9) und dem AES-Antwort entschlüsseln und prüfen ob die Entschlüsselung erfolgreich möglich war.
- Er MUSS prüfen, ob die Struktur des erhaltenen Klartextes p der Struktur aus A_20163 (8) entspricht.
- Er MUSS prüfen, ob die Request-ID in p der Request-ID aus dem Client-Request entspricht (Gleichheit prüfen).
- Er MUSS das dritte Feld-Element in p (“Response-Header-und-Body”) als HTTP-Antwort der E-Rezept-VAU in fachlich weiter verarbeiten.
Implementation
../Sources/VAUClient/VAUInterceptor.swift:133
1: Check Content-Type
// Process VAU server response (validate and extract+decrypt inner FHIR service response)
// [REQ:gemSpec_Krypt:A_20174#11|12] 1: Check Content-Type
static func processVauResponse(httpResponse: HTTPResponse, vauCrypto: VAUCrypto, originalUrl: URL) throws
guard httpResponse.status == .ok,
httpResponse.response.value(forHTTPHeaderField: "Content-Type") == "application/octet-stream"
else {
return httpResponse
}
let extracted = httpResponse.data
let decrypted = try vauCrypto.decrypt(data: extracted)
let decoded = try decrypted.decodeToHTTPResponse(url: originalUrl)
return decoded
}
}
../Sources/VAUClient/VAUInterceptor.swift:53
2: Handle userpseudonym
// Process VAU server response (validate and extract+decrypt inner FHIR service response)
// [REQ:gemSpec_Krypt:A_20174#12] 2: Handle userpseudonym
.handleUserPseudonym(vauEndpointHandler: self.vauEndpointHandler)
../Sources/VAUClient/internal/VAUEndpointHandler.swift:34
2:
// [REQ:gemSpec_Krypt:A_20174#12] 2:
if let pseudonym = httpResponse.response.value(forHTTPHeaderField: "userpseudonym") {
../Sources/VAUClient/internal/VAUCrypto.swift:115
3: Decrypt using AES symmetric key
// Steps according to gemSpec_Krypt A_20174
// [REQ:gemSpec_Krypt:A_20174#13] 3: Decrypt using AES symmetric key
guard let sealed = try? AES.GCM.SealedBox(combined: data),
../Sources/VAUClient/internal/VAUCrypto.swift:122
4+5: Verify decrypted message. Expect: “1
// [REQ:gemSpec_Krypt:A_20174#14] 4+5: Verify decrypted message. Expect: "1 <request id> <response header+body>"
let separated = utf8.split(separator: " ", maxSplits: 2).map { String($0) }
../Sources/VAUClient/VAUInterceptor.swift:54
6: Remove the envelop
// [REQ:gemSpec_Krypt:A_20174#16] 6: Remove the envelop
.processVauResponse(vauCrypto: vauCrypto, originalUrl: originalUrl)
A_20175
Original Requirement
A_20175 - E-Rezept-Client, Speicherung Nutzerpseudonym
Ein E-Rezept-Client MUSS das im Request verwendete Nutzerpseudonym (NP) in Software speichern (kein HSM/TPM/SE) und das NP ausschließlich für seinen Einsatzzweck der E-Rezept-VAU-Kommunikation verwenden. Insbesondere MUSS der Client die Vertraulichkeit des NP wahren (bspw. nicht unnötig in Protokolleinträgen und Fehlermeldungen aufführen). [<=]
Implementation
../Sources/VAUClient/VAUStorage.swift:11
VAUStorage provides a getter and a setter for user pseudonym
/// VAU Storage protocol
/// [REQ:gemSpec_Krypt:A_20175#1|7] VAUStorage provides a getter and a setter for user pseudonym
public protocol VAUStorage {
var userPseudonym: AnyPublisher<String?, Never> { get }
/// Set and save a user pseudonym
/// - Parameter userPseudonym: value to save. Pass in nil to unset
func set(userPseudonym: String?)
}
../Sources/VAUClient/VAUStorage.swift:20
Implementation of VAUStorage is using the Filesystem
// [REQ:gemSpec_Krypt:A_20175#2|2] Implementation of VAUStorage is using the Filesystem
public class FileVAUStorage: VAUStorage {
let userPseudonymFilePath: URL
../Sources/eRpApp/Session/StandardSessionContainer.swift:154
Initialization of the VAUStorage at a predefined location in the filesystem
// Local VAU storage configuration
// [REQ:gemSpec_Krypt:A_20175#3|10] Initialization of the VAUStorage at a predefined location in the filesystem
lazy var vauStorage: VAUStorage = {
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false
)
.appendingPathComponent("VauStorage") else {
preconditionFailure("Could not create a filePath for the vau storage.")
}
return FileVAUStorage(vauStorageBaseFilePath: vauStorageFilePath)
A_20607
Original Requirement
Implementation
We use https only, see DefaultHTTPClient.swift
. ATS forbids other connections.
A_21216
Original Requirement
A_21216 - E-Rezept-Client, Zertifikatsprüfung auf TSL-Basis
Ein E-Rezept-Client, der nicht das E-Rezept-FdV ist, MUSS das VAU-Zertifikat vom E-Rezept-FD beziehen (vgl. A_20160-*, URL /VAUCertificate) und ebenfalls für dieses Zertifikat die OCSP-Response für dieses Zertifikat beziehen (vgl. A_20160-*, URL /VAUCertificateOCSPResponse). Er MUSS das Zertifikat mittels TUC_PKI_018 (OCSP-Graceperiod=12h, PolicyList={oid_erp-vau}) prüfen und dabei die vom FD bezogene OCSP-Response verwenden. [<=]
Implementation
../Sources/TrustStore/internal/CertList.swift:11
/// Data structure according to */CertList* endpoint
/// [REQ:gemSpec_Krypt:A_21216]
public struct CertList: Codable, Equatable {
../Sources/VAUClient/internal/VAUCertList.swift:11
/// Data structure according to */CertList* endpoint
/// [REQ:gemSpec_Krypt:A_21216]
public struct VAUCertList: Codable, Equatable {
A_21217
Original Requirement
A_21217 - E-Rezept-FD, Zertifikatslisten und OCSP-Response für Clients
Ein E-Rezept-FD MUSS
- nachdem die E-Rezept-VAU-Identität (vgl. A_20160-*) erzeugt wurde mittels des Algorithmus aus Tab_KRYPT_ERP_FD_Zertifikatsliste_erstellen die Datenstruktur analog zu Tab_KRYPT_ERP_Zertifikatsliste erstellen.
- diese erzeugte Zertifikatsliste auf seiner Webschnittstelle (HTTPS) über die URL /CertList (GET-Methode, Reponse-Content-Type ‘application/json’) verfügbar machen.
- die Zertifikatsliste mittels des Algorithmus aus Tab_KRYPT_ERP_FD_Zertifikatsliste_erstellen aktualisieren wenn (1) die E-Rezept-VAU-Identität aktualisiert wurde (Schlüsselwechsel der VAU etc.) oder (2) die gematik neue IDP-Zertifikate über die Liste E-Rezept-Clients bekannt machen möchte. Im Fall (2) meldet die gematik dies an den FD.
- an seiner Webschnittstelle (HTTPS) über die URL /OCSPList (GET-Methode, Reponse-Content-Type ‘application/json’) ein Array mit den base64-kodierten OCSP-Responses für die alle Zertifikate aus dem Array "ee_certs”. Diese OCSP-Response-Liste muss der FD mindestens alle 11 Stunden mit “frischen” OCSP-Responses für die Zertifikate aus dem Array “ee_certs” aktualisieren.
Implementation
../Sources/TrustStore/internal/OCSPList.swift:10
/// [REQ:gemSpec_Krypt:A_21217]
/// Data structure according to */OCSPList* endpoint
public struct OCSPList: Codable, Equatable {
A_21218
Original Requirement
A_21218 - E-Rezept-Client, Zertifikatsprüfung auf Basis der X.509-Root
Das E-Rezept-FdV MUSS die RCA3 (das Zertifikat der Version 3 der X.509-Root der TI) als Vertrauensanker im Programm-Code bzw. mit dem Programm-Code fest assoziiert enthalten und als Basis für die Prüfung von TI-Zertifikat verwenden.
Das FdV MUSS einen TI-Zertifikate-Truststore enthalten und pflegen, wie folgend definiert.
Der Truststore MUSS Prüfschlüssel/Zertifikat aufgeteilt in folgende vier Kategorien enthalten: (A) Root-Schlüssel, (B) CA-Zertifikate, © E-Rezept-VAU-Zertifikat, (D) IDP-Zertifikat(e). Initial kann dieser Truststore nur RCA3 enthalten oder die Zertifikate die mittels Tab_KRYPT_ERP_FD_Zertifikatsliste_erstellen ermittelt werden.
Falls im Truststore keine Zertifikate für Kategorie © und (D) vorliegen, so MUSS das FdV den Truststore aktualisieren indem es über den FD (URL /CertList) die Zertifikatsliste lädt und diese mittels des Algorithmus Tab_KRYPT_ERP_FdV_Truststore_aktualisieren prüft und ggf. in den Truststore lädt.
Das E-Rezept-FdV MUSS über den FD (URL /OCSPList) OCSP-Responses für die Zertifikate © und (D) beziehen, wenn aktuell keine OCSP-Responses für diese Zertifikate im FdV vorliegen, die jünger als 12 Stunden sind.
Falls in der OCSP-Liste OCSP-Responses enthalten sind die zu keinem der Zertifikate © und (D) passen, so MUSS das FdV den Truststore aktualisieren (s. o.).
Zertifikate aus © und (D) MÜSSEN OCSP-Responses, die jünger als 12 Stunden sind besitzen, damit diese Zertifikate in fachliche Use-Cases im FdV verwendet werden können.
Die OCSP-Responder-Zertifikate MÜSSEN per Signaturprüfung auf ein Zertifikat der Kategorie (B) rückführbar sein, ansonsten MÜSSEN die entsprechenden OCSP-Responses verworfen werden.
Das FdV MUSS bei der Prüfung der TI-Zertifikate in fachlichen Use-Cases im FdV, prüfen ob das Zertifikat im oben beschriebenen Truststore enthalten ist und eine gültige OCSP-Response enthält die jünger als 12 Stunden ist. Falls dies nicht so ist, so ist das Ergebnis der Prüfung des TI-Zertifikats FAIL.
[<=]
Implementation
../Tests/TrustStoreTests/X509TrustStoreTests.swift:328
OCSP responder certificates must be verifiable by the trust store
// [REQ:gemSpec_Krypt:A_21218] OCSP responder certificates must be verifiable by the trust store
func testCheckEeCertificatesStatus_failWhenResponsesCannotBeVerifiedByTrustStore() throws {
../Sources/TrustStore/DefaultTrustStoreSession.swift:68
DefaultTrustStoreSession
coordinates loading and validity checking
// [REQ:gemSpec_Krypt:A_21218,A_21222#2] `DefaultTrustStoreSession` coordinates loading and validity checking
extension DefaultTrustStoreSession: TrustStoreSession {
../Sources/TrustStore/DefaultTrustStoreSession.swift:179
// [REQ:gemSpec_Krypt:A_21218]
func loadOCSPResponses() -> AnyPublisher<[OCSPResponse], TrustStoreError> {
../Sources/TrustStore/DefaultTrustStoreSession.swift:192
If only OCSP responses >12h available, we must request new ones
// [REQ:gemSpec_Krypt:A_21218] If only OCSP responses >12h available, we must request new ones
ocspResponses
../Sources/TrustStore/DefaultTrustStoreSession.swift:210
If only OCSP responses >12h available, …
// [REQ:gemSpec_Krypt:A_21218] If only OCSP responses >12h available, ...
ocspResponses
../Sources/TrustStore/DefaultTrustStoreSession.swift:234
If only OCSP responses >12h available, we must request new ones
// [REQ:gemSpec_Krypt:A_21218] If only OCSP responses >12h available, we must request new ones
func allSatisfyNotProducedBefore(date: Date) -> Bool {
../Sources/TrustStore/TrustStoreSession.swift:13
/// TrustStoreSession acts as an interactor/mediator for the TrustStoreClient and TrustStoreStorage
///
/// [REQ:gemSpec_Krypt:A_21218,A_21222]
public protocol TrustStoreSession {
../Sources/TrustStore/X509TrustStore.swift:13
// [REQ:gemSpec_Krypt:A_21218]
// [REQ:gemSpec_eRp_FdV:A_20032-01]
// Category A: Cross root certificates
private let rootCa: X509
../Sources/TrustStore/X509TrustStore.swift:105
/// Match a collection of `OCSPResponse`s with the end entity certificates of this `X509TrustStore`.
/// Checks response status, revocation status for each certificate and validates the signer certificates of
/// the responses itself.
///
/// [REQ:gemSpec_Krypt:A_21218]
/// [REQ:gemSpec_eRp_FdV:A_20032-01]
///
/// - Note: This function assumes that up-to-dateness of the responses itself has already been checked.
///
/// - Returns: true on successful matching/validation, false if not successful or error
func checkEeCertificatesStatus(with ocspResponses: [OCSPResponse]) throws -> Bool {
../Sources/TrustStore/X509TrustStore.swift:103
OCSP responder certificates must be verifiable by the trust store
// [REQ:gemSpec_Krypt:A_21218] OCSP responder certificates must be verifiable by the trust store
let verifiedOCSPResponses = basicVerifyFilter(ocspResponses: ocspResponses)
../Sources/TrustStore/X509TrustStore.swift:111
For every EE certificate there must be a matching OCSP response
// [REQ:gemSpec_Krypt:A_21218] For every EE certificate there must be a matching OCSP response
let matchedResponses = try eeCertAndSignerTuple.map { eeCertificate, signer in
../Sources/TrustStore/X509TrustStore.swift:119
For every OCSP response there must be a matching EE certificate
// [REQ:gemSpec_Krypt:A_21218] For every OCSP response there must be a matching EE certificate
let matchedEeCerts = try ocspResponses.map { response in
../Sources/TrustStore/X509TrustStore.swift:130
OCSP responder certificates must be verifiable by the trust store
// [REQ:gemSpec_Krypt:A_21218] OCSP responder certificates must be verifiable by the trust store
private func basicVerifyFilter(ocspResponses: [OCSPResponse]) -> [OCSPResponse] {
(3) ../Sources/TrustStore/X509TrustStore.swift:151
Check ca_certs against category A certificates
// [REQ:gemSpec_Krypt:A_21218:(3)] Check ca_certs against category A certificates
private static let caCertRegex =
(4) ../Sources/TrustStore/X509TrustStore.swift:168
Check ee_certs against category A+B certificates
// [REQ:gemSpec_Krypt:A_21218:(4)] Check ee_certs against category A+B certificates
typealias VauAndIpdCerts = (vauCerts: [X509], idpCerts: [X509])
../Sources/eRpApp/AppConfiguration.swift:117
Gematik Root CA 3 as a trust anchor has to be set in the program code
// [REQ:gemSpec_Krypt:A_21218] Gematik Root CA 3 as a trust anchor has to be set in the program code
// [REQ:BSI-eRp-ePA:O.Ntwk_4#2|16] Gematik Root CA 3 as a trust anchor has to be set in the program code
// swiftlint:disable:next force_try
let TRUSTANCHOR_GemRootCa3 = try! TrustAnchor(withPEM: """
../Tests/TrustStoreTests/DefaultTrustStoreSessionTests.swift:125
If only OCSP responses >12h available, we must request new ones
// Advance the time so that saved mocked OCSP responses will be invalidated
// The same mocked OCSP responses will be received by the client cannot be validated,
// so expect a session failure.
// [REQ:gemSpec_Krypt:A_21218] If only OCSP responses >12h available, we must request new ones
currentDate = currentDate.advanced(by: TimeInterval(expirationInterval))
../Tests/TrustStoreTests/X509TrustStoreTests.swift:251
// [REQ:gemSpec_Krypt:A_21218]
func testCheckCertificateStatus_FdEnc() throws {
../Tests/TrustStoreTests/X509TrustStoreTests.swift:270
// [REQ:gemSpec_Krypt:A_21218]
func testCheckCertificateStatus_FdEncIdpSig1IdpSig3() throws {
../Tests/TrustStoreTests/X509TrustStoreTests.swift:290
For every EE certificate there must be a matching OCSP response
// [REQ:gemSpec_Krypt:A_21218] For every EE certificate there must be a matching OCSP response
func testCheckCertificateStatus_failWhenOneEeCertHasNoMatchingResponse() throws {
../Tests/TrustStoreTests/X509TrustStoreTests.swift:309
For every OCSP response there must be a matching EE certificate
// [REQ:gemSpec_Krypt:A_21218] For every OCSP response there must be a matching EE certificate
func testCheckCertificateStatus_failWhenOneResponseHasNoMatchingEeCert() throws {
Note: grace period for OCSP responses is 12h
A_21222
Original Requirement
A_21222 - E-Rezept-Client, allgemein Zertifikatsprüfung
Ein E-Rezept-Client MUSS bevor er TI-X.509-Zertifikate in fachlichen Abläufen (bspw. VAU-Kanal) verwendet, diese Zertifikate prüfen (vgl. A_21216 und A_21218). [<=]
Implementation
../Sources/TrustStore/TrustStoreSession.swift:13
/// TrustStoreSession acts as an interactor/mediator for the TrustStoreClient and TrustStoreStorage
///
/// [REQ:gemSpec_Krypt:A_21218,A_21222]
public protocol TrustStoreSession {
The TrustStoreSession
protocol and the implementation DefaultTrustStoreSession
provide interfaces for validating certificates. Validity of the IDP Certificates is always checked, as the discovery document is only available as a stream, and each access will trigger a validity check. FD Certificates
../Sources/TrustStore/DefaultTrustStoreSession.swift:68
DefaultTrustStoreSession
coordinates loading and validity checking
// [REQ:gemSpec_Krypt:A_21218,A_21222#2] `DefaultTrustStoreSession` coordinates loading and validity checking
extension DefaultTrustStoreSession: TrustStoreSession {
../Sources/IDP/DefaultIDPSession.swift:264
DiscoveryDocument is validated with the active trustStoreSession
// [REQ:BSI-eRp-ePA:O.Resi_6#2] Implementation of loading the discovery document for fetching signature and
// encryption keys.
// [REQ:gemSpec_Krypt:A_21222#3] DiscoveryDocument is validated with the active trustStoreSession
private func loadDiscoveryDocument() -> AnyPublisher<DiscoveryDocument, IDPError> {
../Sources/VAUClient/VAUCertificate.swift:20
Vau Certificate provider
// [REQ:gemSpec_Krypt:A_21222#4|7] Vau Certificate provider
func loadAndVerifyVauCertificate() -> AnyPublisher<VAUCertificate, VAUError> {
trustStoreSession.loadVauCertificate()
.first()
.mapError { $0.asVAUError() }
.map { X509VAUCertificate(x509: $0) }
.eraseToAnyPublisher()
}
../Sources/TrustStore/DefaultTrustStoreSession.swift:75
Loading of the whole trust store, filtering for vau certificate
// [REQ:gemSpec_Krypt:A_21222#5|5] Loading of the whole trust store, filtering for vau certificate
public func loadVauCertificate() -> AnyPublisher<X509, TrustStoreError> {
loadOCSPCheckedTrustStore()
.map(\.vauCert)
.eraseToAnyPublisher()
}
A_21275
Original Requirement
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application, see also: Requirements for Connecting Using ATS
A_21275−01
Original Requirement
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application, see also: Requirements for Connecting Using ATS
A_21332-02
Original Requirement
A_21332-02 - E-Rezept: TLS-Vorgaben
Ein E-Rezept-FD, ein Apothekenverzeichnis, ein E-Rezept-Client und ein IDP MÜSSEN in Bezug auf die TLS-Verbindung zwischen ihnen
- folgende Ciphersuiten unterstützen
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xC0, 0x30),
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xC0, 0x2F),
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xC0, 0x2C),
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xC0, 0x2B).
- Sie KÖNNEN weitere Cipher-Suiten aus [TR-02102-2, Abschnitt 3.3.1 Tabelle 1] unterstützen.
- Bei dem ephemeren Elliptic-Curve-Diffie-Hellman-Schlüsselaustausch und bei der Signaturprüfung mittels ECDSA MÜSSEN die Kurven P-256 oder P-384 [FIPS-186-5] unterstützt werden. Daneben SOLLEN die Kurven brainpoolP256r1, brainpoolP384r1 oder brainpoolP512r1 (vgl. [RFC-5639] und [RFC-7027]) unterstützt werden. Andere Kurven SOLLEN NICHT verwendet werden (Hinweis: die Intention des letzten Satzes ist insbesondere, dass die Ordnung des Basispunktes in E(F_p) nicht zu klein werden darf).
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application, see also: Requirements for Connecting Using ATS
A_4389
Original Requirement
Implementation
1 ../Sources/VAUClient/internal/VAUCrypto.swift:94
IVs must not be reused, IVs bit length must be larger or equal to 96
// [REQ:gemSpec_Krypt:A_4389:1] IVs must not be reused, IVs bit length must be larger or equal to 96
let nonceGenerator = { try VAURandom.generateSecureRandom(length: self.eciesSpec.ivSize) }
GS-A_4357
Original Requirement
Implementation
../Sources/IDP/internal/IDPCrypto.swift:15
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
/// Key-pair generator type based on BrainpoolP256r1
///
/// [REQ:gemSpec_Krypt:GS-A_4357,GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
public typealias BrainpoolKeyGenerator = () throws -> BrainpoolP256r1.KeyExchange.PrivateKey
../Sources/IDP/internal/JWT/JWE+KDF.swift:31
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4357] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
case bpp256r1(BrainpoolP256r1.KeyExchange.PublicKey,
../Sources/VAUClient/internal/VAUCrypto.swift:99
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4357] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:BSI-eRp-ePA:O.Cryp_3#5] Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#5] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
let keyPairGenerator = { try BrainpoolP256r1.KeyExchange.generateKey() }
GS-A_4357-01
Original Requirement
Implementation
../Sources/IDP/DefaultIDPSession.swift:289
Assure that brainpoolP256r1 is used
// Validate JWT/DiscoveryDocument signature
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02] Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4361-02] Assure that brainpoolP256r1 is used
// [REQ:BSI-eRp-ePA:O.Resi_6#4] Discovery Document signature verification
guard (try? fetchedDocument.backing.verify(with: fetchedDocument.discKey)) ?? false else {
../Sources/IDP/DefaultIDPSession.swift:635
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_IDP_Frontend:A_19908-01] Signature check
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let verified = try? challenge.challenge.verify(with: document.authentication.cert),
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:24
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02]
public func verify(signature raw: Data, message: Data) throws -> Bool {
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:34
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let key = brainpoolP256r1VerifyPublicKey() else {
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:473
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
let alg: JWT.Algorithm = .bp256r1
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:518
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let alg = autCertificateResponse.info.algorithm.alg
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:606
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
var alg: JWT.Algorithm? {
GS-A_4357-02
Original Requirement
GS-A_4357-02 - X.509-Identitäten für die Erstellung und Prüfung digitaler nicht-qualifizierter elektronischer Signaturen
Alle Produkttypen, die X.509-Identitäten bei der Erstellung oder Prüfung digitaler nicht-qualifizierter elektronischer Signaturen verwenden, MÜSSEN die in Tab_KRYPT_002 aufgeführten Algorithmen unterstützen und die Tabellenvorgaben erfüllen.
Produkttypen, die Zertifikate (X.509-Identitäten) auf Basis der Schlüsselgeneration „ECDSA“ ausstellen (vgl. Abschnitt 5.1) oder verwenden, MÜSSEN die in Tab_KRYPT_002a aufgeführten Algorithmen und die Tabellenvorgaben erfüllen.
[<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:289
Assure that brainpoolP256r1 is used
// Validate JWT/DiscoveryDocument signature
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02] Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4361-02] Assure that brainpoolP256r1 is used
// [REQ:BSI-eRp-ePA:O.Resi_6#4] Discovery Document signature verification
guard (try? fetchedDocument.backing.verify(with: fetchedDocument.discKey)) ?? false else {
../Sources/IDP/DefaultIDPSession.swift:635
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_IDP_Frontend:A_19908-01] Signature check
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let verified = try? challenge.challenge.verify(with: document.authentication.cert),
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:24
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02]
public func verify(signature raw: Data, message: Data) throws -> Bool {
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:34
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let key = brainpoolP256r1VerifyPublicKey() else {
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:473
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
let alg: JWT.Algorithm = .bp256r1
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:518
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let alg = autCertificateResponse.info.algorithm.alg
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:606
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
var alg: JWT.Algorithm? {
GS-A_4359
Original Requirement
Implementation
TLS is enforced by the platform for every HTTP connection. Certain domains can be excluded from this rule by listing them in a dedicated NSAppTransportSecurity exception list. This list is empty for our application, see also: Requirements for Connecting Using ATS
GS-A_4361-02
Original Requirement
GS-A_4361-02 - X.509-Identitäten für die Erstellung und Prüfung digitaler Signaturen
Alle Produkttypen, die X.509-Identitäten verwenden, die zur Erstellung und Prüfung digitaler Signaturen in Bezug auf TI-Komponenten (technische X.509-Zertifikate) genutzt werden, MÜSSEN alle in Tab_KRYPT_002 aufgeführten Algorithmen unterstützen und die Tabellenanforderungen erfüllen.
Produkttypen die Zertifikate (X.509-Identitäten) auf Basis der Schlüsselgeneration „ECDSA“ ausstellen (vgl. Abschnitt 5.1) oder verwenden, MÜSSEN die in Tab_KRYPT_002a aufgeführten Algorithmen und die Tabellenvorgaben erfüllen. [<=]
Implementation
../Sources/IDP/DefaultIDPSession.swift:290
Assure that brainpoolP256r1 is used
// Validate JWT/DiscoveryDocument signature
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02] Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4361-02] Assure that brainpoolP256r1 is used
// [REQ:BSI-eRp-ePA:O.Resi_6#4] Discovery Document signature verification
guard (try? fetchedDocument.backing.verify(with: fetchedDocument.discKey)) ?? false else {
../Sources/IDP/DefaultIDPSession.swift:635
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Only implemented for brainpoolP256r1
// [REQ:gemSpec_IDP_Frontend:A_19908-01] Signature check
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let verified = try? challenge.challenge.verify(with: document.authentication.cert),
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:24
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02]
public func verify(signature raw: Data, message: Data) throws -> Bool {
../Sources/IDP/internal/JWT/JWTSignatureVerifier.swift:34
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207]
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let key = brainpoolP256r1VerifyPublicKey() else {
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:473
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
let alg: JWT.Algorithm = .bp256r1
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:518
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
guard let alg = autCertificateResponse.info.algorithm.alg
../Sources/eRpApp/Screens/CardWall/ReadCard/NFCSignatureProvider.swift:606
Assure that brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:A_17207] Assure only brainpoolP256r1 is used
// [REQ:gemSpec_Krypt:GS-A_4357-01,GS-A_4357-02,GS-A_4361-02] Assure that brainpoolP256r1 is used
var alg: JWT.Algorithm? {
GS-A_4367
Original Requirement
GS-A_4367 - Zufallszahlengenerator
Alle Produkttypen, die Zufallszahlen generieren, MÜSSEN die Anforderungen aus [BSI-TR-03116-1#3.8 Erzeugung von Zufallszahlen] erfüllen.
[<=]
Implementation
../Sources/IDP/internal/IDPCrypto.swift:15
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
/// Key-pair generator type based on BrainpoolP256r1
///
/// [REQ:gemSpec_Krypt:GS-A_4357,GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
public typealias BrainpoolKeyGenerator = () throws -> BrainpoolP256r1.KeyExchange.PrivateKey
../Sources/IDP/internal/JWT/JWE+KDF.swift:32
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4357] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
case bpp256r1(BrainpoolP256r1.KeyExchange.PublicKey,
../Sources/IDP/internal/SecKeyRandom.swift:20
/// Generate random Data with given length
///
/// [REQ:gemSpec_Krypt:GS-A_4367]
/// [REQ:BSI-eRp-ePA:O.Rand_1#2] Secure Random generator.
///
/// - Parameters:
/// - length: the number of bytes to generate
/// - randomizer: the randomizer to be used. Default: kSecRandomDefault
/// - Returns: the random initialized Data
/// - Throws: `IDPError`
public func generateSecureRandom(length: Int, randomizer: SecRandomRef? = kSecRandomDefault) throws -> Data {
../Sources/VAUClient/internal/VAUCrypto.swift:100
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4357] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:BSI-eRp-ePA:O.Cryp_3#5] Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#5] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
let keyPairGenerator = { try BrainpoolP256r1.KeyExchange.generateKey() }
../Sources/VAUClient/internal/VAURandom.swift:21
/// Generate random Data with given length
///
/// [REQ:gemSpec_Krypt:GS-A_4367]
/// [REQ:BSI-eRp-ePA:O.Rand_1#3] Secure Random generator.
///
/// - Parameters:
/// - length: the number of bytes to generate
/// - randomizer: the randomizer to be used. Default: kSecRandomDefault
/// - Returns: the random initialized Data
/// - Throws: `VAUError`
static func generateSecureRandom(length: Int, randomizer: SecRandomRef? = kSecRandomDefault) throws -> Data {
We use the platform provided secure random generator. iOS is FIPS 140-2 certified. The operating system uses an entropy pool with different sources, including a true random number generator from the secure enclave, that is present on every device. Security certifcates can be found https://support.apple.com/de-li/guide/certifications/apc3fa917cb49/web, including FIPS 140-2 und Common Criteria.
GS-A_4368
Original Requirement
GS-A_4368 - Schlüsselerzeugung
Alle Produkttypen, die Schlüssel erzeugen, MÜSSEN die Anforderungen aus [BSI-TR-03116-1#3.9 Schlüsselerzeugung] erfüllen. [<=]
Implementation
../Sources/IDP/internal/IDPCrypto.swift:56
AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4389:1] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#3] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
// [REQ:gemSpec_IDP_Frontend:A_21323#4] AES key generation via CryptoKit
aesKey: SymmetricKey = SymmetricKey(size: SymmetricKeySize(bitCount: 256))
../Sources/VAUClient/internal/VAUCrypto.swift:152
AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4389:2] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#6] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
let secretKey = SymmetricKey(data: sharedSecret)
We use the platform provided secure random generator. iOS is FIPS 140-2 certified. The operating system uses an entropy pool with different sources, including a true random number generator from the secure enclave, that is present on every device. Security certifcates can be found https://support.apple.com/de-li/guide/certifications/apc3fa917cb49/web, including FIPS 140-2 und Common Criteria.
GS-A_4385
Original Requirement
GS-A_4385 - TLS-Verbindungen, Version 1.2
Alle Produkttypen, die Übertragungen mittels TLS durchführen, MÜSSEN die TLS-Version 1.2 [RFC-5246] unterstützen.
[<=]
Implementation
../Sources/HTTPClient/DefaultHTTPClient.swift:33
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
GS-A_4387
Original Requirement
GS-A_4387 - TLS-Verbindungen, nicht Version 1.0
Alle Produkttypen, die Übertragungen mittels TLS durchführen, DÜRFEN NICHT die TLS-Version 1.0 unterstützen. [<=]
Implementation
../Sources/HTTPClient/DefaultHTTPClient.swift:33
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
GS-A_4389
Original Requirement
GS-A_4389 - Symmetrischer Anteil der hybriden Verschlüsselung binärer Daten
Produkttypen, die die hybride Verschlüsselung binärer Daten durchführen, MÜSSEN für den symmetrischen Anteil der Verschlüsselung die folgenden Vorgaben berücksichtigen:
Als symmetrische Block-Chiffre muss AES [FIPS-197] mit einer Schlüssellänge von 256 Bit im Galois/Counter Mode (GCM) gemäß [NIST-SP-800-38D] mit der Tag-Länge von 128 Bit verwendet werden.
Die IVs dürfen sich bei gleichem Schlüssel nicht wiederholen (vgl. [NIST-SP-800-38D#S.25] und [BSI-TR-02102-1#S.24]). Der IV soll eine Bitlänge von 96 Bit besitzen, seine Länge muss mindestens 96 Bit sein. Es wird empfohlen den IV zufällig zu wählen (vgl. [gemSpec_Krypt#GS-A_4367]).
Hinweis: Im Normalfall ist davon auszugehen, dass für die Sicherung der Integrität und Authentizität der zu verschlüsselnden Daten zudem noch eine Signatur dieser Daten notwendig ist.
Implementation
2 ../Sources/IDP/internal/IDPCrypto.swift:48
IVs must not be reused, IVs bit length must be larger or equal to 96
// [REQ:gemSpec_Krypt:GS-A_4389:2] IVs must not be reused, IVs bit length must be larger or equal to 96
try generateSecureRandom(length: IDPCrypto.AES256GCMSpec.nonceBytes)
1 ../Sources/IDP/internal/IDPCrypto.swift:54
256bit GCM symmetric key
// [REQ:gemSpec_Krypt:GS-A_4389:1] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#3] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
// [REQ:gemSpec_IDP_Frontend:A_21323#4] AES key generation via CryptoKit
aesKey: SymmetricKey = SymmetricKey(size: SymmetricKeySize(bitCount: 256))
2 ../Sources/VAUClient/internal/VAUCrypto.swift:150
256bit GCM symmetric key
// [REQ:gemSpec_Krypt:GS-A_4389:2] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#6] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
let secretKey = SymmetricKey(data: sharedSecret)
1 ../Sources/VAUClient/internal/VAUCrypto.swift:169
256bit GCM symmetric key
// f) Encrypt
// [REQ:gemSpec_Krypt:GS-A_4389:1] 256bit GCM symmetric key
let sealedBox = try AES.GCM.seal(payload, using: cek, nonce: nonce)
GS-A_4390
Original Requirement
GS-A_4390 - Asymmetrischer Anteil der hybriden Verschlüsselung binärer Daten
Produkttypen, die die hybride Verschlüsselung binärer Daten durchführen, MÜSSEN für den asymmetrischen Anteil der Verschlüsselung die folgenden Vorgaben berücksichtigen:
- Als asymmetrisches Verschlüsselungsverfahren MUSS RSAES-OAEP gemäß [PKCS#1, Kapitel 7.1] verwendet werden.
- Als Mask-Generation-Function für die Verwendung in RSAES-OAEP MUSS MGF 1 mit SHA-256 als Hash-Funktion gemäß [PKCS#1, Anhang B.2.1] verwendet werden.
Implementation
../Sources/AVS/AVSCmsEncrypter.swift:21
RSAES-OAEP with MGF1 implemented in sub-framework OpenSSL-swift
// [REQ:gemSpec_Krypt:GS-A_4390] RSAES-OAEP with MGF1 implemented in sub-framework OpenSSL-swift
// [REQ:gemSpec_eRp_FdV:A_22778-01#3] Encryption of message to the Pharmacy is done with all provided
// certificates
// [REQ:gemSpec_eRp_FdV:A_22779-01#3] Encrypted message is of form of a PKCS#7 container (CMS)
// https://github.com/gematik/OpenSSL-Swift/blob/3c1ea91ba5abfefecfe3588815cb928d777e29ad/Sources/OpenSSL/CMS/CMSContentInfo.swift#L88
// swiftlint:disable:previous line_length
let cms = try CMSContentInfo.encryptPartial(data: data)
GS−A_5035
Original Requirement
Implementation
We use https only, see DefaultHTTPClient.swift
. ATS forbids other connections.
GS−A_5322
Original Requirement
Implementation
There is no API to control the session length, developer forums suggest it is 10 minutes for iOS.
GS−A_5339
Original Requirement
Implementation
We cannot interfere with cipher suite lists, see Requirements for Connecting Using ATS for actual order.
GS−A_5526
Original Requirement
Implementation
We use the recommended NSURLSession for best network security Preventing insecure network connections
GS−A_5542
Original Requirement
Implementation
We use the recommended NSURLSession for best network security Preventing insecure network connections
gemSpec_eRp_APOVZD
A_21154
Original Requirement
A_21154 - Client des Apothekenverzeichnisses - Erlaubnis Standortabfrage
Das Clientsystem MUSS vom Nutzer vor der ersten Abfrage zu dessen aktueller Geoposition die Einwilligung zur Abfrage und Zustimmung zur Übermittlung an das Apothekenverzeichnis einholen. [<=]
Implementation
../Sources/eRpApp/Screens/Pharmacy/Search/PharmacySearchDomain.swift:534
If user defined filters contain location element, ask for permission
// [REQ:gemSpec_eRp_APOVZD:A_21154] If user defined filters contain location element, ask for permission
if filterOptions.contains(.currentLocation) {
A_21779
Original Requirement
Implementation
../Sources/Pharmacy/ModelsR4.Bundle+Location.swift:138
delivery pharmacy
// [[REQ:gemSpec_eRp_APOVZD:A_21779] delivery pharmacy
case "498":
../Sources/Pharmacy/ModelsR4.Bundle+Location.swift:195
Map pickup pharmacy
// [[REQ:gemSpec_eRp_APOVZD:A_21779] Map pickup pharmacy
case "OUTPHARM":
../Sources/Pharmacy/ModelsR4.Bundle+Location.swift:200
Map shipping pharmacy
// [[REQ:gemSpec_eRp_APOVZD:A_21779] Map shipping pharmacy
case "MOBL":
gemSpec_eRp_FdV
A_19086
Original Requirement
A_19086 - E-Rezept-FdV: Verbot von Werbe-Tracking
Das E-Rezept-FdV DARF ein Werbe-Tracking NICHT verwenden. [<=]
Implementation
Tracking is only implemented for the purpose of Usability-Tracking. Sessions are not persisted, session ids are recreated each app startup.
A_19087
Original Requirement
Implementation
Tracking is only implemented for the purpose of Usability-Tracking. Sessions are not persisted, session ids are recreated each app startup.
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:13
Implementation of the opt-in usability-tracker.
// [REQ:gemSpec_eRp_FdV:A_19087#2] Implementation of the opt-in usability-tracker.
final class ContentSquareAnalyticsAdapter: NSObject, Tracker {
A_19088
Original Requirement
Implementation
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:189
Show comply route to display analytics usage within
// [REQ:gemSpec_eRp_FdV:A_19088,A_19091-01#1,A_19092-01#2] Show comply route to display analytics usage within
// onboarding
// [REQ:BSI-eRp-ePA:O.Purp_3#5] Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19089-01#2] Show comply route to display analytics usage within onboarding
case .showTracking:
A_19089-01
Original Requirement
A_19089-01 - E-Rezept-FdV: Informationen zur Einwilligung
Das E-Rezept-FdV MUSS, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, den Versicherten vor der Einwilligung in die Aktivierung dieser Tracking-Funktion in verständlicher und leicht zugänglicher Form sowie in einer klaren und einfachen Sprache folgende Einwilligungsinformationen anzeigen:
- welche Daten durch die Tracking-Funktionen erhoben werden,
- zu welchen Zwecken die Daten erhoben werden,
- welche Informationen durch die Auswertung der erhobenen Daten gewonnen werden und ob Rückschlüsse auf den Gesundheitszustand des Nutzers möglich wären,
- wer die Empfänger der Daten sind,
- wie lange die Daten gespeichert werden
- wie die Tracking-Funktionen deaktiviert werden können.
Implementation
We do not link user session of multiple app starts, we forcefully regenerate a new user-id. Nevertheless the following still applies: Opt-In for Analytics will be asked while the app onboarding runs. After the onboarding ran, the user may change the analytics settings in the settings menu.
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:192
Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19088,A_19091-01#1,A_19092-01#2] Show comply route to display analytics usage within
// onboarding
// [REQ:BSI-eRp-ePA:O.Purp_3#5] Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19089-01#2] Show comply route to display analytics usage within onboarding
case .showTracking:
../Sources/eRpApp/Screens/Settings/SettingsView.swift:47
Show information dialog for analytics usage
// Tracking comply sheet presentation
// [REQ:BSI-eRp-ePA:O.Purp_5#3] Show comply view for settings triggered analytics enabling
// [REQ:gemSpec_eRp_FdV:A_19982#3,A_19089-01#3] Show information dialog for analytics usage
Rectangle()
../Sources/eRpApp/Screens/Settings/SettingsView.swift:177
User info for usage analytics
// [REQ:gemSpec_eRp_FdV:A_19089-01#4] User info for usage analytics
Label(title: { Text(L10n.stgTrkTxtExplanation) }, icon: {})
A_19090
Original Requirement
Implementation
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:61
activate tracking only if permitted
/// Starts tracking and calls `optIn` if permission is granted by the user.
/// Calling this method after calling `resetSessionID()` will create a new `sessionID`
// [REQ:gemSpec_eRp_FdV:A_19090] activate tracking only if permitted
private func startIfPermitted() {
A_19090-01
Original Requirement
A_19090-01 - E-Rezept-FdV: Aktivierung erst nach Lesebestätigung der Einwilligungsinformationen
Das E-Rezept-FdV MUSS sicherstellen, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, dass die Einwilligung des Nutzers in die Aktivierung dieser Tracking-Funktionen erst erfolgt, wenn der Nutzer bestätigt, die angezeigten Einwilligungsinformationen gelesen zu haben. [<=]
Implementation
../Sources/eRpApp/SceneDelegate.swift:300
activate after optIn is granted
// [REQ:gemSpec_eRp_FdV:A_19090-01] activate after optIn is granted
tracker.stopTracking()
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:194
User confirms the opt in within settings
// [REQ:gemSpec_eRp_FdV:A_19090-01,A_19091-01#2] User confirms the opt in within settings
// [REQ:BSI-eRp-ePA:O.Purp_3#6] Accept usage analytics
case .alert(.presented(.allowTracking)):
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:165
User confirms the opt in within settings
// [REQ:gemSpec_eRp_FdV:A_19090-01,A_19091-01#4] User confirms the opt in within settings
// [REQ:BSI-eRp-ePA:O.Purp_5#4] User confirms the opt in within settings
case .confirmedOptInTracking:
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:43
activate after optIn is granted
// [REQ:gemSpec_eRp_FdV:A_19090-01] activate after optIn is granted
Contentsquare.start()
We do not link user session of multiple app starts, we forcefully regenerate a new user-id. Nevertheless the following still applies: Opt-In for Analytics will be asked while the app onboarding runs. After the onboarding ran, the user may change the analytics settings in the settings menu.
A_19091-01
Original Requirement
A_19091-01 - E-Rezept-FdV: Verbot von mehrmaligen Einwilligungsabfragen
Das E-Rezept-FdV MUSS, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, technisch sicherstellen, dass der Benutzer der App maximal einmal eine Abfrage zur Einwilligung in das Tracking angezeigt bekommt. [<=]
Implementation
We do not link user session of multiple app starts, we forcefully regenerate a new user-id. Nevertheless the following still applies: Opt-In for Analytics will be asked while the app onboarding runs. After the onboarding ran, the user may change the analytics settings in the settings menu.
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:189
Show comply route to display analytics usage within
// [REQ:gemSpec_eRp_FdV:A_19088,A_19091-01#1,A_19092-01#2] Show comply route to display analytics usage within
// onboarding
// [REQ:BSI-eRp-ePA:O.Purp_3#5] Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19089-01#2] Show comply route to display analytics usage within onboarding
case .showTracking:
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:194
User confirms the opt in within settings
// [REQ:gemSpec_eRp_FdV:A_19090-01,A_19091-01#2] User confirms the opt in within settings
// [REQ:BSI-eRp-ePA:O.Purp_3#6] Accept usage analytics
case .alert(.presented(.allowTracking)):
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:156
Show comply route to display analytics usage within settings
// [REQ:gemSpec_eRp_FdV:A_19091-01#3] Show comply route to display analytics usage within settings
state.destination = .complyTracking(.init())
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:165
User confirms the opt in within settings
// [REQ:gemSpec_eRp_FdV:A_19090-01,A_19091-01#4] User confirms the opt in within settings
// [REQ:BSI-eRp-ePA:O.Purp_5#4] User confirms the opt in within settings
case .confirmedOptInTracking:
A_19092-01
Original Requirement
A_19092-01 - E-Rezept-FdV: Kopplungsverbot
Das E-Rezept-FdV DARF, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, die Nutzung des E-Rezept-FdV NICHT an die Aktivierung des Session-übergreifenden Tracking koppeln. [<=]
Implementation
We do not link user session of multiple app starts, we forcefully regenerate a new user-id. Nevertheless the following still applies: Opt-In for Analytics will be asked while the app onboarding runs. After the onboarding ran, the user may change the analytics settings in the settings menu.
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:189
Show comply route to display analytics usage within
// [REQ:gemSpec_eRp_FdV:A_19088,A_19091-01#1,A_19092-01#2] Show comply route to display analytics usage within
// onboarding
// [REQ:BSI-eRp-ePA:O.Purp_3#5] Show comply route to display analytics usage within onboarding
// [REQ:gemSpec_eRp_FdV:A_19089-01#2] Show comply route to display analytics usage within onboarding
case .showTracking:
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:199
User may choose to not accept analytics, onboarding will still continue
// [REQ:gemSpec_eRp_FdV:A_19092-01#3] User may choose to not accept analytics, onboarding will still continue
// [REQ:BSI-eRp-ePA:O.Purp_3#7] Deny usage analytics
case .alert(.dismiss):
A_19093-01
Original Requirement
A_19093-01 - E-Rezept-FdV: Keine direkt identifizierenden personenbezogenen Daten
Das E-Rezept-FdV MUSS sicherstellen, falls es Tracking-Funktionen implementiert, dass die Tracking-Informationen keine Daten enthalten, die natürliche Personen direkt identifizieren. [<=]
Implementation
Usage Tracking is called very sparse and boils down to one place where all visited screens are recorded. See usage of @Dependency(\.tracker)
for all cases where the actual analytics framework is used.
../Sources/eRpApp/Tracking/AnalyticsReducer.swift:38
Very sparse usage of actual tracking boils down to this call where
// [REQ:gemSpec_eRp_FdV:A_19093-01#2] Very sparse usage of actual tracking boils down to this call where
// only displayed screens are tracked
tracker.track(screen: newRoute)
A_19094-01
Original Requirement
A_19094-01 - E-Rezept-FdV: Keine Weitergabe von Sicherheitsmerkmalen
Das E-Rezept-FdV MUSS sicherstellen, falls es Tracking-Funktionen implementiert, dass in den übermittelten Tracking-Informationen keine Sicherheitsmerkmale enthalten sind. [<=]
Implementation
Usage Tracking is called very sparse and boils down to one place where all visited screens are recorded. See usage of @Dependency(\.tracker)
for all cases where the actual analytics framework is used.
A_19095
Original Requirement
Implementation
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:74
resets sessionID so that on next app start a new sessionID will be created
// [REQ:gemSpec_eRp_FdV:A_19095] resets sessionID so that on next app start a new sessionID will be created
Contentsquare.optOut()
A_19096-01
Original Requirement
A_19096-01 - E-Rezept-FdV: Jederzeit neue Generierung der Pseudonyme
Das E-Rezept-FdV MUSS, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, technisch sicherstellen, dass eine neue Generierung der pseudonymen Identifier jederzeit durch den Nutzer des FdVs veranlasst werden kann. [<=]
Implementation
We do not link user session of multiple app starts, we forcefully regenerate a new user-id. Nevertheless the following still applies.
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:63
Remove existing sessions while starting the framework, tracking is
// [REQ:gemSpec_eRp_FdV:A_19096-01#1] Remove existing sessions while starting the framework, tracking is
// never cross session.
Contentsquare.start()
A_19097-01
Original Requirement
A_19097-01 - E-Rezept-FdV: Deaktivierung zu jeder Zeit
Das E-Rezept-FdV MUSS technisch sicherstellen, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, dass aktivierte Tracking-Funktionen jederzeit durch den Nutzer des FdVs deaktiviert werden können. [<=]
Implementation
We do not link user session of multiple app starts, we forcefully regenerate a new user-id. Nevertheless the following still applies.
../Sources/eRpApp/Screens/Settings/SettingsView.swift:158
Toggle within Settings to enable and disable usage analytics
// [REQ:gemSpec_eRp_FdV:A_19097-01#2] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_5#1] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_6#1] Current Analytics state is inspectable by the user
// [REQ:gemSpec_eRp_FdV:A_19982#4] Opt out of analytics
Toggle(isOn: $store.trackerOptIn.sending(\.toggleTrackingTapped).animation()) {
A_19176
Original Requirement
Implementation
Authenticity is provided by the appstore and app signing. We choose secure options where possible as the default value. Where the user can choose options, we inform by presenting additional information (e.g. “storing” the login).
A_19177
Original Requirement
A_19177 - E-Rezept-FdV – Anzeige von Protokolldaten
Das E-Rezept-FdV MUSS es den Versicherten ermöglichen, die für die Fachanwendung für ihn erzeugten Protokolleinträge anzeigen zu können. [<=]
Implementation
An Audit Log for every FD access is available in each user profile.
../Sources/eRpApp/Screens/Settings/Profiles/Protocol/AuditEventsView.swift:12
View displaying the audit events
// [REQ:gemSpec_eRp_FdV:A_19177#1,A_19185#2] View displaying the audit events
// [REQ:BSI-eRp-ePA:O.Auth_6#3] View displaying the audit events
struct AuditEventsView: View {
../Sources/eRpApp/Screens/Settings/Profiles/Edit/EditProfileView.swift:400
Actual Button to open the audit events
// [REQ:gemSpec_eRp_FdV:A_19177#2,A_19185#3] Actual Button to open the audit events
// [REQ:BSI-eRp-ePA:O.Auth_6#2] Actual Button to open the audit events
NavigationLink(item: $store.scope(state: \.destination?.auditEvents,
A_19178
Original Requirement
A_19178 - E-Rezept-FdV – Schutzmaßnahmen gegen die OWASP-Mobile-Top-10-Risiken
Das E-Rezept-FdV MUSS Maßnahmen zum Schutz vor den in der jeweils aktuellen Version genannten OWASP-Mobile-Top-10-Risiken [OWASPMobileTop10] umsetzen. [<=]
Implementation
Is covered by our MSTG.
A_19179
Original Requirement
Implementation
Annotation in code
../Sources/IDP/internal/IDPCrypto.swift:44
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_eRp_FdV:A_19179#2] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:BSI-eRp-ePA:O.Cryp_3#3] Brainpool key generator
try BrainpoolP256r1.KeyExchange.generateKey()
../Sources/IDP/internal/IDPCrypto.swift:55
AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4389:1] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#3] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
// [REQ:gemSpec_IDP_Frontend:A_21323#4] AES key generation via CryptoKit
aesKey: SymmetricKey = SymmetricKey(size: SymmetricKeySize(bitCount: 256))
../Sources/IDP/internal/JWT/JWE+KDF.swift:36
Key pair generation delegated to OpenSSL
// [REQ:BSI-eRp-ePA:O.Cryp_3#4] Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#4] Key pair generation delegated to OpenSSL
= { try BrainpoolP256r1.KeyExchange.generateKey() })
../Sources/VAUClient/internal/VAUCrypto.swift:102
Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4357] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:gemSpec_Krypt:GS-A_4367] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
// [REQ:BSI-eRp-ePA:O.Cryp_3#5] Brainpool key generator
// [REQ:gemSpec_eRp_FdV:A_19179#5] Key pair generation delegated to OpenSSL with BrainpoolP256r1 parameters
let keyPairGenerator = { try BrainpoolP256r1.KeyExchange.generateKey() }
../Sources/VAUClient/internal/VAUCrypto.swift:151
AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4389:2] 256bit GCM symmetric key
// [REQ:gemSpec_eRp_FdV:A_19179#6] AES key generation via CryptoKit
// [REQ:gemSpec_Krypt:GS-A_4368] AES key generation via CryptoKit
let secretKey = SymmetricKey(data: sharedSecret)
A_19181-01
Original Requirement
Implementation
There is an opt-in option for analytics. Full app functionality is available also without opting in. The user’s choice is requested during onboarding and the user can opt-in and opt-out of analytics at any time. There are no further configuration choices. After successful authentication via health card the corresponding prescriptions, protocol data and messages are displayed.
The onboarding contains defaults that are best practices, such as using biometrics for authentication. While using the Cardwall, selecting the “save login” option results in an dialog with additional information, to let the user make informed decisions. A missing device passcode results in a dialog that is recommending the setup of a device passcode.
A_19182
Original Requirement
Implementation
In order to minimize the risk of unknown vulnerabilities in dependencies, we use different measures: We develop according to Security by Design Principles (see E-Rezept-App - SSDLC.pdf - Section Richtlinien, Vorgaben und Best Practices). We train our engineers focussing on secure design and coding best practices (see Sicherheitsschulungen.pdf). We publish our Code on Github and use a bug bounty program (https://www.gematik.de/datensicherheit -> Coordinated Vulnerability Disclosure Program)
See O.Source_1 for input/output validation.
A_19183
Original Requirement
Implementation
We have no implementation of any sharing mechanism of FD data.
See O.Purp_8 for usages.
A_19184
Original Requirement
Implementation
../Sources/eRpApp/Screens/Onboarding/OnboardingAnalyticsView.swift:20
Information for the user what is collected
// [REQ:gemSpec_eRp_FdV:A_19184] Information for the user what is collected
VStack(alignment: .leading, spacing: 16) {
../Sources/eRpApp/Screens/Onboarding/OnboardingDomain.swift:207
Alert for the user to choose.
// [REQ:gemSpec_eRp_FdV:A_19184] Alert for the user to choose.
static let trackingAlertState: AlertState<Action.Alert> = {
A_19185
Original Requirement
Implementation
Communication with the Fachdienst is protocoled via Audit Events. The user can revise them in the Settings menu (Profile Settings).
../Sources/eRpApp/Screens/Settings/Profiles/Protocol/AuditEventsView.swift:12
View displaying the audit events
// [REQ:gemSpec_eRp_FdV:A_19177#1,A_19185#2] View displaying the audit events
// [REQ:BSI-eRp-ePA:O.Auth_6#3] View displaying the audit events
struct AuditEventsView: View {
../Sources/eRpApp/Screens/Settings/Profiles/Edit/EditProfileView.swift:400
Actual Button to open the audit events
// [REQ:gemSpec_eRp_FdV:A_19177#2,A_19185#3] Actual Button to open the audit events
// [REQ:BSI-eRp-ePA:O.Auth_6#2] Actual Button to open the audit events
NavigationLink(item: $store.scope(state: \.destination?.auditEvents,
A_19186
Original Requirement
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:17
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
A_19187
Original Requirement
Implementation
../Sources/VAUClient/VAUInterceptor.swift:39
VAU Bearer must be set to trigger a request
// [REQ:gemSpec_eRp_FdV:A_19187] VAU Bearer must be set to trigger a request
return vauAccessTokenProvider.vauBearerToken
A_19188
Original Requirement
Implementation
session data (ACCESS_TOKEN, ID_TOKEN, SSO_TOKEN, CAN) is saved in the keychain. Its deletion is managed by the OS. The key chain is sandboxed and can only be shared with other apps by the same vendor when explicitly set. All other mentioned data is deleted.
../Sources/eRpApp/Session/KeychainStorage.swift:18
Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_eRp_FdV:A_19186]
// [REQ:gemSpec_eRp_FdV:A_19188] Deletion of data saved here is managed by the OS.
// [REQ:gemSpec_IDP_Frontend:A_21322] Storage implementation uses iOS Keychain
// [REQ:gemSpec_IDP_Frontend:A_21595] Storage Implementation
// [REQ:BSI-eRp-ePA:O.Purp_8#1,O.Arch_4#3] Implementation of data storage that is persisted via keychain
// [REQ:BSI-eRp-ePA:O.Source_7#2,O.Data_2#2,O.Auth_13#3] Implementation of data storage that is persisted via keychain
class KeychainStorage: SecureUserDataStore, IDPStorage, SecureEGKCertificateStorage {
A_19229-01
Original Requirement
A_19229-01 - E-Rezept-FdV: E-Rezept lokal löschen - Löschen aller verknüpfter Daten
Das E-Rezept-FdV MUSS, wenn es ein E-Rezept lokal im E-Rezept-FdV löscht, auch alle mit dem E-Rezept verknüpften Daten im E-Rezept-FdV löschen. [<=]
Implementation
Audit events will be deleted when the referencing task is deleted. Cascading relationship “task -> audit event” is defined in Sources/eRpLocalStorage/Prescriptions/ErxTask.xcdatamodeld/ErxTask.xcdatamodel/contents
../Sources/eRpApp/Screens/Main/PrescriptionDetail/PrescriptionDetailDomain.swift:195
Deletion button is tapped -> delete confirmation dialog shows
// Delete
// [REQ:gemSpec_eRp_FdV:A_19229-01#2] Deletion button is tapped -> delete confirmation dialog shows
case .delete:
../Sources/eRpApp/Screens/Main/PrescriptionDetail/PrescriptionDetailDomain.swift:205
Confirmation dialog was confirmed, deletion is triggered
// [REQ:gemSpec_eRp_FdV:A_19229-01#3] Confirmation dialog was confirmed, deletion is triggered
case .destination(.presented(.alert(.confirmedDelete))):
A_19480
Original Requirement
Implementation
../Sources/IDP/IDPSession.swift:26
usage of this token is limited to FD/IDP Access.
/// Subscribe to the session's IDPToken and receive the latest (session) token through this Publisher
///
/// [REQ:gemSpec_eRp_FdV:A_19480] usage of this token is limited to FD/IDP Access.
var autoRefreshedToken: AnyPublisher<IDPToken?, IDPError> { get }
../Sources/IDP/IDPStorage.swift:34
usage of this token is limited to FD/IDP Access.
/// Retrieve and set an IDP Token
/// [REQ:gemSpec_eRp_FdV:A_19480] usage of this token is limited to FD/IDP Access.
var token: AnyPublisher<IDPToken?, Never> { get }
A_19739
Original Requirement
A_19739 - E-Rezept FdV: verpflichtende Zertifikatsprüfung
Das E-Rezept-FdV MUSS alle Zertifikate, die es aktiv verwendet (bspw. TLS-Verbindungsaufbau), auf Integrität und Authentizität prüfen. Falls die Prüfung kein positives Ergebnis (“gültig”) liefert, so MUSS es die von dem Zertifikat und den darin enthaltenen Attributen (bspw. öffentliche Schlüssel) abhängenden Arbeitsabläufe ablehnen.
Das E-Rezept-FdV MUSS alle öffentlichen Schlüssel, die es verwenden will, auf eine positiv verlaufene Zertifikatsprüfung zurückführen können. [<=]
Implementation
For TLS certificates, this is implemented by not deactivating ATS within Info.plist
, path: NSAppTransportSecurity
. For TI Certificates, this is implemented within the TrustStore module.
../Sources/TrustStore/TrustStoreSession.swift:19
/// Request and validate the VAU certificate
///
/// [REQ:gemSpec_eRp_FdV:A_19739]
///
/// - Returns: A publisher that emits a validated VAU certificate or an error
func loadVauCertificate() -> AnyPublisher<X509, TrustStoreError>
../Sources/TrustStore/TrustStoreSession.swift:29
/// Try to validate a given certificate against the underlying truststore.
/// An OCSP response will also be requested and checked against
///
/// [REQ:gemSpec_eRp_FdV:A_19739]
///
/// - Parameter certificate: the certificate to be validated
/// - Returns: A publisher that emits a Boolean stating whether or not the certificate could be validated.
func validate(certificate: X509) -> AnyPublisher<Bool, TrustStoreError>
A_19979
Original Requirement
Implementation
We use external services: The Apothekenverzeichnis and our analytics framework. During the communication with the pharmacy, there will be data shared via a prescription code. The requirement to this feature is described in gemSpec_eRp_FdV sectin 5.2.3.10 and 5.2.3.11.
We do not share sensitive data with third parties. See data usages within O.Purp_8 and O.Arch_2.
A_19980
Original Requirement
Implementation
The user is informed and required to accept this information via the data protection statement. Related data and services are listed in sections 5.
../Sources/eRpApp/Screens/Settings/DataPrivacy/DataPrivacyView.swift:14
Actual View driving the display of DataPrivacy.html
// [REQ:BSI-eRp-ePA:O.Purp_1#2] Actual View driving the display of `DataPrivacy.html`
// [REQ:BSI-eRp-ePA:O.Arch_8#3] Webview containing local html without javascript
// [REQ:gemSpec_eRp_FdV:A_19980#2] Actual View driving the display of `DataPrivacy.html`
struct DataPrivacyView: View {
A_19981
Original Requirement
Implementation
The user is informed and required to accept this information via the data protection statement. Related data and services are listed in sections 5.
A_19982
Original Requirement
Implementation
The agreement to the use of the analytics framework can be revoked. But other agreements cannot be revoked, since the app would not operate properly.
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:157
Opt out of analytics
// Tracking
// [REQ:gemSpec_eRp_FdV:A_19088, A_19089-01#5, A_19092-01#4, A_19097-01#1] React to later opt-in or deactivation
// of usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_5#2] Actual disabling of analytics
// [REQ:gemSpec_eRp_FdV:A_19982#2] Opt out of analytics
case let .toggleTrackingTapped(optIn):
../Sources/eRpApp/Screens/Settings/SettingsView.swift:47
Show information dialog for analytics usage
// Tracking comply sheet presentation
// [REQ:BSI-eRp-ePA:O.Purp_5#3] Show comply view for settings triggered analytics enabling
// [REQ:gemSpec_eRp_FdV:A_19982#3,A_19089-01#3] Show information dialog for analytics usage
Rectangle()
../Sources/eRpApp/Screens/Settings/SettingsView.swift:161
Opt out of analytics
// [REQ:gemSpec_eRp_FdV:A_19097-01#2] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_5#1] Toggle within Settings to enable and disable usage analytics
// [REQ:BSI-eRp-ePA:O.Purp_6#1] Current Analytics state is inspectable by the user
// [REQ:gemSpec_eRp_FdV:A_19982#4] Opt out of analytics
Toggle(isOn: $store.trackerOptIn.sending(\.toggleTrackingTapped).animation()) {
A_19983
Original Requirement
Implementation
All used services except our analytics framework are permitted and attested by the Gematik and under the TI monitoring. The usage of our analytics framework is not under our control, but we exclusively send data to it and receive none.
A_19984
Original Requirement
Implementation
../Sources/Pharmacy/FHIRClient+PharmacyOperation.swift:24
validate pharmacy data format conforming to FHIR
/// Convenience function for searching for pharmacies
///
/// [REQ:gemSpec_eRp_FdV:A_19984] validate pharmacy data format conforming to FHIR
///
/// - Parameters:
/// - searchTerm: Search term
/// - position: Pharmacy position (latitude and longitude)
/// - Returns: `AnyPublisher` that emits a list of `PharmacyLocation`s or is empty when not found
public func searchPharmacies(by searchTerm: String,
../Sources/eRpKit/ScannedErxTask.swift:48
parse task id and access code
// [REQ:gemSpec_eRp_FdV:A_19984] parse task id and access code
guard let taskId = taskString.match(pattern: Self.taskIdRegex) else {
../Sources/eRpKit/ScannedErxTask.swift:103
validate data matrix code structure
// [REQ:gemSpec_eRp_FdV:A_19984] validate data matrix code structure
// [REQ:BSI-eRp-ePA:O.Source_1#4] actual validation by decoding into predefined structure
erxToken = try jsonDecoder.decode(ErxToken.self, from: jsonData)
../Sources/eRpRemoteStorage/FHIRClient+ErxTaskOperation.swift:246
validate pharmacy data format conforming to FHIR
/// Requests all communication Resources for the logged in user
///
/// [REQ:gemSpec_eRp_FdV:A_19984] validate pharmacy data format conforming to FHIR
///
/// - Returns: Array of all loaded communication resources
/// - Parameter referenceDate: Communications with `timestamp` greater or equal `referenceDate` will be fetched
public func communicationResources(
A_20032-01
Original Requirement
Implementation
Note: grace period for OCSP responses is 12h
../Sources/TrustStore/X509TrustStore.swift:14
// [REQ:gemSpec_Krypt:A_21218]
// [REQ:gemSpec_eRp_FdV:A_20032-01]
// Category A: Cross root certificates
private let rootCa: X509
../Sources/TrustStore/X509TrustStore.swift:106
/// Match a collection of `OCSPResponse`s with the end entity certificates of this `X509TrustStore`.
/// Checks response status, revocation status for each certificate and validates the signer certificates of
/// the responses itself.
///
/// [REQ:gemSpec_Krypt:A_21218]
/// [REQ:gemSpec_eRp_FdV:A_20032-01]
///
/// - Note: This function assumes that up-to-dateness of the responses itself has already been checked.
///
/// - Returns: true on successful matching/validation, false if not successful or error
func checkEeCertificatesStatus(with ocspResponses: [OCSPResponse]) throws -> Bool {
A_20033
Original Requirement
A_20033 - E-Rezept-FdV: Prüfung Internet-Zertifikate
Das E-Rezept-FdV MUSS für die Prüfung des internetseitigen Zertifikats von Diensten der TI das Zertifikat auf ein CA-Zertifikat einer CA, die die “CA/Browser Forum Baseline Requirements for the Issuance and Management of Publicly-Trusted Certificates” (https://cabforum.org/baseline-requirements-documents/) erfüllt, kryptographisch (Signaturprüfung) zurückführen können. Ansonsten MUSS es das Zertifikat als “ungültig” bewerten.
Das E-Rezept-FdV MUSS die zeitliche Gültigkeit des Zertifikats prüfen. Falls diese Prüfung negativ ausfällt, muss es das Zertifikat als “ungültig” bewerten. [<=]
Implementation
For TLS certificates, this is implemented by not deactivating ATS within Info.plist
, path: NSAppTransportSecurity
. For TI Certificates, this is implemented within the TrustStore module.
A_20167-02
Original Requirement
A_20167-02 - E-Rezept-FdV: Authentisierung E-Rezept-Fachdienst - IDP-Dienst - Rolle Anwendungsfrontend und optional Authenticator-Modul
Das E-Rezept-FdV MUSS, wenn es eine Authentifizierung des Nutzers über den IDP-Dienst, in seiner Rolle als Authorization-Server, unterstützt, entweder als anfragendes Anwendungsfrontend und Authenticator-Modul oder, wenn ein Authenticator-Modul in einer anderen für die TI zugelassene App genutzt wird, als anfragendes Anwendungsfrontend agieren. [<=]
Implementation
../Sources/eRpApp/Data/PrescriptionRepository.swift:133
no token/not authorized, show authenticator module
// [REQ:gemSpec_eRp_FdV:A_20167-02#2,A_20172] no token/not authorized, show authenticator module
if Result.success(false) == isAuthenticated {
../Sources/eRpApp/Screens/Pharmacy/RedeemService/RedeemService.swift:151
no token/not authorized, show authenticator module
// [REQ:gemSpec_eRp_FdV:A_20167-02#3,A_20172] no token/not authorized, show authenticator module
if Result.success(false) == authenticated {
../Sources/IDP/IDPInterceptor.swift:61
no token available, bailout
// [REQ:gemSpec_eRp_FdV:A_20167-02#4] no token available, bailout
.authentication(error)
../Sources/IDP/IDPInterceptor.swift:71
invalidate/delete unauthorized token
// [REQ:gemSpec_eRp_FdV:A_20167-02#5] invalidate/delete unauthorized token
// [REQ:BSI-eRp-ePA:O.Source_5#2] invalidate/delete unauthorized token
self.session.invalidateAccessToken()
A_20172
Original Requirement
Implementation
../Sources/eRpApp/Data/PrescriptionRepository.swift:133
no token/not authorized, show authenticator module
// [REQ:gemSpec_eRp_FdV:A_20167-02#2,A_20172] no token/not authorized, show authenticator module
if Result.success(false) == isAuthenticated {
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Profile.swift:50
// [REQ:gemSpec_eRp_FdV:A_20172]
func idpChallengePublisher(for profileID: UUID) -> AsyncStream<CardWallReadCardDomain.Action> {
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Profile.swift:75
// [REQ:gemSpec_eRp_FdV:A_20172]
// [REQ:gemSpec_IDP_Frontend:A_20526-01] sign and verify with idp
func signChallengeWithNFCCard(
../Sources/eRpApp/Screens/CardWall/ReadCard/CardWallReadCardDomain.Environment+Profile.swift:107
// [REQ:gemSpec_eRp_FdV:A_20172]
// [REQ:gemSpec_IDP_Frontend:A_20526-01] verify with idp
func verifyResultWithIDP(
../Sources/eRpApp/Screens/Pharmacy/RedeemService/RedeemService.swift:151
no token/not authorized, show authenticator module
// [REQ:gemSpec_eRp_FdV:A_20167-02#3,A_20172] no token/not authorized, show authenticator module
if Result.success(false) == authenticated {
A_20181-01
Original Requirement
A_20181-01 - E-Rezept-FdV: E-Rezept-Token als 2D-Code anzeigen - personenbezogene Daten
Das E-Rezept-FdV DARF NICHT im Anwendungsfall “E-Rezept-Token als 2D-Code anzeigen” personenbezogene Daten zusammen mit der Anzeige des 2D-Codes anzeigen. [<=]
Implementation
Screen that presents the DataMatrix code for redeeming a prescription only contains some static texts and the image of the code.
../Sources/eRpApp/Screens/MatrixCode/MatrixCodeView.swift:17
Screen that presents the DataMatrix code for redeeming a prescription only
// [REQ:gemSpec_eRp_FdV:A_20181-01#2] Screen that presents the DataMatrix code for redeeming a prescription only
// contains some static texts and the image of the code.
struct MatrixCodeView: View {
A_20182
Original Requirement
A_20182 - E-Rezept-FdV - Makelverbot
Das E-Rezept-FdV DARF NICHT zusätzliche Funktionalitäten enthalten, die die berufs- oder gewerbsmäßige Zuweisung und das Makeln von E-Rezepten unterstützen oder den Nutzer in seiner Entscheidung beeinflussen, welche elektronischen Verordnungen in welcher Apotheke eingelöst werden. [<=]
Implementation
No advertisement or similar is presented in the app. Assigning a prescription to an pharmacy in only possible via the app’s pharmacy search. Pharmacy search results are only based on search term and filter criteria set by the user.
A_20183
Original Requirement
Implementation
../Sources/Pharmacy/PharmacyFHIRDataSource.swift:31
/// API for requesting pharmacies with the passed search term
///
/// [REQ:gemSpec_eRp_FdV:A_20183]
///
/// - Parameter searchTerm: String that send to the server for filtering the pharmacies response
/// - Parameter position: Position (latitude and longitude) of pharmacy
/// - Parameter filter: further filter parameters for pharmacies
/// - Returns: `AnyPublisher` that emits all `PharmacyLocation`s for the given `searchTerm`
public func searchPharmacies(by searchTerm: String,
../Sources/Pharmacy/PharmacyRemoteDataStore.swift:22
/// API for requesting pharmacies with the passed search term
///
/// [REQ:gemSpec_eRp_FdV:A_20183]
///
/// - Parameter searchTerm: String that send to the server for filtering the pharmacies response
/// - Parameter position: Position (latitude and longitude) of pharmacy
/// - Parameter filter: further filter parameters for pharmacies
/// - Returns: `AnyPublisher` that emits all `PharmacyLocation`s for the given `searchTerm`
func searchPharmacies(by searchTerm: String,
../Sources/eRpApp/Screens/Pharmacy/Search/PharmacySearchDomain.swift:396
search results mirrored verbatim, no sorting, no highlighting
// [REQ:gemSpec_eRp_FdV:A_20183] search results mirrored verbatim, no sorting, no highlighting
state.searchState = .searchRunning
../Sources/eRpApp/Screens/Pharmacy/Search/PharmacySearchMapDomain.swift:254
search results mirrored verbatim, no sorting, no highlighting
// [REQ:gemSpec_eRp_FdV:A_20183] search results mirrored verbatim, no sorting, no highlighting
return .run { [center = state.mapLocation.region.center, filter = state.pharmacyFilterOptions] send in
A_20184
Original Requirement
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:123
// [REQ:gemSpec_eRp_FdV:A_20184]
// [REQ:gemSpec_IDP_Frontend:A_21328#3] KeychainStorage implementation
let success: Bool
../Sources/eRpApp/Session/StandardSessionContainer.swift:91
Keychain storage encrypts session/ssl tokens
// [REQ:gemSpec_IDP_Frontend:A_21328#2] Keychain storage encrypts session tokens
// [REQ:gemSpec_eRp_FdV:A_20184] Keychain storage encrypts session/ssl tokens
storage: secureUserStore,
../Sources/eRpApp/Session/StandardSessionContainer.swift:109
No persistent storage for idp pairing session
storage: MemoryStorage(), // [REQ:gemSpec_eRp_FdV:A_20184] No persistent storage for idp pairing session
schedulers: schedulers,
A_20185
Original Requirement
Implementation
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:159
OptOut for user
// [REQ:gemSpec_eRp_FdV:A_20185,A_20187] OptOut for user
state.trackerOptIn = false
Token invalidation happens after 12 hours as the IDP provied SSO-Token is no longer valid after that time.
A_20186
Original Requirement
Implementation
../Sources/eRpApp/Session/KeychainStorage.swift:248
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-1#3] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
set(can: nil)
../Sources/eRpApp/Session/ProfileSecureDataWiper.swift:41
Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_20499,A_20499-01#2] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_eRp_FdV:A_20186] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
// [REQ:gemSpec_IDP_Frontend:A_21603] Certificate
// [REQ:BSI-eRp-ePA:O.Auth_14#4] Deletion of SSO_TOKEN, ID_TOKEN, AUTH_TOKEN
storage.wipe()
A_20187
Original Requirement
Implementation
../Sources/eRpApp/Screens/Settings/SettingsDomain.swift:159
OptOut for user
// [REQ:gemSpec_eRp_FdV:A_20185,A_20187] OptOut for user
state.trackerOptIn = false
A_20193
Original Requirement
Implementation
Camera is only used for scanning recipes and avatar setup. CoreLocation is used for pharmacy search. Usage is requested before actual first usage, the user is asked for permission. This is also enforced by the OS.
A_20194
Original Requirement
Implementation
Camera is only used for scanning recipes and avatar setup. CoreLocation is used for pharmacy search. Usage is requested before actual first usage, the user is asked for permission. This is also enforced by the OS.
A_20202
Original Requirement
Implementation
Camera is only used for scanning recipes and avatar setup. CoreLocation is used for pharmacy search. Usage is requested before actual first usage, the user is asked for permission. This is also enforced by the OS.
A_20206
Original Requirement
Implementation
../Sources/HTTPClient/DefaultHTTPClient.swift:35
// [REQ:gemSpec_Krypt:GS-A_4385,A_18467,A_18464,GS-A_4387]
// [REQ:gemSpec_IDP_Frontend:A_20606#2] Setup of minimum TLS Version to use.
// [REQ:gemSpec_eRp_FdV:A_20206]
// [REQ:BSI-eRp-ePA:O.Ntwk_2#2,O.Ntwk_3#2,O.Ntwk_7#2] URLSession is used as Network Framework
urlSessionConfiguration.tlsMinimumSupportedProtocolVersion = .TLSv12
A_20208
Original Requirement
Implementation
../Sources/Pharmacy/PharmacyFHIROperation.swift:14
/// Search for pharmacies by name
/// [REQ:gemSpec_eRp_FdV:A_20208]
case searchPharmacies(searchTerm: String, position: Position?, filter: [String: String], handler: Handler)
A_20285
Original Requirement
A_20285 - E-Rezept-FdV: Wettbewerbsneutralität für Darstellung Apotheken
Das E-Rezept-FdV MUSS Apotheken wettbewerbsneutral darstellen (bspw. Sortierung nach Alphabet oder Entfernung vom aktuellen Standort des Nutzers). [<=]
Implementation
../Sources/eRpApp/Screens/Pharmacy/Search/PharmacySearchDomain.swift:405
pharmacy order is resolved on server side
// [REQ:gemSpec_eRp_FdV:A_20285] pharmacy order is resolved on server side
state.pharmacies = pharmacies
../Sources/eRpApp/Screens/Pharmacy/Search/PharmacySearchMapDomain.swift:268
pharmacy order is resolved on server side
// [REQ:gemSpec_eRp_FdV:A_20285] pharmacy order is resolved on server side
state.pharmacies = pharmacies.map {
A_20603
Original Requirement
Implementation
../Sources/eRpApp/Screens/Main/PrescriptionDetail/PrescriptionDetailDomain.swift:92
Usages of matrixCodeGenerator for code generation. UserProfile is neither part of
// [REQ:gemSpec_eRp_FdV:A_20603] Usages of matrixCodeGenerator for code generation. UserProfile is neither part of
// the screen nor the state.
@Dependency(\.erxMatrixCodeGenerator) var matrixCodeGenerator: ErxMatrixCodeGenerator
../Sources/eRpApp/Screens/MatrixCode/MatrixCodeDomain.swift:71
Usages of matrixCodeGenerator for code generation. UserProfile is neither part of
// [REQ:gemSpec_eRp_FdV:A_20603] Usages of matrixCodeGenerator for code generation. UserProfile is neither part of
// the screen nor the state.
@Dependency(\.erxMatrixCodeGenerator) var erxMatrixCodeGenerator: ErxMatrixCodeGenerator
A_22778-01
Original Requirement
A_22778-01 - E-Rezept-FdV - Einlösen ohne Anmelden - Verschlüsselung mit C.HCI.ENC
Das E-Rezept-FdV MUSS im Anwendungsfall “Einlösen ohne Anmelden” die Nachricht des Versicherten mit allen bereitgestellten C.HCI.ENC Zertifikaten (inkl. der verschiedenen kryptografischen Verfahren) der adressierten Apotheke (Verschlüsselungszertifikat der SMC-B C.HCI.ENC) verschlüsseln. [<=]
Implementation
Encryption of message to the Pharmacy is done with/for all provided certificates/recipients.
../Sources/AVS/AVSCmsEncrypter.swift:10
Encryption of message to the Pharmacy is done for all provided recipients
// [REQ:gemSpec_eRp_FdV:A_22778-01#2] Encryption of message to the Pharmacy is done for all provided recipients
func cmsEncrypt(_ data: Data, recipients: [X509]) throws -> Data
../Sources/AVS/AVSCmsEncrypter.swift:22
Encryption of message to the Pharmacy is done with all provided
// [REQ:gemSpec_Krypt:GS-A_4390] RSAES-OAEP with MGF1 implemented in sub-framework OpenSSL-swift
// [REQ:gemSpec_eRp_FdV:A_22778-01#3] Encryption of message to the Pharmacy is done with all provided
// certificates
// [REQ:gemSpec_eRp_FdV:A_22779-01#3] Encrypted message is of form of a PKCS#7 container (CMS)
// https://github.com/gematik/OpenSSL-Swift/blob/3c1ea91ba5abfefecfe3588815cb928d777e29ad/Sources/OpenSSL/CMS/CMSContentInfo.swift#L88
// swiftlint:disable:previous line_length
let cms = try CMSContentInfo.encryptPartial(data: data)
A_22779-01
Original Requirement
A_22779-01 - E-Rezept-FdV - Einlösen ohne Anmelden - Nachricht verschlüsseln
Das E-Rezept-FdV MUSS im Anwendungsfall “Einlösen ohne Anmelden” die Daten ausschließlich als PKCS#7 verschlüsselten Datensatz (CMS) bereitstellen. [<=]
Implementation
Encrypted message is of form of a PKCS#7 container (CMS)
../Sources/AVS/AVSMessageConverter.swift:32
Encrypted message is of form of a PKCS#7 container (CMS)
// [REQ:gemSpec_eRp_FdV:A_22779-01#2] Encrypted message is of form of a PKCS#7 container (CMS)
// 1. Create a CMS AuthenticatedEnvelopedData structure with help from OpenSSL-swift
let cmsAuthEnvelopedData = try avsCmsEncrypter.cmsEncrypt(data, recipients: recipients)
../Sources/AVS/AVSCmsEncrypter.swift:24
Encrypted message is of form of a PKCS#7 container (CMS)
// [REQ:gemSpec_Krypt:GS-A_4390] RSAES-OAEP with MGF1 implemented in sub-framework OpenSSL-swift
// [REQ:gemSpec_eRp_FdV:A_22778-01#3] Encryption of message to the Pharmacy is done with all provided
// certificates
// [REQ:gemSpec_eRp_FdV:A_22779-01#3] Encrypted message is of form of a PKCS#7 container (CMS)
// https://github.com/gematik/OpenSSL-Swift/blob/3c1ea91ba5abfefecfe3588815cb928d777e29ad/Sources/OpenSSL/CMS/CMSContentInfo.swift#L88
// swiftlint:disable:previous line_length
let cms = try CMSContentInfo.encryptPartial(data: data)
A_24525
Original Requirement
A_24525 - E-Rezept-FdV Tracking-Funktionen als Opt-in
Das E-Rezept-FdV MUSS, falls es Tracking-Funktionen implementiert, die Tracking-Daten mehrerer Nutzersessions verknüpfen, technisch sicherstellen, dass diese Tracking-Funktionen bei der Installation des FdV standardmäßig deaktiviert sind und nur nach expliziter Einwilligung durch den Versicherten als Nutzer des FdV aktiviert werden (Opt-in). [<=]
Implementation
Whether analytics are enabled or not is persisted using UserDefaults
. As these usere Defaults are empty upon installation, any call to bool(for:)
will return to false. Opt-In for Analytics will be asked while the app onboarding runs.
../Sources/eRpApp/Tracking/ContentSquareAnalyticsAdapter.swift:37
Calculate if analytics are enabled or not.
// [REQ:gemSpec_eRp_FdV:A_24525#2] Calculate if analytics are enabled or not.
userDefaults.appTrackingAllowed
A_24579
Original Requirement
A_24579 - E-Rezept-FdV: Apotheke suchen: neutrale Darstellung der Optionen
Das E-Rezept-FdV MUSS im Anwendungsfall “Apotheke suchen” die Apothekensuche und die Suchergebnisse so darstellen, dass Belieferungsoptionen nicht hervorgehoben oder bevorzugt werden. [<=]
Implementation
See snapshot test (e.g. ‘testPharmacySearch_searchResultSuccess.iPhone8-light.png’) or the actual app to verify.
A_24857
Original Requirement
A_24857 - E-Rezept-FdV: Authentifizierung des Nutzers am E-Rezept-FdV zum Start des E-Rezept-FdV
Das E-Rezept-FdV MUSS den Nutzer beim Starten des E-Rezept-FdV am E-Rezept-FdV authentisieren. [<=]
Implementation
../Sources/eRpApp/SceneDelegate.swift:180
Present the authentication window upon every startup
// [REQ:BSI-eRp-ePA:O.Auth_8#2] Present the authentication window
// [REQ:gemSpec_eRp_FdV:A_24857#2] Present the authentication window upon every startup
// dispatching necessary to prevents keyboard not showing on iOS 16
DispatchQueue.main.async { [weak self] in