Add support for different authentication hashes

Allow different hash functions to be used in the NTP and cmdmon
protocols. This breaks the cmdmon protocol compatibility. Extended key
file format is used to specify the hash functions for chronyd and new
authhash command is added to chronyc. MD5 is the default and the only
function included in the chrony source code, other functions will be
available from libraries.
This commit is contained in:
Miroslav Lichvar 2011-10-19 13:26:03 +02:00
parent 6015f99d98
commit 777303f130
20 changed files with 473 additions and 329 deletions

View file

@ -34,27 +34,24 @@ CPPFLAGS = @CPPFLAGS@
DESTDIR=
HASH_OBJ = @HASH_OBJ@
OBJS = util.o sched.o regress.o local.o \
sys.o main.o ntp_io.o ntp_core.o ntp_sources.o \
sources.o sourcestats.o reference.o \
logging.o conf.o cmdmon.o md5.o keys.o \
logging.o conf.o cmdmon.o keys.o \
nameserv.o acquire.o manual.o addrfilt.o \
cmdparse.o mkdirpp.o rtc.o pktlength.o clientlog.o \
broadcast.o refclock.o refclock_shm.o refclock_sock.o \
refclock_pps.o tempcomp.o
refclock_pps.o tempcomp.o $(HASH_OBJ)
EXTRA_OBJS=@EXTRA_OBJECTS@
CLI_OBJS = client.o md5.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o
CLI_OBJS = client.o nameserv.o getdate.o cmdparse.o \
pktlength.o util.o $(HASH_OBJ)
ALL_OBJS = $(OBJS) $(EXTRA_OBJS) $(CLI_OBJS)
SRCS = $(patsubst %.o,%.c,$(OBJS))
EXTRA_SRCS = $(patsubst %.o,%.c,$(EXTRA_OBJS))
CLI_SRCS = $(patsubst %.o,%.c,$(CLI_OBJS))
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
@ -67,14 +64,17 @@ EXTRA_CLI_LIBS=@EXTRA_CLI_LIBS@
all : chronyd chronyc
chronyd : $(OBJS) $(EXTRA_OBJS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) $(LIBS) $(EXTRA_LIBS)
$(CC) $(CFLAGS) -o chronyd $(OBJS) $(EXTRA_OBJS) $(LDFLAGS) @HASH_LINK@ $(LIBS) $(EXTRA_LIBS)
chronyc : $(CLI_OBJS)
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
$(CC) $(CFLAGS) -o chronyc $(CLI_OBJS) $(LDFLAGS) @READLINE_LINK@ @HASH_LINK@ $(LIBS) $(EXTRA_CLI_LIBS)
client.o : client.c
$(CC) $(CFLAGS) $(CPPFLAGS) @READLINE_COMPILE@ -c $<
$(HASH_OBJ) : $(patsubst %.o,%.c,$(HASH_OBJ))
$(CC) $(CFLAGS) $(CPPFLAGS) @HASH_COMPILE@ -c $<
distclean : clean
-rm -f Makefile

15
candm.h
View file

@ -31,6 +31,7 @@
#include "sysincl.h"
#include "addressing.h"
#include "hash.h"
/* This is the default port to use for CANDM, if no alternative is
defined */
@ -368,9 +369,10 @@ typedef struct {
and used also instead of integer microseconds, new commands: modify stratum,
modify polltarget, modify maxdelaydevratio, reselect, reselectdistance
Version 5 : auth data moved to the end of the packet to allow different hashes
*/
#define PROTO_VERSION_NUMBER 4
#define PROTO_VERSION_NUMBER 5
/* The oldest protocol version that is compatible enough with
the current version to report a version mismatch */
@ -390,7 +392,6 @@ typedef struct {
uint32_t sequence; /* Client's sequence number */
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* Command token (to prevent replay attack) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
REQ_Online online;
@ -435,6 +436,10 @@ typedef struct {
REQ_ReselectDistance reselect_distance;
} data; /* Command specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Request;
/* ================================================== */
@ -632,8 +637,6 @@ typedef struct {
uint32_t utoken; /* Unique token per incarnation of daemon */
uint32_t token; /* New command token (only if command was successfully
authenticated) */
uint32_t auth[4]; /* MD5 authentication of the packet */
union {
RPY_Null null;
RPY_N_Sources n_sources;
@ -649,6 +652,10 @@ typedef struct {
RPY_Activity activity;
} data; /* Reply specific parameters */
/* authentication of the packet, there is no hole after the actual data
from the data union, this field only sets the maximum auth size */
uint8_t auth[MAX_HASH_LENGTH];
} CMD_Reply;
/* ================================================== */

111
client.c
View file

@ -32,7 +32,7 @@
#include "candm.h"
#include "nameserv.h"
#include "md5.h"
#include "hash.h"
#include "getdate.h"
#include "cmdparse.h"
#include "pktlength.h"
@ -1094,8 +1094,9 @@ process_cmd_delete(CMD_Request *msg, char *line)
/* ================================================== */
static char *password;
static int password_seen = 0;
static MD5_CTX md5_after_just_password;
static int auth_hash_id;
/* ================================================== */
@ -1103,7 +1104,6 @@ static int
process_cmd_password(CMD_Request *msg, char *line)
{
char *p, *q;
char *password;
struct timeval now;
p = line;
@ -1128,15 +1128,6 @@ process_cmd_password(CMD_Request *msg, char *line)
password_seen = 1;
}
/* Generate MD5 initial context */
MD5Init(&md5_after_just_password);
MD5Update(&md5_after_just_password, (unsigned char *) password, strlen(password));
/* Blank the password for security */
for (p = password; *p; p++) {
*p = 0;
}
if (gettimeofday(&now, NULL) < 0) {
printf("500 - Could not read time of day\n");
return 0;
@ -1149,43 +1140,33 @@ process_cmd_password(CMD_Request *msg, char *line)
/* ================================================== */
static void
static int
generate_auth(CMD_Request *msg)
{
MD5_CTX ctx;
int pkt_len;
int data_len;
pkt_len = PKL_CommandLength(msg);
ctx = md5_after_just_password;
MD5Update(&ctx, (unsigned char *) msg, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(msg->data), pkt_len - offsetof(CMD_Request, data));
}
MD5Final(&ctx);
memcpy(&(msg->auth), &ctx.digest, 16);
data_len = PKL_CommandLength(msg);
assert(auth_hash_id >= 0);
return UTI_GenerateNTPAuth(auth_hash_id, (unsigned char *)password, strlen(password),
(unsigned char *)msg, data_len, ((unsigned char *)msg) + data_len, sizeof (msg->auth));
}
/* ================================================== */
static int
check_reply_auth(CMD_Reply *msg)
check_reply_auth(CMD_Reply *msg, int len)
{
int pkt_len;
MD5_CTX ctx;
int data_len;
pkt_len = PKL_ReplyLength(msg);
ctx = md5_after_just_password;
MD5Update(&ctx, (unsigned char *) msg, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(msg->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
data_len = PKL_ReplyLength(msg);
if (!memcmp((void *) &ctx.digest, (void *) &(msg->auth), 16)) {
return 1;
} else {
return 0;
}
assert(auth_hash_id >= 0);
return UTI_CheckNTPAuth(auth_hash_id, (unsigned char *)password, strlen(password),
(unsigned char *)msg, data_len,
((unsigned char *)msg) + data_len, len - data_len);
}
/* ================================================== */
@ -1238,6 +1219,7 @@ give_help(void)
printf("waitsync [max-tries [max-correction [max-skew]]] : Wait until synchronised\n");
printf("writertc : Save RTC parameters to file\n");
printf("\n");
printf("authhash <name>: Set command authentication hash function\n");
printf("dns -n|+n : Disable/enable resolving IP addresses to hostnames\n");
printf("dns -4|-6|-46 : Resolve hostnames only to IPv4/IPv6/both addresses\n");
printf("timeout <milliseconds> : Set initial response timeout\n");
@ -1273,6 +1255,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
int read_length;
int expected_length;
int command_length;
int auth_length;
struct timeval tv;
int timeout;
int n_attempts;
@ -1301,19 +1284,26 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
packet and we won't get a token back */
request->utoken = htonl(SPECIAL_UTOKEN);
}
generate_auth(request);
auth_length = generate_auth(request);
} else {
memset(request->auth, 0, sizeof (request->auth));
auth_length = 0;
}
command_length = PKL_CommandLength(request);
assert(command_length > 0);
/* add empty MD5 auth so older servers will not drop the request
due to bad length */
if (!auth_length) {
memset(((char *)request) + command_length, 0, 16);
auth_length = 16;
}
#if 0
printf("Sent command length=%d bytes\n", command_length);
printf("Sent command length=%d bytes auth length=%d bytes\n", command_length, auth_length);
#endif
if (sendto(sock_fd, (void *) request, command_length, 0,
if (sendto(sock_fd, (void *) request, command_length + auth_length, 0,
&his_addr.u, his_addr_len) < 0) {
@ -1376,7 +1366,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
read_length = recvfrom_status;
expected_length = PKL_ReplyLength(reply);
bad_length = (read_length != expected_length);
bad_length = (read_length < expected_length);
bad_sender = (where_from.u.sa_family != his_addr.u.sa_family ||
(where_from.u.sa_family == AF_INET &&
(where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr ||
@ -1431,7 +1421,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
#endif
if (password_seen) {
*reply_auth_ok = check_reply_auth(reply);
*reply_auth_ok = check_reply_auth(reply, read_length);
} else {
/* Assume in this case that the reply is always considered
to be authentic */
@ -2476,6 +2466,32 @@ process_cmd_dns(const char *line)
/* ================================================== */
static int
process_cmd_authhash(const char *line)
{
char hash_name[50];
int new_hash_id;
assert(auth_hash_id >= 0);
if (sscanf(line, "%49s", hash_name) != 1) {
fprintf(stderr, "Could not parse hash name\n");
return 0;
}
new_hash_id = HSH_GetHashId(hash_name);
if (new_hash_id < 0) {
fprintf(stderr, "Unknown hash name: %s\n", hash_name);
return 0;
}
auth_hash_id = new_hash_id;
return 1;
}
/* ================================================== */
static int
process_cmd_timeout(const char *line)
{
@ -2634,6 +2650,9 @@ process_line(char *line, int *quit)
} else if (!strncmp(p, "waitsync", 8)) {
ret = process_cmd_waitsync(p+8);
do_normal_submit = 0;
} else if (!strncmp(p, "authhash", 8)) {
ret = process_cmd_authhash(p+8);
do_normal_submit = 0;
} else if (!strncmp(p, "dns ", 4)) {
ret = process_cmd_dns(p+4);
do_normal_submit = 0;
@ -2770,6 +2789,10 @@ main(int argc, char **argv)
display_gpl();
}
/* MD5 is the default authentication hash */
auth_hash_id = HSH_GetHashId("MD5");
assert(auth_hash_id >= 0);
open_io(hostname, port);
if (argc > 0) {

101
cmdmon.c
View file

@ -328,57 +328,28 @@ CAM_Finalise(void)
rest of the packet */
static int
check_rx_packet_auth(CMD_Request *packet)
check_rx_packet_auth(CMD_Request *packet, int packet_len)
{
char *key;
int keylen;
int pkt_len;
MD5_CTX ctx;
int pkt_len, auth_len;
pkt_len = PKL_CommandLength(packet);
auth_len = packet_len - pkt_len;
KEY_CommandKey(&key, &keylen);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Request, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Request, data));
}
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(packet->auth), 16)) {
return 1;
} else {
return 0;
}
return KEY_CheckAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, auth_len);
}
/* ================================================== */
static void
static int
generate_tx_packet_auth(CMD_Reply *packet)
{
char *key;
int keylen;
MD5_CTX ctx;
int pkt_len;
pkt_len = PKL_ReplyLength(packet);
KEY_CommandKey(&key, &keylen);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) key, keylen);
MD5Update(&ctx, (unsigned char *) packet, offsetof(CMD_Request, auth));
if (pkt_len > offsetof(CMD_Reply, data)) {
MD5Update(&ctx, (unsigned char *) &(packet->data), pkt_len - offsetof(CMD_Reply, data));
}
MD5Final(&ctx);
memcpy(&(packet->auth), &ctx.digest, 16);
return KEY_GenerateAuth(KEY_GetCommandKey(), (unsigned char *)packet,
pkt_len, ((unsigned char *)packet) + pkt_len, sizeof (packet->auth));
}
/* ================================================== */
@ -720,7 +691,7 @@ print_reply_packet(CMD_Reply *pkt)
/* ================================================== */
static void
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to, int auth_len)
{
int status;
int tx_message_length;
@ -742,7 +713,7 @@ transmit_reply(CMD_Reply *msg, union sockaddr_in46 *where_to)
assert(0);
}
tx_message_length = PKL_ReplyLength(msg);
tx_message_length = PKL_ReplyLength(msg) + auth_len;
status = sendto(sock_fd, (void *) msg, tx_message_length, 0,
&where_to->u, addrlen);
@ -1756,7 +1727,7 @@ read_from_cmd_socket(void *anything)
{
int status;
int read_length; /* Length of packet read */
int expected_length; /* Expected length of packet */
int expected_length; /* Expected length of packet without auth data */
unsigned long flags;
CMD_Request rx_message;
CMD_Reply tx_message, *prev_tx_message;
@ -1766,7 +1737,8 @@ read_from_cmd_socket(void *anything)
socklen_t from_length;
IPAddr remote_ip;
unsigned short remote_port;
int md5_ok;
int auth_length;
int auth_ok;
int utoken_ok, token_ok;
int issue_token;
int valid_ts;
@ -1867,7 +1839,10 @@ read_from_cmd_socket(void *anything)
if (rx_message.version >= PROTO_VERSION_MISMATCH_COMPAT) {
tx_message.status = htons(STT_BADPKTVERSION);
transmit_reply(&tx_message, &where_from);
/* add empty MD5 auth so older clients will not drop
the reply due to bad length */
memset(((char *)&tx_message) + PKL_ReplyLength(&tx_message), 0, 16);
transmit_reply(&tx_message, &where_from, 16);
}
return;
}
@ -1880,11 +1855,11 @@ read_from_cmd_socket(void *anything)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_INVALID);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
if (read_length != expected_length) {
if (read_length < expected_length) {
if (!LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon, "Read incorrectly sized command packet from %s:%hu", UTI_IPToString(&remote_ip), remote_port);
}
@ -1892,7 +1867,7 @@ read_from_cmd_socket(void *anything)
CLG_LogCommandAccess(&remote_ip, CLG_CMD_BAD_PKT, cooked_now.tv_sec);
tx_message.status = htons(STT_BADPKTLENGTH);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
@ -1909,7 +1884,7 @@ read_from_cmd_socket(void *anything)
}
tx_message.status = htons(STT_NOHOSTACCESS);
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, 0);
return;
}
@ -1920,18 +1895,18 @@ read_from_cmd_socket(void *anything)
clients will set their utokens to 0 to save us wasting our time
if the packet is unauthenticatable. */
if (rx_message.utoken != 0) {
md5_ok = check_rx_packet_auth(&rx_message);
auth_ok = check_rx_packet_auth(&rx_message, read_length);
} else {
md5_ok = 0;
auth_ok = 0;
}
/* All this malarky is to protect the system against various forms
of attack.
Simple packet forgeries are blocked by requiring the packet to
authenticate properly with MD5. (The assumption is that the
command key is in a read-only keys file read by the daemon, and
is known only to administrators.)
authenticate properly with MD5 or other crypto hash. (The
assumption is that the command key is in a read-only keys file
read by the daemon, and is known only to administrators.)
Replay attacks are prevented by 2 fields in the packet. The
'token' field is where the client plays back to us a token that
@ -1973,13 +1948,13 @@ read_from_cmd_socket(void *anything)
rx_message_seq = ntohl(rx_message.sequence);
rx_attempt = ntohs(rx_message.attempt);
if (md5_ok && utoken_ok) {
if (auth_ok && utoken_ok) {
token_ok = check_token(rx_message_token);
} else {
token_ok = 0;
}
if (md5_ok && utoken_ok && !token_ok) {
if (auth_ok && utoken_ok && !token_ok) {
/* This might be a resent message, due to the client not getting
our reply to the first attempt. See if we can find the message. */
prev_tx_message = lookup_reply(rx_message_token, rx_message_seq, rx_attempt);
@ -1997,14 +1972,14 @@ read_from_cmd_socket(void *anything)
}
if (md5_ok && utoken_ok && token_ok) {
if (auth_ok && utoken_ok && token_ok) {
/* See whether we can discard the previous reply from storage */
token_acknowledged(rx_message_token, &now);
}
valid_ts = 0;
if (md5_ok) {
if (auth_ok) {
struct timeval ts;
UTI_TimevalNetworkToHost(&rx_message.data.logon.ts, &ts);
@ -2019,7 +1994,7 @@ read_from_cmd_socket(void *anything)
issue_token = 0;
}
authenticated = md5_ok & utoken_ok & token_ok;
authenticated = auth_ok & utoken_ok & token_ok;
if (authenticated) {
CLG_LogCommandAccess(&remote_ip, CLG_CMD_AUTH, cooked_now.tv_sec);
@ -2119,15 +2094,15 @@ read_from_cmd_socket(void *anything)
/* If the log-on fails, record the reason why */
if (!issue_token && !LOG_RateLimited()) {
LOG(LOGS_WARN, LOGF_CmdMon,
"Bad command logon from %s port %d (md5_ok=%d valid_ts=%d)\n",
"Bad command logon from %s port %d (auth_ok=%d valid_ts=%d)",
UTI_IPToString(&remote_ip),
remote_port,
md5_ok, valid_ts);
auth_ok, valid_ts);
}
if (issue_token == 1) {
tx_message.status = htons(STT_SUCCESS);
} else if (!md5_ok) {
} else if (!auth_ok) {
tx_message.status = htons(STT_UNAUTH);
} else if (!valid_ts) {
tx_message.status = htons(STT_INVALIDTS);
@ -2298,8 +2273,10 @@ read_from_cmd_socket(void *anything)
}
}
if (md5_ok) {
generate_tx_packet_auth(&tx_message);
if (auth_ok) {
auth_length = generate_tx_packet_auth(&tx_message);
} else {
auth_length = 0;
}
if (token_ok) {
@ -2318,7 +2295,7 @@ read_from_cmd_socket(void *anything)
static int do_it=1;
if (do_it) {
transmit_reply(&tx_message, &where_from);
transmit_reply(&tx_message, &where_from, auth_length);
}
#if 0

7
configure vendored
View file

@ -472,6 +472,10 @@ if [ $feat_readline = "1" ]; then
fi
fi
HASH_OBJ="hash_intmd5.o"
HASH_COMPILE=""
HASH_LINK=""
SYSCONFDIR=/etc
if [ "x$SETSYSCONFDIR" != "x" ]; then
SYSCONFDIR=$SETSYSCONFDIR
@ -536,6 +540,9 @@ sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
s%@READLINE_LINK@%${READLINE_LINK}%;\
s%@HASH_OBJ@%${HASH_OBJ}%;\
s%@HASH_LINK@%${HASH_LINK}%;\
s%@HASH_COMPILE@%${HASH_COMPILE}%;\
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
s%@BINDIR@%${BINDIR}%;\
s%@SBINDIR@%${SBINDIR}%;\

41
hash.h Normal file
View file

@ -0,0 +1,41 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2011
*
* 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 crypto hashing.
*/
#ifndef GOT_HASH_H
#define GOT_HASH_H
/* length of hash values produced by SHA512 */
#define MAX_HASH_LENGTH 64
extern int HSH_GetHashId(const char *name);
extern unsigned int HSH_Hash(int id,
const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len);
#endif

64
hash_intmd5.c Normal file
View file

@ -0,0 +1,64 @@
/*
chronyd/chronyc - Programs for keeping computer clocks accurate.
**********************************************************************
* Copyright (C) Miroslav Lichvar 2011
*
* 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.
*
**********************************************************************
=======================================================================
Routines implementing crypto hashing using internal MD5 implementation.
*/
#include "config.h"
#include "sysincl.h"
#include "hash.h"
#include "memory.h"
#include "md5.c"
static MD5_CTX ctx;
int
HSH_GetHashId(const char *name)
{
/* only MD5 is supported */
if (strcmp(name, "MD5"))
return -1;
return 0;
}
unsigned int
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
const unsigned char *in2, unsigned int in2_len,
unsigned char *out, unsigned int out_len)
{
if (out_len < 16)
return 0;
MD5Init(&ctx);
MD5Update(&ctx, in1, in1_len);
if (in2)
MD5Update(&ctx, in2, in2_len);
MD5Final(&ctx);
memcpy(out, ctx.digest, 16);
return 16;
}

164
keys.c
View file

@ -34,11 +34,17 @@
#include "keys.h"
#include "conf.h"
#include "memory.h"
#include "util.h"
#include "local.h"
#include "logging.h"
typedef struct {
unsigned long id;
char *val;
int len;
int hash_id;
int auth_delay;
} Key;
#define MAX_KEYS 256
@ -47,7 +53,7 @@ static int n_keys;
static Key keys[MAX_KEYS];
static int command_key_valid;
static int command_key_pos;
static int command_key_id;
static int cache_valid;
static unsigned long cache_key_id;
static int cache_key_pos;
@ -75,6 +81,37 @@ KEY_Finalise(void)
/* ================================================== */
static int
determine_hash_delay(int key_id)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
int i;
for (i = 0; i < 10; i++) {
LCL_ReadRawTime(&before);
KEY_GenerateAuth(key_id, (unsigned char *)&pkt, NTP_NORMAL_PACKET_SIZE,
(unsigned char *)&pkt.auth_data, sizeof (pkt.auth_data));
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0 || usecs < min_usecs) {
min_usecs = usecs;
}
}
#if 0
LOG(LOGS_INFO, LOGF_Keys, "authentication delay for key %d: %d useconds", key_id, min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
return min_usecs + (min_usecs >> 4);
}
/* ================================================== */
/* Compare two keys */
static int
@ -102,16 +139,16 @@ compare_keys_by_id(const void *a, const void *b)
void
KEY_Reload(void)
{
int i, len1;
int i, len1, fields;
char *key_file;
FILE *in;
unsigned long key_id;
char line[KEYLEN+1], keyval[KEYLEN+1];
char line[KEYLEN+1], buf1[KEYLEN+1], buf2[KEYLEN+1];
char *keyval, *hashname;
for (i=0; i<n_keys; i++) {
Free(keys[i].val);
}
n_keys = 0;
key_file = CNF_GetKeysFile();
@ -127,8 +164,21 @@ KEY_Reload(void)
if (line[len1] == '\n') {
line[len1] = '\0';
}
fields = sscanf(line, "%lu%" SKEYLEN "s%" SKEYLEN "s", &key_id, buf1, buf2);
if (fields >= 2 && fields <= 3) {
if (fields == 3) {
hashname = buf1;
keyval = buf2;
} else {
hashname = "MD5";
keyval = buf1;
}
keys[n_keys].hash_id = HSH_GetHashId(hashname);
if (keys[n_keys].hash_id < 0) {
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %d", key_id);
continue;
}
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
keys[n_keys].id = key_id;
keys[n_keys].len = strlen(keyval);
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len);
@ -149,6 +199,10 @@ KEY_Reload(void)
command_key_valid = 0;
cache_valid = 0;
for (i=0; i<n_keys; i++) {
keys[i].auth_delay = determine_hash_delay(keys[i].id);
}
return;
}
@ -172,30 +226,8 @@ lookup_key(unsigned long id)
/* ================================================== */
void
KEY_CommandKey(char **key, int *len)
{
unsigned long command_key_id;
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
command_key_pos = lookup_key(command_key_id);
command_key_valid = 1;
}
if (command_key_pos >= 0) {
*key = keys[command_key_pos].val;
*len = keys[command_key_pos].len;
} else {
*key = "";
*len = 0;
}
}
/* ================================================== */
int
KEY_GetKey(unsigned long key_id, char **key, int *len)
static int
get_key_pos(unsigned long key_id)
{
if (!cache_valid || key_id != cache_key_id) {
cache_valid = 1;
@ -203,15 +235,19 @@ KEY_GetKey(unsigned long key_id, char **key, int *len)
cache_key_id = key_id;
}
if (cache_key_pos >= 0) {
*key = keys[cache_key_pos].val;
*len = keys[cache_key_pos].len;
return 1;
} else {
*key = "";
*len = 0;
return 0;
return cache_key_pos;
}
/* ================================================== */
unsigned long
KEY_GetCommandKey(void)
{
if (!command_key_valid) {
command_key_id = CNF_GetCommandKey();
}
return command_key_id;
}
/* ================================================== */
@ -239,3 +275,57 @@ KEY_KeyKnown(unsigned long key_id)
}
}
}
/* ================================================== */
int
KEY_GetAuthDelay(unsigned long key_id)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return keys[key_pos].auth_delay;
}
/* ================================================== */
int
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}
/* ================================================== */
int
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
const unsigned char *auth, int auth_len)
{
int key_pos;
key_pos = get_key_pos(key_id);
if (key_pos < 0) {
return 0;
}
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
data, data_len, auth, auth_len);
}

8
keys.h
View file

@ -32,9 +32,15 @@ extern void KEY_Finalise(void);
extern void KEY_Reload(void);
extern void KEY_CommandKey(char **key, int *len);
extern unsigned long KEY_GetCommandKey(void);
extern int KEY_GetKey(unsigned long key_id, char **key, int *len);
extern int KEY_KeyKnown(unsigned long key_id);
extern int KEY_GetAuthDelay(unsigned long key_id);
extern int KEY_GenerateAuth(unsigned long key_id, const unsigned char *data,
int data_len, unsigned char *auth, int auth_len);
extern int KEY_CheckAuth(unsigned long key_id, const unsigned char *data,
int data_len, const unsigned char *auth, int auth_len);
#endif /* GOT_KEYS_H */

View file

@ -54,6 +54,7 @@ typedef enum {
LOGF_CmdMon,
LOGF_Acquire,
LOGF_Manual,
LOGF_Keys,
LOGF_Logging,
LOGF_Rtc,
LOGF_Regress,

2
md5.c
View file

@ -37,8 +37,6 @@
***********************************************************************
*/
#include "config.h"
#include "md5.h"
/*

8
ntp.h
View file

@ -33,6 +33,8 @@
#include <inttypes.h>
#endif
#include "hash.h"
typedef struct {
uint32_t hi;
uint32_t lo;
@ -40,7 +42,7 @@ typedef struct {
typedef uint32_t NTP_int32;
#define AUTH_DATA_LEN 16
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
/* Type definition for leap bits */
typedef enum {
@ -72,7 +74,7 @@ typedef struct {
NTP_int64 receive_ts;
NTP_int64 transmit_ts;
NTP_int32 auth_keyid;
uint8_t auth_data[AUTH_DATA_LEN];
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
} NTP_Packet;
/* We have to declare a buffer type to hold a datagram read from the
@ -89,7 +91,7 @@ typedef union {
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
} ReceiveBuffer;
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN))
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
/* ================================================== */

View file

@ -40,7 +40,6 @@
#include "conf.h"
#include "logging.h"
#include "keys.h"
#include "md5.h"
#include "addrfilt.h"
#include "clientlog.h"
@ -212,13 +211,10 @@ struct NCR_Instance_Record {
static ADF_AuthTable access_auth_table;
static int md5_offset_usecs;
/* ================================================== */
/* Forward prototypes */
static void transmit_timeout(void *arg);
static void determine_md5_delay(void);
/* ================================================== */
@ -230,9 +226,6 @@ NCR_Initialise(void)
: -1;
access_auth_table = ADF_CreateTable();
determine_md5_delay();
}
/* ================================================== */
@ -363,100 +356,11 @@ NCR_DestroyInstance(NCR_Instance instance)
/* ================================================== */
/* ================================================== */
static int
generate_packet_auth(NTP_Packet *pkt, unsigned long keyid)
check_packet_auth(NTP_Packet *pkt, unsigned long keyid, int auth_len)
{
int keylen;
char *keytext;
int keyok;
MD5_CTX ctx;
keyok = KEY_GetKey(keyid, &keytext, &keylen);
if (keyok) {
pkt->auth_keyid = htonl(keyid);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) keytext, keylen);
MD5Update(&ctx, (unsigned char *) pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
memcpy(&(pkt->auth_data), &ctx.digest, 16);
return 1;
} else {
pkt->auth_keyid = htonl(0);
return 0;
}
}
/* ================================================== */
static void
determine_md5_delay(void)
{
NTP_Packet pkt;
struct timeval before, after;
unsigned long usecs, min_usecs=0;
MD5_CTX ctx;
static const char *example_key = "#a0,243asd=-b ds";
int slen;
int i;
slen = strlen(example_key);
for (i=0; i<10; i++) {
LCL_ReadRawTime(&before);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned const char *) example_key, slen);
MD5Update(&ctx, (unsigned const char *) &pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
LCL_ReadRawTime(&after);
usecs = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec);
if (i == 0) {
min_usecs = usecs;
} else {
if (usecs < min_usecs) {
min_usecs = usecs;
}
}
}
#ifdef TRACEON
LOG(LOGS_INFO, LOGF_NtpCore, "MD5 took %d useconds", min_usecs);
#endif
/* Add on a bit extra to allow for copying, conversions etc */
md5_offset_usecs = min_usecs + (min_usecs >> 4);
}
/* ================================================== */
static int
check_packet_auth(NTP_Packet *pkt, unsigned long keyid)
{
int keylen;
char *keytext;
int keyok;
MD5_CTX ctx;
keyok = KEY_GetKey(keyid, &keytext, &keylen);
if (keyok) {
pkt->auth_keyid = htonl(keyid);
MD5Init(&ctx);
MD5Update(&ctx, (unsigned char *) keytext, keylen);
MD5Update(&ctx, (unsigned char *) pkt, offsetof(NTP_Packet, auth_keyid));
MD5Final(&ctx);
if (!memcmp((void *) &ctx.digest, (void *) &(pkt->auth_data), 16)) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
return KEY_CheckAuth(keyid, (void *)pkt, offsetof(NTP_Packet, auth_keyid),
(void *)&(pkt->auth_data), auth_len);
}
/* ================================================== */
@ -572,13 +476,21 @@ transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
/* Authenticate */
if (do_auth) {
int auth_len;
/* Pre-compensate the transmit time by approx. how long it will
take to generate the MD5 authentication bytes. */
local_transmit.tv_usec += md5_offset_usecs;
take to generate the authentication data. */
local_transmit.tv_usec += KEY_GetAuthDelay(key_id);
UTI_NormaliseTimeval(&local_transmit);
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
generate_packet_auth(&message, key_id);
NIO_SendAuthenticatedPacket(&message, where_to);
auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
offsetof(NTP_Packet, auth_keyid),
(unsigned char *)&message.auth_data, sizeof (message.auth_data));
if (auth_len > 0) {
message.auth_keyid = htonl(key_id);
NIO_SendAuthenticatedPacket(&message, where_to,
sizeof (message.auth_keyid) + auth_len);
}
} else {
UTI_TimevalToInt64(&local_transmit, &message.transmit_ts);
NIO_SendNormalPacket(&message, where_to);
@ -723,7 +635,7 @@ transmit_timeout(void *arg)
/* ================================================== */
static void
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int do_auth)
receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance inst, int auth_len)
{
int pkt_leap;
int source_is_synchronized;
@ -953,12 +865,12 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins
/* Test 5 relates to authentication. */
if (inst->do_auth) {
if (do_auth) {
if (auth_len > 0) {
auth_key_id = ntohl(message->auth_keyid);
if (!KEY_KeyKnown(auth_key_id)) {
test5 = 0;
} else {
test5 = check_packet_auth(message, auth_key_id);
test5 = check_packet_auth(message, auth_key_id, auth_len);
}
} else {
/* If we expect authenticated info from this peer/server and the packet
@ -1323,14 +1235,13 @@ NCR_ProcessKnown
struct timeval *now, /* timestamp at time of receipt */
double now_err,
NCR_Instance inst, /* the instance record for this peer/server */
int do_auth /* whether the received packet allegedly contains
authentication info*/
int length /* the length of the received packet */
)
{
int pkt_mode;
int version;
int valid_auth, valid_key;
int authenticate_reply;
int authenticate_reply, auth_len;
unsigned long auth_key_id;
unsigned long reply_auth_key_id;
@ -1344,6 +1255,12 @@ NCR_ProcessKnown
/* Perform tests mentioned in RFC1305 to validate packet contents */
pkt_mode = (message->lvm >> 0) & 0x7;
/* Length of the authentication data, if any */
auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
if (auth_len < 0) {
auth_len = 0;
}
/* Now, depending on the mode we decide what to do */
switch (pkt_mode) {
case MODE_CLIENT:
@ -1367,11 +1284,11 @@ NCR_ProcessKnown
CLG_LogNTPClientAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
if (do_auth) {
if (auth_len > 0) {
auth_key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(auth_key_id);
if (valid_key) {
valid_auth = check_packet_auth(message, auth_key_id);
valid_auth = check_packet_auth(message, auth_key_id, auth_len);
} else {
valid_auth = 0;
}
@ -1410,7 +1327,7 @@ NCR_ProcessKnown
case MODE_ACTIVE:
/* Ordinary symmetric peering */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_PASSIVE:
/* In this software this case should not arise, we don't
@ -1420,7 +1337,7 @@ NCR_ProcessKnown
/* This is where we have the remote configured as a server and he has
us configured as a peer - fair enough. */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_SERVER:
/* Nonsense - we can't have a preconfigured server */
@ -1441,14 +1358,14 @@ NCR_ProcessKnown
case MODE_ACTIVE:
/* Slightly bizarre combination, but we can still process it */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_PASSIVE:
/* We have no passive peers in this software */
break;
case MODE_CLIENT:
/* Standard case where he's a server and we're the client */
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_SERVER:
/* RFC1305 error condition. */
@ -1469,7 +1386,7 @@ NCR_ProcessKnown
/* This would arise if we have the remote configured as a peer and
he does not have us configured */
CLG_LogNTPPeerAccess(&inst->remote_addr.ip_addr, (time_t) now->tv_sec);
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_PASSIVE:
/* Error condition in RFC1305. Also, we can't have any
@ -1478,7 +1395,7 @@ NCR_ProcessKnown
break;
case MODE_CLIENT:
/* This is a wierd combination - how could it arise? */
receive_packet(message, now, now_err, inst, do_auth);
receive_packet(message, now, now_err, inst, auth_len);
break;
case MODE_SERVER:
/* Error condition in RFC1305 */
@ -1513,14 +1430,13 @@ NCR_ProcessUnknown
struct timeval *now, /* timestamp at time of receipt */
double now_err, /* assumed error in the timestamp */
NTP_Remote_Address *remote_addr,
int do_auth /* whether the received packet allegedly contains
authentication info */
int length /* the length of the received packet */
)
{
NTP_Mode his_mode;
NTP_Mode my_mode;
int my_poll, version;
int valid_key, valid_auth;
int valid_key, valid_auth, auth_len;
unsigned long key_id;
/* Check version */
@ -1552,15 +1468,18 @@ NCR_ProcessUnknown
he has supplied a wierd mode in his request, so ignore it. */
if (my_mode != MODE_UNDEFINED) {
int do_auth = 0;
auth_len = length - (NTP_NORMAL_PACKET_SIZE + sizeof (message->auth_keyid));
if (do_auth) {
if (auth_len > 0) {
/* Only reply if we know the key and the packet authenticates
properly. */
key_id = ntohl(message->auth_keyid);
valid_key = KEY_KeyKnown(key_id);
do_auth = 1;
if (valid_key) {
valid_auth = check_packet_auth(message, key_id);
valid_auth = check_packet_auth(message, key_id, auth_len);
} else {
valid_auth = 0;
}

View file

@ -54,11 +54,11 @@ extern void NCR_DestroyInstance(NCR_Instance instance);
/* This routine is called when a new packet arrives off the network,
and it relates to a source we have an ongoing protocol exchange with */
extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int do_auth);
extern void NCR_ProcessKnown(NTP_Packet *message, struct timeval *now, double now_err, NCR_Instance data, int length);
/* This routine is called when a new packet arrives off the network,
and we do not recognize its source */
extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int do_auth);
extern void NCR_ProcessUnknown(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* Slew receive and transmit times in instance records */
extern void NCR_SlewTimes(NCR_Instance inst, struct timeval *when, double dfreq, double doffset);

View file

@ -376,13 +376,9 @@ read_from_socket(void *anything)
#endif
}
if (status == NTP_NORMAL_PACKET_SIZE) {
if (status >= NTP_NORMAL_PACKET_SIZE && status <= sizeof(NTP_Packet)) {
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
} else if (status == sizeof(NTP_Packet)) {
NSR_ProcessAuthenticatedReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr);
NSR_ProcessReceive((NTP_Packet *) &message.ntp_pkt, &now, now_err, &remote_addr, status);
} else {
@ -523,9 +519,9 @@ NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
/* Send an authenticated packet to a given address */
void
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr)
NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len)
{
send_packet((void *) packet, sizeof(NTP_Packet), remote_addr);
send_packet((void *) packet, NTP_NORMAL_PACKET_SIZE + auth_len, remote_addr);
}
/* ================================================== */

View file

@ -41,7 +41,7 @@ extern void NIO_Finalise(void);
extern void NIO_SendNormalPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
/* Function to transmit an authenticated packet */
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr);
extern void NIO_SendAuthenticatedPacket(NTP_Packet *packet, NTP_Remote_Address *remote_addr, int auth_len);
/* Function to send a datagram to a remote machine's UDP echo port. */
extern void NIO_SendEcho(NTP_Remote_Address *remote_addr);

View file

@ -346,9 +346,10 @@ NSR_RemoveSource(NTP_Remote_Address *remote_addr)
/* ================================================== */
/* This routine is called by ntp_io when a new packet arrives off the network.*/
/* This routine is called by ntp_io when a new packet arrives off the network,
possibly with an authentication tail */
void
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length)
{
int slot, found;
@ -362,27 +363,9 @@ NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP
find_slot(remote_addr, &slot, &found);
if (found == 2) { /* Must match IP address AND port number */
NCR_ProcessKnown(message, now, now_err, records[slot].data, 0);
NCR_ProcessKnown(message, now, now_err, records[slot].data, length);
} else {
NCR_ProcessUnknown(message, now, now_err, remote_addr, 0);
}
}
/* ================================================== */
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
void
NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr)
{
int slot, found;
assert(initialised);
find_slot(remote_addr, &slot, &found);
if (found == 2) {
NCR_ProcessKnown(message, now, now_err, records[slot].data, 1);
} else {
NCR_ProcessUnknown(message, now, now_err, remote_addr, 1);
NCR_ProcessUnknown(message, now, now_err, remote_addr, length);
}
}

View file

@ -61,10 +61,7 @@ extern void NSR_ResolveSources(void);
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet arrives off the network */
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
/* Initialisation function */
extern void NSR_Initialise(void);

39
util.c
View file

@ -30,7 +30,7 @@
#include "sysincl.h"
#include "util.h"
#include "md5.h"
#include "hash.h"
/* ================================================== */
@ -336,16 +336,24 @@ UTI_StringToIP(const char *addr, IPAddr *ip)
uint32_t
UTI_IPToRefid(IPAddr *ip)
{
MD5_CTX ctx;
static int MD5_hash = -1;
unsigned char buf[16];
switch (ip->family) {
case IPADDR_INET4:
return ip->addr.in4;
case IPADDR_INET6:
MD5Init(&ctx);
MD5Update(&ctx, (unsigned const char *) ip->addr.in6, sizeof (ip->addr.in6));
MD5Final(&ctx);
return ctx.digest[0] << 24 | ctx.digest[1] << 16 | ctx.digest[2] << 8 | ctx.digest[3];
if (MD5_hash < 0) {
MD5_hash = HSH_GetHashId("MD5");
assert(MD5_hash >= 0);
}
if (HSH_Hash(MD5_hash, (unsigned const char *)ip->addr.in6, sizeof
(ip->addr.in6), NULL, 0, buf, 16) != 16) {
assert(0);
return 0;
};
return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
}
return 0;
}
@ -612,3 +620,22 @@ UTI_FdSetCloexec(int fd)
}
/* ================================================== */
int
UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len)
{
return HSH_Hash(hash_id, key, key_len, data, data_len, auth, auth_len);
}
/* ================================================== */
int
UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len)
{
unsigned char buf[MAX_HASH_LENGTH];
return UTI_GenerateNTPAuth(hash_id, key, key_len, data, data_len,
buf, sizeof (buf)) == auth_len && !memcmp(buf, auth, auth_len);
}

6
util.h
View file

@ -32,6 +32,7 @@
#include "addressing.h"
#include "ntp.h"
#include "candm.h"
#include "hash.h"
/* Convert a timeval into a floating point number of seconds */
extern void UTI_TimevalToDouble(struct timeval *a, double *b);
@ -101,6 +102,11 @@ extern Float UTI_FloatHostToNetwork(double x);
/* Set FD_CLOEXEC on descriptor */
extern void UTI_FdSetCloexec(int fd);
extern int UTI_GenerateNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, unsigned char *auth, int auth_len);
extern int UTI_CheckNTPAuth(int hash_id, const unsigned char *key, int key_len,
const unsigned char *data, int data_len, const unsigned char *auth, int auth_len);
#if defined (INLINE_UTILITIES)
#define INLINE_STATIC inline static
#include "util.c"