2 * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
12 #include <arpa/inet.h>
18 #include <openssl/hmac.h>
20 #define RADLEN(x) ntohs(((uint16_t *)(x))[1])
22 void radmsg_free(struct radmsg *msg) {
24 freetlvlist(msg->attrs);
29 struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
32 msg = malloc(sizeof(struct radmsg));
35 msg->attrs = list_create();
42 memcpy(msg->auth, auth, 16);
46 int radmsg_add(struct radmsg *msg, struct tlv *attr) {
47 if (!msg || !msg->attrs)
51 return list_push(msg->attrs, attr);
54 /* returns first tlv of the given type */
55 struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) {
56 struct list_node *node;
61 for (node = list_first(msg->attrs); node; node = list_next(node)) {
62 tlv = (struct tlv *)node->data;
69 uint8_t *radmsg2buf(struct radmsg *msg) {
70 struct list_node *node;
75 if (!msg || !msg->attrs)
78 for (node = list_first(msg->attrs); node; node = list_next(node))
79 size += 2 + ((struct tlv *)node->data)->l;
89 *(uint16_t *)p = htons(size);
91 memcpy(p, msg->auth, 16);
94 for (node = list_first(msg->attrs); node; node = list_next(node)) {
95 tlv = (struct tlv *)node->data;
103 int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
104 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
105 static unsigned char first = 1;
106 static HMAC_CTX hmacctx;
108 uint8_t auth[16], hash[EVP_MAX_MD_SIZE];
110 pthread_mutex_lock(&lock);
112 HMAC_CTX_init(&hmacctx);
116 memcpy(auth, authattr, 16);
117 memset(authattr, 0, 16);
119 HMAC_Init_ex(&hmacctx, secret, strlen((char *)secret), EVP_md5(), NULL);
120 HMAC_Update(&hmacctx, rad, RADLEN(rad));
121 HMAC_Final(&hmacctx, hash, &md_len);
122 memcpy(authattr, auth, 16);
124 debug(DBG_WARN, "message auth computation failed");
125 pthread_mutex_unlock(&lock);
129 if (memcmp(auth, hash, 16)) {
130 debug(DBG_WARN, "message authenticator, wrong value");
131 pthread_mutex_unlock(&lock);
135 pthread_mutex_unlock(&lock);
139 int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
140 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
141 static unsigned char first = 1;
142 static EVP_MD_CTX mdctx;
143 unsigned char hash[EVP_MAX_MD_SIZE];
147 pthread_mutex_lock(&lock);
149 EVP_MD_CTX_init(&mdctx);
155 result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
156 EVP_DigestUpdate(&mdctx, rad, 4) &&
157 EVP_DigestUpdate(&mdctx, reqauth, 16) &&
158 (len <= 20 || EVP_DigestUpdate(&mdctx, rad + 20, len - 20)) &&
159 EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
160 EVP_DigestFinal_ex(&mdctx, hash, &len) &&
162 !memcmp(hash, rad + 4, 16));
163 pthread_mutex_unlock(&lock);
167 /* if secret set we also validate message authenticator if present */
168 struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
170 uint8_t t, l, *v, *p, auth[16];
178 if (secret && buf[0] == RAD_Accounting_Request) {
180 if (!_validauth(buf, auth, secret)) {
181 debug(DBG_WARN, "buf2radmsg: Accounting-Request message authentication failed");
186 if (rqauth && !_validauth(buf, rqauth, secret)) {
187 debug(DBG_WARN, "buf2radmsg: Invalid auth, ignoring reply");
191 msg = radmsg_init(buf[0], buf[1], (uint8_t *)buf + 4);
196 while (p - buf + 2 <= len) {
200 debug(DBG_WARN, "buf2radmsg: invalid attribute length %d", l);
206 if (p - buf + l > len) {
207 debug(DBG_WARN, "buf2radmsg: attribute length %d exceeds packet length", l + 2);
215 if (t == RAD_Attr_Message_Authenticator && secret) {
217 memcpy(buf + 4, rqauth, 16);
218 if (l != 16 || !_checkmsgauth(buf, v, secret)) {
219 debug(DBG_WARN, "buf2radmsg: message authentication failed");
221 memcpy(buf + 4, msg->auth, 16);
226 memcpy(buf + 4, msg->auth, 16);
227 debug(DBG_DBG, "buf2radmsg: message auth ok");
230 attr = maketlv(t, l, v);
231 if (!attr || !radmsg_add(msg, attr)) {