6 * Copyright (C) 2008 Alan DeKok <aland@networkradius.com>
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
11 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
12 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
14 * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
18 #include <freeradius-devel/ident.h>
21 #include <freeradius-devel/radiusd.h>
22 #include <freeradius-devel/modules.h>
25 * FIXME: Add check for this header to configure.in
27 #include <openssl/hmac.h>
30 * FIXME: Fix the build system to create definitions from names.
32 typedef struct rlm_wimax_t {
37 * A mapping of configuration file names to internal variables.
39 * Note that the string is dynamically allocated, so it MUST
40 * be freed. When the configuration file parse re-reads the string,
41 * it free's the old one, and strdup's the new one, placing the pointer
42 * to the strdup'd string into 'config.string'. This gets around
45 static const CONF_PARSER module_config[] = {
46 { "delete_mppe_keys", PW_TYPE_BOOLEAN,
47 offsetof(rlm_wimax_t,delete_mppe_keys), NULL, "no" },
49 { NULL, -1, 0, NULL, NULL } /* end the list */
54 * Only free memory we allocated. The strings allocated via
55 * cf_section_parse() do not need to be freed.
57 static int wimax_detach(void *instance)
64 * Do any per-module initialization that is separate to each
65 * configured instance of the module. e.g. set up connections
66 * to external databases, read configuration files, set up
67 * dictionary entries, etc.
69 * If configuration information is given in the config section
70 * that must be referenced in later calls, store a handle to it
71 * in *instance otherwise put a null pointer there.
73 static int wimax_instantiate(CONF_SECTION *conf, void **instance)
78 * Set up a storage area for instance data
80 inst = rad_malloc(sizeof(*inst));
84 memset(inst, 0, sizeof(*inst));
87 * If the configuration parameters can't be parsed, then
90 if (cf_section_parse(conf, inst, module_config) < 0) {
101 * Find the named user in this modules database. Create the set
102 * of attribute-value pairs to check and reply with for this user
103 * from the database. The authentication code only needs to check
104 * the password, the rest is done here.
106 static int wimax_authorize(void *instance, REQUEST *request)
110 /* quiet the compiler */
115 * Fix Calling-Station-Id. Damn you, WiMAX!
117 vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID, 0);
118 if (vp && (vp->length == 6)) {
122 memcpy(buffer, vp->vp_octets, 6);
125 * RFC 3580 Section 3.20 says this is the preferred
126 * format. Everyone *SANE* is using this format,
129 for (i = 0; i < 6; i++) {
130 fr_bin2hex(&buffer[i], &vp->vp_strvalue[i * 3], 1);
131 vp->vp_strvalue[(i * 3) + 2] = '-';
134 vp->vp_strvalue[(5*3)+2] = '\0';
135 vp->length = (5*3)+2;
137 DEBUG2("rlm_wimax: Fixing WiMAX binary Calling-Station-Id to %s",
141 return RLM_MODULE_OK;
146 * Massage the request before recording it or proxying it
148 static int wimax_preacct(void *instance, REQUEST *request)
150 return wimax_authorize(instance, request);
154 * Write accounting information to this modules database.
156 static int wimax_accounting(void *instance, REQUEST *request)
158 /* quiet the compiler */
162 return RLM_MODULE_OK;
166 * Generate the keys after the user has been authenticated.
168 static int wimax_postauth(void *instance, REQUEST *request)
170 rlm_wimax_t *inst = instance;
171 VALUE_PAIR *msk, *emsk, *vp;
172 VALUE_PAIR *mn_nai, *ip, *fa_rk;
174 unsigned int rk1_len, rk2_len, rk_len;
175 int rk_lifetime = 3600; /* ? */
177 uint8_t usage_data[24];
178 uint8_t mip_rk_1[EVP_MAX_MD_SIZE], mip_rk_2[EVP_MAX_MD_SIZE];
179 uint8_t mip_rk[2 * EVP_MAX_MD_SIZE];
181 msk = pairfind(request->reply->vps, 1129, 0);
182 emsk = pairfind(request->reply->vps, 1130, 0);
184 RDEBUG("No EAP-MSK or EAP-EMSK. Cannot create WiMAX keys.");
185 return RLM_MODULE_NOOP;
189 * If we delete the MS-MPPE-*-Key attributes, then add in
190 * the WiMAX-MSK so that the client has a key available.
192 if (inst->delete_mppe_keys) {
193 pairdelete(&request->reply->vps, 16, VENDORPEC_MICROSOFT);
194 pairdelete(&request->reply->vps, 17, VENDORPEC_MICROSOFT);
196 vp = radius_pairmake(request, &request->reply->vps, "WiMAX-MSK", "0x00", T_OP_EQ);
198 memcpy(vp->vp_octets, msk->vp_octets, msk->length);
199 vp->length = msk->length;
204 * Initialize usage data.
206 memcpy(usage_data, "miprk@wimaxforum.org", 21); /* with trailing \0 */
207 usage_data[21] = 0x02;
208 usage_data[22] = 0x00;
209 usage_data[23] = 0x01;
212 * MIP-RK-1 = HMAC-SSHA256(EMSK, usage-data | 0x01)
214 HMAC_CTX_init(&hmac);
215 HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);
217 HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
218 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
221 * MIP-RK-2 = HMAC-SSHA256(EMSK, MIP-RK-1 | usage-data | 0x01)
223 HMAC_CTX_init(&hmac);
224 HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);
226 HMAC_Update(&hmac, (const uint8_t *) &mip_rk_1, rk1_len);
227 HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
228 HMAC_Final(&hmac, &mip_rk_2[0], &rk2_len);
230 vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT, 0);
231 if (vp) rk_lifetime = vp->vp_integer;
233 memcpy(mip_rk, mip_rk_1, rk1_len);
234 memcpy(mip_rk + rk1_len, mip_rk_2, rk2_len);
235 rk_len = rk1_len + rk2_len;
238 * MIP-SPI = HMAC-SSHA256(MIP-RK, "SPI CMIP PMIP");
240 HMAC_CTX_init(&hmac);
241 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha256(), NULL);
243 HMAC_Update(&hmac, (const uint8_t *) "SPI CMIP PMIP", 12);
244 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
247 * Take the 4 most significant octets.
248 * If less than 256, add 256.
250 mip_spi = ((mip_rk_1[0] << 24) | (mip_rk_1[1] << 16) |
251 (mip_rk_1[2] << 8) | mip_rk_1[3]);
252 if (mip_spi < 256) mip_spi += 256;
258 if (len > 128) len = 128; /* buffer size */
260 fr_bin2hex(mip_rk, buffer, len);
261 radlog_request(L_DBG, 0, request, "MIP-RK = 0x%s", buffer);
262 radlog_request(L_DBG, 0, request, "MIP-SPI = %08x",
267 * FIXME: Perform SPI collision prevention
271 * Calculate mobility keys
273 mn_nai = pairfind(request->packet->vps, 1900, 0);
274 if (!mn_nai) mn_nai = pairfind(request->reply->vps, 1900, 0);
276 RDEBUG("WARNING: WiMAX-MN-NAI was not found in the request or in the reply.");
277 RDEBUG("WARNING: We cannot calculate MN-HA keys.");
281 * WiMAX-IP-Technology
284 if (mn_nai) vp = pairfind(request->reply->vps, 23, VENDORPEC_WIMAX);
286 RDEBUG("WARNING: WiMAX-IP-Technology not found in reply.");
287 RDEBUG("WARNING: Not calculating MN-HA keys");
290 if (vp) switch (vp->vp_integer) {
293 * Look for WiMAX-hHA-IP-MIP4
295 ip = pairfind(request->reply->vps, 6, VENDORPEC_WIMAX);
297 RDEBUG("WARNING: WiMAX-hHA-IP-MIP4 not found. Cannot calculate MN-HA-PMIP4 key");
303 * H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI);
305 HMAC_CTX_init(&hmac);
306 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
308 HMAC_Update(&hmac, (const uint8_t *) "PMIP4 MN HA", 11);
309 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
310 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
311 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
314 * Put MN-HA-PMIP4 into WiMAX-MN-hHA-MIP4-Key
316 vp = pairfind(request->reply->vps, 10, VENDORPEC_WIMAX);
318 vp = radius_paircreate(request, &request->reply->vps,
319 10, VENDORPEC_WIMAX, PW_TYPE_OCTETS);
322 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-Key");
325 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
326 vp->length = rk1_len;
329 * Put MN-HA-PMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
331 vp = pairfind(request->reply->vps, 11, VENDORPEC_WIMAX);
333 vp = radius_paircreate(request, &request->reply->vps,
334 11, VENDORPEC_WIMAX, PW_TYPE_INTEGER);
337 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-SPI");
340 vp->vp_integer = mip_spi + 1;
345 * Look for WiMAX-hHA-IP-MIP4
347 ip = pairfind(request->reply->vps, 6, VENDORPEC_WIMAX);
349 RDEBUG("WARNING: WiMAX-hHA-IP-MIP4 not found. Cannot calculate MN-HA-CMIP4 key");
355 * H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI);
357 HMAC_CTX_init(&hmac);
358 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
360 HMAC_Update(&hmac, (const uint8_t *) "CMIP4 MN HA", 11);
361 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
362 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
363 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
366 * Put MN-HA-CMIP4 into WiMAX-MN-hHA-MIP4-Key
368 vp = pairfind(request->reply->vps, 10, VENDORPEC_WIMAX);
370 vp = radius_paircreate(request, &request->reply->vps,
371 10, VENDORPEC_WIMAX, PW_TYPE_OCTETS);
374 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-Key");
377 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
378 vp->length = rk1_len;
381 * Put MN-HA-CMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
383 vp = pairfind(request->reply->vps, 11, VENDORPEC_WIMAX);
385 vp = radius_paircreate(request, &request->reply->vps,
386 11, VENDORPEC_WIMAX, PW_TYPE_INTEGER);
389 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-SPI");
392 vp->vp_integer = mip_spi;
397 * Look for WiMAX-hHA-IP-MIP6
399 ip = pairfind(request->reply->vps, 7, VENDORPEC_WIMAX);
401 RDEBUG("WARNING: WiMAX-hHA-IP-MIP6 not found. Cannot calculate MN-HA-CMIP6 key");
407 * H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI);
409 HMAC_CTX_init(&hmac);
410 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
412 HMAC_Update(&hmac, (const uint8_t *) "CMIP6 MN HA", 11);
413 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipv6addr, 16);
414 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
415 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
418 * Put MN-HA-CMIP6 into WiMAX-MN-hHA-MIP6-Key
420 vp = pairfind(request->reply->vps, 12, VENDORPEC_WIMAX);
422 vp = radius_paircreate(request, &request->reply->vps,
423 12, VENDORPEC_WIMAX, PW_TYPE_OCTETS);
426 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP6-Key");
429 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
430 vp->length = rk1_len;
433 * Put MN-HA-CMIP6-SPI into WiMAX-MN-hHA-MIP6-SPI
435 vp = pairfind(request->reply->vps, 13, VENDORPEC_WIMAX);
437 vp = radius_paircreate(request, &request->reply->vps,
438 13, VENDORPEC_WIMAX, PW_TYPE_INTEGER);
441 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP6-SPI");
444 vp->vp_integer = mip_spi + 2;
448 break; /* do nothing */
452 * Generate FA-RK, if requested.
454 * FA-RK= H(MIP-RK, "FA-RK")
456 fa_rk = pairfind(request->reply->vps, 14, VENDORPEC_WIMAX);
457 if (fa_rk && (fa_rk->length <= 1)) {
458 HMAC_CTX_init(&hmac);
459 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
461 HMAC_Update(&hmac, (const uint8_t *) "FA-RK", 5);
463 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
465 memcpy(fa_rk->vp_octets, &mip_rk_1[0], rk1_len);
466 fa_rk->length = rk1_len;
470 * Create FA-RK-SPI, which is really SPI-CMIP4, which is
471 * really MIP-SPI. Clear? Of course. This is WiMAX.
474 vp = pairfind(request->reply->vps, 61, VENDORPEC_WIMAX);
476 vp = radius_paircreate(request, &request->reply->vps,
477 61, VENDORPEC_WIMAX, PW_TYPE_INTEGER);
480 RDEBUG("WARNING: Failed creating WiMAX-FA-RK-SPI");
482 vp->vp_integer = mip_spi;
487 * Generate MN-FA = H(FA-RK, "MN FA" | FA-IP | MN-NAI)
489 ip = pairfind(request->reply->vps, 1901, 0);
490 if (fa_rk && ip && mn_nai) {
491 HMAC_CTX_init(&hmac);
492 HMAC_Init_ex(&hmac, fa_rk->vp_octets, fa_rk->length,
495 HMAC_Update(&hmac, (const uint8_t *) "MN FA", 5);
496 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
497 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
499 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
501 vp = radius_paircreate(request, &request->reply->vps,
502 1902, 0, PW_TYPE_OCTETS);
504 RDEBUG("WARNING: Failed creating WiMAX-MN-FA");
506 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
507 vp->length = rk1_len;
512 * Give additional information about requests && responses
514 * WiMAX-RRQ-MN-HA-SPI
516 vp = pairfind(request->packet->vps, 20, VENDORPEC_WIMAX);
518 RDEBUG("Client requested MN-HA key: Should use SPI to look up key from storage.");
520 RDEBUG("WARNING: MN-NAI was not found!");
526 if (!pairfind(request->packet->vps, 18, VENDORPEC_WIMAX)) {
527 RDEBUG("WARNING: HA-IP was not found!");
532 * WiMAX-HA-RK-Key-Requested
534 vp = pairfind(request->packet->vps, 58, VENDORPEC_WIMAX);
535 if (vp && (vp->vp_integer == 1)) {
536 RDEBUG("Client requested HA-RK: Should use IP to look it up from storage.");
541 * Wipe the context of all sensitive information.
543 HMAC_CTX_cleanup(&hmac);
545 return RLM_MODULE_UPDATED;
550 * The module name should be the only globally exported symbol.
551 * That is, everything else should be 'static'.
553 * If the module needs to temporarily modify it's instantiation
554 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
555 * The server will then take care of ensuring that the module
556 * is single-threaded.
558 module_t rlm_wimax = {
561 RLM_TYPE_THREAD_SAFE, /* type */
562 wimax_instantiate, /* instantiation */
563 wimax_detach, /* detach */
565 NULL, /* authentication */
566 wimax_authorize, /* authorization */
567 wimax_preacct, /* preaccounting */
568 wimax_accounting, /* accounting */
569 NULL, /* checksimul */
570 NULL, /* pre-proxy */
571 NULL, /* post-proxy */
572 wimax_postauth /* post-auth */