+
+int _createmessageauth(unsigned char *rad, unsigned char *authattrval, uint8_t *secret) {
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned char first = 1;
+ static HMAC_CTX hmacctx;
+ unsigned int md_len;
+
+ if (!authattrval)
+ return 1;
+
+ pthread_mutex_lock(&lock);
+ if (first) {
+ HMAC_CTX_init(&hmacctx);
+ first = 0;
+ }
+
+ memset(authattrval, 0, 16);
+ md_len = 0;
+ HMAC_Init_ex(&hmacctx, secret, strlen((char *)secret), EVP_md5(), NULL);
+ HMAC_Update(&hmacctx, rad, RADLEN(rad));
+ HMAC_Final(&hmacctx, authattrval, &md_len);
+ if (md_len != 16) {
+ debug(DBG_WARN, "message auth computation failed");
+ pthread_mutex_unlock(&lock);
+ return 0;
+ }
+ pthread_mutex_unlock(&lock);
+ return 1;
+}
+
+int _radsign(unsigned char *rad, unsigned char *sec) {
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ static unsigned char first = 1;
+ static EVP_MD_CTX mdctx;
+ unsigned int md_len;
+ int result;
+
+ pthread_mutex_lock(&lock);
+ if (first) {
+ EVP_MD_CTX_init(&mdctx);
+ first = 0;
+ }
+
+ result = (EVP_DigestInit_ex(&mdctx, EVP_md5(), NULL) &&
+ EVP_DigestUpdate(&mdctx, rad, RADLEN(rad)) &&
+ EVP_DigestUpdate(&mdctx, sec, strlen((char *)sec)) &&
+ EVP_DigestFinal_ex(&mdctx, rad + 4, &md_len) &&
+ md_len == 16);
+ pthread_mutex_unlock(&lock);
+ return result;
+}
+
+uint8_t *radmsg2buf(struct radmsg *msg, uint8_t *secret) {
+ struct list_node *node;
+ struct tlv *tlv;
+ int size;
+ uint8_t *buf, *p, *msgauth = NULL;
+
+ if (!msg || !msg->attrs)
+ return NULL;
+ size = 20;
+ for (node = list_first(msg->attrs); node; node = list_next(node))
+ size += 2 + ((struct tlv *)node->data)->l;
+ if (size > 65535)
+ return NULL;
+ buf = malloc(size);
+ if (!buf)
+ return NULL;
+
+ p = buf;
+ *p++ = msg->code;
+ *p++ = msg->id;
+ *(uint16_t *)p = htons(size);
+ p += 2;
+ memcpy(p, msg->auth, 16);
+ p += 16;
+
+ for (node = list_first(msg->attrs); node; node = list_next(node)) {
+ tlv = (struct tlv *)node->data;
+ p = tlv2buf(p, tlv);
+ p[-1] += 2;
+ if (tlv->t == RAD_Attr_Message_Authenticator && secret)
+ msgauth = p;
+ p += tlv->l;
+ }
+ if (msgauth && !_createmessageauth(buf, msgauth, secret)) {
+ free(buf);
+ return NULL;
+ }
+ if (secret) {
+ 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)) {
+ free(buf);
+ return NULL;
+ }
+ if (msg->code == RAD_Accounting_Request)
+ memcpy(msg->auth, buf + 4, 16);
+ }
+ return buf;
+}
+