forked from
lass.pds.lassul.us/superconfig
This repository has no description
4.2 kB
134 lines
1{ self, ... }:
2{
3 perSystem =
4 { pkgs, ... }:
5 let
6 lib = pkgs.lib;
7
8 # Generate key entries from flake structure
9 sshKeyEntries = lib.concatStringsSep "\n" (
10 lib.mapAttrsToList (
11 name: key:
12 if key.encrypted && key.private != null then
13 ''
14 ["${name}"]="${key.private}"
15 ''
16 else
17 ""
18 ) self.keys.ssh
19 );
20 in
21 {
22 packages.ssh-with-age = (pkgs.writeShellApplication {
23 name = "ssh-with-age";
24 runtimeInputs = [
25 pkgs.openssh
26 pkgs.age
27 pkgs.age-plugin-se
28 pkgs.age-plugin-yubikey
29 pkgs.libfido2
30 ];
31 text = ''
32 # SSH wrapper that tries each encrypted SSH key with the connected FIDO2 device
33
34 # Key mapping from flake
35 declare -A SSH_KEYS
36 ${sshKeyEntries}
37
38 usage() {
39 echo "Usage: ssh-with-age [ssh_options...] destination"
40 echo " ssh-with-age --list-keys"
41 echo " ssh-with-age --list-devices"
42 echo ""
43 echo "Tries each encrypted SSH key to find one that works with the connected FIDO2 device."
44 exit 1
45 }
46
47 list_keys() {
48 echo "Available encrypted SSH keys:"
49 for key in "''${!SSH_KEYS[@]}"; do
50 echo " $key"
51 done
52 }
53
54 list_devices() {
55 echo "Connected FIDO2 devices:"
56 fido2-token -L
57 }
58
59 if [[ "$1" == "--list-keys" ]]; then
60 list_keys
61 exit 0
62 fi
63
64 if [[ "$1" == "--list-devices" ]]; then
65 list_devices
66 exit 0
67 fi
68
69 if [[ "$1" == "-h" || "$1" == "--help" ]]; then
70 usage
71 fi
72
73 # Create temporary file for decrypted key
74 temp_key=$(mktemp)
75 trap 'rm -f "$temp_key"' EXIT
76
77 # Try each encrypted SSH key
78 found_key=""
79 for key_name in "''${!SSH_KEYS[@]}"; do
80 encrypted_key="''${SSH_KEYS[$key_name]}"
81
82 if [[ ! -f "$encrypted_key" ]]; then
83 continue
84 fi
85
86 echo "Trying key: $key_name..."
87
88 # Try to decrypt with hardware plugins
89 decrypted=false
90 # Try each hardware plugin method
91 if age -d -j fido2-hmac "$encrypted_key" > "$temp_key" 2>/dev/null || \
92 age -d -j se "$encrypted_key" > "$temp_key" 2>/dev/null || \
93 age -d -j yubikey "$encrypted_key" > "$temp_key" 2>/dev/null; then
94 decrypted=true
95 fi
96
97 if [[ "$decrypted" == "true" ]]; then
98
99 # Check if this is a FIDO2 key by looking at the key type
100 if grep -q "sk-" "$temp_key"; then
101 # Try to use the key with SSH agent to verify it works with connected device
102 chmod 600 "$temp_key"
103
104 # Test if the key works by trying ssh-add
105 if SSH_ASKPASS=/bin/false ssh-add -T "$temp_key" 2>/dev/null; then
106 found_key="$key_name"
107 echo "✓ Found working key: $key_name"
108 break
109 else
110 echo " Key $key_name requires a different FIDO2 device"
111 fi
112 else
113 echo " Key $key_name is not a FIDO2 key"
114 fi
115 else
116 echo " Could not decrypt $key_name (missing age identity?)"
117 fi
118 done
119
120 if [[ -z "$found_key" ]]; then
121 echo "No matching SSH key found for the connected FIDO2 device." >&2
122 echo "Make sure:" >&2
123 echo " 1. Your FIDO2 device is connected" >&2
124 echo " 2. You have the correct age identity to decrypt the keys" >&2
125 echo " 3. The SSH key was generated with this FIDO2 device" >&2
126 exit 1
127 fi
128
129 # Use the found key with SSH
130 ssh -i "$temp_key" "$@"
131 '';
132 }).overrideAttrs { passthru.usage = builtins.readFile ./usage.kdl; };
133 };
134}