ntp: accept NTPv4 packets with truncated MACs

In order to allow deterministic parsing of NTPv4 extension fields, the
MAC must not be longer than 192 bits (RFC 7822). One way to get around
this limitation when using symmetric keys which produce longer MACs is
to truncate them to 192 bits (32-bit key ID and 160-bit hash).

Modify the code to accept NTPv4 packets with MACs truncated to 192
bits, but still allow long MACs in NTPv4 packets to not break
compatibility with older chrony clients.
This commit is contained in:
Miroslav Lichvar 2016-11-29 12:52:20 +01:00
parent 38c4a7ff97
commit 89b127bf6c
2 changed files with 27 additions and 9 deletions

4
ntp.h
View file

@ -56,6 +56,10 @@ typedef uint32_t NTP_int32;
#define NTP_MIN_MAC_LENGTH (4 + 16)
#define NTP_MAX_MAC_LENGTH (4 + MAX_HASH_LENGTH)
/* The maximum length of MAC in NTPv4 packets which allows deterministic
parsing of extension fields (RFC 7822) */
#define NTP_MAX_V4_MAC_LENGTH (4 + 20)
/* Type definition for leap bits */
typedef enum {
LEAP_Normal = 0,

View file

@ -1162,7 +1162,7 @@ static int
check_packet_auth(NTP_Packet *pkt, int length,
AuthenticationMode *auth_mode, uint32_t *key_id)
{
int i, version, remainder, ext_length;
int i, version, remainder, ext_length, max_mac_length;
unsigned char *data;
uint32_t id;
@ -1175,15 +1175,28 @@ check_packet_auth(NTP_Packet *pkt, int length,
while (1) {
remainder = length - i;
/* Check if the remaining data is a valid MAC. This needs to be done
before trying to parse it as an extension field, because we support
MACs longer than the shortest valid extension field. */
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= NTP_MAX_MAC_LENGTH) {
/* Check if the remaining data is a valid MAC. There is a limit on MAC
length in NTPv4 packets to allow deterministic parsing of extension
fields (RFC 7822), but we need to support longer MACs to not break
compatibility with older chrony clients. This needs to be done before
trying to parse the data as an extension field. */
max_mac_length = version == 4 && remainder <= NTP_MAX_V4_MAC_LENGTH ?
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= max_mac_length) {
id = ntohl(*(uint32_t *)(data + i));
if (KEY_CheckAuth(id, (void *)pkt, i, (void *)(data + i + 4),
remainder - 4, NTP_MAX_MAC_LENGTH - 4)) {
remainder - 4, max_mac_length - 4)) {
*auth_mode = AUTH_SYMMETRIC;
*key_id = id;
/* If it's an NTPv4 packet with long MAC and no extension fields,
rewrite the version in the packet to respond with long MAC too */
if (version == 4 && NTP_NORMAL_PACKET_LENGTH + remainder == length &&
remainder > NTP_MAX_V4_MAC_LENGTH)
pkt->lvm = NTP_LVM(NTP_LVM_TO_LEAP(pkt->lvm), 3, NTP_LVM_TO_MODE(pkt->lvm));
return 1;
}
}
@ -1234,7 +1247,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
{
SST_Stats stats;
int pkt_leap;
int pkt_leap, pkt_version;
uint32_t pkt_refid, pkt_key_id;
double pkt_root_delay;
double pkt_root_dispersion;
@ -1292,6 +1305,7 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->report.total_rx_count++;
pkt_leap = NTP_LVM_TO_LEAP(message->lvm);
pkt_version = NTP_LVM_TO_VERSION(message->lvm);
pkt_refid = ntohl(message->reference_id);
pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay);
pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion);
@ -1597,8 +1611,8 @@ receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
inst->report.remote_addr = inst->remote_addr.ip_addr;
inst->report.local_addr = inst->local_addr.ip_addr;
inst->report.remote_port = inst->remote_addr.port;
inst->report.leap = NTP_LVM_TO_LEAP(message->lvm);
inst->report.version = NTP_LVM_TO_VERSION(message->lvm);
inst->report.leap = pkt_leap;
inst->report.version = pkt_version;
inst->report.mode = NTP_LVM_TO_MODE(message->lvm);
inst->report.stratum = message->stratum;
inst->report.poll = message->poll;