ntp: move auth parsing to ntp_auth
Move the remaining authentication-specific code to the new file.
This commit is contained in:
parent
ca28dbd2c3
commit
56a102ed4d
3 changed files with 122 additions and 106 deletions
115
ntp_auth.c
115
ntp_auth.c
|
@ -32,6 +32,7 @@
|
|||
#include "logging.h"
|
||||
#include "memory.h"
|
||||
#include "ntp_auth.h"
|
||||
#include "ntp_ext.h"
|
||||
#include "ntp_signd.h"
|
||||
#include "srcparams.h"
|
||||
#include "util.h"
|
||||
|
@ -109,6 +110,19 @@ adjust_timestamp(NTP_AuthMode mode, uint32_t key_id, struct timespec *ts)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_zero_data(unsigned char *data, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (data[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static NAU_Instance
|
||||
create_instance(NTP_AuthMode mode)
|
||||
{
|
||||
|
@ -220,6 +234,107 @@ NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketIn
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||
{
|
||||
int parsed, remainder, ef_length, ef_type;
|
||||
unsigned char *data;
|
||||
|
||||
data = (void *)packet;
|
||||
parsed = NTP_HEADER_LENGTH;
|
||||
remainder = info->length - parsed;
|
||||
|
||||
info->ext_fields = 0;
|
||||
|
||||
/* Check if this is a plain NTP packet with no extension fields or MAC */
|
||||
if (remainder <= 0)
|
||||
return 1;
|
||||
|
||||
/* In NTPv3 and older packets don't have extension fields. Anything after
|
||||
the header is assumed to be a MAC. */
|
||||
if (info->version <= 3) {
|
||||
info->auth.mode = AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
|
||||
/* Check if it is an MS-SNTP authenticator field or extended authenticator
|
||||
field with zeroes as digest */
|
||||
if (info->version == 3 && info->auth.mac.key_id) {
|
||||
if (remainder == 20 && is_zero_data(data + parsed + 4, remainder - 4))
|
||||
info->auth.mode = AUTH_MSSNTP;
|
||||
else if (remainder == 72 && is_zero_data(data + parsed + 8, remainder - 8))
|
||||
info->auth.mode = AUTH_MSSNTP_EXT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for a crypto NAK */
|
||||
if (remainder == 4 && ntohl(*(uint32_t *)(data + parsed)) == 0) {
|
||||
info->auth.mode = AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the rest of the NTPv4 packet */
|
||||
|
||||
while (remainder > 0) {
|
||||
/* 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. */
|
||||
|
||||
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= NTP_MAX_MAC_LENGTH) {
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
if (remainder <= NTP_MAX_V4_MAC_LENGTH ||
|
||||
KEY_CheckAuth(info->auth.mac.key_id, data, parsed, (void *)(data + parsed + 4),
|
||||
remainder - 4, NTP_MAX_MAC_LENGTH - 4))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if this is a valid NTPv4 extension field and skip it */
|
||||
if (!NEF_ParseField(packet, info->length, parsed, &ef_length, &ef_type, NULL, NULL)) {
|
||||
/* Invalid MAC or format error */
|
||||
DEBUG_LOG("Invalid format or MAC");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ef_length > 0);
|
||||
|
||||
switch (ef_type) {
|
||||
default:
|
||||
DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type);
|
||||
}
|
||||
|
||||
info->ext_fields++;
|
||||
parsed += ef_length;
|
||||
remainder = info->length - parsed;
|
||||
}
|
||||
|
||||
if (remainder == 0) {
|
||||
/* No MAC */
|
||||
return 1;
|
||||
} else if (remainder >= NTP_MIN_MAC_LENGTH) {
|
||||
/* This is not 100% reliable as a MAC could fail to authenticate and could
|
||||
pass as an extension field, leaving reminder smaller than the minimum MAC
|
||||
length */
|
||||
info->auth.mode = AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Invalid format");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info)
|
||||
{
|
||||
|
|
|
@ -56,6 +56,9 @@ extern void NAU_AdjustRequestTimestamp(NAU_Instance instance, struct timespec *t
|
|||
extern int NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request,
|
||||
NTP_PacketInfo *info);
|
||||
|
||||
/* Parse a request or response to detect the authentication mode */
|
||||
extern int NAU_ParsePacket(NTP_Packet *packet, NTP_PacketInfo *info);
|
||||
|
||||
/* Verify that a request is authentic */
|
||||
extern int NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info);
|
||||
|
||||
|
|
110
ntp_core.c
110
ntp_core.c
|
@ -32,7 +32,6 @@
|
|||
#include "array.h"
|
||||
#include "ntp_auth.h"
|
||||
#include "ntp_core.h"
|
||||
#include "ntp_ext.h"
|
||||
#include "ntp_io.h"
|
||||
#include "memory.h"
|
||||
#include "sched.h"
|
||||
|
@ -44,7 +43,6 @@
|
|||
#include "util.h"
|
||||
#include "conf.h"
|
||||
#include "logging.h"
|
||||
#include "keys.h"
|
||||
#include "addrfilt.h"
|
||||
#include "clientlog.h"
|
||||
|
||||
|
@ -1268,25 +1266,9 @@ transmit_timeout(void *arg)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
is_zero_data(unsigned char *data, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (data[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
|
||||
{
|
||||
int parsed, remainder, ef_length, ef_type;
|
||||
unsigned char *data;
|
||||
|
||||
if (length < NTP_HEADER_LENGTH || length % 4U != 0) {
|
||||
DEBUG_LOG("NTP packet has invalid length %d", length);
|
||||
return 0;
|
||||
|
@ -1303,95 +1285,11 @@ parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
data = (void *)packet;
|
||||
parsed = NTP_HEADER_LENGTH;
|
||||
remainder = length - parsed;
|
||||
/* Parse authentication extension fields or MAC */
|
||||
if (!NAU_ParsePacket(packet, info))
|
||||
return 0;
|
||||
|
||||
/* Check if this is a plain NTP packet with no extension fields or MAC */
|
||||
if (remainder == 0)
|
||||
return 1;
|
||||
|
||||
/* In NTPv3 and older packets don't have extension fields. Anything after
|
||||
the header is assumed to be a MAC. */
|
||||
if (info->version <= 3) {
|
||||
info->auth.mode = AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
|
||||
/* Check if it is an MS-SNTP authenticator field or extended authenticator
|
||||
field with zeroes as digest */
|
||||
if (info->version == 3 && info->auth.mac.key_id) {
|
||||
if (remainder == 20 && is_zero_data(data + parsed + 4, remainder - 4))
|
||||
info->auth.mode = AUTH_MSSNTP;
|
||||
else if (remainder == 72 && is_zero_data(data + parsed + 8, remainder - 8))
|
||||
info->auth.mode = AUTH_MSSNTP_EXT;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check for a crypto NAK */
|
||||
if (remainder == 4 && ntohl(*(uint32_t *)(data + parsed)) == 0) {
|
||||
info->auth.mode = AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Parse the rest of the NTPv4 packet */
|
||||
|
||||
while (remainder > 0) {
|
||||
/* 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. */
|
||||
|
||||
if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= NTP_MAX_MAC_LENGTH) {
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
if (remainder <= NTP_MAX_V4_MAC_LENGTH ||
|
||||
KEY_CheckAuth(info->auth.mac.key_id, data, parsed, (void *)(data + parsed + 4),
|
||||
remainder - 4, NTP_MAX_MAC_LENGTH - 4))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if this is a valid NTPv4 extension field and skip it */
|
||||
if (!NEF_ParseField(packet, length, parsed, &ef_length, &ef_type, NULL, NULL)) {
|
||||
/* Invalid MAC or format error */
|
||||
DEBUG_LOG("Invalid format or MAC");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ef_length > 0);
|
||||
|
||||
switch (ef_type) {
|
||||
default:
|
||||
DEBUG_LOG("Unknown extension field type=%x", (unsigned int)ef_type);
|
||||
}
|
||||
|
||||
info->ext_fields++;
|
||||
parsed += ef_length;
|
||||
remainder = length - parsed;
|
||||
}
|
||||
|
||||
if (remainder == 0) {
|
||||
/* No MAC */
|
||||
return 1;
|
||||
} else if (remainder >= NTP_MIN_MAC_LENGTH) {
|
||||
/* This is not 100% reliable as a MAC could fail to authenticate and could
|
||||
pass as an extension field, leaving reminder smaller than the minimum MAC
|
||||
length */
|
||||
info->auth.mode = AUTH_SYMMETRIC;
|
||||
info->auth.mac.start = parsed;
|
||||
info->auth.mac.length = remainder;
|
||||
info->auth.mac.key_id = ntohl(*(uint32_t *)(data + parsed));
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG_LOG("Invalid format");
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
|
Loading…
Reference in a new issue