Add support for different authentication hashes
Allow different hash functions to be used in the NTP and cmdmon protocols. This breaks the cmdmon protocol compatibility. Extended key file format is used to specify the hash functions for chronyd and new authhash command is added to chronyc. MD5 is the default and the only function included in the chrony source code, other functions will be available from libraries.
This commit is contained in:
parent
6015f99d98
commit
777303f130
20 changed files with 473 additions and 329 deletions
22
Makefile.in
22
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
|
||||
|
||||
|
|
15
candm.h
15
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;
|
||||
|
||||
/* ================================================== */
|
||||
|
|
111
client.c
111
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 <name>: Set command authentication hash function\n");
|
||||
printf("dns -n|+n : Disable/enable resolving IP addresses to hostnames\n");
|
||||
printf("dns -4|-6|-46 : Resolve hostnames only to IPv4/IPv6/both addresses\n");
|
||||
printf("timeout <milliseconds> : Set initial response timeout\n");
|
||||
|
@ -1273,6 +1255,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
|
|||
int read_length;
|
||||
int expected_length;
|
||||
int command_length;
|
||||
int auth_length;
|
||||
struct timeval tv;
|
||||
int timeout;
|
||||
int n_attempts;
|
||||
|
@ -1301,19 +1284,26 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
|
|||
packet and we won't get a token back */
|
||||
request->utoken = htonl(SPECIAL_UTOKEN);
|
||||
}
|
||||
generate_auth(request);
|
||||
auth_length = generate_auth(request);
|
||||
} else {
|
||||
memset(request->auth, 0, sizeof (request->auth));
|
||||
auth_length = 0;
|
||||
}
|
||||
|
||||
command_length = PKL_CommandLength(request);
|
||||
assert(command_length > 0);
|
||||
|
||||
/* add empty MD5 auth so older servers will not drop the request
|
||||
due to bad length */
|
||||
if (!auth_length) {
|
||||
memset(((char *)request) + command_length, 0, 16);
|
||||
auth_length = 16;
|
||||
}
|
||||
|
||||
#if 0
|
||||
printf("Sent command length=%d bytes\n", command_length);
|
||||
printf("Sent command length=%d bytes auth length=%d bytes\n", command_length, auth_length);
|
||||
#endif
|
||||
|
||||
if (sendto(sock_fd, (void *) request, command_length, 0,
|
||||
if (sendto(sock_fd, (void *) request, command_length + auth_length, 0,
|
||||
&his_addr.u, his_addr_len) < 0) {
|
||||
|
||||
|
||||
|
@ -1376,7 +1366,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
|
|||
read_length = recvfrom_status;
|
||||
expected_length = PKL_ReplyLength(reply);
|
||||
|
||||
bad_length = (read_length != expected_length);
|
||||
bad_length = (read_length < expected_length);
|
||||
bad_sender = (where_from.u.sa_family != his_addr.u.sa_family ||
|
||||
(where_from.u.sa_family == AF_INET &&
|
||||
(where_from.in4.sin_addr.s_addr != his_addr.in4.sin_addr.s_addr ||
|
||||
|
@ -1431,7 +1421,7 @@ submit_request(CMD_Request *request, CMD_Reply *reply, int *reply_auth_ok)
|
|||
#endif
|
||||
|
||||
if (password_seen) {
|
||||
*reply_auth_ok = check_reply_auth(reply);
|
||||
*reply_auth_ok = check_reply_auth(reply, read_length);
|
||||
} else {
|
||||
/* Assume in this case that the reply is always considered
|
||||
to be authentic */
|
||||
|
@ -2476,6 +2466,32 @@ process_cmd_dns(const char *line)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_authhash(const char *line)
|
||||
{
|
||||
char hash_name[50];
|
||||
int new_hash_id;
|
||||
|
||||
assert(auth_hash_id >= 0);
|
||||
|
||||
if (sscanf(line, "%49s", hash_name) != 1) {
|
||||
fprintf(stderr, "Could not parse hash name\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_hash_id = HSH_GetHashId(hash_name);
|
||||
if (new_hash_id < 0) {
|
||||
fprintf(stderr, "Unknown hash name: %s\n", hash_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
auth_hash_id = new_hash_id;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
process_cmd_timeout(const char *line)
|
||||
{
|
||||
|
@ -2634,6 +2650,9 @@ process_line(char *line, int *quit)
|
|||
} else if (!strncmp(p, "waitsync", 8)) {
|
||||
ret = process_cmd_waitsync(p+8);
|
||||
do_normal_submit = 0;
|
||||
} else if (!strncmp(p, "authhash", 8)) {
|
||||
ret = process_cmd_authhash(p+8);
|
||||
do_normal_submit = 0;
|
||||
} else if (!strncmp(p, "dns ", 4)) {
|
||||
ret = process_cmd_dns(p+4);
|
||||
do_normal_submit = 0;
|
||||
|
@ -2770,6 +2789,10 @@ main(int argc, char **argv)
|
|||
display_gpl();
|
||||
}
|
||||
|
||||
/* MD5 is the default authentication hash */
|
||||
auth_hash_id = HSH_GetHashId("MD5");
|
||||
assert(auth_hash_id >= 0);
|
||||
|
||||
open_io(hostname, port);
|
||||
|
||||
if (argc > 0) {
|
||||
|
|
101
cmdmon.c
101
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
|
||||
|
|
7
configure
vendored
7
configure
vendored
|
@ -472,6 +472,10 @@ if [ $feat_readline = "1" ]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
HASH_OBJ="hash_intmd5.o"
|
||||
HASH_COMPILE=""
|
||||
HASH_LINK=""
|
||||
|
||||
SYSCONFDIR=/etc
|
||||
if [ "x$SETSYSCONFDIR" != "x" ]; then
|
||||
SYSCONFDIR=$SETSYSCONFDIR
|
||||
|
@ -536,6 +540,9 @@ sed -e "s%@EXTRA_OBJECTS@%${EXTRA_OBJECTS}%;\
|
|||
s%@EXTRA_CLI_LIBS@%${EXTRA_CLI_LIBS}%;\
|
||||
s%@READLINE_COMPILE@%${READLINE_COMPILE}%;\
|
||||
s%@READLINE_LINK@%${READLINE_LINK}%;\
|
||||
s%@HASH_OBJ@%${HASH_OBJ}%;\
|
||||
s%@HASH_LINK@%${HASH_LINK}%;\
|
||||
s%@HASH_COMPILE@%${HASH_COMPILE}%;\
|
||||
s%@SYSCONFDIR@%${SYSCONFDIR}%;\
|
||||
s%@BINDIR@%${BINDIR}%;\
|
||||
s%@SBINDIR@%${SBINDIR}%;\
|
||||
|
|
41
hash.h
Normal file
41
hash.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Header file for crypto hashing.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef GOT_HASH_H
|
||||
#define GOT_HASH_H
|
||||
|
||||
/* length of hash values produced by SHA512 */
|
||||
#define MAX_HASH_LENGTH 64
|
||||
|
||||
extern int HSH_GetHashId(const char *name);
|
||||
|
||||
extern unsigned int HSH_Hash(int id,
|
||||
const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len);
|
||||
|
||||
#endif
|
64
hash_intmd5.c
Normal file
64
hash_intmd5.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2011
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
Routines implementing crypto hashing using internal MD5 implementation.
|
||||
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "sysincl.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
|
||||
#include "md5.c"
|
||||
|
||||
static MD5_CTX ctx;
|
||||
|
||||
int
|
||||
HSH_GetHashId(const char *name)
|
||||
{
|
||||
/* only MD5 is supported */
|
||||
if (strcmp(name, "MD5"))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
HSH_Hash(int id, const unsigned char *in1, unsigned int in1_len,
|
||||
const unsigned char *in2, unsigned int in2_len,
|
||||
unsigned char *out, unsigned int out_len)
|
||||
{
|
||||
if (out_len < 16)
|
||||
return 0;
|
||||
|
||||
MD5Init(&ctx);
|
||||
MD5Update(&ctx, in1, in1_len);
|
||||
if (in2)
|
||||
MD5Update(&ctx, in2, in2_len);
|
||||
MD5Final(&ctx);
|
||||
|
||||
memcpy(out, ctx.digest, 16);
|
||||
|
||||
return 16;
|
||||
}
|
164
keys.c
164
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<n_keys; i++) {
|
||||
Free(keys[i].val);
|
||||
}
|
||||
|
||||
n_keys = 0;
|
||||
|
||||
key_file = CNF_GetKeysFile();
|
||||
|
@ -127,8 +164,21 @@ KEY_Reload(void)
|
|||
if (line[len1] == '\n') {
|
||||
line[len1] = '\0';
|
||||
}
|
||||
fields = sscanf(line, "%lu%" SKEYLEN "s%" SKEYLEN "s", &key_id, buf1, buf2);
|
||||
if (fields >= 2 && fields <= 3) {
|
||||
if (fields == 3) {
|
||||
hashname = buf1;
|
||||
keyval = buf2;
|
||||
} else {
|
||||
hashname = "MD5";
|
||||
keyval = buf1;
|
||||
}
|
||||
keys[n_keys].hash_id = HSH_GetHashId(hashname);
|
||||
if (keys[n_keys].hash_id < 0) {
|
||||
LOG(LOGS_WARN, LOGF_Keys, "Unknown hash function in key %d", key_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sscanf(line, "%lu%" SKEYLEN "s", &key_id, keyval) == 2) {
|
||||
keys[n_keys].id = key_id;
|
||||
keys[n_keys].len = strlen(keyval);
|
||||
keys[n_keys].val = MallocArray(char, 1 + keys[n_keys].len);
|
||||
|
@ -149,6 +199,10 @@ KEY_Reload(void)
|
|||
command_key_valid = 0;
|
||||
cache_valid = 0;
|
||||
|
||||
for (i=0; i<n_keys; i++) {
|
||||
keys[i].auth_delay = determine_hash_delay(keys[i].id);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -172,30 +226,8 @@ lookup_key(unsigned long id)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
void
|
||||
KEY_CommandKey(char **key, int *len)
|
||||
{
|
||||
unsigned long command_key_id;
|
||||
|
||||
if (!command_key_valid) {
|
||||
command_key_id = CNF_GetCommandKey();
|
||||
command_key_pos = lookup_key(command_key_id);
|
||||
command_key_valid = 1;
|
||||
}
|
||||
|
||||
if (command_key_pos >= 0) {
|
||||
*key = keys[command_key_pos].val;
|
||||
*len = keys[command_key_pos].len;
|
||||
} else {
|
||||
*key = "";
|
||||
*len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetKey(unsigned long key_id, char **key, int *len)
|
||||
static int
|
||||
get_key_pos(unsigned long key_id)
|
||||
{
|
||||
if (!cache_valid || key_id != cache_key_id) {
|
||||
cache_valid = 1;
|
||||
|
@ -203,15 +235,19 @@ KEY_GetKey(unsigned long key_id, char **key, int *len)
|
|||
cache_key_id = key_id;
|
||||
}
|
||||
|
||||
if (cache_key_pos >= 0) {
|
||||
*key = keys[cache_key_pos].val;
|
||||
*len = keys[cache_key_pos].len;
|
||||
return 1;
|
||||
} else {
|
||||
*key = "";
|
||||
*len = 0;
|
||||
return 0;
|
||||
return cache_key_pos;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
unsigned long
|
||||
KEY_GetCommandKey(void)
|
||||
{
|
||||
if (!command_key_valid) {
|
||||
command_key_id = CNF_GetCommandKey();
|
||||
}
|
||||
|
||||
return command_key_id;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
@ -239,3 +275,57 @@ KEY_KeyKnown(unsigned long key_id)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GetAuthDelay(unsigned long key_id)
|
||||
{
|
||||
int key_pos;
|
||||
|
||||
key_pos = get_key_pos(key_id);
|
||||
|
||||
if (key_pos < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return keys[key_pos].auth_delay;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_GenerateAuth(unsigned long key_id, const unsigned char *data, int data_len,
|
||||
unsigned char *auth, int auth_len)
|
||||
{
|
||||
int key_pos;
|
||||
|
||||
key_pos = get_key_pos(key_id);
|
||||
|
||||
if (key_pos < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return UTI_GenerateNTPAuth(keys[key_pos].hash_id,
|
||||
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
|
||||
data, data_len, auth, auth_len);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
KEY_CheckAuth(unsigned long key_id, const unsigned char *data, int data_len,
|
||||
const unsigned char *auth, int auth_len)
|
||||
{
|
||||
int key_pos;
|
||||
|
||||
key_pos = get_key_pos(key_id);
|
||||
|
||||
if (key_pos < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return UTI_CheckNTPAuth(keys[key_pos].hash_id,
|
||||
(unsigned char *)keys[key_pos].val, keys[key_pos].len,
|
||||
data, data_len, auth, auth_len);
|
||||
}
|
||||
|
|
8
keys.h
8
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 */
|
||||
|
|
|
@ -54,6 +54,7 @@ typedef enum {
|
|||
LOGF_CmdMon,
|
||||
LOGF_Acquire,
|
||||
LOGF_Manual,
|
||||
LOGF_Keys,
|
||||
LOGF_Logging,
|
||||
LOGF_Rtc,
|
||||
LOGF_Regress,
|
||||
|
|
2
md5.c
2
md5.c
|
@ -37,8 +37,6 @@
|
|||
***********************************************************************
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
|
|
8
ntp.h
8
ntp.h
|
@ -33,6 +33,8 @@
|
|||
#include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
|
@ -40,7 +42,7 @@ typedef struct {
|
|||
|
||||
typedef uint32_t NTP_int32;
|
||||
|
||||
#define AUTH_DATA_LEN 16
|
||||
#define MAX_NTP_AUTH_DATA_LEN MAX_HASH_LENGTH
|
||||
|
||||
/* Type definition for leap bits */
|
||||
typedef enum {
|
||||
|
@ -72,7 +74,7 @@ typedef struct {
|
|||
NTP_int64 receive_ts;
|
||||
NTP_int64 transmit_ts;
|
||||
NTP_int32 auth_keyid;
|
||||
uint8_t auth_data[AUTH_DATA_LEN];
|
||||
uint8_t auth_data[MAX_NTP_AUTH_DATA_LEN];
|
||||
} NTP_Packet;
|
||||
|
||||
/* We have to declare a buffer type to hold a datagram read from the
|
||||
|
@ -89,7 +91,7 @@ typedef union {
|
|||
uint8_t arbitrary[MAX_NTP_MESSAGE_SIZE];
|
||||
} ReceiveBuffer;
|
||||
|
||||
#define NTP_NORMAL_PACKET_SIZE (sizeof(NTP_Packet) - (sizeof(NTP_int32) + AUTH_DATA_LEN))
|
||||
#define NTP_NORMAL_PACKET_SIZE offsetof(NTP_Packet, auth_keyid)
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
|
|
163
ntp_core.c
163
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
12
ntp_io.c
12
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);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
|
2
ntp_io.h
2
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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,10 +61,7 @@ extern void NSR_ResolveSources(void);
|
|||
extern NSR_Status NSR_RemoveSource(NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* This routine is called by ntp_io when a new packet arrives off the network */
|
||||
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
|
||||
|
||||
/* This routine is called by ntp_io when a new packet with an authentication tail arrives off the network */
|
||||
extern void NSR_ProcessAuthenticatedReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr);
|
||||
extern void NSR_ProcessReceive(NTP_Packet *message, struct timeval *now, double now_err, NTP_Remote_Address *remote_addr, int length);
|
||||
|
||||
/* Initialisation function */
|
||||
extern void NSR_Initialise(void);
|
||||
|
|
39
util.c
39
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);
|
||||
}
|
||||
|
|
6
util.h
6
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"
|
||||
|
|
Loading…
Reference in a new issue