1 /* Copyright (c) 2006-2010, UNINETT AS.
2 * Copyright (c) 2010, UNINETT AS, NORDUnet A/S.
3 * Copyright (c) 2010-2012, NORDUnet A/S. */
4 /* See LICENSE for licensing information. */
7 #include <sys/inttypes.h>
13 #include <arpa/inet.h>
19 #include <openssl/hmac.h>
20 #include <openssl/rand.h>
22 #define RADLEN(x) ntohs(((uint16_t *)(x))[1])
24 void radmsg_free(struct radmsg *msg) {
26 freetlvlist(msg->attrs);
31 struct radmsg *radmsg_init(uint8_t code, uint8_t id, uint8_t *auth) {
34 msg = malloc(sizeof(struct radmsg));
37 memset(msg, 0, sizeof(struct radmsg));
38 msg->attrs = list_create();
46 memcpy(msg->auth, auth, 16);
47 else if (!RAND_bytes(msg->auth, 16)) {
54 int radmsg_add(struct radmsg *msg, struct tlv *attr) {
55 if (!msg || !msg->attrs)
59 return list_push(msg->attrs, attr);
62 /* returns first tlv of the given type */
63 struct tlv *radmsg_gettype(struct radmsg *msg, uint8_t type) {
64 struct list_node *node;
69 for (node = list_first(msg->attrs); node; node = list_next(node)) {
70 tlv = (struct tlv *)node->data;
77 int _checkmsgauth(unsigned char *rad, uint8_t *authattr, uint8_t *secret) {
78 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
79 static unsigned char first = 1;
80 static HMAC_CTX hmacctx;
82 uint8_t auth[16], hash[EVP_MAX_MD_SIZE];
84 pthread_mutex_lock(&lock);
86 HMAC_CTX_init(&hmacctx);
90 memcpy(auth, authattr, 16);
91 memset(authattr, 0, 16);
93 HMAC_Init_ex(&hmacctx, secret, strlen((char *)secret), EVP_md5(), NULL);
94 HMAC_Update(&hmacctx, rad, RADLEN(rad));
95 HMAC_Final(&hmacctx, hash, &md_len);
96 memcpy(authattr, auth, 16);
98 debug(DBG_WARN, "message auth computation failed");
99 pthread_mutex_unlock(&lock);
103 if (memcmp(auth, hash, 16)) {
104 debug(DBG_WARN, "message authenticator, wrong value");
105 pthread_mutex_unlock(&lock);
109 pthread_mutex_unlock(&lock);
113 int _validauth(unsigned char *rad, unsigned char *reqauth, unsigned char *sec) {
114 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
115 static unsigned char first = 1;
116 static EVP_MD_CTX mdctx;
117 unsigned char hash[EVP_MAX_MD_SIZE];
121 pthread_mutex_lock(&lock);
123 EVP_MD_CTX_init(&mdctx);
129 result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
130 EVP_DigestUpdate(&mdctx, rad, 4) &&
131 EVP_DigestUpdate(&mdctx, reqauth, 16) &&
132 (len <= 20 || EVP_DigestUpdate(&mdctx, rad + 20, len - 20)) &&
133 EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
134 EVP_DigestFinal_ex(&mdctx, hash, &len) &&
136 !memcmp(hash, rad + 4, 16));
137 pthread_mutex_unlock(&lock);
141 int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *secret) {
142 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
143 static unsigned char first = 1;
144 static HMAC_CTX hmacctx;
150 pthread_mutex_lock(&lock);
152 HMAC_CTX_init(&hmacctx);
156 memset(authattrval, 0, 16);
158 HMAC_Init_ex(&hmacctx, secret, strlen((char *)secret), EVP_md5(), NULL);
159 HMAC_Update(&hmacctx, rad, RADLEN(rad));
160 HMAC_Final(&hmacctx, authattrval, &md_len);
162 debug(DBG_WARN, "message auth computation failed");
163 pthread_mutex_unlock(&lock);
166 pthread_mutex_unlock(&lock);
170 int _radsign(unsigned char *rad, unsigned char *sec) {
171 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
172 static unsigned char first = 1;
173 static EVP_MD_CTX mdctx;
177 pthread_mutex_lock(&lock);
179 EVP_MD_CTX_init(&mdctx);
183 result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
184 EVP_DigestUpdate(&mdctx, rad, RADLEN(rad)) &&
185 EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
186 EVP_DigestFinal_ex(&mdctx, rad + 4, &md_len) &&
188 pthread_mutex_unlock(&lock);
192 uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
193 struct list_node *node;
196 uint8_t *buf, *p, *msgauth = NULL;
198 if (!msg || !msg->attrs)
201 for (node = list_first(msg->attrs); node; node = list_next(node))
202 size += 2 + ((struct tlv *)node->data)->l;
212 *(uint16_t *)p = htons(size);
214 memcpy(p, msg->auth, 16);
217 for (node = list_first(msg->attrs); node; node = list_next(node)) {
218 tlv = (struct tlv *)node->data;
221 if (tlv->t == RAD_Attr_Message_Authenticator && secret)
225 if (msgauth && !_createmessageauth(buf, msgauth, secret)) {
230 if ((msg->code == RAD_Access_Accept || msg->code == RAD_Access_Reject || msg->code == RAD_Access_Challenge || msg->code == RAD_Accounting_Response || msg->code == RAD_Accounting_Request) && !_radsign(buf, secret)) {
234 if (msg->code == RAD_Accounting_Request)
235 memcpy(msg->auth, buf + 4, 16);
240 /* if secret set we also validate message authenticator if present */
241 struct radmsg *buf2radmsg(uint8_t *buf, uint8_t *secret, uint8_t *rqauth) {
243 uint8_t t, l, *v = NULL, *p, auth[16];
251 if (secret && buf[0] == RAD_Accounting_Request) {
253 if (!_validauth(buf, auth, secret)) {
254 debug(DBG_WARN, "buf2radmsg: Accounting-Request message authentication failed");
259 if (rqauth && !_validauth(buf, rqauth, secret)) {
260 debug(DBG_WARN, "buf2radmsg: Invalid auth, ignoring reply");
264 msg = radmsg_init(buf[0], buf[1], (uint8_t *)buf + 4);
269 while (p - buf + 2 <= len) {
273 debug(DBG_WARN, "buf2radmsg: invalid attribute length %d", l);
279 if (p - buf + l > len) {
280 debug(DBG_WARN, "buf2radmsg: attribute length %d exceeds packet length", l + 2);
288 if (t == RAD_Attr_Message_Authenticator && secret) {
290 memcpy(buf + 4, rqauth, 16);
291 if (l != 16 || !_checkmsgauth(buf, v, secret)) {
292 debug(DBG_WARN, "buf2radmsg: message authentication failed");
294 memcpy(buf + 4, msg->auth, 16);
299 memcpy(buf + 4, msg->auth, 16);
300 debug(DBG_DBG, "buf2radmsg: message auth ok");
303 attr = maketlv(t, l, v);
304 if (!attr || !radmsg_add(msg, attr)) {
313 /* Local Variables: */
314 /* c-file-style: "stroustrup" */