The Android Open Source Project | 845e012 | 2009-03-03 19:31:34 -0800 | [diff] [blame] | 1 | /* |
| 2 | * EAP peer method: EAP-PSK (RFC 4764) |
| 3 | * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License version 2 as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * Alternatively, this software may be distributed under the terms of BSD |
| 10 | * license. |
| 11 | * |
| 12 | * See README and COPYING for more details. |
| 13 | * |
| 14 | * Note: EAP-PSK is an EAP authentication method and as such, completely |
| 15 | * different from WPA-PSK. This file is not needed for WPA-PSK functionality. |
| 16 | */ |
| 17 | |
| 18 | #include "includes.h" |
| 19 | |
| 20 | #include "common.h" |
| 21 | #include "eap_i.h" |
| 22 | #include "config_ssid.h" |
| 23 | #include "md5.h" |
| 24 | #include "aes_wrap.h" |
| 25 | #include "eap_psk_common.h" |
| 26 | |
| 27 | |
| 28 | struct eap_psk_data { |
| 29 | enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state; |
| 30 | u8 rand_p[EAP_PSK_RAND_LEN]; |
| 31 | u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN]; |
| 32 | u8 *id_s, *id_p; |
| 33 | size_t id_s_len, id_p_len; |
| 34 | u8 msk[EAP_MSK_LEN]; |
| 35 | u8 emsk[EAP_EMSK_LEN]; |
| 36 | }; |
| 37 | |
| 38 | |
| 39 | static void * eap_psk_init(struct eap_sm *sm) |
| 40 | { |
| 41 | struct wpa_ssid *config = eap_get_config(sm); |
| 42 | struct eap_psk_data *data; |
| 43 | |
| 44 | if (config == NULL || !config->eappsk) { |
| 45 | wpa_printf(MSG_INFO, "EAP-PSK: pre-shared key not configured"); |
| 46 | return NULL; |
| 47 | } |
| 48 | |
| 49 | data = os_zalloc(sizeof(*data)); |
| 50 | if (data == NULL) |
| 51 | return NULL; |
| 52 | eap_psk_key_setup(config->eappsk, data->ak, data->kdk); |
| 53 | wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN); |
| 54 | wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN); |
| 55 | data->state = PSK_INIT; |
| 56 | |
| 57 | if (config->nai) { |
| 58 | data->id_p = os_malloc(config->nai_len); |
| 59 | if (data->id_p) |
| 60 | os_memcpy(data->id_p, config->nai, config->nai_len); |
| 61 | data->id_p_len = config->nai_len; |
| 62 | } |
| 63 | if (data->id_p == NULL) { |
| 64 | wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity"); |
| 65 | os_free(data); |
| 66 | return NULL; |
| 67 | } |
| 68 | |
| 69 | return data; |
| 70 | } |
| 71 | |
| 72 | |
| 73 | static void eap_psk_deinit(struct eap_sm *sm, void *priv) |
| 74 | { |
| 75 | struct eap_psk_data *data = priv; |
| 76 | os_free(data->id_s); |
| 77 | os_free(data->id_p); |
| 78 | os_free(data); |
| 79 | } |
| 80 | |
| 81 | |
| 82 | static u8 * eap_psk_process_1(struct eap_psk_data *data, |
| 83 | struct eap_method_ret *ret, |
| 84 | const u8 *reqData, size_t reqDataLen, |
| 85 | size_t *respDataLen) |
| 86 | { |
| 87 | const struct eap_psk_hdr_1 *hdr1; |
| 88 | struct eap_psk_hdr_2 *hdr2; |
| 89 | u8 *resp, *buf, *pos; |
| 90 | size_t buflen; |
| 91 | |
| 92 | wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state"); |
| 93 | |
| 94 | hdr1 = (const struct eap_psk_hdr_1 *) reqData; |
| 95 | if (reqDataLen < sizeof(*hdr1) || |
| 96 | be_to_host16(hdr1->length) < sizeof(*hdr1) || |
| 97 | be_to_host16(hdr1->length) > reqDataLen) { |
| 98 | wpa_printf(MSG_INFO, "EAP-PSK: Invalid first message " |
| 99 | "length (%lu %d; expected %lu or more)", |
| 100 | (unsigned long) reqDataLen, |
| 101 | be_to_host16(hdr1->length), |
| 102 | (unsigned long) sizeof(*hdr1)); |
| 103 | ret->ignore = TRUE; |
| 104 | return NULL; |
| 105 | } |
| 106 | wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags); |
| 107 | if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) { |
| 108 | wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)", |
| 109 | EAP_PSK_FLAGS_GET_T(hdr1->flags)); |
| 110 | ret->methodState = METHOD_DONE; |
| 111 | ret->decision = DECISION_FAIL; |
| 112 | return NULL; |
| 113 | } |
| 114 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s, |
| 115 | EAP_PSK_RAND_LEN); |
| 116 | os_free(data->id_s); |
| 117 | data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1); |
| 118 | data->id_s = os_malloc(data->id_s_len); |
| 119 | if (data->id_s == NULL) { |
| 120 | wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for " |
| 121 | "ID_S (len=%lu)", (unsigned long) data->id_s_len); |
| 122 | ret->ignore = TRUE; |
| 123 | return NULL; |
| 124 | } |
| 125 | os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len); |
| 126 | wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S", |
| 127 | data->id_s, data->id_s_len); |
| 128 | |
| 129 | if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) { |
| 130 | wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data"); |
| 131 | ret->ignore = TRUE; |
| 132 | return NULL; |
| 133 | } |
| 134 | |
| 135 | *respDataLen = sizeof(*hdr2) + data->id_p_len; |
| 136 | resp = os_malloc(*respDataLen); |
| 137 | if (resp == NULL) |
| 138 | return NULL; |
| 139 | hdr2 = (struct eap_psk_hdr_2 *) resp; |
| 140 | hdr2->code = EAP_CODE_RESPONSE; |
| 141 | hdr2->identifier = hdr1->identifier; |
| 142 | hdr2->length = host_to_be16(*respDataLen); |
| 143 | hdr2->type = EAP_TYPE_PSK; |
| 144 | hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */ |
| 145 | os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN); |
| 146 | os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN); |
| 147 | os_memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len); |
| 148 | /* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */ |
| 149 | buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN; |
| 150 | buf = os_malloc(buflen); |
| 151 | if (buf == NULL) { |
| 152 | os_free(resp); |
| 153 | return NULL; |
| 154 | } |
| 155 | os_memcpy(buf, data->id_p, data->id_p_len); |
| 156 | pos = buf + data->id_p_len; |
| 157 | os_memcpy(pos, data->id_s, data->id_s_len); |
| 158 | pos += data->id_s_len; |
| 159 | os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN); |
| 160 | pos += EAP_PSK_RAND_LEN; |
| 161 | os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN); |
| 162 | omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p); |
| 163 | os_free(buf); |
| 164 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p, |
| 165 | EAP_PSK_RAND_LEN); |
| 166 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN); |
| 167 | wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_P", |
| 168 | (u8 *) (hdr2 + 1), data->id_p_len); |
| 169 | |
| 170 | data->state = PSK_MAC_SENT; |
| 171 | |
| 172 | return resp; |
| 173 | } |
| 174 | |
| 175 | |
| 176 | static u8 * eap_psk_process_3(struct eap_psk_data *data, |
| 177 | struct eap_method_ret *ret, |
| 178 | const u8 *reqData, size_t reqDataLen, |
| 179 | size_t *respDataLen) |
| 180 | { |
| 181 | const struct eap_psk_hdr_3 *hdr3; |
| 182 | struct eap_psk_hdr_4 *hdr4; |
| 183 | u8 *resp, *buf, *rpchannel, nonce[16], *decrypted; |
| 184 | const u8 *pchannel, *tag, *msg; |
| 185 | u8 mac[EAP_PSK_MAC_LEN]; |
| 186 | size_t buflen, left, data_len; |
| 187 | int failed = 0; |
| 188 | |
| 189 | wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state"); |
| 190 | |
| 191 | hdr3 = (const struct eap_psk_hdr_3 *) reqData; |
| 192 | left = be_to_host16(hdr3->length); |
| 193 | if (left < sizeof(*hdr3) || reqDataLen < left) { |
| 194 | wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message " |
| 195 | "length (%lu %d; expected %lu)", |
| 196 | (unsigned long) reqDataLen, |
| 197 | be_to_host16(hdr3->length), |
| 198 | (unsigned long) sizeof(*hdr3)); |
| 199 | ret->ignore = TRUE; |
| 200 | return NULL; |
| 201 | } |
| 202 | left -= sizeof(*hdr3); |
| 203 | pchannel = (const u8 *) (hdr3 + 1); |
| 204 | wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags); |
| 205 | if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) { |
| 206 | wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)", |
| 207 | EAP_PSK_FLAGS_GET_T(hdr3->flags)); |
| 208 | ret->methodState = METHOD_DONE; |
| 209 | ret->decision = DECISION_FAIL; |
| 210 | return NULL; |
| 211 | } |
| 212 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s, |
| 213 | EAP_PSK_RAND_LEN); |
| 214 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN); |
| 215 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left); |
| 216 | |
| 217 | if (left < 4 + 16 + 1) { |
| 218 | wpa_printf(MSG_INFO, "EAP-PSK: Too short PCHANNEL data in " |
| 219 | "third message (len=%lu, expected 21)", |
| 220 | (unsigned long) left); |
| 221 | ret->ignore = TRUE; |
| 222 | return NULL; |
| 223 | } |
| 224 | |
| 225 | /* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */ |
| 226 | buflen = data->id_s_len + EAP_PSK_RAND_LEN; |
| 227 | buf = os_malloc(buflen); |
| 228 | if (buf == NULL) |
| 229 | return NULL; |
| 230 | os_memcpy(buf, data->id_s, data->id_s_len); |
| 231 | os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN); |
| 232 | omac1_aes_128(data->ak, buf, buflen, mac); |
| 233 | os_free(buf); |
| 234 | if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { |
| 235 | wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " |
| 236 | "message"); |
| 237 | ret->methodState = METHOD_DONE; |
| 238 | ret->decision = DECISION_FAIL; |
| 239 | return NULL; |
| 240 | } |
| 241 | wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully"); |
| 242 | |
| 243 | eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, |
| 244 | data->msk, data->emsk); |
| 245 | wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN); |
| 246 | wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN); |
| 247 | wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN); |
| 248 | |
| 249 | os_memset(nonce, 0, 12); |
| 250 | os_memcpy(nonce + 12, pchannel, 4); |
| 251 | pchannel += 4; |
| 252 | left -= 4; |
| 253 | |
| 254 | tag = pchannel; |
| 255 | pchannel += 16; |
| 256 | left -= 16; |
| 257 | |
| 258 | msg = pchannel; |
| 259 | |
| 260 | wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - nonce", |
| 261 | nonce, sizeof(nonce)); |
| 262 | wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5); |
| 263 | wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left); |
| 264 | |
| 265 | decrypted = os_malloc(left); |
| 266 | if (decrypted == NULL) { |
| 267 | ret->methodState = METHOD_DONE; |
| 268 | ret->decision = DECISION_FAIL; |
| 269 | return NULL; |
| 270 | } |
| 271 | os_memcpy(decrypted, msg, left); |
| 272 | |
| 273 | if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce), |
| 274 | reqData, 22, decrypted, left, tag)) { |
| 275 | wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed"); |
| 276 | os_free(decrypted); |
| 277 | return NULL; |
| 278 | } |
| 279 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message", |
| 280 | decrypted, left); |
| 281 | |
| 282 | /* Verify R flag */ |
| 283 | switch (decrypted[0] >> 6) { |
| 284 | case EAP_PSK_R_FLAG_CONT: |
| 285 | wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported"); |
| 286 | failed = 1; |
| 287 | break; |
| 288 | case EAP_PSK_R_FLAG_DONE_SUCCESS: |
| 289 | wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS"); |
| 290 | break; |
| 291 | case EAP_PSK_R_FLAG_DONE_FAILURE: |
| 292 | wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_FAILURE"); |
| 293 | wpa_printf(MSG_INFO, "EAP-PSK: Authentication server rejected " |
| 294 | "authentication"); |
| 295 | failed = 1; |
| 296 | break; |
| 297 | } |
| 298 | |
| 299 | *respDataLen = sizeof(*hdr4) + 4 + 16 + 1; |
| 300 | resp = os_malloc(*respDataLen + 1); |
| 301 | if (resp == NULL) { |
| 302 | os_free(decrypted); |
| 303 | return NULL; |
| 304 | } |
| 305 | hdr4 = (struct eap_psk_hdr_4 *) resp; |
| 306 | hdr4->code = EAP_CODE_RESPONSE; |
| 307 | hdr4->identifier = hdr3->identifier; |
| 308 | hdr4->length = host_to_be16(*respDataLen); |
| 309 | hdr4->type = EAP_TYPE_PSK; |
| 310 | hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */ |
| 311 | os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN); |
| 312 | rpchannel = (u8 *) (hdr4 + 1); |
| 313 | |
| 314 | /* nonce++ */ |
| 315 | inc_byte_array(nonce, sizeof(nonce)); |
| 316 | os_memcpy(rpchannel, nonce + 12, 4); |
| 317 | |
| 318 | data_len = 1; |
| 319 | if (decrypted[0] & EAP_PSK_E_FLAG) { |
| 320 | wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag"); |
| 321 | failed = 1; |
| 322 | rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) | |
| 323 | EAP_PSK_E_FLAG; |
| 324 | if (left > 1) { |
| 325 | /* Add empty EXT_Payload with same EXT_Type */ |
| 326 | (*respDataLen)++; |
| 327 | hdr4->length = host_to_be16(*respDataLen); |
| 328 | rpchannel[4 + 16 + 1] = decrypted[1]; |
| 329 | data_len++; |
| 330 | } |
| 331 | } else if (failed) |
| 332 | rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6; |
| 333 | else |
| 334 | rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6; |
| 335 | |
| 336 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)", |
| 337 | rpchannel + 4 + 16, data_len); |
| 338 | aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22, |
| 339 | rpchannel + 4 + 16, data_len, rpchannel + 4); |
| 340 | wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)", |
| 341 | rpchannel, 4 + 16 + data_len); |
| 342 | |
| 343 | wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully", |
| 344 | failed ? "un" : ""); |
| 345 | data->state = PSK_DONE; |
| 346 | ret->methodState = METHOD_DONE; |
| 347 | ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC; |
| 348 | |
| 349 | os_free(decrypted); |
| 350 | |
| 351 | return resp; |
| 352 | } |
| 353 | |
| 354 | |
| 355 | static u8 * eap_psk_process(struct eap_sm *sm, void *priv, |
| 356 | struct eap_method_ret *ret, |
| 357 | const u8 *reqData, size_t reqDataLen, |
| 358 | size_t *respDataLen) |
| 359 | { |
| 360 | struct eap_psk_data *data = priv; |
| 361 | const u8 *pos; |
| 362 | u8 *resp = NULL; |
| 363 | size_t len; |
| 364 | |
| 365 | pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK, |
| 366 | reqData, reqDataLen, &len); |
| 367 | if (pos == NULL) { |
| 368 | ret->ignore = TRUE; |
| 369 | return NULL; |
| 370 | } |
| 371 | len += sizeof(struct eap_hdr) + 1; |
| 372 | |
| 373 | ret->ignore = FALSE; |
| 374 | ret->methodState = METHOD_MAY_CONT; |
| 375 | ret->decision = DECISION_FAIL; |
| 376 | ret->allowNotifications = TRUE; |
| 377 | |
| 378 | switch (data->state) { |
| 379 | case PSK_INIT: |
| 380 | resp = eap_psk_process_1(data, ret, reqData, len, |
| 381 | respDataLen); |
| 382 | break; |
| 383 | case PSK_MAC_SENT: |
| 384 | resp = eap_psk_process_3(data, ret, reqData, len, |
| 385 | respDataLen); |
| 386 | break; |
| 387 | case PSK_DONE: |
| 388 | wpa_printf(MSG_DEBUG, "EAP-PSK: in DONE state - ignore " |
| 389 | "unexpected message"); |
| 390 | ret->ignore = TRUE; |
| 391 | return NULL; |
| 392 | } |
| 393 | |
| 394 | if (ret->methodState == METHOD_DONE) { |
| 395 | ret->allowNotifications = FALSE; |
| 396 | } |
| 397 | |
| 398 | return resp; |
| 399 | } |
| 400 | |
| 401 | |
| 402 | static Boolean eap_psk_isKeyAvailable(struct eap_sm *sm, void *priv) |
| 403 | { |
| 404 | struct eap_psk_data *data = priv; |
| 405 | return data->state == PSK_DONE; |
| 406 | } |
| 407 | |
| 408 | |
| 409 | static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len) |
| 410 | { |
| 411 | struct eap_psk_data *data = priv; |
| 412 | u8 *key; |
| 413 | |
| 414 | if (data->state != PSK_DONE) |
| 415 | return NULL; |
| 416 | |
| 417 | key = os_malloc(EAP_MSK_LEN); |
| 418 | if (key == NULL) |
| 419 | return NULL; |
| 420 | |
| 421 | *len = EAP_MSK_LEN; |
| 422 | os_memcpy(key, data->msk, EAP_MSK_LEN); |
| 423 | |
| 424 | return key; |
| 425 | } |
| 426 | |
| 427 | |
| 428 | static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) |
| 429 | { |
| 430 | struct eap_psk_data *data = priv; |
| 431 | u8 *key; |
| 432 | |
| 433 | if (data->state != PSK_DONE) |
| 434 | return NULL; |
| 435 | |
| 436 | key = os_malloc(EAP_EMSK_LEN); |
| 437 | if (key == NULL) |
| 438 | return NULL; |
| 439 | |
| 440 | *len = EAP_EMSK_LEN; |
| 441 | os_memcpy(key, data->emsk, EAP_EMSK_LEN); |
| 442 | |
| 443 | return key; |
| 444 | } |
| 445 | |
| 446 | |
| 447 | int eap_peer_psk_register(void) |
| 448 | { |
| 449 | struct eap_method *eap; |
| 450 | int ret; |
| 451 | |
| 452 | eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, |
| 453 | EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK"); |
| 454 | if (eap == NULL) |
| 455 | return -1; |
| 456 | |
| 457 | eap->init = eap_psk_init; |
| 458 | eap->deinit = eap_psk_deinit; |
| 459 | eap->process = eap_psk_process; |
| 460 | eap->isKeyAvailable = eap_psk_isKeyAvailable; |
| 461 | eap->getKey = eap_psk_getKey; |
| 462 | eap->get_emsk = eap_psk_get_emsk; |
| 463 | |
| 464 | ret = eap_peer_method_register(eap); |
| 465 | if (ret) |
| 466 | eap_peer_method_free(eap); |
| 467 | return ret; |
| 468 | } |