forked from
lass.pds.lassul.us/superconfig
This repository has no description
4.1 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.libfido2
29 ];
30 text = ''
31 # SSH wrapper that tries each encrypted SSH key with the connected FIDO2 device
32
33 # Key mapping from flake
34 declare -A SSH_KEYS
35 ${sshKeyEntries}
36
37 usage() {
38 echo "Usage: ssh-with-age [ssh_options...] destination"
39 echo " ssh-with-age --list-keys"
40 echo " ssh-with-age --list-devices"
41 echo ""
42 echo "Tries each encrypted SSH key to find one that works with the connected FIDO2 device."
43 exit 1
44 }
45
46 list_keys() {
47 echo "Available encrypted SSH keys:"
48 for key in "''${!SSH_KEYS[@]}"; do
49 echo " $key"
50 done
51 }
52
53 list_devices() {
54 echo "Connected FIDO2 devices:"
55 fido2-token -L
56 }
57
58 if [[ "$1" == "--list-keys" ]]; then
59 list_keys
60 exit 0
61 fi
62
63 if [[ "$1" == "--list-devices" ]]; then
64 list_devices
65 exit 0
66 fi
67
68 if [[ "$1" == "-h" || "$1" == "--help" ]]; then
69 usage
70 fi
71
72 # Create temporary file for decrypted key
73 temp_key=$(mktemp)
74 trap 'rm -f "$temp_key"' EXIT
75
76 # Try each encrypted SSH key
77 found_key=""
78 for key_name in "''${!SSH_KEYS[@]}"; do
79 encrypted_key="''${SSH_KEYS[$key_name]}"
80
81 if [[ ! -f "$encrypted_key" ]]; then
82 continue
83 fi
84
85 echo "Trying key: $key_name..."
86
87 # Try to decrypt with repository age keys
88 decrypted=false
89 for age_key in ${toString (builtins.attrValues self.keys.age)}; do
90 if age -d -j fido2-hmac "$encrypted_key" > "$temp_key" 2>/dev/null || \
91 age -d -j se "$encrypted_key" > "$temp_key" 2>/dev/null; then
92 decrypted=true
93 break
94 fi
95 done
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 };
133 };
134}