nts: allow multiple server keys and certificates

Allow the ntsservercert and ntsserverkey directives to be specified
multiple times to enable the NTS-KE server to operate under multiple
names.
This commit is contained in:
Miroslav Lichvar 2021-02-11 12:26:35 +01:00
parent 80e627c86b
commit 90557cf1ba
8 changed files with 73 additions and 40 deletions

48
conf.c
View file

@ -76,6 +76,7 @@ static void parse_log(char *);
static void parse_mailonchange(char *);
static void parse_makestep(char *);
static void parse_maxchange(char *);
static void parse_ntsserver(char *, ARR_Instance files);
static void parse_ratelimit(char *line, int *enabled, int *interval,
int *burst, int *leak);
static void parse_refclock(char *);
@ -252,8 +253,8 @@ static char *user;
/* NTS server and client configuration */
static char *nts_dump_dir = NULL;
static char *nts_ntp_server = NULL;
static char *nts_server_cert_file = NULL;
static char *nts_server_key_file = NULL;
static ARR_Instance nts_server_cert_files; /* array of (char *) */
static ARR_Instance nts_server_key_files; /* array of (char *) */
static int nts_server_port = NKE_PORT;
static int nts_server_processes = 1;
static int nts_server_connections = 100;
@ -388,6 +389,9 @@ CNF_Initialise(int r, int client_only)
ntp_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
cmd_restrictions = ARR_CreateInstance(sizeof (AllowDeny));
nts_server_cert_files = ARR_CreateInstance(sizeof (char *));
nts_server_key_files = ARR_CreateInstance(sizeof (char *));
rtc_device = Strdup(DEFAULT_RTC_DEVICE);
hwclock_file = Strdup(DEFAULT_HWCLOCK_FILE);
user = Strdup(DEFAULT_USER);
@ -426,6 +430,10 @@ CNF_Finalise(void)
Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_name);
Free(((RefclockParameters *)ARR_GetElement(refclock_sources, i))->driver_parameter);
}
for (i = 0; i < ARR_GetSize(nts_server_cert_files); i++)
Free(*(char **)ARR_GetElement(nts_server_cert_files, i));
for (i = 0; i < ARR_GetSize(nts_server_key_files); i++)
Free(*(char **)ARR_GetElement(nts_server_key_files, i));
ARR_DestroyInstance(init_sources);
ARR_DestroyInstance(ntp_sources);
@ -437,6 +445,9 @@ CNF_Finalise(void)
ARR_DestroyInstance(ntp_restrictions);
ARR_DestroyInstance(cmd_restrictions);
ARR_DestroyInstance(nts_server_cert_files);
ARR_DestroyInstance(nts_server_key_files);
Free(drift_file);
Free(dumpdir);
Free(hwclock_file);
@ -457,8 +468,6 @@ CNF_Finalise(void)
Free(tempcomp_point_file);
Free(nts_dump_dir);
Free(nts_ntp_server);
Free(nts_server_cert_file);
Free(nts_server_key_file);
Free(nts_trusted_cert_file);
}
@ -659,9 +668,9 @@ CNF_ParseLine(const char *filename, int number, char *line)
} else if (!strcasecmp(command, "ntsrotate")) {
parse_int(p, &nts_rotate);
} else if (!strcasecmp(command, "ntsservercert")) {
parse_string(p, &nts_server_cert_file);
parse_ntsserver(p, nts_server_cert_files);
} else if (!strcasecmp(command, "ntsserverkey")) {
parse_string(p, &nts_server_key_file);
parse_ntsserver(p, nts_server_key_files);
} else if (!strcasecmp(command, "peer")) {
parse_source(p, command, 1);
} else if (!strcasecmp(command, "pidfile")) {
@ -1158,6 +1167,17 @@ parse_mailonchange(char *line)
/* ================================================== */
static void
parse_ntsserver(char *line, ARR_Instance files)
{
char *file = NULL;
parse_string(line, &file);
ARR_AppendElement(files, &file);
}
/* ================================================== */
static void
parse_allow_deny(char *line, ARR_Instance restrictions, int allow)
{
@ -2515,18 +2535,16 @@ CNF_GetNtsNtpServer(void)
/* ================================================== */
char *
CNF_GetNtsServerCertFile(void)
int
CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys)
{
return nts_server_cert_file;
}
*certs = ARR_GetElements(nts_server_cert_files);
*keys = ARR_GetElements(nts_server_key_files);
/* ================================================== */
if (ARR_GetSize(nts_server_cert_files) != ARR_GetSize(nts_server_key_files))
LOG_FATAL("Uneven number of NTS certs and keys");
char *
CNF_GetNtsServerKeyFile(void)
{
return nts_server_key_file;
return ARR_GetSize(nts_server_cert_files);
}
/* ================================================== */

3
conf.h
View file

@ -153,8 +153,7 @@ extern int CNF_GetHwTsInterface(unsigned int index, CNF_HwTsInterface **iface);
extern char *CNF_GetNtsDumpDir(void);
extern char *CNF_GetNtsNtpServer(void);
extern char *CNF_GetNtsServerCertFile(void);
extern char *CNF_GetNtsServerKeyFile(void);
extern int CNF_GetNtsServerCertAndKeyFiles(const char ***certs, const char ***keys);
extern int CNF_GetNtsServerPort(void);
extern int CNF_GetNtsServerProcesses(void);
extern int CNF_GetNtsServerConnections(void);

View file

@ -1567,10 +1567,16 @@ The port will be open only when a certificate and key is specified by the
[[ntsservercert]]*ntsservercert* _file_::
This directive specifies a file containing a certificate in the PEM format
for *chronyd* to operate as an NTS server.
+
This directive can be used multiple times to specify multiple certificates.
[[ntsserverkey]]*ntsserverkey* _file_::
This directive specifies a file containing a private key in the PEM format
for *chronyd* to operate as an NTS server.
+
This directive can be used multiple times to specify multiple keys. The number
of keys must be the same as the number of certificates and the corresponding
files must be specified in the same order.
[[ntsprocesses]]*ntsprocesses* _processes_::
This directive specifies how many helper processes will *chronyd* operating

View file

@ -678,13 +678,14 @@ void
NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
{
int i, processes, sock_fd1, sock_fd2;
const char **certs, **keys;
char prefix[16];
pid_t pid;
helper_sock_fd = INVALID_SOCK_FD;
is_helper = 0;
if (!CNF_GetNtsServerCertFile() || !CNF_GetNtsServerKeyFile())
if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0)
return;
processes = CNF_GetNtsServerProcesses();
@ -728,21 +729,19 @@ NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level)
void
NKS_Initialise(void)
{
char *cert, *key;
const char **certs, **keys;
int i, n_certs_keys;
double key_delay;
int i;
server_sock_fd4 = INVALID_SOCK_FD;
server_sock_fd6 = INVALID_SOCK_FD;
cert = CNF_GetNtsServerCertFile();
key = CNF_GetNtsServerKeyFile();
if (!cert || !key)
n_certs_keys = CNF_GetNtsServerCertAndKeyFiles(&certs, &keys);
if (n_certs_keys <= 0)
return;
if (helper_sock_fd == INVALID_SOCK_FD) {
server_credentials = NKSN_CreateServerCertCredentials(cert, key);
server_credentials = NKSN_CreateServerCertCredentials(certs, keys, n_certs_keys);
if (!server_credentials)
return;
} else {

View file

@ -642,10 +642,11 @@ deinit_gnutls(void)
/* ================================================== */
static NKSN_Credentials
create_credentials(const char *cert, const char *key, const char *trusted_certs)
create_credentials(const char **certs, const char **keys, int n_certs_keys,
const char *trusted_certs)
{
gnutls_certificate_credentials_t credentials = NULL;
int r;
int i, r;
init_gnutls();
@ -653,15 +654,18 @@ create_credentials(const char *cert, const char *key, const char *trusted_certs)
if (r < 0)
goto error;
if (cert && key) {
if (certs && keys) {
assert(!trusted_certs);
r = gnutls_certificate_set_x509_key_file(credentials, cert, key,
GNUTLS_X509_FMT_PEM);
if (r < 0)
goto error;
for (i = 0; i < n_certs_keys; i++) {
r = gnutls_certificate_set_x509_key_file(credentials, certs[i], keys[i],
GNUTLS_X509_FMT_PEM);
if (r < 0)
goto error;
}
} else {
assert(!cert && !key);
if (certs || keys || n_certs_keys > 0)
assert(0);
if (!CNF_GetNoSystemCert()) {
r = gnutls_certificate_set_x509_system_trust(credentials);
@ -692,9 +696,9 @@ error:
/* ================================================== */
NKSN_Credentials
NKSN_CreateServerCertCredentials(const char *cert, const char *key)
NKSN_CreateServerCertCredentials(const char **certs, const char **keys, int n_certs_keys)
{
return create_credentials(cert, key, NULL);
return create_credentials(certs, keys, n_certs_keys, NULL);
}
/* ================================================== */
@ -702,7 +706,7 @@ NKSN_CreateServerCertCredentials(const char *cert, const char *key)
NKSN_Credentials
NKSN_CreateClientCertCredentials(const char *trusted_certs)
{
return create_credentials(NULL, NULL, trusted_certs);
return create_credentials(NULL, NULL, 0, trusted_certs);
}
/* ================================================== */

View file

@ -41,7 +41,8 @@ typedef int (*NKSN_MessageHandler)(void *arg);
/* Get server or client credentials using a server certificate and key,
or certificates of trusted CAs. The credentials may be shared between
different clients or servers. */
extern NKSN_Credentials NKSN_CreateServerCertCredentials(const char *cert, const char *key);
extern NKSN_Credentials NKSN_CreateServerCertCredentials(const char **certs, const char **keys,
int n_certs_keys);
extern NKSN_Credentials NKSN_CreateClientCertCredentials(const char *trusted_certs);
/* Destroy the credentials */

View file

@ -59,8 +59,10 @@ struct NtsServer *server;
void
NNS_Initialise(void)
{
const char **certs, **keys;
/* Create an NTS-NTP server instance only if NTS-KE server is enabled */
if (!CNF_GetNtsServerCertFile() || !CNF_GetNtsServerKeyFile()) {
if (CNF_GetNtsServerCertAndKeyFiles(&certs, &keys) <= 0) {
server = NULL;
return;
}

View file

@ -163,19 +163,23 @@ void
test_unit(void)
{
NKSN_Credentials client_cred, server_cred;
const char *cert, *key;
int sock_fds[2], i;
LCL_Initialise();
TST_RegisterDummyDrivers();
cert = "nts_ke.crt";
key = "nts_ke.key";
for (i = 0; i < 50; i++) {
SCH_Initialise();
server = NKSN_CreateInstance(1, NULL, handle_request, NULL);
client = NKSN_CreateInstance(0, "test", handle_response, NULL);
server_cred = NKSN_CreateServerCertCredentials("nts_ke.crt", "nts_ke.key");
client_cred = NKSN_CreateClientCertCredentials("nts_ke.crt");
server_cred = NKSN_CreateServerCertCredentials(&cert, &key, 1);
client_cred = NKSN_CreateClientCertCredentials(cert);
TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds) == 0);
TEST_CHECK(fcntl(sock_fds[0], F_SETFL, O_NONBLOCK) == 0);