/** Set the next section type if it's not already set * * @param[in] request The current request. * @param[in] type_da to use. Usually attr_auth_type. * @param[in] enumv Enumeration value of the specified type_da. */ bool module_section_type_set(REQUEST *request, fr_dict_attr_t const *type_da, fr_dict_enum_t const *enumv) { VALUE_PAIR *vp; switch (pair_update_control(&vp, type_da)) { case 0: fr_value_box_copy(vp, &vp->data, enumv->value); vp->data.enumv = vp->da; /* So we get the correct string alias */ RDEBUG2("Setting &control:%pP", vp); return true; case 1: RDEBUG2("&control:%s already set. Not setting to %s", vp->da->name, enumv->alias); return false; default: MEM(0); return false; } }
/** Send the challenge itself * * Challenges will come from one of three places eventually: * * 1 from attributes like FR_EAP_AKA_RANDx * (these might be retrieved from a database) * * 2 from internally implemented SIM authenticators * (a simple one based upon XOR will be provided) * * 3 from some kind of SS7 interface. * * For now, they only come from attributes. * It might be that the best way to do 2/3 will be with a different * module to generate/calculate things. */ static int eap_aka_send_challenge(eap_session_t *eap_session) { REQUEST *request = eap_session->request; eap_aka_session_t *eap_aka_session = talloc_get_type_abort(eap_session->opaque, eap_aka_session_t); VALUE_PAIR **to_peer, *vp; RADIUS_PACKET *packet; fr_sim_vector_src_t src = SIM_VECTOR_SRC_AUTO; rad_assert(request); rad_assert(request->reply); /* * to_peer is the data to the client */ packet = eap_session->request->reply; to_peer = &packet->vps; RDEBUG2("Acquiring UMTS vector(s)"); /* * Toggle the AMF high bit to indicate we're doing AKA' */ if (eap_aka_session->type == FR_EAP_AKA_PRIME) { uint8_t amf_buff[2] = { 0x80, 0x00 }; /* Set the AMF separation bit high */ MEM(pair_update_control(&vp, attr_sim_amf) >= 0); fr_pair_value_memcpy(vp, amf_buff, sizeof(amf_buff)); } /* * Get vectors from attribute or generate * them using COMP128-* or Milenage. */ if (fr_sim_vector_umts_from_attrs(eap_session, request->control, &eap_aka_session->keys, &src) != 0) { REDEBUG("Failed retrieving UMTS vectors"); return RLM_MODULE_FAIL; } /* * Don't leave the AMF hanging around */ if (eap_aka_session->type == FR_EAP_AKA_PRIME) pair_delete_control(attr_sim_amf); /* * All set, calculate keys! */ switch (eap_aka_session->kdf) { case FR_EAP_AKA_KDF_VALUE_EAP_AKA_PRIME_WITH_CK_PRIME_IK_PRIME: fr_sim_crypto_kdf_1_umts(&eap_aka_session->keys); break; default: fr_sim_crypto_kdf_0_umts(&eap_aka_session->keys); break; } if (RDEBUG_ENABLED3) fr_sim_crypto_keys_log(request, &eap_aka_session->keys); RDEBUG2("Sending AKA-Challenge"); eap_session->this_round->request->code = FR_EAP_CODE_REQUEST; /* * Set the subtype to challenge */ MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_subtype)); vp->vp_uint16 = FR_EAP_AKA_SUBTYPE_VALUE_AKA_CHALLENGE; fr_pair_replace(to_peer, vp); /* * Indicate we'd like to use protected success messages */ if (eap_aka_session->send_result_ind) { MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_result_ind)); vp->vp_bool = true; fr_pair_replace(to_peer, vp); } /* * We support EAP-AKA' and the peer should use that * if it's able to... */ if (eap_aka_session->send_at_bidding) { MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_bidding)); vp->vp_uint16 = FR_EAP_AKA_BIDDING_VALUE_PREFER_AKA_PRIME; fr_pair_replace(to_peer, vp); } /* * Send the network name and KDF to the peer */ if (eap_aka_session->type == FR_EAP_AKA_PRIME) { if (!eap_aka_session->keys.network_len) { REDEBUG2("No network name available, can't set EAP-AKA-KDF-Input"); failure: fr_pair_list_free(&packet->vps); return -1; } MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_kdf_input)); fr_pair_value_bstrncpy(vp, eap_aka_session->keys.network, eap_aka_session->keys.network_len); fr_pair_replace(to_peer, vp); MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_kdf)); vp->vp_uint16 = eap_aka_session->kdf; fr_pair_replace(to_peer, vp); } /* * Okay, we got the challenge! Put it into an attribute. */ MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_rand)); fr_pair_value_memcpy(vp, eap_aka_session->keys.umts.vector.rand, SIM_VECTOR_UMTS_RAND_SIZE); fr_pair_replace(to_peer, vp); /* * Send the AUTN value to the client, so it can authenticate * whoever has knowledge of the Ki. */ MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_autn)); fr_pair_value_memcpy(vp, eap_aka_session->keys.umts.vector.autn, SIM_VECTOR_UMTS_AUTN_SIZE); fr_pair_replace(to_peer, vp); /* * need to include an AT_MAC attribute so that it will get * calculated. */ MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_mac)); fr_pair_replace(to_peer, vp); /* * If we have checkcode data, send that to the peer * for validation. */ if (eap_aka_session->checkcode_state) { ssize_t slen; slen = fr_sim_crypto_finalise_checkcode(eap_aka_session->checkcode, &eap_aka_session->checkcode_state); if (slen < 0) { RPEDEBUG("Failed calculating checkcode"); goto failure; } eap_aka_session->checkcode_len = slen; MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_checkcode)); fr_pair_value_memcpy(vp, eap_aka_session->checkcode, slen); /* * If we don't have checkcode data, then we exchanged * no identity packets, so checkcode is zero. */ } else { MEM(vp = fr_pair_afrom_da(packet, attr_eap_aka_checkcode)); eap_aka_session->checkcode_len = 0; } fr_pair_replace(to_peer, vp); /* * We've sent the challenge so the peer should now be able * to accept encrypted attributes. */ eap_aka_session->allow_encrypted = true; /* * Encode the packet */ if (eap_aka_compose(eap_session) < 0) goto failure; return 0; }