summaryrefslogtreecommitdiffstats
path: root/raddb/certs/realms/README.md
blob: 9f754fac193c396d3841766f5dc5dee3a8da297e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
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.