diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:49:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:49:46 +0000 |
commit | 50b37d4a27d3295a29afca2286f1a5a086142cec (patch) | |
tree | 9212f763934ee090ef72d823f559f52ce387f268 /raddb/certs | |
parent | Initial commit. (diff) | |
download | freeradius-50b37d4a27d3295a29afca2286f1a5a086142cec.tar.xz freeradius-50b37d4a27d3295a29afca2286f1a5a086142cec.zip |
Adding upstream version 3.2.1+dfsg.upstream/3.2.1+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | raddb/certs/.gitignore | 13 | ||||
-rw-r--r-- | raddb/certs/Makefile | 186 | ||||
-rw-r--r-- | raddb/certs/README.md | 248 | ||||
-rwxr-xr-x | raddb/certs/bootstrap | 86 | ||||
-rw-r--r-- | raddb/certs/ca.cnf | 62 | ||||
-rw-r--r-- | raddb/certs/client.cnf | 53 | ||||
-rw-r--r-- | raddb/certs/demoCA/cacert.pem | 22 | ||||
-rw-r--r-- | raddb/certs/inner-server.cnf | 55 | ||||
-rw-r--r-- | raddb/certs/ocsp.cnf | 61 | ||||
-rw-r--r-- | raddb/certs/realms/README.md | 235 | ||||
-rw-r--r-- | raddb/certs/server.cnf | 72 | ||||
-rw-r--r-- | raddb/certs/xpextensions | 75 |
12 files changed, 1168 insertions, 0 deletions
diff --git a/raddb/certs/.gitignore b/raddb/certs/.gitignore new file mode 100644 index 0000000..45e1bcb --- /dev/null +++ b/raddb/certs/.gitignore @@ -0,0 +1,13 @@ +*.pem +*.key +*.crt +*.csr +*.p12 +*.old +*.attr +*.crl +dh +index.txt +random +serial +passwords.mk diff --git a/raddb/certs/Makefile b/raddb/certs/Makefile new file mode 100644 index 0000000..c9fbc9e --- /dev/null +++ b/raddb/certs/Makefile @@ -0,0 +1,186 @@ +###################################################################### +# +# Make file to be installed in /etc/raddb/certs to enable +# the easy creation of certificates. +# +# See the README file in this directory for more information. +# +# $Id$ +# +###################################################################### + +DH_KEY_SIZE = 2048 +OPENSSL = openssl +EXTERNAL_CA = $(wildcard external_ca.*) + +ifneq "$(EXTERNAL_CA)" "" +PARTIAL = -partial_chain +endif + +# +# Set the passwords +# +include passwords.mk + +###################################################################### +# +# Make the necessary files, but not client certificates. +# +###################################################################### +.PHONY: all +all: index.txt serial dh ca server client + +.PHONY: client +client: client.pem + +.PHONY: ca +ca: ca.der ca.crl + +.PHONY: server +server: server.pem server.vrfy + +.PHONY: inner-server +inner-server: inner-server.pem inner-server.vrfy + +.PHONY: verify +verify: server.vrfy client.vrfy + +passwords.mk: server.cnf ca.cnf client.cnf inner-server.cnf + @echo "PASSWORD_SERVER = '$(shell grep output_password server.cnf | sed 's/.*=//;s/^ *//')'" > $@ + @echo "PASSWORD_INNER = '$(shell grep output_password inner-server.cnf | sed 's/.*=//;s/^ *//')'" >> $@ + @echo "PASSWORD_CA = '$(shell grep output_password ca.cnf | sed 's/.*=//;s/^ *//')'" >> $@ + @echo "PASSWORD_CLIENT = '$(shell grep output_password client.cnf | sed 's/.*=//;s/^ *//')'" >> $@ + @echo "USER_NAME = '$(shell grep emailAddress client.cnf | grep '@' | sed 's/.*=//;s/^ *//')'" >> $@ + @echo "CA_DEFAULT_DAYS = '$(shell grep default_days ca.cnf | sed 's/.*=//;s/^ *//')'" >> $@ + +###################################################################### +# +# Diffie-Hellman parameters +# +###################################################################### +dh: + $(OPENSSL) dhparam -out dh -2 $(DH_KEY_SIZE) + +###################################################################### +# +# Create a new self-signed CA certificate +# +###################################################################### +ca.key ca.pem: ca.cnf + @[ -f index.txt ] || $(MAKE) index.txt + @[ -f serial ] || $(MAKE) serial + $(OPENSSL) req -new -x509 -keyout ca.key -out ca.pem \ + -days $(CA_DEFAULT_DAYS) -config ./ca.cnf \ + -passin pass:$(PASSWORD_CA) -passout pass:$(PASSWORD_CA) + chmod g+r ca.key + +ca.der: ca.pem + $(OPENSSL) x509 -inform PEM -outform DER -in ca.pem -out ca.der + +ca.crl: ca.pem + $(OPENSSL) ca -gencrl -keyfile ca.key -cert ca.pem -config ./ca.cnf -out ca-crl.pem -key $(PASSWORD_CA) + $(OPENSSL) crl -in ca-crl.pem -outform der -out ca.crl + rm ca-crl.pem + +###################################################################### +# +# Create a new server certificate, signed by the above CA. +# +###################################################################### +server.csr server.key: server.cnf + $(OPENSSL) req -new -out server.csr -keyout server.key -config ./server.cnf + chmod g+r server.key + +server.crt: ca.key ca.pem server.csr + $(OPENSSL) ca -batch -keyfile ca.key -cert ca.pem -in server.csr -key $(PASSWORD_CA) -out server.crt -extensions xpserver_ext -extfile xpextensions -config ./server.cnf + +server.p12: server.crt + $(OPENSSL) pkcs12 -export -in server.crt -inkey server.key -out server.p12 -passin pass:$(PASSWORD_SERVER) -passout pass:$(PASSWORD_SERVER) + chmod g+r server.p12 + +server.pem: server.p12 + $(OPENSSL) pkcs12 -in server.p12 -out server.pem -passin pass:$(PASSWORD_SERVER) -passout pass:$(PASSWORD_SERVER) + chmod g+r server.pem + +.PHONY: server.vrfy +server.vrfy: ca.pem + @$(OPENSSL) verify $(PARTIAL) -CAfile ca.pem server.pem + +###################################################################### +# +# Create a new client certificate, signed by the the above server +# certificate. +# +###################################################################### +client.csr client.key: client.cnf + $(OPENSSL) req -new -out client.csr -keyout client.key -config ./client.cnf + chmod g+r client.key + +client.crt: ca.key ca.pem client.csr + $(OPENSSL) ca -batch -keyfile ca.key -cert ca.pem -in client.csr -key $(PASSWORD_CA) -out client.crt -extensions xpclient_ext -extfile xpextensions -config ./client.cnf + +client.p12: client.crt + $(OPENSSL) pkcs12 -export -in client.crt -inkey client.key -out client.p12 -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT) + chmod g+r client.p12 + cp client.p12 $(USER_NAME).p12 + +client.pem: client.p12 + $(OPENSSL) pkcs12 -in client.p12 -out client.pem -passin pass:$(PASSWORD_CLIENT) -passout pass:$(PASSWORD_CLIENT) + chmod g+r client.pem + cp client.pem $(USER_NAME).pem + +.PHONY: client.vrfy +client.vrfy: ca.pem client.pem + c_rehash . + $(OPENSSL) verify -CApath . client.pem + +###################################################################### +# +# Create a new inner-server certificate, signed by the above CA. +# +###################################################################### +inner-server.csr inner-server.key: inner-server.cnf + $(OPENSSL) req -new -out inner-server.csr -keyout inner-server.key -config ./inner-server.cnf + chmod g+r inner-server.key + +inner-server.crt: ca.key ca.pem inner-server.csr + $(OPENSSL) ca -batch -keyfile ca.key -cert ca.pem -in inner-server.csr -key $(PASSWORD_CA) -out inner-server.crt -extensions xpserver_ext -extfile xpextensions -config ./inner-server.cnf + +inner-server.p12: inner-server.crt + $(OPENSSL) pkcs12 -export -in inner-server.crt -inkey inner-server.key -out inner-server.p12 -passin pass:$(PASSWORD_INNER) -passout pass:$(PASSWORD_INNER) + chmod g+r inner-server.p12 + +inner-server.pem: inner-server.p12 + $(OPENSSL) pkcs12 -in inner-server.p12 -out inner-server.pem -passin pass:$(PASSWORD_INNER) -passout pass:$(PASSWORD_INNER) + chmod g+r inner-server.pem + +.PHONY: inner-server.vrfy +inner-server.vrfy: ca.pem + @$(OPENSSL) verify $(PARTIAL) -CAfile ca.pem inner-server.pem + +###################################################################### +# +# Miscellaneous rules. +# +###################################################################### +index.txt: + @touch index.txt + +serial: + @echo '01' > serial + +print: + $(OPENSSL) x509 -text -in server.crt + +printca: + $(OPENSSL) x509 -text -in ca.pem + +clean: + @rm -f *~ *old client.csr client.key client.crt client.p12 client.pem + +# +# Make a target that people won't run too often. +# +destroycerts: + rm -f *~ dh *.csr *.crt *.p12 *.der *.pem *.key index.txt* \ + serial* *\.0 *\.1 ca-crl.pem ca.crl diff --git a/raddb/certs/README.md b/raddb/certs/README.md new file mode 100644 index 0000000..1d73f99 --- /dev/null +++ b/raddb/certs/README.md @@ -0,0 +1,248 @@ +# Certificate Documentation + +This directory contains scripts to create the server certificates. To +make a set of default (i.e. test) certificates, simply type: + +``` +$ ./bootstrap +``` + +The `openssl` command will be run against the sample configuration +files included here, and will make a self-signed certificate authority +(i.e. root CA), and a server certificate. This "root CA" should be +installed on any client machine needing to do EAP-TLS, PEAP, or +EAP-TTLS. + +The Extended Key Usage (EKU) fields for "TLS web server" will be +automatically included in the server certificate. Without those +extensions many clients will refuse to authenticate to FreeRADIUS. + +The root CA and the "XP Extensions" file also contain a +crlDistributionPoints attribute. Many systems need this to be present +in order to validate the RADIUS server certificate. The RADIUS server +must have the URI defined but the CA need not have...however it is +best practice for a CA to have a revocation URI. Note that whilst the +Windows Mobile client cannot actually use the CRL when doing 802.1X it +is recommended that the URI be an actual working URL and contain a +revocation format file as there may be other OS behaviour at play and +future OSes that may do something with that URI. + +For Windows, you will need to import the `p12` and/or the `der` format +of the certificates. Linux systems need the `pem` format. + +In general, you should use self-signed certificates for 802.1X (EAP) +authentication. When you list root CAs from other organisations in +the `ca_file`, you permit them to masquerade as you, to authenticate +your users, and to issue client certificates for EAP-TLS. + +If you already have CA and server certificates, rename (or delete) +this directory, and create a new `certs` directory containing your +certificates. Note that the `make install` command will **not** +over-write your existing `raddb/certs` directory. + + +## New Installations of FreeRADIUS + +We suggest that new installations use the test certificates for +initial tests, and then create real certificates to use for normal +user authentication. See the instructions below for how to create the +various certificates. The old test certificates can be deleted by +running the following command: + +``` +$ make destroycerts +``` + +Then, follow the instructions below for creating real certificates. + +If you do not want to enable EAP-TLS, PEAP, or EAP-TTLS, then delete +the relevant sub-sections from the `raddb/mods-available/eap` file. +See the comments in that file for more information. + + +## Making a root Certificate + +We recommend using a private certificate authority (CA). While it can +be difficult to install this CA on multiple client machines, it is (in +general) more secure. + +``` +$ vi ca.cnf +``` + +Edit `default_days` to set the desired lifetime of the CA certificate. + +Edit the `input_password` and `output_password` fields to be the +password for the CA certificate. + +Edit the `[certificate_authority]` section to have the correct values +for your country, state, etc. + +Create the CA certificate: + +``` +$ make ca.pem +``` + +Then the `DER` format needed by Windows: + +``` +$ make ca.der +``` + + +## Making a Server Certificate + +The following steps will let you create a server certificate for use +with TLS-based EAP methods, such as EAP-TLS, PEAP, and TTLS. Follow +similar steps to create an `inner-server.pem` file, for use with +EAP-TLS that is tunneled inside of another TLS-based EAP method. + +``` +$ vi server.cnf +``` + +Edit `default_days` to set the lifetime of the server certificate. +The maximum for this is 825 for compatibility with all client devices. + +Edit the `input_password` and `output_password` fields to be the +password for the server certificate. + +Edit the `[server]` section to have the correct values for your +country, state, etc. Be sure that the `commonName` field here is +different from the `commonName` for the CA certificate. + +Create the server certificate: + +``` +$ make server +``` + + +### Making a certificate for a public CA + +If you wish to use an existing certificate authority, you can +create a certificate signing request for the server certificate, edit +`server.cnf` as above, and run the following command. + +``` +$ make server.csr +``` + +This step creates a "Certificate Signing Request" suitable for +submission to a public CA. + + +## Making a Client certificate + +Client certificates are used by EAP-TLS, and optionally by EAP-TTLS +and PEAP. The following steps outline how to create a client +certificate that is signed by the CA certificate created above. You +will have to have the password for the CA certificate in the +`input_password` and `output_password` fields of the `ca.cnf` file. + +``` +$ vi client.cnf +``` + +Edit `default_days` to set the lifetime of the client certificate. + +Edit the `input_password` and `output_password` fields to be the +password for the client certificate. You will have to give these +passwords to the end user who will be using the certificates. + +Edit the `[client]` section to have the correct values for your +country, state, etc. Be sure that the `commonName` field here is +the `User-Name` which will be used for logins! + +``` +$ make client +``` + +The users certificate will be in `emailAddress.pem`, +e.g. `user@example.com.pem`. + +To create another client certificate, just repeat the steps for +making a client certificate, being sure to enter a different login +name for `commonName`, and a different password. + + +## Performance + +EAP performance for EAP-TLS, TTLS, and PEAP is dominated by SSL +calculations. That is, a normal system can handle PAP +authentication at a rate of 10k packets/s. However, SSL involves +RSA calculations, which are very expensive. To benchmark your system, +do: + +``` +$ openssl speed rsa +``` + +or + +``` +$ openssl speed rsa2048 +``` + +to test 2048 bit keys. + +The number that is printed is the **maximum** number of +authentications per second which can be done for EAP-TLS (or TTLS, +or PEAP). In practice, you will see results much lower than this +number, i.e. the actual EAP-TLS performance may be half of the +number printed here. + +The reason is that EAP requires many round-trip packets, whereas +`openssl speed rsa2028` only does RSA calculations, and nothing else. + + +## Compatibility + +The certificates created using this method are known to be compatible +with ALL operating systems. Some common issues are: + +* iOS and macOS have requirements on certificates. See: + https://support.apple.com/en-us/HT210176 + +* Many systems require certain OIDs in the certificates + (`id-kp-serverAuth` for `TLS Web server authentication`). + If the certificate does not contain these fields, the system + will stop doing EAP. The most visible effect is that the client + starts EAP, gets a few Access-Challenge packets, and then a little + while later re-starts EAP. If this happens, see the FAQ, and the + comments in `raddb/mods-available/eap` for how to fix it. + +* All systems requires the root certificates to be on the client PC. + If it doesn't have them, you will see the same issue as above. + +* Windows XP post SP2 has a bug where it has problems with + certificate chains. i.e. if the server certificate is an + intermediate one, and not a root one, then authentication + will silently fail, as above. + +* Some versions of Windows CE cannot handle 4K RSA certificates. + They will (again) silently fail, as above. + +* In none of these cases will Windows give the end user any + reasonable error message describing what went wrong. This leads + people to blame the RADIUS server. That blame is misplaced. + +* Certificate chains of more than 64K bytes are known to not work. + This is partly a problem in FreeRADIUS. However, most clients cannot + handle 64K certificate chains. Most Access Points will shut down the + EAP session after about 50 round trips, while 64K certificate chains + will take about 60 round trips. So don't use large certificate + chains. They will only work after everyone upgrades everything in the + network. + +* All other operating systems are known to work with EAP and + FreeRADIUS. This includes Linux, the BSDs, macOS, iOS, Android, + Solaris, Symbian, along with all known embedded systems, phones, + WiFi devices, etc. + + +## Security Considerations + +The default certificate configuration files uses SHA256 for message +digests for security. diff --git a/raddb/certs/bootstrap b/raddb/certs/bootstrap new file mode 100755 index 0000000..57de8cf --- /dev/null +++ b/raddb/certs/bootstrap @@ -0,0 +1,86 @@ +#!/bin/sh +# +# This is a wrapper script to create default certificates when the +# server first starts in debugging mode. Once the certificates have been +# created, this file should be deleted. +# +# Ideally, this program should be run as part of the installation of any +# binary package. The installation should also ensure that the permissions +# and owners are correct for the files generated by this script. +# +# $Id$ +# +umask 027 +cd `dirname $0` + +make -h > /dev/null 2>&1 + +# +# If we have a working "make", then use it. Otherwise, run the commands +# manually. +# +if [ "$?" = "0" ]; then + make all + exit $? +fi + +# +# The following commands were created by running "make -n", and edited +# to remove the trailing backslash, and to add "exit 1" after the commands. +# +# Don't edit the following text. Instead, edit the Makefile, and +# re-generate these commands. +# +if [ ! -f dh ]; then + openssl dhparam -out dh 2048 || exit 1 + if [ -e /dev/urandom ] ; then + ln -sf /dev/urandom random + else + date > ./random; + fi +fi + +if [ ! -f server.key ]; then + openssl req -new -out server.csr -keyout server.key -config ./server.cnf || exit 1 + chmod g+r server.key +fi + +if [ ! -f ca.key ]; then + openssl req -new -x509 -keyout ca.key -out ca.pem -days `grep default_days ca.cnf | sed 's/.*=//;s/^ *//'` -config ./ca.cnf || exit 1 +fi + +if [ ! -f index.txt ]; then + touch index.txt +fi + +if [ ! -f serial ]; then + echo '01' > serial +fi + +if [ ! -f server.crt ]; then + openssl ca -batch -keyfile ca.key -cert ca.pem -in server.csr -key `grep output_password ca.cnf | sed 's/.*=//;s/^ *//'` -out server.crt -extensions xpserver_ext -extfile xpextensions -config ./server.cnf || exit 1 +fi + +if [ ! -f server.p12 ]; then + openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -passin pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` -passout pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` || exit 1 + chmod g+r server.p12 +fi + +if [ ! -f server.pem ]; then + openssl pkcs12 -in server.p12 -out server.pem -passin pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` -passout pass:`grep output_password server.cnf | sed 's/.*=//;s/^ *//'` || exit 1 + openssl verify -CAfile ca.pem server.pem || exit 1 + chmod g+r server.pem +fi + +if [ ! -f ca.der ]; then + openssl x509 -inform PEM -outform DER -in ca.pem -out ca.der || exit 1 +fi + +if [ ! -f client.key ]; then + openssl req -new -out client.csr -keyout client.key -config ./client.cnf + chmod g+r client.key +fi + +if [ ! -f client.crt ]; then + openssl ca -batch -keyfile ca.key -cert ca.pem -in client.csr -key `grep output_password ca.cnf | sed 's/.*=//;s/^ *//'` -out client.crt -extensions xpclient_ext -extfile xpextensions -config ./client.cnf +fi diff --git a/raddb/certs/ca.cnf b/raddb/certs/ca.cnf new file mode 100644 index 0000000..d49991b --- /dev/null +++ b/raddb/certs/ca.cnf @@ -0,0 +1,62 @@ +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./ +certs = $dir +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir +certificate = $dir/ca.pem +serial = $dir/serial +crl = $dir/crl.pem +private_key = $dir/ca.key +RANDFILE = $dir/.rand +name_opt = ca_default +cert_opt = ca_default +default_days = 60 +default_crl_days = 30 +default_md = sha256 +preserve = no +policy = policy_match +crlDistributionPoints = URI:http://www.example.org/example_ca.crl + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +prompt = no +distinguished_name = certificate_authority +default_bits = 2048 +input_password = whatever +output_password = whatever +x509_extensions = v3_ca + +[certificate_authority] +countryName = FR +stateOrProvinceName = Radius +localityName = Somewhere +organizationName = Example Inc. +emailAddress = admin@example.org +commonName = "Example Certificate Authority" + +[v3_ca] +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +basicConstraints = critical,CA:true +crlDistributionPoints = URI:http://www.example.org/example_ca.crl + diff --git a/raddb/certs/client.cnf b/raddb/certs/client.cnf new file mode 100644 index 0000000..2650e47 --- /dev/null +++ b/raddb/certs/client.cnf @@ -0,0 +1,53 @@ +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./ +certs = $dir +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir +certificate = $dir/ca.pem +serial = $dir/serial +crl = $dir/crl.pem +private_key = $dir/ca.key +RANDFILE = $dir/.rand +name_opt = ca_default +cert_opt = ca_default +default_days = 60 +default_crl_days = 30 +default_md = sha256 +preserve = no +policy = policy_match + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +prompt = no +distinguished_name = client +default_bits = 2048 +input_password = whatever +output_password = whatever + +[client] +countryName = FR +stateOrProvinceName = Radius +localityName = Somewhere +organizationName = Example Inc. +emailAddress = user@example.org +commonName = user@example.org diff --git a/raddb/certs/demoCA/cacert.pem b/raddb/certs/demoCA/cacert.pem new file mode 100644 index 0000000..7ddff4d --- /dev/null +++ b/raddb/certs/demoCA/cacert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDtjCCAx+gAwIBAgIBADANBgkqhkiG9w0BAQQFADCBnzELMAkGA1UEBhMCQ0Ex +ETAPBgNVBAgTCFByb3ZpbmNlMRIwEAYDVQQHEwlTb21lIENpdHkxFTATBgNVBAoT +DE9yZ2FuaXphdGlvbjESMBAGA1UECxMJbG9jYWxob3N0MRswGQYDVQQDExJDbGll +bnQgY2VydGlmaWNhdGUxITAfBgkqhkiG9w0BCQEWEmNsaWVudEBleGFtcGxlLmNv +bTAeFw0wNDAxMjUxMzI2MDdaFw0wNjAxMjQxMzI2MDdaMIGfMQswCQYDVQQGEwJD +QTERMA8GA1UECBMIUHJvdmluY2UxEjAQBgNVBAcTCVNvbWUgQ2l0eTEVMBMGA1UE +ChMMT3JnYW5pemF0aW9uMRIwEAYDVQQLEwlsb2NhbGhvc3QxGzAZBgNVBAMTEkNs +aWVudCBjZXJ0aWZpY2F0ZTEhMB8GCSqGSIb3DQEJARYSY2xpZW50QGV4YW1wbGUu +Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDUxbGXJPFkrPH/sYnbHI+/ +9PFDlup8sekPeNaUUXJTd4ld/lLMuZtB6A3etYsSepQ/T1jLxWKHgZL73G/s6fhx +58Ew01z1GIgX6bEzJJ7dKhx10xBDrodVPOx6d+8mqn10KB25t34XxkRsXdmxiLQy +UMoCKZY3IqEjpyawC0An/QIDAQABo4H/MIH8MB0GA1UdDgQWBBRo020+Hue8nVoF +cCHDY9oTZdGt4zCBzAYDVR0jBIHEMIHBgBRo020+Hue8nVoFcCHDY9oTZdGt46GB +paSBojCBnzELMAkGA1UEBhMCQ0ExETAPBgNVBAgTCFByb3ZpbmNlMRIwEAYDVQQH +EwlTb21lIENpdHkxFTATBgNVBAoTDE9yZ2FuaXphdGlvbjESMBAGA1UECxMJbG9j +YWxob3N0MRswGQYDVQQDExJDbGllbnQgY2VydGlmaWNhdGUxITAfBgkqhkiG9w0B +CQEWEmNsaWVudEBleGFtcGxlLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBBAUAA4GBADPAC2ax5Xnvc6BnmCUtq41eVRH8AP0nbYDRL4NHd8Z0P9wnQ/yh +UHcE5LwJeeT2CsOtnug+bzRzaSKdH3cim6LpgjWdpWMCSgAWPbptbJhsC60or4UT +L/jw12UBvxt8Lf9ljOHmLAGZe25k4+jUNzNUzpkShHZRU5BjuFu8VIXF +-----END CERTIFICATE----- diff --git a/raddb/certs/inner-server.cnf b/raddb/certs/inner-server.cnf new file mode 100644 index 0000000..2101c2e --- /dev/null +++ b/raddb/certs/inner-server.cnf @@ -0,0 +1,55 @@ +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./ +certs = $dir +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir +certificate = $dir/server.pem +serial = $dir/serial +crl = $dir/crl.pem +private_key = $dir/server.key +RANDFILE = $dir/.rand +name_opt = ca_default +cert_opt = ca_default +default_days = 60 +default_crl_days = 30 +default_md = sha256 +preserve = no +policy = policy_match +copy_extensions = copy + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +prompt = no +distinguished_name = server +default_bits = 2048 +input_password = whatever +output_password = whatever + +[server] +countryName = FR +stateOrProvinceName = Radius +localityName = Somewhere +organizationName = Example Inc. +emailAddress = admin@example.org +commonName = "Example Inner Server Certificate" + diff --git a/raddb/certs/ocsp.cnf b/raddb/certs/ocsp.cnf new file mode 100644 index 0000000..01225d8 --- /dev/null +++ b/raddb/certs/ocsp.cnf @@ -0,0 +1,61 @@ +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./ +certs = $dir +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir +certificate = $dir/server.pem +serial = $dir/serial +crl = $dir/crl.pem +private_key = $dir/server.key +RANDFILE = $dir/.rand +name_opt = ca_default +cert_opt = ca_default +default_days = 60 +default_crl_days = 30 +default_md = sha256 +preserve = no +policy = policy_match +unique_subject = no +x509_extensions = v3_ocsp + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +prompt = no +distinguished_name = server +default_bits = 2048 +input_password = whatever +output_password = whatever + +[ server ] +countryName = FR +stateOrProvinceName = Radius +localityName = Somewhere +organizationName = Example Inc. +emailAddress = admin@example.org +commonName = "Example OCSP Responder Certificate" +subjectAltName = ocsp.example.org + +[ v3_ocsp ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = OCSPSigning diff --git a/raddb/certs/realms/README.md b/raddb/certs/realms/README.md new file mode 100644 index 0000000..9f754fa --- /dev/null +++ b/raddb/certs/realms/README.md @@ -0,0 +1,235 @@ +# Multiple Certificate Chains + +As of version 3.0.24, FreeRADIUS supports loading multiple certificate +chains, keyed by a realm name. These chains are in _addition_ to the +default certificates loaded by the `tls` section. + +Loading multiple certificate chains means that the server can have +different identities. i.e. When a user `bob@example.com` requests +network access, the server can present an `example.com` certificate. +On the other hand, when a user `doug@example.org` requests network +access, the server cna present an `example.org` certificate. + +This functionality means that it is possible to configure only one +`eap` module, and then use multiple certificate chains. Previous +versions of the server required that the administrator configure +multiple EAP modules, one for each certificate being used. + +The selection can be performed in one of two ways. First, the +certificates can be loaded dynamically at run-time. Second, the +certificates can be pre-loaded for speed. + +## Dynamic Loading of Certificate Chains + +The server can dynamically load a certificate chain by setting a +special attribute. This has to be done _after_ the server has +received the EAP identity request, and _before_ the TLS session setup +has started. + +The simplest way to do this is via the following `unlang` statements: + +``` +authenticate { + ... + Auth-Type eap { + if ("%{unpack:&EAP-Message 4 byte}" == 1) { + update control { + TLS-Session-Cert-File := "${certdir}/realms/%{Realm}" + } + } + + eap + } + ... +} +``` + +This configuration looks at the `EAP-Message` attribute, and checks if +it is an EAP-Identity packet. If so, it then adds a special attribute +`TLS-Session-Cert-File`, with a value based on the `Realm`, from the +`User-Name`. That setting tells the server to look in the file for a +certificate. + +If the file is there, and contains a correctly formatted `PEM` +certificate chain, then it is loaded and used. + +If the file does not exist, or the file does not contain a correctly +formatted `PEM` certificate chain, then the user is rejected. + +### Format + +This file should contain the server certificate, followed by +intermediate certificates, in order. i.e. If we have a server +certificate signed by CA1, which is signed by CA2, which is signed by +a root CA, then the "certificate_file" should contain server.pem, +followed by CA1.pem, followed by CA2.pem. + +When using `ca_file` or `ca_dir`, the file should contain only the +server certificate. + +### Private Key + +The private should be placed in the same file as the other +certificates, but at the start. + +``` +private key +server cert +... +ca cert +``` + +The private key can also be placed into a separate file. The filename +should be placed into the `TLS-Session-Cert-Private-Key-File` +attribute. + +For simplicity, the private keys _should not_ have passwords. There +is essentially no security benefit to "securing" the key with a +password, and then placing the password into the file system, right +next to the private key. + +### Realms + +There is no need to place the certificates into files named for each +realm. However, it is by far and away the easiest way to manage these +certificate chains. + +For every realm which is handles this way, the `proxy.conf` file +should define a _local_ realm. That is, it should contain a +definition such as: + +``` +example.org { +} +``` + +This defines the realm `example.org`, and tells FreeRADIUS that there +are no home servers associated with the realm. + +The `suffix` module should also be configured, as per the default +configuration. i.e. list `suffix` in the `authorize` section _before_ +the `eap` module. + +### Caveats + +The root CA certificate for the server certificate should be located +in the `ca_dir`, along with other root CAs. If the root CA is not +there, then it *must* be included at the end of the file. + +These certificates will be loaded and parsed _for every matching +authentication request_. That limitation means that dynamic loading +of the certificates is likely be slow, and to severely impact +performance. The good news is that we can fix that with a little more +configuration. + +## Preloading Certificate Chains + +The server can also pre-load certificate chains. In the EAP module, +you can do: + +``` +eap { + ... + tls { + ... + realm_dir = ${certdir}/realms/ + ... + } + ... +} +``` + +Each file in that directory should be a `PEM` encoded certificate +chain, as described in the previous section. For safety, every file +*must* have a `.pem` as the filename extension. +e.g. `example.org.pem`. + +If there is a corresponding private key, it should be placed into a +`.key` file. e.g. `example.org.key`. + +These certificates will be loaded when the server starts, and cached +for the lifetime of the server. There is no way to reload these +certificates dynamically, the server must be restarted. + +Once the `realm_dir` configuration has been added, the selection of +certificates is identical to that described in the previous section. +Just set `TLS-Session-Cert-File`, and the server will figure it out. + +However, it is possible to dynamically add new certificate, and have +the server pick it up. In fact, as the process for choosing +certificates are the same, the server will do this automatically! + +## RadSec + +The above configuration applies to RadSec, too, as the `tls` +configuration in the server is for all TLS functionality, and not just +EAP. + +This means that the server can accept RadSec connections, and then +present different server certificates to different clients. + +For this functionality to work, the certificates for EAP and RadSec +*should* be in separate directories. + +### Clients + +RadSec clients can set the SNI to send in the `tls` subsection of the +`home_server` definition. Look for "SNI" in `sites-available/tls`, +and see the `hostname` configuration item for documentation. + +For example, an identity provider could host multiple sites, but +present itself with one public IP address. If the RadSec clients do +not use SNI, then they must be configured with the certificate of the +identity provider. + +When SNI is used, the RadSec clients can be configured with the +certificate of the hosted system that they're connecting to. This +ability means that there is no need to change certificates when +changing providers. In addition, there is no need to change the +configuration of all RadSec clients when the hosting system changes +its certifiates. Because the hosting system certificates are never +used. + +Instead, each hosted company is responsible for its own certificates, +and for its own RadSec clients. + +SNI also permits the use of a load balancer such as haproxy. That +load balancer can terminate the TLS connection, and then use SNI to +route the underlying RADIUS TCP traffic to a particular host. + +### Servers + +See the `realm_dir` configuration item in the `tls` subsection for the +location of the server certificates. + +If the server receives an SNI for a realm it does not recognize, it +will just use the default TLS configuration. + +If the realm is recognized (i.e. there is a file in +`${realm_dir}/%{TLS-Server-Name-Indication}.pem`, then that certificate will be chosen, and +present to the RadSec client. If there is no such file, then the +default TLS configuration is used. + +The current behavior is to _require_ that the server certificate is in +a file which taken from +`${realm_dir}/%{TLS-Server-Name-Indication}.pem`. Only the +`realm_dir` portion of the filename is configurable. The SNI portion +is taken from the TLS messages, and the `.pem` suffix is hard-coded in +the source code. + +Taking the filename from an untrusted source is fine here. The +standard (RFC 6066 Section 3) says that the Server Name Indication +field is a DNS "A label". Which means that there are a limited number +of characters allowed: + +* `.`, `-`, `a-Z`, `A-Z`, `0-9` + +If the SNI contain anything else, the TLS connection is rejected. + +Note that if session resumption is enabled for RadSec, the session +cache *must* also cache the `TLS-Server-Name-Indication` attribute. +The SNI is sent on resumption for TLS 1.2 and earlier, but it is not +sent for TLS 1.3. As such, the only way to select the right policy on +resumption is to check the value of the cached +TLS-Server-Name-Indication attribute. + diff --git a/raddb/certs/server.cnf b/raddb/certs/server.cnf new file mode 100644 index 0000000..daca18d --- /dev/null +++ b/raddb/certs/server.cnf @@ -0,0 +1,72 @@ +[ ca ] +default_ca = CA_default + +[ CA_default ] +dir = ./ +certs = $dir +crl_dir = $dir/crl +database = $dir/index.txt +new_certs_dir = $dir +certificate = $dir/server.pem +serial = $dir/serial +crl = $dir/crl.pem +private_key = $dir/server.key +RANDFILE = $dir/.rand +name_opt = ca_default +cert_opt = ca_default +default_days = 60 +default_crl_days = 30 +default_md = sha256 +preserve = no +policy = policy_match +copy_extensions = copy + +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +prompt = no +distinguished_name = server +default_bits = 2048 +input_password = whatever +output_password = whatever +#req_extensions = v3_req + +[server] +countryName = FR +stateOrProvinceName = Radius +localityName = Somewhere +organizationName = Example Inc. +emailAddress = admin@example.org +commonName = "Example Server Certificate" + +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment +subjectAltName = @alt_names +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always + +# This should be a host name of the RADIUS server. +# Note that the host name is exchanged in EAP *before* +# the user machine has network access. So the host name +# here doesn't really have to match anything in DNS. +[alt_names] +DNS.1 = radius.example.com + +# NAIRealm from RFC 7585 +otherName.0 = 1.3.6.1.5.5.7.8.8;FORMAT:UTF8,UTF8:*.example.com diff --git a/raddb/certs/xpextensions b/raddb/certs/xpextensions new file mode 100644 index 0000000..ae87f42 --- /dev/null +++ b/raddb/certs/xpextensions @@ -0,0 +1,75 @@ +# +# File containing the OIDs required for Windows +# and iOS +# +# http://support.microsoft.com/kb/814394/en-us +# +# https://support.apple.com/en-us/HT210176 +# +[ xpclient_ext] +extendedKeyUsage = 1.3.6.1.5.5.7.3.2 +crlDistributionPoints = URI:http://www.example.com/example_ca.crl + +[ xpserver_ext] +extendedKeyUsage = 1.3.6.1.5.5.7.3.1 +crlDistributionPoints = URI:http://www.example.com/example_ca.crl + +# Enterprise Wi-Fi clients from 2020 onwards which have the +# Wi-Fi Certified WPA3 Release 2 (December 2019) certification +# honour the following two policies for enhanced security +# posture regarding certificate validation: +# +# https://www.wi-fi.org/discover-wi-fi/security +# +# Adding the 'Trust Override Disabled - STRICT' policy means that +# the client device is not allowed to request and accept ad-hoc +# trust decisions from the user ("Is this the certificate you +# expect here?") and instead aborts authentication until the +# device has been properly configured using out-of-band means +# with all the details needed to verify the certificate (i.e. +# either the tuple (CA, server name) or the literal server cert). +# +# Adding the 'Trust Override Disabled - TOFU' policy means that +# the client device is allowed to ask the end user for such an +# override exactly once, when first connecting to an unknown +# network. Once the network is known and the trust decision made, +# any other certificate that is presented and would require +# another override is rejected and authentication aborted. +# +# Both of these policies provide a protection against rogue +# authentication servers in that they make sure configurations +# on end user devices are sufficient to identify the genuine +# server. +# +# The difference is that the TOFU policy allows a leap of faith +# on first sight of a network ONCE - very much comparable to +# how SSH establishes trust in a new host. This adds convenience +# for end users who did not bother to configure their devices +# beforehand, but adds an element of uncertainty in that the +# attacker could be present on that first contact with the network. +# +# Network administrators who consider the TOFU leap of faith +# unacceptable should choose STRICT; everyone else gains security +# by choosing TOFU without giving up on convenience for their +# end users. +# +# For completeness, it is also possible to include none of the +# two to stay with the "anything goes" that was the situation +# prior to Wi-Fi Certified WPA3 Release December 2019. +# +# This is the 'Trust Override Disabled - STRICT' policy. +#certificatePolicies = 1.3.6.1.4.1.40808.1.3.1 +# This is the 'Trust Override Disabled - TOFU' policy. +certificatePolicies = 1.3.6.1.4.1.40808.1.3.2 + +# +# Add this to the PKCS#7 keybag attributes holding the client's private key +# for machine authentication. +# +# the presence of this OID tells Windows XP that the cert is intended +# for use by the computer itself, and not by an end-user. +# +# The other solution is to use Microsoft's web certificate server +# to generate these certs. +# +# 1.3.6.1.4.1.311.17.2 |