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"