yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame^] | 1 | /* |
| 2 | * EAP peer state machines internal structures (RFC 4137) |
| 3 | * Copyright (c) 2004-2014, 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 | #ifndef EAP_I_H |
| 10 | #define EAP_I_H |
| 11 | |
| 12 | #include "wpabuf.h" |
| 13 | #include "utils/list.h" |
| 14 | #include "eap_peer/eap.h" |
| 15 | #include "eap_common/eap_common.h" |
| 16 | |
| 17 | #define NO_EAP_METHOD_ERROR (-1) |
| 18 | |
| 19 | /* RFC 4137 - EAP Peer state machine */ |
| 20 | |
| 21 | typedef enum { |
| 22 | DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC |
| 23 | } EapDecision; |
| 24 | |
| 25 | typedef enum { |
| 26 | METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE |
| 27 | } EapMethodState; |
| 28 | |
| 29 | /** |
| 30 | * struct eap_method_ret - EAP return values from struct eap_method::process() |
| 31 | * |
| 32 | * These structure contains OUT variables for the interface between peer state |
| 33 | * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as |
| 34 | * the return value of struct eap_method::process() so it is not included in |
| 35 | * this structure. |
| 36 | */ |
| 37 | struct eap_method_ret { |
| 38 | /** |
| 39 | * ignore - Whether method decided to drop the current packed (OUT) |
| 40 | */ |
| 41 | bool ignore; |
| 42 | |
| 43 | /** |
| 44 | * methodState - Method-specific state (IN/OUT) |
| 45 | */ |
| 46 | EapMethodState methodState; |
| 47 | |
| 48 | /** |
| 49 | * decision - Authentication decision (OUT) |
| 50 | */ |
| 51 | EapDecision decision; |
| 52 | |
| 53 | /** |
| 54 | * allowNotifications - Whether method allows notifications (OUT) |
| 55 | */ |
| 56 | bool allowNotifications; |
| 57 | }; |
| 58 | |
| 59 | |
| 60 | /** |
| 61 | * struct eap_method - EAP method interface |
| 62 | * This structure defines the EAP method interface. Each method will need to |
| 63 | * register its own EAP type, EAP name, and set of function pointers for method |
| 64 | * specific operations. This interface is based on section 4.4 of RFC 4137. |
| 65 | */ |
| 66 | struct eap_method { |
| 67 | /** |
| 68 | * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF) |
| 69 | */ |
| 70 | int vendor; |
| 71 | |
| 72 | /** |
| 73 | * method - EAP type number (EAP_TYPE_*) |
| 74 | */ |
| 75 | enum eap_type method; |
| 76 | |
| 77 | /** |
| 78 | * name - Name of the method (e.g., "TLS") |
| 79 | */ |
| 80 | const char *name; |
| 81 | |
| 82 | /** |
| 83 | * init - Initialize an EAP method |
| 84 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 85 | * Returns: Pointer to allocated private data, or %NULL on failure |
| 86 | * |
| 87 | * This function is used to initialize the EAP method explicitly |
| 88 | * instead of using METHOD_INIT state as specific in RFC 4137. The |
| 89 | * method is expected to initialize it method-specific state and return |
| 90 | * a pointer that will be used as the priv argument to other calls. |
| 91 | */ |
| 92 | void * (*init)(struct eap_sm *sm); |
| 93 | |
| 94 | /** |
| 95 | * deinit - Deinitialize an EAP method |
| 96 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 97 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 98 | * |
| 99 | * Deinitialize the EAP method and free any allocated private data. |
| 100 | */ |
| 101 | void (*deinit)(struct eap_sm *sm, void *priv); |
| 102 | |
| 103 | /** |
| 104 | * process - Process an EAP request |
| 105 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 106 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 107 | * @ret: Return values from EAP request validation and processing |
| 108 | * @reqData: EAP request to be processed (eapReqData) |
| 109 | * Returns: Pointer to allocated EAP response packet (eapRespData) |
| 110 | * |
| 111 | * This function is a combination of m.check(), m.process(), and |
| 112 | * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other |
| 113 | * words, this function validates the incoming request, processes it, |
| 114 | * and build a response packet. m.check() and m.process() return values |
| 115 | * are returned through struct eap_method_ret *ret variable. Caller is |
| 116 | * responsible for freeing the returned EAP response packet. |
| 117 | */ |
| 118 | struct wpabuf * (*process)(struct eap_sm *sm, void *priv, |
| 119 | struct eap_method_ret *ret, |
| 120 | const struct wpabuf *reqData); |
| 121 | |
| 122 | /** |
| 123 | * isKeyAvailable - Find out whether EAP method has keying material |
| 124 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 125 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 126 | * Returns: %true if key material (eapKeyData) is available |
| 127 | */ |
| 128 | bool (*isKeyAvailable)(struct eap_sm *sm, void *priv); |
| 129 | |
| 130 | /** |
| 131 | * getKey - Get EAP method specific keying material (eapKeyData) |
| 132 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 133 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 134 | * @len: Pointer to variable to store key length (eapKeyDataLen) |
| 135 | * Returns: Keying material (eapKeyData) or %NULL if not available |
| 136 | * |
| 137 | * This function can be used to get the keying material from the EAP |
| 138 | * method. The key may already be stored in the method-specific private |
| 139 | * data or this function may derive the key. |
| 140 | */ |
| 141 | u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len); |
| 142 | |
| 143 | /** |
| 144 | * get_status - Get EAP method status |
| 145 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 146 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 147 | * @buf: Buffer for status information |
| 148 | * @buflen: Maximum buffer length |
| 149 | * @verbose: Whether to include verbose status information |
| 150 | * Returns: Number of bytes written to buf |
| 151 | * |
| 152 | * Query EAP method for status information. This function fills in a |
| 153 | * text area with current status information from the EAP method. If |
| 154 | * the buffer (buf) is not large enough, status information will be |
| 155 | * truncated to fit the buffer. |
| 156 | */ |
| 157 | int (*get_status)(struct eap_sm *sm, void *priv, char *buf, |
| 158 | size_t buflen, int verbose); |
| 159 | |
| 160 | /** |
| 161 | * has_reauth_data - Whether method is ready for fast reauthentication |
| 162 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 163 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 164 | * Returns: %true or %false based on whether fast reauthentication is |
| 165 | * possible |
| 166 | * |
| 167 | * This function is an optional handler that only EAP methods |
| 168 | * supporting fast re-authentication need to implement. |
| 169 | */ |
| 170 | bool (*has_reauth_data)(struct eap_sm *sm, void *priv); |
| 171 | |
| 172 | /** |
| 173 | * deinit_for_reauth - Release data that is not needed for fast re-auth |
| 174 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 175 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 176 | * |
| 177 | * This function is an optional handler that only EAP methods |
| 178 | * supporting fast re-authentication need to implement. This is called |
| 179 | * when authentication has been completed and EAP state machine is |
| 180 | * requesting that enough state information is maintained for fast |
| 181 | * re-authentication |
| 182 | */ |
| 183 | void (*deinit_for_reauth)(struct eap_sm *sm, void *priv); |
| 184 | |
| 185 | /** |
| 186 | * init_for_reauth - Prepare for start of fast re-authentication |
| 187 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 188 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 189 | * |
| 190 | * This function is an optional handler that only EAP methods |
| 191 | * supporting fast re-authentication need to implement. This is called |
| 192 | * when EAP authentication is started and EAP state machine is |
| 193 | * requesting fast re-authentication to be used. |
| 194 | */ |
| 195 | void * (*init_for_reauth)(struct eap_sm *sm, void *priv); |
| 196 | |
| 197 | /** |
| 198 | * get_identity - Get method specific identity for re-authentication |
| 199 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 200 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 201 | * @len: Length of the returned identity |
| 202 | * Returns: Pointer to the method specific identity or %NULL if default |
| 203 | * identity is to be used |
| 204 | * |
| 205 | * This function is an optional handler that only EAP methods |
| 206 | * that use method specific identity need to implement. |
| 207 | */ |
| 208 | const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len); |
| 209 | |
| 210 | /** |
| 211 | * get_error_code - Get the latest EAP method error code |
| 212 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 213 | * Returns: An int for the EAP method specific error code if exists or |
| 214 | * NO_EAP_METHOD_ERROR otherwise. |
| 215 | * |
| 216 | * This method is an optional handler that only EAP methods that need to |
| 217 | * report their error code need to implement. |
| 218 | */ |
| 219 | int (*get_error_code)(void *priv); |
| 220 | |
| 221 | /** |
| 222 | * free - Free EAP method data |
| 223 | * @method: Pointer to the method data registered with |
| 224 | * eap_peer_method_register(). |
| 225 | * |
| 226 | * This function will be called when the EAP method is being |
| 227 | * unregistered. If the EAP method allocated resources during |
| 228 | * registration (e.g., allocated struct eap_method), they should be |
| 229 | * freed in this function. No other method functions will be called |
| 230 | * after this call. If this function is not defined (i.e., function |
| 231 | * pointer is %NULL), a default handler is used to release the method |
| 232 | * data with free(method). This is suitable for most cases. |
| 233 | */ |
| 234 | void (*free)(struct eap_method *method); |
| 235 | |
| 236 | #define EAP_PEER_METHOD_INTERFACE_VERSION 1 |
| 237 | /** |
| 238 | * version - Version of the EAP peer method interface |
| 239 | * |
| 240 | * The EAP peer method implementation should set this variable to |
| 241 | * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the |
| 242 | * EAP method is using supported API version when using dynamically |
| 243 | * loadable EAP methods. |
| 244 | */ |
| 245 | int version; |
| 246 | |
| 247 | /** |
| 248 | * next - Pointer to the next EAP method |
| 249 | * |
| 250 | * This variable is used internally in the EAP method registration code |
| 251 | * to create a linked list of registered EAP methods. |
| 252 | */ |
| 253 | struct eap_method *next; |
| 254 | |
| 255 | #ifdef CONFIG_DYNAMIC_EAP_METHODS |
| 256 | /** |
| 257 | * dl_handle - Handle for the dynamic library |
| 258 | * |
| 259 | * This variable is used internally in the EAP method registration code |
| 260 | * to store a handle for the dynamic library. If the method is linked |
| 261 | * in statically, this is %NULL. |
| 262 | */ |
| 263 | void *dl_handle; |
| 264 | #endif /* CONFIG_DYNAMIC_EAP_METHODS */ |
| 265 | |
| 266 | /** |
| 267 | * get_emsk - Get EAP method specific keying extended material (EMSK) |
| 268 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 269 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 270 | * @len: Pointer to a variable to store EMSK length |
| 271 | * Returns: EMSK or %NULL if not available |
| 272 | * |
| 273 | * This function can be used to get the extended keying material from |
| 274 | * the EAP method. The key may already be stored in the method-specific |
| 275 | * private data or this function may derive the key. |
| 276 | */ |
| 277 | u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len); |
| 278 | |
| 279 | /** |
| 280 | * getSessionId - Get EAP method specific Session-Id |
| 281 | * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() |
| 282 | * @priv: Pointer to private EAP method data from eap_method::init() |
| 283 | * @len: Pointer to a variable to store Session-Id length |
| 284 | * Returns: Session-Id or %NULL if not available |
| 285 | * |
| 286 | * This function can be used to get the Session-Id from the EAP method. |
| 287 | * The Session-Id may already be stored in the method-specific private |
| 288 | * data or this function may derive the Session-Id. |
| 289 | */ |
| 290 | u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len); |
| 291 | }; |
| 292 | |
| 293 | |
| 294 | struct eap_erp_key { |
| 295 | struct dl_list list; |
| 296 | size_t rRK_len; |
| 297 | size_t rIK_len; |
| 298 | u8 rRK[ERP_MAX_KEY_LEN]; |
| 299 | u8 rIK[ERP_MAX_KEY_LEN]; |
| 300 | u32 next_seq; |
| 301 | char keyname_nai[]; |
| 302 | }; |
| 303 | |
| 304 | /** |
| 305 | * struct eap_sm - EAP state machine data |
| 306 | */ |
| 307 | struct eap_sm { |
| 308 | enum { |
| 309 | EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED, |
| 310 | EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD, |
| 311 | EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS, |
| 312 | EAP_FAILURE |
| 313 | } EAP_state; |
| 314 | /* Long-term local variables */ |
| 315 | enum eap_type selectedMethod; |
| 316 | EapMethodState methodState; |
| 317 | int lastId; |
| 318 | struct wpabuf *lastRespData; |
| 319 | EapDecision decision; |
| 320 | /* Short-term local variables */ |
| 321 | bool rxReq; |
| 322 | bool rxSuccess; |
| 323 | bool rxFailure; |
| 324 | int reqId; |
| 325 | enum eap_type reqMethod; |
| 326 | int reqVendor; |
| 327 | u32 reqVendorMethod; |
| 328 | bool ignore; |
| 329 | /* Constants */ |
| 330 | int ClientTimeout; |
| 331 | |
| 332 | /* Miscellaneous variables */ |
| 333 | bool allowNotifications; /* peer state machine <-> methods */ |
| 334 | struct wpabuf *eapRespData; /* peer to lower layer */ |
| 335 | bool eapKeyAvailable; /* peer to lower layer */ |
| 336 | u8 *eapKeyData; /* peer to lower layer */ |
| 337 | size_t eapKeyDataLen; /* peer to lower layer */ |
| 338 | u8 *eapSessionId; /* peer to lower layer */ |
| 339 | size_t eapSessionIdLen; /* peer to lower layer */ |
| 340 | const struct eap_method *m; /* selected EAP method */ |
| 341 | /* not defined in RFC 4137 */ |
| 342 | bool changed; |
| 343 | void *eapol_ctx; |
| 344 | const struct eapol_callbacks *eapol_cb; |
| 345 | void *eap_method_priv; |
| 346 | int init_phase2; |
| 347 | int fast_reauth; |
| 348 | bool reauthInit; /* send EAP-Identity/Re-auth */ |
| 349 | u32 erp_seq; |
| 350 | |
| 351 | bool rxResp /* LEAP only */; |
| 352 | bool leap_done; |
| 353 | bool peap_done; |
| 354 | u8 req_sha1[20]; /* SHA1() of the current EAP packet */ |
| 355 | u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used |
| 356 | * in duplicate request detection. */ |
| 357 | |
| 358 | void *msg_ctx; |
| 359 | void *scard_ctx; |
| 360 | void *ssl_ctx; |
| 361 | void *ssl_ctx2; |
| 362 | |
| 363 | unsigned int workaround; |
| 364 | |
| 365 | /* Optional challenges generated in Phase 1 (EAP-FAST) */ |
| 366 | u8 *peer_challenge, *auth_challenge; |
| 367 | |
| 368 | int num_rounds; |
| 369 | int num_rounds_short; |
| 370 | int force_disabled; |
| 371 | |
| 372 | struct wps_context *wps; |
| 373 | |
| 374 | int prev_failure; |
| 375 | struct eap_peer_config *last_config; |
| 376 | |
| 377 | struct ext_password_data *ext_pw; |
| 378 | struct wpabuf *ext_pw_buf; |
| 379 | |
| 380 | int external_sim; |
| 381 | |
| 382 | unsigned int expected_failure:1; |
| 383 | unsigned int ext_cert_check:1; |
| 384 | unsigned int waiting_ext_cert_check:1; |
| 385 | unsigned int use_machine_cred:1; |
| 386 | |
| 387 | struct dl_list erp_keys; /* struct eap_erp_key */ |
| 388 | }; |
| 389 | |
| 390 | const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); |
| 391 | const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); |
| 392 | const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash); |
| 393 | const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len); |
| 394 | const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len); |
| 395 | void eap_clear_config_otp(struct eap_sm *sm); |
| 396 | const char * eap_get_config_phase1(struct eap_sm *sm); |
| 397 | const char * eap_get_config_phase2(struct eap_sm *sm); |
| 398 | int eap_get_config_fragment_size(struct eap_sm *sm); |
| 399 | struct eap_peer_config * eap_get_config(struct eap_sm *sm); |
| 400 | void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); |
| 401 | const struct wpa_config_blob * |
| 402 | eap_get_config_blob(struct eap_sm *sm, const char *name); |
| 403 | void eap_notify_pending(struct eap_sm *sm); |
| 404 | int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); |
| 405 | |
| 406 | #endif /* EAP_I_H */ |