📄 ttls.c
字号:
/* * rlm_eap_ttls.c contains the interfaces that are called from eap * * Version: $Id: ttls.c,v 1.45 2008/03/07 09:53:26 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2003 Alan DeKok <aland@freeradius.org> * Copyright 2006 The FreeRADIUS server project */#include <freeradius-devel/ident.h>RCSID("$Id: ttls.c,v 1.45 2008/03/07 09:53:26 aland Exp $")#include "eap_ttls.h"/* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | AVP Code | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |V M r r r r r r| AVP Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Vendor-ID (opt) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Data ... * +-+-+-+-+-+-+-+-+ *//* * Verify that the diameter packet is valid. */static int diameter_verify(const uint8_t *data, unsigned int data_len){ uint32_t attr; uint32_t length; unsigned int offset; unsigned int data_left = data_len; while (data_left > 0) { if (data_len < 12) { DEBUG2(" rlm_eap_ttls: Diameter attribute is too small to contain a Diameter header"); return 0; } rad_assert(data_left <= data_len); memcpy(&attr, data, sizeof(attr)); data += 4; attr = ntohl(attr); if (attr > 255) { DEBUG2(" rlm_eap_ttls: Non-RADIUS attribute in tunneled authentication is not supported"); return 0; } memcpy(&length, data , sizeof(length)); data += 4; length = ntohl(length); /* * A "vendor" flag, with a vendor ID of zero, * is equivalent to no vendor. This is stupid. */ offset = 8; if ((length & (1 << 31)) != 0) { int attribute; uint32_t vendor; DICT_ATTR *da; memcpy(&vendor, data, sizeof(vendor)); vendor = ntohl(vendor); if (vendor > 65535) { DEBUG2(" rlm_eap_ttls: Vendor codes larger than 65535 are not supported"); return 0; } attribute = (vendor << 16) | attr; da = dict_attrbyvalue(attribute); /* * SHOULD check ((length & (1 << 30)) != 0) * for the mandatory bit. */ if (!da) { DEBUG2(" rlm_eap_ttls: Fatal! Vendor %u, Attribute %u was not found in our dictionary. ", vendor, attr); return 0; } data += 4; /* skip the vendor field */ offset += 4; /* offset to value field */ } /* * Ignore the M bit. We support all RADIUS attributes... */ /* * Get the length. If it's too big, die. */ length &= 0x00ffffff; /* * Too short or too long is bad. */ if (length < offset) { DEBUG2(" rlm_eap_ttls: Tunneled attribute %d is too short (%d)to contain anything useful.", attr, length); return 0; } /* * EAP Messages cane be longer than MAX_STRING_LEN. * Other attributes cannot be. */ if ((attr != PW_EAP_MESSAGE) && (length > (MAX_STRING_LEN + 8))) { DEBUG2(" rlm_eap_ttls: Tunneled attribute %d is too long (%d) to pack into a RADIUS attribute.", attr, length); return 0; } if (length > data_left) { DEBUG2(" rlm_eap_ttls: Tunneled attribute %d is longer than room left in the packet (%d > %d).", attr, length, data_left); return 0; } /* * Check for broken implementations, which don't * pad the AVP to a 4-octet boundary. */ if (data_left == length) break; /* * The length does NOT include the padding, so * we've got to account for it here by rounding up * to the nearest 4-byte boundary. */ length += 0x03; length &= ~0x03; /* * If the rest of the diameter packet is larger than * this attribute, continue. * * Otherwise, if the attribute over-flows the end * of the packet, die. */ if (data_left < length) { DEBUG2(" rlm_eap_ttls: ERROR! Diameter attribute overflows packet!"); return 0; } /* * Check again for equality, now that we're padded * length to a multiple of 4 octets. */ if (data_left == length) break; /* * data_left > length, continue. */ data_left -= length; data += length - offset; } /* * We got this far. It looks OK. */ return 1;}/* * Convert diameter attributes to our VALUE_PAIR's */static VALUE_PAIR *diameter2vp(SSL *ssl, const uint8_t *data, size_t data_len){ uint32_t attr; uint32_t length; size_t offset; size_t size; size_t data_left = data_len; VALUE_PAIR *first = NULL; VALUE_PAIR **last = &first; VALUE_PAIR *vp; while (data_left > 0) { rad_assert(data_left <= data_len); memcpy(&attr, data, sizeof(attr)); data += 4; attr = ntohl(attr); memcpy(&length, data, sizeof(length)); data += 4; length = ntohl(length); /* * A "vendor" flag, with a vendor ID of zero, * is equivalent to no vendor. This is stupid. */ offset = 8; if ((length & (1 << 31)) != 0) { uint32_t vendor; memcpy(&vendor, data, sizeof(vendor)); vendor = ntohl(vendor); if (attr > 65535) { DEBUG2(" rlm_eap_ttls: Cannot handle vendor attributes greater than 65535"); pairfree(&first); return NULL; } if (vendor > 32767) { DEBUG2(" rlm_eap_ttls: Cannot handle vendor Id greater than 32767"); pairfree(&first); return NULL; } attr |= (vendor << 16); data += 4; /* skip the vendor field, it's zero */ offset += 4; /* offset to value field */ } /* * Vendor attributes can be larger than 255. * Normal attributes cannot be. */ if ((attr > 255) && (VENDOR(attr) == 0)) { DEBUG2(" rlm_eap_ttls: Cannot handle Diameter attributes"); pairfree(&first); return NULL; } /* * FIXME: Handle the M bit. For now, we assume that * some other module takes care of any attribute * with the M bit set. */ /* * Get the length. */ length &= 0x00ffffff; /* * Get the size of the value portion of the * attribute. */ size = length - offset; /* * Create it. */ vp = paircreate(attr, PW_TYPE_OCTETS); if (!vp) { DEBUG2(" rlm_eap_ttls: Failure in creating VP"); pairfree(&first); return NULL; } /* * If it's a type from our dictionary, then * we need to put the data in a relevant place. */ switch (vp->type) { case PW_TYPE_INTEGER: case PW_TYPE_DATE: if (size != vp->length) { DEBUG2(" rlm_eap_ttls: Invalid length attribute %d", attr); pairfree(&first); pairfree(&vp); return NULL; } memcpy(&vp->vp_integer, data, vp->length); /* * Stored in host byte order: change it. */ vp->vp_integer = ntohl(vp->vp_integer); break; case PW_TYPE_IPADDR: if (size != vp->length) { DEBUG2(" rlm_eap_ttls: Invalid length attribute %d", attr); pairfree(&first); pairfree(&vp); return NULL; } memcpy(&vp->vp_ipaddr, data, vp->length); /* * Stored in network byte order: don't change it. */ break; /* * String, octet, etc. Copy the data from the * value field over verbatim. * * FIXME: Ipv6 attributes ? * */ case PW_TYPE_OCTETS: if (attr == PW_EAP_MESSAGE) { const uint8_t *eap_message = data; /* * vp exists the first time around. */ while (1) { vp->length = size; if (vp->length > 253) vp->length = 253; memcpy(vp->vp_octets, eap_message, vp->length); size -= vp->length; eap_message += vp->length; *last = vp; last = &(vp->next); if (size == 0) break; vp = paircreate(attr, PW_TYPE_OCTETS); if (!vp) { DEBUG2(" rlm_eap_ttls: Failure in creating VP"); pairfree(&first); return NULL; } } goto next_attr; } /* else it's another kind of attribute */ /* FALL-THROUGH */ default: vp->length = size; memcpy(vp->vp_strvalue, data, vp->length); break; } /* * User-Password is NUL padded to a multiple * of 16 bytes. Let's chop it to something * more reasonable. * * NOTE: This means that the User-Password * attribute CANNOT EVER have embedded zeros in it! */ switch (vp->attribute) { case PW_USER_PASSWORD: /* * If the password is exactly 16 octets, * it won't be zero-terminated. */ vp->vp_strvalue[vp->length] = '\0'; vp->length = strlen(vp->vp_strvalue); break; /* * Ensure that the client is using the * correct challenge. This weirdness is * to protect against against replay * attacks, where anyone observing the * CHAP exchange could pose as that user, * by simply choosing to use the same * challenge. * * By using a challenge based on * information from the current session, * we can guarantee that the client is * not *choosing* a challenge. * * We're a little forgiving in that we * have loose checks on the length, and * we do NOT check the Id (first octet of * the response to the challenge) * * But if the client gets the challenge correct, * we're not too worried about the Id. */ case PW_CHAP_CHALLENGE: case PW_MSCHAP_CHALLENGE: if ((vp->length < 8) || (vp->length > 16)) { DEBUG2(" TTLS: Tunneled challenge has invalid length"); pairfree(&first); pairfree(&vp); return NULL; } else { uint8_t challenge[16]; eapttls_gen_challenge(ssl, challenge, sizeof(challenge)); if (memcmp(challenge, vp->vp_octets, vp->length) != 0) { DEBUG2(" TTLS: Tunneled challenge is incorrect"); pairfree(&first); pairfree(&vp); return NULL; } } break; default: break; } /* switch over checking/re-writing of attributes. */ /* * Update the list. */ *last = vp; last = &(vp->next); next_attr: /* * Catch non-aligned attributes. */ if (data_left == length) break; /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -