static int eap_sim_sendstart(eap_handler_t *handler) { VALUE_PAIR **vps, *newvp; uint16_t words[3]; eap_sim_state_t *ess; RADIUS_PACKET *packet; uint8_t *p; rad_assert(handler->request != NULL); rad_assert(handler->request->reply); ess = (eap_sim_state_t *)handler->opaque; /* these are the outgoing attributes */ packet = handler->request->reply; vps = &packet->vps; rad_assert(vps != NULL); /* * Add appropriate TLVs for the EAP things we wish to send. */ /* the version list. We support only version 1. */ words[0] = htons(sizeof(words[1])); words[1] = htons(EAP_SIM_VERSION); words[2] = 0; newvp = paircreate(packet, PW_EAP_SIM_VERSION_LIST, 0); pairmemcpy(newvp, (uint8_t const *) words, sizeof(words)); pairadd(vps, newvp); /* set the EAP_ID - new value */ newvp = paircreate(packet, PW_EAP_ID, 0); newvp->vp_integer = ess->sim_id++; pairreplace(vps, newvp); /* record it in the ess */ ess->keys.versionlistlen = 2; memcpy(ess->keys.versionlist, words + 1, ess->keys.versionlistlen); /* the ANY_ID attribute. We do not support re-auth or pseudonym */ newvp = paircreate(packet, PW_EAP_SIM_FULLAUTH_ID_REQ, 0); newvp->length = 2; newvp->vp_octets = p = talloc_array(newvp, uint8_t, 2); p[0] = 0; p[0] = 1; pairadd(vps, newvp); /* the SUBTYPE, set to start. */ newvp = paircreate(packet, PW_EAP_SIM_SUBTYPE, 0); newvp->vp_integer = EAPSIM_START; pairreplace(vps, newvp); return 1; }
static int eap_sim_sendstart(EAP_HANDLER *handler) { VALUE_PAIR **vps, *newvp; uint16_t *words; struct eap_sim_server_state *ess; rad_assert(handler->request != NULL); rad_assert(handler->request->reply); ess = (struct eap_sim_server_state *)handler->opaque; /* these are the outgoing attributes */ vps = &handler->request->reply->vps; rad_assert(vps != NULL); /* * add appropriate TLVs for the EAP things we wish to send. */ /* the version list. We support only version 1. */ newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_VERSION_LIST, 0, PW_TYPE_OCTETS); words = (uint16_t *)newvp->vp_strvalue; newvp->length = 3*sizeof(uint16_t); words[0] = htons(1*sizeof(uint16_t)); words[1] = htons(EAP_SIM_VERSION); words[2] = 0; pairadd(vps, newvp); /* set the EAP_ID - new value */ newvp = paircreate(ATTRIBUTE_EAP_ID, 0, PW_TYPE_INTEGER); newvp->vp_integer = ess->sim_id++; pairreplace(vps, newvp); /* record it in the ess */ ess->keys.versionlistlen = 2; memcpy(ess->keys.versionlist, words+1, ess->keys.versionlistlen); /* the ANY_ID attribute. We do not support re-auth or pseudonym */ newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_FULLAUTH_ID_REQ, 0, PW_TYPE_OCTETS); newvp->length = 2; newvp->vp_strvalue[0]=0; newvp->vp_strvalue[0]=1; pairadd(vps, newvp); /* the SUBTYPE, set to start. */ newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, 0, PW_TYPE_INTEGER); newvp->vp_integer = eapsim_start; pairreplace(vps, newvp); return 1; }
/* * this code sends the success message. * * the only work to be done is the add the appropriate SEND/RECV * radius attributes derived from the MSK. * */ static int eap_sim_sendsuccess(eap_handler_t *handler) { unsigned char *p; struct eap_sim_server_state *ess; VALUE_PAIR *vp; RADIUS_PACKET *packet; /* outvps is the data to the client. */ packet = handler->request->reply; ess = (struct eap_sim_server_state *)handler->opaque; /* set the EAP_ID - new value */ vp = paircreate(packet, ATTRIBUTE_EAP_ID, 0); vp->vp_integer = ess->sim_id++; pairreplace(&handler->request->reply->vps, vp); p = ess->keys.msk; eap_add_reply(handler->request, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN); p += EAPTLS_MPPE_KEY_LEN; eap_add_reply(handler->request, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN); return 1; }
/* * this code sends the success message. * * the only work to be done is the add the appropriate SEND/RECV * radius attributes derived from the MSK. * */ static int eap_sim_sendsuccess(EAP_HANDLER *handler) { unsigned char *p; struct eap_sim_server_state *ess; VALUE_PAIR **outvps; VALUE_PAIR *newvp; /* outvps is the data to the client. */ outvps= &handler->request->reply->vps; ess = (struct eap_sim_server_state *)handler->opaque; /* set the EAP_ID - new value */ newvp = paircreate(ATTRIBUTE_EAP_ID, 0, PW_TYPE_INTEGER); newvp->vp_integer = ess->sim_id++; pairreplace(outvps, newvp); p = ess->keys.msk; add_reply(outvps, "MS-MPPE-Recv-Key", p, EAPTLS_MPPE_KEY_LEN); p += EAPTLS_MPPE_KEY_LEN; add_reply(outvps, "MS-MPPE-Send-Key", p, EAPTLS_MPPE_KEY_LEN); return 1; }
/** Send the challenge itself * * Challenges will come from one of three places eventually: * * 1 from attributes like PW_EAP_SIM_RANDx * (these might be retrived 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_sim_sendchallenge(eap_handler_t *handler) { REQUEST *request = handler->request; eap_sim_state_t *ess; VALUE_PAIR **invps, **outvps, *newvp; RADIUS_PACKET *packet; uint8_t *p; ess = (eap_sim_state_t *)handler->opaque; rad_assert(handler->request != NULL); rad_assert(handler->request->reply); /* * Invps is the data from the client but this is for non-protocol data here. * We should already have consumed any client originated data. */ invps = &handler->request->packet->vps; /* * Outvps is the data to the client */ packet = handler->request->reply; outvps = &packet->vps; if (RDEBUG_ENABLED2) { RDEBUG2("EAP-SIM decoded packet:"); debug_pair_list(*invps); } /* * Okay, we got the challenges! Put them into an attribute. */ newvp = paircreate(packet, PW_EAP_SIM_RAND, 0); newvp->length = 2 + (EAPSIM_RAND_SIZE * 3); newvp->vp_octets = p = talloc_array(newvp, uint8_t, newvp->length); memset(p, 0, 2); /* clear reserved bytes */ p += 2; memcpy(p, ess->keys.rand[0], EAPSIM_RAND_SIZE); p += EAPSIM_RAND_SIZE; memcpy(p, ess->keys.rand[1], EAPSIM_RAND_SIZE); p += EAPSIM_RAND_SIZE; memcpy(p, ess->keys.rand[2], EAPSIM_RAND_SIZE); pairadd(outvps, newvp); /* * Set the EAP_ID - new value */ newvp = paircreate(packet, PW_EAP_ID, 0); newvp->vp_integer = ess->sim_id++; pairreplace(outvps, newvp); /* * Make a copy of the identity */ ess->keys.identitylen = strlen(handler->identity); memcpy(ess->keys.identity, handler->identity, ess->keys.identitylen); /* * Use the SIM identity, if available */ newvp = pairfind(*invps, PW_EAP_SIM_IDENTITY, 0, TAG_ANY); if (newvp && newvp->length > 2) { uint16_t len; memcpy(&len, newvp->vp_octets, sizeof(uint16_t)); len = ntohs(len); if (len <= newvp->length - 2 && len <= MAX_STRING_LEN) { ess->keys.identitylen = len; memcpy(ess->keys.identity, newvp->vp_octets + 2, ess->keys.identitylen); } } /* * All set, calculate keys! */ eapsim_calculate_keys(&ess->keys); #ifdef EAP_SIM_DEBUG_PRF eapsim_dump_mk(&ess->keys); #endif /* * Need to include an AT_MAC attribute so that it will get * calculated. The NONCE_MT and the MAC are both 16 bytes, so * We store the NONCE_MT in the MAC for the encoder, which * will pull it out before it does the operation. */ newvp = paircreate(packet, PW_EAP_SIM_MAC, 0); pairmemcpy(newvp, ess->keys.nonce_mt, 16); pairreplace(outvps, newvp); newvp = paircreate(packet, PW_EAP_SIM_KEY, 0); pairmemcpy(newvp, ess->keys.K_aut, 16); pairreplace(outvps, newvp); /* the SUBTYPE, set to challenge. */ newvp = paircreate(packet, PW_EAP_SIM_SUBTYPE, 0); newvp->vp_integer = EAPSIM_CHALLENGE; pairreplace(outvps, newvp); return 1; }
/* * this code sends the challenge itself. * * Challenges will come from one of three places eventually: * * 1 from attributes like ATTRIBUTE_EAP_SIM_RANDx * (these might be retrived 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_sim_sendchallenge(EAP_HANDLER *handler) { struct eap_sim_server_state *ess; VALUE_PAIR **invps, **outvps, *newvp; ess = (struct eap_sim_server_state *)handler->opaque; rad_assert(handler->request != NULL); rad_assert(handler->request->reply); /* invps is the data from the client. * but, this is for non-protocol data here. We should * already have consumed any client originated data. */ invps = &handler->request->packet->vps; /* outvps is the data to the client. */ outvps= &handler->request->reply->vps; if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, "+++> EAP-sim decoded packet:\n"); debug_pair_list(*invps); } /* okay, we got the challenges! Put them into an attribute */ newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_RAND, 0, PW_TYPE_OCTETS); memset(newvp->vp_strvalue, 0, 2); /* clear reserved bytes */ memcpy(newvp->vp_strvalue+2+EAPSIM_RAND_SIZE*0, ess->keys.rand[0], EAPSIM_RAND_SIZE); memcpy(newvp->vp_strvalue+2+EAPSIM_RAND_SIZE*1, ess->keys.rand[1], EAPSIM_RAND_SIZE); memcpy(newvp->vp_strvalue+2+EAPSIM_RAND_SIZE*2, ess->keys.rand[2], EAPSIM_RAND_SIZE); newvp->length = 2+EAPSIM_RAND_SIZE*3; pairadd(outvps, newvp); /* set the EAP_ID - new value */ newvp = paircreate(ATTRIBUTE_EAP_ID, 0, PW_TYPE_INTEGER); newvp->vp_integer = ess->sim_id++; pairreplace(outvps, newvp); /* make a copy of the identity */ ess->keys.identitylen = strlen(handler->identity); memcpy(ess->keys.identity, handler->identity, ess->keys.identitylen); /* use the SIM identity, if available */ newvp = pairfind(*invps, ATTRIBUTE_EAP_SIM_BASE + PW_EAP_SIM_IDENTITY, 0, TAG_ANY); if (newvp && newvp->length > 2) { uint16_t len; memcpy(&len, newvp->vp_octets, sizeof(uint16_t)); len = ntohs(len); if (len <= newvp->length - 2 && len <= MAX_STRING_LEN) { ess->keys.identitylen = len; memcpy(ess->keys.identity, newvp->vp_octets + 2, ess->keys.identitylen); } } /* all set, calculate keys! */ eapsim_calculate_keys(&ess->keys); #ifdef EAP_SIM_DEBUG_PRF eapsim_dump_mk(&ess->keys); #endif /* * need to include an AT_MAC attribute so that it will get * calculated. The NONCE_MT and the MAC are both 16 bytes, so * we store the NONCE_MT in the MAC for the encoder, which * will pull it out before it does the operation. */ newvp = paircreate(ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0, PW_TYPE_OCTETS); memcpy(newvp->vp_strvalue, ess->keys.nonce_mt, 16); newvp->length = 16; pairreplace(outvps, newvp); newvp = paircreate(ATTRIBUTE_EAP_SIM_KEY, 0, PW_TYPE_OCTETS); memcpy(newvp->vp_strvalue, ess->keys.K_aut, 16); newvp->length = 16; pairreplace(outvps, newvp); /* the SUBTYPE, set to challenge. */ newvp = paircreate(ATTRIBUTE_EAP_SIM_SUBTYPE, 0, PW_TYPE_INTEGER); newvp->vp_integer = eapsim_challenge; pairreplace(outvps, newvp); return 1; }
static int respond_eap_md5(RADIUS_PACKET *req, RADIUS_PACKET *rep) { VALUE_PAIR *vp, *id, *state; size_t valuesize; uint8_t identifier; uint8_t const *value; FR_MD5_CTX context; uint8_t response[16]; cleanresp(rep); if ((state = paircopy2(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no state attribute found\n"); return 0; } if ((id = paircopy2(NULL, req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no EAP-ID attribute found\n"); return 0; } identifier = id->vp_integer; if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n"); return 0; } /* got the details of the MD5 challenge */ valuesize = vp->vp_octets[0]; value = &vp->vp_octets[1]; /* sanitize items */ if(valuesize > vp->length) { fprintf(stderr, "radeapclient: md5 valuesize if too big (%u > %u)\n", (unsigned int) valuesize, (unsigned int) vp->length); return 0; } /* now do the CHAP operation ourself, rather than build the * buffer. We could also call rad_chap_encode, but it wants * a CHAP-Challenge, which we don't want to bother with. */ fr_md5_init(&context); fr_md5_update(&context, &identifier, 1); fr_md5_update(&context, (uint8_t *) password, strlen(password)); fr_md5_update(&context, value, valuesize); fr_md5_final(response, &context); { uint8_t *p; uint8_t lg_response; vp = paircreate(rep, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0); vp->length = 17; p = talloc_zero_array(vp, uint8_t, 17); lg_response = 16; memcpy(p, &lg_response, 1); memcpy(p + 1, response, 16); pairmemsteal(vp, p); } pairreplace(&(rep->vps), vp); pairreplace(&(rep->vps), id); /* copy the state object in */ pairreplace(&(rep->vps), state); return 1; }
/* * this code runs the EAP-SIM client state machine. * the *request* is from the server. * the *reponse* is to the server. * */ static int respond_eap_sim(RADIUS_PACKET *req, RADIUS_PACKET *resp) { enum eapsim_clientstates state, newstate; enum eapsim_subtype subtype; VALUE_PAIR *vp, *statevp, *radstate, *eapid; char statenamebuf[32], subtypenamebuf[32]; if ((radstate = paircopy2(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL) { return 0; } if ((eapid = paircopy2(NULL, req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) == NULL) { return 0; } /* first, dig up the state from the request packet, setting * outselves to be in EAP-SIM-Start state if there is none. */ if((statevp = pairfind(resp->vps, ATTRIBUTE_EAP_SIM_STATE, 0, TAG_ANY)) == NULL) { /* must be initial request */ statevp = paircreate(resp, ATTRIBUTE_EAP_SIM_STATE, 0); statevp->vp_integer = eapsim_client_init; pairreplace(&(resp->vps), statevp); } state = statevp->vp_integer; /* * map the attributes, and authenticate them. */ unmap_eapsim_types(req); if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL) { return 0; } subtype = vp->vp_integer; /* * look for the appropriate state, and process incoming message */ switch(state) { case eapsim_client_init: switch(subtype) { case eapsim_start: newstate = process_eap_start(req, resp); break; case eapsim_challenge: case eapsim_notification: case eapsim_reauth: default: fprintf(stderr, "radeapclient: sim in state %s message %s is illegal. Reply dropped.\n", sim_state2name(state, statenamebuf, sizeof(statenamebuf)), sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf))); /* invalid state, drop message */ return 0; } break; case eapsim_client_start: switch(subtype) { case eapsim_start: /* NOT SURE ABOUT THIS ONE, retransmit, I guess */ newstate = process_eap_start(req, resp); break; case eapsim_challenge: newstate = process_eap_challenge(req, resp); break; default: fprintf(stderr, "radeapclient: sim in state %s message %s is illegal. Reply dropped.\n", sim_state2name(state, statenamebuf, sizeof(statenamebuf)), sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf))); /* invalid state, drop message */ return 0; } break; default: fprintf(stderr, "radeapclient: sim in illegal state %s\n", sim_state2name(state, statenamebuf, sizeof(statenamebuf))); return 0; } /* copy the eap state object in */ pairreplace(&(resp->vps), eapid); /* update stete info, and send new packet */ map_eapsim_types(resp); /* copy the radius state object in */ pairreplace(&(resp->vps), radstate); statevp->vp_integer = newstate; return 1; }
/* * we got an EAP-Request/Sim/Challenge message in a legal state. * * use the RAND challenge to produce the SRES result, and then * use that to generate a new MAC. * * for the moment, we ignore the RANDs, then just plug in the SRES * values. * */ static int process_eap_challenge(RADIUS_PACKET *req, RADIUS_PACKET *rep) { VALUE_PAIR *newvp; VALUE_PAIR *mac, *randvp; VALUE_PAIR *sres1,*sres2,*sres3; VALUE_PAIR *Kc1, *Kc2, *Kc3; uint8_t calcmac[20]; /* look for the AT_MAC and the challenge data */ mac = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0, TAG_ANY); randvp= pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_RAND, 0, TAG_ANY); if(!mac || !randvp) { fprintf(stderr, "radeapclient: challenge message needs to contain RAND and MAC\n"); return 0; } /* * compare RAND with randX, to verify this is the right response * to this challenge. */ { VALUE_PAIR *randcfgvp[3]; uint8_t const *randcfg[3]; randcfg[0] = &randvp->vp_octets[2]; randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE]; randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2]; randcfgvp[0] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND1, 0, TAG_ANY); randcfgvp[1] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND2, 0, TAG_ANY); randcfgvp[2] = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_RAND3, 0, TAG_ANY); if(!randcfgvp[0] || !randcfgvp[1] || !randcfgvp[2]) { fprintf(stderr, "radeapclient: needs to have rand1, 2 and 3 set.\n"); return 0; } if(memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE)!=0 || memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE)!=0 || memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE)!=0) { int rnum,i,j; fprintf(stderr, "radeapclient: one of rand 1,2,3 didn't match\n"); for(rnum = 0; rnum < 3; rnum++) { fprintf(stderr, "received rand %d: ", rnum); j=0; for (i = 0; i < EAPSIM_RAND_SIZE; i++) { if(j==4) { printf("_"); j=0; } j++; fprintf(stderr, "%02x", randcfg[rnum][i]); } fprintf(stderr, "\nconfigured rand %d: ", rnum); j=0; for (i = 0; i < EAPSIM_RAND_SIZE; i++) { if(j==4) { printf("_"); j=0; } j++; fprintf(stderr, "%02x", randcfgvp[rnum]->vp_octets[i]); } fprintf(stderr, "\n"); } return 0; } } /* * now dig up the sres values from the response packet, * which were put there when we read things in. * * Really, they should be calculated from the RAND! * */ sres1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES1, 0, TAG_ANY); sres2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES2, 0, TAG_ANY); sres3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_SRES3, 0, TAG_ANY); if(!sres1 || !sres2 || !sres3) { fprintf(stderr, "radeapclient: needs to have sres1, 2 and 3 set.\n"); return 0; } memcpy(eapsim_mk.sres[0], sres1->vp_strvalue, sizeof(eapsim_mk.sres[0])); memcpy(eapsim_mk.sres[1], sres2->vp_strvalue, sizeof(eapsim_mk.sres[1])); memcpy(eapsim_mk.sres[2], sres3->vp_strvalue, sizeof(eapsim_mk.sres[2])); Kc1 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC1, 0, TAG_ANY); Kc2 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC2, 0, TAG_ANY); Kc3 = pairfind(rep->vps, ATTRIBUTE_EAP_SIM_KC3, 0, TAG_ANY); if(!Kc1 || !Kc2 || !Kc3) { fprintf(stderr, "radeapclient: needs to have Kc1, 2 and 3 set.\n"); return 0; } memcpy(eapsim_mk.Kc[0], Kc1->vp_strvalue, sizeof(eapsim_mk.Kc[0])); memcpy(eapsim_mk.Kc[1], Kc2->vp_strvalue, sizeof(eapsim_mk.Kc[1])); memcpy(eapsim_mk.Kc[2], Kc3->vp_strvalue, sizeof(eapsim_mk.Kc[2])); /* all set, calculate keys */ eapsim_calculate_keys(&eapsim_mk); if(debug_flag) { eapsim_dump_mk(&eapsim_mk); } /* verify the MAC, now that we have all the keys. */ if(eapsim_checkmac(NULL, req->vps, eapsim_mk.K_aut, eapsim_mk.nonce_mt, sizeof(eapsim_mk.nonce_mt), calcmac)) { printf("MAC check succeed\n"); } else { int i, j; j=0; printf("calculated MAC ("); for (i = 0; i < 20; i++) { if(j==4) { printf("_"); j=0; } j++; printf("%02x", calcmac[i]); } printf(" did not match\n"); return 0; } /* form new response clear of any EAP stuff */ cleanresp(rep); /* mark the subtype as being EAP-SIM/Response/Start */ newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_SUBTYPE, 0); newvp->vp_integer = eapsim_challenge; pairreplace(&(rep->vps), newvp); { uint8_t *p; /* * fill the SIM_MAC with a field that will in fact get appended * to the packet before the MAC is calculated */ newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC, 0); p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3); memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE); memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE); memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE); pairmemsteal(newvp, p); pairreplace(&(rep->vps), newvp); } newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_KEY, 0); pairmemcpy(newvp, eapsim_mk.K_aut, EAPSIM_AUTH_SIZE); pairreplace(&(rep->vps), newvp); return 1; }
/* * we got an EAP-Request/Sim/Start message in a legal state. * * pick a supported version, put it into the reply, and insert a nonce. */ static int process_eap_start(RADIUS_PACKET *req, RADIUS_PACKET *rep) { VALUE_PAIR *vp, *newvp; VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp; uint16_t const *versions; uint16_t selectedversion; unsigned int i,versioncount; /* form new response clear of any EAP stuff */ cleanresp(rep); if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_VERSION_LIST, 0, TAG_ANY)) == NULL) { fprintf(stderr, "illegal start message has no VERSION_LIST\n"); return 0; } versions = (uint16_t const *) vp->vp_strvalue; /* verify that the attribute length is big enough for a length field */ if(vp->length < 4) { fprintf(stderr, "start message has illegal VERSION_LIST. Too short: %u\n", (unsigned int) vp->length); return 0; } versioncount = ntohs(versions[0])/2; /* verify that the attribute length is big enough for the given number * of versions present. */ if((unsigned)vp->length <= (versioncount*2 + 2)) { fprintf(stderr, "start message is too short. Claimed %d versions does not fit in %u bytes\n", versioncount, (unsigned int) vp->length); return 0; } /* * record the versionlist for the MK calculation. */ eapsim_mk.versionlistlen = versioncount*2; memcpy(eapsim_mk.versionlist, (unsigned char const *)(versions+1), eapsim_mk.versionlistlen); /* walk the version list, and pick the one we support, which * at present, is 1, EAP_SIM_VERSION. */ selectedversion=0; for(i=0; i < versioncount; i++) { if(ntohs(versions[i+1]) == EAP_SIM_VERSION) { selectedversion=EAP_SIM_VERSION; break; } } if(selectedversion == 0) { fprintf(stderr, "eap-sim start message. No compatible version found. We need %d\n", EAP_SIM_VERSION); for(i=0; i < versioncount; i++) { fprintf(stderr, "\tfound version %d\n", ntohs(versions[i+1])); } } /* * now make sure that we have only FULLAUTH_ID_REQ. * I think that it actually might not matter - we can answer in * anyway we like, but it is illegal to have more than one * present. */ anyidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_ANY_ID_REQ, 0, TAG_ANY); fullauthidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_FULLAUTH_ID_REQ, 0, TAG_ANY); permanentidreq_vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_PERMANENT_ID_REQ, 0, TAG_ANY); if(!fullauthidreq_vp || anyidreq_vp != NULL || permanentidreq_vp != NULL) { fprintf(stderr, "start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.\n", (anyidreq_vp != NULL ? "a " : "no "), (fullauthidreq_vp != NULL ? "a " : "no "), (permanentidreq_vp != NULL ? "a " : "no ")); return 0; } /* okay, we have just any_id_req there, so fill in response */ /* mark the subtype as being EAP-SIM/Response/Start */ newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_SUBTYPE, 0); newvp->vp_integer = eapsim_start; pairreplace(&(rep->vps), newvp); /* insert selected version into response. */ { uint16_t no_versions; no_versions = htons(selectedversion); newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE + PW_EAP_SIM_SELECTED_VERSION, 0); pairmemcpy(newvp, (uint8_t *) &no_versions, 2); pairreplace(&(rep->vps), newvp); /* record the selected version */ memcpy(eapsim_mk.versionselect, &no_versions, 2); } vp = newvp = NULL; { uint32_t nonce[4]; uint8_t *p; /* * insert a nonce_mt that we make up. */ nonce[0]=fr_rand(); nonce[1]=fr_rand(); nonce[2]=fr_rand(); nonce[3]=fr_rand(); newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_NONCE_MT, 0); p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */ memcpy(&p[2], nonce, 16); pairmemsteal(newvp, p); pairreplace(&(rep->vps), newvp); /* also keep a copy of the nonce! */ memcpy(eapsim_mk.nonce_mt, nonce, 16); } { uint16_t idlen; uint8_t *p; uint16_t no_idlen; /* * insert the identity here. */ vp = pairfind(rep->vps, PW_USER_NAME, 0, TAG_ANY); if(!vp) { fprintf(stderr, "eap-sim: We need to have a User-Name attribute!\n"); return 0; } newvp = paircreate(rep, ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_IDENTITY, 0); idlen = strlen(vp->vp_strvalue); p = talloc_zero_array(newvp, uint8_t, idlen + 2); no_idlen = htons(idlen); memcpy(p, &no_idlen, 2); memcpy(p + 2, vp->vp_strvalue, idlen); pairmemsteal(newvp, p); pairreplace(&(rep->vps), newvp); /* record it */ memcpy(eapsim_mk.identity, vp->vp_strvalue, idlen); eapsim_mk.identitylen = idlen; } return 1; }
static int respond_eap_md5(RADIUS_PACKET *req, RADIUS_PACKET *rep,const char* pwd) { VALUE_PAIR *vp, *id, *state; size_t valuesize; uint8_t identifier; uint8_t *value; FR_MD5_CTX context; uint8_t response[16]; cleanresp(rep); if ((state = paircopy2(req->vps, PW_STATE)) == NULL) { fr_strerror_printf("radeapclient: no state attribute found"); return 0; } if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL) { fr_strerror_printf("radeapclient: no EAP-ID attribute found"); return 0; } identifier = id->vp_integer; if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5)) == NULL) { fr_strerror_printf("radeapclient: no EAP-MD5 attribute found"); return 0; } /* got the details of the MD5 challenge */ valuesize = vp->vp_octets[0]; value = &vp->vp_octets[1]; /* sanitize items */ if(valuesize > vp->length) { fr_strerror_printf("radeapclient: md5 valuesize if too big (%u > %u)\n", (unsigned int) valuesize, (unsigned int) vp->length); return 0; } /* now do the CHAP operation ourself, rather than build the * buffer. We could also call rad_chap_encode, but it wants * a CHAP-Challenge, which we don't want to bother with. */ fr_MD5Init(&context); fr_MD5Update(&context, &identifier, 1); fr_MD5Update(&context, (uint8_t *) pwd, strlen(pwd)); fr_MD5Update(&context, value, valuesize); fr_MD5Final(response, &context); vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS); vp->vp_octets[0]=16; memcpy(&vp->vp_strvalue[1], response, 16); vp->length = 17; pairreplace(&(rep->vps), vp); pairreplace(&(rep->vps), id); /* copy the state object in */ pairreplace(&(rep->vps), state); return 1; }
static int respond_eap_md5(RADIUS_PACKET *req, RADIUS_PACKET *rep) { VALUE_PAIR *vp, *id, *state; int valuesize, namesize; unsigned char identifier; unsigned char *value; unsigned char *name; MD5_CTX context; char response[16]; cleanresp(rep); if ((state = paircopy2(req->vps, PW_STATE)) == NULL) { fprintf(stderr, "radeapclient: no state attribute found\n"); return 0; } if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL) { fprintf(stderr, "radeapclient: no EAP-ID attribute found\n"); return 0; } identifier = id->lvalue; if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5)) == NULL) { fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n"); return 0; } /* got the details of the MD5 challenge */ valuesize = vp->strvalue[0]; value = &vp->strvalue[1]; name = &vp->strvalue[valuesize+1]; namesize = vp->length - (valuesize + 1); /* sanitize items */ if(valuesize > vp->length) { fprintf(stderr, "radeapclient: md5 valuesize if too big (%d > %d)\n", valuesize, vp->length); return 0; } /* now do the CHAP operation ourself, rather than build the * buffer. We could also call rad_chap_encode, but it wants * a CHAP-Challenge, which we don't want to bother with. */ librad_MD5Init(&context); librad_MD5Update(&context, &identifier, 1); librad_MD5Update(&context, password, strlen(password)); librad_MD5Update(&context, value, valuesize); librad_MD5Final(response, &context); vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS); vp->strvalue[0]=16; memcpy(&vp->strvalue[1], response, 16); vp->length = 17; pairreplace(&(rep->vps), vp); pairreplace(&(rep->vps), id); /* copy the state object in */ pairreplace(&(rep->vps), state); return 1; }