dhcpcd-discuss

Re: DHCPv6 and OPTION_USER_CLASS

Roy Marples

Sun Apr 29 18:40:53 2018

On 29/04/2018 19:28, Mattieu Baptiste wrote:
Great, it works! It just seem to have a little trouble when
relaunching (see below).

# 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 0x790333), next in 0.5 seconds
vlan832: broadcasting SOLICIT6 (xid 0x790333), next in 1.1 seconds
vlan832: validated using 0x00001110
vlan832: ADV 2a01:cb00:7c8:7f00::/56 from fe80::ba0:bab
vlan832: broadcasting REQUEST6 (xid 0x422f0f), next in 1.0 seconds
vlan832: validated using 0x00001110
vlan832: REPLY6 received from fe80::ba0:bab
vlan832: renew in 36957, rebind in 207360, expire in 259200 seconds
lo0: adding reject route to 2a01:cb00:7c8:7f00::/56 via ::1
vlan832: writing lease `/var/db/dhcpcd/vlan832.lease6'
vlan832: delegated prefix 2a01:cb00:7c8:7f00::/56
vlan832: executing `/usr/local/libexec/dhcpcd-run-hooks' BOUND6

One out of two times, when I launch dhcpcd in debug mode, it fails again with:
vlan832: broadcasting SOLICIT6 (xid 0x567cb9), next in 1.0 seconds
vlan832: broadcasting SOLICIT6 (xid 0x567cb9), next in 2.1 seconds
vlan832: broadcasting SOLICIT6 (xid 0x567cb9), next in 4.1 seconds

Dumping the trafic, when sending Rebind and then Solicit, it tries to
use the server token, and not the client one:
Authentication
     Option: Authentication (11)
     Length: 27
     Value: 000000de908bb0960efd44646863706c697665626f786672...
     Protocol: 0
     Algorithm: 0
     RDM: 0
     Replay Detection: de908bb0960efd44
     Authentication Information: 646863706c697665626f786672323530


Yes.
I've adjusted the patch to solve this. I need to test more fully as a result of the change, but I don't see any reason why it would break other protocols.

Roy
diff --git a/src/auth.c b/src/auth.c
index be7dd7ad..a272e93d 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,12 @@ dhcp_auth_encode(struct auth *auth, const struct token *t,
 	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) {
-			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