]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
nts: allow multiple server keys and certificates
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 11 Feb 2021 11:26:35 +0000 (12:26 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 11 Feb 2021 15:13:39 +0000 (16:13 +0100)
Allow the ntsservercert and ntsserverkey directives to be specified
multiple times to enable the NTS-KE server to operate under multiple
names.

conf.c
conf.h
doc/chrony.conf.adoc
nts_ke_server.c
nts_ke_session.c
nts_ke_session.h
nts_ntp_server.c
test/unit/nts_ke_session.c

diff --git a/conf.c b/conf.c
index 3f278702a2c4976594a00ca2e3c5309f961db85d..4c62a075c9ba7f23d52436355f506761e321ed56 100644 (file)
--- 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 1d3f36b662b05f8475d3b9ccd720145ade754292..cf5fc3ba7b680dade379777036ff94546aaeb77f 100644 (file)
--- 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);
index d80cecf691bb9b30952de028dfeecbf3b27820d1..d9da7b40d24918f558c2dd40f10d5f07603aeb4c 100644 (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
index 4303f70a0b25fef06777c80ef04376babe1f0826..123967883d3c73c698a3d547e628169f27b22077 100644 (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 {
index 822df217537a4a94fbc55ca08344037260d615af..d92b4c24c4a99bc36b2199b8c769d054176d12f5 100644 (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);
 }
 
 /* ================================================== */
index e5d3ccf6e94e4f88c37405b2300bd57bfc039637..ed9c711f16fb3d2fc614ad3531bcb0caa681f74d 100644 (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 */
index 8f29acadcd58f018a83f448193df2864ab644f05..a3da48516626e71e1e0a8d9bb4e185ba11f30fe5 100644 (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;
   }
index 0aadc54f581dd1cea00761f4409d77b8a1aca889..b29675b9a3049a26d3d822f6e4f11cd41bb56217 100644 (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);