Converting Dropbear Keys to Use Within OpenSSH
The existing instructions for installing the openSSH server to replace the default dropbear SSH server instruct you to create entirely new keys for openSSH to use.
That can cause issues because it means that the key fingerprint of the SSH servers will be different, since the new keys do not match the original keys generated by dropbear. Many SSH clients are configured to reject changes in server key fingerprint due to security concerns about man-in-the-middle attacks. To workaround this, you could change the fingerprints within each client's known_hosts file, but in some scenarios changing that information on each computer you access the router from becomes impractical.
As an alternative, you can make it so the openSSH server uses the same keys that the dropbear SSH server originally used. However, dropbear stores the SSH keys in a special format that openSSH does not know how to understand, so it isn't as simple as moving the existing dropbear keys into the location that openSSH expects. Luckily, there is an existing Entware package, dropbearconvert, which provides a utility for converting between dropbear and openssh formatted SSH keys, and by using that utility we can preserve the dropbear keys and provide them to the openSSH server instead of generating entirely new keys.
Script to Automate Conversion with dropbearconvert Utility
This script downloads the dropbearconvert package and temporarily installs the dropbearconvert utility using opkg (if needed; it will use an existing installed copy if one exists). Next the script uses the utility to convert the private dropbear keys into the openSSH versions, and finally it uninstalls the dropbearconvert package (if it was not using an existing installed copy from PATH). This script also regenerates the corresponding public keys, in openSSH format, and copies the existing authorized_keys information from the dropbear location into the existing openSSH configuration. This script requires you to explicitly opt in to any key overwriting, and also generates backup files automatically to help you recover should any issues arise.
A downloadable version of the script is available as a GitHub gist. This script is written by emabrey and distributed under the terms of the GPLv2. Also, this script relies upon the dropbearconvert utility authored by Matt Johnston, and you can find the license for that utility online.
#! /bin/sh # SPDX-License-Identifier: GPL-2.0-only # License available at https://www.gnu.org/licenses/old-licenses/gpl-2.0.html # Script written by emabrey #### Configuration #### DROPBEAR_DIR="/etc/dropbear"; # Path for locating existing dropbear keys OPENSSH_DIR="/etc/ssh"; # Path for placement of converted openSSH keys FORCE_ENABLED=false; # Key overwrite enabled (see -f or --force) CONVERT_PROG="dropbearconvert" # The name of the dropbearconvert package/program BACKUP_UUID="bfe22494-8bea-43c3-908c-59e412b89cce" #The filename UUID to use when making backup files #### Script #### if [ "$#" -gt 1 ]; then echo "Too many arguments, please consult --help option helptext; aborting"; exit 1; fi if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then echo "Usage: $0 [option...] "; echo " "; echo " -f, --force Overwrite the existing openSSH keys"; echo " -h, --help Display this help message "; echo " "; exit 0; elif [ "$1" = "-f" ] || [ "$1" = "--force" ]; then FORCE_ENABLED=true; elif [ -n "$1" ]; then echo "Unrecognized option; aborting"; exit 1; fi if ! [ -e "$DROPBEAR_DIR" ] || ! [ -d "$DROPBEAR_DIR" ]; then echo "Configured dropbear directory is not a valid directory; aborting"; exit 1; fi; if ! [ -e "$OPENSSH_DIR" ] || ! [ -d "$OPENSSH_DIR" ]; then echo "Configured openSSH directory is not a valid directory; aborting"; exit 1; fi; for program in "echo" "cp" "rm"; do if ! command -v $program >/dev/null 2>&1; then printf "%s\n" "Missing $program, which is required; aborting;" exit 1; fi; done; echo "The dropbear to openSSH key conversion is about to start..."; if [ "$FORCE_ENABLED" = "true" ]; then echo "WARNING: SSH key overwriting is enabled; press Ctrl-C if unintentional"; fi; # Give user time to abort if they accidentally ran the program # overwriting SSH keys accidentally could be a catastrophic issue # so the script is trying to give you one last chance to change your mind # if you've made a mistake echo "5.." && sleep 1; echo "4.." && sleep 1; echo "3.." && sleep 1; echo "2.." && sleep 1; echo "1.." && sleep 1; echo "---" # Detect existing dropbear key converter, or temporarily install it if ! command -v "$CONVERT_PROG" >/dev/null 2>&1; then # Check for entware installer if ! command -v "opkg" >/dev/null 2>&1; then echo "Unable to proceed; $CONVERT_PROG utility is not available"; echo "Try manually installing the $CONVERT_PROG program to PATH first"; exit 1; fi echo "Updating entware repository database" && opkg update >/dev/null 2>&1; echo "Temporarily installing $CONVERT_PROG utility..." && opkg install "$CONVERT_PROG" >/dev/null 2>&1; hash -r; REMOVEDC=true; # Verify that the installation succeeded if ! command -v "$CONVERT_PROG" >/dev/null 2>&1; then echo "The temporary installation failed; aborting" exit 1; fi else echo "Pre-existing $CONVERT_PROG installation detected" REMOVEDC=false fi; echo "---" KEYCOUNT=0 # Counts up for each conversion for keytype in "rsa" "ed25519"; do DROPBEAR_KEY="${DROPBEAR_DIR}/dropbear_${keytype}_host_key" # dropbear input OPENSSH_KEY="${OPENSSH_DIR}/ssh_host_${keytype}_key" # openSSH output KEY_PRIVATE="$OPENSSH_KEY" KEY_PUBLIC="${OPENSSH_KEY}.pub" echo "Attempting to convert dropbear $keytype keys to openSSH format..."; # If there are existing keys, check if force is enabled and backup and remove # the existing files if that option is enabled for existing_keyfile in "$KEY_PRIVATE" "$KEY_PUBLIC"; do if [ -e "$existing_keyfile" ] && [ -f "$existing_keyfile" ]; then if [ "$FORCE_ENABLED" = "true" ]; then echo " - openSSH $keytype keys have been detected; making backup and overwriting" # Make a backup and remove original private key cp "$existing_keyfile" "${existing_keyfile}.${BACKUP_UUID}.bak"; rm "$existing_keyfile"; fi; fi; done; if [ -e "$KEY_PRIVATE" ] || [ -e "$KEY_PUBLIC" ]; then echo " - Existing openSSH $keytype keys have been detected; key type skipped" echo " - To forcibly overwrite the keys, run using the -f (--force) option" elif [ -e "$DROPBEAR_KEY" ] && [ -f "$DROPBEAR_KEY" ]; then # generate converted private key echo "Converting dropbear $keytype private key into private openSSH key..." "$CONVERT_PROG" dropbear openssh "$DROPBEAR_KEY" "$KEY_PRIVATE" >/dev/null 2>&1; KEYCOUNT=$((KEYCOUNT+1)) # Now try to generate converted public key if command -v "ssh-keygen" >/dev/null 2>&1; then echo "Converting openssh $keytype private key into public openSSH key..." ssh-keygen -y -f "$KEY_PRIVATE" -y > "$KEY_PUBLIC"; else echo "Skipping public key conversion because ssh-keygen is not available"; fi; else echo "Unable to find dropbear $keytype key; skipping conversion" fi; done; echo "---" # If we temporarily installed the converter, remove it if command -v "$CONVERT_PROG" >/dev/null 2>&1 && [ "$REMOVEDC" ]; then echo "Removing $CONVERT_PROG utility..." && opkg remove "$CONVERT_PROG" >/dev/null 2>&1; hash -r # Make sure the removal was completed if command -v "$CONVERT_PROG" >/dev/null 2>&1; then echo "Removal of the $CONVERT_PROG utility may have experienced an error" echo "A manual execution of \`opkg remove $CONVERT_PROG\` may be required" fi; else echo "Pre-existing $CONVERT_PROG installation detected; skipping uninstall" fi echo "---" if [ -e "$DROPBEAR_DIR/authorized_keys" ] && command -v "sort" >/dev/null 2>&1; then echo "Copying dropbear authorized keys to openSSH authorized keys file..."; AUTH_KEY_FILE="${OPENSSH_DIR}/authorized_keys" if ! [ -d "$AUTH_KEY_FILE" ]; then if ! [ -e "$AUTH_KEY_FILE" ]; then touch "$AUTH_KEY_FILE"; else # Make a backup of the original authorized keys file just in case # Uses a UUID to eliminate chance of collision in POSIX compliant way cp "$AUTH_KEY_FILE" "${OPENSSH_DIR}/authorized_keys.${BACKUP_UUID}.bak" fi; sort -u "$DROPBEAR_DIR/authorized_keys" "$AUTH_KEY_FILE" -o "$AUTH_KEY_FILE"; fi fi; echo "---" echo "There were $KEYCOUNT private keys converted during this script execution"; echo "The dropbear to openSSH key conversion is now complete!"
Advice on Running Script
This script requires permissions that allow it to access both the system-level directories for the dropbear and openSSH servers, and in most setups that means you need to run this script as the root user.
When running the script, it will only generate converted openSSH keys if there are not already existing openSSH keys in the relevant default key-file locations. If you have just installed the openSSH server (or if you recently ran the sshd service for the first time), it is likely that those key-files are the auto-generated keys, and are safe to overwrite. To allow the script to overwrite existing keys, simply pass in the -f or --force option when running the script. If overwriting is enabled, the script will generate backup files ending in the *.bak extension containing each overwritten key.
Please note that even if the key-file overwriting is not enabled, the script always overwrites the existing authorized_keys file in a safe manner by combining the unique keys from the existing dropbear and openSSH authorized_keys files. However, to ensure that no data is lost, this safe operation still generates a backup file for the authorized_keys file as well. This backup file, and the key backup files (if enabled), will be created within the same directory the output openSSH keys are being written to.
The script is compatible with an existing installation of the dropboxconvert program on the PATH, and will use your existing installation without modifying it when present. However, if the script automatically does a temporary install of the dropboxconvert package, it will make an attempt to automatically uninstall it at the end of the script run. If it fails to remove the temporary installation of the program, it will print a message saying that a manual removal command is likely needed. To manually remove the dropboxconvert program from your device, simply execute opkg remove dropboxconvert from a root shell.
Configuring openSSH
Below is a basic sshd configuration file. You can use this as your configuration file by first replacing the default one located at etc/ssh/sshd_config and secondly restarting the sshd service service restart sshd (but finish reading this article before doing so).
This configuration file loads both the openSSH and dropbear authorized_keys files (which enables you to continue to add keys for openSSH via the LuCI interface), disables insecure SHA-1 based KEX (Key EXchange) as well as providing a workaround for an existing bug in OpenSSH for Windows v9.5p1. This configuration also makes the sshd daemon listen on 0.0.0.0:22 and [::1]:22], and uses the openSSH keys located in /etc/ssh/ssh_host_rsa_key and /etc/ssh/ssh_host_ed25519_key (which you should have generated with the script above so that they match the keys from your dropbear server).
Finally, the last part of this configuration enables SSH compression, enables TCP keepalive to ensure the connection does not drop, enables DNS lookups for ssh server hostnames, and ensures that your SSH traffic uses a custom DSCP class (af41, where 4 is the highest priority and 1 is the highest availability - read more on DSCP here).
# This is the sshd server system-wide configuration file. See # sshd_config(5) for more information. # This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin Include /etc/ssh/sshd_config.d/*.conf Port 22 AddressFamily any ListenAddress 0.0.0.0 ListenAddress :: HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ed25519_key AuthorizedKeysFile .ssh/authorized_keys /etc/dropbear/authorized_keys KexAlgorithms -diffie-hellman-group1-sha1,-diffie-hellman-group-exchange-sha1,-sntrup761x25519-sha512@openssh.com PermitRootLogin prohibit-password MaxAuthTries 3 PubkeyAuthentication yes PasswordAuthentication no PermitEmptyPasswords no Compression yes IPQoS af41 TCPKeepAlive yes UseDNS yes # override default of no subsystems Subsystem sftp /usr/lib/sftp-server
Safely Setting up openSSH for Public Key Authentication
This configuration will ONLY allow root login via public keys, so ensure that your ssh fingerprint is loaded within /etc/ssh/authorized_keys or /etc/dropbear/authorized_keys before disabling dropbear. Failure to verify that you have a public key added to the openSSH server WILL leave you locked out of SSH and unable to access your SSH server on port 22. If you are somehow locked out, quickly re-enable the dropbear service using LuCI and log back into the dropbear SSH server on port 2222 to fix the incorrectly configured openSSH server (ssh <router_ip> -p 2222). It is STRONGLY advised that you start a SSH session on the dropbear server (on port 2222) before switching to openSSH and disabling the dropbear service (service dropbear disable && service dropbear stop). So long as you have the session already open, stopping the dropbear service will not end your SSH session; this allows you to stop the dropbear service, restart the openSSH service with the new configuration, and verify that you are able to login to the new openSSH server all without losing access to your OpenWRT device over SSH. Once you have verified you have public key access to openSSH on port 22, you can safely end your leftover dropbear SSH session and the transfer is complete.
So the safe order of events is:
- Install the openSSH server (
opkg install openssh-server) - Run the conversion shell script to generate the openSSH keys from the dropbear keys (
convert_key.sh) - Move dropbear to port 2222 and restart it (
uci set dropbear.@dropbear[0].Port=2222 && uci commit dropbear && service dropbear restart) - Start an SSH session from another device using the dropbear server on port 2222 (
ssh <server_ip> -p 2222) - Using that SSH session, copy the provided sshd settings into the file at
etc/ssh/sshd_config, replacing its contents - Restart the openSSH server to start using the new configuration file's settings (
service sshd restart) - Verify that you can access the openSSH server using only public key authentication (
ssh <server_ip> -p 22) - Once you have verified the ability to access the openSSH server, disable the dropbear server on port 2222 (
service dropbear disable && service dropbear stop) - Double and/or triple check that the openSSH server is definitely accessible using public key authentication, and once you are sure, close the dropbear SSH session you started in step 4.