All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
rlm_eap_tls.c
Go to the documentation of this file.
1 /*
2  * rlm_eap_tls.c contains the interfaces that are called from eap
3  *
4  * Version: $Id: 05a531ffb631f03c257cf7756f2f1bf3706a7727 $
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 2001 hereUare Communications, Inc. <raghud@hereuare.com>
21  * Copyright 2003 Alan DeKok <aland@freeradius.org>
22  * Copyright 2006 The FreeRADIUS server project
23  *
24  */
25 
26 RCSID("$Id: 05a531ffb631f03c257cf7756f2f1bf3706a7727 $")
27 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
28 
29 #ifdef HAVE_OPENSSL_RAND_H
30 #include <openssl/rand.h>
31 #endif
32 
33 #ifdef HAVE_OPENSSL_EVP_H
34 #include <openssl/evp.h>
35 #endif
36 
37 #include "rlm_eap_tls.h"
38 
39 #ifdef HAVE_SYS_STAT_H
40 #include <sys/stat.h>
41 #endif
42 
44  { FR_CONF_OFFSET("tls", PW_TYPE_STRING, rlm_eap_tls_t, tls_conf_name) },
45 
46  { FR_CONF_OFFSET("require_client_cert", PW_TYPE_BOOLEAN, rlm_eap_tls_t, req_client_cert), .dflt = "yes" },
47 
48  { FR_CONF_OFFSET("virtual_server", PW_TYPE_STRING, rlm_eap_tls_t, virtual_server) },
50 };
51 
52 
53 /*
54  * Attach the EAP-TLS module.
55  */
56 static int mod_instantiate(CONF_SECTION *cs, void **instance)
57 {
59 
60  /*
61  * Parse the config file & get all the configured values
62  */
63  *instance = inst = talloc_zero(cs, rlm_eap_tls_t);
64  if (!inst) return -1;
65 
66  if (cf_section_parse(cs, inst, module_config) < 0) {
67  return -1;
68  }
69 
70  inst->tls_conf = eap_tls_conf_parse(cs, "tls");
71 
72  if (!inst->tls_conf) {
73  ERROR("rlm_eap_tls: Failed initializing SSL context");
74  return -1;
75  }
76 
77  return 0;
78 }
79 
80 static int CC_HINT(nonnull) mod_process(void *instance, eap_session_t *eap_session);
81 
82 /*
83  * Send an initial eap-tls request to the peer, using the libeap functions.
84  */
85 static int mod_session_init(void *type_arg, eap_session_t *eap_session)
86 {
87  tls_session_t *tls_session;
89  VALUE_PAIR *vp;
90  bool client_cert;
91 
92  inst = type_arg;
93 
94  eap_session->tls = true;
95 
96  /*
97  * EAP-TLS-Require-Client-Cert attribute will override
98  * the require_client_cert configuration option.
99  */
100  vp = fr_pair_find_by_num(eap_session->request->config, 0, PW_EAP_TLS_REQUIRE_CLIENT_CERT, TAG_ANY);
101  if (vp) {
102  client_cert = vp->vp_integer ? true : false;
103  } else {
104  client_cert = inst->req_client_cert;
105  }
106 
107  /*
108  * EAP-TLS always requires a client certificate.
109  */
110  tls_session = eap_tls_session_init(eap_session, inst->tls_conf, client_cert);
111  if (!tls_session) return 0;
112 
113  eap_session->opaque = ((void *)tls_session);
114 
115  /*
116  * Set up type-specific information.
117  */
118  tls_session->prf_label = "client EAP encryption";
119 
120  /*
121  * TLS session initialization is over. Now handle TLS
122  * related handshaking or application data.
123  */
124  if (eap_tls_start(eap_session) < 0) {
125  talloc_free(tls_session);
126  return 0;
127  }
128 
129  eap_session->process = mod_process;
130 
131  return 1;
132 }
133 
134 /*
135  * Do authentication, by letting EAP-TLS do most of the work.
136  */
137 static int CC_HINT(nonnull) mod_process(void *type_arg, eap_session_t *eap_session)
138 {
139  fr_tls_status_t status;
140  tls_session_t *tls_session = (tls_session_t *) eap_session->opaque;
141  REQUEST *request = eap_session->request;
143 
144  inst = type_arg;
145 
146  status = eap_tls_process(eap_session);
147  if ((status == FR_TLS_INVALID) || (status == FR_TLS_FAIL)) {
148  REDEBUG("[eap-tls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
149  } else {
150  RDEBUG2("[eap-tls process] = %s", fr_int2str(fr_tls_status_table, status, "<INVALID>"));
151  }
152 
153  switch (status) {
154  /*
155  * EAP-TLS handshake was successful, return an
156  * EAP-TLS-Success packet here.
157  *
158  * If a virtual server was configured, check that
159  * it accepts the certificates, too.
160  */
161  case FR_TLS_SUCCESS:
162  if (inst->virtual_server) {
163  VALUE_PAIR *vp;
164  REQUEST *fake;
165 
166  /* create a fake request */
167  fake = request_alloc_fake(request);
168  rad_assert(!fake->packet->vps);
169 
170  fake->packet->vps = fr_pair_list_copy(fake->packet, request->packet->vps);
171 
172  /* set the virtual server to use */
173  if ((vp = fr_pair_find_by_num(request->config, 0, PW_VIRTUAL_SERVER, TAG_ANY)) != NULL) {
174  fake->server = vp->vp_strvalue;
175  } else {
176  fake->server = inst->virtual_server;
177  }
178 
179  RDEBUG2("Validating certificate");
180  rad_virtual_server(fake);
181 
182  /* copy the reply vps back to our reply */
183  fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps, &fake->reply->vps, 0, 0,
184  TAG_ANY);
185 
186  /* reject if virtual server didn't return accept */
187  if (fake->reply->code != PW_CODE_ACCESS_ACCEPT) {
188  RDEBUG2("Certificate rejected by the virtual server");
189  talloc_free(fake);
190  eap_tls_fail(eap_session);
191  return 0;
192  }
193 
194  talloc_free(fake);
195  /* success */
196  }
197  break;
198 
199  /*
200  * The TLS code is still working on the TLS
201  * exchange, and it's a valid TLS request.
202  * do nothing.
203  */
204  case FR_TLS_HANDLED:
205  return 1;
206 
207  /*
208  * Handshake is done, proceed with decoding tunneled
209  * data.
210  */
211  case FR_TLS_RECORD_COMPLETE:
212  RDEBUG2("Received unexpected tunneled data after successful handshake");
213 #ifndef NDEBUG
214  if ((rad_debug_lvl > 2) && fr_log_fp) {
215  unsigned int i;
216  unsigned int data_len;
217  unsigned char buffer[1024];
218 
219  data_len = (tls_session->record_to_buff)(&tls_session->dirty_in,
220  buffer, sizeof(buffer));
221  DEBUG(" Tunneled data (%u bytes)", data_len);
222  for (i = 0; i < data_len; i++) {
223  if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, " %x: ", i);
224  if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
225 
226  fprintf(fr_log_fp, "%02x ", buffer[i]);
227  }
228  fprintf(fr_log_fp, "\n");
229  }
230 #endif
231 
232  eap_tls_fail(eap_session);
233  return 0;
234 
235  /*
236  * Anything else: fail.
237  *
238  * Also, remove the session from the cache so that
239  * the client can't re-use it.
240  */
241  default:
242  tls_fail(tls_session);
243 
244  return 0;
245  }
246 
247  /*
248  * Success: Automatically return MPPE keys.
249  */
250  if (eap_tls_success(eap_session) < 0) return 0;
251  return 1;
252 }
253 
254 /*
255  * The module name should be the only globally exported symbol.
256  * That is, everything else should be 'static'.
257  */
259 rlm_eap_module_t rlm_eap_tls = {
260  .name = "eap_tls",
261  .instantiate = mod_instantiate, /* Create new submodule instance */
262  .session_init = mod_session_init, /* Initialise a new EAP session */
263  .process = mod_process /* Process next round of EAP method */
264 };
FILE * fr_log_fp
Definition: radius.c:81
void fr_pair_list_mcopy_by_num(TALLOC_CTX *ctx, VALUE_PAIR **to, VALUE_PAIR **from, unsigned int vendor, unsigned int attr, int8_t tag)
Copy / delete matching pairs between VALUE_PAIR lists.
Definition: pair.c:1823
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define CONF_PARSER_TERMINATOR
Definition: conffile.h:289
fr_tls_server_conf_t * tls_conf
Shared TLS configuration structure.
Definition: rlm_eap_tls.h:39
#define inst
static int mod_process(void *instance, eap_session_t *eap_session)
Definition: rlm_eap_gtc.c:132
REQUEST * request_alloc_fake(REQUEST *oldreq)
Definition: request.c:124
Defines a CONF_PAIR to C data type mapping.
Definition: conffile.h:267
static int mod_session_init(void *instance, eap_session_t *eap_session)
Definition: rlm_eap_gtc.c:89
#define rad_assert(expr)
Definition: rad_assert.h:38
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
Definition: pair.c:1394
#define DEBUG(fmt,...)
Definition: log.h:175
int eap_tls_success(eap_session_t *eap_session)
Send an EAP-TLS success.
Definition: eap_tls.c:211
Tracks the progress of a single session of any EAP method.
Definition: eap.h:60
int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables)
Parse a configuration section into user-supplied variables.
Definition: conffile.c:2234
unsigned int code
Packet code (type).
Definition: libradius.h:155
static int mod_instantiate(CONF_SECTION *cs, void **instance)
Definition: rlm_eap_tls.c:56
RFC2865 - Access-Accept.
Definition: radius.h:93
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
fr_tls_status_t eap_tls_process(eap_session_t *eap_session)
Process an EAP TLS request.
Definition: eap_tls.c:708
A truth value.
Definition: radius.h:56
char const * name
The name of the sub-module (without rlm_ prefix).
Definition: eap.h:96
static USES_APPLE_DEPRECATED_API CONF_PARSER module_config[]
Definition: rlm_eap_tls.c:43
#define RDEBUG2(fmt,...)
Definition: log.h:244
static int CC_HINT(nonnull)
Definition: rlm_eap_tls.c:80
tls_session_t * eap_tls_session_init(eap_session_t *eap_session, fr_tls_server_conf_t *tls_conf, bool client_cert)
Create a new tls_session_t associated with an eap_session_t.
Definition: eap_tls.c:844
#define TAG_ANY
Definition: pair.h:191
Interface to call EAP sub mdoules.
Definition: eap.h:95
static const void * fake
Definition: rlm_sql_null.c:33
#define FR_CONF_OFFSET(_n, _t, _s, _f)
Definition: conffile.h:168
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
rlm_eap_module_t rlm_eap_tls
Definition: rlm_eap_tls.c:259
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
#define REDEBUG(fmt,...)
Definition: log.h:254
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
int eap_tls_fail(eap_session_t *eap_session)
Send an EAP-TLS failure.
Definition: eap_tls.c:254
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
Definition: token.c:506
fr_tls_server_conf_t * eap_tls_conf_parse(CONF_SECTION *cs, char const *attr)
Parse TLS configuration.
Definition: eap_tls.c:891
String of printable characters.
Definition: radius.h:33
bool req_client_cert
Whether we require the client to provide a certificate or not.
Definition: rlm_eap_tls.h:41
#define RCSID(id)
Definition: build.h:135
int rad_virtual_server(REQUEST *)
Definition: auth.c:659
int eap_tls_start(eap_session_t *eap_session)
Send an initial EAP-TLS request to the peer.
Definition: eap_tls.c:192
#define ERROR(fmt,...)
Definition: log.h:145
char const * server
Definition: radiusd.h:289
#define USES_APPLE_DEPRECATED_API
Definition: build.h:122