How to configure 802.1X client and server in FreeBSD

This article describes the steps required to configure 802.1X client and server using EAP-TLS both client and server side in FreeBSD.

Background

I recently bought a new switch of ebay capable of 802.1X PNAC (Port based Network Access Control). I wanted to have this set up for a long time, but it wasn’t unil now I had a switch thats actually supported it. This article describes how I got it up and running.

Certificates

Since I already have EAP-TLS set up for my wifi (authentication using X.509 client certificates) I will also use EAP-TLS for wired access. So I configured a private CA in order to issue both server certificates for the radius server and also client certificates for all clients that will use my network.  I have a more general post about how set up the CA here.

Radius server (Authentication server)

You will need to configure a Radius server to handle the authentication requests. I already have EAP-TLS configured using hostpad and its internal radius server for my wifi. But that server is very limited, so I decided to give FreeRADIUS a go. This also means that my wifi clients will be authenticated using the FreeRADIUS server from now on.

I understand that FreeRADIUS is very flexible and “easy” to customize, but I really think that the configuration is very hard do grasp. It would be virtually impossible to configure it without some guide to follow. The two big problems are that the configuration is split up into MANY files and that all the documentation is inside the config files, which makes them really hard to read. Luckily I found this guide online that did exactly what I wanted. So please have a look at that guide under “Configuration” to see how I configured FreeRADIUS. Its basically just a few minor changes in four files.

The switch (Authenticator)

This article will not cover the switch configuration needed for this setup. The configuration you will have to do is very depended on what brand of switch you have and what software it is running.  I have a Juniper EX2200-C and there is good online documentation on how to set up 802.1X.

The Supplicant (802.1X client)

In 802.1X the client is called the supplicant. To authenticate against the radius server you will basically need a small supplicant software installed on the client that will handle the authentication. This is done using EAPOL-packages that are sent out on the network and then handled by the switch (The Authenticator). The switch then talks to the raidus server (The Authentication server) to verify the client.

In Linux and FreeBSD the most commonly used supplicant software is called wpa_supplicant. Most of you who know of wpa_supplicant have used it for wifi authentication in differents forms. It can handle alot of different security types like WPA2 Enterprise, WPA2 or even WEP. But it can also work with wired network authentication. The configuration is actually very straight forward and similar to the wifi configs.

network={
    key_mgmt=IEEE8021X
    eap=TLS
    identity="identity"
    ca_cert="/etc/ssl/chain.pem"
    client_cert="/etc/ssl/client.cert.pem"
    private_key="/etc/ssl/client.key"
    private_key_passwd="passw0rd"
}

This is all you will need to have wpa_supplicant authenticate using client certificates over ethernet.

To have the wpa_supplicant automatically started when you FreeBSD machine boots you can just add the WPA keyword to your interface declaration in /etc/rc.conf like this:

ifconfig_ue0="DHCP WPA"

Smart Card/HSM backed OpenSSL CA

This article describes how to set up a Smart Card/HSM backed OpenSSL CA using a Smart Card HSM or any PKCS11 enabled device.

Background

Since some years back I use WPA2 Enterprise with EAP-TLS (Certificate authentication) for my wifi at home. Historically I have used certificates from a public CA for this purpose. This is not best practice since you don’t have control over the certificates that are issued.

Also, I recently bought a new switch capable of 802.1X authentication on all ports. For this purpose I want all my machines (even those without wifi) to have certificates. So I decided to go through the hassle of setting up my own private CA.

Setting up CA

For the basic setup of the CA I followed Jamies excellent guide on setting up a CA. So in this post you can assume that all the basic stuff like folders structure and basic commands are the same. I will only show you the differences needed to have the Root CA key stored on a PKCS11 device like a HSM, Smart Card HSM or a Yubikey. I will even try to follow his topic names so you can follow along.

Configure PKCS11 Engine

I will not discuss the operating system part of getting PKCS11 devices to work in this article. But basically you just need to install some packages, you can read about it here.

First of all we need to configure OpenSSL to talk to your PKCS11 device. This can be done from configuration or interactively on the command line.

From conf:

# At beginning of conf (before everything else)
openssl_conf            = openssl_def

# At end of conf (after everything else)
[openssl_def]
engines = engine_section

[engine_section]
pkcs11 = pkcs11_section

[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/local/lib/engines/pkcs11.so
MODULE_PATH = /usr/local/lib/opensc-pkcs11.so
init = 0

From cli:

OpenSSL> engine -t dynamic -pre SO_PATH:/usr/local/lib/engines/pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/local/lib/opensc-
pkcs11.so

Create the root pair

First of all we need to have a RSA key pair on the PKCS11 device:

# pkcs11-tool --module /usr/local/lib/opensc-pkcs11.so -l --keypairgen --key-type rsa:2048 --label "SSL Root CA"
Using slot 0 with a present token (0x0)
Logging in to "HSM 2 (UserPIN)".
Please enter User PIN:
Key pair generated:
Private Key Object; RSA
  label:      SSL Root CA
  ID:         d15c3e9578a612a658bb14e0e147db4f2279cf19
  Usage:      decrypt, sign, unwrap
Public Key Object; RSA 2048 bits
  label:      SSL Root CA
  ID:         d15c3e9578a612a658bb14e0e147db4f2279cf19
  Usage:      encrypt, verify, wrap

Create the root certificate

I will assume that you have configured pkcs11 in openssl.cnf (otherwise you will have to first run the engine command in openssl interactively before any other command).

# openssl req -config openssl.cnf -new -x509 -days 7300 -sha256 -extensions v3_ca -engine pkcs11 -keyform engine -key 0:d15c3e9578a612a658bb14e0e147db4f2279cf19 -out certs/ca.cert.pem
engine "pkcs11" set.
Enter PKCS#11 token PIN for HSM 2 (UserPIN):
0x8018b6000 07:41:35.523 cannot lock memory, sensitive data may be paged to disk
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [SE]:
State or Province Name []:
Locality Name []:
Organization Name [PeanOrg]:
Organizational Unit Name []:PeanOrg Certificate Authority
Common Name []:PeanOrg Root CA
Email Address []:

Create the intermediate pair

For the intermediate key pair I followed jamies guide. I need frequent access to this CA so I have decided to have the intermediate pair on file instead of HSM.

Create the intermediate certificate

I changed one thing in jamies intermediate/openssl.cnf because I dont see the point of having province set in the CAs

stateOrProvinceName     = optional

To use the Root key stored on pkcs11 to sign the intermediate certificate use this command:

# openssl ca -config openssl.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -engine pkcs11 -keyform engine -keyfile 0:d15c3e9578a612a658bb14e0e147db4f2279cf19 -in intermediate/csr/intermediate.csr.pem -out intermediate/certs/intermediate.cert.pem
Using configuration from openssl.cnf
engine "pkcs11" set.
Enter PKCS#11 token PIN for HSM 2 (UserPIN):
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 4096 (0x1000)
        Validity
            Not Before: Apr  7 05:54:22 2018 GMT
            Not After : Apr  4 05:54:22 2028 GMT
        Subject:
            countryName               = SE
            organizationName          = PeanOrg
            organizationalUnitName    = PeanOrg Certificate Authority
            commonName                = PeanOrg Intermediate CA 1
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                77:9C:07:23:FD:40:E9:5C:7E:30:73:8F:59:28:25:F5:06:43:B4:70
            X509v3 Authority Key Identifier:
                keyid:A4:F2:DE:15:8E:9E:A8:87:B0:95:D4:21:A2:BD:4C:41:02:93:E0:8D

            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Key Usage: critical
                Digital Signature, Certificate Sign, CRL Sign
Certificate is to be certified until Apr  4 05:54:22 2028 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

We now have all we need to sign certificates. Just follow Jamies guide Sign server and client certificates

References

It took me a few hours to get this going because of sort of a lack of documentation on how to use OpenSSL and PKCS11 together, during my efforts I found these resources helpful

Minimal scp only chroot in FreeBSD

Background

The other day I needed to receive a few files from a friend. And I wanted to provide an easy to use service to do so. Back in the days I did run a FTP service with anonymous login and write acces to a inbox folder (1777).  But these days I have a few more security concerns and wanted to provide a scp drop site, and exactly that. A “scp only chroot”.

Configuration

Giving chrooted ssh access is pretty straight forward in the sshd_config. But to actually get it to work you will have to fiddle around a bit. You will need to figure out exactly what files you will need inside the chroot for the service to function properly.

Create user

Just use your favourite way of creating users in your system.

sshd

The easy part is to configure your sshd_config to chroot the specific user, group or whatever you want to chroot. Since this is probably a one off for me I settled for a single user.

Match User scponly
  ChrootDirectory /home/%u
  X11Forwarding no
  AllowTcpForwarding no

This short configuration will chroot the user scponly to /home/scponly when it connects. You just need to restart sshd in order to these settings to take effect.

Setting up environment

The hardest part was to set up the environment since you will need to make all libs and so on available inside the chroot.

Since this was to be a one off solution I will not go through the hassle of loop/null mounts or stuff like that. I will simply copy the stuff thats actually needed into the chroot. To find out what libs you actually need you can use the tool ldd(1)

# ldd /usr/local/bin/scp 
/usr/local/bin/scp:
	libcrypto.so.8 => /lib/libcrypto.so.8 (0x800a00000)
	libz.so.6 => /lib/libz.so.6 (0x800e69000)
	libutil.so.9 => /lib/libutil.so.9 (0x801082000)
	libldns.so.2 => /usr/local/lib/libldns.so.2 (0x801296000)
	libcrypt.so.5 => /lib/libcrypt.so.5 (0x8014f3000)
	libc.so.7 => /lib/libc.so.7 (0x801712000)

So I just created a few directories in /home/scponly

# cd /home/scponly
# mkdir etc bin lib dev libexec

and then copied these libs to /home/scponly/lib/.

You will also need to have a shell that then can invoke scp. I copied /rescue/sh to /home/scponly/bin/ because it is statically linked and does not depend on any libraries. When all this was done I thought the whole thing was finished but I encountered a few problems.

Problems

The first one was scp complaining about missing ld-elf.so.1. So just like the other libs I just copied it in to /home/sftponly/libexec/.

Secondly scp started to complain about missing /dev/null. And my solution to this was to just create a empty file called null in /home/sftponly/dev/ and chmod to 666. Why it works with a regular file I dont know. If you have any idea please tell me in the comments.

The final problem I faced was an error when invoking scp that said “unknown user 1005”. I did some searches on the web and found several solutions that where Linux specific so no help there. But they involved putting a few more files and libs relevant to nss into the chroot.

What I finally found out was that its the /etc/master.passwd (think of shadow in linux) and its database that where missing. So I just did grep scponly /etc/master.passwd > /home/scponly/etc/master.passwd to copy only the record for scponly to the chroot.

sad:*:1005:1002::0:0:scp only user:/home/scponly:/bin/sh

Finally the actual databased needed to be created with this command

# pwd_mkdb -d /home/scponly/etc/ /home/scponly/etc/master.passwd

Thats it! Now I have a account thats basically all it can do is scp. Yes you can login and get a shell but since there is no other binaries than scp and sh you are pretty limited.