/src/hostap/src/ap/authsrv.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Authentication server setup |
3 | | * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> |
4 | | * |
5 | | * This software may be distributed under the terms of the BSD license. |
6 | | * See README for more details. |
7 | | */ |
8 | | |
9 | | #include "utils/includes.h" |
10 | | |
11 | | #include "utils/common.h" |
12 | | #include "crypto/crypto.h" |
13 | | #include "crypto/tls.h" |
14 | | #include "eap_server/eap.h" |
15 | | #include "eap_server/eap_sim_db.h" |
16 | | #include "eapol_auth/eapol_auth_sm.h" |
17 | | #include "radius/radius_server.h" |
18 | | #include "hostapd.h" |
19 | | #include "ap_config.h" |
20 | | #include "sta_info.h" |
21 | | #include "authsrv.h" |
22 | | |
23 | | |
24 | | #if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA) |
25 | | #define EAP_SIM_DB |
26 | | #endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */ |
27 | | |
28 | | |
29 | | #ifdef EAP_SIM_DB |
30 | | static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd, |
31 | | struct sta_info *sta, void *ctx) |
32 | | { |
33 | | if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0) |
34 | | return 1; |
35 | | return 0; |
36 | | } |
37 | | |
38 | | |
39 | | static void hostapd_sim_db_cb(void *ctx, void *session_ctx) |
40 | | { |
41 | | struct hostapd_data *hapd = ctx; |
42 | | if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) { |
43 | | #ifdef RADIUS_SERVER |
44 | | radius_server_eap_pending_cb(hapd->radius_srv, session_ctx); |
45 | | #endif /* RADIUS_SERVER */ |
46 | | } |
47 | | } |
48 | | #endif /* EAP_SIM_DB */ |
49 | | |
50 | | |
51 | | #ifdef RADIUS_SERVER |
52 | | |
53 | | static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity, |
54 | | size_t identity_len, int phase2, |
55 | | struct eap_user *user) |
56 | | { |
57 | | const struct hostapd_eap_user *eap_user; |
58 | | int i; |
59 | | int rv = -1; |
60 | | |
61 | | eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2); |
62 | | if (eap_user == NULL) |
63 | | goto out; |
64 | | |
65 | | if (user == NULL) |
66 | | return 0; |
67 | | |
68 | | os_memset(user, 0, sizeof(*user)); |
69 | | for (i = 0; i < EAP_MAX_METHODS; i++) { |
70 | | user->methods[i].vendor = eap_user->methods[i].vendor; |
71 | | user->methods[i].method = eap_user->methods[i].method; |
72 | | } |
73 | | |
74 | | if (eap_user->password) { |
75 | | user->password = os_memdup(eap_user->password, |
76 | | eap_user->password_len); |
77 | | if (user->password == NULL) |
78 | | goto out; |
79 | | user->password_len = eap_user->password_len; |
80 | | user->password_hash = eap_user->password_hash; |
81 | | if (eap_user->salt && eap_user->salt_len) { |
82 | | user->salt = os_memdup(eap_user->salt, |
83 | | eap_user->salt_len); |
84 | | if (!user->salt) |
85 | | goto out; |
86 | | user->salt_len = eap_user->salt_len; |
87 | | } |
88 | | } |
89 | | user->force_version = eap_user->force_version; |
90 | | user->macacl = eap_user->macacl; |
91 | | user->ttls_auth = eap_user->ttls_auth; |
92 | | user->remediation = eap_user->remediation; |
93 | | user->accept_attr = eap_user->accept_attr; |
94 | | user->t_c_timestamp = eap_user->t_c_timestamp; |
95 | | rv = 0; |
96 | | |
97 | | out: |
98 | | if (rv) |
99 | | wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__); |
100 | | |
101 | | return rv; |
102 | | } |
103 | | |
104 | | |
105 | | static int hostapd_setup_radius_srv(struct hostapd_data *hapd) |
106 | | { |
107 | | struct radius_server_conf srv; |
108 | | struct hostapd_bss_config *conf = hapd->conf; |
109 | | os_memset(&srv, 0, sizeof(srv)); |
110 | | srv.client_file = conf->radius_server_clients; |
111 | | srv.auth_port = conf->radius_server_auth_port; |
112 | | srv.acct_port = conf->radius_server_acct_port; |
113 | | srv.conf_ctx = hapd; |
114 | | srv.ipv6 = conf->radius_server_ipv6; |
115 | | srv.get_eap_user = hostapd_radius_get_eap_user; |
116 | | srv.eap_req_id_text = conf->eap_req_id_text; |
117 | | srv.eap_req_id_text_len = conf->eap_req_id_text_len; |
118 | | srv.sqlite_file = conf->eap_user_sqlite; |
119 | | #ifdef CONFIG_RADIUS_TEST |
120 | | srv.dump_msk_file = conf->dump_msk_file; |
121 | | #endif /* CONFIG_RADIUS_TEST */ |
122 | | #ifdef CONFIG_HS20 |
123 | | srv.subscr_remediation_url = conf->subscr_remediation_url; |
124 | | srv.subscr_remediation_method = conf->subscr_remediation_method; |
125 | | srv.hs20_sim_provisioning_url = conf->hs20_sim_provisioning_url; |
126 | | srv.t_c_server_url = conf->t_c_server_url; |
127 | | #endif /* CONFIG_HS20 */ |
128 | | srv.erp_domain = conf->erp_domain; |
129 | | srv.eap_cfg = hapd->eap_cfg; |
130 | | |
131 | | hapd->radius_srv = radius_server_init(&srv); |
132 | | if (hapd->radius_srv == NULL) { |
133 | | wpa_printf(MSG_ERROR, "RADIUS server initialization failed."); |
134 | | return -1; |
135 | | } |
136 | | |
137 | | return 0; |
138 | | } |
139 | | |
140 | | #endif /* RADIUS_SERVER */ |
141 | | |
142 | | |
143 | | #ifdef EAP_TLS_FUNCS |
144 | | static void authsrv_tls_event(void *ctx, enum tls_event ev, |
145 | | union tls_event_data *data) |
146 | | { |
147 | | switch (ev) { |
148 | | case TLS_CERT_CHAIN_SUCCESS: |
149 | | wpa_printf(MSG_DEBUG, "authsrv: remote certificate verification success"); |
150 | | break; |
151 | | case TLS_CERT_CHAIN_FAILURE: |
152 | | wpa_printf(MSG_INFO, "authsrv: certificate chain failure: reason=%d depth=%d subject='%s' err='%s'", |
153 | | data->cert_fail.reason, |
154 | | data->cert_fail.depth, |
155 | | data->cert_fail.subject, |
156 | | data->cert_fail.reason_txt); |
157 | | break; |
158 | | case TLS_PEER_CERTIFICATE: |
159 | | wpa_printf(MSG_DEBUG, "authsrv: peer certificate: depth=%d serial_num=%s subject=%s", |
160 | | data->peer_cert.depth, |
161 | | data->peer_cert.serial_num ? data->peer_cert.serial_num : "N/A", |
162 | | data->peer_cert.subject); |
163 | | break; |
164 | | case TLS_ALERT: |
165 | | if (data->alert.is_local) |
166 | | wpa_printf(MSG_DEBUG, "authsrv: local TLS alert: %s", |
167 | | data->alert.description); |
168 | | else |
169 | | wpa_printf(MSG_DEBUG, "authsrv: remote TLS alert: %s", |
170 | | data->alert.description); |
171 | | break; |
172 | | case TLS_UNSAFE_RENEGOTIATION_DISABLED: |
173 | | /* Not applicable to TLS server */ |
174 | | break; |
175 | | } |
176 | | } |
177 | | #endif /* EAP_TLS_FUNCS */ |
178 | | |
179 | | |
180 | | static struct eap_config * authsrv_eap_config(struct hostapd_data *hapd) |
181 | 0 | { |
182 | 0 | struct eap_config *cfg; |
183 | |
|
184 | 0 | cfg = os_zalloc(sizeof(*cfg)); |
185 | 0 | if (!cfg) |
186 | 0 | return NULL; |
187 | | |
188 | 0 | cfg->eap_server = hapd->conf->eap_server; |
189 | 0 | cfg->ssl_ctx = hapd->ssl_ctx; |
190 | 0 | cfg->msg_ctx = hapd->msg_ctx; |
191 | 0 | cfg->eap_sim_db_priv = hapd->eap_sim_db_priv; |
192 | 0 | cfg->tls_session_lifetime = hapd->conf->tls_session_lifetime; |
193 | 0 | cfg->tls_flags = hapd->conf->tls_flags; |
194 | 0 | cfg->max_auth_rounds = hapd->conf->max_auth_rounds; |
195 | 0 | cfg->max_auth_rounds_short = hapd->conf->max_auth_rounds_short; |
196 | 0 | if (hapd->conf->pac_opaque_encr_key) |
197 | 0 | cfg->pac_opaque_encr_key = |
198 | 0 | os_memdup(hapd->conf->pac_opaque_encr_key, 16); |
199 | 0 | if (hapd->conf->eap_fast_a_id) { |
200 | 0 | cfg->eap_fast_a_id = os_memdup(hapd->conf->eap_fast_a_id, |
201 | 0 | hapd->conf->eap_fast_a_id_len); |
202 | 0 | cfg->eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len; |
203 | 0 | } |
204 | 0 | if (hapd->conf->eap_fast_a_id_info) |
205 | 0 | cfg->eap_fast_a_id_info = |
206 | 0 | os_strdup(hapd->conf->eap_fast_a_id_info); |
207 | 0 | cfg->eap_fast_prov = hapd->conf->eap_fast_prov; |
208 | 0 | cfg->pac_key_lifetime = hapd->conf->pac_key_lifetime; |
209 | 0 | cfg->pac_key_refresh_time = hapd->conf->pac_key_refresh_time; |
210 | 0 | cfg->eap_teap_auth = hapd->conf->eap_teap_auth; |
211 | 0 | cfg->eap_teap_pac_no_inner = hapd->conf->eap_teap_pac_no_inner; |
212 | 0 | cfg->eap_teap_separate_result = hapd->conf->eap_teap_separate_result; |
213 | 0 | cfg->eap_teap_id = hapd->conf->eap_teap_id; |
214 | 0 | cfg->eap_teap_method_sequence = hapd->conf->eap_teap_method_sequence; |
215 | 0 | cfg->eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind; |
216 | 0 | cfg->eap_sim_id = hapd->conf->eap_sim_id; |
217 | 0 | cfg->imsi_privacy_key = hapd->imsi_privacy_key; |
218 | 0 | cfg->tnc = hapd->conf->tnc; |
219 | 0 | cfg->wps = hapd->wps; |
220 | 0 | cfg->fragment_size = hapd->conf->fragment_size; |
221 | 0 | cfg->pwd_group = hapd->conf->pwd_group; |
222 | 0 | cfg->pbc_in_m1 = hapd->conf->pbc_in_m1; |
223 | 0 | if (hapd->conf->server_id) { |
224 | 0 | cfg->server_id = (u8 *) os_strdup(hapd->conf->server_id); |
225 | 0 | cfg->server_id_len = os_strlen(hapd->conf->server_id); |
226 | 0 | } else { |
227 | 0 | cfg->server_id = (u8 *) os_strdup("hostapd"); |
228 | 0 | cfg->server_id_len = 7; |
229 | 0 | } |
230 | 0 | cfg->erp = hapd->conf->eap_server_erp; |
231 | | #ifdef CONFIG_TESTING_OPTIONS |
232 | | cfg->skip_prot_success = hapd->conf->eap_skip_prot_success; |
233 | | #endif /* CONFIG_TESTING_OPTIONS */ |
234 | |
|
235 | 0 | return cfg; |
236 | 0 | } |
237 | | |
238 | | |
239 | | int authsrv_init(struct hostapd_data *hapd) |
240 | 0 | { |
241 | | #ifdef EAP_TLS_FUNCS |
242 | | if (hapd->conf->eap_server && |
243 | | (hapd->conf->ca_cert || hapd->conf->server_cert || |
244 | | hapd->conf->private_key || hapd->conf->dh_file || |
245 | | hapd->conf->server_cert2 || hapd->conf->private_key2)) { |
246 | | struct tls_config conf; |
247 | | struct tls_connection_params params; |
248 | | |
249 | | os_memset(&conf, 0, sizeof(conf)); |
250 | | conf.tls_session_lifetime = hapd->conf->tls_session_lifetime; |
251 | | if (hapd->conf->crl_reload_interval > 0 && |
252 | | hapd->conf->check_crl <= 0) { |
253 | | wpa_printf(MSG_INFO, |
254 | | "Cannot enable CRL reload functionality - it depends on check_crl being set"); |
255 | | } else if (hapd->conf->crl_reload_interval > 0) { |
256 | | conf.crl_reload_interval = |
257 | | hapd->conf->crl_reload_interval; |
258 | | wpa_printf(MSG_INFO, |
259 | | "Enabled CRL reload functionality"); |
260 | | } |
261 | | conf.tls_flags = hapd->conf->tls_flags; |
262 | | conf.event_cb = authsrv_tls_event; |
263 | | conf.cb_ctx = hapd; |
264 | | hapd->ssl_ctx = tls_init(&conf); |
265 | | if (hapd->ssl_ctx == NULL) { |
266 | | wpa_printf(MSG_ERROR, "Failed to initialize TLS"); |
267 | | authsrv_deinit(hapd); |
268 | | return -1; |
269 | | } |
270 | | |
271 | | os_memset(¶ms, 0, sizeof(params)); |
272 | | params.ca_cert = hapd->conf->ca_cert; |
273 | | params.client_cert = hapd->conf->server_cert; |
274 | | params.client_cert2 = hapd->conf->server_cert2; |
275 | | params.private_key = hapd->conf->private_key; |
276 | | params.private_key2 = hapd->conf->private_key2; |
277 | | params.private_key_passwd = hapd->conf->private_key_passwd; |
278 | | params.private_key_passwd2 = hapd->conf->private_key_passwd2; |
279 | | params.dh_file = hapd->conf->dh_file; |
280 | | params.openssl_ciphers = hapd->conf->openssl_ciphers; |
281 | | params.openssl_ecdh_curves = hapd->conf->openssl_ecdh_curves; |
282 | | params.ocsp_stapling_response = |
283 | | hapd->conf->ocsp_stapling_response; |
284 | | params.ocsp_stapling_response_multi = |
285 | | hapd->conf->ocsp_stapling_response_multi; |
286 | | params.check_cert_subject = hapd->conf->check_cert_subject; |
287 | | |
288 | | if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) { |
289 | | wpa_printf(MSG_ERROR, "Failed to set TLS parameters"); |
290 | | authsrv_deinit(hapd); |
291 | | return -1; |
292 | | } |
293 | | |
294 | | if (tls_global_set_verify(hapd->ssl_ctx, |
295 | | hapd->conf->check_crl, |
296 | | hapd->conf->check_crl_strict)) { |
297 | | wpa_printf(MSG_ERROR, "Failed to enable check_crl"); |
298 | | authsrv_deinit(hapd); |
299 | | return -1; |
300 | | } |
301 | | } |
302 | | #endif /* EAP_TLS_FUNCS */ |
303 | |
|
304 | | #ifdef CRYPTO_RSA_OAEP_SHA256 |
305 | | crypto_rsa_key_free(hapd->imsi_privacy_key); |
306 | | hapd->imsi_privacy_key = NULL; |
307 | | if (hapd->conf->imsi_privacy_key) { |
308 | | hapd->imsi_privacy_key = crypto_rsa_key_read( |
309 | | hapd->conf->imsi_privacy_key, true); |
310 | | if (!hapd->imsi_privacy_key) { |
311 | | wpa_printf(MSG_ERROR, |
312 | | "Failed to read/parse IMSI privacy key %s", |
313 | | hapd->conf->imsi_privacy_key); |
314 | | authsrv_deinit(hapd); |
315 | | return -1; |
316 | | } |
317 | | } |
318 | | #endif /* CRYPTO_RSA_OAEP_SHA256 */ |
319 | |
|
320 | | #ifdef EAP_SIM_DB |
321 | | if (hapd->conf->eap_sim_db) { |
322 | | hapd->eap_sim_db_priv = |
323 | | eap_sim_db_init(hapd->conf->eap_sim_db, |
324 | | hapd->conf->eap_sim_db_timeout, |
325 | | hostapd_sim_db_cb, hapd); |
326 | | if (hapd->eap_sim_db_priv == NULL) { |
327 | | wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM " |
328 | | "database interface"); |
329 | | authsrv_deinit(hapd); |
330 | | return -1; |
331 | | } |
332 | | } |
333 | | #endif /* EAP_SIM_DB */ |
334 | |
|
335 | 0 | hapd->eap_cfg = authsrv_eap_config(hapd); |
336 | 0 | if (!hapd->eap_cfg) { |
337 | 0 | wpa_printf(MSG_ERROR, |
338 | 0 | "Failed to build EAP server configuration"); |
339 | 0 | authsrv_deinit(hapd); |
340 | 0 | return -1; |
341 | 0 | } |
342 | | |
343 | | #ifdef RADIUS_SERVER |
344 | | if (hapd->conf->radius_server_clients && |
345 | | hostapd_setup_radius_srv(hapd)) |
346 | | return -1; |
347 | | #endif /* RADIUS_SERVER */ |
348 | | |
349 | 0 | return 0; |
350 | 0 | } |
351 | | |
352 | | |
353 | | void authsrv_deinit(struct hostapd_data *hapd) |
354 | 0 | { |
355 | | #ifdef RADIUS_SERVER |
356 | | radius_server_deinit(hapd->radius_srv); |
357 | | hapd->radius_srv = NULL; |
358 | | #endif /* RADIUS_SERVER */ |
359 | |
|
360 | | #ifdef CRYPTO_RSA_OAEP_SHA256 |
361 | | crypto_rsa_key_free(hapd->imsi_privacy_key); |
362 | | hapd->imsi_privacy_key = NULL; |
363 | | #endif /* CRYPTO_RSA_OAEP_SHA256 */ |
364 | |
|
365 | | #ifdef EAP_TLS_FUNCS |
366 | | if (hapd->ssl_ctx) { |
367 | | tls_deinit(hapd->ssl_ctx); |
368 | | hapd->ssl_ctx = NULL; |
369 | | } |
370 | | #endif /* EAP_TLS_FUNCS */ |
371 | |
|
372 | | #ifdef EAP_SIM_DB |
373 | | if (hapd->eap_sim_db_priv) { |
374 | | eap_sim_db_deinit(hapd->eap_sim_db_priv); |
375 | | hapd->eap_sim_db_priv = NULL; |
376 | | } |
377 | | #endif /* EAP_SIM_DB */ |
378 | |
|
379 | 0 | eap_server_config_free(hapd->eap_cfg); |
380 | 0 | hapd->eap_cfg = NULL; |
381 | 0 | } |