static int mod_authenticate (void *arg, eap_handler_t *handler) { pwd_session_t *pwd_session; pwd_hdr *hdr; pwd_id_packet *id; eap_packet_t *response; REQUEST *request, *fake; VALUE_PAIR *pw, *vp; EAP_DS *eap_ds; int len, ret = 0; eap_pwd_t *inst = (eap_pwd_t *)arg; uint16_t offset; uint8_t exch, *buf, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN]; uint8_t peer_confirm[SHA256_DIGEST_LENGTH]; BIGNUM *x = NULL, *y = NULL; if ((!handler) || ((eap_ds = handler->eap_ds) == NULL) || (!inst)) { return 0; } pwd_session = (pwd_session_t *)handler->opaque; request = handler->request; response = handler->eap_ds->response; hdr = (pwd_hdr *)response->type.data; buf = hdr->data; len = response->type.length - sizeof(pwd_hdr); /* * see if we're fragmenting, if so continue until we're done */ if (pwd_session->out_buf_pos) { if (len) { RDEBUG2("pwd got something more than an ACK for a fragment"); } return send_pwd_request(pwd_session, eap_ds); } /* * the first fragment will have a total length, make a * buffer to hold all the fragments */ if (EAP_PWD_GET_LENGTH_BIT(hdr)) { if (pwd_session->in_buf) { RDEBUG2("pwd already alloced buffer for fragments"); return 0; } pwd_session->in_buf_len = ntohs(buf[0] * 256 | buf[1]); if ((pwd_session->in_buf = talloc_zero_array(pwd_session, uint8_t, pwd_session->in_buf_len)) == NULL) { RDEBUG2("pwd cannot allocate %d buffer to hold fragments", pwd_session->in_buf_len); return 0; } memset(pwd_session->in_buf, 0, pwd_session->in_buf_len); pwd_session->in_buf_pos = 0; buf += sizeof(uint16_t); len -= sizeof(uint16_t); } /* * all fragments, including the 1st will have the M(ore) bit set, * buffer those fragments! */ if (EAP_PWD_GET_MORE_BIT(hdr)) { rad_assert(pwd_session->in_buf != NULL); if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent."); return 0; } memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len); pwd_session->in_buf_pos += len; /* * send back an ACK for this fragment */ exch = EAP_PWD_GET_EXCHANGE(hdr); eap_ds->request->code = PW_EAP_REQUEST; eap_ds->request->type.num = PW_EAP_PWD; eap_ds->request->type.length = sizeof(pwd_hdr); if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) { return 0; } hdr = (pwd_hdr *)eap_ds->request->type.data; EAP_PWD_SET_EXCHANGE(hdr, exch); return 1; } if (pwd_session->in_buf) { /* * the last fragment... */ if ((pwd_session->in_buf_pos + len) > pwd_session->in_buf_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent."); return 0; } memcpy(pwd_session->in_buf + pwd_session->in_buf_pos, buf, len); buf = pwd_session->in_buf; len = pwd_session->in_buf_len; } switch (pwd_session->state) { case PWD_STATE_ID_REQ: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) { RDEBUG2("pwd exchange is incorrect: not ID"); return 0; } id = (pwd_id_packet *)buf; if ((id->prf != EAP_PWD_DEF_PRF) || (id->random_function != EAP_PWD_DEF_RAND_FUN) || (id->prep != EAP_PWD_PREP_NONE) || (memcmp(id->token, (char *)&pwd_session->token, 4)) || (id->group_num != ntohs(pwd_session->group_num))) { RDEBUG2("pwd id response is invalid"); return 0; } /* * we've agreed on the ciphersuite, record it... */ ptr = (uint8_t *)&pwd_session->ciphersuite; memcpy(ptr, (char *)&id->group_num, sizeof(uint16_t)); ptr += sizeof(uint16_t); *ptr = EAP_PWD_DEF_RAND_FUN; ptr += sizeof(uint8_t); *ptr = EAP_PWD_DEF_PRF; pwd_session->peer_id_len = len - sizeof(pwd_id_packet); if (pwd_session->peer_id_len >= sizeof(pwd_session->peer_id)) { RDEBUG2("pwd id response is malformed"); return 0; } memcpy(pwd_session->peer_id, id->identity, pwd_session->peer_id_len); pwd_session->peer_id[pwd_session->peer_id_len] = '\0'; /* * make fake request to get the password for the usable ID */ if ((fake = request_alloc_fake(handler->request)) == NULL) { RDEBUG("pwd unable to create fake request!"); return 0; } fake->username = pairmake_packet("User-Name", "", T_OP_EQ); if (!fake->username) { RDEBUG("pwd unanable to create value pair for username!"); request_free(&fake); return 0; } memcpy(fake->username->vp_strvalue, pwd_session->peer_id, pwd_session->peer_id_len); fake->username->length = pwd_session->peer_id_len; fake->username->vp_strvalue[fake->username->length] = 0; if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { fake->server = vp->vp_strvalue; } else if (inst->conf->virtual_server) { fake->server = inst->conf->virtual_server; } /* else fake->server == request->server */ if ((debug_flag > 0) && fr_log_fp) { RDEBUG("Sending tunneled request"); debug_pair_list(fake->packet->vps); fprintf(fr_log_fp, "server %s {\n", (!fake->server) ? "" : fake->server); } /* * Call authorization recursively, which will * get the password. */ process_authorize(0, fake); /* * Note that we don't do *anything* with the reply * attributes. */ if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, "} # server %s\n", (!fake->server) ? "" : fake->server); RDEBUG("Got tunneled reply code %d", fake->reply->code); debug_pair_list(fake->reply->vps); } if ((pw = pairfind(fake->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) { DEBUG2("failed to find password for %s to do pwd authentication", pwd_session->peer_id); request_free(&fake); return 0; } if (compute_password_element(pwd_session, pwd_session->group_num, pw->data.strvalue, strlen(pw->data.strvalue), inst->conf->server_id, strlen(inst->conf->server_id), pwd_session->peer_id, strlen(pwd_session->peer_id), &pwd_session->token)) { DEBUG2("failed to obtain password element :-("); request_free(&fake); return 0; } request_free(&fake); /* * compute our scalar and element */ if (compute_scalar_element(pwd_session, inst->bnctx)) { DEBUG2("failed to compute server's scalar and element"); return 0; } if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { DEBUG2("server point allocation failed"); return 0; } /* * element is a point, get both coordinates: x and y */ if (!EC_POINT_get_affine_coordinates_GFp(pwd_session->group, pwd_session->my_element, x, y, inst->bnctx)) { DEBUG2("server point assignment failed"); BN_free(x); BN_free(y); return 0; } /* * construct request */ pwd_session->out_buf_len = BN_num_bytes(pwd_session->order) + (2 * BN_num_bytes(pwd_session->prime)); if ((pwd_session->out_buf = talloc_array(pwd_session, uint8_t, pwd_session->out_buf_len)) == NULL) { return 0; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); ptr = pwd_session->out_buf; offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(x); BN_bn2bin(x, ptr + offset); ptr += BN_num_bytes(pwd_session->prime); offset = BN_num_bytes(pwd_session->prime) - BN_num_bytes(y); BN_bn2bin(y, ptr + offset); ptr += BN_num_bytes(pwd_session->prime); offset = BN_num_bytes(pwd_session->order) - BN_num_bytes(pwd_session->my_scalar); BN_bn2bin(pwd_session->my_scalar, ptr + offset); pwd_session->state = PWD_STATE_COMMIT; ret = send_pwd_request(pwd_session, eap_ds); break; case PWD_STATE_COMMIT: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } /* * process the peer's commit and generate the shared key, k */ if (process_peer_commit(pwd_session, buf, inst->bnctx)) { RDEBUG2("failed to process peer's commit"); return 0; } /* * compute our confirm blob */ if (compute_server_confirm(pwd_session, pwd_session->my_confirm, inst->bnctx)) { ERROR("rlm_eap_pwd: failed to compute confirm!"); return 0; } /* * construct a response...which is just our confirm blob */ pwd_session->out_buf_len = SHA256_DIGEST_LENGTH; if ((pwd_session->out_buf = talloc_array(pwd_session, uint8_t, pwd_session->out_buf_len)) == NULL) { return 0; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); memcpy(pwd_session->out_buf, pwd_session->my_confirm, SHA256_DIGEST_LENGTH); pwd_session->state = PWD_STATE_CONFIRM; ret = send_pwd_request(pwd_session, eap_ds); break; case PWD_STATE_CONFIRM: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } if (compute_peer_confirm(pwd_session, peer_confirm, inst->bnctx)) { RDEBUG2("pwd exchange cannot compute peer's confirm"); return 0; } if (memcmp(peer_confirm, buf, SHA256_DIGEST_LENGTH)) { RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); return 0; } if (compute_keys(pwd_session, peer_confirm, msk, emsk)) { RDEBUG2("pwd exchange cannot generate (E)MSK!"); return 0; } eap_ds->request->code = PW_EAP_SUCCESS; /* * return the MSK (in halves) */ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN); eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk+MPPE_KEY_LEN, MPPE_KEY_LEN); ret = 1; break; default: RDEBUG2("unknown PWD state"); return 0; } /* * we processed the buffered fragments, get rid of them */ if (pwd_session->in_buf) { talloc_free(pwd_session->in_buf); pwd_session->in_buf = NULL; } return ret; }
static int eap_pwd_initiate (void *instance, eap_handler_t *handler) { pwd_session_t *pwd_session; eap_pwd_t *inst = (eap_pwd_t *)instance; VALUE_PAIR *vp; pwd_id_packet *pack; if (!inst || !handler) { ERROR("rlm_eap_pwd: initiate, NULL data provided"); return -1; } /* * make sure the server's been configured properly */ if (!inst->conf->server_id) { ERROR("rlm_eap_pwd: server ID is not configured!"); return -1; } switch (inst->conf->group) { case 19: case 20: case 21: case 25: case 26: break; default: ERROR("rlm_eap_pwd: group is not supported!"); return -1; } if ((pwd_session = talloc_zero(handler, pwd_session_t)) == NULL) { return -1; } /* * set things up so they can be free'd reliably */ pwd_session->group_num = inst->conf->group; pwd_session->private_value = NULL; pwd_session->peer_scalar = NULL; pwd_session->my_scalar = NULL; pwd_session->k = NULL; pwd_session->my_element = NULL; pwd_session->peer_element = NULL; pwd_session->group = NULL; pwd_session->pwe = NULL; pwd_session->order = NULL; pwd_session->prime = NULL; /* * figure out the MTU (basically do what eap-tls does) */ pwd_session->mtu = inst->conf->fragment_size; vp = pairfind(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY); if (vp && ((int)(vp->vp_integer - 9) < pwd_session->mtu)) { /* * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type) * * the fragmentation code deals with the included length * so we don't need to subtract that here. */ pwd_session->mtu = vp->vp_integer - 9; } pwd_session->state = PWD_STATE_ID_REQ; pwd_session->in_buf = NULL; pwd_session->out_buf_pos = 0; handler->opaque = pwd_session; handler->free_opaque = free_session; /* * construct an EAP-pwd-ID/Request */ pwd_session->out_buf_len = sizeof(pwd_id_packet) + strlen(inst->conf->server_id); if ((pwd_session->out_buf = talloc_zero_array(pwd_session, uint8_t, pwd_session->out_buf_len)) == NULL) { return -1; } pack = (pwd_id_packet *)pwd_session->out_buf; pack->group_num = htons(pwd_session->group_num); pack->random_function = EAP_PWD_DEF_RAND_FUN; pack->prf = EAP_PWD_DEF_PRF; pwd_session->token = random(); memcpy(pack->token, (char *)&pwd_session->token, 4); pack->prep = EAP_PWD_PREP_NONE; strcpy(pack->identity, inst->conf->server_id); handler->stage = AUTHENTICATE; return send_pwd_request(pwd_session, handler->eap_ds); }
static int mod_session_init (void *instance, eap_handler_t *handler) { pwd_session_t *session; eap_pwd_t *inst = (eap_pwd_t *)instance; VALUE_PAIR *vp; pwd_id_packet_t *packet; if (!inst || !handler) { ERROR("rlm_eap_pwd: Initiate, NULL data provided"); return 0; } /* * make sure the server's been configured properly */ if (!inst->server_id) { ERROR("rlm_eap_pwd: Server ID is not configured"); return 0; } switch (inst->group) { case 19: case 20: case 21: case 25: case 26: break; default: ERROR("rlm_eap_pwd: Group is not supported"); return 0; } if ((session = talloc_zero(handler, pwd_session_t)) == NULL) return 0; talloc_set_destructor(session, _free_pwd_session); /* * set things up so they can be free'd reliably */ session->group_num = inst->group; session->private_value = NULL; session->peer_scalar = NULL; session->my_scalar = NULL; session->k = NULL; session->my_element = NULL; session->peer_element = NULL; session->group = NULL; session->pwe = NULL; session->order = NULL; session->prime = NULL; /* * The admin can dynamically change the MTU. */ session->mtu = inst->fragment_size; vp = fr_pair_find_by_num(handler->request->packet->vps, PW_FRAMED_MTU, 0, TAG_ANY); /* * session->mtu is *our* MTU. We need to subtract off the EAP * overhead. * * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type) * * The fragmentation code deals with the included length * so we don't need to subtract that here. */ if (vp && (vp->vp_integer > 100) && (vp->vp_integer < session->mtu)) { session->mtu = vp->vp_integer - 9; } session->state = PWD_STATE_ID_REQ; session->in = NULL; session->out_pos = 0; handler->opaque = session; /* * construct an EAP-pwd-ID/Request */ session->out_len = sizeof(pwd_id_packet_t) + strlen(inst->server_id); if ((session->out = talloc_zero_array(session, uint8_t, session->out_len)) == NULL) { return 0; } packet = (pwd_id_packet_t *)session->out; packet->group_num = htons(session->group_num); packet->random_function = EAP_PWD_DEF_RAND_FUN; packet->prf = EAP_PWD_DEF_PRF; session->token = fr_rand(); memcpy(packet->token, (char *)&session->token, 4); packet->prep = EAP_PWD_PREP_NONE; memcpy(packet->identity, inst->server_id, session->out_len - sizeof(pwd_id_packet_t) ); handler->stage = PROCESS; return send_pwd_request(session, handler->eap_ds); }
static int mod_process(void *arg, eap_handler_t *handler) { pwd_session_t *session; pwd_hdr *hdr; pwd_id_packet_t *packet; eap_packet_t *response; REQUEST *request, *fake; VALUE_PAIR *pw, *vp; EAP_DS *eap_ds; size_t in_len; int ret = 0; eap_pwd_t *inst = (eap_pwd_t *)arg; uint16_t offset; uint8_t exch, *in, *ptr, msk[MSK_EMSK_LEN], emsk[MSK_EMSK_LEN]; uint8_t peer_confirm[SHA256_DIGEST_LENGTH]; if (((eap_ds = handler->eap_ds) == NULL) || !inst) return 0; session = (pwd_session_t *)handler->opaque; request = handler->request; response = handler->eap_ds->response; hdr = (pwd_hdr *)response->type.data; /* * The header must be at least one byte. */ if (!hdr || (response->type.length < sizeof(pwd_hdr))) { RDEBUG("Packet with insufficient data"); return 0; } in = hdr->data; in_len = response->type.length - sizeof(pwd_hdr); /* * see if we're fragmenting, if so continue until we're done */ if (session->out_pos) { if (in_len) RDEBUG2("pwd got something more than an ACK for a fragment"); return send_pwd_request(session, eap_ds); } /* * the first fragment will have a total length, make a * buffer to hold all the fragments */ if (EAP_PWD_GET_LENGTH_BIT(hdr)) { if (session->in) { RDEBUG2("pwd already alloced buffer for fragments"); return 0; } if (in_len < 2) { RDEBUG("Invalid packet: length bit set, but no length field"); return 0; } session->in_len = ntohs(in[0] * 256 | in[1]); if ((session->in = talloc_zero_array(session, uint8_t, session->in_len)) == NULL) { RDEBUG2("pwd cannot allocate %zd buffer to hold fragments", session->in_len); return 0; } memset(session->in, 0, session->in_len); session->in_pos = 0; in += sizeof(uint16_t); in_len -= sizeof(uint16_t); } /* * all fragments, including the 1st will have the M(ore) bit set, * buffer those fragments! */ if (EAP_PWD_GET_MORE_BIT(hdr)) { rad_assert(session->in != NULL); if ((session->in_pos + in_len) > session->in_len) { RDEBUG2("Fragment overflows packet."); return 0; } memcpy(session->in + session->in_pos, in, in_len); session->in_pos += in_len; /* * send back an ACK for this fragment */ exch = EAP_PWD_GET_EXCHANGE(hdr); eap_ds->request->code = PW_EAP_REQUEST; eap_ds->request->type.num = PW_EAP_PWD; eap_ds->request->type.length = sizeof(pwd_hdr); if ((eap_ds->request->type.data = talloc_array(eap_ds->request, uint8_t, sizeof(pwd_hdr))) == NULL) { return 0; } hdr = (pwd_hdr *)eap_ds->request->type.data; EAP_PWD_SET_EXCHANGE(hdr, exch); return 1; } if (session->in) { /* * the last fragment... */ if ((session->in_pos + in_len) > session->in_len) { RDEBUG2("pwd will not overflow a fragment buffer. Nope, not prudent"); return 0; } memcpy(session->in + session->in_pos, in, in_len); in = session->in; in_len = session->in_len; } switch (session->state) { case PWD_STATE_ID_REQ: { BIGNUM *x = NULL, *y = NULL; if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_ID) { RDEBUG2("pwd exchange is incorrect: not ID"); return 0; } packet = (pwd_id_packet_t *) in; if (in_len < sizeof(*packet)) { RDEBUG("Packet is too small (%zd < %zd).", in_len, sizeof(*packet)); return 0; } if ((packet->prf != EAP_PWD_DEF_PRF) || (packet->random_function != EAP_PWD_DEF_RAND_FUN) || (packet->prep != EAP_PWD_PREP_NONE) || (CRYPTO_memcmp(packet->token, &session->token, 4)) || (packet->group_num != ntohs(session->group_num))) { RDEBUG2("pwd id response is invalid"); return 0; } /* * we've agreed on the ciphersuite, record it... */ ptr = (uint8_t *)&session->ciphersuite; memcpy(ptr, (char *)&packet->group_num, sizeof(uint16_t)); ptr += sizeof(uint16_t); *ptr = EAP_PWD_DEF_RAND_FUN; ptr += sizeof(uint8_t); *ptr = EAP_PWD_DEF_PRF; session->peer_id_len = in_len - sizeof(pwd_id_packet_t); if (session->peer_id_len >= sizeof(session->peer_id)) { RDEBUG2("pwd id response is malformed"); return 0; } memcpy(session->peer_id, packet->identity, session->peer_id_len); session->peer_id[session->peer_id_len] = '\0'; /* * make fake request to get the password for the usable ID */ if ((fake = request_alloc_fake(handler->request)) == NULL) { RDEBUG("pwd unable to create fake request!"); return 0; } fake->username = fr_pair_afrom_num(fake->packet, PW_USER_NAME, 0); if (!fake->username) { RDEBUG("Failed creating pair for peer id"); talloc_free(fake); return 0; } fr_pair_value_bstrncpy(fake->username, session->peer_id, session->peer_id_len); fr_pair_add(&fake->packet->vps, fake->username); if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) { fake->server = vp->vp_strvalue; } else if (inst->virtual_server) { fake->server = inst->virtual_server; } /* else fake->server == request->server */ RDEBUG("Sending tunneled request"); rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL); if (fake->server) { RDEBUG("server %s {", fake->server); } else { RDEBUG("server {"); } /* * Call authorization recursively, which will * get the password. */ RINDENT(); process_authorize(0, fake); REXDENT(); /* * Note that we don't do *anything* with the reply * attributes. */ if (fake->server) { RDEBUG("} # server %s", fake->server); } else { RDEBUG("}"); } RDEBUG("Got tunneled reply code %d", fake->reply->code); rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL); if ((pw = fr_pair_find_by_num(fake->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL) { DEBUG2("failed to find password for %s to do pwd authentication", session->peer_id); talloc_free(fake); return 0; } if (compute_password_element(session, session->group_num, pw->data.strvalue, strlen(pw->data.strvalue), inst->server_id, strlen(inst->server_id), session->peer_id, strlen(session->peer_id), &session->token)) { DEBUG2("failed to obtain password element"); talloc_free(fake); return 0; } TALLOC_FREE(fake); /* * compute our scalar and element */ if (compute_scalar_element(session, inst->bnctx)) { DEBUG2("failed to compute server's scalar and element"); return 0; } MEM(x = BN_new()); MEM(y = BN_new()); /* * element is a point, get both coordinates: x and y */ if (!EC_POINT_get_affine_coordinates_GFp(session->group, session->my_element, x, y, inst->bnctx)) { DEBUG2("server point assignment failed"); BN_clear_free(x); BN_clear_free(y); return 0; } /* * construct request */ session->out_len = BN_num_bytes(session->order) + (2 * BN_num_bytes(session->prime)); if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) { return 0; } memset(session->out, 0, session->out_len); ptr = session->out; offset = BN_num_bytes(session->prime) - BN_num_bytes(x); BN_bn2bin(x, ptr + offset); BN_clear_free(x); ptr += BN_num_bytes(session->prime); offset = BN_num_bytes(session->prime) - BN_num_bytes(y); BN_bn2bin(y, ptr + offset); BN_clear_free(y); ptr += BN_num_bytes(session->prime); offset = BN_num_bytes(session->order) - BN_num_bytes(session->my_scalar); BN_bn2bin(session->my_scalar, ptr + offset); session->state = PWD_STATE_COMMIT; ret = send_pwd_request(session, eap_ds); } break; case PWD_STATE_COMMIT: if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_COMMIT) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } /* * process the peer's commit and generate the shared key, k */ if (process_peer_commit(session, in, in_len, inst->bnctx)) { RDEBUG2("failed to process peer's commit"); return 0; } /* * compute our confirm blob */ if (compute_server_confirm(session, session->my_confirm, inst->bnctx)) { ERROR("rlm_eap_pwd: failed to compute confirm!"); return 0; } /* * construct a response...which is just our confirm blob */ session->out_len = SHA256_DIGEST_LENGTH; if ((session->out = talloc_array(session, uint8_t, session->out_len)) == NULL) { return 0; } memset(session->out, 0, session->out_len); memcpy(session->out, session->my_confirm, SHA256_DIGEST_LENGTH); session->state = PWD_STATE_CONFIRM; ret = send_pwd_request(session, eap_ds); break; case PWD_STATE_CONFIRM: if (in_len < SHA256_DIGEST_LENGTH) { RDEBUG("Peer confirm is too short (%zd < %d)", in_len, SHA256_DIGEST_LENGTH); return 0; } if (EAP_PWD_GET_EXCHANGE(hdr) != EAP_PWD_EXCH_CONFIRM) { RDEBUG2("pwd exchange is incorrect: not commit!"); return 0; } if (compute_peer_confirm(session, peer_confirm, inst->bnctx)) { RDEBUG2("pwd exchange cannot compute peer's confirm"); return 0; } if (CRYPTO_memcmp(peer_confirm, in, SHA256_DIGEST_LENGTH)) { RDEBUG2("pwd exchange fails: peer confirm is incorrect!"); return 0; } if (compute_keys(session, peer_confirm, msk, emsk)) { RDEBUG2("pwd exchange cannot generate (E)MSK!"); return 0; } eap_ds->request->code = PW_EAP_SUCCESS; /* * return the MSK (in halves) */ eap_add_reply(handler->request, "MS-MPPE-Recv-Key", msk, MPPE_KEY_LEN); eap_add_reply(handler->request, "MS-MPPE-Send-Key", msk + MPPE_KEY_LEN, MPPE_KEY_LEN); ret = 1; break; default: RDEBUG2("unknown PWD state"); return 0; } /* * we processed the buffered fragments, get rid of them */ if (session->in) { talloc_free(session->in); session->in = NULL; } return ret; }
static int eap_pwd_initiate (void *type_data, EAP_HANDLER *handler) { pwd_session_t *pwd_session; eap_pwd_t *inst = (eap_pwd_t *)type_data; VALUE_PAIR *vp; pwd_id_packet *pack; if ((inst == NULL) || (handler == NULL)) { radlog(L_ERR, "rlm_eap_pwd: initiate, NULL data provided"); return -1; } if ((pwd_session = (pwd_session_t *)malloc(sizeof(*pwd_session))) == NULL) { radlog(L_ERR, "rlm_eap_pwd: initiate, out of memory (1)"); return -1; } /* * set things up so they can be free'd reliably */ pwd_session->group_num = inst->conf->group; pwd_session->private_value = NULL; pwd_session->peer_scalar = NULL; pwd_session->my_scalar = NULL; pwd_session->k = NULL; pwd_session->my_element = NULL; pwd_session->peer_element = NULL; pwd_session->group = NULL; pwd_session->pwe = NULL; pwd_session->order = NULL; pwd_session->prime = NULL; /* * figure out the MTU (basically do what eap-tls does) */ pwd_session->mtu = inst->conf->fragment_size; vp = pairfind(handler->request->packet->vps, PW_FRAMED_MTU, 0); if (vp && ((int)(vp->vp_integer - 9) < pwd_session->mtu)) { /* * 9 = 4 (EAPOL header) + 4 (EAP header) + 1 (EAP type) * * the fragmentation code deals with the included length * so we don't need to subtract that here. */ pwd_session->mtu = vp->vp_integer - 9; } pwd_session->state = PWD_STATE_ID_REQ; pwd_session->in_buf = NULL; pwd_session->out_buf_pos = 0; handler->opaque = pwd_session; handler->free_opaque = free_session; /* * construct an EAP-pwd-ID/Request */ pwd_session->out_buf_len = sizeof(pwd_id_packet) + strlen(inst->conf->server_id); if ((pwd_session->out_buf = malloc(pwd_session->out_buf_len)) == NULL) { radlog(L_ERR, "rlm_eap_pwd: initiate, out of memory to send ID request"); return -1; } memset(pwd_session->out_buf, 0, pwd_session->out_buf_len); pack = (pwd_id_packet *)pwd_session->out_buf; pack->group_num = htons(pwd_session->group_num); pack->random_function = EAP_PWD_DEF_RAND_FUN; pack->prf = EAP_PWD_DEF_PRF; pwd_session->token = random(); memcpy(pack->token, (char *)&pwd_session->token, 4); pack->prep = EAP_PWD_PREP_NONE; strcpy(pack->identity, inst->conf->server_id); handler->stage = AUTHENTICATE; return send_pwd_request(pwd_session, handler->eap_ds); }