34 RCSID(
"$Id: 9740e025e6fdc50972e5ce7ba8efbe8b96574f6c $")
37 #include "rlm_eap_pwd.h"
41 #define MPPE_KEY_LEN 32
42 #define MSK_EMSK_LEN (2*MPPE_KEY_LEN)
67 *instance = inst = talloc_zero(cs,
eap_pwd_t);
77 if ((inst->
bnctx = BN_CTX_new()) == NULL) {
90 BN_clear_free(session->
k);
93 EC_GROUP_free(session->
group);
94 EC_POINT_clear_free(session->
pwe);
95 BN_clear_free(session->
order);
96 BN_clear_free(session->
prime);
115 switch (session->
state) {
129 ERROR(
"rlm_eap_pwd: PWD state is invalid. Can't send request");
144 totlen = ntohs(session->
out_len);
145 memcpy(hdr->data, (
char *)&totlen,
sizeof(totlen));
146 memcpy(hdr->data +
sizeof(uint16_t),
148 session->
mtu -
sizeof(pwd_hdr) -
sizeof(uint16_t));
149 session->
out_pos += (session->
mtu -
sizeof(pwd_hdr) -
sizeof(uint16_t));
154 memcpy(hdr->data, session->
out + session->
out_pos, (session->
mtu -
sizeof(pwd_hdr)));
155 session->
out_pos += (session->
mtu -
sizeof(pwd_hdr));
162 memcpy(hdr->data, session->
out + session->
out_pos,
164 talloc_free(session->
out);
178 pwd_id_packet_t *packet;
180 if (!inst || !eap_session) {
181 ERROR(
"rlm_eap_pwd: Initiate, NULL data provided");
189 ERROR(
"rlm_eap_pwd: Server ID is not configured");
192 switch (inst->
group) {
201 ERROR(
"rlm_eap_pwd: Group is not supported");
205 if ((session = talloc_zero(eap_session,
pwd_session_t)) == NULL)
return 0;
217 session->
group = NULL;
219 session->
order = NULL;
220 session->
prime = NULL;
237 if (vp && (vp->vp_integer > 100) && (vp->vp_integer < session->
mtu)) {
238 session->
mtu = vp->vp_integer - 9;
244 eap_session->opaque = session;
250 if ((session->
out = talloc_zero_array(session, uint8_t, session->
out_len)) == NULL)
return 0;
252 packet = (pwd_id_packet_t *)session->
out;
253 packet->group_num = htons(session->
group_num);
257 memcpy(packet->token, (
char *)&session->
token, 4);
259 memcpy(packet->identity, inst->
server_id, session->
out_len -
sizeof(pwd_id_packet_t) );
272 pwd_id_packet_t *packet;
282 uint8_t peer_confirm[SHA256_DIGEST_LENGTH];
283 BIGNUM *x = NULL, *y = NULL;
285 if (((eap_round = eap_session->
this_round) == NULL) || !
inst)
return 0;
288 request = eap_session->
request;
290 hdr = (pwd_hdr *)response->
type.
data;
295 if (!hdr || (response->
type.
length <
sizeof(pwd_hdr))) {
296 RDEBUG(
"Packet with insufficient data");
301 in_len = response->
type.
length -
sizeof(pwd_hdr);
307 if (in_len)
RDEBUG2(
"pwd got something more than an ACK for a fragment");
318 RDEBUG2(
"pwd already alloced buffer for fragments");
323 RDEBUG(
"Invalid packet: length bit set, but no length field");
327 session->
in_len = ntohs(in[0] * 256 | in[1]);
328 if ((session->
in = talloc_zero_array(session, uint8_t, session->
in_len)) == NULL) {
329 RDEBUG2(
"pwd cannot allocate %zd buffer to hold fragments", session->
in_len);
333 memset(session->
in, 0, session->
in_len);
335 in +=
sizeof(uint16_t);
336 in_len -=
sizeof(uint16_t);
347 RDEBUG2(
"Fragment overflows packet.");
351 memcpy(session->
in + session->
in_pos, in, in_len);
352 session->
in_pos += in_len;
362 if ((eap_round->
request->
type.
data = talloc_array(eap_round->
request, uint8_t,
sizeof(pwd_hdr))) == NULL) {
376 RDEBUG2(
"pwd will not overflow a fragment buffer. Nope, not prudent");
379 memcpy(session->
in + session->
in_pos, in, in_len);
384 switch (session->
state) {
387 RDEBUG2(
"pwd exchange is incorrect: not ID");
391 packet = (pwd_id_packet_t *) in;
392 if (in_len <
sizeof(packet)) {
393 RDEBUG(
"Packet is too small (%zd < %zd).", in_len,
sizeof(packet));
400 (CRYPTO_memcmp(packet->token, &session->
token, 4)) ||
401 (packet->group_num != ntohs(session->
group_num))) {
402 RDEBUG2(
"pwd id response is invalid");
409 memcpy(ptr, (
char *)&packet->group_num,
sizeof(uint16_t));
410 ptr +=
sizeof(uint16_t);
412 ptr +=
sizeof(uint8_t);
415 session->
peer_id_len = in_len -
sizeof(pwd_id_packet_t);
417 RDEBUG2(
"pwd id response is malformed");
428 RDEBUG(
"pwd unable to create fake request!");
433 RDEBUG(
"Failed creating pair for peer id");
441 fake->
server = vp->vp_strvalue;
446 RDEBUG(
"Sending tunneled request");
477 DEBUG2(
"failed to find password for %s to do pwd authentication", session->
peer_id);
483 pw->
data.strvalue, strlen(pw->
data.strvalue),
487 DEBUG2(
"failed to obtain password element");
497 DEBUG2(
"failed to compute server's scalar and element");
501 if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) {
502 DEBUG2(
"server point allocation failed");
509 if (!EC_POINT_get_affine_coordinates_GFp(session->
group, session->
my_element, x, y, inst->
bnctx)) {
510 DEBUG2(
"server point assignment failed");
519 session->
out_len = BN_num_bytes(session->
order) + (2 * BN_num_bytes(session->
prime));
520 if ((session->
out = talloc_array(session, uint8_t, session->
out_len)) == NULL) {
526 offset = BN_num_bytes(session->
prime) - BN_num_bytes(x);
527 BN_bn2bin(x, ptr + offset);
529 ptr += BN_num_bytes(session->
prime);
530 offset = BN_num_bytes(session->
prime) - BN_num_bytes(y);
531 BN_bn2bin(y, ptr + offset);
533 ptr += BN_num_bytes(session->
prime);
534 offset = BN_num_bytes(session->
order) - BN_num_bytes(session->
my_scalar);
535 BN_bn2bin(session->
my_scalar, ptr + offset);
543 RDEBUG2(
"pwd exchange is incorrect: not commit!");
551 RDEBUG2(
"failed to process peer's commit");
559 ERROR(
"rlm_eap_pwd: failed to compute confirm!");
566 session->
out_len = SHA256_DIGEST_LENGTH;
567 if ((session->
out = talloc_array(session, uint8_t, session->
out_len)) == NULL)
return 0;
570 memcpy(session->
out, session->
my_confirm, SHA256_DIGEST_LENGTH);
577 if (in_len < SHA256_DIGEST_LENGTH) {
578 RDEBUG(
"Peer confirm is too short (%zd < %d)", in_len, SHA256_DIGEST_LENGTH);
583 RDEBUG2(
"pwd exchange is incorrect: not commit!");
587 RDEBUG2(
"pwd exchange cannot compute peer's confirm");
590 if (CRYPTO_memcmp(peer_confirm, in, SHA256_DIGEST_LENGTH)) {
591 RDEBUG2(
"pwd exchange fails: peer confirm is incorrect!");
595 RDEBUG2(
"pwd exchange cannot generate (E)MSK!");
618 talloc_free(session->
in);
#define EAP_PWD_SET_EXCHANGE(x, y)
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
#define RINDENT()
Indent R* messages by one level.
rlm_rcode_t process_authorize(int type, REQUEST *request)
static int _free_pwd_session(pwd_session_t *session)
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
uint32_t fr_rand(void)
Return a 32-bit random number.
static int mod_instantiate(CONF_SECTION *cs, void **instance)
#define EAP_PWD_GET_LENGTH_BIT(x)
int process_peer_commit(pwd_session_t *session, uint8_t *in, size_t in_len, BN_CTX *bnctx)
VALUE_PAIR * username
Cached username VALUE_PAIR from request RADIUS_PACKET.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define CONF_PARSER_TERMINATOR
int compute_scalar_element(pwd_session_t *session, BN_CTX *bnctx)
static int mod_process(void *arg, eap_session_t *eap_session)
int compute_password_element(pwd_session_t *session, uint16_t grp_num, char const *password, int password_len, char const *id_server, int id_server_len, char const *id_peer, int id_peer_len, uint32_t *token)
int compute_keys(pwd_session_t *session, uint8_t *peer_confirm, uint8_t *msk, uint8_t *emsk)
eap_packet_t * request
Packet we will send to the peer.
void * opaque
Opaque data used by EAP methods.
#define EAP_PWD_GET_MORE_BIT(x)
#define EAP_PWD_SET_MORE_BIT(x)
REQUEST * request_alloc_fake(REQUEST *oldreq)
Defines a CONF_PAIR to C data type mapping.
REQUEST * request
Request that contains the response we're processing.
static int mod_session_init(void *instance, eap_session_t *eap_session)
int compute_peer_confirm(pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
#define PWD_STATE_CONFIRM
#define EAP_PWD_PREP_NONE
Highest priority debug messages (-x).
char peer_id[MAX_STRING_LEN]
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Tracks the progress of a single session of any EAP method.
int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables)
Parse a configuration section into user-supplied variables.
unsigned int code
Packet code (type).
eap_round_t * this_round
The EAP response we're processing, and the EAP request we're building.
uint8_t my_confirm[SHA256_DIGEST_LENGTH]
Stores an attribute, a value and various bits of other data.
RADIUS_PACKET * reply
Outgoing response.
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
static int CC_HINT(nonnull)
#define REXDENT()
Exdent (unindent) R* messages by one level.
static int mod_detach(void *arg)
Contains a pair of request and response packets.
char const * name
The name of the sub-module (without rlm_ prefix).
int compute_server_confirm(pwd_session_t *session, uint8_t *out, BN_CTX *bnctx)
void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of VALUE_PAIRs.
#define EAP_PWD_GET_EXCHANGE(x)
Interface to call EAP sub mdoules.
#define FR_CONF_OFFSET(_n, _t, _s, _f)
#define EAP_PWD_EXCH_CONFIRM
RADIUS_PACKET * packet
Incoming request.
#define EAP_PWD_EXCH_COMMIT
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
static CONF_PARSER pwd_module_config[]
#define EAP_PWD_DEF_RAND_FUN
Structure to hold EAP data.
static int send_pwd_request(pwd_session_t *session, eap_round_t *eap_round)
void fr_pair_value_bstrncpy(VALUE_PAIR *vp, void const *src, size_t len)
Copy data into an "string" data type.
eap_packet_t * response
Packet we received from the peer.
String of printable characters.
#define EAP_PWD_SET_LENGTH_BIT(x)
rlm_eap_module_t rlm_eap_pwd
void eap_add_reply(REQUEST *request, char const *name, uint8_t const *value, int len)
#define USES_APPLE_DEPRECATED_API
char const * virtual_server