dhcpcd-discuss

Re: DHCPv6 and OPTION_USER_CLASS

Roy Marples

Sun Apr 29 18:03:09 2018

On 29/04/2018 17:34, Mattieu Baptiste wrote:
Mmm, with the following conf:
ipv6only
duid
authprotocol token 0x123/0x456
authtoken 0x123 "" forever fti/xxxxxxx
authtoken 0x456 "" forever dhcpliveboxfr250
userclass FSVDSL_livebox.Internet.softathome.livebox3
vendclass 1038 sagem
persistent
noipv6rs
allowinterfaces vlan832
interface vlan832
         ia_pd 1

I now have this error:
# dhcpcd -Bd
dhcpcd-7.0.3 starting
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' PREINIT
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' CARRIER
DUID 00:01:00:06:20:f6:4d:7a:00:0d:b9:33:8e:8c
vlan832: IAID ff:00:03:40
vlan832: IAID 00:00:00:01
vlan832: reading lease `/var/db/dhcpcd/vlan832.lease6'
vlan832: soliciting a DHCPv6 lease
vlan832: delaying SOLICIT6 (xid 0xd38e24), next in 0.2 seconds
vlan832: broadcasting SOLICIT6 (xid 0xd38e24), next in 0.9 seconds
vlan832: authentication failed from fe80::ba0:bab: No such process
vlan832: broadcasting SOLICIT6 (xid 0xd38e24), next in 1.8 seconds
vlan832: authentication failed from fe80::ba0:bab: No such process
vlan832: broadcasting SOLICIT6 (xid 0xd38e24), next in 3.8 seconds
vlan832: authentication failed from fe80::ba0:bab: No such process
^Creceived SIGINT, stopping
vlan832: removing interface
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' STOPPED
dhcpcd exited


Arrrggghhhh!
I tested on a network bit orientated arch.
Attached is a corrected patch which should now work.

Let me know!

Roy
diff --git a/src/auth.c b/src/auth.c
index be7dd7ad..6592f539 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -151,7 +151,24 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
 
 	memcpy(&replay, d, sizeof(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)) {
 			/* We don't know if the singular point is increasing
 			 * or decreasing. */
@@ -174,7 +191,7 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
 	 * Rest of data is MAC. */
 	switch (protocol) {
 	case AUTH_PROTO_TOKEN:
-		secretid = 0;
+		secretid = auth->token_rcv_secretid;
 		break;
 	case AUTH_PROTO_DELAYED:
 		if (dlen < sizeof(secretid) + sizeof(hmac_code)) {
@@ -182,6 +199,7 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
 			return NULL;
 		}
 		memcpy(&secretid, d, sizeof(secretid));
+		secretid = ntohl(secretid);
 		d += sizeof(secretid);
 		dlen -= sizeof(secretid);
 		break;
@@ -197,6 +215,7 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
 			dlen -= realm_len;
 		}
 		memcpy(&secretid, d, sizeof(secretid));
+		secretid = ntohl(secretid);
 		d += sizeof(secretid);
 		dlen -= sizeof(secretid);
 		break;
@@ -266,7 +285,6 @@ dhcp_auth_validate(struct authstate *state, const struct auth *auth,
 	}
 
 	/* Find a token for the realm and secret */
-	secretid = ntohl(secretid);
 	TAILQ_FOREACH(t, &auth->tokens, next) {
 		if (t->secretid == secretid &&
 		    t->realm_len == realm_len &&
@@ -482,11 +500,10 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
 	uint32_t giaddr, secretid;
 	bool auth_info;
 
-	if (auth->protocol == 0 && t == NULL) {
+	if (auth->protocol == AUTH_PROTO_TOKEN && t == NULL) {
 		TAILQ_FOREACH(t, &auth->tokens, next) {
-			if (t->secretid == 0 &&
-			    t->realm_len == 0)
-			break;
+			if (t->secretid == auth->token_snd_secretid)
+				break;
 		}
 		if (t == NULL) {
 			errno = EINVAL;
diff --git a/src/auth.h b/src/auth.h
index ac35ba76..f65d62c3 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -71,6 +71,8 @@ struct auth {
 	uint64_t last_replay;
 	uint8_t last_replay_set;
 	struct token_head tokens;
+	uint32_t token_snd_secretid;
+	uint32_t token_rcv_secretid;
 #endif
 };
 
diff --git a/src/dhcpcd.conf.5.in b/src/dhcpcd.conf.5.in
index f1a8a8d7..d56c4dd4 100644
--- a/src/dhcpcd.conf.5.in
+++ b/src/dhcpcd.conf.5.in
@@ -74,9 +74,16 @@ Example:
 .D1 # A generic 192.168.0.1 network
 .D1 profile 192.168.0.1
 .D1 static ip_address=192.168.0.98/24
-.It Ic authprotocol Ar protocol Ar algorithm Ar rdm
+.It Ic authprotocol Ar protocol Op Ar algorithm Op Ar rdm
 Authenticate DHCP messages.
 See the Supported Authentication Protocols section.
+If
+.Ar protocol
+is
+.Ar token
+then
+.Ar algorithm is
+snd_secretid/rcv_secretid so you can send and recieve different tokens.
 .It Ic authtoken Ar secretid Ar realm Ar expire Ar key
 Define a shared key for use in authentication.
 .Ar realm
@@ -863,7 +870,11 @@ References an option from the global definition.
 .Ss Supported Authentication Protocols
 .Bl -tag -width -indent
 .It Ic token
-Sends and expects the token with the secretid 0 and realm of "" in each message.
+Sends a plain text token the server expects and matches a token sent by
+the server.
+The tokens to not have to be the same.
+If unspecified, the token with secretid of 0 will be used in sending messages
+and validating received messages.
 .It Ic delayedrealm
 Delayed Authentication.
 .Nm dhcpcd
diff --git a/src/if-options.c b/src/if-options.c
index 4eb6e6ea..5943e700 100644
--- a/src/if-options.c
+++ b/src/if-options.c
@@ -1913,12 +1913,32 @@ err_sla:
 		}
 		if (fp)
 			*fp++ = '\0';
-		if (strcasecmp(arg, "hmacmd5") == 0 ||
-		    strcasecmp(arg, "hmac-md5") == 0)
-			ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
-		else {
-			logerrx("%s: unsupported algorithm", arg);
-			return 1;
+		if (ifo->auth.protocol == AUTH_PROTO_TOKEN) {
+			np = strchr(arg, '/');
+			if (np) {
+				if (fp == NULL || np < fp)
+					*np++ = '\0';
+				else
+					np = NULL;
+			}
+			if (parse_uint32(&ifo->auth.token_snd_secretid,
+			    arg) == -1)
+				logerrx("%s: not a number", arg);
+			else
+				ifo->auth.token_rcv_secretid =
+				    ifo->auth.token_snd_secretid;
+			if (np &&
+			    parse_uint32(&ifo->auth.token_rcv_secretid,
+			    np) == -1)
+				logerrx("%s: not a number", arg);
+		} else {
+			if (strcasecmp(arg, "hmacmd5") == 0 ||
+			    strcasecmp(arg, "hmac-md5") == 0)
+				ifo->auth.algorithm = AUTH_ALG_HMAC_MD5;
+			else {
+				logerrx("%s: unsupported algorithm", arg);
+				return 1;
+			}
 		}
 		arg = fp;
 		if (arg == NULL) {

Follow-Ups:
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
References:
DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Re: DHCPv6 and OPTION_USER_CLASSRoy Marples
Re: DHCPv6 and OPTION_USER_CLASSMattieu Baptiste
Archive administrator: postmaster@marples.name