$search
00001 /* 00002 * hostapd / EAP-TLS (RFC 2716) 00003 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eap_i.h" 00019 #include "eap_tls_common.h" 00020 #include "crypto/tls.h" 00021 00022 00023 static void eap_tls_reset(struct eap_sm *sm, void *priv); 00024 00025 00026 struct eap_tls_data { 00027 struct eap_ssl_data ssl; 00028 enum { START, CONTINUE, SUCCESS, FAILURE } state; 00029 int established; 00030 }; 00031 00032 00033 static const char * eap_tls_state_txt(int state) 00034 { 00035 switch (state) { 00036 case START: 00037 return "START"; 00038 case CONTINUE: 00039 return "CONTINUE"; 00040 case SUCCESS: 00041 return "SUCCESS"; 00042 case FAILURE: 00043 return "FAILURE"; 00044 default: 00045 return "Unknown?!"; 00046 } 00047 } 00048 00049 00050 static void eap_tls_state(struct eap_tls_data *data, int state) 00051 { 00052 wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s", 00053 eap_tls_state_txt(data->state), 00054 eap_tls_state_txt(state)); 00055 data->state = state; 00056 } 00057 00058 00059 static void * eap_tls_init(struct eap_sm *sm) 00060 { 00061 struct eap_tls_data *data; 00062 00063 data = os_zalloc(sizeof(*data)); 00064 if (data == NULL) 00065 return NULL; 00066 data->state = START; 00067 00068 if (eap_server_tls_ssl_init(sm, &data->ssl, 1)) { 00069 wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL."); 00070 eap_tls_reset(sm, data); 00071 return NULL; 00072 } 00073 00074 return data; 00075 } 00076 00077 00078 static void eap_tls_reset(struct eap_sm *sm, void *priv) 00079 { 00080 struct eap_tls_data *data = priv; 00081 if (data == NULL) 00082 return; 00083 eap_server_tls_ssl_deinit(sm, &data->ssl); 00084 os_free(data); 00085 } 00086 00087 00088 static struct wpabuf * eap_tls_build_start(struct eap_sm *sm, 00089 struct eap_tls_data *data, u8 id) 00090 { 00091 struct wpabuf *req; 00092 00093 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS, 1, EAP_CODE_REQUEST, 00094 id); 00095 if (req == NULL) { 00096 wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for " 00097 "request"); 00098 eap_tls_state(data, FAILURE); 00099 return NULL; 00100 } 00101 00102 wpabuf_put_u8(req, EAP_TLS_FLAGS_START); 00103 00104 eap_tls_state(data, CONTINUE); 00105 00106 return req; 00107 } 00108 00109 00110 static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id) 00111 { 00112 struct eap_tls_data *data = priv; 00113 struct wpabuf *res; 00114 00115 if (data->ssl.state == FRAG_ACK) { 00116 return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0); 00117 } 00118 00119 if (data->ssl.state == WAIT_FRAG_ACK) { 00120 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, 00121 id); 00122 goto check_established; 00123 } 00124 00125 switch (data->state) { 00126 case START: 00127 return eap_tls_build_start(sm, data, id); 00128 case CONTINUE: 00129 if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) 00130 data->established = 1; 00131 break; 00132 default: 00133 wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d", 00134 __func__, data->state); 00135 return NULL; 00136 } 00137 00138 res = eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id); 00139 00140 check_established: 00141 if (data->established && data->ssl.state != WAIT_FRAG_ACK) { 00142 /* TLS handshake has been completed and there are no more 00143 * fragments waiting to be sent out. */ 00144 wpa_printf(MSG_DEBUG, "EAP-TLS: Done"); 00145 eap_tls_state(data, SUCCESS); 00146 } 00147 00148 return res; 00149 } 00150 00151 00152 static Boolean eap_tls_check(struct eap_sm *sm, void *priv, 00153 struct wpabuf *respData) 00154 { 00155 const u8 *pos; 00156 size_t len; 00157 00158 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &len); 00159 if (pos == NULL || len < 1) { 00160 wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame"); 00161 return TRUE; 00162 } 00163 00164 return FALSE; 00165 } 00166 00167 00168 static void eap_tls_process_msg(struct eap_sm *sm, void *priv, 00169 const struct wpabuf *respData) 00170 { 00171 struct eap_tls_data *data = priv; 00172 if (data->state == SUCCESS && wpabuf_len(data->ssl.tls_in) == 0) { 00173 wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS " 00174 "handshake message"); 00175 return; 00176 } 00177 if (eap_server_tls_phase1(sm, &data->ssl) < 0) 00178 eap_tls_state(data, FAILURE); 00179 } 00180 00181 00182 static void eap_tls_process(struct eap_sm *sm, void *priv, 00183 struct wpabuf *respData) 00184 { 00185 struct eap_tls_data *data = priv; 00186 if (eap_server_tls_process(sm, &data->ssl, respData, data, 00187 EAP_TYPE_TLS, NULL, eap_tls_process_msg) < 00188 0) 00189 eap_tls_state(data, FAILURE); 00190 } 00191 00192 00193 static Boolean eap_tls_isDone(struct eap_sm *sm, void *priv) 00194 { 00195 struct eap_tls_data *data = priv; 00196 return data->state == SUCCESS || data->state == FAILURE; 00197 } 00198 00199 00200 static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len) 00201 { 00202 struct eap_tls_data *data = priv; 00203 u8 *eapKeyData; 00204 00205 if (data->state != SUCCESS) 00206 return NULL; 00207 00208 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 00209 "client EAP encryption", 00210 EAP_TLS_KEY_LEN); 00211 if (eapKeyData) { 00212 *len = EAP_TLS_KEY_LEN; 00213 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived key", 00214 eapKeyData, EAP_TLS_KEY_LEN); 00215 } else { 00216 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key"); 00217 } 00218 00219 return eapKeyData; 00220 } 00221 00222 00223 static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 00224 { 00225 struct eap_tls_data *data = priv; 00226 u8 *eapKeyData, *emsk; 00227 00228 if (data->state != SUCCESS) 00229 return NULL; 00230 00231 eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 00232 "client EAP encryption", 00233 EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 00234 if (eapKeyData) { 00235 emsk = os_malloc(EAP_EMSK_LEN); 00236 if (emsk) 00237 os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN, 00238 EAP_EMSK_LEN); 00239 os_free(eapKeyData); 00240 } else 00241 emsk = NULL; 00242 00243 if (emsk) { 00244 *len = EAP_EMSK_LEN; 00245 wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK", 00246 emsk, EAP_EMSK_LEN); 00247 } else { 00248 wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK"); 00249 } 00250 00251 return emsk; 00252 } 00253 00254 00255 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv) 00256 { 00257 struct eap_tls_data *data = priv; 00258 return data->state == SUCCESS; 00259 } 00260 00261 00262 int eap_server_tls_register(void) 00263 { 00264 struct eap_method *eap; 00265 int ret; 00266 00267 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 00268 EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS"); 00269 if (eap == NULL) 00270 return -1; 00271 00272 eap->init = eap_tls_init; 00273 eap->reset = eap_tls_reset; 00274 eap->buildReq = eap_tls_buildReq; 00275 eap->check = eap_tls_check; 00276 eap->process = eap_tls_process; 00277 eap->isDone = eap_tls_isDone; 00278 eap->getKey = eap_tls_getKey; 00279 eap->isSuccess = eap_tls_isSuccess; 00280 eap->get_emsk = eap_tls_get_emsk; 00281 00282 ret = eap_server_method_register(eap); 00283 if (ret) 00284 eap_server_method_free(eap); 00285 return ret; 00286 }