[ntp:hackers] Protocol specification modification for MS-SNTP

Dave Hart davehart at gmail.com
Mon Jul 6 22:13:05 UTC 2009


On Mon, Jul 6, 2009 at 9:28 PM, David Mills wrote:
>
> The Samba folks have modified ntpd to support Microsoft authentication,
> which requies some bending of the protocol specification and
> implementation. I'd like to make it much simpler, reduce the code
> clutter and support alternative digest algorithms. The present protocol
> specification requires a nonzero key ID and MD5 digest algorithm by
> default. The ntpd never generates a MAC with a zero key ID. The current
> MS-SNTP code uses a 20-octet all-zero MAC, causing ntpd to hand the
> packet off to another program which fills in the MAC. This makes MS-SNTP
> "legal" and much more likely to be supported by "official" servers.

I think there's a small misunderstanding, and it may be my fault due
to misinformation in an earlier email or bug comment of mine.  I'm
pretty sure the domain member's NTP requests to its domain controller
has 16 bytes of zeros (where the hash would be) but does not have a
zero keyid.  Instead, the keyid identifies the particular client to
the server, which uses it to select which secret (machine account
password) to use when signing the response.

I just saw Andrew Bartlett replied confirming this understanding.

> I
> propose to add something like this, either to the protocol specification
> or as an addendum:
>
> "A received MAC with a zero key ID is a special case. By default, the
> packet is treated as if the MAC were not present, so is not
> authenticated. On output the MAC is returned exactly as received and the
> packet is not authenticated. As a configurable option, an output packet
> with zero key ID can be passed to another program that fills in the MAC."
>
> In order to retain backwards compatibility, I  propose to add a new
> configuration command digest with argument the OpenSSL digest name. If
> it has 16 octets, it replaces the default MD5 algorithm, perhaps with
> HMAC-MD5. In this case it would not be compatible with servers or
> clients using MD5. If it has 20 octets, it does not replace the 16-octet
> algorithm, but can be selected according to the following rules. For an
> input packet, a MAC with either 16 octets or 20 octets selects the
> appropriate algorithm. In stateless modes the server responds using the
> same algorithm.  For stateful associations a new digest opton on the
> configuration command is used to specify the algorithm, either 16 octet
> or 20 octet.
>
> Of course, this only works if the OpenSSL library is available.

I don't think the 16-octet case occurs.  The sizes I'm familiar with
for digests are 4, 12, and 20 bytes, for crypto-NAK, DES, and
MD5/autokey.  All begin with 4 bytes of keyid.

I'm testing changes to enable the symmetric client workaround (AKA
--enable-wintime) and the Samba4 DC emulation (AKA --enable-ntp-signd)
in all builds, with an eye towards removing those knobs entirely.
I've also changed the code so that a received crypto-NAK does not
trigger a symmetric-mode response, by conditioning the symmetric
client workaround response on the incoming packet having no extension
(has_mac == 0).

I've verified the changed ntpd has a working symmetric client
workaround by using w32time to synchronize to the test ntpd without
using the ,0x8 w32time override to use client mode.  I would love to
find someone with a working autokey setup to verify the changes do not
break autokey, and similarly someone using ntpd+Samba4 to emulate a
Windows DC.

I'm inlining below a patch to 4.2.5p185, also available on
pogo:~hart/ntp-dev-1242.  Lazily, the need for --enable-ntp-signd is
not removed in this code, though the test for it in ntp_proto.c is
gone, it still controls whether send_via_ntp_signd() is stubbed out or
not.  I do intend to remove the HAVE_NTP_SIGND completely if this goes
forward, making the conditionalizing of send_via_ntp_signd() use
appropriate platform macros (basically we want it on Unix and not
other platforms for now).

It would be preferable to me if we can manage to support both Autokey
and Samba signing at the same time.  I think the only concession
needed is breaking every 2^128th autokey and MD5 signature where the
hash happens to be all zeroes.  With care, even that should be
avoidable if we treat a correctly-validated all-zeroes signature
differently from one where our computed digest differs.

Cheers,
Dave Hart

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2009/07/06 16:23:27+00:00 davehart at shiny.ad.hartbrothers.com
#   enable Windows symmetric mode hack and Samba DC emulation (signd) by default
#
# include/ntpd.h
#   2009/07/06 16:23:26+00:00 davehart at shiny.ad.hartbrothers.com +0 -2
#   send_via_ntp_signd() is no longer conditionalized on HAVE_NTP_SIGND
#
# ntpd/ntp_proto.c
#   2009/07/06 16:23:26+00:00 davehart at shiny.ad.hartbrothers.com +25 -28
#   enable Windows symmetric mode hack and Samba DC emulation (signd) by default
#
# ntpd/ntp_signd.c
#   2009/07/06 16:23:26+00:00 davehart at shiny.ad.hartbrothers.com +5 -3
#   make send_via_ntp_signd a stub routine when HAVE_NTP_SIGND is not defined
#
diff -Nrpu a/include/ntpd.h b/include/ntpd.h
--- a/include/ntpd.h	2009-07-06 16:33:14 +00:00
+++ b/include/ntpd.h	2009-07-06 16:33:14 +00:00
@@ -474,7 +474,6 @@ extern u_char	num_refclock_conf;
 #endif

 /* ntp_signd.c */
-#ifdef HAVE_NTP_SIGND
 extern void
 send_via_ntp_signd(
 	struct recvbuf *rbufp,	/* receive packet pointer */
@@ -483,4 +482,3 @@ send_via_ntp_signd(
 	int flags,
 	struct pkt  *xpkt
 	);
-#endif
diff -Nrpu a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c
--- a/ntpd/ntp_proto.c	2009-07-06 16:33:14 +00:00
+++ b/ntpd/ntp_proto.c	2009-07-06 16:33:14 +00:00
@@ -317,14 +317,12 @@ receive(
 	l_fp	p_org;			/* origin timestamp */
 	l_fp	p_rec;			/* receive timestamp */
 	l_fp	p_xmt;			/* transmit timestamp */
+	static unsigned char zero_key[16];
 #ifdef OPENSSL
 	struct autokey *ap;		/* autokey structure pointer */
 	int	rval;			/* cookie snatcher */
 	keyid_t	pkeyid = 0, tkeyid = 0;	/* key IDs */
 #endif /* OPENSSL */
-#ifdef WINTIME
-	static unsigned char zero_key[16];
-#endif /* WINTIME */

 	/*
 	 * Monitor the packet and get restrictions. Note that the packet
@@ -416,7 +414,7 @@ receive(
 			hismode = MODE_CLIENT;
 		} else {
 			sys_badlength++;
-			return;                 /* invalid mode */
+			return;			/* invalid mode */
 		}
 	}

@@ -559,11 +557,11 @@ receive(
 			    authlen + has_mac, is_authentic);
 #endif

-#ifdef WINTIME
 		/* If the signature is 20 bytes long, the last 16 of
 		 * which are zero, then this is a Microsoft client
-		 * wanting AD-style authentication of the server's
-		 * reply.
+		 * wanting AD-style authentication of the reply from
+		 * its domain controller, which may be Samba 4 plus
+		 * ntpd.
 		 *
 		 * This is described in Microsoft's WSPP docs, in MS-SNTP:
 		 * http://msdn.microsoft.com/en-us/library/cc212930.aspx
@@ -571,13 +569,13 @@ receive(
 	} else if (has_mac == MAX_MAC_LEN
 		   && (retcode == AM_FXMIT || retcode == AM_NEWPASS)
 		   && (memcmp(zero_key, (char *)pkt + authlen + 4, MAX_MAC_LEN - 4) == 0)) {
-		
-		/* Don't try to verify the zeros, just set a
-		 * flag and otherwise pretend we never saw the signature */
+
+		/*
+		 * Don't try to verify the zeros, just set a flag and
+		 * otherwise pretend we never saw the signature
+		 */
 		is_authentic = AUTH_NONE;
-		
 		flags = FLAG_ADKEY;
-#endif /* WINTIME */

 	} else {
 #ifdef OPENSSL
@@ -927,18 +925,20 @@ receive(
 		if (!AUTH(sys_authenticate | (restrict_mask &
 		    RES_NOPEER), is_authentic)) {

-#ifdef WINTIME
-			/*
-			 * If authenticated but cannot mobilize an
-			 * association, send a summetric passive
-			 * response without mobilizing an association.
-			 * This is for drat broken Windows clients. See
-			 * Microsoft KB 875424 for preferred workaround.
-			 */
-			fast_xmit(rbufp, MODE_PASSIVE, skeyid, NULL, flags);
-#else /* WINTIME */
-			sys_restricted++;
-#endif /* WINTIME */
+			if (has_mac == 0)
+				/*
+				 * If not authenticated and cannot
+				 * mobilize an association, send a
+				 * symmetric passive response without
+				 * mobilizing an association.  This is
+				 * for drat broken Windows clients.
+				 * See Microsoft KB 875424 for
+				 * preferred workaround.
+				 */
+				fast_xmit(rbufp, MODE_PASSIVE, skeyid,
+				    NULL, flags);
+			else
+				sys_restricted++;
 			return;			/* hooray */
 		}

@@ -3257,15 +3257,12 @@ fast_xmit(
 	}

 	if (flags & FLAG_ADKEY) {
-#ifdef HAVE_NTP_SIGND
 		get_systime(&xmt_tx);
 		if (mask == NULL) {
 			HTONL_FP(&xmt_tx, &xpkt.xmt);
 		}
 		send_via_ntp_signd(rbufp, xmode, xkeyid, flags, &xpkt);
-#endif
-		/* If we don't have the support, drop the packet on the floor.
-		   An all zero sig is compleatly bogus anyway */
+
 		return;
 	}

diff -Nrpu a/ntpd/ntp_signd.c b/ntpd/ntp_signd.c
--- a/ntpd/ntp_signd.c	2009-07-06 16:33:14 +00:00
+++ b/ntpd/ntp_signd.c	2009-07-06 16:33:14 +00:00
@@ -6,7 +6,6 @@
 #include <config.h>
 #endif

-#ifdef HAVE_NTP_SIGND

 #include "ntpd.h"
 #include "ntp_io.h"
@@ -22,6 +21,7 @@
 #include <unistd.h>
 #endif /* HAVE_LIBSCF_H */

+#ifdef HAVE_NTP_SIGND
 #include <sys/un.h>

 /* socket routines by tridge - from junkcode.samba.org */
@@ -120,6 +120,8 @@ recv_packet(int fd, char **buf, uint32_t
 	}
 	return 0;
 }
+#endif	/* HAVE_NTP_SIGND */
+

 void
 send_via_ntp_signd(
@@ -130,7 +132,7 @@ send_via_ntp_signd(
 	struct pkt  *xpkt
 	)
 {
-	
+#ifdef HAVE_NTP_SIGND
 	/* We are here because it was detected that the client
 	 * sent an all-zero signature, and we therefore know
 	 * it's windows trying to talk to an AD server
@@ -238,5 +240,5 @@ send_via_ntp_signd(
 		close(fd);
 		
 	}
+#endif	/* HAVE_NTP_SIGND */
 }
-#endif


More information about the hackers mailing list