]> git.ipfire.org Git - thirdparty/chrony.git/commitdiff
nts: add support for multiple sets of trusted certificates
authorMiroslav Lichvar <mlichvar@redhat.com>
Thu, 18 Feb 2021 15:53:36 +0000 (16:53 +0100)
committerMiroslav Lichvar <mlichvar@redhat.com>
Thu, 18 Feb 2021 16:44:04 +0000 (17:44 +0100)
Modify the session, NTS-KE, and NTS-NTP code to support multiple sets of
trusted certificates and identify the sets by a 32-bit ID.

14 files changed:
ntp_auth.c
ntp_auth.h
ntp_core.c
nts_ke_client.c
nts_ke_client.h
nts_ke_session.c
nts_ke_session.h
nts_ntp_client.c
nts_ntp_client.h
stubs.c
test/unit/ntp_auth.c
test/unit/nts_ke_client.c
test/unit/nts_ke_session.c
test/unit/nts_ntp_client.c

index a5da2f3a7c68f5a83b3ddab0036c68b945d40736..67d28b663f08df085d644043c6ac048d03e905fb 100644 (file)
@@ -161,11 +161,12 @@ NAU_CreateSymmetricInstance(uint32_t key_id)
 /* ================================================== */
 
 NAU_Instance
-NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, uint16_t ntp_port)
+NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set,
+                      uint16_t ntp_port)
 {
   NAU_Instance instance = create_instance(NTP_AUTH_NTS);
 
-  instance->nts = NNC_CreateInstance(nts_address, name, ntp_port);
+  instance->nts = NNC_CreateInstance(nts_address, name, cert_set, ntp_port);
 
   return instance;
 }
index 9d6c512f980a42164115d6dfd3ab3c4b78772692..d99966556ac97e4dad30de533a0767f4106a8c11 100644 (file)
@@ -37,7 +37,7 @@ typedef struct NAU_Instance_Record *NAU_Instance;
 extern NAU_Instance NAU_CreateNoneInstance(void);
 extern NAU_Instance NAU_CreateSymmetricInstance(uint32_t key_id);
 extern NAU_Instance NAU_CreateNtsInstance(IPSockAddr *nts_address, const char *name,
-                                          uint16_t ntp_port);
+                                          uint32_t cert_set, uint16_t ntp_port);
 
 /* Destroy an instance */
 extern void NAU_DestroyInstance(NAU_Instance instance);
index 4e5fc59d0eab3fd6f8541f1dc76015d9224a3af1..f7b4c1c19eebadbe79b96492b3e2387593d2e373 100644 (file)
@@ -571,7 +571,8 @@ NCR_CreateInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type,
     nts_address.ip_addr = remote_addr->ip_addr;
     nts_address.port = params->nts_port;
 
-    result->auth = NAU_CreateNtsInstance(&nts_address, name, result->remote_addr.port);
+    result->auth = NAU_CreateNtsInstance(&nts_address, name, 0,
+                                         result->remote_addr.port);
   } else if (params->authkey != INACTIVE_AUTHKEY) {
     result->auth = NAU_CreateSymmetricInstance(params->authkey);
   } else {
index 0b13627ec4ec5087d7b0340e4f4edbe38b4a4656..dddb4c00b978ce2c63264b9a3e2fd2bf219a08d7 100644 (file)
@@ -44,6 +44,7 @@
 struct NKC_Instance_Record {
   char *name;
   IPSockAddr address;
+  NKSN_Credentials credentials;
   NKSN_Instance session;
   int destroying;
   int got_response;
@@ -58,8 +59,8 @@ struct NKC_Instance_Record {
 
 /* ================================================== */
 
-static NKSN_Credentials client_credentials = NULL;
-static int client_credentials_refs = 0;
+static NKSN_Credentials default_credentials = NULL;
+static int default_credentials_refs = 0;
 
 /* ================================================== */
 
@@ -266,9 +267,10 @@ handle_message(void *arg)
 /* ================================================== */
 
 NKC_Instance
-NKC_CreateInstance(IPSockAddr *address, const char *name)
+NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set)
 {
   const char **trusted_certs;
+  uint32_t *certs_ids;
   NKC_Instance inst;
   int n_certs;
 
@@ -282,11 +284,24 @@ NKC_CreateInstance(IPSockAddr *address, const char *name)
   inst->got_response = 0;
 
   n_certs = CNF_GetNtsTrustedCertsPaths(&trusted_certs);
+  certs_ids = MallocArray(uint32_t, n_certs);
+  memset(certs_ids, 0, sizeof (uint32_t) * n_certs);
+
+  /* Share the credentials among clients using the default set of trusted
+     certificates, which likely contains most certificates */
+  if (cert_set == 0) {
+    if (!default_credentials)
+      default_credentials = NKSN_CreateClientCertCredentials(trusted_certs, certs_ids,
+                                                             n_certs, cert_set);
+    inst->credentials = default_credentials;
+    if (default_credentials)
+      default_credentials_refs++;
+  } else {
+    inst->credentials = NKSN_CreateClientCertCredentials(trusted_certs, certs_ids,
+                                                         n_certs, cert_set);
+  }
 
-  /* Share the credentials with other client instances */
-  if (!client_credentials)
-    client_credentials = NKSN_CreateClientCertCredentials(trusted_certs, n_certs);
-  client_credentials_refs++;
+  Free(certs_ids);
 
   return inst;
 }
@@ -300,10 +315,16 @@ NKC_DestroyInstance(NKC_Instance inst)
 
   Free(inst->name);
 
-  client_credentials_refs--;
-  if (client_credentials_refs <= 0 && client_credentials) {
-    NKSN_DestroyCertCredentials(client_credentials);
-    client_credentials = NULL;
+  if (inst->credentials) {
+    if (inst->credentials == default_credentials) {
+      default_credentials_refs--;
+      if (default_credentials_refs <= 0) {
+        NKSN_DestroyCertCredentials(default_credentials);
+        default_credentials = NULL;
+      }
+    } else {
+      NKSN_DestroyCertCredentials(inst->credentials);
+    }
   }
 
   /* If the asynchronous resolver is running, let the handler free
@@ -329,7 +350,7 @@ NKC_Start(NKC_Instance inst)
 
   inst->got_response = 0;
 
-  if (!client_credentials) {
+  if (!inst->credentials) {
     DEBUG_LOG("Missing client credentials");
     return 0;
   }
@@ -351,7 +372,7 @@ NKC_Start(NKC_Instance inst)
   }
 
   /* Start an NTS-KE session */
-  if (!NKSN_StartSession(inst->session, sock_fd, label, client_credentials, CLIENT_TIMEOUT)) {
+  if (!NKSN_StartSession(inst->session, sock_fd, label, inst->credentials, CLIENT_TIMEOUT)) {
     SCK_CloseSocket(sock_fd);
     return 0;
   }
index 9738b104958a00bb3635e45385236469adafc2a8..a1bedb693ddbfcb2b2b427d19373211837186491 100644 (file)
@@ -33,7 +33,7 @@
 typedef struct NKC_Instance_Record *NKC_Instance;
 
 /* Create a client NTS-KE instance */
-extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name);
+extern NKC_Instance NKC_CreateInstance(IPSockAddr *address, const char *name, uint32_t cert_set);
 
 /* Destroy an instance */
 extern void NKC_DestroyInstance(NKC_Instance inst);
index 9936d37ff5ad224160232d394788b10b4f28ff99..97b135d250820a418b2745fa947b2e0871817802 100644 (file)
@@ -643,7 +643,8 @@ deinit_gnutls(void)
 
 static NKSN_Credentials
 create_credentials(const char **certs, const char **keys, int n_certs_keys,
-                   const char **trusted_certs, int n_trusted_certs)
+                   const char **trusted_certs, uint32_t *trusted_certs_ids,
+                   int n_trusted_certs, uint32_t trusted_cert_set)
 {
   gnutls_certificate_credentials_t credentials = NULL;
   int i, r;
@@ -655,7 +656,8 @@ create_credentials(const char **certs, const char **keys, int n_certs_keys,
     goto error;
 
   if (certs && keys) {
-    assert(!trusted_certs);
+    if (trusted_certs || trusted_certs_ids)
+      assert(0);
 
     for (i = 0; i < n_certs_keys; i++) {
       r = gnutls_certificate_set_x509_key_file(credentials, certs[i], keys[i],
@@ -667,16 +669,19 @@ create_credentials(const char **certs, const char **keys, int n_certs_keys,
     if (certs || keys || n_certs_keys > 0)
       assert(0);
 
-    if (!CNF_GetNoSystemCert()) {
+    if (trusted_cert_set == 0 && !CNF_GetNoSystemCert()) {
       r = gnutls_certificate_set_x509_system_trust(credentials);
       if (r < 0)
         goto error;
     }
 
-    if (trusted_certs) {
+    if (trusted_certs && trusted_certs_ids) {
       for (i = 0; i < n_trusted_certs; i++) {
         struct stat buf;
 
+        if (trusted_certs_ids[i] != trusted_cert_set)
+          continue;
+
         if (stat(trusted_certs[i], &buf) == 0 && S_ISDIR(buf.st_mode))
           r = gnutls_certificate_set_x509_trust_dir(credentials, trusted_certs[i],
                                                     GNUTLS_X509_FMT_PEM);
@@ -708,15 +713,16 @@ error:
 NKSN_Credentials
 NKSN_CreateServerCertCredentials(const char **certs, const char **keys, int n_certs_keys)
 {
-  return create_credentials(certs, keys, n_certs_keys, NULL, 0);
+  return create_credentials(certs, keys, n_certs_keys, NULL, NULL, 0, 0);
 }
 
 /* ================================================== */
 
 NKSN_Credentials
-NKSN_CreateClientCertCredentials(const char **trusted_certs, int n_certs)
+NKSN_CreateClientCertCredentials(const char **certs, uint32_t *ids,
+                                 int n_certs_ids, uint32_t trusted_cert_set)
 {
-  return create_credentials(NULL, NULL, 0, trusted_certs, n_certs);
+  return create_credentials(NULL, NULL, 0, certs, ids, n_certs_ids, trusted_cert_set);
 }
 
 /* ================================================== */
index eb19b920283d2c725d82b04c7dd7daad89da1224..2735e04cdac644f8451e22ce9cc8819fc6ad62ff 100644 (file)
@@ -43,8 +43,9 @@ typedef int (*NKSN_MessageHandler)(void *arg);
    different clients or servers. */
 extern NKSN_Credentials NKSN_CreateServerCertCredentials(const char **certs, const char **keys,
                                                          int n_certs_keys);
-extern NKSN_Credentials NKSN_CreateClientCertCredentials(const char **trusted_certs,
-                                                         int n_certs);
+extern NKSN_Credentials NKSN_CreateClientCertCredentials(const char **certs, uint32_t *ids,
+                                                         int n_certs_ids,
+                                                         uint32_t trusted_cert_set);
 
 /* Destroy the credentials */
 extern void NKSN_DestroyCertCredentials(NKSN_Credentials credentials);
index c7833fa2aaf32934eb0fd49afd8a3b4f96ccab65..5de97ee23aa423b125d49598ccb23788f81f502a 100644 (file)
@@ -54,6 +54,8 @@ struct NNC_Instance_Record {
   IPSockAddr nts_address;
   /* Hostname or IP address for certificate verification */
   char *name;
+  /* ID of trusted certificates */
+  uint32_t cert_set;
   /* Configured NTP port */
   uint16_t default_ntp_port;
   /* Address of NTP server (can be negotiated in NTS-KE) */
@@ -114,7 +116,7 @@ reset_instance(NNC_Instance inst)
 /* ================================================== */
 
 NNC_Instance
-NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint16_t ntp_port)
+NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set, uint16_t ntp_port)
 {
   NNC_Instance inst;
 
@@ -122,6 +124,7 @@ NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint16_t ntp_port)
 
   inst->nts_address = *nts_address;
   inst->name = Strdup(name);
+  inst->cert_set = cert_set;
   inst->default_ntp_port = ntp_port;
   inst->ntp_address.ip_addr = nts_address->ip_addr;
   inst->ntp_address.port = ntp_port;
@@ -233,7 +236,7 @@ get_cookies(NNC_Instance inst)
       return 0;
     }
 
-    inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name);
+    inst->nke = NKC_CreateInstance(&inst->nts_address, inst->name, inst->cert_set);
 
     inst->nke_attempts++;
     update_next_nke_attempt(inst, now);
index 88287f135e3bcf1c8727b8ffd3e0957cafd6c6f6..2c314cca7974da5c638af18ff242f5162d14d386 100644 (file)
@@ -34,7 +34,7 @@
 typedef struct NNC_Instance_Record *NNC_Instance;
 
 extern NNC_Instance NNC_CreateInstance(IPSockAddr *nts_address, const char *name,
-                                       uint16_t ntp_port);
+                                       uint32_t cert_set, uint16_t ntp_port);
 extern void NNC_DestroyInstance(NNC_Instance inst);
 extern int NNC_PrepareForAuth(NNC_Instance inst);
 extern int NNC_GenerateRequestAuth(NNC_Instance inst, NTP_Packet *packet,
diff --git a/stubs.c b/stubs.c
index 02e863620dd7a6919f0388479c54b2a1196b31f6..cb7b9a655cd844cd999cc76057efa3ccd942b949 100644 (file)
--- a/stubs.c
+++ b/stubs.c
@@ -491,7 +491,8 @@ NNS_GenerateResponseAuth(NTP_Packet *request, NTP_PacketInfo *req_info,
 }
 
 NNC_Instance
-NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint16_t ntp_port)
+NNC_CreateInstance(IPSockAddr *nts_address, const char *name, uint32_t cert_set,
+                   uint16_t ntp_port)
 {
   return NULL;
 }
index a1a2d537641ae018a09efa932602f1a5992b88a2..5be74370d5484c41660fa8224d3cb46308c9f02a 100644 (file)
@@ -177,7 +177,7 @@ test_unit(void)
         can_auth_res = can_auth_req;
         break;
       case 2:
-        inst = NAU_CreateNtsInstance(&nts_addr, "test", 0);
+        inst = NAU_CreateNtsInstance(&nts_addr, "test", 0, 0);
         TEST_CHECK(NAU_IsAuthEnabled(inst));
         TEST_CHECK(NAU_GetSuggestedNtpVersion(inst) == 4);
         mode = NTP_AUTH_NTS;
index a90757309549ed322648a6b37735d9afeae1cdaf..72690bf1f3bba7c61b3c31f4a576ec9547c160b9 100644 (file)
@@ -120,7 +120,7 @@ test_unit(void)
   SCK_GetLoopbackIPAddress(AF_INET, &addr.ip_addr);
   addr.port = 0;
 
-  inst = NKC_CreateInstance(&addr, "test");
+  inst = NKC_CreateInstance(&addr, "test", 0);
   TEST_CHECK(inst);
 
   for (i = 0; i < 10000; i++) {
index 1dd9aba7086684a65b69458a2ba906cd05700aa8..d0e72c7af15d0294b9d58bea1c3dee58bfd14d81 100644 (file)
@@ -165,12 +165,14 @@ test_unit(void)
   NKSN_Credentials client_cred, server_cred;
   const char *cert, *key;
   int sock_fds[2], i;
+  uint32_t cert_id;
 
   LCL_Initialise();
   TST_RegisterDummyDrivers();
 
   cert = "nts_ke.crt";
   key = "nts_ke.key";
+  cert_id = 0;
 
   for (i = 0; i < 50; i++) {
     SCH_Initialise();
@@ -179,7 +181,7 @@ test_unit(void)
     client = NKSN_CreateInstance(0, "test", handle_response, NULL);
 
     server_cred = NKSN_CreateServerCertCredentials(&cert, &key, 1);
-    client_cred = NKSN_CreateClientCertCredentials(&cert, 1);
+    client_cred = NKSN_CreateClientCertCredentials(&cert, &cert_id, 1, 0);
 
     TEST_CHECK(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fds) == 0);
     TEST_CHECK(fcntl(sock_fds[0], F_SETFL, O_NONBLOCK) == 0);
index 2b1e5a7563d946ad1bf967f2cfb96bb433fbb001..c14fd41b7c092aac62cc589ce1b99fc43fd55bf9 100644 (file)
@@ -27,7 +27,7 @@
 #include "ntp.h"
 #include "nts_ke_client.h"
 
-#define NKC_CreateInstance(address, name) Malloc(1)
+#define NKC_CreateInstance(address, name, cert_set) Malloc(1)
 #define NKC_DestroyInstance(inst) Free(inst)
 #define NKC_Start(inst) (random() % 2)
 #define NKC_IsActive(inst) (random() % 2)
@@ -227,7 +227,7 @@ test_unit(void)
   SCK_GetLoopbackIPAddress(AF_INET, &addr.ip_addr);
   addr.port = 0;
 
-  inst = NNC_CreateInstance(&addr, "test", 0);
+  inst = NNC_CreateInstance(&addr, "test", 0, 0);
   TEST_CHECK(inst);
 
   for (i = 0; i < 100000; i++) {