diff options
Diffstat (limited to 'contrib/hostapd/radius.c')
-rw-r--r-- | contrib/hostapd/radius.c | 219 |
1 files changed, 127 insertions, 92 deletions
diff --git a/contrib/hostapd/radius.c b/contrib/hostapd/radius.c index 5fd323d..ce79a62 100644 --- a/contrib/hostapd/radius.c +++ b/contrib/hostapd/radius.c @@ -16,18 +16,20 @@ #include <stdlib.h> #include <stdio.h> #include <unistd.h> -#include <netinet/in.h> #include <string.h> -#include <sys/ioctl.h> #include <signal.h> #include <sys/time.h> +#ifndef CONFIG_NATIVE_WINDOWS +#include <netinet/in.h> +#include <sys/ioctl.h> #include <sys/socket.h> #include <arpa/inet.h> - +#endif /* CONFIG_NATIVE_WINDOWS */ #include "common.h" #include "radius.h" #include "md5.h" +#include "crypto.h" struct radius_msg *radius_msg_new(u8 code, u8 identifier) @@ -124,8 +126,10 @@ static const char *radius_code_string(u8 code) struct radius_attr_type { u8 type; char *name; - enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, - RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32 } data_type; + enum { + RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP, + RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6 + } data_type; }; static struct radius_attr_type radius_attrs[] = @@ -179,8 +183,8 @@ static struct radius_attr_type radius_attrs[] = { RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator", RADIUS_ATTR_UNDIST }, { RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval", - RADIUS_ATTR_INT32 } - + RADIUS_ATTR_INT32 }, + { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, }; #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0])) @@ -231,6 +235,19 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) printf(" Invalid IP address length %d\n", len); break; +#ifdef CONFIG_IPV6 + case RADIUS_ATTR_IPV6: + if (len == 16) { + char buf[128]; + const char *atxt; + struct in6_addr *addr = (struct in6_addr *) pos; + atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf)); + printf(" Value: %s\n", atxt ? atxt : "?"); + } else + printf(" Invalid IPv6 address length %d\n", len); + break; +#endif /* CONFIG_IPV6 */ + case RADIUS_ATTR_HEXDUMP: case RADIUS_ATTR_UNDIST: printf(" Value:"); @@ -242,7 +259,8 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr) case RADIUS_ATTR_INT32: if (len == 4) { u32 *val = (u32 *) pos; - printf(" Value: %d\n", ntohl(*val)); + printf(" Value: %u\n", + (unsigned int) ntohl(*val)); } else printf(" Invalid INT32 length %d\n", len); break; @@ -302,7 +320,8 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, { u8 auth[MD5_MAC_LEN]; struct radius_attr_hdr *attr; - MD5_CTX context; + const u8 *addr[4]; + size_t len[4]; memset(auth, 0, MD5_MAC_LEN); attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, @@ -318,13 +337,15 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, (u8 *) (attr + 1)); /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ - MD5Init(&context); - MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2); - MD5Update(&context, req_authenticator, MD5_MAC_LEN); - MD5Update(&context, (u8 *) (msg->hdr + 1), - msg->buf_used - sizeof(*msg->hdr)); - MD5Update(&context, secret, secret_len); - MD5Final(msg->hdr->authenticator, &context); + addr[0] = (u8 *) msg->hdr; + len[0] = 1 + 1 + 2; + addr[1] = req_authenticator; + len[1] = MD5_MAC_LEN; + addr[2] = (u8 *) (msg->hdr + 1); + len[2] = msg->buf_used - sizeof(*msg->hdr); + addr[3] = secret; + len[3] = secret_len; + md5_vector(4, addr, len, msg->hdr->authenticator); if (msg->buf_used > 0xffff) { printf("WARNING: too long RADIUS message (%lu)\n", @@ -338,14 +359,16 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret, void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret, size_t secret_len) { - MD5_CTX context; + const u8 *addr[2]; + size_t len[2]; msg->hdr->length = htons(msg->buf_used); memset(msg->hdr->authenticator, 0, MD5_MAC_LEN); - MD5Init(&context); - MD5Update(&context, msg->buf, msg->buf_used); - MD5Update(&context, secret, secret_len); - MD5Final(msg->hdr->authenticator, &context); + addr[0] = msg->buf; + len[0] = msg->buf_used; + addr[1] = secret; + len[1] = secret_len; + md5_vector(2, addr, len, msg->hdr->authenticator); if (msg->buf_used > 0xffff) { printf("WARNING: too long RADIUS messages (%lu)\n", @@ -378,7 +401,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg, struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type, - u8 *data, size_t data_len) + const u8 *data, size_t data_len) { size_t buf_needed; struct radius_attr_hdr *attr; @@ -493,9 +516,9 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len) } -int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len) +int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len) { - u8 *pos = data; + const u8 *pos = data; size_t left = data_len; while (left > 0) { @@ -605,10 +628,11 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, } -int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len, - struct radius_msg *sent_msg) +int radius_msg_verify(struct radius_msg *msg, const u8 *secret, + size_t secret_len, struct radius_msg *sent_msg, int auth) { - MD5_CTX context; + const u8 *addr[4]; + size_t len[4]; u8 hash[MD5_MAC_LEN]; if (sent_msg == NULL) { @@ -616,19 +640,22 @@ int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len, return 1; } - if (radius_msg_verify_msg_auth(msg, secret, secret_len, + if (auth && + radius_msg_verify_msg_auth(msg, secret, secret_len, sent_msg->hdr->authenticator)) { return 1; } /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */ - MD5Init(&context); - MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2); - MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN); - MD5Update(&context, (u8 *) (msg->hdr + 1), - msg->buf_used - sizeof(*msg->hdr)); - MD5Update(&context, secret, secret_len); - MD5Final(hash, &context); + addr[0] = (u8 *) msg->hdr; + len[0] = 1 + 1 + 2; + addr[1] = sent_msg->hdr->authenticator; + len[1] = MD5_MAC_LEN; + addr[2] = (u8 *) (msg->hdr + 1); + len[2] = msg->buf_used - sizeof(*msg->hdr); + addr[3] = secret; + len[3] = secret_len; + md5_vector(4, addr, len, hash); if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { printf("Response Authenticator invalid!\n"); return 1; @@ -639,29 +666,6 @@ int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len, } -int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret, - size_t secret_len, struct radius_msg *sent_msg) -{ - MD5_CTX context; - u8 hash[MD5_MAC_LEN]; - - MD5Init(&context); - MD5Update(&context, msg->buf, 4); - MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN); - if (msg->buf_used > sizeof(struct radius_hdr)) - MD5Update(&context, msg->buf + sizeof(struct radius_hdr), - msg->buf_used - sizeof(struct radius_hdr)); - MD5Update(&context, secret, secret_len); - MD5Final(hash, &context); - if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { - printf("Response Authenticator invalid!\n"); - return 1; - } - - return 0; -} - - int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, u8 type) { @@ -694,16 +698,19 @@ void radius_msg_make_authenticator(struct radius_msg *msg, u8 *data, size_t len) { struct timeval tv; - MD5_CTX context; long int l; + const u8 *addr[3]; + size_t elen[3]; gettimeofday(&tv, NULL); l = random(); - MD5Init(&context); - MD5Update(&context, (u8 *) &tv, sizeof(tv)); - MD5Update(&context, data, len); - MD5Update(&context, (u8 *) &l, sizeof(l)); - MD5Final(msg->hdr->authenticator, &context); + addr[0] = (u8 *) &tv; + elen[0] = sizeof(tv); + addr[1] = data; + elen[1] = len; + addr[2] = (u8 *) &l; + elen[2] = sizeof(l); + md5_vector(3, addr, elen, msg->hdr->authenticator); } @@ -780,8 +787,9 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len, const u8 *pos; size_t left, plen; u8 hash[MD5_MAC_LEN]; - MD5_CTX context; int i, first = 1; + const u8 *addr[3]; + size_t elen[3]; /* key: 16-bit salt followed by encrypted key info */ @@ -804,15 +812,19 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len, /* b(1) = MD5(Secret + Request-Authenticator + Salt) * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ - MD5Init(&context); - MD5Update(&context, secret, secret_len); + addr[0] = secret; + elen[0] = secret_len; if (first) { - MD5Update(&context, req_authenticator, MD5_MAC_LEN); - MD5Update(&context, key, 2); /* Salt */ - first = 0; - } else - MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN); - MD5Final(hash, &context); + addr[1] = req_authenticator; + elen[1] = MD5_MAC_LEN; + addr[2] = key; + elen[2] = 2; /* Salt */ + } else { + addr[1] = pos - MD5_MAC_LEN; + elen[1] = MD5_MAC_LEN; + } + md5_vector(first ? 3 : 2, addr, elen, hash); + first = 0; for (i = 0; i < MD5_MAC_LEN; i++) *ppos++ = *pos++ ^ hash[i]; @@ -845,7 +857,8 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, { int i, len, first = 1; u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; - MD5_CTX context; + const u8 *addr[3]; + size_t _len[3]; saltbuf[0] = salt >> 8; saltbuf[1] = salt; @@ -864,16 +877,19 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, while (len > 0) { /* b(1) = MD5(Secret + Request-Authenticator + Salt) * b(i) = MD5(Secret + c(i - 1)) for i > 1 */ - MD5Init(&context); - MD5Update(&context, secret, secret_len); + addr[0] = secret; + _len[0] = secret_len; if (first) { - MD5Update(&context, req_authenticator, MD5_MAC_LEN); - MD5Update(&context, saltbuf, sizeof(saltbuf)); - first = 0; + addr[1] = req_authenticator; + _len[1] = MD5_MAC_LEN; + addr[2] = saltbuf; + _len[2] = sizeof(saltbuf); } else { - MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN); + addr[1] = pos - MD5_MAC_LEN; + _len[1] = MD5_MAC_LEN; } - MD5Final(hash, &context); + md5_vector(first ? 3 : 2, addr, _len, hash); + first = 0; for (i = 0; i < MD5_MAC_LEN; i++) *pos++ ^= hash[i]; @@ -1037,8 +1053,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, { u8 buf[128]; int padlen, i, pos; - MD5_CTX context; size_t buf_len; + const u8 *addr[2]; + size_t len[2]; u8 hash[16]; if (data_len > 128) @@ -1054,20 +1071,22 @@ radius_msg_add_attr_user_password(struct radius_msg *msg, buf_len += padlen; } - MD5Init(&context); - MD5Update(&context, secret, secret_len); - MD5Update(&context, msg->hdr->authenticator, 16); - MD5Final(hash, &context); + addr[0] = secret; + len[0] = secret_len; + addr[1] = msg->hdr->authenticator; + len[1] = 16; + md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[i] ^= hash[i]; pos = 16; while (pos < buf_len) { - MD5Init(&context); - MD5Update(&context, secret, secret_len); - MD5Update(&context, &buf[pos - 16], 16); - MD5Final(hash, &context); + addr[0] = secret; + len[0] = secret_len; + addr[1] = &buf[pos - 16]; + len[1] = 16; + md5_vector(2, addr, len, hash); for (i = 0; i < 16; i++) buf[pos + i] ^= hash[i]; @@ -1104,13 +1123,14 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len) int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, - size_t *len) + size_t *len, const u8 *start) { int i; struct radius_attr_hdr *attr = NULL; for (i = 0; i < msg->attr_used; i++) { - if (msg->attrs[i]->type == type) { + if (msg->attrs[i]->type == type && + (start == NULL || (u8 *) msg->attrs[i] > start)) { attr = msg->attrs[i]; break; } @@ -1123,3 +1143,18 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, *len = attr->length - sizeof(*attr); return 0; } + + +int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len) +{ + int i, count; + + for (count = 0, i = 0; i < msg->attr_used; i++) { + if (msg->attrs[i]->type == type && + msg->attrs[i]->length >= + sizeof(struct radius_attr_hdr) + min_len) + count++; + } + + return count; +} |