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 #define WIMAX2ATTR(x) ((24757 << 16) | (x))
35 * Find the named user in this modules database. Create the set
36 * of attribute-value pairs to check and reply with for this user
37 * from the database. The authentication code only needs to check
38 * the password, the rest is done here.
40 static int wimax_authorize(void *instance, REQUEST *request)
44 /* quiet the compiler */
49 * Fix Calling-Station-Id. Damn you, WiMAX!
51 vp = pairfind(request->packet->vps, PW_CALLING_STATION_ID);
52 if (vp && (vp->length == 6)) {
56 memcpy(buffer, vp->vp_octets, 6);
59 * RFC 3580 Section 3.20 says this is the preferred
60 * format. Everyone *SANE* is using this format,
63 for (i = 0; i < 6; i++) {
64 fr_bin2hex(&buffer[i], &vp->vp_strvalue[i * 3], 1);
65 vp->vp_strvalue[(i * 3) + 2] = '-';
68 vp->vp_strvalue[(5*3)+2] = '\0';
71 DEBUG2("rlm_wimax: Fixing WiMAX binary Calling-Station-Id to %s",
80 * Massage the request before recording it or proxying it
82 static int wimax_preacct(void *instance, REQUEST *request)
84 return wimax_authorize(instance, request);
88 * Write accounting information to this modules database.
90 static int wimax_accounting(void *instance, REQUEST *request)
92 /* quiet the compiler */
100 * Generate the keys after the user has been authenticated.
102 static int wimax_postauth(UNUSED void *instance, REQUEST *request)
104 VALUE_PAIR *msk, *emsk, *vp;
105 VALUE_PAIR *mn_nai, *ip, *fa_rk;
107 unsigned int rk1_len, rk2_len, rk_len;
108 int rk_lifetime = 3600; /* ? */
110 uint8_t usage_data[24];
111 uint8_t mip_rk_1[EVP_MAX_MD_SIZE], mip_rk_2[EVP_MAX_MD_SIZE];
112 uint8_t mip_rk[2 * EVP_MAX_MD_SIZE];
114 msk = pairfind(request->reply->vps, 1129);
115 emsk = pairfind(request->reply->vps, 1130);
117 RDEBUG("No EAP-MSK or EAP-EMSK. Cannot create WiMAX keys.");
118 return RLM_MODULE_NOOP;
122 * Initialize usage data.
124 memcpy(usage_data, "miprk@wimaxforum.org", 21); /* with trailing \0 */
125 usage_data[21] = 0x02;
126 usage_data[22] = 0x00;
127 usage_data[23] = 0x01;
130 * MIP-RK-1 = HMAC-SSHA256(EMSK, usage-data | 0x01)
132 HMAC_CTX_init(&hmac);
133 HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);
135 HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
136 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
139 * MIP-RK-2 = HMAC-SSHA256(EMSK, MIP-RK-1 | usage-data | 0x01)
141 HMAC_CTX_init(&hmac);
142 HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);
144 HMAC_Update(&hmac, (const uint8_t *) &mip_rk_1, rk1_len);
145 HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
146 HMAC_Final(&hmac, &mip_rk_2[0], &rk2_len);
148 vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT);
149 if (vp) rk_lifetime = vp->vp_integer;
151 memcpy(mip_rk, mip_rk_1, rk1_len);
152 memcpy(mip_rk + rk1_len, mip_rk_2, rk2_len);
153 rk_len = rk1_len + rk2_len;
156 * MIP-SPI = HMAC-SSHA256(MIP-RK, "SPI CMIP PMIP");
158 HMAC_CTX_init(&hmac);
159 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha256(), NULL);
161 HMAC_Update(&hmac, (const uint8_t *) "SPI CMIP PMIP", 12);
162 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
165 * Take the 4 most significant octets.
166 * If less than 256, add 256.
168 mip_spi = ((mip_rk_1[0] << 24) | (mip_rk_1[1] << 16) |
169 (mip_rk_1[2] << 8) | mip_rk_1[3]);
170 if (mip_spi < 256) mip_spi += 256;
176 if (len > 128) len = 128; /* buffer size */
178 fr_bin2hex(mip_rk, buffer, len);
179 radlog_request(L_DBG, 0, request, "MIP-RK = 0x%s", buffer);
180 radlog_request(L_DBG, 0, request, "MIP-SPI = %08x",
185 * FIXME: Perform SPI collision prevention
189 * Calculate mobility keys
191 mn_nai = pairfind(request->packet->vps, 1900);
192 if (!mn_nai) mn_nai = pairfind(request->reply->vps, 1900);
194 RDEBUG("WARNING: WiMAX-MN-NAI was not found in the request or in the reply.");
195 RDEBUG("WARNING: We cannot calculate MN-HA keys.");
199 * WiMAX-IP-Technology
202 if (mn_nai) vp = pairfind(request->reply->vps, WIMAX2ATTR(23));
204 RDEBUG("WARNING: WiMAX-IP-Technology not found in reply.");
205 RDEBUG("WARNING: Not calculating MN-HA keys");
208 if (vp) switch (vp->vp_integer) {
211 * Look for WiMAX-hHA-IP-MIP4
213 ip = pairfind(request->reply->vps, WIMAX2ATTR(6));
215 RDEBUG("WARNING: WiMAX-hHA-IP-MIP4 not found. Cannot calculate MN-HA-PMIP4 key");
221 * H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI);
223 HMAC_CTX_init(&hmac);
224 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
226 HMAC_Update(&hmac, (const uint8_t *) "PMIP4 MN HA", 11);
227 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
228 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
229 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
232 * Put MN-HA-PMIP4 into WiMAX-MN-hHA-MIP4-Key
234 vp = pairfind(request->reply->vps, WIMAX2ATTR(10));
236 vp = radius_paircreate(request, &request->reply->vps,
237 WIMAX2ATTR(10), PW_TYPE_OCTETS);
240 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-Key");
243 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
244 vp->length = rk1_len;
247 * Put MN-HA-PMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
249 vp = pairfind(request->reply->vps, WIMAX2ATTR(11));
251 vp = radius_paircreate(request, &request->reply->vps,
252 WIMAX2ATTR(11), PW_TYPE_INTEGER);
255 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-SPI");
258 vp->vp_integer = mip_spi + 1;
263 * Look for WiMAX-hHA-IP-MIP4
265 ip = pairfind(request->reply->vps, WIMAX2ATTR(6));
267 RDEBUG("WARNING: WiMAX-hHA-IP-MIP4 not found. Cannot calculate MN-HA-CMIP4 key");
273 * H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI);
275 HMAC_CTX_init(&hmac);
276 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
278 HMAC_Update(&hmac, (const uint8_t *) "CMIP4 MN HA", 11);
279 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
280 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
281 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
284 * Put MN-HA-CMIP4 into WiMAX-MN-hHA-MIP4-Key
286 vp = pairfind(request->reply->vps, WIMAX2ATTR(10));
288 vp = radius_paircreate(request, &request->reply->vps,
289 WIMAX2ATTR(10), PW_TYPE_OCTETS);
292 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-Key");
295 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
296 vp->length = rk1_len;
299 * Put MN-HA-CMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
301 vp = pairfind(request->reply->vps, WIMAX2ATTR(11));
303 vp = radius_paircreate(request, &request->reply->vps,
304 WIMAX2ATTR(11), PW_TYPE_INTEGER);
307 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-SPI");
310 vp->vp_integer = mip_spi;
315 * Look for WiMAX-hHA-IP-MIP6
317 ip = pairfind(request->reply->vps, WIMAX2ATTR(7));
319 RDEBUG("WARNING: WiMAX-hHA-IP-MIP6 not found. Cannot calculate MN-HA-CMIP6 key");
325 * H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI);
327 HMAC_CTX_init(&hmac);
328 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
330 HMAC_Update(&hmac, (const uint8_t *) "CMIP6 MN HA", 11);
331 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipv6addr, 16);
332 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
333 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
336 * Put MN-HA-CMIP6 into WiMAX-MN-hHA-MIP6-Key
338 vp = pairfind(request->reply->vps, WIMAX2ATTR(12));
340 vp = radius_paircreate(request, &request->reply->vps,
341 WIMAX2ATTR(12), PW_TYPE_OCTETS);
344 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP6-Key");
347 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
348 vp->length = rk1_len;
351 * Put MN-HA-CMIP6-SPI into WiMAX-MN-hHA-MIP6-SPI
353 vp = pairfind(request->reply->vps, WIMAX2ATTR(13));
355 vp = radius_paircreate(request, &request->reply->vps,
356 WIMAX2ATTR(13), PW_TYPE_INTEGER);
359 RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP6-SPI");
362 vp->vp_integer = mip_spi + 2;
366 break; /* do nothing */
370 * Generate FA-RK, if requested.
372 * FA-RK= H(MIP-RK, "FA-RK")
374 fa_rk = pairfind(request->reply->vps, WIMAX2ATTR(14));
375 if (fa_rk && (fa_rk->length == 0)) {
376 HMAC_CTX_init(&hmac);
377 HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);
379 HMAC_Update(&hmac, (const uint8_t *) "FA-RK", 5);
381 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
383 memcpy(fa_rk->vp_octets, &mip_rk_1[0], rk1_len);
384 fa_rk->length = rk1_len;
388 * Create FA-RK-SPI, which is really SPI-CMIP4, which is
389 * really MIP-SPI. Clear? Of course. This is WiMAX.
392 vp = pairfind(request->reply->vps, WIMAX2ATTR(61));
394 vp = radius_paircreate(request, &request->reply->vps,
395 WIMAX2ATTR(61), PW_TYPE_INTEGER);
398 RDEBUG("WARNING: Failed creating WiMAX-FA-RK-SPI");
400 vp->vp_integer = mip_spi;
405 * Generate MN-FA = H(FA-RK, "MN FA" | FA-IP | MN-NAI)
407 ip = pairfind(request->reply->vps, 1901);
408 if (fa_rk && ip && mn_nai) {
409 HMAC_CTX_init(&hmac);
410 HMAC_Init_ex(&hmac, fa_rk->vp_octets, fa_rk->length,
413 HMAC_Update(&hmac, (const uint8_t *) "MN FA", 5);
414 HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
415 HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
417 HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);
419 vp = radius_paircreate(request, &request->reply->vps,
420 1902, PW_TYPE_OCTETS);
422 RDEBUG("WARNING: Failed creating WiMAX-MN-FA");
424 memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
425 vp->length = rk1_len;
430 * Give additional information about requests && responses
432 * WiMAX-RRQ-MN-HA-SPI
434 vp = pairfind(request->packet->vps, WIMAX2ATTR(20));
436 RDEBUG("Client requested MN-HA key: Should use SPI to look up key from storage.");
438 RDEBUG("WARNING: MN-NAI was not found!");
444 if (!pairfind(request->packet->vps, WIMAX2ATTR(18))) {
445 RDEBUG("WARNING: HA-IP was not found!");
450 * WiMAX-HA-RK-Key-Requested
452 vp = pairfind(request->packet->vps, WIMAX2ATTR(58));
453 if (vp && (vp->vp_integer == 1)) {
454 RDEBUG("Client requested HA-RK: Should use IP to look it up from storage.");
459 * Wipe the context of all sensitive information.
461 HMAC_CTX_cleanup(&hmac);
463 return RLM_MODULE_UPDATED;
468 * The module name should be the only globally exported symbol.
469 * That is, everything else should be 'static'.
471 * If the module needs to temporarily modify it's instantiation
472 * data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
473 * The server will then take care of ensuring that the module
474 * is single-threaded.
476 module_t rlm_wimax = {
479 RLM_TYPE_THREAD_SAFE, /* type */
480 NULL, /* instantiation */
483 NULL, /* authentication */
484 wimax_authorize, /* authorization */
485 wimax_preacct, /* preaccounting */
486 wimax_accounting, /* accounting */
487 NULL, /* checksimul */
488 NULL, /* pre-proxy */
489 NULL, /* post-proxy */
490 wimax_postauth /* post-auth */