Extended Brain Storage

# OpenBSD: OpenSSH with Two-Factor Authentication

Posted on June 15, 2019

The OpenSSH daemon is targeted by brute-force attacks almost everyday. There are various ways to deal with the annoying attempts of unauthorised access, such as using certificates, one of which is multi-factor authentication. Here are some thoughts to set this up in the realm of OpenBSD

### Introduction

Having a very complex password or long passphrase may seem to be an adequate solution to minimise the risk that a few random password guesses will be successful. Hands-on experience shows that a better solution is to replace passwords with certificates. And even better solution is to combine multiple pieces of evidence (factors), also known as multi-factor authentication (MFA).

### Prerequisite

The following how-to considers that users can successfully log in using certificates.

On the server side, the SSH daemon’s configuration file (sshd_config) needs to be updated in order to accept user’s password additionally to the already configured publickey method:

$echo "AuthenticationMethods publickey,password" >> /etc/ssh/sshd_config  And the server restarted: $ rcctl restart sshd


### OATH OTP Provider

As root, installation of login_oath and libqrencode to generate QR codes:

$pkg_add login_oath quirks-3.124 signed on 2019-04-15T12:10:16Z login_oath-0.8p4:openpam-20141014: ok login_oath-0.8p4:oath-toolkit-2.6.2p0: ok login_oath-0.8p4: ok New and changed readme(s): /usr/local/share/doc/pkg-readmes/login_oath$ pkg_add libqrencode
quirks-3.124 signed on 2019-04-15T12:10:16Z
libqrencode-4.0.2: ok


As unprivileged user:

$openssl rand -hex 20 > ~/.totp-key # generate the seed (in hexadecimal format)$ chmod 400 ~/.totp-key


Alternatively (not used in the following example), a more secure variant using sha512:

$head -50 /dev/urandom | sha512 > ~/.totp-key # generate the seed (in hexadecimal format)$ chmod 400 ~/.totp-key


Verification can be perfomed as follows (the -d<NUM> specifies the number of digits in OTP, the default is 6):

$oathtool -v -d6 --totp cat ~/.totp-key Hex secret: <HEX-SECRET> Base32 secret: <BASE32-SECRET> Digits: 6 Window size: 0 Start counter: 0x0 (0)  Generating the QR code image for the previously generated <BASE32-SECRET>: $ qrencode -d 90 -s 4 -o <USERNAME>@<SERVER-DOMAINNAME>.png 'otpauth://totp/<USERNAME>@<SERVER-DOMAINNAME>?secret=<BASE32-SECRET>&issuer=<SERVER-DOMAINNAME>'


The generated file needs to be delivered to the client device application using e-mail, for instance.

The OATH provider needs to be integrated with the login class capability database. After the following lines that are present in the /etc/login.conf file:

# Default allowed authentication styles for authentication type ftp
auth-ftp-defaults:auth-ftp=passwd:


it is necessary to add the following lines:

# Default allowed authentication styles for authentication type ssh
auth-ssh-defaults:auth-ssh=-totp:


and also update the appropriate class for which the TOTP is being set with the following line:

:tc=auth-ssh-defaults:\


As typically, it is the staff group, the update looks like this:

staff:\
:datasize-cur=1536M:\
:datasize-max=infinity:\
:maxproc-max=512:\
:maxproc-cur=256:\
:requirehome@:\
:tc=auth-ssh-defaults:\
:tc=default:


Finally, the changes need to by applied either by restarting the server or sourcing the appropriate files as follows:

$[ -f /etc/login.conf.db ] && cap_mkdb /etc/login.conf  Once connected using an SSH client, the SSH certificate as well as the TOTP (code) will be required. ### Trusting Keys Signed by a Certificate Authority Important note: The following lines are for pure reference only. The configuration may (and most probably will not) work anymore. Reader discretion advised. Considering the Certificate Authority (CA) was set up using the Easy-RSA, the following commands need to be performed in order to create a signed SSH certificate: $ cd /PATH/TO/Easy-RSA/ROOT/
$ssh-keygen -s ./ca.domain.tld/private/ca.key -I <USERNAME>@<SERVER-DOMAINNAME> -n <USERNAME> ~/.ssh/id_rsa.pub Enter passphrase: Signed user key ~/.ssh/id_rsa-cert.pub: id "<USERNAME>@<SERVER-DOMAINNAME>" serial 0 for <USERNAME> valid forever  If found useful in any way, the SSH Fingerprint ASCII Visualisation can be retrieved later using (this feature has been available since OpenSSH 5.1): $ ssh-keygen -lv -f ~/.ssh/id_rsa.pub


Verification of the SSH certificate can be performed as follows:

$ssh-keygen -L -f ~/.ssh/id_rsa-cert.pub ~/.ssh/id_rsa-cert.pub: Type: ssh-rsa-cert-v01@openssh.com user certificate Public key: RSA-CERT SHA256:<SHA256-HASH> Signing CA: RSA SHA256:<SHA256-HASH> (using ssh-rsa) Key ID: "<USERNAME>@<SERVER-DOMAINNAME>" Serial: 0 Valid: forever Principals: <USERNAME> Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc  The local SSH configuration file needs to be updated accordingly: $ cat << EOF > ~/.ssh/config
Host <SERVER-DOMAINNAME>
HostName <SERVER-DOMAINNAME>
CertificateFile ~/.ssh/id_rsa-cert.pub
IdentityFile ~/.ssh/id_rsa
EOF


Before the CA’s public key can be transported to the OpenSSH server, it needs to be converted from the X.509 to the PKCS#8 format as follows:

$cd /PATH/TO/Easy-RSA/ROOT/$ openssl x509 -in ./ca.domain.tld/ca.crt -noout -pubkey >pubkey.pem
$ssh-keygen -i -m PKCS8 -f pubkey.pem >ca.domain.tld.pub  On the server side, the following line should be added to the sshd_config file in order to make sure that the server trusts the keys signed by the CA: $ echo "AuthenticationMethods publickey,password" >> /etc/ssh/sshd_config
$echo "TrustedUserCAKeys /etc/ssh/ca.domain.tld.pub" >> /etc/ssh/sshd_config  All settings need to be verified now before the OpenSSH daemon is restarted, as the server may become unavailable when something was incorrectly configured! $ rcctl restart sshd


Before connecting the client to the OpenSSH server,

• the server fingerprint (RSA, ECC etc.) can be printed on the server as follows:
$ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key 2048 SHA256:<SERVER-FINGERPRINT> server.domain.tld  • and the very same fingerprint should be saved into the local known_hosts file on the client’s device: $ vi ~/.ssh/known_hosts