static int vector_gsm_from_triplets(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, fr_sim_keys_t *keys) { REQUEST *request = eap_session->request; VALUE_PAIR *rand = NULL, *sres = NULL, *kc = NULL; fr_cursor_t cursor; int i; for (i = 0, (kc = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_sim_kc)); (i < idx) && (kc = fr_cursor_next(&cursor)); i++); if (!kc) { RDEBUG3("No &control:%s[%i] attribute found, not using GSM triplets", attr_eap_sim_kc->name, idx); return 1; } if (kc->vp_length != SIM_VECTOR_GSM_KC_SIZE) { REDEBUG("&control:%s[%i] is not " STRINGIFY(SIM_VECTOR_GSM_KC_SIZE) " bytes, got %zu bytes", attr_eap_sim_kc->name, idx, kc->vp_length); return -1; } for (i = 0, (rand = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_sim_rand)); (i < idx) && (rand = fr_cursor_next(&cursor)); i++); if (!rand) { RDEBUG3("No &control:%s[%i] attribute found, not using GSM triplets", attr_eap_sim_rand->name, idx); return 1; } if (rand->vp_length != SIM_VECTOR_GSM_RAND_SIZE) { REDEBUG("&control:EAP-SIM-Rand[%i] is not " STRINGIFY(SIM_RAND_SIZE) " bytes, got %zu bytes", idx, rand->vp_length); return -1; } for (i = 0, (sres = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_sim_sres)); (i < idx) && (sres = fr_cursor_next(&cursor)); i++); if (!sres) { RDEBUG3("No &control:%s[%i] attribute found, not using GSM triplets", attr_eap_sim_sres->name, idx); return 1; } if (sres->vp_length != SIM_VECTOR_GSM_SRES_SIZE) { REDEBUG("&control:%s[%i] is not " STRINGIFY(SIM_VECTOR_GSM_SRES_SIZE) " bytes, got %zu bytes", attr_eap_sim_sres->name, idx, sres->vp_length); return -1; } memcpy(keys->gsm.vector[idx].kc, kc->vp_strvalue, SIM_VECTOR_GSM_KC_SIZE); memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, SIM_VECTOR_GSM_RAND_SIZE); memcpy(keys->gsm.vector[idx].sres, sres->vp_octets, SIM_VECTOR_GSM_SRES_SIZE); return 0; }
/** Do any RADIUS-layer fixups for proxying. * */ static void radius_fixups(rlm_radius_t *inst, REQUEST *request) { VALUE_PAIR *vp; /* * Check for proxy loops. */ if (RDEBUG_ENABLED) { fr_cursor_t cursor; for (vp = fr_cursor_iter_by_da_init(&cursor, &request->packet->vps, attr_proxy_state); vp; vp = fr_cursor_next(&cursor)) { if (vp->vp_length != 4) continue; if (memcmp(&inst->proxy_state, vp->vp_octets, 4) == 0) { RWARN("Possible proxy loop - please check server configuration."); break; } } } if (request->packet->code != FR_CODE_ACCESS_REQUEST) return; if (fr_pair_find_by_da(request->packet->vps, attr_chap_password, TAG_ANY) && !fr_pair_find_by_da(request->packet->vps, attr_chap_challenge, TAG_ANY)) { MEM(pair_add_request(&vp, attr_chap_challenge) >= 0); fr_pair_value_memcpy(vp, request->packet->vector, sizeof(request->packet->vector)); } }
/** Derive triplets from quintuplets * */ static int vector_gsm_from_quintuplets(eap_session_t *eap_session, VALUE_PAIR *vps, int idx, fr_sim_keys_t *keys) { REQUEST *request = eap_session->request; fr_cursor_t cursor; VALUE_PAIR *ck = NULL, *ik = NULL, *rand = NULL, *xres = NULL; int i; /* * Fetch CK */ for (i = 0, (ck = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_ck)); (i < idx) && (ck = fr_cursor_next(&cursor)); i++); if (!ck) { RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation", attr_eap_aka_ck->name, idx); return 1; } /* * Fetch IK */ for (i = 0, (ik = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_ik)); (i < idx) && (ik = fr_cursor_next(&cursor)); i++); if (!ik) { RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation", attr_eap_aka_ik->name, idx); return 1; } /* * Fetch RAND */ for (i = 0, (rand = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_rand)); (i < idx) && (rand = fr_cursor_next(&cursor)); i++); if (!rand) { RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation", attr_eap_aka_rand->name, idx); return 1; } if (rand->vp_length != SIM_VECTOR_UMTS_RAND_SIZE) { REDEBUG("&control:%s[%i] incorrect length. Expected " STRINGIFY(SIM_VECTOR_UMTS_RAND_SIZE) " bytes, " "got %zu bytes", attr_eap_aka_rand->name, idx, rand->vp_length); return -1; } /* * Fetch XRES */ for (i = 0, (xres = fr_cursor_iter_by_da_init(&cursor, &vps, attr_eap_aka_xres)); (i < idx) && (xres = fr_cursor_next(&cursor)); i++); if (!xres) { RDEBUG3("No &control:%s[%i] attribute found, not using quintuplet derivation", attr_eap_aka_xres->name, idx); return 1; } memcpy(keys->gsm.vector[idx].rand, rand->vp_octets, SIM_VECTOR_GSM_RAND_SIZE); milenage_gsm_from_umts(keys->gsm.vector[idx].sres, keys->gsm.vector[idx].kc, ik->vp_octets, ck->vp_octets, xres->vp_octets); return 0; }
/* * Use a reply packet to determine what to do. */ static rlm_rcode_t CC_HINT(nonnull) process_reply(NDEBUG_UNUSED eap_session_t *eap_session, tls_session_t *tls_session, REQUEST *request, RADIUS_PACKET *reply) { rlm_rcode_t rcode = RLM_MODULE_REJECT; VALUE_PAIR *vp; fr_cursor_t cursor; eap_fast_tunnel_t *t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t); rad_assert(eap_session->request == request); /* * If the response packet was Access-Accept, then * we're OK. If not, die horribly. * * FIXME: EAP-Messages can only start with 'identity', * NOT 'eap start', so we should check for that.... */ switch (reply->code) { case FR_CODE_ACCESS_ACCEPT: RDEBUG2("Got tunneled Access-Accept"); rcode = RLM_MODULE_OK; /* * Copy what we need into the TTLS tunnel and leave * the rest to be cleaned up. */ for (vp = fr_cursor_init(&cursor, &reply->vps); vp; vp = fr_cursor_next(&cursor)) { if (fr_dict_vendor_num_by_da(vp->da) != VENDORPEC_MICROSOFT) continue; /* FIXME must be a better way to capture/re-derive this later for ISK */ switch (vp->da->attr) { case FR_MSCHAP_MPPE_SEND_KEY: if (vp->vp_length != RADIUS_CHAP_CHALLENGE_LENGTH) { wrong_length: REDEBUG("Found %s with incorrect length. Expected %u, got %zu", vp->da->name, RADIUS_CHAP_CHALLENGE_LENGTH, vp->vp_length); rcode = RLM_MODULE_INVALID; break; } memcpy(t->isk.mppe_send, vp->vp_octets, RADIUS_CHAP_CHALLENGE_LENGTH); break; case FR_MSCHAP_MPPE_RECV_KEY: if (vp->vp_length != RADIUS_CHAP_CHALLENGE_LENGTH) goto wrong_length; memcpy(t->isk.mppe_recv, vp->vp_octets, RADIUS_CHAP_CHALLENGE_LENGTH); break; case FR_MSCHAP2_SUCCESS: RDEBUG2("Got %s, tunneling it to the client in a challenge", vp->da->name); rcode = RLM_MODULE_HANDLED; t->authenticated = true; break; default: break; } } RHEXDUMP(L_DBG_LVL_MAX, (uint8_t *)&t->isk, 2 * RADIUS_CHAP_CHALLENGE_LENGTH, "ISK[j]"); /* FIXME (part of above) */ break; case FR_CODE_ACCESS_REJECT: REDEBUG("Got tunneled Access-Reject"); rcode = RLM_MODULE_REJECT; break; case FR_CODE_ACCESS_CHALLENGE: RDEBUG2("Got tunneled Access-Challenge"); /* * Copy the EAP-Message back to the tunnel. */ (void) fr_cursor_init(&cursor, &reply->vps); for (vp = fr_cursor_iter_by_da_init(&cursor, &reply->vps, attr_eap_message); vp; vp = fr_cursor_next(&cursor)) { eap_fast_tlv_append(tls_session, attr_eap_fast_eap_payload, true, vp->vp_length, vp->vp_octets); } rcode = RLM_MODULE_HANDLED; break; default: REDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); rcode = RLM_MODULE_INVALID; break; } return rcode; }