📄 radius.c
字号:
struct radius_attr_hdr *attr = NULL; int i; for (i = 0; i < msg->attr_used; i++) { if (msg->attrs[i]->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) { if (attr != NULL) { printf("Multiple Message-Authenticator " "attributes in RADIUS message\n"); return 1; } attr = msg->attrs[i]; } } if (attr == NULL) { printf("No Message-Authenticator attribute found\n"); return 1; } memcpy(orig, attr + 1, MD5_MAC_LEN); memset(attr + 1, 0, MD5_MAC_LEN); if (req_auth) { memcpy(orig_authenticator, msg->hdr->authenticator, sizeof(orig_authenticator)); memcpy(msg->hdr->authenticator, req_auth, sizeof(msg->hdr->authenticator)); } hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth); memcpy(attr + 1, orig, MD5_MAC_LEN); if (req_auth) { memcpy(msg->hdr->authenticator, orig_authenticator, sizeof(orig_authenticator)); } if (memcmp(orig, auth, MD5_MAC_LEN) != 0) { printf("Invalid Message-Authenticator!\n"); return 1; } return 0;}int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len, struct radius_msg *sent_msg){ MD5_CTX context; u8 hash[MD5_MAC_LEN]; if (sent_msg == NULL) { printf("No matching Access-Request message found\n"); return 1; } if (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); if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { printf("Response Authenticator invalid!\n"); return 1; } return 0;}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){ struct radius_attr_hdr *attr = NULL; int i; for (i = 0; i < src->attr_used; i++) { if (src->attrs[i]->type == type) { attr = src->attrs[i]; break; } } if (attr == NULL) return 0; if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1), attr->length - sizeof(*attr))) return -1; return 1;}/* Create Request Authenticator. The value should be unique over the lifetime * of the shared secret between authenticator and authentication server. * Use one-way MD5 hash calculated from current timestamp and some data given * by the caller. */void radius_msg_make_authenticator(struct radius_msg *msg, u8 *data, size_t len){ struct timeval tv; MD5_CTX context; long int l; 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);}/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message. * Returns the Attribute payload and sets alen to indicate the length of the * payload if a vendor attribute with subtype is found, otherwise returns NULL. * The returned payload is allocated with malloc() and caller must free it. */static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor, u8 subtype, size_t *alen){ u8 *data, *pos; int i; size_t len; if (msg == NULL) return NULL; for (i = 0; i < msg->attr_used; i++) { struct radius_attr_hdr *attr = msg->attrs[i]; int left; u32 vendor_id; struct radius_attr_vendor *vhdr; if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC) continue; left = attr->length - sizeof(*attr); if (left < 4) continue; pos = (u8 *) (attr + 1); memcpy(&vendor_id, pos, 4); pos += 4; left -= 4; if (ntohl(vendor_id) != vendor) continue; while (left >= sizeof(*vhdr)) { vhdr = (struct radius_attr_vendor *) pos; if (vhdr->vendor_length > left || vhdr->vendor_length < sizeof(*vhdr)) { left = 0; break; } if (vhdr->vendor_type != subtype) { pos += vhdr->vendor_length; left -= vhdr->vendor_length; continue; } len = vhdr->vendor_length - sizeof(*vhdr); data = malloc(len); if (data == NULL) return NULL; memcpy(data, pos + sizeof(*vhdr), len); if (alen) *alen = len; return data; } } return NULL;}static u8 * decrypt_ms_key(const u8 *key, size_t len, const u8 *req_authenticator, const u8 *secret, size_t secret_len, size_t *reslen){ u8 *plain, *ppos, *res; const u8 *pos; size_t left, plen; u8 hash[MD5_MAC_LEN]; MD5_CTX context; int i, first = 1; /* key: 16-bit salt followed by encrypted key info */ if (len < 2 + 16) return NULL; pos = key + 2; left = len - 2; if (left % 16) { printf("Invalid ms key len %lu\n", (unsigned long) left); return NULL; } plen = left; ppos = plain = malloc(plen); if (plain == NULL) return NULL; while (left > 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); 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); for (i = 0; i < MD5_MAC_LEN; i++) *ppos++ = *pos++ ^ hash[i]; left -= MD5_MAC_LEN; } if (plain[0] > plen - 1) { printf("Failed to decrypt MPPE key\n"); free(plain); return NULL; } res = malloc(plain[0]); if (res == NULL) { free(plain); return NULL; } memcpy(res, plain + 1, plain[0]); if (reslen) *reslen = plain[0]; free(plain); return res;}static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt, const u8 *req_authenticator, const u8 *secret, size_t secret_len, u8 *ebuf, size_t *elen){ int i, len, first = 1; u8 hash[MD5_MAC_LEN], saltbuf[2], *pos; MD5_CTX context; saltbuf[0] = salt >> 8; saltbuf[1] = salt; len = 1 + key_len; if (len & 0x0f) { len = (len & 0xf0) + 16; } memset(ebuf, 0, len); ebuf[0] = key_len; memcpy(ebuf + 1, key, key_len); *elen = len; pos = ebuf; 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); if (first) { MD5Update(&context, req_authenticator, MD5_MAC_LEN); MD5Update(&context, saltbuf, sizeof(saltbuf)); first = 0; } else { MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN); } MD5Final(hash, &context); for (i = 0; i < MD5_MAC_LEN; i++) *pos++ ^= hash[i]; len -= MD5_MAC_LEN; }}struct radius_ms_mppe_keys *radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, u8 *secret, size_t secret_len){ u8 *key; size_t keylen; struct radius_ms_mppe_keys *keys; if (msg == NULL || sent_msg == NULL) return NULL; keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys)); if (keys == NULL) return NULL; memset(keys, 0, sizeof(*keys)); key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, &keylen); if (key) { keys->send = decrypt_ms_key(key, keylen, sent_msg->hdr->authenticator, secret, secret_len, &keys->send_len); free(key); } key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT, RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, &keylen); if (key) { keys->recv = decrypt_ms_key(key, keylen, sent_msg->hdr->authenticator, secret, secret_len, &keys->recv_len); free(key); } return keys;}struct radius_ms_mppe_keys *radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg, u8 *secret, size_t secret_len){ u8 *key; size_t keylen; struct radius_ms_mppe_keys *keys; if (msg == NULL || sent_msg == NULL) return NULL; keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys)); if (keys == NULL) return NULL; memset(keys, 0, sizeof(*keys)); key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO, RADIUS_CISCO_AV_PAIR, &keylen); if (key && keylen == 51 && memcmp(key, "leap:session-key=", 17) == 0) { keys->recv = decrypt_ms_key(key + 17, keylen - 17, sent_msg->hdr->authenticator, secret, secret_len, &keys->recv_len); free(key); } return keys;}int radius_msg_add_mppe_keys(struct radius_msg *msg, const u8 *req_authenticator, const u8 *secret, size_t secret_len, const u8 *send_key, size_t send_key_len, const u8 *recv_key, size_t recv_key_len){ struct radius_attr_hdr *attr; u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT); u8 *buf; struct radius_attr_vendor *vhdr; u8 *pos; size_t elen; int hlen; u16 salt; hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2; /* MS-MPPE-Send-Key */ buf = malloc(hlen + send_key_len + 16); if (buf == NULL) { return 0; } pos = buf; memcpy(pos, &vendor_id, sizeof(vendor_id)); pos += sizeof(vendor_id); vhdr = (struct radius_attr_vendor *) pos; vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY; pos = (u8 *) (vhdr + 1); salt = random() | 0x8000; *pos++ = salt >> 8; *pos++ = salt; encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret, secret_len, pos, &elen); vhdr->vendor_length = hlen + elen - sizeof(vendor_id); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, hlen + elen); free(buf); if (attr == NULL) { return 0; } /* MS-MPPE-Recv-Key */ buf = malloc(hlen + send_key_len + 16); if (buf == NULL) { return 0; } pos = buf; memcpy(pos, &vendor_id, sizeof(vendor_id)); pos += sizeof(vendor_id); vhdr = (struct radius_attr_vendor *) pos; vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY; pos = (u8 *) (vhdr + 1); salt ^= 1; *pos++ = salt >> 8; *pos++ = salt; encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret, secret_len, pos, &elen); vhdr->vendor_length = hlen + elen - sizeof(vendor_id); attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC, buf, hlen + elen); free(buf); if (attr == NULL) { return 0; } return 1;}/* Add User-Password attribute to a RADIUS message and encrypt it as specified * in RFC 2865, Chap. 5.2 */struct radius_attr_hdr *radius_msg_add_attr_user_password(struct radius_msg *msg, u8 *data, size_t data_len, u8 *secret, size_t secret_len){ u8 buf[128]; int padlen, i, pos; MD5_CTX context; size_t buf_len; u8 hash[16]; if (data_len > 128) return NULL; memcpy(buf, data, data_len); buf_len = data_len; padlen = data_len % 16; if (padlen) { padlen = 16 - padlen; memset(buf + data_len, 0, padlen); buf_len += padlen; } MD5Init(&context); MD5Update(&context, secret, secret_len); MD5Update(&context, msg->hdr->authenticator, 16); MD5Final(hash, &context); 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); for (i = 0; i < 16; i++) buf[pos + i] ^= hash[i]; pos += 16; } return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, buf, buf_len);}int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len){ int i; struct radius_attr_hdr *attr = NULL; size_t dlen; for (i = 0; i < msg->attr_used; i++) { if (msg->attrs[i]->type == type) { attr = msg->attrs[i]; break; } } if (!attr) return -1; dlen = attr->length - sizeof(*attr); if (buf) memcpy(buf, (attr + 1), dlen > len ? len : dlen); return dlen;}int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf, 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 && (start == NULL || (u8 *) msg->attrs[i] > start)) { attr = msg->attrs[i]; break; } } if (!attr) return -1; *buf = (u8 *) (attr + 1); *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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -