nts: make server and client AEAD algorithms configurable
Add ntsaeads directive to specify a list of AEAD algorithms enabled for NTS. The list is shared between the server and client. For the client it also specifies the order of priority. The default is "30 15", matching the previously hardcoded preference of AES-128-GCM-SIV (30) over AES-SIV-CMAC-256 (15).
This commit is contained in:
parent
79a790e6b5
commit
42fbf41686
6 changed files with 163 additions and 17 deletions
39
conf.c
39
conf.c
|
@ -57,6 +57,7 @@ static int parse_string(char *line, char **result);
|
|||
static int parse_int(char *line, int *result);
|
||||
static int parse_double(char *line, double *result);
|
||||
static int parse_null(char *line);
|
||||
static int parse_ints(char *line, ARR_Instance array);
|
||||
|
||||
static void parse_allow_deny(char *line, ARR_Instance restrictions, int allow);
|
||||
static void parse_authselectmode(char *);
|
||||
|
@ -261,7 +262,10 @@ static char *user;
|
|||
/* Address refresh interval */
|
||||
static int refresh = 1209600; /* 2 weeks */
|
||||
|
||||
#define DEFAULT_NTS_AEADS "30 15"
|
||||
|
||||
/* NTS server and client configuration */
|
||||
static ARR_Instance nts_aeads; /* array of int */
|
||||
static char *nts_dump_dir = NULL;
|
||||
static char *nts_ntp_server = NULL;
|
||||
static ARR_Instance nts_server_cert_files; /* array of (char *) */
|
||||
|
@ -397,6 +401,8 @@ check_number_of_args(char *line, int num)
|
|||
void
|
||||
CNF_Initialise(int r, int client_only)
|
||||
{
|
||||
char buf[10];
|
||||
|
||||
restarted = r;
|
||||
|
||||
hwts_interfaces = ARR_CreateInstance(sizeof (CNF_HwTsInterface));
|
||||
|
@ -410,6 +416,9 @@ CNF_Initialise(int r, int client_only)
|
|||
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
||||
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
|
||||
|
||||
nts_aeads = ARR_CreateInstance(sizeof (int));
|
||||
snprintf(buf, sizeof (buf), DEFAULT_NTS_AEADS);
|
||||
parse_ints(buf, nts_aeads);
|
||||
nts_server_cert_files = ARR_CreateInstance(sizeof (char *));
|
||||
nts_server_key_files = ARR_CreateInstance(sizeof (char *));
|
||||
nts_trusted_certs_paths = ARR_CreateInstance(sizeof (char *));
|
||||
|
@ -469,6 +478,7 @@ CNF_Finalise(void)
|
|||
ARR_DestroyInstance(ntp_restrictions);
|
||||
ARR_DestroyInstance(cmd_restrictions);
|
||||
|
||||
ARR_DestroyInstance(nts_aeads);
|
||||
ARR_DestroyInstance(nts_server_cert_files);
|
||||
ARR_DestroyInstance(nts_server_key_files);
|
||||
ARR_DestroyInstance(nts_trusted_certs_paths);
|
||||
|
@ -679,6 +689,8 @@ CNF_ParseLine(const char *filename, int number, char *line)
|
|||
no_system_cert = parse_null(p);
|
||||
} else if (!strcasecmp(command, "ntpsigndsocket")) {
|
||||
parse_string(p, &ntp_signd_socket);
|
||||
} else if (!strcasecmp(command, "ntsaeads")) {
|
||||
parse_ints(p, nts_aeads);
|
||||
} else if (!strcasecmp(command, "ntsratelimit")) {
|
||||
parse_ratelimit(p, &nts_ratelimit_enabled, &nts_ratelimit_interval,
|
||||
&nts_ratelimit_burst, &nts_ratelimit_leak, NULL);
|
||||
|
@ -806,6 +818,25 @@ parse_null(char *line)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
parse_ints(char *line, ARR_Instance array)
|
||||
{
|
||||
char *s;
|
||||
int v;
|
||||
|
||||
ARR_SetSize(array, 0);
|
||||
|
||||
while (*line) {
|
||||
s = line;
|
||||
line = CPS_SplitWord(line);
|
||||
parse_int(s, &v);
|
||||
ARR_AppendElement(array, &v);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static void
|
||||
parse_source(char *line, char *type, int fatal)
|
||||
{
|
||||
|
@ -2599,6 +2630,14 @@ CNF_GetRefresh(void)
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
ARR_Instance
|
||||
CNF_GetNtsAeads(void)
|
||||
{
|
||||
return nts_aeads;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
char *
|
||||
CNF_GetNtsDumpDir(void)
|
||||
{
|
||||
|
|
2
conf.h
2
conf.h
|
@ -29,6 +29,7 @@
|
|||
#define GOT_CONF_H
|
||||
|
||||
#include "addressing.h"
|
||||
#include "array.h"
|
||||
#include "reference.h"
|
||||
#include "sources.h"
|
||||
|
||||
|
@ -163,6 +164,7 @@ extern int CNF_GetPtpDomain(void);
|
|||
|
||||
extern int CNF_GetRefresh(void);
|
||||
|
||||
extern ARR_Instance CNF_GetNtsAeads(void);
|
||||
extern char *CNF_GetNtsDumpDir(void);
|
||||
extern char *CNF_GetNtsNtpServer(void);
|
||||
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
|
||||
|
|
|
@ -833,6 +833,34 @@ changes in the frequency and offset of the clock. The offsets in the
|
|||
<<chronyc.adoc#sourcestats,*sourcestats*>> reports (and the _tracking.log_ and
|
||||
_statistics.log_ files) may be smaller than the actual offsets.
|
||||
|
||||
[[ntsaeads1]]*ntsaeads* _ID_...::
|
||||
This directive specifies a list of IDs of Authenticated Encryption with
|
||||
Associated Data (AEAD) algorithms enabled for NTS authentication of NTP
|
||||
messages. The algorithms are specified in decreasing order of priority.
|
||||
Algorithms that are not supported by the installed version of the crypto
|
||||
library (Nettle, GnuTLS) are ignored.
|
||||
+
|
||||
The following IDs are supported:
|
||||
+
|
||||
* 15: AES-SIV-CMAC-256
|
||||
* 30: AES-128-GCM-SIV
|
||||
{blank}::
|
||||
+
|
||||
The default list of IDs is _30 15_. AES-128-GCM-SIV is prefered over
|
||||
AES-SIV-CMAC-256 for shorter keys, which makes NTS cookies shorter and improves
|
||||
reliability of NTS in networks that block or limit rate of longer NTP messages.
|
||||
+
|
||||
The ID of the used algorithm is reported for each server by the
|
||||
<<chronyc.adoc#authdata,*authdata*>> command.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsaeads 15
|
||||
----
|
||||
+
|
||||
This list is used also by the <<ntsaeads2,NTS server>>.
|
||||
|
||||
[[ntsdumpdir1]]*ntsdumpdir* _directory_::
|
||||
This directive specifies a directory for the client to save NTS cookies it
|
||||
received from the server in order to avoid making an NTS-KE request when
|
||||
|
@ -1779,6 +1807,43 @@ per process that the NTS server will accept. The default value is 100. The
|
|||
maximum practical value is half of the system *FD_SETSIZE* constant (usually
|
||||
1024).
|
||||
|
||||
[[ntsaeads2]]*ntsaeads* _ID_...::
|
||||
This directive specifies a list of IDs of Authenticated Encryption with
|
||||
Associated Data (AEAD) algorithms enabled for NTS authentication of NTP
|
||||
messages. *chronyd* as a server uses the first enabled algorithm from the list
|
||||
provided by the client. Algorithms that are not supported by the installed
|
||||
version of the crypto library (Nettle, GnuTLS) are ignored.
|
||||
+
|
||||
The following IDs are supported:
|
||||
+
|
||||
* 15: AES-SIV-CMAC-256
|
||||
* 30: AES-128-GCM-SIV
|
||||
{blank}::
|
||||
+
|
||||
The default list of IDs is _30 15_. AES-128-GCM-SIV is prefered over
|
||||
AES-SIV-CMAC-256 for shorter keys, which makes NTS cookies shorter and improves
|
||||
reliability of NTS in networks that block or limit rate of longer NTP messages.
|
||||
+
|
||||
An example of the directive is:
|
||||
+
|
||||
----
|
||||
ntsaeads 15
|
||||
----
|
||||
+
|
||||
This list is used also by the <<ntsaeads1,NTS client>>.
|
||||
+
|
||||
Note the the NTS specification (RFC 8915) requires servers to support
|
||||
AES-SIV-CMAC-256, i.e. 15 should be always included in the specified list.
|
||||
+
|
||||
The AES-128-GCM-SIV keys used by *chronyd* do not comply to RFC 8915 for
|
||||
compatibility with older *chrony* clients unless the use of compliant keys is
|
||||
negotiated with an
|
||||
https://chrony-project.org/doc/spec/nts-compliant-128gcm.html[NTS-KE record].
|
||||
Support for this record was added in version 4.6.1. As a client, *chronyd* can
|
||||
interoperate with a server that uses compliant keys, but does not support the
|
||||
negotiation, if it responds to incorrectly authenticated requests with an NTS
|
||||
NAK.
|
||||
|
||||
[[ntsdumpdir2]]*ntsdumpdir* _directory_::
|
||||
This directive specifies a directory where *chronyd* operating as an NTS server
|
||||
can save the keys which encrypt NTS cookies provided to clients. The keys are
|
||||
|
|
|
@ -100,12 +100,14 @@ name_resolve_handler(DNS_Status status, int n_addrs, IPAddr *ip_addrs, void *arg
|
|||
|
||||
/* ================================================== */
|
||||
|
||||
#define MAX_AEAD_ALGORITHMS 4
|
||||
|
||||
static int
|
||||
prepare_request(NKC_Instance inst)
|
||||
{
|
||||
NKSN_Instance session = inst->session;
|
||||
uint16_t data[2];
|
||||
int i, length;
|
||||
uint16_t data[MAX_AEAD_ALGORITHMS];
|
||||
int i, aead_algorithm, length;
|
||||
|
||||
NKSN_BeginMessage(session);
|
||||
|
||||
|
@ -113,11 +115,12 @@ prepare_request(NKC_Instance inst)
|
|||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NEXT_PROTOCOL, data, sizeof (data[0])))
|
||||
return 0;
|
||||
|
||||
length = 0;
|
||||
if (SIV_GetKeyLength(AEAD_AES_128_GCM_SIV) > 0)
|
||||
data[length++] = htons(AEAD_AES_128_GCM_SIV);
|
||||
if (SIV_GetKeyLength(AEAD_AES_SIV_CMAC_256) > 0)
|
||||
data[length++] = htons(AEAD_AES_SIV_CMAC_256);
|
||||
for (i = length = 0; i < ARR_GetSize(CNF_GetNtsAeads()) && length < MAX_AEAD_ALGORITHMS;
|
||||
i++) {
|
||||
aead_algorithm = *(int *)ARR_GetElement(CNF_GetNtsAeads(), i);
|
||||
if (SIV_GetKeyLength(aead_algorithm) > 0)
|
||||
data[length++] = htons(aead_algorithm);
|
||||
}
|
||||
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, data,
|
||||
length * sizeof (data[0])))
|
||||
return 0;
|
||||
|
@ -177,15 +180,22 @@ process_response(NKC_Instance inst)
|
|||
next_protocol = NKE_NEXT_PROTOCOL_NTPV4;
|
||||
break;
|
||||
case NKE_RECORD_AEAD_ALGORITHM:
|
||||
if (length != 2 || (ntohs(data[0]) != AEAD_AES_SIV_CMAC_256 &&
|
||||
ntohs(data[0]) != AEAD_AES_128_GCM_SIV) ||
|
||||
SIV_GetKeyLength(ntohs(data[0])) <= 0) {
|
||||
DEBUG_LOG("Unexpected NTS-KE AEAD algorithm");
|
||||
if (length != 2) {
|
||||
DEBUG_LOG("Unexpected AEAD algorithm");
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
aead_algorithm = ntohs(data[0]);
|
||||
inst->context.algorithm = aead_algorithm;
|
||||
for (i = 0; i < ARR_GetSize(CNF_GetNtsAeads()); i++) {
|
||||
if (ntohs(data[0]) == *(int *)ARR_GetElement(CNF_GetNtsAeads(), i) &&
|
||||
SIV_GetKeyLength(ntohs(data[0])) > 0) {
|
||||
aead_algorithm = ntohs(data[0]);
|
||||
inst->context.algorithm = aead_algorithm;
|
||||
}
|
||||
}
|
||||
if (aead_algorithm < 0) {
|
||||
DEBUG_LOG("Unexpected AEAD algorithm");
|
||||
error = 1;
|
||||
}
|
||||
break;
|
||||
case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
|
||||
if (length != 0) {
|
||||
|
|
|
@ -426,8 +426,8 @@ process_request(NKSN_Instance session)
|
|||
int next_protocol_records = 0, aead_algorithm_records = 0;
|
||||
int next_protocol_values = 0, aead_algorithm_values = 0;
|
||||
int next_protocol = -1, aead_algorithm = -1, error = -1;
|
||||
int i, j, critical, type, length;
|
||||
int compliant_128gcm = 0;
|
||||
int i, critical, type, length;
|
||||
uint16_t data[NKE_MAX_RECORD_BODY_LENGTH / sizeof (uint16_t)];
|
||||
|
||||
assert(NKE_MAX_RECORD_BODY_LENGTH % sizeof (uint16_t) == 0);
|
||||
|
@ -462,9 +462,12 @@ process_request(NKSN_Instance session)
|
|||
|
||||
for (i = 0; i < MIN(length, sizeof (data)) / 2; i++) {
|
||||
aead_algorithm_values++;
|
||||
/* Use the first supported algorithm */
|
||||
if (aead_algorithm < 0 && SIV_GetKeyLength(ntohs(data[i])) > 0)
|
||||
aead_algorithm = ntohs(data[i]);
|
||||
/* Use the first enabled and supported algorithm */
|
||||
for (j = 0; j < ARR_GetSize(CNF_GetNtsAeads()); j++) {
|
||||
if (ntohs(data[i]) == *(int *)ARR_GetElement(CNF_GetNtsAeads(), j) &&
|
||||
aead_algorithm < 0 && SIV_GetKeyLength(ntohs(data[i])) > 0)
|
||||
aead_algorithm = ntohs(data[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
|
||||
|
|
|
@ -313,4 +313,31 @@ check_sync && test_fail
|
|||
check_file_messages " 3 1 .* 123 " 0 0 log.packets || test_fail
|
||||
check_file_messages " 3 2 .* 123 " 0 0 log.packets || test_fail
|
||||
|
||||
for server_aead in "" "15" "30"; do
|
||||
for client_aead in "" "15" "30"; do
|
||||
server_conf="
|
||||
ntsaeads $server_aead
|
||||
ntsserverkey tmp/server1.key
|
||||
ntsservercert tmp/server1.crt
|
||||
ntsprocesses 0"
|
||||
client_conf="
|
||||
nosystemcert
|
||||
ntsaeads $client_aead
|
||||
ntstrustedcerts tmp/server1.crt
|
||||
ntstrustedcerts tmp/server2.crt"
|
||||
client_server_conf=""
|
||||
|
||||
run_test || test_fail
|
||||
check_chronyd_exit || test_fail
|
||||
if [ -n "$server_aead" ] && [ "$server_aead" == "$client_aead" ] &&
|
||||
( [ "$server_aead" != "30" ] || check_config_h '.*_SIV_GCM 1' ); then
|
||||
check_source_selection || test_fail
|
||||
check_sync || test_fail
|
||||
else
|
||||
check_source_selection && test_fail
|
||||
check_sync && test_fail
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
test_pass
|
||||
|
|
Loading…
Reference in a new issue