]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP peer: Add Session-Id derivation
authorStevent Li <steventl@qca.qualcomm.com>
Wed, 6 Feb 2013 16:52:33 +0000 (18:52 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 8 Feb 2013 23:20:38 +0000 (01:20 +0200)
This adds a new getSessionId() callback for EAP peer methods to allow
EAP Session-Id to be derived. This commits implements this for EAP-FAST,
EAP-GPSK, EAP-IKEv2, EAP-PEAP, EAP-TLS, and EAP-TTLS.

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

13 files changed:
src/eap_common/eap_gpsk_common.c
src/eap_common/eap_gpsk_common.h
src/eap_peer/eap.c
src/eap_peer/eap.h
src/eap_peer/eap_fast.c
src/eap_peer/eap_gpsk.c
src/eap_peer/eap_i.h
src/eap_peer/eap_ikev2.c
src/eap_peer/eap_peap.c
src/eap_peer/eap_tls.c
src/eap_peer/eap_tls_common.c
src/eap_peer/eap_tls_common.h
src/eap_peer/eap_ttls.c

index 7d106dd06232199d8cfc1d6ff81bacf8f14be3b2..7a33215f9b8943866da954762160fc1c2fb9d198 100644 (file)
@@ -340,6 +340,141 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
 }
 
 
+static int eap_gpsk_derive_mid_helper(u32 csuite_specifier,
+                                     u8 *kdf_out, size_t kdf_out_len,
+                                     const u8 *psk, const u8 *seed,
+                                     size_t seed_len, u8 method_type)
+{
+       u8 *pos, *data;
+       size_t data_len;
+       int (*gkdf)(const u8 *_psk, const u8 *_data, size_t _data_len,
+                   u8 *buf, size_t len);
+
+       gkdf = NULL;
+       switch (csuite_specifier) {
+       case EAP_GPSK_CIPHER_AES:
+               gkdf = eap_gpsk_gkdf_cmac;
+               break;
+#ifdef EAP_GPSK_SHA256
+       case EAP_GPSK_CIPHER_SHA256:
+               gkdf = eap_gpsk_gkdf_sha256;
+               break;
+#endif /* EAP_GPSK_SHA256 */
+       default:
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d used in "
+                          "Session-Id derivation", csuite_specifier);
+               return -1;
+       }
+
+#define SID_LABEL "Method ID"
+       /* "Method ID" || EAP_Method_Type || CSuite_Sel || inputString */
+       data_len = strlen(SID_LABEL) + 1 + 6 + seed_len;
+       data = os_malloc(data_len);
+       if (data == NULL)
+               return -1;
+       pos = data;
+       os_memcpy(pos, SID_LABEL, strlen(SID_LABEL));
+       pos += strlen(SID_LABEL);
+#undef SID_LABEL
+       os_memcpy(pos, &method_type, 1);
+       pos += 1;
+       WPA_PUT_BE32(pos, EAP_GPSK_VENDOR_IETF); /* CSuite/Vendor = IETF */
+       pos += 4;
+       WPA_PUT_BE16(pos, csuite_specifier); /* CSuite/Specifier */
+       pos += 2;
+       os_memcpy(pos, seed, seed_len); /* inputString */
+       wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Data to Method ID derivation",
+                   data, data_len);
+
+       if (gkdf(psk, data, data_len, kdf_out, kdf_out_len) < 0) {
+               os_free(data);
+               return -1;
+       }
+       os_free(data);
+       wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Method ID", kdf_out, kdf_out_len);
+
+       return 0;
+}
+
+
+/**
+ * eap_gpsk_session_id - Derive EAP-GPSK Session ID
+ * @psk: Pre-shared key
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_peer: 32-byte RAND_Peer
+ * @rand_server: 32-byte RAND_Server
+ * @id_peer: ID_Peer
+ * @id_peer_len: Length of ID_Peer
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @method_type: EAP Authentication Method Type
+ * @sid: Buffer for 17-byte Session ID
+ * @sid_len: Buffer for returning length of Session ID
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+                              int specifier,
+                              const u8 *rand_peer, const u8 *rand_server,
+                              const u8 *id_peer, size_t id_peer_len,
+                              const u8 *id_server, size_t id_server_len,
+                              u8 method_type, u8 *sid, size_t *sid_len)
+{
+       u8 *seed, *pos;
+       u8 kdf_out[16];
+       size_t seed_len;
+       int ret;
+
+       wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)",
+                  vendor, specifier);
+
+       if (vendor != EAP_GPSK_VENDOR_IETF)
+               return -1;
+
+       wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+       /*
+        * inputString = RAND_Peer || ID_Peer || RAND_Server || ID_Server
+        *            (= seed)
+        * KS = 16, CSuite_Sel = 0x00000000 0x0001
+        * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type ||
+        *                      CSuite_Sel || inputString)
+        */
+       seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len;
+       seed = os_malloc(seed_len);
+       if (seed == NULL) {
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+                          "for Session-Id derivation");
+               return -1;
+       }
+
+       pos = seed;
+       os_memcpy(pos, rand_peer, EAP_GPSK_RAND_LEN);
+       pos += EAP_GPSK_RAND_LEN;
+       os_memcpy(pos, id_peer, id_peer_len);
+       pos += id_peer_len;
+       os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+       pos += EAP_GPSK_RAND_LEN;
+       os_memcpy(pos, id_server, id_server_len);
+       pos += id_server_len;
+       wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+       ret = eap_gpsk_derive_mid_helper(specifier,
+                                        kdf_out, sizeof(kdf_out),
+                                        psk, seed, seed_len,
+                                        method_type);
+
+       sid[0] = method_type;
+       os_memcpy(sid + 1, kdf_out, sizeof(kdf_out));
+       *sid_len = 1 + sizeof(kdf_out);
+
+       os_free(seed);
+
+       return ret;
+}
+
+
 /**
  * eap_gpsk_mic_len - Get the length of the MIC
  * @vendor: CSuite/Vendor
index e3d2b6b4aa63e3e421a9c03a3de910636d07da3e..fbcd54732b6020da6c5265067f9f2ea198f15ee5 100644 (file)
@@ -53,6 +53,12 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
                         const u8 *id_server, size_t id_server_len,
                         u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
                         u8 *pk, size_t *pk_len);
+int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
+                              int specifier,
+                              const u8 *rand_peer, const u8 *rand_server,
+                              const u8 *id_peer, size_t id_peer_len,
+                              const u8 *id_server, size_t id_server_len,
+                              u8 method_type, u8 *sid, size_t *sid_len);
 size_t eap_gpsk_mic_len(int vendor, int specifier);
 int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
                         int specifier, const u8 *data, size_t len, u8 *mic);
index 85c242a8de6209b49816cbc4fbde338dd8dc53e5..4df88539b00b4316c98d0a47bafd5b177279e7b0 100644 (file)
@@ -161,6 +161,8 @@ SM_STATE(EAP, INITIALIZE)
        eapol_set_bool(sm, EAPOL_eapFail, FALSE);
        os_free(sm->eapKeyData);
        sm->eapKeyData = NULL;
+       os_free(sm->eapSessionId);
+       sm->eapSessionId = NULL;
        sm->eapKeyAvailable = FALSE;
        eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
        sm->lastId = -1; /* new session - make sure this does not match with
@@ -403,6 +405,13 @@ SM_STATE(EAP, METHOD)
                os_free(sm->eapKeyData);
                sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
                                               &sm->eapKeyDataLen);
+               os_free(sm->eapSessionId);
+               sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv,
+                                                      &sm->eapSessionIdLen);
+               if (sm->eapSessionId) {
+                       wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+                                   sm->eapSessionId, sm->eapSessionIdLen);
+               }
        }
 }
 
@@ -1462,6 +1471,8 @@ void eap_sm_abort(struct eap_sm *sm)
        sm->eapRespData = NULL;
        os_free(sm->eapKeyData);
        sm->eapKeyData = NULL;
+       os_free(sm->eapSessionId);
+       sm->eapSessionId = NULL;
 
        /* This is not clearly specified in the EAP statemachines draft, but
         * it seems necessary to make sure that some of the EAPOL variables get
@@ -2158,6 +2169,28 @@ void eap_notify_lower_layer_success(struct eap_sm *sm)
 }
 
 
+/**
+ * eap_get_eapSessionId - Get Session-Id from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the session
+ * Returns: Pointer to the EAP Session-Id or %NULL on failure
+ *
+ * Fetch EAP Session-Id from the EAP state machine. The Session-Id is available
+ * only after a successful authentication. EAP state machine continues to manage
+ * the Session-Id and the caller must not change or free the returned data.
+ */
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len)
+{
+       if (sm == NULL || sm->eapSessionId == NULL) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = sm->eapSessionIdLen;
+       return sm->eapSessionId;
+}
+
+
 /**
  * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
  * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
index 8bccef1b17d42d6d0afdfc5870524bd077bc38dc..f87f9b3b0cece8cb95a63bd38a087d5c2b24eece 100644 (file)
@@ -306,6 +306,7 @@ void eap_set_force_disabled(struct eap_sm *sm, int disabled);
 int eap_key_available(struct eap_sm *sm);
 void eap_notify_success(struct eap_sm *sm);
 void eap_notify_lower_layer_success(struct eap_sm *sm);
+const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
 struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
index 7ca5288ca26e3db145f87c71cb2f3f4df562a799..3b8d803dc603987d9dd8c6286e6cae405a5f999b 100644 (file)
@@ -53,6 +53,8 @@ struct eap_fast_data {
        int session_ticket_used;
 
        u8 key_data[EAP_FAST_KEY_LEN];
+       u8 *session_id;
+       size_t id_len;
        u8 emsk[EAP_EMSK_LEN];
        int success;
 
@@ -238,6 +240,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
                pac = pac->next;
                eap_fast_free_pac(prev);
        }
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
 }
@@ -785,6 +788,21 @@ static struct wpabuf * eap_fast_process_crypto_binding(
                return NULL;
        }
 
+       if (!data->anon_provisioning && data->phase2_success) {
+               os_free(data->session_id);
+               data->session_id = eap_peer_tls_derive_session_id(
+                       sm, &data->ssl, EAP_TYPE_FAST, &data->id_len);
+               if (data->session_id) {
+                       wpa_hexdump(MSG_DEBUG, "EAP-FAST: Derived Session-Id",
+                                   data->session_id, data->id_len);
+               } else {
+                       wpa_printf(MSG_ERROR, "EAP-FAST: Failed to derive "
+                                  "Session-Id");
+                       wpabuf_free(resp);
+                       return NULL;
+               }
+       }
+
        pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
        eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
                                      pos, _bind, cmk);
@@ -1604,6 +1622,8 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
                os_free(data);
                return NULL;
        }
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (data->phase2_priv && data->phase2_method &&
            data->phase2_method->init_for_reauth)
                data->phase2_method->init_for_reauth(sm, data->phase2_priv);
@@ -1662,6 +1682,25 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_fast_data *data = priv;
+       u8 *id;
+
+       if (!data->success)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 {
        struct eap_fast_data *data = priv;
@@ -1696,6 +1735,7 @@ int eap_peer_fast_register(void)
        eap->process = eap_fast_process;
        eap->isKeyAvailable = eap_fast_isKeyAvailable;
        eap->getKey = eap_fast_getKey;
+       eap->getSessionId = eap_fast_get_session_id;
        eap->get_status = eap_fast_get_status;
 #if 0
        eap->has_reauth_data = eap_fast_has_reauth_data;
index 2bd0d480f8e451df6c8d409402a75886c1385d4c..8a0644d024d82bc868181bc9731524a2217ba103 100644 (file)
@@ -23,8 +23,8 @@ struct eap_gpsk_data {
        size_t sk_len;
        u8 pk[EAP_GPSK_MAX_PK_LEN];
        size_t pk_len;
-       u8 session_id;
-       int session_id_set;
+       u8 session_id[128];
+       size_t id_len;
        u8 *id_peer;
        size_t id_peer_len;
        u8 *id_server;
@@ -354,6 +354,21 @@ static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data,
                return NULL;
        }
 
+       if (eap_gpsk_derive_session_id(data->psk, data->psk_len,
+                                      data->vendor, data->specifier,
+                                      data->rand_peer, data->rand_server,
+                                      data->id_peer, data->id_peer_len,
+                                      data->id_server, data->id_server_len,
+                                      EAP_TYPE_GPSK,
+                                      data->session_id, &data->id_len) < 0) {
+               wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+               eap_gpsk_state(data, FAILURE);
+               wpabuf_free(resp);
+               return NULL;
+       }
+       wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+                   data->session_id, data->id_len);
+
        /* No PD_Payload_1 */
        wpabuf_put_be16(resp, 0);
 
@@ -708,6 +723,24 @@ static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_gpsk_data *data = priv;
+       u8 *sid;
+
+       if (data->state != SUCCESS)
+               return NULL;
+
+       sid = os_malloc(data->id_len);
+       if (sid == NULL)
+               return NULL;
+       os_memcpy(sid, data->session_id, data->id_len);
+       *len = data->id_len;
+
+       return sid;
+}
+
+
 int eap_peer_gpsk_register(void)
 {
        struct eap_method *eap;
@@ -724,6 +757,7 @@ int eap_peer_gpsk_register(void)
        eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
        eap->getKey = eap_gpsk_getKey;
        eap->get_emsk = eap_gpsk_get_emsk;
+       eap->getSessionId = eap_gpsk_get_session_id;
 
        ret = eap_peer_method_register(eap);
        if (ret)
index dd943174e444ba700330df60cfa552ad5ed16d79..62c867ca2fac9afbb255b84bdc58776ea0d03ce6 100644 (file)
@@ -261,6 +261,19 @@ struct eap_method {
         * private data or this function may derive the key.
         */
        u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+       /**
+        * getSessionId - Get EAP method specific Session-Id
+        * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+        * @priv: Pointer to private EAP method data from eap_method::init()
+        * @len: Pointer to a variable to store Session-Id length
+        * Returns: Session-Id or %NULL if not available
+        *
+        * This function can be used to get the Session-Id from the EAP method.
+        * The Session-Id may already be stored in the method-specific private
+        * data or this function may derive the Session-Id.
+        */
+       u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
 };
 
 
@@ -298,6 +311,8 @@ struct eap_sm {
        Boolean eapKeyAvailable; /* peer to lower layer */
        u8 *eapKeyData; /* peer to lower layer */
        size_t eapKeyDataLen; /* peer to lower layer */
+       u8 *eapSessionId; /* peer to lower layer */
+       size_t eapSessionIdLen; /* peer to lower layer */
        const struct eap_method *m; /* selected EAP method */
        /* not defined in RFC 4137 */
        Boolean changed;
index a227f8b14ed042c042ece656f1b5eabde8dca24d..09a655ecff79481b1dd80eca05e94b5194bafac6 100644 (file)
@@ -475,6 +475,36 @@ static u8 * eap_ikev2_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_ikev2_data *data = priv;
+       u8 *sid;
+       size_t sid_len;
+       size_t offset;
+
+       if (data->state != DONE || !data->keymat_ok)
+               return NULL;
+
+       sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+       sid = os_malloc(sid_len);
+       if (sid) {
+               offset = 0;
+               sid[offset] = EAP_TYPE_IKEV2;
+               offset++;
+               os_memcpy(sid + offset, data->ikev2.i_nonce,
+                         data->ikev2.i_nonce_len);
+               offset += data->ikev2.i_nonce_len;
+               os_memcpy(sid + offset, data->ikev2.r_nonce,
+                         data->ikev2.r_nonce_len);
+               *len = sid_len;
+               wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+                           sid, sid_len);
+       }
+
+       return sid;
+}
+
+
 int eap_peer_ikev2_register(void)
 {
        struct eap_method *eap;
@@ -492,6 +522,7 @@ int eap_peer_ikev2_register(void)
        eap->isKeyAvailable = eap_ikev2_isKeyAvailable;
        eap->getKey = eap_ikev2_getKey;
        eap->get_emsk = eap_ikev2_get_emsk;
+       eap->getSessionId = eap_ikev2_get_session_id;
 
        ret = eap_peer_method_register(eap);
        if (ret)
index 7fff1458a8af871ccf27fb57517838658357a51a..3b9320907c090db57bde412278257c335c14128f 100644 (file)
@@ -56,6 +56,8 @@ struct eap_peap_data {
        int resuming; /* starting a resumed session */
        int reauth; /* reauthentication */
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
 
        struct wpabuf *pending_phase2_req;
        enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
@@ -179,6 +181,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
        os_free(data->phase2_types);
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
 }
@@ -1107,6 +1110,20 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
                                           "derive key");
                        }
 
+                       os_free(data->session_id);
+                       data->session_id =
+                               eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                              EAP_TYPE_PEAP,
+                                                              &data->id_len);
+                       if (data->session_id) {
+                               wpa_hexdump(MSG_DEBUG,
+                                           "EAP-PEAP: Derived Session-Id",
+                                           data->session_id, data->id_len);
+                       } else {
+                               wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
+                                          "derive Session-Id");
+                       }
+
                        if (sm->workaround && data->resuming) {
                                /*
                                 * At least few RADIUS servers (Aegis v1.1.6;
@@ -1178,6 +1195,8 @@ static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_peap_data *data = priv;
        os_free(data->key_data);
        data->key_data = NULL;
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@ -1260,6 +1279,25 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_peap_data *data = priv;
+       u8 *id;
+
+       if (data->session_id == NULL || !data->phase2_success)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 int eap_peer_peap_register(void)
 {
        struct eap_method *eap;
@@ -1279,6 +1317,7 @@ int eap_peer_peap_register(void)
        eap->has_reauth_data = eap_peap_has_reauth_data;
        eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
        eap->init_for_reauth = eap_peap_init_for_reauth;
+       eap->getSessionId = eap_peap_get_session_id;
 
        ret = eap_peer_method_register(eap);
        if (ret)
index 061a72b10a542d7971c7ab82581d458c4fbbb9bc..d2066cd852eff297a44da48705b8906e567d9ce5 100644 (file)
@@ -21,6 +21,8 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv);
 struct eap_tls_data {
        struct eap_ssl_data ssl;
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
        void *ssl_ctx;
        u8 eap_type;
 };
@@ -103,6 +105,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
                return;
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
+       os_free(data->session_id);
        os_free(data);
 }
 
@@ -165,6 +168,17 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
        } else {
                wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
        }
+
+       os_free(data->session_id);
+       data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                         EAP_TYPE_TLS,
+                                                         &data->id_len);
+       if (data->session_id) {
+               wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
+                           data->session_id, data->id_len);
+       } else {
+               wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
+       }
 }
 
 
@@ -228,6 +242,8 @@ static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_tls_data *data = priv;
        os_free(data->key_data);
        data->key_data = NULL;
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@ -289,6 +305,25 @@ static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_tls_data *data = priv;
+       u8 *id;
+
+       if (data->session_id == NULL)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 int eap_peer_tls_register(void)
 {
        struct eap_method *eap;
@@ -304,6 +339,7 @@ int eap_peer_tls_register(void)
        eap->process = eap_tls_process;
        eap->isKeyAvailable = eap_tls_isKeyAvailable;
        eap->getKey = eap_tls_getKey;
+       eap->getSessionId = eap_tls_get_session_id;
        eap->get_status = eap_tls_get_status;
        eap->has_reauth_data = eap_tls_has_reauth_data;
        eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
index aedd85a79e853b9db5677af5cf4a1d989428e1bb..a777bb01371832050ae780cd45620ca72f378d87 100644 (file)
@@ -339,6 +339,52 @@ fail:
 }
 
 
+/**
+ * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+                                   struct eap_ssl_data *data, u8 eap_type,
+                                   size_t *len)
+{
+       struct tls_keys keys;
+       u8 *out;
+
+       /*
+        * TLS library did not support session ID generation,
+        * so get the needed TLS session parameters
+        */
+       if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+               return NULL;
+
+       if (keys.client_random == NULL || keys.server_random == NULL ||
+           keys.master_key == NULL)
+               return NULL;
+
+       *len = 1 + keys.client_random_len + keys.server_random_len;
+       out = os_malloc(*len);
+       if (out == NULL)
+               return NULL;
+
+       /* Session-Id = EAP type || client.random || server.random */
+       out[0] = eap_type;
+       os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+       os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+                 keys.server_random_len);
+
+       return out;
+}
+
+
 /**
  * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
  * @data: Data for TLS processing
index 91d3a25a0ec97dbc8b59461bd98bfbd549972c08..1a5e0f89e4e575c7d25d62d6cbeb4d6b2c21b3db 100644 (file)
@@ -94,6 +94,9 @@ int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
 void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
 u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
                             const char *label, size_t len);
+u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
+                                   struct eap_ssl_data *data, u8 eap_type,
+                                   size_t *len);
 int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
                                EapType eap_type, int peap_version,
                                u8 id, const u8 *in_data, size_t in_len,
index 9360a424c799a8240def25a44f2c9472ae620411..5091bf0844bab1ef0c7ee46f89e3614437ee3cfd 100644 (file)
@@ -54,6 +54,8 @@ struct eap_ttls_data {
        int resuming; /* starting a resumed session */
        int reauth; /* reauthentication */
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
 
        struct wpabuf *pending_phase2_req;
 
@@ -140,6 +142,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
        os_free(data->phase2_eap_types);
        eap_peer_tls_ssl_deinit(sm, &data->ssl);
        os_free(data->key_data);
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
        os_free(data);
 }
@@ -222,6 +225,17 @@ static int eap_ttls_v0_derive_key(struct eap_sm *sm,
        wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
                        data->key_data, EAP_TLS_KEY_LEN);
 
+       os_free(data->session_id);
+       data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                         EAP_TYPE_TTLS,
+                                                         &data->id_len);
+       if (data->session_id) {
+               wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
+                           data->session_id, data->id_len);
+       } else {
+               wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
+       }
+
        return 0;
 }
 
@@ -1528,6 +1542,8 @@ static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
        struct eap_ttls_data *data = priv;
        os_free(data->key_data);
        data->key_data = NULL;
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@ -1612,6 +1628,25 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 }
 
 
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+       struct eap_ttls_data *data = priv;
+       u8 *id;
+
+       if (data->session_id == NULL || !data->phase2_success)
+               return NULL;
+
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+
+       return id;
+}
+
+
 int eap_peer_ttls_register(void)
 {
        struct eap_method *eap;
@@ -1627,6 +1662,7 @@ int eap_peer_ttls_register(void)
        eap->process = eap_ttls_process;
        eap->isKeyAvailable = eap_ttls_isKeyAvailable;
        eap->getKey = eap_ttls_getKey;
+       eap->getSessionId = eap_ttls_get_session_id;
        eap->get_status = eap_ttls_get_status;
        eap->has_reauth_data = eap_ttls_has_reauth_data;
        eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;