[Git][NTPsec/ntpsec][master] 3 commits: NS-KE-client off the ground far enough to check certificates

Hal Murray gitlab at mg.gitlab.com
Sat Feb 9 11:39:18 UTC 2019


Hal Murray pushed to branch master at NTPsec / ntpsec


Commits:
9948b076 by Hal Murray at 2019-02-08T21:07:56Z
NS-KE-client off the ground far enough to check certificates

- - - - -
5ee06547 by Hal Murray at 2019-02-08T21:07:56Z
Setup C2S and S2C

- - - - -
f89d1134 by Hal Murray at 2019-02-09T11:38:40Z
NTS-KE-server is off the ground

- - - - -


9 changed files:

- include/ntpd.h
- include/nts.h
- libntp/ssl_init.c
- ntpd/ntp_proto.c
- ntpd/ntpd.c
- ntpd/nts.c
- ntpd/nts_client.c
- + ntpd/nts_server.c
- ntpd/wscript


Changes:

=====================================
include/ntpd.h
=====================================
@@ -421,6 +421,7 @@ extern const uint8_t	num_refclock_conf;
 #endif
 
 /* nts.c */
+void nts_start_server(void);
 bool nts_probe(struct peer *peer);
 int nts_client_ke_request(struct ntscfg_t *);
 int nts_server_ke_verify(struct ntscfg_t *);


=====================================
include/nts.h
=====================================
@@ -4,6 +4,8 @@
 #ifndef GUARD_NTS_H
 #define GUARD_NTS_H
 
+#include <openssl/ssl.h>
+
 #define NTS_MAX_COOKIES	8	/* RFC 4.1.6 */
 #define NTS_COOKIELEN	128	/* placeholder - see RFC 6 */
 
@@ -21,11 +23,20 @@ struct ntscfg_t {
     uint32_t expire;
 };
 
+// FIXME AEAD_AES_SIV_CMAC_256
+// We are using AEAD_AES_SIV_CMAC_256, from RFC 5297
+// There is no clean API yet
+#define IANA_AEAD_AES_SIV_CMAC_256 15
+#define AEAD_AES_SIV_CMAC_256_KEYLEN 32
+
+#define NTS_MAX_KEYLEN 64
 /* Client-side state per connection to server */
 struct ntsstate_t {
     char cookies[NTS_MAX_COOKIES][NTS_COOKIELEN];
     int current_cookie;
     int cookie_count;
+    uint8_t c2s[NTS_MAX_KEYLEN], s2c[NTS_MAX_KEYLEN];
+    int keylen;
 };
 
 /* Configuration data for an NTS server or client instance */
@@ -41,4 +52,7 @@ struct ntsconfig_t {
 
 extern struct ntsconfig_t ntsconfig;
 
+bool nts_make_keys(SSL *ssl, uint8_t *c2s, uint8_t *s2c, int keylen);
+
+
 #endif /* GUARD_NTS_H */


=====================================
libntp/ssl_init.c
=====================================
@@ -33,8 +33,10 @@ ssl_init(void)
 		return;
 
 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+	SSL_library_init();
 	OpenSSL_add_all_digests();
 	OpenSSL_add_all_ciphers();
+	SSL_load_error_strings();
 	atexit(&atexit_ssl_cleanup);
 #endif
 


=====================================
ntpd/ntp_proto.c
=====================================
@@ -829,6 +829,13 @@ transmit(
 		return;
 	}
 
+	/* Does server need NTS lookup? */
+	if (peer->cfg.nts_cfg.flags & FLAG_NTS) {
+                peer->cfg.nts_cfg.flags &= !FLAG_NTS;
+                nts_probe(peer);
+		return;
+        }
+
 	/* Does server need DNS lookup? */
 	if (peer->cfg.flags & FLAG_DNS) {
 		peer->outdate = current_time;


=====================================
ntpd/ntpd.c
=====================================
@@ -500,9 +500,7 @@ ntpdmain(
 	int		pipe_fds[2];
 	int		rc;
 	int		exit_code;
-#  ifdef SIGDANGER
 	struct sigaction sa;
-#  endif
 # endif	/* HAVE_WORKING_FORK*/
 	int op;
 
@@ -629,6 +627,10 @@ ntpdmain(
 # endif		/* HAVE_WORKING_FORK */
 	}
 
+	/* Ignore SIGPIPE - from OpenSSL */
+	sa.sa_handler = SIG_IGN;
+ 	sigaction(SIGPIPE, &sa, NULL);
+
 	/*
 	 * Set up signals we pay attention to locally.
 	 */
@@ -902,6 +904,9 @@ ntpdmain(
 	    msyslog(LOG_ERR, "statistics directory %s does not exist or is unwriteable, error %s", statsdir, strerror(errno));
 	}
 
+	if (ntsconfig.ntsenable)
+            nts_start_server();
+
 	mainloop();
         /* unreachable, mainloop() never returns */
 }


=====================================
ntpd/nts.c
=====================================
@@ -15,7 +15,15 @@
 #include "ntp_types.h"
 #include "ntpd.h"
 
-struct ntsconfig_t ntsconfig;
+struct ntsconfig_t ntsconfig = {
+  .ntsenable = false,
+  .mintls = 0,
+  .maxtls = 0,
+  .tlsciphers = NULL,
+  .tlsciphersuites = NULL,
+  .ca = NULL,
+  .cert = NULL
+};
 
 /* By design, there is no per-client-side state on the server */
 


=====================================
ntpd/nts_client.c
=====================================
@@ -16,6 +16,7 @@
 #endif
 
 #include <openssl/ssl.h>
+#include <openssl/x509.h>
 
 #include "ntp_types.h"
 #include "ntpd.h"
@@ -28,6 +29,9 @@ bool nts_probe(struct peer * peer) {
   SSL_CTX *ctx;
   SSL     *ssl;
   int      server = 0;
+  X509    *cert = NULL;
+  uint8_t  buff[1000];
+  int      transfered;
 
   server = open_TCP_socket(peer->hostname);
   if (-1 == server) return false;
@@ -35,33 +39,120 @@ bool nts_probe(struct peer * peer) {
   // No error checking yet.
   // Ugly since most SSL routines return 1 on success.
 
-// Fedora 29: 0x1010101fL  1.1.1a
-// Fedora 28: 0x1010009fL  1.1.0i
+// Fedora 29:  0x1010101fL  1.1.1a
+// Fedora 28:  0x1010009fL  1.1.0i
+// CentOS 6:   0x1000105fL  1.0.1e
+// NetBSD 8:   0x100020bfL  1.0.2k
+// FreeBSD 12: 0x1010101fL  1.1.1a-freebsd
 #if (OPENSSL_VERSION_NUMBER > 0x1010000fL)
   ctx = SSL_CTX_new(TLS_client_method());
+  SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);  // FIXME
+  SSL_CTX_set_max_proto_version(ctx, 0);
 #else
+  /* Older versions of OpenSSL don't support min/max version requests.
+   * That's OK, since we don't want anything older than 1.2 and
+   * they don't support anything newer. */
   ctx = SSL_CTX_new(TLSv1_2_client_method());
+  if (1) // FIXME if (non-default version request)
+    msyslog(LOG_INFO, "NTSc: can't set min/max TLS versions.");
 #endif
 
-#if (OPENSSL_VERSION_NUMBER > 0x1010000fL)
-  SSL_CTX_set_default_verify_file(ctx);   // Use system root certs
-#else
-  // FIXME
-#endif
+  SSL_CTX_set_default_verify_paths(ctx);   // Use system root certs
 
-#if (OPENSSL_VERSION_NUMBER > 0x1010000fL)
-  // FIXME
-  SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
-  SSL_CTX_set_max_proto_version(ctx, 0);
-#else
-  // FIXME
-#endif
+  if (NULL != ntsconfig.tlsciphers) {
+    if (1 != SSL_CTX_set_cipher_list(ctx, ntsconfig.tlsciphers)) {
+      msyslog(LOG_ERR, "NTSc: error setting TLS ciphers");
+    }
+  }
+  if (NULL != ntsconfig.tlsciphersuites) {
+    if (1 != SSL_CTX_set_ciphersuites(ctx, ntsconfig.tlsciphersuites)) {
+      msyslog(LOG_ERR, "NTSc: error setting TLS ciphersuites");
+    }
+  }
 
   ssl = SSL_new(ctx);
 
   SSL_set_fd(ssl, server);
   SSL_set_tlsext_host_name(ssl, peer->hostname);
 
+  SSL_connect(ssl);
+  SSL_do_handshake(ssl);
+
+  switch (SSL_version(ssl)) {
+#ifdef TLS1_3_VERSION
+    case TLS1_3_VERSION:
+      msyslog(LOG_INFO, "NTSc: Using TLS1.3");
+      break;
+#endif
+    case TLS1_2_VERSION:
+      msyslog(LOG_INFO, "NTSc: Using TLS1.2");
+      break;
+    default:
+      msyslog(LOG_INFO, "NTSc: Strange version: %d, \"%s\"",
+        SSL_version(ssl), SSL_get_version(ssl));
+      break;
+    }
+
+  /* This may be clutter, but this is how to do it. */
+  msyslog(LOG_INFO, "NTSc: Using %s with %d secret bits",
+    SSL_get_cipher_name(ssl),
+    SSL_get_cipher_bits(ssl, NULL));
+
+  cert = SSL_get_peer_certificate(ssl);
+  if (NULL == cert) {
+    msyslog(LOG_INFO, "NTSc: No certificate");
+  } else {
+    X509_NAME *certname;
+    char name[200];
+    int certok;
+    certname = X509_get_subject_name(cert);
+    X509_NAME_oneline(certname, name, sizeof(name));
+    msyslog(LOG_INFO, "NTSc: certificate subject name: %s", name);
+    certname = X509_get_issuer_name(cert);
+    X509_NAME_oneline(certname, name, sizeof(name));
+    msyslog(LOG_INFO, "NTSc: certificate issuer name: %s", name);
+    certok = SSL_get_verify_result(ssl);
+    if (X509_V_OK == certok) {
+      msyslog(LOG_INFO, "NTSc: certificate is valid.");
+    } else {
+      msyslog(LOG_ERR, "NTSc: certificate invalid: %d", certok);
+    }
+  }
+
+  // FIXME AEAD_AES_SIV_CMAC_256
+  /* We are using AEAD_AES_SIV_CMAC_256, from RFC 5297
+   * There is no clean API yet.
+   */
+  peer->nts_state.keylen = AEAD_AES_SIV_CMAC_256_KEYLEN;
+  nts_make_keys(ssl,
+    peer->nts_state.c2s,
+    peer->nts_state.s2c,
+    peer->nts_state.keylen);
+
+  {
+    uint8_t req[16] = {
+      0x00, 0x01, 0x00, 0x02,
+      0x00, 0x00, 0x00, 0x04,
+      0x00, 0x02, 0x00, 0x0f,
+      0x80, 0x00, 0x00, 0x00 };
+    transfered = SSL_write(ssl, req, sizeof(req));
+    if (sizeof(req) != transfered) {
+      msyslog(LOG_ERR, "NTSc: write failed: %d, %m", transfered);
+      goto bail;
+    }
+    transfered = SSL_read(ssl, buff, sizeof(buff));
+    if (0 > transfered) {
+      msyslog(LOG_ERR, "NTSc: read failed: %d, %m", transfered);
+      goto bail;
+    }
+    msyslog(LOG_ERR, "NTSc: read %d bytes", transfered);
+  }
+
+  SSL_shutdown(ssl);
+
+  // unpack buffer
+
+bail:
   SSL_free(ssl);
   close(server);
   SSL_CTX_free(ctx);
@@ -72,32 +163,36 @@ bool nts_probe(struct peer * peer) {
 int open_TCP_socket(const char *hostname) {
   struct addrinfo hints;
   struct addrinfo *answer;
+  sockaddr_u sockaddr;
   int gai_rc, err;
   int sockfd;
 
 #ifdef HAVE_RES_INIT
-  res_init();
+  res_init();  /* see comment in ntp_dns */
 #endif
 
   ZERO(hints);
   hints.ai_protocol = IPPROTO_TCP;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_family = AF_UNSPEC;
-  gai_rc = getaddrinfo(hostname, "ntp", &hints, &answer);
+  gai_rc = getaddrinfo(hostname, "8123", &hints, &answer);  // FIXME
   if (0 != gai_rc) {
-    msyslog(LOG_INFO, "DNS: nts_probe: DNS error: %d, %s",
+    msyslog(LOG_INFO, "NTSc: nts_probe: DNS error: %d, %s",
       gai_rc, gai_strerror(gai_rc));
     return -1;
   }
 
+  memcpy(&sockaddr, answer->ai_addr, answer->ai_addrlen);
+  msyslog(LOG_INFO, "NTSc: nts_probe connecting to %s=%s",
+    hostname, socktoa(&sockaddr));
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if (-1 == sockfd) {
-    msyslog(LOG_INFO, "DNS: nts_probe: no socket: %m");
+    msyslog(LOG_INFO, "NTSc: nts_probe: no socket: %m");
   } else {
     // Use first answer
     err = connect(sockfd, answer->ai_addr, answer->ai_addrlen);
     if (-1 == err) {
-      msyslog(LOG_INFO, "DNS: nts_probe: can't connect: %m");
+      msyslog(LOG_INFO, "NTSc: nts_probe: can't connect: %m");
       close(sockfd);
       sockfd = -1;
     }
@@ -107,4 +202,35 @@ int open_TCP_socket(const char *hostname) {
   return sockfd;
 }
 
+bool nts_make_keys(SSL *ssl, uint8_t *c2s, uint8_t *s2c, int keylen) {
+  // char *label = "EXPORTER-network-time-security/1";
+  // Subject: [Ntp] [NTS4NTP] info for NTS developers
+  // From: Martin Langer <mart.langer at ostfalia.de>
+  // Date: Tue, 15 Jan 2019 11:40:13 +0100
+  // bug in OpenSSL 1.1.1a
+  const char *label = "EXPORTER-nts/1";
+  unsigned char context[5] = {0x00, 0x00, 0x00, 0x0f, 0x00};
+  if (1 != SSL_export_keying_material(ssl, c2s, keylen,
+        label, strlen(label),
+        context, 5, 1)) {
+     msyslog(LOG_ERR, "NTS: Error making c2s\n");
+     return false;
+     // ERR_print_errors_fp(stderr);
+  }
+  context[4] = 0x01;
+  if (1 != SSL_export_keying_material(ssl, s2c, keylen,
+        label, strlen(label),
+        context, 5, 1)) {
+     msyslog(LOG_ERR, "NTS: Error making s2c\n");
+     return false;
+     // ERR_print_errors_fp(stderr);
+  }
+  // Hack for debugging - obviously not good for security
+  msyslog(LOG_INFO, "NTS: C2S %02x %02x %02x %02x %02x\n",
+    c2s[0], c2s[1], c2s[2], c2s[3], c2s[4]);
+  msyslog(LOG_INFO, "NTS: S2C %02x %02x %02x %02x %02x\n",
+    s2c[0], s2c[1], s2c[2], s2c[3], s2c[4]);
+  return true;
+}
+
 /* end */


=====================================
ntpd/nts_server.c
=====================================
@@ -0,0 +1,158 @@
+/*
+ * nts_server.c - Network Time Security (NTS) server side support
+ *
+ * Section references are to
+ * https://tools.ietf.org/html/draft-ietf-ntp-using-nts-for-ntp-15
+ *
+ */
+#include "config.h"
+
+#include <signal.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#include "ntp.h"
+#include "ntpd.h"
+#include "ntp_stdlib.h"
+
+int create_listener(int port);
+void* nts_ke_listener(void*);
+void nts_ke_request(SSL *ssl);
+
+void nts_start_server(void) {
+    SSL_CTX *ctx;
+    pthread_t worker;
+    sigset_t block_mask, saved_sig_mask;
+    int rc;
+
+    ctx = SSL_CTX_new(TLS_server_method());
+    // FIXME set min/max versions
+
+    if (1 != SSL_CTX_use_certificate_chain_file(ctx, "/etc/ntp/cert-chain.pem")) {
+        // FIXME log SSL errors
+        msyslog(LOG_ERR, "NTSs: can't load cert-chain");
+    }
+
+    if (1 != SSL_CTX_use_PrivateKey_file(ctx, "/etc/ntp/key.pem", SSL_FILETYPE_PEM)) {
+        // FIXME log SSL errors
+        msyslog(LOG_ERR, "NTSs: can't load private key");
+    }
+    if (1 != SSL_CTX_check_private_key(ctx)) {
+        msyslog(LOG_ERR, "NTSs: Private Key doesn't work ******");
+    } else {
+        msyslog(LOG_INFO, "NTSs: Private Key OK");
+    }
+
+    sigfillset(&block_mask);
+    pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
+    rc = pthread_create(&worker, NULL, nts_ke_listener, ctx);
+    if (rc) {
+      msyslog(LOG_ERR, "NTSs: nts_start_server: error from pthread_create: %m");
+    }
+    pthread_sigmask(SIG_SETMASK, &saved_sig_mask, NULL);
+
+}
+
+void nts_ke_request(SSL *ssl);
+void* nts_ke_listener(void* arg) {
+    SSL_CTX *ctx = (SSL_CTX *)arg;
+    int sock;
+
+    sock = create_listener(123);
+    if (sock < 0) return NULL;
+
+    while(1) {
+        struct sockaddr addr;
+        uint len = sizeof(addr);
+        SSL *ssl;
+
+        int client = accept(sock, &addr, &len);
+        if (client < 0) {
+            msyslog(LOG_ERR, "NTSs: TCP accept failed: %m");
+            continue;
+        }
+        msyslog(LOG_INFO, "NTSs: TCP accept-ed from %s",
+            socktoa((sockaddr_u *)&addr));
+
+        /* This could/should go in a new thread. */  // FIXME
+        ssl = SSL_new(ctx);
+        SSL_set_fd(ssl, client);
+
+        if (SSL_accept(ssl) <= 0) {
+            msyslog(LOG_ERR, "NTSs: SSL accept failed: %m");
+            close(client);
+            continue;
+        }
+        msyslog(LOG_INFO, "NTSs: SSL accept-ed from %s",
+            socktoa((sockaddr_u *)&addr));
+        msyslog(LOG_INFO, "NTSs: Using TLS version %s, cipher %s with %d secret bits",
+            SSL_get_version(ssl),
+            SSL_get_cipher_name(ssl),
+            SSL_get_cipher_bits(ssl, NULL));
+
+        nts_ke_request(ssl);
+
+        SSL_shutdown(ssl);
+        SSL_free(ssl);
+        close(client);
+    }
+}
+
+void nts_ke_request(SSL *ssl) {
+    uint8_t buff[1000];
+    size_t bytes_read, bytes_written;
+    uint8_t c2s[NTS_MAX_KEYLEN], s2c[NTS_MAX_KEYLEN];
+    int keylen = AEAD_AES_SIV_CMAC_256_KEYLEN;
+
+
+    bytes_read = SSL_read(ssl, buff, sizeof(buff));
+    if (0 >= bytes_read) {
+        msyslog(LOG_INFO, "NTSs: SSL_read error");
+        return;
+    }
+
+    // Hack, echo it back
+    bytes_written = SSL_write(ssl, buff, bytes_read);
+    if (bytes_written != bytes_read) {
+        msyslog(LOG_INFO, "NTSs: SSL_write error");
+        return;
+    }
+
+    if (!nts_make_keys(ssl, c2s, s2c, keylen))
+      return;
+
+}
+
+int create_listener(int port)
+{
+    int sock;
+    struct sockaddr_in addr;
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(port);
+    addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    if (sock < 0) {
+        msyslog(LOG_ERR, "NTSs: Can't create socket: %m");
+        return -1;
+    }
+
+    if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+        msyslog(LOG_ERR, "NTSs: can't bind: %m");
+        return -1;
+    }
+
+    if (listen(sock, 1) < 0) {
+        msyslog(LOG_ERR, "NTSs: can't listen: %m");
+        return -1;
+    }
+    return sock;
+}   
+
+
+/* end */


=====================================
ntpd/wscript
=====================================
@@ -57,6 +57,7 @@ def build(ctx):
         "ntp_restrict.c",
         "ntp_util.c",
         "nts.c",
+        "nts_server.c",
         "nts_client.c",
         "nts_lib.c",
     ]



View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/96edbcc8aa0329b5e2887664dee8199745fa56e5...f89d113491f47096cb85b9ac60f23a7dfd4512af

-- 
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/96edbcc8aa0329b5e2887664dee8199745fa56e5...f89d113491f47096cb85b9ac60f23a7dfd4512af
You're receiving this email because of your account on gitlab.com.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.ntpsec.org/pipermail/vc/attachments/20190209/9842d7e2/attachment-0001.html>


More information about the vc mailing list