From 777303f1309668170f83e0db237b3c73355b4284 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 19 Oct 2011 13:26:03 +0200 Subject: [PATCH] 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. --- Makefile.in | 22 +++---- candm.h | 15 +++-- client.c | 111 ++++++++++++++++++++-------------- cmdmon.c | 101 ++++++++++++------------------- configure | 7 +++ hash.h | 41 +++++++++++++ hash_intmd5.c | 64 ++++++++++++++++++++ keys.c | 164 ++++++++++++++++++++++++++++++++++++++------------ keys.h | 8 ++- logging.h | 1 + md5.c | 2 - ntp.h | 8 ++- ntp_core.c | 163 +++++++++++++------------------------------------ ntp_core.h | 4 +- ntp_io.c | 12 ++-- ntp_io.h | 2 +- ntp_sources.c | 27 ++------- ntp_sources.h | 5 +- util.c | 39 ++++++++++-- util.h | 6 ++ 20 files changed, 473 insertions(+), 329 deletions(-) create mode 100644 hash.h create mode 100644 hash_intmd5.c diff --git a/Makefile.in b/Makefile.in index f5ad0bb..bc02bbd 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/candm.h b/candm.h index 8c34a72..fdff31d 100644 --- a/candm.h +++ b/candm.h @@ -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; /* ================================================== */ diff --git a/client.c b/client.c index 788ec96..7884991 100644 --- a/client.c +++ b/client.c @@ -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 : 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 : 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; @@ -2769,6 +2788,10 @@ main(int argc, char **argv) if (on_terminal && (argc == 0)) { display_gpl(); } + + /* MD5 is the default authentication hash */ + auth_hash_id = HSH_GetHashId("MD5"); + assert(auth_hash_id >= 0); open_io(hostname, port); diff --git a/cmdmon.c b/cmdmon.c index e0ea228..0baf86d 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -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 diff --git a/configure b/configure index 4f2c381..39c4e0e 100755 --- a/configure +++ b/configure @@ -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}%;\ diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..cb08233 --- /dev/null +++ b/hash.h @@ -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 diff --git a/hash_intmd5.c b/hash_intmd5.c new file mode 100644 index 0000000..16726d8 --- /dev/null +++ b/hash_intmd5.c @@ -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; +} diff --git a/keys.c b/keys.c index 68a1f1b..36fd56b 100644 --- a/keys.c +++ b/keys.c @@ -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= 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= 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); +} diff --git a/keys.h b/keys.h index 3de80ce..9ba30c1 100644 --- a/keys.h +++ b/keys.h @@ -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 */ diff --git a/logging.h b/logging.h index b927eaa..13ef41e 100644 --- a/logging.h +++ b/logging.h @@ -54,6 +54,7 @@ typedef enum { LOGF_CmdMon, LOGF_Acquire, LOGF_Manual, + LOGF_Keys, LOGF_Logging, LOGF_Rtc, LOGF_Regress, diff --git a/md5.c b/md5.c index e7a1121..f997a6e 100644 --- a/md5.c +++ b/md5.c @@ -37,8 +37,6 @@ *********************************************************************** */ -#include "config.h" - #include "md5.h" /* diff --git a/ntp.h b/ntp.h index 297b25b..7ebeece 100644 --- a/ntp.h +++ b/ntp.h @@ -33,6 +33,8 @@ #include #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) /* ================================================== */ diff --git a/ntp_core.c b/ntp_core.c index c935cdb..e7b8c01 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -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; } diff --git a/ntp_core.h b/ntp_core.h index 239e3c8..c21199b 100644 --- a/ntp_core.h +++ b/ntp_core.h @@ -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); diff --git a/ntp_io.c b/ntp_io.c index 7fdff42..6a556f6 100644 --- a/ntp_io.c +++ b/ntp_io.c @@ -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); } /* ================================================== */ diff --git a/ntp_io.h b/ntp_io.h index d033130..231568b 100644 --- a/ntp_io.h +++ b/ntp_io.h @@ -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); diff --git a/ntp_sources.c b/ntp_sources.c index 5c05969..ca84ff4 100644 --- a/ntp_sources.c +++ b/ntp_sources.c @@ -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); } } diff --git a/ntp_sources.h b/ntp_sources.h index 654cb05..7914f92 100644 --- a/ntp_sources.h +++ b/ntp_sources.h @@ -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); diff --git a/util.c b/util.c index 33bc28f..29fbb65 100644 --- a/util.c +++ b/util.c @@ -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); +} diff --git a/util.h b/util.h index 249e778..dfcbd73 100644 --- a/util.h +++ b/util.h @@ -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"