Téléverser les fichiers vers "modules"

This commit is contained in:
2026-08-19 11:40:56 +02:00
parent c7e98d14a4
commit 2ab3c19731
3 changed files with 36 additions and 77 deletions
+29 -36
View File
@@ -136,15 +136,20 @@ let
executable = true;
text = ''
#!${pinPython}/bin/python3
"""Change a FIDO2 PIN without exposing secrets in argv.
"""Initialize the PIN of a virgin FIDO2 authenticator.
STEP 1 LAB contract:
- exactly one FIDO2 HID device must be connected;
- the authenticator must support CTAP2;
- no FIDO2 PIN must currently be configured;
- the new PIN and its confirmation arrive on stdin;
- secrets are never placed in argv or emitted in output.
Input on stdin, one UTF-8 line each:
1. current PIN
2. new PIN
3. confirmation
1. new PIN
2. confirmation
Output contains technical tokens only, never the PIN values.
Exactly one CTAP2 change_pin operation is attempted.
Output contains technical tokens only, never PIN values.
"""
import sys
@@ -167,22 +172,16 @@ let
return value.rstrip("\r\n")
current = read_secret()
new_pin = read_secret()
confirmation = read_secret()
if new_pin != confirmation:
fail("CONFIRM_MISMATCH", 31)
if len(current) < 4 or len(new_pin) < 4:
fail("PIN_POLICY", 32)
# CTAP2 PINs are UTF-8 strings with a maximum encoded size of 63 bytes.
if len(current.encode("utf-8")) > 63 or len(new_pin.encode("utf-8")) > 63:
if len(new_pin) < 4 or len(new_pin.encode("utf-8")) > 63:
fail("PIN_POLICY", 32)
devices = []
device = None
try:
devices = list(CtapHidDevice.list_devices())
@@ -201,57 +200,51 @@ let
ctap = Ctap2(device)
info = ctap.get_info()
# clientPin=True means a PIN is currently configured.
if not info.options.get("clientPin", False):
fail("PIN_NOT_CONFIGURED", 36)
# Étape 1 stricte : on ne doit jamais tenter de valider/changer
# un PIN existant. Ce contrôle ne consomme aucune tentative de PIN.
if info.options.get("clientPin", False):
fail("PIN_ALREADY_CONFIGURED", 36)
client_pin = ClientPin(ctap)
client_pin.set_pin(new_pin)
# IMPORTANT: exactly one PIN-changing command. Do not verify the old PIN
# first: that would add an unnecessary extra PIN operation.
client_pin.change_pin(current, new_pin)
# GET_INFO ne consomme pas de tentative de PIN. Vérifier que la clé
# annonce désormais bien clientPin=True avant de déclarer le succès.
if not ctap.get_info().options.get("clientPin", False):
fail("PIN_STATE_NOT_UPDATED", 37)
# Forget Python references as soon as the operation is complete.
current = ""
new_pin = ""
confirmation = ""
print("OK", flush=True)
raise SystemExit(0)
except CtapError as exc:
code = exc.code
if code == CtapError.ERR.PIN_INVALID:
fail("WRONG_PIN", 40)
if code == CtapError.ERR.PIN_AUTH_BLOCKED:
fail("PIN_AUTH_BLOCKED", 41)
if code == CtapError.ERR.PIN_BLOCKED:
fail("PIN_BLOCKED", 42)
if code == CtapError.ERR.PIN_NOT_SET:
fail("PIN_NOT_CONFIGURED", 43)
if code == CtapError.ERR.PIN_POLICY_VIOLATION:
fail("PIN_POLICY", 44)
if code == CtapError.ERR.PIN_NOT_SET:
fail("PIN_STATE_ERROR", 45)
fail("PIN_FAILED", 45)
fail("PIN_FAILED", 46)
except (PermissionError, OSError):
fail("NO_YUBIKEY", 46)
fail("NO_YUBIKEY", 47)
except ValueError:
# python-fido2 may reject an invalid PIN before sending CTAP2.
fail("PIN_POLICY", 47)
fail("PIN_POLICY", 48)
except SystemExit:
raise
except Exception:
# Do not expose exception text: it could contain device/environment
# details and is not needed by the UI. The setup log stores the token.
fail("PIN_HELPER_ERROR", 48)
fail("PIN_HELPER_ERROR", 49)
finally:
current = ""
new_pin = ""
confirmation = ""
for dev in devices:
@@ -264,7 +257,7 @@ let
workstationSetup = pkgs.stdenv.mkDerivation {
pname = "nixos-workstations-setup";
version = "1.5.0";
version = "1.6.0";
src = ../workstation-setup;
@@ -301,7 +294,7 @@ let
state_dir="''${XDG_STATE_HOME:-$HOME/.local/state}/nixos-workstations"
password_marker="$state_dir/password-initialized"
pin_marker="$state_dir/yubikey-pin-initialized"
pin_marker="$state_dir/yubikey-pin-created"
# Une session déjà finalisée n'affiche plus l'assistant.
if [ -e "$password_marker" ] && [ -e "$pin_marker" ]; then