fr_aka_sim_ctx_t encode_ctx;
uint8_t const *request_hmac_extra = NULL;
size_t request_hmac_extra_len = 0;
+ fr_pair_t *vp;
int ret;
/*
return UNLANG_ACTION_CALCULATE_RESULT;
}
- RDEBUG2("Encoding attributes");
- log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->reply_pairs, NULL);
-
/*
* It's not an EAP-Success or an EAP-Failure
* it's a real EAP-SIM/AKA/AKA' response.
* of request we're sending.
*/
switch (subtype_vp->vp_uint16) {
- case FR_SUBTYPE_VALUE_SIM_START:
case FR_SUBTYPE_VALUE_AKA_IDENTITY:
- {
- fr_pair_t *id_vp;
-
+ case FR_SUBTYPE_VALUE_SIM_START:
if (RDEBUG_ENABLED2) break;
/*
* Figure out if the state machine is
* requesting an ID.
*/
- if ((id_vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_any_id_req)) ||
- (id_vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_fullauth_id_req)) ||
- (id_vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_permanent_id_req))) {
- RDEBUG2("Sending EAP-Request/%pV (%s)", &subtype_vp->data, id_vp->da->name);
+ if ((vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_any_id_req)) ||
+ (vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_fullauth_id_req)) ||
+ (vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_permanent_id_req))) {
+ RDEBUG2("Sending EAP-Request/%pV (%s)", &subtype_vp->data, vp->da->name);
} else {
RDEBUG2("Sending EAP-Request/%pV", &subtype_vp->data);
}
- }
break;
/*
* it should have used that.
*/
case FR_SUBTYPE_VALUE_AKA_CHALLENGE:
- {
- fr_pair_t *bidding_vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_bidding);
+ vp = fr_pair_find_by_da(&request->reply_pairs, attr_eap_aka_sim_bidding);
/*
* Explicit NO
*/
if (inst->aka.send_at_bidding_prefer_prime_is_set &&
!inst->aka.send_at_bidding_prefer_prime) {
- if (bidding_vp) pair_delete_reply(attr_eap_aka_sim_bidding);
+ if (vp) pair_delete_reply(attr_eap_aka_sim_bidding);
/*
* Implicit or explicit YES
*/
} else if (inst->aka.send_at_bidding_prefer_prime) {
- MEM(pair_append_reply(&bidding_vp, attr_eap_aka_sim_bidding) >= 0);
- bidding_vp->vp_uint16 = FR_BIDDING_VALUE_PREFER_AKA_PRIME;
+ MEM(pair_append_reply(&vp, attr_eap_aka_sim_bidding) >= 0);
+ vp->vp_uint16 = FR_BIDDING_VALUE_PREFER_AKA_PRIME;
}
- }
FALL_THROUGH;
case FR_SUBTYPE_VALUE_SIM_CHALLENGE:
case FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION:
- {
- fr_pair_t *vp;
+ /*
+ * Include our copy of the checkcode if we've been
+ * calculating it.
+ */
+ if (mod_session->checkcode_state) {
+ uint8_t *checkcode;
+
+ MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
+ if (fr_aka_sim_crypto_finalise_checkcode(vp, &checkcode, mod_session->checkcode_state) < 0) {
+ RPWDEBUG("Failed calculating checkcode");
+ pair_delete_reply(vp);
+ }
+ fr_pair_value_memdup_buffer_shallow(vp, checkcode, false); /* Buffer already in the correct ctx */
+ }
/*
* Extra data to append to the packet when signing.
}
fr_assert(mod_session->ctx.k_encr && mod_session->ctx.k_aut);
- }
FALL_THROUGH;
default:
encode_ctx.hmac_extra = request_hmac_extra;
encode_ctx.hmac_extra_len = request_hmac_extra_len;
+ RDEBUG2("Encoding attributes");
+ log_request_pair_list(L_DBG_LVL_2, request, NULL, &request->reply_pairs, NULL);
ret = fr_aka_sim_encode(request, &request->reply_pairs, &encode_ctx);
- if (ret <= 0) { /* No valid packets have length 0 */
- RPEDEBUG("Failed encoding response");
- RETURN_MODULE_FAIL;
+ if (ret <= 0) RETURN_MODULE_FAIL;
+
+ switch (subtype_vp->vp_uint16) {
+ case FR_SUBTYPE_VALUE_AKA_IDENTITY:
+ /*
+ * Ingest the identity message into the checkcode
+ */
+ if (mod_session->ctx.checkcode_md) {
+ RDEBUG2("Updating checkcode");
+ if (!mod_session->checkcode_state &&
+ (fr_aka_sim_crypto_init_checkcode(mod_session, &mod_session->checkcode_state,
+ mod_session->ctx.checkcode_md) < 0)) {
+ RPWDEBUG("Failed initialising checkcode");
+ break;
+ }
+
+ if (fr_aka_sim_crypto_update_checkcode(mod_session->checkcode_state,
+ eap_session->this_round->request) < 0) {
+ RPWDEBUG("Failed updating checkcode");
+ }
+ }
+ break;
+
+ default:
+ break;
}
return UNLANG_ACTION_CALCULATE_RESULT; /* rcode is already correct */
}
subtype_vp = fr_pair_find_by_da(&request->request_pairs, attr_eap_aka_sim_subtype);
- if (subtype_vp) {
- RDEBUG2("Received EAP-Response/%pV", &(subtype_vp)->data);
- } else {
- REDEBUG2("Missing Sub-Type");
+ if (!subtype_vp) {
+ REDEBUG2("Missing Sub-Type"); /* Let the state machine enter the right state */
+ break;
+ }
+
+ RDEBUG2("Received EAP-Response/%pV", &(subtype_vp)->data);
+
+ switch (subtype_vp->vp_uint16) {
+ /*
+ * Ingest the identity message into the checkcode
+ */
+ case FR_SUBTYPE_VALUE_AKA_IDENTITY:
+ if (mod_session->checkcode_state) {
+ RDEBUG2("Updating checkcode");
+ if (fr_aka_sim_crypto_update_checkcode(mod_session->checkcode_state,
+ eap_session->this_round->response) < 0) {
+ RPWDEBUG("Failed updating checkcode");
+ }
+ }
+ break;
+
+ case FR_SUBTYPE_VALUE_AKA_CHALLENGE:
+ case FR_SUBTYPE_VALUE_AKA_SIM_REAUTHENTICATION:
+ /*
+ * Include our copy of the checkcode if we've been
+ * calculating it. This is put in the control list
+ * so the state machine can check they're identical.
+ *
+ * This lets us simulate checkcode failures easily
+ * when testing the state machine.
+ */
+ if (mod_session->checkcode_state) {
+ uint8_t *checkcode;
+ fr_pair_t *vp;
+
+ MEM(pair_update_control(&vp, attr_eap_aka_sim_checkcode) >= 0);
+ if (fr_aka_sim_crypto_finalise_checkcode(vp, &checkcode, mod_session->checkcode_state) < 0) {
+ RPWDEBUG("Failed calculating checkcode");
+ pair_delete_control(vp);
+ }
+ fr_pair_value_memdup_buffer_shallow(vp, checkcode, false); /* Buffer already in the correct ctx */
+
+ }
+ break;
+
+ default:
+ break;
}
break;
}
return 0;
}
+/** Check &control.checkcode matches &reply.checkcode
+ *
+ * @param[in] request The current request.
+ * @return
+ * - 1 if the check was skipped.
+ * - 0 if the check was successful.
+ * - -1 if the check failed.
+ */
+static int checkcode_validate(request_t *request)
+{
+ fr_pair_t *peer_checkcode, *our_checkcode;
+ /*
+ * Checkcode validation
+ *
+ * The actual cryptographic calculations are
+ * done by the calling module, we just check
+ * the result.
+ */
+ our_checkcode = fr_pair_find_by_da(&request->control_pairs, attr_eap_aka_sim_checkcode);
+ if (our_checkcode) {
+ /*
+ * If the peer doesn't include a checkcode then that
+ * means they don't support it, and we can't validate
+ * their view of the identity packets.
+ */
+ peer_checkcode = fr_pair_find_by_da(&request->request_pairs, attr_eap_aka_sim_checkcode);
+ if (peer_checkcode) {
+ if (fr_pair_cmp(peer_checkcode, our_checkcode) == 0) {
+ RDEBUG2("Received checkcode matches calculated checkcode");
+ return 0;
+ } else {
+ REDEBUG("Received checkcode does not match calculated checkcode");
+ RHEXDUMP_INLINE2(peer_checkcode->vp_octets, peer_checkcode->vp_length, "Received");
+ RHEXDUMP_INLINE2(our_checkcode->vp_octets, our_checkcode->vp_length, "Expected");
+ return -1;
+ }
+ /*
+ * Only print something if we calculated a checkcode
+ */
+ } else {
+ RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
+ }
+ }
+ return 1;
+}
+
/** Set the crypto identity from a received identity
*
*/
ssize_t slen;
fr_pair_t *mac;
-#if 0
- *checkcode;
-#endif
-
SECTION_RCODE_PROCESS;
mac = fr_pair_find_by_da(&request->request_pairs, attr_eap_aka_sim_mac);
goto failure;
}
-#if 0
- /*
- * If the peer doesn't include a checkcode then that
- * means they don't support it, and we can't validate
- * their view of the identity packets.
- */
- checkcode = fr_pair_find_by_da(&request->request_pairs, attr_eap_aka_sim_checkcode);
- if (checkcode) {
- if (checkcode->vp_length != eap_aka_sim_session->checkcode_len) {
- REDEBUG("Received checkcode's length (%zu) does not match calculated checkcode's length (%zu)",
- checkcode->vp_length, eap_aka_sim_session->checkcode_len);
- goto failure;
- }
-
- if (memcmp(checkcode->vp_octets, eap_aka_sim_session->checkcode,
- eap_aka_sim_session->checkcode_len) == 0) {
- RDEBUG2("Received checkcode matches calculated checkcode");
- } else {
- REDEBUG("Received checkcode does not match calculated checkcode");
- RHEXDUMP_INLINE2(checkcode->vp_octets, checkcode->vp_length, "Received");
- RHEXDUMP_INLINE2(eap_aka_sim_session->checkcode,
- eap_aka_sim_session->checkcode_len, "Expected");
- goto failure;
- }
/*
- * Only print something if we calculated a checkcode
+ * Validate the checkcode
*/
- } else if (eap_aka_sim_session->checkcode_len > 0){
- RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
- }
-#endif
+ if (checkcode_validate(request) < 0) goto failure;
/*
* Check to see if the supplicant sent
MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
fr_pair_value_memdup(vp, NULL, 0, false);
-#if 0
- /*
- * If there's no checkcode_md we're not doing
- * checkcodes.
- */
- if (eap_aka_sim_session->checkcode_md) {
- /*
- * If we have checkcode data, send that to the peer
- * in AT_CHECKCODE for validation.
- */
- if (eap_aka_sim_session->checkcode_state) {
- ssize_t slen;
-
- slen = fr_aka_sim_crypto_finalise_checkcode(eap_aka_sim_session->checkcode,
- &eap_aka_sim_session->checkcode_state);
- if (slen < 0) {
- RPEDEBUG("Failed calculating checkcode");
- goto failure;
- }
- eap_aka_sim_session->checkcode_len = slen;
-
- MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
- fr_pair_value_memdup(vp, eap_aka_sim_session->checkcode, slen, false);
- /*
- * If we don't have checkcode data, then we exchanged
- * no identity packets, so checkcode is zero.
- */
- } else {
- MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
- fr_pair_value_memdup(vp, NULL, 0, false);
- eap_aka_sim_session->checkcode_len = 0;
- }
- }
-#endif
-
/*
* We've sent the challenge so the peer should now be able
* to accept encrypted attributes.
uint8_t calc_mac[AKA_SIM_MAC_DIGEST_SIZE];
ssize_t slen;
fr_pair_t *vp = NULL, *mac;
-#if 0
- *checkcode;
-#endif
+
SECTION_RCODE_PROCESS;
}
/*
- * If the peer doesn't include a checkcode then that
- * means they don't support it, and we can't validate
- * their view of the identity packets.
+ * Validate the checkcode
*/
-#if 0
- if (eap_aka_sim_session->checkcode_md) {
- checkcode = fr_pair_find_by_da(&request->request_pairs, attr_eap_aka_sim_checkcode);
- if (checkcode) {
- if (checkcode->vp_length != eap_aka_sim_session->checkcode_len) {
- REDEBUG("Received checkcode's length (%zu) does not match "
- "calculated checkcode's length (%zu)",
- checkcode->vp_length, eap_aka_sim_session->checkcode_len);
- goto failure;
- }
-
- if (memcmp(checkcode->vp_octets,
- eap_aka_sim_session->checkcode, eap_aka_sim_session->checkcode_len) == 0) {
- RDEBUG2("Received checkcode matches calculated checkcode");
- } else {
- REDEBUG("Received checkcode does not match calculated checkcode");
- RHEXDUMP_INLINE2(checkcode->vp_octets, checkcode->vp_length, "Received");
- RHEXDUMP_INLINE2(eap_aka_sim_session->checkcode,
- eap_aka_sim_session->checkcode_len, "Expected");
- goto failure;
- }
- /*
- * Only print something if we calculated a checkcode
- */
- } else if (eap_aka_sim_session->checkcode_len > 0){
- RDEBUG2("Peer didn't include AT_CHECKCODE, skipping checkcode validation");
- }
- }
-#endif
+ if (checkcode_validate(request) < 0) goto failure;
vp = fr_pair_find_by_da(&request->request_pairs, attr_eap_aka_sim_res);
if (!vp) {
MEM(pair_update_reply(&vp, attr_eap_aka_sim_mac) >= 0);
fr_pair_value_memdup(vp, NULL, 0, false);
-#if 0
- /*
- * If we have checkcode data, send that to the peer
- * in AT_CHECKCODE for validation.
- */
- if (eap_aka_sim_session->checkcode_state) {
- ssize_t slen;
-
- slen = fr_aka_sim_crypto_finalise_checkcode(eap_aka_sim_session->checkcode,
- &eap_aka_sim_session->checkcode_state);
- if (slen < 0) {
- RPEDEBUG("Failed calculating checkcode");
- goto failure;
- }
- eap_aka_sim_session->checkcode_len = slen;
-
- MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
- fr_pair_value_memdup(vp, eap_aka_sim_session->checkcode, slen, false);
- /*
- * If we don't have checkcode data, then we exchanged
- * no identity packets, so AT_CHECKCODE is zero.
- */
- } else {
- MEM(pair_update_reply(&vp, attr_eap_aka_sim_checkcode) >= 0);
- fr_pair_value_memdup(vp, NULL, 0, false);
- eap_aka_sim_session->checkcode_len = 0;
- }
-#endif
-
/*
* We've sent the challenge so the peer should now be able
* to accept encrypted attributes.
SECTION_RCODE_PROCESS;
-#if 0
- /*
- * Digest the identity response
- */
- if (eap_aka_sim_session->checkcode_md) {
- // TODO: Need another way of doing this
- if (fr_aka_sim_crypto_update_checkcode(eap_aka_sim_session->checkcode_state,
- eap_session->this_round->response) < 0) {
- RPEDEBUG("Failed updating checkcode");
- failure:
- return STATE_TRANSITION(common_failure_notification);
- }
- }
-#endif
-
/*
* See if the user wants us to request another
* identity.
*/
common_reply(request, eap_aka_sim_session, FR_SUBTYPE_VALUE_AKA_IDENTITY);
-#if 0
- /*
- * Digest the packet contents, updating our checkcode.
- */
- if (eap_aka_sim_session->checkcode_md) {
- if (!eap_aka_sim_session->checkcode_state &&
- fr_aka_sim_crypto_init_checkcode(eap_aka_sim_session, &eap_aka_sim_session->checkcode_state,
- eap_aka_sim_session->checkcode_md) < 0) {
- RPEDEBUG("Failed initialising checkcode");
- goto failure;
- }
- // TODO: Need another way of doing this
- if (fr_aka_sim_crypto_update_checkcode(eap_aka_sim_session->checkcode_state,
- eap_session->this_round->request) < 0) {
- RPEDEBUG("Failed updating checkcode");
- goto failure;
- }
- }
-#endif
-
RETURN_MODULE_HANDLED;
}
running = AKA_SIM_METHOD_HINT_SIM;
eap_aka_sim_session->type = FR_EAP_METHOD_SIM;
- eap_aka_sim_session->mac_md = EVP_sha1(); /* no checkcode support, so no checkcode_md */
+ eap_aka_sim_session->mac_md = EVP_sha1();
break;
case FR_EAP_METHOD_AKA:
running = AKA_SIM_METHOD_HINT_AKA;
eap_aka_sim_session->type = FR_EAP_METHOD_AKA;
- eap_aka_sim_session->checkcode_md = eap_aka_sim_session->mac_md = EVP_sha1();
+ eap_aka_sim_session->mac_md = EVP_sha1();
break;
case FR_EAP_METHOD_AKA_PRIME:
eap_aka_sim_session->type = FR_EAP_METHOD_AKA_PRIME;
eap_aka_sim_session->kdf = FR_KDF_VALUE_PRIME_WITH_CK_PRIME_IK_PRIME;
- eap_aka_sim_session->checkcode_md = eap_aka_sim_session->mac_md = EVP_sha256();
+ eap_aka_sim_session->mac_md = EVP_sha256();
break;
default: