Add MessageAuthenticator support
To address RadiusBLAST vulnerability. Fixes #16
This commit is contained in:
parent
42ef80e0b4
commit
cc012e18fa
8 changed files with 149 additions and 2 deletions
|
|
@ -183,6 +183,16 @@ sending of RADIUS interim accounting records (in seconds).</p>
|
||||||
<p>This secret will be used in all RADIUS queries. If this is not set
|
<p>This secret will be used in all RADIUS queries. If this is not set
|
||||||
then RADIUS queries will fail.</p>
|
then RADIUS queries will fail.</p>
|
||||||
</dd>
|
</dd>
|
||||||
|
<dt><code>radius_require_message_authenticator</code> (string)</dt>
|
||||||
|
<dd>
|
||||||
|
<p>If set to true, RADIUS answers to AccessRequests will have to contain
|
||||||
|
a valid MessageAuthenticator. If set to auto (default), if the first
|
||||||
|
RADIUS answer to AccessRequests contains a valid MessageAuthenticator,
|
||||||
|
subsequent answers will have to contain one. If set to no (not
|
||||||
|
recommended), RADIUS answers to AccessRequests do not have to contain a
|
||||||
|
valid MessageAuthenticator. It is advised to set this to true after
|
||||||
|
checking that your RADIUS server does send MessageAuthenticator.</p>
|
||||||
|
</dd>
|
||||||
<dt><code>radius_authtypes</code> (string)</dt>
|
<dt><code>radius_authtypes</code> (string)</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<p>A comma separated list of supported RADIUS authentication methods
|
<p>A comma separated list of supported RADIUS authentication methods
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.\" Automatically generated by Pandoc 3.0.1
|
.\" Automatically generated by Pandoc 3.1.3
|
||||||
.\"
|
.\"
|
||||||
.\" Define V font for inline verbatim, using C font in formats
|
.\" Define V font for inline verbatim, using C font in formats
|
||||||
.\" that render this, and otherwise B font.
|
.\" that render this, and otherwise B font.
|
||||||
|
|
@ -360,6 +360,18 @@ RADIUS interim accounting records (in seconds).
|
||||||
This secret will be used in all RADIUS queries.
|
This secret will be used in all RADIUS queries.
|
||||||
If this is not set then RADIUS queries will fail.
|
If this is not set then RADIUS queries will fail.
|
||||||
.PP
|
.PP
|
||||||
|
\f[B]radius_require_message_authenticator\f[R] (string)
|
||||||
|
.PP
|
||||||
|
If set to true, RADIUS answers to AccessRequests will have to contain a
|
||||||
|
valid MessageAuthenticator.
|
||||||
|
If set to auto (default), if the first RADIUS answer to AccessRequests
|
||||||
|
contains a valid MessageAuthenticator, subsequent answers will have to
|
||||||
|
contain one.
|
||||||
|
If set to no (not recommended), RADIUS answers to AccessRequests do not
|
||||||
|
have to contain a valid MessageAuthenticator.
|
||||||
|
It is advised to set this to true after checking that your RADIUS server
|
||||||
|
does send MessageAuthenticator.
|
||||||
|
.PP
|
||||||
\f[B]radius_authtypes\f[R] (string)
|
\f[B]radius_authtypes\f[R] (string)
|
||||||
.PP
|
.PP
|
||||||
A comma separated list of supported RADIUS authentication methods
|
A comma separated list of supported RADIUS authentication methods
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,18 @@ should be set by a line like: set configstring \"value\" set ipaddress
|
||||||
: This secret will be used in all RADIUS queries. If this is not set
|
: This secret will be used in all RADIUS queries. If this is not set
|
||||||
then RADIUS queries will fail.
|
then RADIUS queries will fail.
|
||||||
|
|
||||||
|
`radius_require_message_authenticator` (string)
|
||||||
|
|
||||||
|
: If set to true, RADIUS answers to AccessRequests will have to contain
|
||||||
|
a valid MessageAuthenticator.
|
||||||
|
If set to auto (default), if the first RADIUS answer to AccessRequests
|
||||||
|
contains a valid MessageAuthenticator, subsequent answers will have to
|
||||||
|
contain one.
|
||||||
|
If set to no (not recommended), RADIUS answers to AccessRequests do not have
|
||||||
|
to contain a valid MessageAuthenticator.
|
||||||
|
It is advised to set this to true after checking that your RADIUS server
|
||||||
|
does send MessageAuthenticator.
|
||||||
|
|
||||||
`radius_authtypes` (string)
|
`radius_authtypes` (string)
|
||||||
|
|
||||||
: A comma separated list of supported RADIUS authentication methods
|
: A comma separated list of supported RADIUS authentication methods
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,18 @@ The following `variables` may be set:
|
||||||
|
|
||||||
This secret will be used in all RADIUS queries. If this is not set then RADIUS queries will fail.
|
This secret will be used in all RADIUS queries. If this is not set then RADIUS queries will fail.
|
||||||
|
|
||||||
|
**radius\_require\_message\_authenticator** (string)
|
||||||
|
|
||||||
|
If set to true, RADIUS answers to AccessRequests will have to contain
|
||||||
|
a valid MessageAuthenticator.
|
||||||
|
If set to auto (default), if the first RADIUS answer to AccessRequests
|
||||||
|
contains a valid MessageAuthenticator, subsequent answers will have to
|
||||||
|
contain one.
|
||||||
|
If set to no (not recommended), RADIUS answers to AccessRequests do not have
|
||||||
|
to contain a valid MessageAuthenticator.
|
||||||
|
It is advised to set this to true after checking that your RADIUS server
|
||||||
|
does send MessageAuthenticator.
|
||||||
|
|
||||||
**radius\_authtypes** (string)
|
**radius\_authtypes** (string)
|
||||||
|
|
||||||
A comma separated list of supported RADIUS authentication methods ("pap" or "chap"), in order of preference (default "pap").
|
A comma separated list of supported RADIUS authentication methods ("pap" or "chap"), in order of preference (default "pap").
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ set primary_radius 10.0.0.3
|
||||||
#set secondary_radius 0.0.0.0
|
#set secondary_radius 0.0.0.0
|
||||||
#set secondary_radius_port 1812
|
#set secondary_radius_port 1812
|
||||||
set radius_secret "secret"
|
set radius_secret "secret"
|
||||||
|
# Set this to yes once you have confirmed that your RADIUS server provides MessageAuthenticator in its responses
|
||||||
|
#set radius_require_message_authenticator auto
|
||||||
|
|
||||||
# Acceptable authentication types (pap, chap) in order of preference
|
# Acceptable authentication types (pap, chap) in order of preference
|
||||||
#set radius_authtypes "pap"
|
#set radius_authtypes "pap"
|
||||||
|
|
|
||||||
1
l2tpns.c
1
l2tpns.c
|
|
@ -166,6 +166,7 @@ config_descriptt config_values[] = {
|
||||||
CONFIG("radius_accounting", radius_accounting, BOOL),
|
CONFIG("radius_accounting", radius_accounting, BOOL),
|
||||||
CONFIG("radius_interim", radius_interim, INT),
|
CONFIG("radius_interim", radius_interim, INT),
|
||||||
CONFIG("radius_secret", radiussecret, STRING),
|
CONFIG("radius_secret", radiussecret, STRING),
|
||||||
|
CONFIG("radius_require_message_authenticator", radius_require_message_authenticator, STRING),
|
||||||
CONFIG("radius_authtypes", radius_authtypes_s, STRING),
|
CONFIG("radius_authtypes", radius_authtypes_s, STRING),
|
||||||
CONFIG("radius_dae_port", radius_dae_port, SHORT),
|
CONFIG("radius_dae_port", radius_dae_port, SHORT),
|
||||||
CONFIG("radius_bind_min", radius_bind_min, SHORT),
|
CONFIG("radius_bind_min", radius_bind_min, SHORT),
|
||||||
|
|
|
||||||
1
l2tpns.h
1
l2tpns.h
|
|
@ -732,6 +732,7 @@ typedef struct
|
||||||
int ppp_keepalive; // send echoes regardless
|
int ppp_keepalive; // send echoes regardless
|
||||||
|
|
||||||
char radiussecret[64];
|
char radiussecret[64];
|
||||||
|
char radius_require_message_authenticator[5];
|
||||||
int radius_accounting;
|
int radius_accounting;
|
||||||
int radius_interim;
|
int radius_interim;
|
||||||
in_addr_t radiusserver[MAXRADSERVER]; // radius servers
|
in_addr_t radiusserver[MAXRADSERVER]; // radius servers
|
||||||
|
|
|
||||||
99
radius.c
99
radius.c
|
|
@ -32,6 +32,10 @@ extern ip_filtert *ip_filters;
|
||||||
|
|
||||||
static const hasht zero;
|
static const hasht zero;
|
||||||
|
|
||||||
|
static enum {
|
||||||
|
MAYBE = 0, YES, NO,
|
||||||
|
} radius_sends_message_authenticator[MAXRADSERVER];
|
||||||
|
|
||||||
static void calc_auth(const void *buf, size_t len, const uint8_t *in, uint8_t *out)
|
static void calc_auth(const void *buf, size_t len, const uint8_t *in, uint8_t *out)
|
||||||
{
|
{
|
||||||
MD5_CTX ctx;
|
MD5_CTX ctx;
|
||||||
|
|
@ -163,7 +167,7 @@ void radiussend(uint16_t r, uint8_t state)
|
||||||
uint8_t b[4096]; // RADIUS packet
|
uint8_t b[4096]; // RADIUS packet
|
||||||
char pass[129];
|
char pass[129];
|
||||||
int pl;
|
int pl;
|
||||||
uint8_t *p;
|
uint8_t *p, *ma = NULL;
|
||||||
sessionidt s;
|
sessionidt s;
|
||||||
|
|
||||||
CSTAT(radiussend);
|
CSTAT(radiussend);
|
||||||
|
|
@ -237,6 +241,16 @@ void radiussend(uint16_t r, uint8_t state)
|
||||||
memcpy(b + 4, radius[r].auth, 16);
|
memcpy(b + 4, radius[r].auth, 16);
|
||||||
|
|
||||||
p = b + 20;
|
p = b + 20;
|
||||||
|
|
||||||
|
if (state == RADIUSAUTH || state == RADIUSJUSTAUTH)
|
||||||
|
{
|
||||||
|
*p = 80; // MessageAuthenticator
|
||||||
|
p[1] = 18; // length
|
||||||
|
ma = p+2;
|
||||||
|
memset(ma, 0, 16); // Zero for the computation
|
||||||
|
p += p[1];
|
||||||
|
}
|
||||||
|
|
||||||
if (s)
|
if (s)
|
||||||
{
|
{
|
||||||
*p = 1; // user name
|
*p = 1; // user name
|
||||||
|
|
@ -464,12 +478,18 @@ void radiussend(uint16_t r, uint8_t state)
|
||||||
|
|
||||||
// All AVpairs added
|
// All AVpairs added
|
||||||
*(uint16_t *) (b + 2) = htons(p - b);
|
*(uint16_t *) (b + 2) = htons(p - b);
|
||||||
|
|
||||||
if (state != RADIUSAUTH && state != RADIUSJUSTAUTH)
|
if (state != RADIUSAUTH && state != RADIUSJUSTAUTH)
|
||||||
{
|
{
|
||||||
// Build auth for accounting packet
|
// Build auth for accounting packet
|
||||||
calc_auth(b, p - b, zero, b + 4);
|
calc_auth(b, p - b, zero, b + 4);
|
||||||
memcpy(radius[r].auth, b + 4, 16);
|
memcpy(radius[r].auth, b + 4, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute MessageAuthenticator
|
||||||
|
if (ma)
|
||||||
|
MD5_Hmac(ma, b, p-b, config->radiussecret, strlen(config->radiussecret));
|
||||||
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
memset(&addr, 0, sizeof(addr));
|
||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
*(uint32_t *) & addr.sin_addr = config->radiusserver[(radius[r].try - 1) % config->numradiusservers];
|
*(uint32_t *) & addr.sin_addr = config->radiusserver[(radius[r].try - 1) % config->numradiusservers];
|
||||||
|
|
@ -587,6 +607,83 @@ void processrad(uint8_t *buf, int len, char socket_index)
|
||||||
|
|
||||||
if (radius[r].state == RADIUSAUTH || radius[r].state == RADIUSJUSTAUTH)
|
if (radius[r].state == RADIUSAUTH || radius[r].state == RADIUSJUSTAUTH)
|
||||||
{
|
{
|
||||||
|
// First check MessageAuthenticator
|
||||||
|
{
|
||||||
|
uint8_t *p = buf + 20;
|
||||||
|
uint8_t *e = buf + len;
|
||||||
|
int seen = 0, want;
|
||||||
|
|
||||||
|
for (; p + 2 <= e && p[1] && p + p[1] <= e; p += p[1])
|
||||||
|
{
|
||||||
|
if (*p == 80)
|
||||||
|
{
|
||||||
|
// MessageAuthenticator
|
||||||
|
uint8_t auth[16];
|
||||||
|
uint8_t authcheck[16];
|
||||||
|
uint8_t vector[16];
|
||||||
|
|
||||||
|
/* Set original vector for computation */
|
||||||
|
memcpy(vector, buf+4, 16);
|
||||||
|
memcpy(buf+4, radius[r].auth, 16);
|
||||||
|
|
||||||
|
/* Set authenticator to zero for computation */
|
||||||
|
memcpy(auth, p+2, 16);
|
||||||
|
memset(p+2, 0, 16);
|
||||||
|
|
||||||
|
MD5_Hmac(authcheck, buf, len, config->radiussecret, strlen(config->radiussecret));
|
||||||
|
if (memcmp(auth, authcheck, 16) != 0)
|
||||||
|
{
|
||||||
|
LOG(1, 0, 0, "Incorrect MessageAuthenticator in Access reply (wrong secret in radius config?)\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore vector */
|
||||||
|
memcpy(buf+4, vector, 16);
|
||||||
|
|
||||||
|
/* Restore authenticator */
|
||||||
|
memcpy(p+2, auth, 16);
|
||||||
|
|
||||||
|
seen = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp(config->radius_require_message_authenticator, "no"))
|
||||||
|
want = 0;
|
||||||
|
else if (!strcmp(config->radius_require_message_authenticator, "yes"))
|
||||||
|
want = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (config->radius_require_message_authenticator[0]
|
||||||
|
&& strcmp(config->radius_require_message_authenticator, "auto"))
|
||||||
|
LOG(1, 0, 0, "Unrecognized radius_require_message_authenticator '%s', assuming auto\n",
|
||||||
|
config->radius_require_message_authenticator);
|
||||||
|
|
||||||
|
int num = radius[r].try % config->numradiusservers;
|
||||||
|
|
||||||
|
switch (radius_sends_message_authenticator[num]) {
|
||||||
|
case YES:
|
||||||
|
want = 1;
|
||||||
|
break;
|
||||||
|
case NO:
|
||||||
|
want = 0;
|
||||||
|
break;
|
||||||
|
case MAYBE:
|
||||||
|
want = seen;
|
||||||
|
if (seen)
|
||||||
|
radius_sends_message_authenticator[num] = YES;
|
||||||
|
else
|
||||||
|
radius_sends_message_authenticator[num] = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (want && !seen)
|
||||||
|
{
|
||||||
|
LOG(1, 0, 0, "Missing MessageAuthenticator in Access reply\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// run post-auth plugin
|
// run post-auth plugin
|
||||||
struct param_post_auth packet = {
|
struct param_post_auth packet = {
|
||||||
&tunnel[t],
|
&tunnel[t],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue