Jouni Malinen | 6fc6879 | 2008-02-27 17:34:43 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Example application showing how EAP peer code from wpa_supplicant can be |
| 3 | * used as a library. |
| 4 | * Copyright (c) 2007, Jouni Malinen <j@w1.fi> |
| 5 | * |
Jouni Malinen | 0f3d578 | 2012-02-11 16:46:35 +0200 | [diff] [blame] | 6 | * This software may be distributed under the terms of the BSD license. |
| 7 | * See README for more details. |
Jouni Malinen | 6fc6879 | 2008-02-27 17:34:43 -0800 | [diff] [blame] | 8 | */ |
| 9 | |
| 10 | #include "includes.h" |
| 11 | |
| 12 | #include "common.h" |
| 13 | #include "eap_peer/eap.h" |
| 14 | #include "eap_peer/eap_config.h" |
| 15 | #include "wpabuf.h" |
| 16 | |
| 17 | void eap_example_server_rx(const u8 *data, size_t data_len); |
| 18 | |
| 19 | |
| 20 | struct eap_peer_ctx { |
| 21 | Boolean eapSuccess; |
| 22 | Boolean eapRestart; |
| 23 | Boolean eapFail; |
| 24 | Boolean eapResp; |
| 25 | Boolean eapNoResp; |
| 26 | Boolean eapReq; |
| 27 | Boolean portEnabled; |
| 28 | Boolean altAccept; /* for EAP */ |
| 29 | Boolean altReject; /* for EAP */ |
Jouni Malinen | ebdfdf1 | 2014-12-04 12:38:06 +0200 | [diff] [blame] | 30 | Boolean eapTriggerStart; |
Jouni Malinen | 6fc6879 | 2008-02-27 17:34:43 -0800 | [diff] [blame] | 31 | |
| 32 | struct wpabuf *eapReqData; /* for EAP */ |
| 33 | |
| 34 | unsigned int idleWhile; /* for EAP state machine */ |
| 35 | |
| 36 | struct eap_peer_config eap_config; |
| 37 | struct eap_sm *eap; |
| 38 | }; |
| 39 | |
| 40 | |
| 41 | static struct eap_peer_ctx eap_ctx; |
| 42 | |
| 43 | |
| 44 | static struct eap_peer_config * peer_get_config(void *ctx) |
| 45 | { |
| 46 | struct eap_peer_ctx *peer = ctx; |
| 47 | return &peer->eap_config; |
| 48 | } |
| 49 | |
| 50 | |
| 51 | static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable) |
| 52 | { |
| 53 | struct eap_peer_ctx *peer = ctx; |
| 54 | if (peer == NULL) |
| 55 | return FALSE; |
| 56 | switch (variable) { |
| 57 | case EAPOL_eapSuccess: |
| 58 | return peer->eapSuccess; |
| 59 | case EAPOL_eapRestart: |
| 60 | return peer->eapRestart; |
| 61 | case EAPOL_eapFail: |
| 62 | return peer->eapFail; |
| 63 | case EAPOL_eapResp: |
| 64 | return peer->eapResp; |
| 65 | case EAPOL_eapNoResp: |
| 66 | return peer->eapNoResp; |
| 67 | case EAPOL_eapReq: |
| 68 | return peer->eapReq; |
| 69 | case EAPOL_portEnabled: |
| 70 | return peer->portEnabled; |
| 71 | case EAPOL_altAccept: |
| 72 | return peer->altAccept; |
| 73 | case EAPOL_altReject: |
| 74 | return peer->altReject; |
Jouni Malinen | ebdfdf1 | 2014-12-04 12:38:06 +0200 | [diff] [blame] | 75 | case EAPOL_eapTriggerStart: |
| 76 | return peer->eapTriggerStart; |
Jouni Malinen | 6fc6879 | 2008-02-27 17:34:43 -0800 | [diff] [blame] | 77 | } |
| 78 | return FALSE; |
| 79 | } |
| 80 | |
| 81 | |
| 82 | static void peer_set_bool(void *ctx, enum eapol_bool_var variable, |
| 83 | Boolean value) |
| 84 | { |
| 85 | struct eap_peer_ctx *peer = ctx; |
| 86 | if (peer == NULL) |
| 87 | return; |
| 88 | switch (variable) { |
| 89 | case EAPOL_eapSuccess: |
| 90 | peer->eapSuccess = value; |
| 91 | break; |
| 92 | case EAPOL_eapRestart: |
| 93 | peer->eapRestart = value; |
| 94 | break; |
| 95 | case EAPOL_eapFail: |
| 96 | peer->eapFail = value; |
| 97 | break; |
| 98 | case EAPOL_eapResp: |
| 99 | peer->eapResp = value; |
| 100 | break; |
| 101 | case EAPOL_eapNoResp: |
| 102 | peer->eapNoResp = value; |
| 103 | break; |
| 104 | case EAPOL_eapReq: |
| 105 | peer->eapReq = value; |
| 106 | break; |
| 107 | case EAPOL_portEnabled: |
| 108 | peer->portEnabled = value; |
| 109 | break; |
| 110 | case EAPOL_altAccept: |
| 111 | peer->altAccept = value; |
| 112 | break; |
| 113 | case EAPOL_altReject: |
| 114 | peer->altReject = value; |
| 115 | break; |
Jouni Malinen | ebdfdf1 | 2014-12-04 12:38:06 +0200 | [diff] [blame] | 116 | case EAPOL_eapTriggerStart: |
| 117 | peer->eapTriggerStart = value; |
| 118 | break; |
Jouni Malinen | 6fc6879 | 2008-02-27 17:34:43 -0800 | [diff] [blame] | 119 | } |
| 120 | } |
| 121 | |
| 122 | |
| 123 | static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable) |
| 124 | { |
| 125 | struct eap_peer_ctx *peer = ctx; |
| 126 | if (peer == NULL) |
| 127 | return 0; |
| 128 | switch (variable) { |
| 129 | case EAPOL_idleWhile: |
| 130 | return peer->idleWhile; |
| 131 | } |
| 132 | return 0; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | static void peer_set_int(void *ctx, enum eapol_int_var variable, |
| 137 | unsigned int value) |
| 138 | { |
| 139 | struct eap_peer_ctx *peer = ctx; |
| 140 | if (peer == NULL) |
| 141 | return; |
| 142 | switch (variable) { |
| 143 | case EAPOL_idleWhile: |
| 144 | peer->idleWhile = value; |
| 145 | break; |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | |
| 150 | static struct wpabuf * peer_get_eapReqData(void *ctx) |
| 151 | { |
| 152 | struct eap_peer_ctx *peer = ctx; |
| 153 | if (peer == NULL || peer->eapReqData == NULL) |
| 154 | return NULL; |
| 155 | |
| 156 | return peer->eapReqData; |
| 157 | } |
| 158 | |
| 159 | |
| 160 | static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob) |
| 161 | { |
| 162 | printf("TODO: %s\n", __func__); |
| 163 | } |
| 164 | |
| 165 | |
| 166 | static const struct wpa_config_blob * |
| 167 | peer_get_config_blob(void *ctx, const char *name) |
| 168 | { |
| 169 | printf("TODO: %s\n", __func__); |
| 170 | return NULL; |
| 171 | } |
| 172 | |
| 173 | |
| 174 | static void peer_notify_pending(void *ctx) |
| 175 | { |
| 176 | printf("TODO: %s\n", __func__); |
| 177 | } |
| 178 | |
| 179 | |
Jouni Malinen | 1276081 | 2009-12-06 11:28:41 +0200 | [diff] [blame] | 180 | static int eap_peer_register_methods(void) |
| 181 | { |
| 182 | int ret = 0; |
| 183 | |
| 184 | #ifdef EAP_MD5 |
| 185 | if (ret == 0) |
| 186 | ret = eap_peer_md5_register(); |
| 187 | #endif /* EAP_MD5 */ |
| 188 | |
| 189 | #ifdef EAP_TLS |
| 190 | if (ret == 0) |
| 191 | ret = eap_peer_tls_register(); |
| 192 | #endif /* EAP_TLS */ |
| 193 | |
| 194 | #ifdef EAP_MSCHAPv2 |
| 195 | if (ret == 0) |
| 196 | ret = eap_peer_mschapv2_register(); |
| 197 | #endif /* EAP_MSCHAPv2 */ |
| 198 | |
| 199 | #ifdef EAP_PEAP |
| 200 | if (ret == 0) |
| 201 | ret = eap_peer_peap_register(); |
| 202 | #endif /* EAP_PEAP */ |
| 203 | |
| 204 | #ifdef EAP_TTLS |
| 205 | if (ret == 0) |
| 206 | ret = eap_peer_ttls_register(); |
| 207 | #endif /* EAP_TTLS */ |
| 208 | |
| 209 | #ifdef EAP_GTC |
| 210 | if (ret == 0) |
| 211 | ret = eap_peer_gtc_register(); |
| 212 | #endif /* EAP_GTC */ |
| 213 | |
| 214 | #ifdef EAP_OTP |
| 215 | if (ret == 0) |
| 216 | ret = eap_peer_otp_register(); |
| 217 | #endif /* EAP_OTP */ |
| 218 | |
| 219 | #ifdef EAP_SIM |
| 220 | if (ret == 0) |
| 221 | ret = eap_peer_sim_register(); |
| 222 | #endif /* EAP_SIM */ |
| 223 | |
| 224 | #ifdef EAP_LEAP |
| 225 | if (ret == 0) |
| 226 | ret = eap_peer_leap_register(); |
| 227 | #endif /* EAP_LEAP */ |
| 228 | |
| 229 | #ifdef EAP_PSK |
| 230 | if (ret == 0) |
| 231 | ret = eap_peer_psk_register(); |
| 232 | #endif /* EAP_PSK */ |
| 233 | |
| 234 | #ifdef EAP_AKA |
| 235 | if (ret == 0) |
| 236 | ret = eap_peer_aka_register(); |
| 237 | #endif /* EAP_AKA */ |
| 238 | |
| 239 | #ifdef EAP_AKA_PRIME |
| 240 | if (ret == 0) |
| 241 | ret = eap_peer_aka_prime_register(); |
| 242 | #endif /* EAP_AKA_PRIME */ |
| 243 | |
| 244 | #ifdef EAP_FAST |
| 245 | if (ret == 0) |
| 246 | ret = eap_peer_fast_register(); |
| 247 | #endif /* EAP_FAST */ |
| 248 | |
| 249 | #ifdef EAP_PAX |
| 250 | if (ret == 0) |
| 251 | ret = eap_peer_pax_register(); |
| 252 | #endif /* EAP_PAX */ |
| 253 | |
| 254 | #ifdef EAP_SAKE |
| 255 | if (ret == 0) |
| 256 | ret = eap_peer_sake_register(); |
| 257 | #endif /* EAP_SAKE */ |
| 258 | |
| 259 | #ifdef EAP_GPSK |
| 260 | if (ret == 0) |
| 261 | ret = eap_peer_gpsk_register(); |
| 262 | #endif /* EAP_GPSK */ |
| 263 | |
| 264 | #ifdef EAP_WSC |
| 265 | if (ret == 0) |
| 266 | ret = eap_peer_wsc_register(); |
| 267 | #endif /* EAP_WSC */ |
| 268 | |
| 269 | #ifdef EAP_IKEV2 |
| 270 | if (ret == 0) |
| 271 | ret = eap_peer_ikev2_register(); |
| 272 | #endif /* EAP_IKEV2 */ |
| 273 | |
| 274 | #ifdef EAP_VENDOR_TEST |
| 275 | if (ret == 0) |
| 276 | ret = eap_peer_vendor_test_register(); |
| 277 | #endif /* EAP_VENDOR_TEST */ |
| 278 | |
| 279 | #ifdef EAP_TNC |
| 280 | if (ret == 0) |
| 281 | ret = eap_peer_tnc_register(); |
| 282 | #endif /* EAP_TNC */ |
| 283 | |
| 284 | return ret; |
| 285 | } |
| 286 | |
| 287 | |
Jouni Malinen | 6fc6879 | 2008-02-27 17:34:43 -0800 | [diff] [blame] | 288 | static struct eapol_callbacks eap_cb; |
| 289 | static struct eap_config eap_conf; |
| 290 | |
| 291 | int eap_example_peer_init(void) |
| 292 | { |
| 293 | if (eap_peer_register_methods() < 0) |
| 294 | return -1; |
| 295 | |
| 296 | os_memset(&eap_ctx, 0, sizeof(eap_ctx)); |
| 297 | |
| 298 | eap_ctx.eap_config.identity = (u8 *) os_strdup("user"); |
| 299 | eap_ctx.eap_config.identity_len = 4; |
| 300 | eap_ctx.eap_config.password = (u8 *) os_strdup("password"); |
| 301 | eap_ctx.eap_config.password_len = 8; |
| 302 | eap_ctx.eap_config.ca_cert = (u8 *) os_strdup("ca.pem"); |
| 303 | eap_ctx.eap_config.fragment_size = 1398; |
| 304 | |
| 305 | os_memset(&eap_cb, 0, sizeof(eap_cb)); |
| 306 | eap_cb.get_config = peer_get_config; |
| 307 | eap_cb.get_bool = peer_get_bool; |
| 308 | eap_cb.set_bool = peer_set_bool; |
| 309 | eap_cb.get_int = peer_get_int; |
| 310 | eap_cb.set_int = peer_set_int; |
| 311 | eap_cb.get_eapReqData = peer_get_eapReqData; |
| 312 | eap_cb.set_config_blob = peer_set_config_blob; |
| 313 | eap_cb.get_config_blob = peer_get_config_blob; |
| 314 | eap_cb.notify_pending = peer_notify_pending; |
| 315 | |
| 316 | os_memset(&eap_conf, 0, sizeof(eap_conf)); |
| 317 | eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf); |
| 318 | if (eap_ctx.eap == NULL) |
| 319 | return -1; |
| 320 | |
| 321 | /* Enable "port" to allow authentication */ |
| 322 | eap_ctx.portEnabled = TRUE; |
| 323 | |
| 324 | return 0; |
| 325 | } |
| 326 | |
| 327 | |
| 328 | void eap_example_peer_deinit(void) |
| 329 | { |
| 330 | eap_peer_sm_deinit(eap_ctx.eap); |
| 331 | eap_peer_unregister_methods(); |
| 332 | wpabuf_free(eap_ctx.eapReqData); |
| 333 | os_free(eap_ctx.eap_config.identity); |
| 334 | os_free(eap_ctx.eap_config.password); |
| 335 | os_free(eap_ctx.eap_config.ca_cert); |
| 336 | } |
| 337 | |
| 338 | |
| 339 | int eap_example_peer_step(void) |
| 340 | { |
| 341 | int res; |
| 342 | res = eap_peer_sm_step(eap_ctx.eap); |
| 343 | |
| 344 | if (eap_ctx.eapResp) { |
| 345 | struct wpabuf *resp; |
| 346 | printf("==> Response\n"); |
| 347 | eap_ctx.eapResp = FALSE; |
| 348 | resp = eap_get_eapRespData(eap_ctx.eap); |
| 349 | if (resp) { |
| 350 | /* Send EAP response to the server */ |
| 351 | eap_example_server_rx(wpabuf_head(resp), |
| 352 | wpabuf_len(resp)); |
| 353 | wpabuf_free(resp); |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | if (eap_ctx.eapSuccess) { |
| 358 | res = 0; |
| 359 | if (eap_key_available(eap_ctx.eap)) { |
| 360 | const u8 *key; |
| 361 | size_t key_len; |
| 362 | key = eap_get_eapKeyData(eap_ctx.eap, &key_len); |
| 363 | wpa_hexdump(MSG_DEBUG, "EAP keying material", |
| 364 | key, key_len); |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | return res; |
| 369 | } |
| 370 | |
| 371 | |
| 372 | void eap_example_peer_rx(const u8 *data, size_t data_len) |
| 373 | { |
| 374 | /* Make received EAP message available to the EAP library */ |
| 375 | eap_ctx.eapReq = TRUE; |
| 376 | wpabuf_free(eap_ctx.eapReqData); |
| 377 | eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len); |
| 378 | } |