{ lib, config, pkgs, ... }: with lib; let cfg = config.my.yubikey; inherit (config.host) username; formatKey = key: ":${key.handle},${key.userKey},${key.coseType},${key.options}"; authfileContent = u: keys: u + lib.concatMapStrings formatKey keys; in { options.my.yubikey = { enable = mkEnableOption "YubiKey"; pam = { enable = mkEnableOption "YubiKey PAM U2F"; origin = mkOption { type = types.str; default = "pam://yubi"; }; keys = mkOption { type = types.listOf ( types.submodule { options = { handle = mkOption { type = types.str; example = ""; }; userKey = mkOption { type = types.str; example = ""; }; coseType = mkOption { type = types.str; default = "es256"; }; options = mkOption { type = types.str; default = ""; }; }; } ); default = [ ]; }; }; }; config = mkMerge [ (mkIf cfg.enable { services.udev.packages = with pkgs; [ yubikey-manager yubikey-personalization ]; }) (mkIf (cfg.enable && cfg.pam.enable) { security.pam = { u2f = { enable = true; settings = { interactive = true; cue = true; origin = cfg.pam.origin; authfile = pkgs.writeText "u2f-mappings" (authfileContent username cfg.pam.keys); }; }; services = { login.u2fAuth = true; sudo.u2fAuth = true; }; }; }) ]; }