Make client_cert bool everywhere
[freeradius.git] / src / modules / rlm_eap / types / rlm_eap_ttls / rlm_eap_ttls.c
1 /*
2  * rlm_eap_ttls.c  contains the interfaces that are called from eap
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2003 Alan DeKok <aland@freeradius.org>
21  * Copyright 2006 The FreeRADIUS server project
22  */
23
24 RCSID("$Id$")
25 USES_APPLE_DEPRECATED_API       /* OpenSSL API has been deprecated by Apple */
26
27 #include "eap_ttls.h"
28
29 typedef struct rlm_eap_ttls_t {
30         /*
31          *      TLS configuration
32          */
33         char const *tls_conf_name;
34         fr_tls_server_conf_t *tls_conf;
35
36         /*
37          *      Default tunneled EAP type
38          */
39         char const *default_method_name;
40         int default_method;
41
42         /*
43          *      Use the reply attributes from the tunneled session in
44          *      the non-tunneled reply to the client.
45          */
46         bool use_tunneled_reply;
47
48         /*
49          *      Use SOME of the request attributes from outside of the
50          *      tunneled session in the tunneled request
51          */
52         bool copy_request_to_tunnel;
53
54         /*
55          *      RFC 5281 (TTLS) says that the length field MUST NOT be
56          *      in fragments after the first one.  However, we've done
57          *      it that way for years, and no one has complained.
58          *
59          *      In the interests of allowing the server to follow the
60          *      RFC, we add the option here.  If set to "no", it sends
61          *      the length field in ONLY the first fragment.
62          */
63         bool include_length;
64
65         /*
66          *      Virtual server for inner tunnel session.
67          */
68         char const *virtual_server;
69
70         /*
71          *      Do we do require a client cert?
72          */
73         bool req_client_cert;
74 } rlm_eap_ttls_t;
75
76
77 static CONF_PARSER module_config[] = {
78         { "tls", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, tls_conf_name), NULL },
79         { "default_eap_type", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, default_method_name), "md5" },
80         { "copy_request_to_tunnel", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, copy_request_to_tunnel), "no" },
81         { "use_tunneled_reply", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, use_tunneled_reply), "no" },
82         { "virtual_server", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_eap_ttls_t, virtual_server), NULL },
83         { "include_length", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, include_length), "yes" },
84         { "require_client_cert", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_eap_ttls_t, req_client_cert), "no" },
85
86         { NULL, -1, 0, NULL, NULL }        /* end the list */
87 };
88
89
90 /*
91  *      Attach the module.
92  */
93 static int eapttls_attach(CONF_SECTION *cs, void **instance)
94 {
95         rlm_eap_ttls_t          *inst;
96
97         *instance = inst = talloc_zero(cs, rlm_eap_ttls_t);
98         if (!inst) return -1;
99
100         /*
101          *      Parse the configuration attributes.
102          */
103         if (cf_section_parse(cs, inst, module_config) < 0) {
104                 return -1;
105         }
106
107         /*
108          *      Convert the name to an integer, to make it easier to
109          *      handle.
110          */
111         inst->default_method = eap_name2type(inst->default_method_name);
112         if (inst->default_method < 0) {
113                 ERROR("rlm_eap_ttls: Unknown EAP type %s",
114                        inst->default_method_name);
115                 return -1;
116         }
117
118         /*
119          *      Read tls configuration, either from group given by 'tls'
120          *      option, or from the eap-tls configuration.
121          */
122         inst->tls_conf = eaptls_conf_parse(cs, "tls");
123
124         if (!inst->tls_conf) {
125                 ERROR("rlm_eap_ttls: Failed initializing SSL context");
126                 return -1;
127         }
128
129         return 0;
130 }
131
132
133 /*
134  *      Free the TTLS per-session data
135  */
136 static void ttls_free(void *p)
137 {
138         ttls_tunnel_t *t = (ttls_tunnel_t *) p;
139
140         if (!t) return;
141
142         rad_assert(talloc_get_type_abort(t, ttls_tunnel_t) != NULL);
143
144         if (t->username) {
145                 DEBUG2("rlm_eap_ttls: Freeing handler for user %s",
146                        t->username->vp_strvalue);
147         }
148
149         pairfree(&t->username);
150         pairfree(&t->state);
151         pairfree(&t->accept_vps);
152         talloc_free(t);
153 }
154
155
156 /*
157  *      Allocate the TTLS per-session data
158  */
159 static ttls_tunnel_t *ttls_alloc(rlm_eap_ttls_t *inst, eap_handler_t *handler)
160 {
161         ttls_tunnel_t *t;
162
163         t = talloc_zero(handler, ttls_tunnel_t);
164
165         t->default_method = inst->default_method;
166         t->copy_request_to_tunnel = inst->copy_request_to_tunnel;
167         t->use_tunneled_reply = inst->use_tunneled_reply;
168         t->virtual_server = inst->virtual_server;
169         return t;
170 }
171
172
173 /*
174  *      Send an initial eap-tls request to the peer, using the libeap functions.
175  */
176 static int eapttls_initiate(void *type_arg, eap_handler_t *handler)
177 {
178         int             status;
179         tls_session_t   *ssn;
180         rlm_eap_ttls_t  *inst;
181         VALUE_PAIR      *vp;
182         bool            client_cert;
183         REQUEST         *request = handler->request;
184
185         inst = type_arg;
186
187         handler->tls = true;
188         handler->finished = false;
189
190         /*
191          *      Check if we need a client certificate.
192          */
193
194         /*
195          * EAP-TLS-Require-Client-Cert attribute will override
196          * the require_client_cert configuration option.
197          */
198         vp = pairfind(handler->request->config_items, PW_EAP_TLS_REQUIRE_CLIENT_CERT, 0, TAG_ANY);
199         if (vp) {
200                 client_cert = vp->vp_integer ? true : false;
201         } else {
202                 client_cert = inst->req_client_cert;
203         }
204
205         ssn = eaptls_session(handler, inst->tls_conf, client_cert);
206         if (!ssn) {
207                 return 0;
208         }
209
210         handler->opaque = ((void *)ssn);
211
212         /*
213          *      Set up type-specific information.
214          */
215         ssn->prf_label = "ttls keying material";
216
217         /*
218          *      TLS session initialization is over.  Now handle TLS
219          *      related handshaking or application data.
220          */
221         status = eaptls_start(handler->eap_ds, ssn->peap_flag);
222         RDEBUG2("Start returned %d", status);
223         if (status == 0) {
224                 return 0;
225         }
226
227         /*
228          *      The next stage to process the packet.
229          */
230         handler->stage = AUTHENTICATE;
231
232         return 1;
233 }
234
235
236 /*
237  *      Do authentication, by letting EAP-TLS do most of the work.
238  */
239 static int mod_authenticate(void *arg, eap_handler_t *handler)
240 {
241         int rcode;
242         fr_tls_status_t status;
243         rlm_eap_ttls_t *inst = (rlm_eap_ttls_t *) arg;
244         tls_session_t *tls_session = (tls_session_t *) handler->opaque;
245         ttls_tunnel_t *t = (ttls_tunnel_t *) tls_session->opaque;
246         REQUEST *request = handler->request;
247
248         RDEBUG2("Authenticate");
249
250         tls_session->length_flag = inst->include_length;
251
252         /*
253          *      Process TLS layer until done.
254          */
255         status = eaptls_process(handler);
256         RDEBUG2("eaptls_process returned %d\n", status);
257         switch (status) {
258                 /*
259                  *      EAP-TLS handshake was successful, tell the
260                  *      client to keep talking.
261                  *
262                  *      If this was EAP-TLS, we would just return
263                  *      an EAP-TLS-Success packet here.
264                  */
265         case FR_TLS_SUCCESS:
266                 if (SSL_session_reused(tls_session->ssl)) {
267                         RDEBUG("Skipping Phase2 due to session resumption");
268                         goto do_keys;
269                 }
270
271                 if (t && t->authenticated) {
272                         RDEBUG2("Using saved attributes from the original Access-Accept");
273                         debug_pair_list(t->accept_vps);
274                         pairfilter(handler->request->reply,
275                                   &handler->request->reply->vps,
276                                   &t->accept_vps, 0, 0, TAG_ANY);
277                 do_keys:
278                         /*
279                          *      Success: Automatically return MPPE keys.
280                          */
281                         return eaptls_success(handler, 0);
282                 } else {
283                         eaptls_request(handler->eap_ds, tls_session);
284                 }
285                 return 1;
286
287                 /*
288                  *      The TLS code is still working on the TLS
289                  *      exchange, and it's a valid TLS request.
290                  *      do nothing.
291                  */
292         case FR_TLS_HANDLED:
293                 return 1;
294
295                 /*
296                  *      Handshake is done, proceed with decoding tunneled
297                  *      data.
298                  */
299         case FR_TLS_OK:
300                 break;
301
302                 /*
303                  *      Anything else: fail.
304                  */
305         default:
306                 return 0;
307         }
308
309         /*
310          *      Session is established, proceed with decoding
311          *      tunneled data.
312          */
313         RDEBUG2("Session established.  Proceeding to decode tunneled attributes");
314
315         /*
316          *      We may need TTLS data associated with the session, so
317          *      allocate it here, if it wasn't already alloacted.
318          */
319         if (!tls_session->opaque) {
320                 tls_session->opaque = ttls_alloc(inst, handler);
321                 tls_session->free_opaque = ttls_free;
322         }
323
324         /*
325          *      Process the TTLS portion of the request.
326          */
327         rcode = eapttls_process(handler, tls_session);
328         switch (rcode) {
329         case PW_CODE_ACCESS_REJECT:
330                 eaptls_fail(handler, 0);
331                 return 0;
332
333                 /*
334                  *      Access-Challenge, continue tunneled conversation.
335                  */
336         case PW_CODE_ACCESS_CHALLENGE:
337                 eaptls_request(handler->eap_ds, tls_session);
338                 return 1;
339
340                 /*
341                  *      Success: Automatically return MPPE keys.
342                  */
343         case PW_CODE_ACCESS_ACCEPT:
344                 return eaptls_success(handler, 0);
345
346                 /*
347                  *      No response packet, MUST be proxying it.
348                  *      The main EAP module will take care of discovering
349                  *      that the request now has a "proxy" packet, and
350                  *      will proxy it, rather than returning an EAP packet.
351                  */
352         case PW_CODE_STATUS_CLIENT:
353 #ifdef WITH_PROXY
354                 rad_assert(handler->request->proxy != NULL);
355 #endif
356                 return 1;
357                 break;
358
359         default:
360                 break;
361         }
362
363         /*
364          *      Something we don't understand: Reject it.
365          */
366         eaptls_fail(handler, 0);
367         return 0;
368 }
369
370 /*
371  *      The module name should be the only globally exported symbol.
372  *      That is, everything else should be 'static'.
373  */
374 rlm_eap_module_t rlm_eap_ttls = {
375         "eap_ttls",
376         eapttls_attach,                 /* attach */
377         eapttls_initiate,               /* Start the initial request */
378         NULL,                           /* authorization */
379         mod_authenticate,               /* authentication */
380         NULL                            /* detach */
381 };