Change to using a NTP time stamp for Replay Detection as that seems

to be the norm.
This commit is contained in:
Roy Marples 2014-01-30 13:04:42 +00:00
parent 35fef8ed25
commit cf0840eff5
5 changed files with 64 additions and 22 deletions

54
auth.c
View File

@ -123,19 +123,26 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
errno = EPERM;
return NULL;
}
dlen -= 3;
memcpy(&replay, d, sizeof(replay));
replay = ntohll(replay);
if (state->token) {
if (state->replay == (replay ^ 0x8000000000000000ULL)) {
/* We don't know if the singular point is increasing
* or decreasing. */
errno = EPERM;
return NULL;
}
if ((uint64_t)(replay - state->replay) <= 0) {
/* Replay attack detected */
errno = EPERM;
return NULL;
}
}
d+= sizeof(replay);
dlen -= sizeof(replay);
if (state->token && replay - state->replay <= 0) {
/* Replay attack detected */
errno = EPERM;
return NULL;
}
realm = NULL;
realm_len = 0;
@ -302,7 +309,7 @@ finish:
static uint64_t last_rdm;
static uint8_t last_rdm_set;
static uint64_t
get_next_rdm_monotonic(void)
get_next_rdm_monotonic_counter(void)
{
FILE *fp;
char *line, *ep;
@ -346,6 +353,33 @@ get_next_rdm_monotonic(void)
return rdm;
}
#define JAN_1970 2208988800UL /* 1970 - 1900 in seconds */
static uint64_t
get_next_rdm_monotonic_clock(void)
{
struct timespec ts;
uint32_t pack[2];
double frac;
uint64_t rdm;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
return ++last_rdm; /* report error? */
pack[0] = htonl((uint32_t)ts.tv_sec + JAN_1970);
frac = (ts.tv_nsec / 1e9 * 0x100000000ULL);
pack[1] = htonl((uint32_t)frac);
memcpy(&rdm, &pack, sizeof(rdm));
return rdm;
}
static uint64_t
get_next_rdm_monotonic(const struct auth *auth)
{
if (auth->options & DHCPCD_AUTH_RDM_COUNTER)
return get_next_rdm_monotonic_counter();
return get_next_rdm_monotonic_clock();
}
/*
* Encode a DHCP message.
@ -459,11 +493,11 @@ dhcp_auth_encode(const struct auth *auth, const struct token *t,
*data++ = auth->rdm;
switch (auth->rdm) {
case AUTH_RDM_MONOTONIC:
rdm = get_next_rdm_monotonic();
rdm = get_next_rdm_monotonic(auth);
break;
default:
/* This block appeases gcc, clang doesn't need it */
rdm = get_next_rdm_monotonic();
rdm = get_next_rdm_monotonic(auth);
break;
}
rdm = htonll(rdm);

1
auth.h
View File

@ -32,6 +32,7 @@
#define DHCPCD_AUTH_SEND (1 << 0)
#define DHCPCD_AUTH_REQUIRE (1 << 1)
#define DHCPCD_AUTH_RDM_COUNTER (1 << 2)
#define AUTH_PROTO_TOKEN 0
#define AUTH_PROTO_DELAYED 1

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd January 24, 2014
.Dd January 30, 2014
.Dt DHCPCD 8
.Os
.Sh NAME
@ -661,12 +661,3 @@ RFC\ 5969, RFC\ 6106.
.Sh BUGS
Please report them to
.Lk http://roy.marples.name/projects/dhcpcd
.Pp
If authentication is used and the
.Pa @DBDIR@/dhcpcd-rdm.monotonic
file is removed or altered then the DHCP server will need it's notion
of the last replay value
.Nm
sent reset.
We could change this to use a NTP time stamp instead, but it's
more likely the RTC on this host is broken which would cause the same result.

View File

@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd January 29, 2014
.Dd January 30, 2014
.Dt DHCPCD.CONF 5
.Os
.Sh NAME
@ -683,8 +683,20 @@ is the default.
If none specified,
.Ic monotonic
is the default.
If this is changed from what was previously used,
or the means of calculating or storing it is broken then the DHCP server
will probably have to have its notion of the clients Replay Detection Value
reset.
.Bl -tag -width -indent
.It Ic monocounter
Read the number in the file
.Pa @DBDIR@/dhcpcd-rdm.monotonic
and add one to it.
.It Ic monotime
Create a NTP timestamp from the system time.
.It Ic monotonic
Same as
.Ic monotime .
.El
.Sh SEE ALSO
.Xr fnmatch 3 ,

View File

@ -1609,7 +1609,11 @@ parse_option(const char *ifname, struct if_options *ifo,
ifo->auth.rdm = AUTH_RDM_MONOTONIC;
break;
}
if (strcasecmp(arg, "monotonic") == 0)
if (strcasecmp(arg, "monocounter") == 0) {
ifo->auth.rdm = AUTH_RDM_MONOTONIC;
ifo->auth.options |= DHCPCD_AUTH_RDM_COUNTER;
} else if (strcasecmp(arg, "monotonic") ==0 ||
strcasecmp(arg, "monotime") == 0)
ifo->auth.rdm = AUTH_RDM_MONOTONIC;
else {
syslog(LOG_ERR, "%s: unsupported RDM", arg);