From 6615bb1b78de5bcc46ae6111ea8f0a3b2579cb67 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 18 Feb 2021 16:53:36 +0100 Subject: [PATCH] nts: add support for multiple sets of trusted certificates 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. --- ntp_auth.c | 5 ++-- ntp_auth.h | 2 +- ntp_core.c | 3 ++- nts_ke_client.c | 47 +++++++++++++++++++++++++++----------- nts_ke_client.h | 2 +- nts_ke_session.c | 20 ++++++++++------ nts_ke_session.h | 5 ++-- nts_ntp_client.c | 7 ++++-- nts_ntp_client.h | 2 +- stubs.c | 3 ++- test/unit/ntp_auth.c | 2 +- test/unit/nts_ke_client.c | 2 +- test/unit/nts_ke_session.c | 4 +++- test/unit/nts_ntp_client.c | 4 ++-- 14 files changed, 72 insertions(+), 36 deletions(-) diff --git a/ntp_auth.c b/ntp_auth.c index a5da2f3..67d28b6 100644 --- a/ntp_auth.c +++ b/ntp_auth.c @@ -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; } diff --git a/ntp_auth.h b/ntp_auth.h index 9d6c512..d999665 100644 --- a/ntp_auth.h +++ b/ntp_auth.h @@ -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); diff --git a/ntp_core.c b/ntp_core.c index 4e5fc59..f7b4c1c 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -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 { diff --git a/nts_ke_client.c b/nts_ke_client.c index 0b13627..dddb4c0 100644 --- a/nts_ke_client.c +++ b/nts_ke_client.c @@ -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 with other client instances */ - if (!client_credentials) - client_credentials = NKSN_CreateClientCertCredentials(trusted_certs, n_certs); - client_credentials_refs++; + /* 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); + } + + 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; } diff --git a/nts_ke_client.h b/nts_ke_client.h index 9738b10..a1bedb6 100644 --- a/nts_ke_client.h +++ b/nts_ke_client.h @@ -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); diff --git a/nts_ke_session.c b/nts_ke_session.c index 9936d37..97b135d 100644 --- a/nts_ke_session.c +++ b/nts_ke_session.c @@ -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); } /* ================================================== */ diff --git a/nts_ke_session.h b/nts_ke_session.h index eb19b92..2735e04 100644 --- a/nts_ke_session.h +++ b/nts_ke_session.h @@ -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); diff --git a/nts_ntp_client.c b/nts_ntp_client.c index c7833fa..5de97ee 100644 --- a/nts_ntp_client.c +++ b/nts_ntp_client.c @@ -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); diff --git a/nts_ntp_client.h b/nts_ntp_client.h index 88287f1..2c314cc 100644 --- a/nts_ntp_client.h +++ b/nts_ntp_client.h @@ -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 02e8636..cb7b9a6 100644 --- 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; } diff --git a/test/unit/ntp_auth.c b/test/unit/ntp_auth.c index a1a2d53..5be7437 100644 --- a/test/unit/ntp_auth.c +++ b/test/unit/ntp_auth.c @@ -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; diff --git a/test/unit/nts_ke_client.c b/test/unit/nts_ke_client.c index a907573..72690bf 100644 --- a/test/unit/nts_ke_client.c +++ b/test/unit/nts_ke_client.c @@ -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++) { diff --git a/test/unit/nts_ke_session.c b/test/unit/nts_ke_session.c index 1dd9aba..d0e72c7 100644 --- a/test/unit/nts_ke_session.c +++ b/test/unit/nts_ke_session.c @@ -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); diff --git a/test/unit/nts_ntp_client.c b/test/unit/nts_ntp_client.c index 2b1e5a7..c14fd41 100644 --- a/test/unit/nts_ntp_client.c +++ b/test/unit/nts_ntp_client.c @@ -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++) {