summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Fedoryshchenko <denys.f@collabora.com>2025-06-25 22:31:08 +0300
committerDenys Fedoryshchenko <denys.f@collabora.com>2025-07-01 14:32:13 +0300
commit1ce263f13ac0b3aed3b14b4a9bb6a51afe210684 (patch)
treece765094676327c751586010e65ce4af4545f262
parente06f5b835eb3ef28a2489ca903bc410175225c11 (diff)
downloadaccel-ppp-1ce263f13ac0b3aed3b14b4a9bb6a51afe210684.tar.gz
accel-ppp-1ce263f13ac0b3aed3b14b4a9bb6a51afe210684.zip
Add RADIUS blast attack protection with Message-Authenticator
Recently FreeRadius started to complain accel-ppp doesn't pass BlastRADIUS check. This commit fixes that. This commit implements protection against RADIUS blast attacks by adding support for the Message-Authenticator attribute in Access-Request packets. This security enhancement helps prevent unauthorized access attempts and replay attacks on RADIUS authentication. - Added new configuration option `blast-protection=1` in [radius] to enable Message-Authenticator inclusion - Implemented HMAC-MD5 calculation for Message-Authenticator attribute (RFC 2869) - Modified packet building to include 18-byte Message-Authenticator attribute when enabled - Updated packet structure to support signing with shared secret Enable blast protection by adding to the `[radius]` section: ``` blast-protection=1 ``` When enabled, all Access-Request packets will include a Message-Authenticator attribute with HMAC-MD5 signature, providing cryptographic integrity verification and protection against packet modification attacks. Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
-rw-r--r--accel-pppd/accel-ppp.conf1
-rw-r--r--accel-pppd/accel-ppp.conf.55
-rw-r--r--accel-pppd/radius/dm_coa.c1
-rw-r--r--accel-pppd/radius/packet.c51
-rw-r--r--accel-pppd/radius/radius.c8
-rw-r--r--accel-pppd/radius/radius.h2
-rw-r--r--accel-pppd/radius/radius_p.h1
-rw-r--r--accel-pppd/radius/req.c13
8 files changed, 81 insertions, 1 deletions
diff --git a/accel-pppd/accel-ppp.conf b/accel-pppd/accel-ppp.conf
index 99d35c79..3f277a16 100644
--- a/accel-pppd/accel-ppp.conf
+++ b/accel-pppd/accel-ppp.conf
@@ -227,6 +227,7 @@ verbose=1
#strip-realm=0
#attr-tunnel-type=My-Tunnel-Type
#nas-port-id-in-req=1
+blast-protection=1
[client-ip-range]
10.0.0.0/8
diff --git a/accel-pppd/accel-ppp.conf.5 b/accel-pppd/accel-ppp.conf.5
index 72376c35..8860d520 100644
--- a/accel-pppd/accel-ppp.conf.5
+++ b/accel-pppd/accel-ppp.conf.5
@@ -1008,6 +1008,11 @@ Specifies should accel-ppp send NAS-Port-Id on Access-Request and Accounting-Req
.br
Configuration of log and log_file modules.
.TP
+.BI "blast-protection=" 0|1
+If this option is given and
+.B 1
+is specified then radius module will include Message-Authenticator attribute in Access-Request packets.
+.TP
.BI "log-file=" file
Path to file to write general log.
.TP
diff --git a/accel-pppd/radius/dm_coa.c b/accel-pppd/radius/dm_coa.c
index e88cc347..8eb45a60 100644
--- a/accel-pppd/radius/dm_coa.c
+++ b/accel-pppd/radius/dm_coa.c
@@ -106,6 +106,7 @@ static int dm_coa_send_nak(int fd, struct rad_packet_t *req, struct sockaddr_in
if (err_code)
rad_packet_add_int(reply, NULL, "Error-Cause", err_code);
+ // TODO: We need to add Message-Authenticator attribute here
if (rad_packet_build(reply, RA)) {
rad_packet_free(reply);
return -1;
diff --git a/accel-pppd/radius/packet.c b/accel-pppd/radius/packet.c
index 3c2ef99d..0ef9a0e3 100644
--- a/accel-pppd/radius/packet.c
+++ b/accel-pppd/radius/packet.c
@@ -8,14 +8,20 @@
#include <sys/mman.h>
#include <linux/mman.h>
#include <arpa/inet.h>
+#include <openssl/hmac.h>
+#include <openssl/evp.h>
#include "log.h"
#include "mempool.h"
-
#include "radius_p.h"
+#include "attr_defs.h"
#include "memdebug.h"
+#define HMAC_MD5_LEN 16
+/* Radius header + attribute: type + length */
+#define PACKET_SIGNED_OFFSET (20 + 2)
+
static mempool_t packet_pool;
static mempool_t attr_pool;
static mempool_t buf_pool;
@@ -47,6 +53,34 @@ void print_buf(uint8_t *buf,int size)
printf("\n");
}
+
+int hmac_md5(const uint8_t *key, size_t key_len,
+ const uint8_t *data, size_t data_len,
+ uint8_t out[HMAC_MD5_LEN])
+{
+ unsigned int len = 0;
+ HMAC_CTX *ctx = HMAC_CTX_new();
+ if (!ctx)
+ return -1;
+
+ if (HMAC_Init_ex(ctx, key, (int)key_len, EVP_md5(), NULL) != 1)
+ goto err;
+
+ if (HMAC_Update(ctx, data, data_len) != 1)
+ goto err;
+
+ if (HMAC_Final(ctx, out, &len) != 1 || len != HMAC_MD5_LEN)
+ goto err;
+
+ HMAC_CTX_free(ctx);
+ return 0;
+
+err:
+ HMAC_CTX_free(ctx);
+ return -1;
+}
+
+
int rad_packet_build(struct rad_packet_t *pack, uint8_t *RA)
{
struct rad_attr_t *attr;
@@ -302,6 +336,9 @@ void rad_packet_free(struct rad_packet_t *pack)
mempool_free(pack->buf);
//munmap(pack->buf, REQ_LENGTH_MAX);
+ if (pack->secret)
+ _free(pack->secret);
+
while(!list_empty(&pack->attrs)) {
attr = list_entry(pack->attrs.next, typeof(*attr), entry);
list_del(&attr->entry);
@@ -811,6 +848,18 @@ int rad_packet_send(struct rad_packet_t *pack, int fd, struct sockaddr_in *addr)
clock_gettime(CLOCK_MONOTONIC, &pack->tv);
+ if (pack->secret && pack->message_authenticator) {
+ uint8_t hmac[HMAC_MD5_LEN];
+ uint8_t *ptr = pack->buf;
+ uint8_t *hmac_ptr = ptr + PACKET_SIGNED_OFFSET;
+ if (hmac_md5((const uint8_t *)pack->secret, strlen(pack->secret), pack->buf, pack->len, hmac) < 0) {
+ log_emerg("radius:packet: failed to calculate HMAC\n");
+ return -1;
+ }
+ memcpy(hmac_ptr, hmac, HMAC_MD5_LEN);
+ }
+
+
while (1) {
if (addr)
n = sendto(fd, pack->buf, pack->len, 0, (struct sockaddr *)addr, sizeof(*addr));
diff --git a/accel-pppd/radius/radius.c b/accel-pppd/radius/radius.c
index 2406ba04..9fbbc467 100644
--- a/accel-pppd/radius/radius.c
+++ b/accel-pppd/radius/radius.c
@@ -58,6 +58,7 @@ static int conf_strip_realm;
const char *conf_attr_tunnel_type;
int conf_acct_delay_start;
+int conf_blast_protection;
static LIST_HEAD(sessions);
static pthread_rwlock_t sessions_lock = PTHREAD_RWLOCK_INITIALIZER;
@@ -1086,6 +1087,13 @@ static int load_config(void)
else
conf_acct_delay_start = 0;
+ opt = conf_get_opt("radius", "blast-protection");
+ if (opt && atoi(opt) > 0) {
+ conf_blast_protection = 1;
+ } else {
+ conf_blast_protection = 0;
+ }
+
return 0;
}
diff --git a/accel-pppd/radius/radius.h b/accel-pppd/radius/radius.h
index 1925c973..c19b25c2 100644
--- a/accel-pppd/radius/radius.h
+++ b/accel-pppd/radius/radius.h
@@ -103,6 +103,8 @@ struct rad_attr_t
struct rad_packet_t
{
+ int message_authenticator; // 1 if message authenticator is required
+ uint8_t *secret; // shared secret for this packet for Message-Authenticator signature
int code;
uint8_t id;
int len;
diff --git a/accel-pppd/radius/radius_p.h b/accel-pppd/radius/radius_p.h
index 87613624..06588ead 100644
--- a/accel-pppd/radius/radius_p.h
+++ b/accel-pppd/radius/radius_p.h
@@ -198,6 +198,7 @@ extern int conf_acct_interim_jitter;
extern int conf_accounting;
extern const char *conf_attr_tunnel_type;
extern int conf_acct_delay_start;
+extern int conf_blast_protection;
int rad_check_nas_pack(struct rad_packet_t *pack);
struct radius_pd_t *rad_find_session(const char *sessionid, const char *username, const char *port_id, int port, in_addr_t ipaddr, const char *csid);
diff --git a/accel-pppd/radius/req.c b/accel-pppd/radius/req.c
index be74f047..863174a2 100644
--- a/accel-pppd/radius/req.c
+++ b/accel-pppd/radius/req.c
@@ -15,6 +15,8 @@
#include "memdebug.h"
+#define HMAC_MD5_LEN 16
+
static int make_socket(struct rad_req_t *req);
static mempool_t req_pool;
@@ -73,6 +75,17 @@ static struct rad_req_t *__rad_req_alloc(struct radius_pd_t *rpd, int code, cons
if (!req->pack)
goto out_err;
+ if (code == CODE_ACCESS_REQUEST && conf_blast_protection) {
+ uint8_t buf[HMAC_MD5_LEN] = {0};
+ req->pack->message_authenticator = 1;
+ req->pack->secret = strdup(req->serv->secret);
+ if (rad_packet_add_octets(req->pack, NULL, "Message-Authenticator", buf, HMAC_MD5_LEN)) {
+ free(req->pack->secret);
+ req->pack->secret == NULL;
+ goto out_err;
+ }
+ }
+
if (code == CODE_ACCOUNTING_REQUEST && rpd->acct_username)
username = rpd->acct_username;