version 1.1.1.1.8.1, 2018/01/13 21:35:30 |
version 1.1.1.1.8.2, 2018/06/07 18:34:03 |
Line 151 dhcp_auth_validate(struct authstate *sta |
|
Line 151 dhcp_auth_validate(struct authstate *sta |
|
|
|
memcpy(&replay, d, sizeof(replay)); |
memcpy(&replay, d, sizeof(replay)); |
replay = ntohll(replay); |
replay = ntohll(replay); |
if (state->token) { |
/* |
|
* Test for a replay attack. |
|
* |
|
* NOTE: Some servers always send a replay data value of zero. |
|
* This is strictly compliant with RFC 3315 and 3318 which say: |
|
* "If the RDM field contains 0x00, the replay detection field MUST be |
|
* set to the value of a monotonically increasing counter." |
|
* An example of a monotonically increasing sequence is: |
|
* 1, 2, 2, 2, 2, 2, 2 |
|
* Errata 3474 updates RFC 3318 to say: |
|
* "If the RDM field contains 0x00, the replay detection field MUST be |
|
* set to the value of a strictly increasing counter." |
|
* |
|
* Taking the above into account, dhcpcd will only test for |
|
* strictly speaking replay attacks if it receives any non zero |
|
* replay data to validate against. |
|
*/ |
|
if (state->token && state->replay != 0) { |
if (state->replay == (replay ^ 0x8000000000000000ULL)) { |
if (state->replay == (replay ^ 0x8000000000000000ULL)) { |
/* We don't know if the singular point is increasing |
/* We don't know if the singular point is increasing |
* or decreasing. */ |
* or decreasing. */ |
Line 174 dhcp_auth_validate(struct authstate *sta |
|
Line 191 dhcp_auth_validate(struct authstate *sta |
|
* Rest of data is MAC. */ |
* Rest of data is MAC. */ |
switch (protocol) { |
switch (protocol) { |
case AUTH_PROTO_TOKEN: |
case AUTH_PROTO_TOKEN: |
secretid = 0; |
secretid = auth->token_rcv_secretid; |
break; |
break; |
case AUTH_PROTO_DELAYED: |
case AUTH_PROTO_DELAYED: |
if (dlen < sizeof(secretid) + sizeof(hmac_code)) { |
if (dlen < sizeof(secretid) + sizeof(hmac_code)) { |
Line 182 dhcp_auth_validate(struct authstate *sta |
|
Line 199 dhcp_auth_validate(struct authstate *sta |
|
return NULL; |
return NULL; |
} |
} |
memcpy(&secretid, d, sizeof(secretid)); |
memcpy(&secretid, d, sizeof(secretid)); |
|
secretid = ntohl(secretid); |
d += sizeof(secretid); |
d += sizeof(secretid); |
dlen -= sizeof(secretid); |
dlen -= sizeof(secretid); |
break; |
break; |
Line 197 dhcp_auth_validate(struct authstate *sta |
|
Line 215 dhcp_auth_validate(struct authstate *sta |
|
dlen -= realm_len; |
dlen -= realm_len; |
} |
} |
memcpy(&secretid, d, sizeof(secretid)); |
memcpy(&secretid, d, sizeof(secretid)); |
|
secretid = ntohl(secretid); |
d += sizeof(secretid); |
d += sizeof(secretid); |
dlen -= sizeof(secretid); |
dlen -= sizeof(secretid); |
break; |
break; |
Line 266 dhcp_auth_validate(struct authstate *sta |
|
Line 285 dhcp_auth_validate(struct authstate *sta |
|
} |
} |
|
|
/* Find a token for the realm and secret */ |
/* Find a token for the realm and secret */ |
secretid = ntohl(secretid); |
|
TAILQ_FOREACH(t, &auth->tokens, next) { |
TAILQ_FOREACH(t, &auth->tokens, next) { |
if (t->secretid == secretid && |
if (t->secretid == secretid && |
t->realm_len == realm_len && |
t->realm_len == realm_len && |
Line 478 dhcp_auth_encode(struct auth *auth, cons |
|
Line 496 dhcp_auth_encode(struct auth *auth, cons |
|
uint64_t rdm; |
uint64_t rdm; |
uint8_t hmac_code[HMAC_LENGTH]; |
uint8_t hmac_code[HMAC_LENGTH]; |
time_t now; |
time_t now; |
uint8_t hops, *p, info, *m, *data; |
uint8_t hops, *p, *m, *data; |
uint32_t giaddr, secretid; |
uint32_t giaddr, secretid; |
|
bool auth_info; |
|
|
if (auth->protocol == 0 && t == NULL) { |
/* Ignore the token argument given to us - always send using the |
|
* configured token. */ |
|
if (auth->protocol == AUTH_PROTO_TOKEN) { |
TAILQ_FOREACH(t, &auth->tokens, next) { |
TAILQ_FOREACH(t, &auth->tokens, next) { |
if (t->secretid == 0 && |
if (t->secretid == auth->token_snd_secretid) |
t->realm_len == 0) |
break; |
break; |
|
} |
} |
if (t == NULL) { |
if (t == NULL) { |
errno = EINVAL; |
errno = EINVAL; |
Line 532 dhcp_auth_encode(struct auth *auth, cons |
|
Line 552 dhcp_auth_encode(struct auth *auth, cons |
|
/* DISCOVER or INFORM messages don't write auth info */ |
/* DISCOVER or INFORM messages don't write auth info */ |
if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) || |
if ((mp == 4 && (mt == DHCP_DISCOVER || mt == DHCP_INFORM)) || |
(mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ))) |
(mp == 6 && (mt == DHCP6_SOLICIT || mt == DHCP6_INFORMATION_REQ))) |
info = 0; |
auth_info = false; |
else |
else |
info = 1; |
auth_info = true; |
|
|
/* Work out the auth area size. |
/* Work out the auth area size. |
* We only need to do this for DISCOVER messages */ |
* We only need to do this for DISCOVER messages */ |
Line 545 dhcp_auth_encode(struct auth *auth, cons |
|
Line 565 dhcp_auth_encode(struct auth *auth, cons |
|
dlen += t->key_len; |
dlen += t->key_len; |
break; |
break; |
case AUTH_PROTO_DELAYEDREALM: |
case AUTH_PROTO_DELAYEDREALM: |
if (info && t) |
if (auth_info && t) |
dlen += t->realm_len; |
dlen += t->realm_len; |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case AUTH_PROTO_DELAYED: |
case AUTH_PROTO_DELAYED: |
if (info && t) |
if (auth_info && t) |
dlen += sizeof(t->secretid) + sizeof(hmac_code); |
dlen += sizeof(t->secretid) + sizeof(hmac_code); |
break; |
break; |
} |
} |
Line 572 dhcp_auth_encode(struct auth *auth, cons |
|
Line 592 dhcp_auth_encode(struct auth *auth, cons |
|
/* Write out our option */ |
/* Write out our option */ |
*data++ = auth->protocol; |
*data++ = auth->protocol; |
*data++ = auth->algorithm; |
*data++ = auth->algorithm; |
*data++ = auth->rdm; |
/* |
switch (auth->rdm) { |
* RFC 3315 21.4.4.1 says that SOLICIT in DELAYED authentication |
case AUTH_RDM_MONOTONIC: |
* should not set RDM or it's data. |
rdm = get_next_rdm_monotonic(auth); |
* An expired draft draft-ietf-dhc-dhcpv6-clarify-auth-01 suggets |
break; |
* this should not be set for INFORMATION REQ messages as well, |
default: |
* which is probably a good idea because both states start from zero. |
/* This block appeases gcc, clang doesn't need it */ |
*/ |
rdm = get_next_rdm_monotonic(auth); |
if (auth_info || |
break; |
!(auth->protocol & (AUTH_PROTO_DELAYED | AUTH_PROTO_DELAYEDREALM))) |
|
{ |
|
*data++ = auth->rdm; |
|
switch (auth->rdm) { |
|
case AUTH_RDM_MONOTONIC: |
|
rdm = get_next_rdm_monotonic(auth); |
|
break; |
|
default: |
|
/* This block appeases gcc, clang doesn't need it */ |
|
rdm = get_next_rdm_monotonic(auth); |
|
break; |
|
} |
|
rdm = htonll(rdm); |
|
memcpy(data, &rdm, 8); |
|
} else { |
|
*data++ = 0; /* rdm */ |
|
memset(data, 0, 8); /* replay detection data */ |
} |
} |
rdm = htonll(rdm); |
|
memcpy(data, &rdm, 8); |
|
data += 8; |
data += 8; |
dlen -= 1 + 1 + 1 + 8; |
dlen -= 1 + 1 + 1 + 8; |
|
|
Line 603 dhcp_auth_encode(struct auth *auth, cons |
|
Line 637 dhcp_auth_encode(struct auth *auth, cons |
|
} |
} |
|
|
/* DISCOVER or INFORM messages don't write auth info */ |
/* DISCOVER or INFORM messages don't write auth info */ |
if (!info) |
if (!auth_info) |
return (ssize_t)dlen; |
return (ssize_t)dlen; |
|
|
/* Loading a saved lease without an authentication option */ |
/* Loading a saved lease without an authentication option */ |