Add enable EA

This commit is contained in:
Elias Bonnici 2024-07-03 16:15:12 +02:00
parent c90ba130ce
commit bb0c9480b6
No known key found for this signature in database
GPG Key ID: 5EAC28EA3F980CCF
14 changed files with 142 additions and 2 deletions

View File

@ -22,7 +22,7 @@ from .base import (
PinComplexityException,
)
from fido2.ctap import CtapError
from fido2.ctap2 import Ctap2, ClientPin
from fido2.ctap2 import Ctap2, ClientPin, Config
from fido2.ctap2.credman import CredentialManagement
from fido2.ctap2.bio import BioEnrollment, FPBioEnrollment, CaptureError
from fido2.pcsc import CtapPcscDevice
@ -199,6 +199,8 @@ class Ctap2Node(RpcNode):
permissions |= ClientPin.PERMISSION.CREDENTIAL_MGMT
if BioEnrollment.is_supported(self._info):
permissions |= ClientPin.PERMISSION.BIO_ENROLL
if Config.is_supported(self._info):
permissions |= ClientPin.PERMISSION.AUTHENTICATOR_CFG
try:
if permissions:
self._token = self.client_pin.get_pin_token(pin, permissions)
@ -228,6 +230,14 @@ class Ctap2Node(RpcNode):
except CtapError as e:
return _handle_pin_error(e, self.client_pin)
@action(condition=lambda self: Config.is_supported(self._info))
def enable_ep_attestation(self, params, event, signal):
if self._info.options["clientPin"] and not self._token:
raise AuthRequiredException()
config = Config(self.ctap, self.client_pin.protocol, self._token)
config._call(Config.CMD.ENABLE_ENTERPRISE_ATT)
return dict()
@child(condition=lambda self: BioEnrollment.is_supported(self._info))
def fingerprints(self):
if not self._token:

View File

@ -161,6 +161,12 @@ class _FidoStateNotifier extends FidoStateNotifier {
throw decodedException;
}
}
@override
Future<void> enableEnterpriseAttestation() {
// TODO: implement enableEnterpriseAttestation
throw UnimplementedError();
}
}
final androidFingerprintProvider = AsyncNotifierProvider.autoDispose

View File

@ -184,6 +184,12 @@ class _DesktopFidoStateNotifier extends FidoStateNotifier {
rethrow;
}
}
@override
Future<void> enableEnterpriseAttestation() async {
await _session.command('enable_ep_attestation');
ref.invalidateSelf();
}
}
final desktopFingerprintProvider = AsyncNotifierProvider.autoDispose

View File

@ -21,6 +21,8 @@ final actions = fido.feature('actions');
final actionsPin = actions.feature('pin');
final actionsAddFingerprint = actions.feature('addFingerprint');
final actionsReset = actions.feature('reset');
final enableEnterpriseAttestation =
actions.feature('enableEnterpriseAttestation');
final credentials = fido.feature('credentials');

View File

@ -25,6 +25,8 @@ const _credentialInfo = '$_prefix.credential.info';
// Key actions
const managePinAction = Key('$_keyAction.manage_pin');
const addFingerprintAction = Key('$_keyAction.add_fingerprint');
const enableEnterpriseAttestation =
Key('$_keyAction.enable_enterprise_attestation');
const newPin = Key('$_keyAction.new_pin');
const confirmPin = Key('$_keyAction.confirm_pin');
const currentPin = Key('$_keyAction.current_pin');

View File

@ -50,6 +50,8 @@ class FidoState with _$FidoState {
bool get forcePinChange => info['force_pin_change'] == true;
bool get pinBlocked => pinRetries == 0;
bool? get enterpriseAttestation => info['options']['ep'];
}
@freezed

View File

@ -41,6 +41,7 @@ abstract class FidoStateNotifier extends ApplicationStateNotifier<FidoState> {
Stream<InteractionEvent> reset();
Future<PinResult> setPin(String newPin, {String? oldPin});
Future<PinResult> unlock(String pin);
Future<void> enableEnterpriseAttestation();
}
final fingerprintProvider = AsyncNotifierProvider.autoDispose

View File

@ -0,0 +1,50 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../app/message.dart';
import '../../app/models.dart';
import '../../app/state.dart';
import '../../widgets/responsive_dialog.dart';
import '../state.dart';
class EnableEnterpriseAttestationDialog extends ConsumerWidget {
final DevicePath devicePath;
const EnableEnterpriseAttestationDialog(this.devicePath, {super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = AppLocalizations.of(context)!;
return ResponsiveDialog(
title: Text(l10n.s_enable_ep_attestation),
actions: [
TextButton(
onPressed: () async {
await ref
.read(fidoStateProvider(devicePath).notifier)
.enableEnterpriseAttestation();
await ref.read(withContextProvider)((context) async {
Navigator.of(context).pop();
showMessage(context, l10n.s_ep_attestation_enabled);
});
},
child: Text(l10n.s_enable),
),
],
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(l10n.p_enable_ep_attestation_desc),
]
.map((e) => Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: e,
))
.toList(),
),
),
);
}
}

View File

@ -25,6 +25,7 @@ import '../features.dart' as features;
import '../keys.dart' as keys;
import '../models.dart';
import 'add_fingerprint_dialog.dart';
import 'enterprise_attestation_dialog.dart';
import 'pin_dialog.dart';
bool passkeysShowActionsNotifier(FidoState state) {
@ -50,6 +51,12 @@ Widget _fidoBuildActions(BuildContext context, DeviceNode node, FidoState state,
Theme.of(context).colorScheme;
final authBlocked = state.pinBlocked;
final enterpriseAttestation = state.enterpriseAttestation;
final canEnableEnterpriseAttestation = state.enterpriseAttestation == false &&
!(state.alwaysUv && !state.hasPin) &&
!(!state.unlocked && state.hasPin);
return Column(
children: [
if (fingerprints != null)
@ -115,8 +122,27 @@ Widget _fidoBuildActions(BuildContext context, DeviceNode node, FidoState state,
}
: null,
),
if (enterpriseAttestation != null)
ActionListItem(
key: keys.enableEnterpriseAttestation,
feature: features.enableEnterpriseAttestation,
icon: const Icon(Symbols.local_police),
title: l10n.s_ep_attestation,
subtitle:
enterpriseAttestation ? l10n.s_enabled : l10n.s_disabled,
onTap: canEnableEnterpriseAttestation
? (context) {
Navigator.of(context).popUntil((route) => route.isFirst);
showBlurDialog(
context: context,
builder: (context) =>
EnableEnterpriseAttestationDialog(node.path),
);
}
: null,
)
],
)
),
],
);
}

View File

@ -30,6 +30,9 @@
"s_delete": "Löschen",
"s_move": null,
"s_quit": "Beenden",
"s_enable": null,
"s_enabled": null,
"s_disabled": null,
"s_status": null,
"s_unlock": "Entsperren",
"s_calculate": "Berechnen",
@ -301,6 +304,10 @@
"common_pin": {}
}
},
"s_ep_attestation": null,
"s_ep_attestation_enabled": null,
"s_enable_ep_attestation": null,
"p_enable_ep_attestation_desc": null,
"s_pin_required": null,
"p_pin_required_desc": null,
"l_piv_pin_blocked": null,

View File

@ -30,6 +30,9 @@
"s_delete": "Delete",
"s_move": "Move",
"s_quit": "Quit",
"s_enable": "Enable",
"s_enabled": "Enabled",
"s_disabled": "Disabled",
"s_status": "Status",
"s_unlock": "Unlock",
"s_calculate": "Calculate",
@ -301,6 +304,10 @@
"common_pin": {}
}
},
"s_ep_attestation": "Enterprise Attestation",
"s_ep_attestation_enabled": "Enterprise Attestation enabled",
"s_enable_ep_attestation": "Enable Enterprise Attestation",
"p_enable_ep_attestation_desc": "This will enable Enterprise Attestation, allowing authorized domains to uniquely identify your YubiKey.",
"s_pin_required": "PIN required",
"p_pin_required_desc": "The action you are about to perform requires the PIV PIN to be entered.",
"l_piv_pin_blocked": "Blocked, use PUK to reset",

View File

@ -30,6 +30,9 @@
"s_delete": "Supprimer",
"s_move": "Déplacer",
"s_quit": "Quitter",
"s_enable": null,
"s_enabled": null,
"s_disabled": null,
"s_status": "État",
"s_unlock": "Déverrouiller",
"s_calculate": "Calculer",
@ -301,6 +304,10 @@
"common_pin": {}
}
},
"s_ep_attestation": null,
"s_ep_attestation_enabled": null,
"s_enable_ep_attestation": null,
"p_enable_ep_attestation_desc": null,
"s_pin_required": "PIN requis",
"p_pin_required_desc": "L'action que vous allez effectuer nécessite la saisie du PIN PIV.",
"l_piv_pin_blocked": "Bloqué, utilisez PUK pour réinitialiser",

View File

@ -30,6 +30,9 @@
"s_delete": "削除",
"s_move": "移動",
"s_quit": "終了",
"s_enable": null,
"s_enabled": null,
"s_disabled": null,
"s_status": "ステータス",
"s_unlock": "ロック解除",
"s_calculate": "計算",
@ -301,6 +304,10 @@
"common_pin": {}
}
},
"s_ep_attestation": null,
"s_ep_attestation_enabled": null,
"s_enable_ep_attestation": null,
"p_enable_ep_attestation_desc": null,
"s_pin_required": "PINが必要",
"p_pin_required_desc": "実行しようとしているアクションでは、PIV PINを入力する必要があります。",
"l_piv_pin_blocked": "ブロックされています。リセットするにはPUKを使用してください",

View File

@ -30,6 +30,9 @@
"s_delete": "Usuń",
"s_move": null,
"s_quit": "Wyjdź",
"s_enable": null,
"s_enabled": null,
"s_disabled": null,
"s_status": "Status",
"s_unlock": "Odblokuj",
"s_calculate": "Oblicz",
@ -301,6 +304,10 @@
"common_pin": {}
}
},
"s_ep_attestation": null,
"s_ep_attestation_enabled": null,
"s_enable_ep_attestation": null,
"p_enable_ep_attestation_desc": null,
"s_pin_required": "Wymagany PIN",
"p_pin_required_desc": "Czynność, którą zamierzasz wykonać, wymaga wprowadzenia kodu PIN PIV.",
"l_piv_pin_blocked": "Zablokowano, użyj PUK, aby zresetować",