main
 1{
 2  lib,
 3  pkgs,
 4  desktop,
 5  ...
 6}:
 7{
 8  environment.systemPackages =
 9    with pkgs;
10    [
11      age-plugin-yubikey
12      yubico-piv-tool
13      yubikey-personalization
14      yubikey-manager
15      yubikey-agent
16      openssh-askpass # GTK askpass for FIDO2 PIN prompts
17    ]
18    ++ lib.optionals (builtins.isString desktop) [
19      yubioath-flutter # Maybe not necessary
20    ];
21
22  programs.yubikey-touch-detector.enable = builtins.isString desktop;
23
24  services = {
25    pcscd.enable = true;
26    udev = {
27      packages = [ pkgs.yubikey-personalization ];
28      # FIXME: is it necessary ?
29      extraRules = ''
30        # Yubico YubiKey
31        KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0113|0114|0115|0116|0120|0402|0403|0406|0407|0410", TAG+="uaccess", MODE="0660", GROUP="wheel"
32        # ACTION=="remove", ENV{ID_VENDOR_ID}=="1050", ENV{ID_MODEL_ID}=="0113|0114|0115|0116|0120|0402|0403|0406|0407|0410", RUN+="${pkgs.systemd}/bin/loginctl lock-sessions"
33      '';
34    };
35  };
36
37  security.pam.u2f = {
38    enable = true;
39    settings = {
40      origin = "pam://yubi";
41      authfile = pkgs.writeText "u2f-mappings" (
42        lib.concatStrings [
43          "vincent"
44          ":4IiWZI9g6D8W6LeAW13ug4CnS8PreNRcHdcebkUDny3gWGfmpMJg4TgBWaZSIdh+sgg4jQA4MxYwTCmmP/ipWQ==,qOl+ouBRk6MMEJiE7H5LuTAirhBhN0UQrCNlLQoRsVttp6IBKG4yq4zDwm4fmYlfy1MFhvh7oOapMOmodMKJpQ==,es256,+presence" # yubikey5-a
45          ":Sz4J2qMhoE7bE/uzwUzjJxG/bE0s+cw18zXcQjRsLIdJTVbuMad1ivKlYeLZW6vWV0lYiODlRW21HTSaFzu06A==,p7OZ3z5fiAIuJRHVzm56Y8Ti934+4cVHjsG7kaapmz8cWPfXfXfj5c8QiyIz3EQ0hOoxVV5cbkzUTxe7hdQIsA==,es256,+presence" # yubikey5-c1
46          ":ofF2mo6vyUqsgdIYEF7SLrpA9CuJkQrktzvhZMJPssK5oZX34+NwikZil7cUAe+ceiqfMCBKAdDcfISZe0FVEQ==,iJjAhEUExKa2xvAOtBd34YF0bJuYaT7oKxIKQF0WJqoeaQIHhPE8NNkDNykMNDI+hNxYYcJZqX5Q1lZ3K+Ei5Q==,es256,+presence" # yubikey5-c2 (okinawa)
47        ]
48      );
49    };
50  };
51
52  programs.gnupg.agent.pinentryPackage = pkgs.pinentry-gnome3;
53
54  # SSH agent with FIDO2 support
55  # Uses NixOS's startAgent which sets SSH_ASKPASS in the agent's environment.
56  # The silent askpass auto-confirms "Confirm user presence" prompts (yubikey-touch-detector
57  # already shows a desktop notification), while falling back to GTK for PIN/passphrase prompts.
58  programs.ssh = {
59    startAgent = true;
60    enableAskPassword = true;
61    askPassword = "${pkgs.writeShellScript "ssh-askpass-silent" ''
62      case "$1" in
63        *PIN*|*passphrase*|*password*)
64          exec ${pkgs.openssh-askpass}/libexec/gtk-ssh-askpass "$@"
65          ;;
66      esac
67      exit 0
68    ''}";
69  };
70
71  # Disable GNOME's gcr-ssh-agent (conflicts with programs.ssh.startAgent)
72  # niri module enables gnome-keyring which enables gcr-ssh-agent by default
73  services.gnome.gcr-ssh-agent.enable = false;
74
75  # SSH_ASKPASS_REQUIRE for the user environment (agent confirmation prompts)
76  environment.variables.SSH_ASKPASS_REQUIRE = "prefer";
77
78  # Disabled - using FIDO2 keys with ssh-agent instead of PIV with yubikey-agent
79  services.yubikey-agent.enable = false;
80  # systemd.packages = [ pkgs.yubikey-agent ];
81
82  # This overrides the systemd user unit shipped with the
83  # yubikey-agent package
84  # systemd.user.services.yubikey-agent =
85  #   lib.mkIf (config.programs.gnupg.agent.pinentryPackage != null)
86  #     {t
87  #       path = [ config.programs.gnupg.agent.pinentryPackage ];
88  #       wantedBy = [ "default.target" ];
89  #     };
90}