ntp: refactor authentication
Move most of the authentication-specific code to a new file and introduce authenticator instances in order to support other authentication mechanisms (e.g. NTS).
This commit is contained in:
parent
588785e160
commit
ca28dbd2c3
5 changed files with 452 additions and 135 deletions
2
configure
vendored
2
configure
vendored
|
@ -483,7 +483,7 @@ fi
|
||||||
|
|
||||||
if [ $feat_ntp = "1" ]; then
|
if [ $feat_ntp = "1" ]; then
|
||||||
add_def FEAT_NTP
|
add_def FEAT_NTP
|
||||||
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o"
|
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_auth.o ntp_core.o ntp_ext.o ntp_io.o ntp_sources.o"
|
||||||
if [ $feat_ntp_signd = "1" ]; then
|
if [ $feat_ntp_signd = "1" ]; then
|
||||||
add_def FEAT_SIGND
|
add_def FEAT_SIGND
|
||||||
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
|
EXTRA_OBJECTS="$EXTRA_OBJECTS ntp_signd.o"
|
||||||
|
|
310
ntp_auth.c
Normal file
310
ntp_auth.c
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
/*
|
||||||
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
|
**********************************************************************
|
||||||
|
* Copyright (C) Miroslav Lichvar 2019
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
NTP authentication
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "sysincl.h"
|
||||||
|
|
||||||
|
#include "keys.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "ntp_auth.h"
|
||||||
|
#include "ntp_signd.h"
|
||||||
|
#include "srcparams.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* Structure to hold authentication configuration and state */
|
||||||
|
|
||||||
|
struct NAU_Instance_Record {
|
||||||
|
NTP_AuthMode mode; /* Authentication mode of NTP packets */
|
||||||
|
uint32_t key_id; /* Identifier of a symmetric key */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static int
|
||||||
|
generate_symmetric_auth(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info)
|
||||||
|
{
|
||||||
|
int auth_len, max_auth_len;
|
||||||
|
|
||||||
|
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
|
||||||
|
of extension fields (RFC 7822) */
|
||||||
|
max_auth_len = (info->version == 4 ? NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH) - 4;
|
||||||
|
max_auth_len = MIN(max_auth_len, sizeof (NTP_Packet) - info->length - 4);
|
||||||
|
|
||||||
|
auth_len = KEY_GenerateAuth(key_id, (unsigned char *)packet, info->length,
|
||||||
|
(unsigned char *)packet + info->length + 4, max_auth_len);
|
||||||
|
if (!auth_len) {
|
||||||
|
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(uint32_t *)((unsigned char *)packet + info->length) = htonl(key_id);
|
||||||
|
info->length += 4 + auth_len;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static int
|
||||||
|
check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
|
||||||
|
{
|
||||||
|
int trunc_len;
|
||||||
|
|
||||||
|
if (info->auth.mac.length < NTP_MIN_MAC_LENGTH)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
trunc_len = info->version == 4 && info->auth.mac.length <= NTP_MAX_V4_MAC_LENGTH ?
|
||||||
|
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
|
||||||
|
|
||||||
|
if (!KEY_CheckAuth(info->auth.mac.key_id, (void *)packet, info->auth.mac.start,
|
||||||
|
(unsigned char *)packet + info->auth.mac.start + 4,
|
||||||
|
info->auth.mac.length - 4, trunc_len - 4))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static void
|
||||||
|
adjust_timestamp(NTP_AuthMode mode, uint32_t key_id, struct timespec *ts)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case AUTH_SYMMETRIC:
|
||||||
|
ts->tv_nsec += KEY_GetAuthDelay(key_id);
|
||||||
|
UTI_NormaliseTimespec(ts);
|
||||||
|
break;
|
||||||
|
case AUTH_MSSNTP:
|
||||||
|
ts->tv_nsec += NSD_GetAuthDelay(key_id);
|
||||||
|
UTI_NormaliseTimespec(ts);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
static NAU_Instance
|
||||||
|
create_instance(NTP_AuthMode mode)
|
||||||
|
{
|
||||||
|
NAU_Instance instance;
|
||||||
|
|
||||||
|
instance = MallocNew(struct NAU_Instance_Record);
|
||||||
|
instance->mode = mode;
|
||||||
|
instance->key_id = INACTIVE_AUTHKEY;
|
||||||
|
|
||||||
|
assert(sizeof (instance->key_id) == 4);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
NAU_Instance
|
||||||
|
NAU_CreateNoneInstance(void)
|
||||||
|
{
|
||||||
|
return create_instance(AUTH_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
NAU_Instance
|
||||||
|
NAU_CreateSymmetricInstance(uint32_t key_id)
|
||||||
|
{
|
||||||
|
NAU_Instance instance = create_instance(AUTH_SYMMETRIC);
|
||||||
|
|
||||||
|
instance->key_id = key_id;
|
||||||
|
|
||||||
|
if (!KEY_KeyKnown(key_id))
|
||||||
|
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "missing");
|
||||||
|
else if (!KEY_CheckKeyLength(key_id))
|
||||||
|
LOG(LOGS_WARN, "Key %"PRIu32" is %s", key_id, "too short");
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
void
|
||||||
|
NAU_DestroyInstance(NAU_Instance instance)
|
||||||
|
{
|
||||||
|
Free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_IsAuthEnabled(NAU_Instance instance)
|
||||||
|
{
|
||||||
|
return instance->mode != AUTH_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_GetSuggestedNtpVersion(NAU_Instance instance)
|
||||||
|
{
|
||||||
|
/* If the MAC in NTPv4 packets would be truncated, prefer NTPv3 for
|
||||||
|
compatibility with older chronyd servers */
|
||||||
|
if (instance->mode == AUTH_SYMMETRIC &&
|
||||||
|
KEY_GetAuthLength(instance->key_id) + sizeof (instance->key_id) > NTP_MAX_V4_MAC_LENGTH)
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
return NTP_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_PrepareRequestAuth(NAU_Instance instance)
|
||||||
|
{
|
||||||
|
switch (instance->mode) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
void
|
||||||
|
NAU_AdjustRequestTimestamp(NAU_Instance instance, struct timespec *ts)
|
||||||
|
{
|
||||||
|
adjust_timestamp(instance->mode, instance->key_id, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request, NTP_PacketInfo *info)
|
||||||
|
{
|
||||||
|
switch (instance->mode) {
|
||||||
|
case AUTH_NONE:
|
||||||
|
break;
|
||||||
|
case AUTH_SYMMETRIC:
|
||||||
|
if (!generate_symmetric_auth(instance->key_id, request, info))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info)
|
||||||
|
{
|
||||||
|
switch (info->auth.mode) {
|
||||||
|
case AUTH_NONE:
|
||||||
|
break;
|
||||||
|
case AUTH_SYMMETRIC:
|
||||||
|
if (!check_symmetric_auth(request, info))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case AUTH_MSSNTP:
|
||||||
|
/* MS-SNTP requests are not authenticated */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
void
|
||||||
|
NAU_AdjustResponseTimestamp(NTP_Packet *request, NTP_PacketInfo *info, struct timespec *ts)
|
||||||
|
{
|
||||||
|
adjust_timestamp(info->auth.mode, info->auth.mac.key_id, ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
|
||||||
|
NTP_Packet *response, NTP_PacketInfo *response_info,
|
||||||
|
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||||
|
{
|
||||||
|
switch (request_info->auth.mode) {
|
||||||
|
case AUTH_NONE:
|
||||||
|
break;
|
||||||
|
case AUTH_SYMMETRIC:
|
||||||
|
if (!generate_symmetric_auth(request_info->auth.mac.key_id, response, response_info))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case AUTH_MSSNTP:
|
||||||
|
/* Sign the packet asynchronously by ntp_signd */
|
||||||
|
if (!NSD_SignAndSendPacket(request_info->auth.mac.key_id, response, response_info,
|
||||||
|
remote_addr, local_addr))
|
||||||
|
return 0;
|
||||||
|
/* Don't send the original packet */
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
DEBUG_LOG("Could not authenticate response auth_mode=%d", (int)request_info->auth.mode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response, NTP_PacketInfo *info)
|
||||||
|
{
|
||||||
|
/* If we don't expect the packet to be authenticated, ignore any
|
||||||
|
authentication data in the packet */
|
||||||
|
if (instance->mode == AUTH_NONE)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* The authentication must match the expected mode */
|
||||||
|
if (info->auth.mode != instance->mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (info->auth.mode) {
|
||||||
|
case AUTH_NONE:
|
||||||
|
break;
|
||||||
|
case AUTH_SYMMETRIC:
|
||||||
|
/* Check if it is authenticated with the specified key */
|
||||||
|
if (info->auth.mac.key_id != instance->key_id)
|
||||||
|
return 0;
|
||||||
|
/* and that the MAC is valid */
|
||||||
|
if (!check_symmetric_auth(response, info))
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
79
ntp_auth.h
Normal file
79
ntp_auth.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||||
|
|
||||||
|
**********************************************************************
|
||||||
|
* Copyright (C) Miroslav Lichvar 2019
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
**********************************************************************
|
||||||
|
|
||||||
|
=======================================================================
|
||||||
|
|
||||||
|
Header file for NTP authentication
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GOT_NTP_AUTH_H
|
||||||
|
#define GOT_NTP_AUTH_H
|
||||||
|
|
||||||
|
#include "addressing.h"
|
||||||
|
#include "ntp.h"
|
||||||
|
|
||||||
|
typedef struct NAU_Instance_Record *NAU_Instance;
|
||||||
|
|
||||||
|
/* Create an authenticator instance in a specific mode */
|
||||||
|
extern NAU_Instance NAU_CreateNoneInstance(void);
|
||||||
|
extern NAU_Instance NAU_CreateSymmetricInstance(uint32_t key_id);
|
||||||
|
|
||||||
|
/* Destroy an instance */
|
||||||
|
extern void NAU_DestroyInstance(NAU_Instance instance);
|
||||||
|
|
||||||
|
/* Check if an instance is not in the None mode */
|
||||||
|
extern int NAU_IsAuthEnabled(NAU_Instance instance);
|
||||||
|
|
||||||
|
/* Get NTP version recommended for better compatibility */
|
||||||
|
extern int NAU_GetSuggestedNtpVersion(NAU_Instance instance);
|
||||||
|
|
||||||
|
/* Perform operations necessary for NAU_GenerateRequestAuth() */
|
||||||
|
extern int NAU_PrepareRequestAuth(NAU_Instance instance);
|
||||||
|
|
||||||
|
/* Adjust a transmit timestamp for an estimated minimum time it takes to call
|
||||||
|
NAU_GenerateRequestAuth() */
|
||||||
|
extern void NAU_AdjustRequestTimestamp(NAU_Instance instance, struct timespec *ts);
|
||||||
|
|
||||||
|
/* Extend a request with data required by the authentication mode */
|
||||||
|
extern int NAU_GenerateRequestAuth(NAU_Instance instance, NTP_Packet *request,
|
||||||
|
NTP_PacketInfo *info);
|
||||||
|
|
||||||
|
/* Verify that a request is authentic */
|
||||||
|
extern int NAU_CheckRequestAuth(NTP_Packet *request, NTP_PacketInfo *info);
|
||||||
|
|
||||||
|
/* Adjust a transmit timestamp for an estimated minimum time it takes to call
|
||||||
|
NAU_GenerateResponseAuth() */
|
||||||
|
extern void NAU_AdjustResponseTimestamp(NTP_Packet *request, NTP_PacketInfo *info,
|
||||||
|
struct timespec *ts);
|
||||||
|
|
||||||
|
/* Extend a response with data required by the authentication mode. This
|
||||||
|
function can be called only if the previous call of NAU_CheckRequestAuth()
|
||||||
|
was on the same request. */
|
||||||
|
extern int NAU_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *request_info,
|
||||||
|
NTP_Packet *response, NTP_PacketInfo *response_info,
|
||||||
|
NTP_Remote_Address *remote_addr,
|
||||||
|
NTP_Local_Address *local_addr);
|
||||||
|
|
||||||
|
/* Verify that a response is authentic */
|
||||||
|
extern int NAU_CheckResponseAuth(NAU_Instance instance, NTP_Packet *response,
|
||||||
|
NTP_PacketInfo *info);
|
||||||
|
|
||||||
|
#endif
|
193
ntp_core.c
193
ntp_core.c
|
@ -30,10 +30,10 @@
|
||||||
#include "sysincl.h"
|
#include "sysincl.h"
|
||||||
|
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
#include "ntp_auth.h"
|
||||||
#include "ntp_core.h"
|
#include "ntp_core.h"
|
||||||
#include "ntp_ext.h"
|
#include "ntp_ext.h"
|
||||||
#include "ntp_io.h"
|
#include "ntp_io.h"
|
||||||
#include "ntp_signd.h"
|
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
#include "reference.h"
|
#include "reference.h"
|
||||||
|
@ -128,9 +128,7 @@ struct NCR_Instance_Record {
|
||||||
double offset_correction; /* Correction applied to measured offset
|
double offset_correction; /* Correction applied to measured offset
|
||||||
(e.g. for asymmetry in network delay) */
|
(e.g. for asymmetry in network delay) */
|
||||||
|
|
||||||
NTP_AuthMode auth_mode; /* Authentication mode of our requests */
|
NAU_Instance auth; /* Authentication */
|
||||||
uint32_t auth_key_id; /* The ID of the authentication key to
|
|
||||||
use. */
|
|
||||||
|
|
||||||
/* Count of transmitted packets since last valid response */
|
/* Count of transmitted packets since last valid response */
|
||||||
unsigned int tx_count;
|
unsigned int tx_count;
|
||||||
|
@ -200,6 +198,7 @@ struct NCR_Instance_Record {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NTP_Remote_Address addr;
|
NTP_Remote_Address addr;
|
||||||
NTP_Local_Address local_addr;
|
NTP_Local_Address local_addr;
|
||||||
|
NAU_Instance auth;
|
||||||
int interval;
|
int interval;
|
||||||
} BroadcastDestination;
|
} BroadcastDestination;
|
||||||
|
|
||||||
|
@ -407,8 +406,10 @@ NCR_Finalise(void)
|
||||||
if (server_sock_fd6 != INVALID_SOCK_FD)
|
if (server_sock_fd6 != INVALID_SOCK_FD)
|
||||||
NIO_CloseServerSocket(server_sock_fd6);
|
NIO_CloseServerSocket(server_sock_fd6);
|
||||||
|
|
||||||
for (i = 0; i < ARR_GetSize(broadcasts); i++)
|
for (i = 0; i < ARR_GetSize(broadcasts); i++) {
|
||||||
NIO_CloseServerSocket(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->local_addr.sock_fd);
|
NIO_CloseServerSocket(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->local_addr.sock_fd);
|
||||||
|
NAU_DestroyInstance(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->auth);
|
||||||
|
}
|
||||||
|
|
||||||
ARR_DestroyInstance(broadcasts);
|
ARR_DestroyInstance(broadcasts);
|
||||||
ADF_DestroyTable(access_auth_table);
|
ADF_DestroyTable(access_auth_table);
|
||||||
|
@ -562,30 +563,14 @@ NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourcePar
|
||||||
result->auto_offline = params->auto_offline;
|
result->auto_offline = params->auto_offline;
|
||||||
result->poll_target = params->poll_target;
|
result->poll_target = params->poll_target;
|
||||||
|
|
||||||
result->version = NTP_VERSION;
|
if (params->authkey != INACTIVE_AUTHKEY) {
|
||||||
|
result->auth = NAU_CreateSymmetricInstance(params->authkey);
|
||||||
if (params->authkey == INACTIVE_AUTHKEY) {
|
|
||||||
result->auth_mode = AUTH_NONE;
|
|
||||||
result->auth_key_id = 0;
|
|
||||||
} else {
|
} else {
|
||||||
result->auth_mode = AUTH_SYMMETRIC;
|
result->auth = NAU_CreateNoneInstance();
|
||||||
result->auth_key_id = params->authkey;
|
|
||||||
if (!KEY_KeyKnown(result->auth_key_id)) {
|
|
||||||
LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
|
|
||||||
result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
|
|
||||||
"missing");
|
|
||||||
} else if (!KEY_CheckKeyLength(result->auth_key_id)) {
|
|
||||||
LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
|
|
||||||
result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
|
|
||||||
"too short");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the MAC in NTPv4 packets would be truncated, use version 3 by
|
|
||||||
default for compatibility with older chronyd servers */
|
|
||||||
if (KEY_GetAuthLength(result->auth_key_id) + 4 > NTP_MAX_V4_MAC_LENGTH)
|
|
||||||
result->version = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result->version = NAU_GetSuggestedNtpVersion(result->auth);
|
||||||
|
|
||||||
if (params->version)
|
if (params->version)
|
||||||
result->version = CLAMP(NTP_MIN_COMPAT_VERSION, params->version, NTP_VERSION);
|
result->version = CLAMP(NTP_MIN_COMPAT_VERSION, params->version, NTP_VERSION);
|
||||||
|
|
||||||
|
@ -639,6 +624,8 @@ NCR_DestroyInstance(NCR_Instance instance)
|
||||||
if (instance->filter)
|
if (instance->filter)
|
||||||
SPF_DestroyInstance(instance->filter);
|
SPF_DestroyInstance(instance->filter);
|
||||||
|
|
||||||
|
NAU_DestroyInstance(instance->auth);
|
||||||
|
|
||||||
/* This will destroy the source instance inside the
|
/* This will destroy the source instance inside the
|
||||||
structure, which will cause reselection if this was the
|
structure, which will cause reselection if this was the
|
||||||
synchronising source etc. */
|
synchronising source etc. */
|
||||||
|
@ -919,8 +906,7 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||||
int interleaved, /* Flag enabling interleaved mode */
|
int interleaved, /* Flag enabling interleaved mode */
|
||||||
int my_poll, /* The log2 of the local poll interval */
|
int my_poll, /* The log2 of the local poll interval */
|
||||||
int version, /* The NTP version to be set in the packet */
|
int version, /* The NTP version to be set in the packet */
|
||||||
int auth_mode, /* The authentication mode */
|
NAU_Instance auth, /* The authentication to be used for the packet */
|
||||||
uint32_t key_id, /* The authentication key ID */
|
|
||||||
NTP_int64 *remote_ntp_rx, /* The receive timestamp from received packet */
|
NTP_int64 *remote_ntp_rx, /* The receive timestamp from received packet */
|
||||||
NTP_int64 *remote_ntp_tx, /* The transmit timestamp from received packet */
|
NTP_int64 *remote_ntp_tx, /* The transmit timestamp from received packet */
|
||||||
NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
|
NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
|
||||||
|
@ -938,9 +924,9 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||||
{
|
{
|
||||||
NTP_PacketInfo info;
|
NTP_PacketInfo info;
|
||||||
NTP_Packet message;
|
NTP_Packet message;
|
||||||
int auth_len, max_auth_len, ret, precision;
|
|
||||||
struct timespec local_receive, local_transmit;
|
struct timespec local_receive, local_transmit;
|
||||||
double smooth_offset, local_transmit_err;
|
double smooth_offset, local_transmit_err;
|
||||||
|
int ret, precision;
|
||||||
NTP_int64 ts_fuzz;
|
NTP_int64 ts_fuzz;
|
||||||
|
|
||||||
/* Parameters read from reference module */
|
/* Parameters read from reference module */
|
||||||
|
@ -950,6 +936,8 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||||
struct timespec our_ref_time;
|
struct timespec our_ref_time;
|
||||||
double our_root_delay, our_root_dispersion;
|
double our_root_delay, our_root_dispersion;
|
||||||
|
|
||||||
|
assert(auth || (request && request_info));
|
||||||
|
|
||||||
/* Don't reply with version higher than ours */
|
/* Don't reply with version higher than ours */
|
||||||
if (version > NTP_VERSION) {
|
if (version > NTP_VERSION) {
|
||||||
version = NTP_VERSION;
|
version = NTP_VERSION;
|
||||||
|
@ -1065,39 +1053,27 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
|
||||||
if (smooth_time)
|
if (smooth_time)
|
||||||
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
|
||||||
|
|
||||||
/* Authenticate the packet */
|
/* Pre-compensate the transmit time by approximately how long it will take
|
||||||
|
to generate the authentication data */
|
||||||
|
if (auth)
|
||||||
|
NAU_AdjustRequestTimestamp(auth, &local_transmit);
|
||||||
|
else
|
||||||
|
NAU_AdjustResponseTimestamp(request, request_info, &local_transmit);
|
||||||
|
|
||||||
if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
|
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
||||||
/* Pre-compensate the transmit time by approximately how long it will
|
&message.transmit_ts, &ts_fuzz);
|
||||||
take to generate the authentication data */
|
|
||||||
local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
|
|
||||||
KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
|
|
||||||
UTI_NormaliseTimespec(&local_transmit);
|
|
||||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
|
||||||
&message.transmit_ts, &ts_fuzz);
|
|
||||||
|
|
||||||
if (auth_mode == AUTH_SYMMETRIC) {
|
/* Generate the authentication data */
|
||||||
/* Truncate long MACs in NTPv4 packets to allow deterministic parsing
|
if (auth) {
|
||||||
of extension fields (RFC 7822) */
|
if (!NAU_GenerateRequestAuth(auth, &message, &info)) {
|
||||||
max_auth_len = (version == 4 ?
|
DEBUG_LOG("Could not generate request auth");
|
||||||
NTP_MAX_V4_MAC_LENGTH : (sizeof (message) - info.length)) - 4;
|
return 0;
|
||||||
|
|
||||||
auth_len = KEY_GenerateAuth(key_id, (unsigned char *)&message, info.length,
|
|
||||||
(unsigned char *)&message + info.length + 4, max_auth_len);
|
|
||||||
if (!auth_len) {
|
|
||||||
DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
*(uint32_t *)((unsigned char *)&message + info.length) = htonl(key_id);
|
|
||||||
info.length += 4 + auth_len;
|
|
||||||
} else if (auth_mode == AUTH_MSSNTP) {
|
|
||||||
/* MS-SNTP packets are signed (asynchronously) by ntp_signd */
|
|
||||||
return NSD_SignAndSendPacket(key_id, &message, &info, where_to, from);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
|
if (!NAU_GenerateResponseAuth(request, request_info, &message, &info, where_to, from)) {
|
||||||
&message.transmit_ts, &ts_fuzz);
|
DEBUG_LOG("Could not generate response auth");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do not send a packet with a non-zero transmit timestamp which is
|
/* Do not send a packet with a non-zero transmit timestamp which is
|
||||||
|
@ -1174,6 +1150,16 @@ transmit_timeout(void *arg)
|
||||||
|
|
||||||
DEBUG_LOG("Transmit timeout for %s", UTI_IPSockAddrToString(&inst->remote_addr));
|
DEBUG_LOG("Transmit timeout for %s", UTI_IPSockAddrToString(&inst->remote_addr));
|
||||||
|
|
||||||
|
/* Prepare authentication */
|
||||||
|
if (!NAU_PrepareRequestAuth(inst->auth)) {
|
||||||
|
if (inst->burst_total_samples_to_go > 0)
|
||||||
|
inst->burst_total_samples_to_go--;
|
||||||
|
adjust_poll(inst, 0.25);
|
||||||
|
SRC_UpdateReachability(inst->source, 0);
|
||||||
|
restart_timeout(inst, get_transmit_delay(inst, 1, 0.0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Open new client socket */
|
/* Open new client socket */
|
||||||
if (inst->mode == MODE_CLIENT) {
|
if (inst->mode == MODE_CLIENT) {
|
||||||
close_client_socket(inst);
|
close_client_socket(inst);
|
||||||
|
@ -1225,7 +1211,7 @@ transmit_timeout(void *arg)
|
||||||
|
|
||||||
/* Send the request (which may also be a response in the symmetric mode) */
|
/* Send the request (which may also be a response in the symmetric mode) */
|
||||||
sent = transmit_packet(inst->mode, interleaved, inst->local_poll, inst->version,
|
sent = transmit_packet(inst->mode, interleaved, inst->local_poll, inst->version,
|
||||||
inst->auth_mode, inst->auth_key_id,
|
inst->auth,
|
||||||
initial ? NULL : &inst->remote_ntp_rx,
|
initial ? NULL : &inst->remote_ntp_rx,
|
||||||
initial ? &inst->init_remote_ntp_tx : &inst->remote_ntp_tx,
|
initial ? &inst->init_remote_ntp_tx : &inst->remote_ntp_tx,
|
||||||
initial ? &inst->init_local_rx : &inst->local_rx,
|
initial ? &inst->init_local_rx : &inst->local_rx,
|
||||||
|
@ -1410,45 +1396,6 @@ parse_packet(NTP_Packet *packet, int length, NTP_PacketInfo *info)
|
||||||
|
|
||||||
/* ================================================== */
|
/* ================================================== */
|
||||||
|
|
||||||
static int
|
|
||||||
check_symmetric_auth(NTP_Packet *packet, NTP_PacketInfo *info)
|
|
||||||
{
|
|
||||||
int trunc_len;
|
|
||||||
|
|
||||||
if (info->auth.mac.length < NTP_MIN_MAC_LENGTH)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
trunc_len = info->version == 4 && info->auth.mac.length <= NTP_MAX_V4_MAC_LENGTH ?
|
|
||||||
NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
|
|
||||||
|
|
||||||
if (!KEY_CheckAuth(info->auth.mac.key_id, (void *)packet, info->auth.mac.start,
|
|
||||||
(unsigned char *)packet + info->auth.mac.start + 4,
|
|
||||||
info->auth.mac.length - 4, trunc_len - 4))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================================================== */
|
|
||||||
|
|
||||||
static int
|
|
||||||
check_packet_auth(NTP_Packet *packet, NTP_PacketInfo *info,
|
|
||||||
NTP_AuthMode *auth_mode, uint32_t *key_id)
|
|
||||||
{
|
|
||||||
*auth_mode = info->auth.mode;
|
|
||||||
|
|
||||||
if (info->auth.mode != AUTH_SYMMETRIC)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!check_symmetric_auth(packet, info))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*key_id = info->auth.mac.key_id;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================================================== */
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
|
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
|
||||||
struct timespec *sample_time, double delay)
|
struct timespec *sample_time, double delay)
|
||||||
|
@ -1610,10 +1557,9 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||||
SST_Stats stats;
|
SST_Stats stats;
|
||||||
|
|
||||||
int pkt_leap, pkt_version;
|
int pkt_leap, pkt_version;
|
||||||
uint32_t pkt_refid, pkt_key_id;
|
uint32_t pkt_refid;
|
||||||
double pkt_root_delay;
|
double pkt_root_delay;
|
||||||
double pkt_root_dispersion;
|
double pkt_root_dispersion;
|
||||||
NTP_AuthMode pkt_auth_mode;
|
|
||||||
|
|
||||||
/* The skew and estimated frequency offset relative to the remote source */
|
/* The skew and estimated frequency offset relative to the remote source */
|
||||||
double skew, source_freq_lo, source_freq_hi;
|
double skew, source_freq_lo, source_freq_hi;
|
||||||
|
@ -1668,14 +1614,8 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||||
/* Test 4 would check for denied access. It would always pass as this
|
/* Test 4 would check for denied access. It would always pass as this
|
||||||
function is called only for known sources. */
|
function is called only for known sources. */
|
||||||
|
|
||||||
/* Test 5 checks for authentication failure. If we expect authenticated info
|
/* Test 5 checks for authentication failure */
|
||||||
from this peer/server and the packet doesn't have it, the authentication
|
test5 = NAU_CheckResponseAuth(inst->auth, message, info);
|
||||||
is bad, or it's authenticated with a different key than expected, it's got
|
|
||||||
to fail. If we don't expect the packet to be authenticated, just ignore
|
|
||||||
the test. */
|
|
||||||
test5 = inst->auth_mode == AUTH_NONE ||
|
|
||||||
(check_packet_auth(message, info, &pkt_auth_mode, &pkt_key_id) &&
|
|
||||||
pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
|
|
||||||
|
|
||||||
/* Test 6 checks for unsynchronised server */
|
/* Test 6 checks for unsynchronised server */
|
||||||
test6 = pkt_leap != LEAP_Unsynchronised &&
|
test6 = pkt_leap != LEAP_Unsynchronised &&
|
||||||
|
@ -1994,7 +1934,7 @@ process_response(NCR_Instance inst, NTP_Local_Address *local_addr,
|
||||||
test5) << 1 | test6) << 1 | test7) << 1 |
|
test5) << 1 | test6) << 1 | test7) << 1 |
|
||||||
testA) << 1 | testB) << 1 | testC) << 1 | testD;
|
testA) << 1 | testB) << 1 | testC) << 1 | testD;
|
||||||
inst->report.interleaved = interleaved_packet;
|
inst->report.interleaved = interleaved_packet;
|
||||||
inst->report.authenticated = inst->auth_mode != AUTH_NONE;
|
inst->report.authenticated = NAU_IsAuthEnabled(inst->auth);
|
||||||
inst->report.tx_tss_char = tss_chars[local_transmit.source];
|
inst->report.tx_tss_char = tss_chars[local_transmit.source];
|
||||||
inst->report.rx_tss_char = tss_chars[local_receive.source];
|
inst->report.rx_tss_char = tss_chars[local_receive.source];
|
||||||
|
|
||||||
|
@ -2179,9 +2119,7 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||||
NTP_Mode my_mode;
|
NTP_Mode my_mode;
|
||||||
NTP_int64 *local_ntp_rx, *local_ntp_tx;
|
NTP_int64 *local_ntp_rx, *local_ntp_tx;
|
||||||
NTP_Local_Timestamp local_tx, *tx_ts;
|
NTP_Local_Timestamp local_tx, *tx_ts;
|
||||||
int valid_auth, log_index, interleaved, poll, version;
|
int log_index, interleaved, poll, version;
|
||||||
NTP_AuthMode auth_mode;
|
|
||||||
uint32_t key_id;
|
|
||||||
|
|
||||||
/* Ignore the packet if it wasn't received by server socket */
|
/* Ignore the packet if it wasn't received by server socket */
|
||||||
if (!NIO_IsServerSocket(local_addr->sock_fd)) {
|
if (!NIO_IsServerSocket(local_addr->sock_fd)) {
|
||||||
|
@ -2230,23 +2168,10 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the packet includes MAC that authenticates properly */
|
/* Check authentication */
|
||||||
valid_auth = check_packet_auth(message, &info, &auth_mode, &key_id);
|
if (!NAU_CheckRequestAuth(message, &info)) {
|
||||||
|
DEBUG_LOG("NTP packet discarded auth mode=%d", (int)info.auth.mode);
|
||||||
/* If authentication failed, select whether and how we should respond */
|
return;
|
||||||
if (!valid_auth) {
|
|
||||||
switch (auth_mode) {
|
|
||||||
case AUTH_NONE:
|
|
||||||
/* Reply with no MAC */
|
|
||||||
break;
|
|
||||||
case AUTH_MSSNTP:
|
|
||||||
/* Ignore the failure (MS-SNTP servers don't check client MAC) */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Discard packets in other modes */
|
|
||||||
DEBUG_LOG("NTP packet discarded auth_mode=%u", auth_mode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If it is an NTPv4 packet with a long MAC and no extension fields,
|
/* If it is an NTPv4 packet with a long MAC and no extension fields,
|
||||||
|
@ -2288,8 +2213,8 @@ NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_a
|
||||||
poll = MAX(poll, message->poll);
|
poll = MAX(poll, message->poll);
|
||||||
|
|
||||||
/* Send a reply */
|
/* Send a reply */
|
||||||
transmit_packet(my_mode, interleaved, poll, version,
|
transmit_packet(my_mode, interleaved, poll, version, NULL,
|
||||||
auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
|
&message->receive_ts, &message->transmit_ts,
|
||||||
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr,
|
rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr,
|
||||||
message, &info);
|
message, &info);
|
||||||
|
|
||||||
|
@ -2727,8 +2652,9 @@ broadcast_timeout(void *arg)
|
||||||
UTI_ZeroNtp64(&orig_ts);
|
UTI_ZeroNtp64(&orig_ts);
|
||||||
zero_local_timestamp(&recv_ts);
|
zero_local_timestamp(&recv_ts);
|
||||||
|
|
||||||
transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
|
transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, destination->auth,
|
||||||
NULL, NULL, NULL, &destination->addr, &destination->local_addr, NULL, NULL);
|
&orig_ts, &orig_ts, &recv_ts, NULL, NULL, NULL,
|
||||||
|
&destination->addr, &destination->local_addr, NULL, NULL);
|
||||||
|
|
||||||
/* Requeue timeout. We don't care if interval drifts gradually. */
|
/* Requeue timeout. We don't care if interval drifts gradually. */
|
||||||
SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
|
SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
|
||||||
|
@ -2749,6 +2675,7 @@ NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
|
||||||
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
|
||||||
destination->local_addr.if_index = INVALID_IF_INDEX;
|
destination->local_addr.if_index = INVALID_IF_INDEX;
|
||||||
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
|
destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
|
||||||
|
destination->auth = NAU_CreateNoneInstance();
|
||||||
destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
|
destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
|
||||||
|
|
||||||
SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
|
||||||
|
|
3
stubs.c
3
stubs.c
|
@ -412,7 +412,8 @@ NSD_GetAuthDelay(uint32_t key_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr, int length)
|
NSD_SignAndSendPacket(uint32_t key_id, NTP_Packet *packet, NTP_PacketInfo *info,
|
||||||
|
NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue