diff --git a/conf.c b/conf.c index 3f27870..4c62a07 100644 --- a/conf.c +++ b/conf.c @@ -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); } /* ================================================== */ diff --git a/conf.h b/conf.h index 1d3f36b..cf5fc3b 100644 --- a/conf.h +++ b/conf.h @@ -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); diff --git a/doc/chrony.conf.adoc b/doc/chrony.conf.adoc index d80cecf..d9da7b4 100644 --- a/doc/chrony.conf.adoc +++ b/doc/chrony.conf.adoc @@ -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 diff --git a/nts_ke_server.c b/nts_ke_server.c index 4303f70..1239678 100644 --- a/nts_ke_server.c +++ b/nts_ke_server.c @@ -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 { diff --git a/nts_ke_session.c b/nts_ke_session.c index 822df21..d92b4c2 100644 --- a/nts_ke_session.c +++ b/nts_ke_session.c @@ -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); } /* ================================================== */ diff --git a/nts_ke_session.h b/nts_ke_session.h index e5d3ccf..ed9c711 100644 --- a/nts_ke_session.h +++ b/nts_ke_session.h @@ -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 */ diff --git a/nts_ntp_server.c b/nts_ntp_server.c index 8f29aca..a3da485 100644 --- a/nts_ntp_server.c +++ b/nts_ntp_server.c @@ -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; } diff --git a/test/unit/nts_ke_session.c b/test/unit/nts_ke_session.c index 0aadc54..b29675b 100644 --- a/test/unit/nts_ke_session.c +++ b/test/unit/nts_ke_session.c @@ -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);