diff options
| author | Denys Fedoryshchenko <denys.f@collabora.com> | 2025-06-25 22:31:08 +0300 |
|---|---|---|
| committer | Denys Fedoryshchenko <denys.f@collabora.com> | 2025-07-01 14:32:13 +0300 |
| commit | 1ce263f13ac0b3aed3b14b4a9bb6a51afe210684 (patch) | |
| tree | ce765094676327c751586010e65ce4af4545f262 | |
| parent | e06f5b835eb3ef28a2489ca903bc410175225c11 (diff) | |
| download | accel-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.conf | 1 | ||||
| -rw-r--r-- | accel-pppd/accel-ppp.conf.5 | 5 | ||||
| -rw-r--r-- | accel-pppd/radius/dm_coa.c | 1 | ||||
| -rw-r--r-- | accel-pppd/radius/packet.c | 51 | ||||
| -rw-r--r-- | accel-pppd/radius/radius.c | 8 | ||||
| -rw-r--r-- | accel-pppd/radius/radius.h | 2 | ||||
| -rw-r--r-- | accel-pppd/radius/radius_p.h | 1 | ||||
| -rw-r--r-- | accel-pppd/radius/req.c | 13 |
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; |
