[Git][NTPsec/ntpsec][master] 3 commits: Add unresolved issues section to nts.adoc.
Eric S. Raymond
gitlab at mg.gitlab.com
Wed Feb 6 02:13:04 UTC 2019
Eric S. Raymond pushed to branch master at NTPsec / ntpsec
Commits:
b20431c8 by James Browning at 2019-02-05T18:00:15Z
Add unresolved issues section to nts.adoc.
- - - - -
79491d27 by James Browning at 2019-02-05T18:24:52Z
nts_lib foundation
- - - - -
033d512f by James Browning at 2019-02-05T20:05:56Z
NTS records handling 1
- - - - -
7 changed files:
- devel/nts.adoc
- + include/nts_lib.h
- + ntpd/nts_lib.c
- ntpd/wscript
- tests/common/tests_main.c
- + tests/ntpd/nts_lib.c
- tests/wscript
Changes:
=====================================
devel/nts.adoc
=====================================
@@ -569,6 +569,12 @@ the hexadecimal timestamps and such.
...
----
+== Unresolved issues for the next RFC revision
+
+The binary KE request-response format is unfortunate for all the usual
+reasons (endianness issues etc). At the expected transaction volume,
+the encode/decode overhead shouldn't be an issue.
+
== Martin Langer's notes ==
um... maybe the first hint... The current OpenSSL version doesn't
=====================================
include/nts_lib.h
=====================================
@@ -0,0 +1,110 @@
+#ifndef GUARD_NTS_LIB_H
+#define GUARD_NTS_LIB_H
+
+#include <linux/types.h>
+#include <openssl/evp.h>
+#include <stdbool.h>
+
+typedef struct {
+ void *key_c2s;
+ void *key_s2c;
+ void *nonce;
+ char *plaintext;
+ void *ciphertext;
+ char *cookie;
+ void *iv;
+ void *bit; // pointer for mempcpy, upf
+ __u8 addr_peer[16];
+
+ int tally;
+
+ __u16 size_iv;
+ __u16 size_key_csc;
+ __u16 size_nonce;
+ __u16 size_ciphertext;
+ __u16 size_plaintext;
+ __u16 nts_algo;
+ __u16 cookie_key_id;
+ __u16 recipe;
+ __u16 countdown;
+ __u16 now; // network order word
+} cookie_bits;
+
+typedef struct {
+ __u8 *next;
+ __u8 *record;
+ __u8 *body;
+ __u8 *bit; // pointer for mempcpy, upf
+
+ __u16 body_length;
+ __u16 record_type;
+ __u16 record_length;
+ __u16 now; // network order word
+ bool critical;
+} record_bits;
+
+enum record_type {
+ end_of_message = 0,
+ next_protocol_negotiation = 1,
+ error = 2,
+ warning = 3,
+ algorithm_negotiation = 4,
+ new_cookie = 5,
+ server_negotiation = 6,
+ port_negotiation = 7
+};
+
+enum errors_type {
+ unrecognized_critical_section = 0,
+ bad_request = 1
+};
+
+enum aead_ciphers {
+ AEAD_AES_128_GCM = 1,
+ AEAD_AES_256_GCM = 2,
+ AEAD_AES_128_CCM = 3,
+ AEAD_AES_256_CCM = 4,
+
+ AEAD_AES_128_GCM_8 = 5,
+ AEAD_AES_256_GCM_8 = 6,
+ AEAD_AES_128_GCM_12 = 7,
+ AEAD_AES_256_GCM_12 = 8,
+
+ AEAD_AES_128_CCM_SHORT = 9,
+ AEAD_AES_256_CCM_SHORT = 10,
+ AEAD_AES_128_CCM_SHORT_8 = 11,
+ AEAD_AES_256_CCM_SHORT_8 = 12,
+ AEAD_AES_128_CCM_SHORT_12 = 13,
+ AEAD_AES_256_CCM_SHORT_12 = 14,
+
+ AEAD_AES_SIV_CMAC_256 = 15,
+ AEAD_AES_SIV_CMAC_384 = 16,
+ AEAD_AES_SIV_CMAC_512 = 17,
+
+ AEAD_AES_128_CCM_8 = 18,
+ AEAD_AES_256_CCM_8 = 19,
+
+ AEAD_AES_128_OCB_TAGLEN128 = 20,
+ AEAD_AES_128_OCB_TAGLEN96 = 21,
+ AEAD_AES_128_OCB_TAGLEN64 = 22,
+ AEAD_AES_192_OCB_TAGLEN128 = 23,
+ AEAD_AES_192_OCB_TAGLEN96 = 24,
+ AEAD_AES_192_OCB_TAGLEN64 = 25,
+ AEAD_AES_256_OCB_TAGLEN128 = 26,
+ AEAD_AES_256_OCB_TAGLEN96 = 27,
+ AEAD_AES_256_OCB_TAGLEN64 = 28,
+
+ AEAD_CHACHA20_POLY1305 = 29
+};
+
+extern __u8 *upf(void *src, void *dest, size_t n);
+
+extern int nts_record_form(record_bits *in);
+extern int nts_record_parse(record_bits *in);
+
+extern int nts_cookie_prep(cookie_bits *input);
+extern int nts_cookie_clean(cookie_bits *a);
+extern int nts_cookie_plaintext_parse(cookie_bits *out);
+extern int nts_cookie_plaintext_form(cookie_bits *in);
+
+#endif // GUARD_NTS_LIB_H
\ No newline at end of file
=====================================
ntpd/nts_lib.c
=====================================
@@ -0,0 +1,114 @@
+#include "nts_lib.h"
+#include "config.h"
+#include "nts_lib.h"
+#include "ntp_types.h"
+#include "ntpd.h"
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+
+// a binary unpack function it should sort of reverse mempcpy
+__u8 *upf(void *src, void *dest, size_t n) {
+ (void)memcpy(dest, src, n);
+ return (__u8 *)src + n;
+}
+
+/* parse an NTS record to retrieve the body, body_length and record_type
+ *
+ * Assumes the record field is set to an appropriate value.
+ *
+ * sets the record_length, record_type and body fields
+ *
+ * returns 0 on success
+ */
+int nts_record_parse(record_bits *in) {
+ in->bit = upf(in->record, &in->now, sizeof(__u16));
+
+ if (0x80 & in->record[0]) {
+ in->critical = true;
+ in->now &= htons(~0x8000);
+ }
+ in->record_type = ntohs(in->now);
+
+ in->bit = upf(in->bit, &in->now, sizeof(__u16));
+ in->body_length = ntohs(in->now);
+ if (0 != in->body_length) {
+ in->body = in->bit;
+ in->bit += in->body_length;
+ } else {
+ in->body = NULL;
+ }
+ return 0;
+}
+
+/* form an NTS record
+ *
+ * Assumes the record_length, record_type and body fields are set to appropriate
+ * values
+ *
+ * sets the record_length and record fields.
+ *
+ * returns 0 on success
+ * returns 1 on memory allcation failure;
+ */
+int nts_record_form(record_bits *in) {
+ in->record_length = (4 + in->body_length);
+ in->record = malloc(in->record_length);
+ if (NULL == in->record) {
+ return 1;
+ }
+ in->now = htons(in->record_type);
+ if (in->critical) {
+ in->now |= htons(0x8000);
+ }
+ in->bit = mempcpy(in->record, &in->now, sizeof(__u16));
+ in->now = htons(in->body_length);
+ in->bit = mempcpy(in->bit, &in->now, sizeof(__u16));
+ if (0 < in->body_length) {
+ in->bit = mempcpy(in->bit, in->body, in->body_length);
+ }
+ return 0;
+}
+
+// Allocate & initialize structure & fields for NTS cookie generation/parsing
+int nts_cookie_prep(cookie_bits *input) {
+ UNUSED_ARG(input);
+ return 0;
+}
+
+// Free (most) storage used by NTS cookie generation/parsing routines
+int nts_cookie_clean(cookie_bits *a) {
+ UNUSED_ARG(a);
+ return 0;
+}
+
+/* Parse the plaintext to retrieve the AEAD algorithm to use when processing,
+ * the c2s key used to decipher the AEAF extension from the client and the
+ * s2c key used to encipher the AEAF extension returned to the client.
+ *
+ * Assumes the plaintext and recipe fields are set.
+ *
+ * Sets the key_c2s, key_s2c and size_key_csc fields
+ * optionally sets fields addr_peer and countdown
+ *
+ * returns number of bytes remaining in the plaintext (should be 0)
+ */
+int nts_cookie_plaintext_parse(cookie_bits *out) {
+ UNUSED_ARG(out);
+ return 0;
+}
+
+/* Form the cookie plaintext from the AEAD algorithm number, the c2s key and
+ * the sc key extracted during the NTS-KE session.
+ *
+ * Assumes the key_c2s, key_s2c, recipe and size_key_csc fields are set
+ * optionally uses fields addr_peer and countdown
+ *
+ * sets the plaintext and size_plaintext fields.
+ *
+ * returns 0 on success
+ */
+int nts_cookie_plaintext_form(cookie_bits *in) {
+ UNUSED_ARG(in);
+ return 0;
+}
=====================================
ntpd/wscript
=====================================
@@ -57,6 +57,7 @@ def build(ctx):
"ntp_restrict.c",
"ntp_util.c",
"nts.c",
+ "nts_lib.c",
]
ctx(
=====================================
tests/common/tests_main.c
=====================================
@@ -73,6 +73,7 @@ static void RunAllTests(void)
RUN_TEST_GROUP(leapsec);
RUN_TEST_GROUP(hackrestrict);
RUN_TEST_GROUP(recvbuff);
+ RUN_TEST_GROUP(nts_lib);
#endif
}
=====================================
tests/ntpd/nts_lib.c
=====================================
@@ -0,0 +1,293 @@
+#include "nts_lib.h"
+#include "unity.h"
+#include "unity_fixture.h"
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+TEST_GROUP(nts_lib);
+
+TEST_SETUP(nts_lib) {}
+
+TEST_TEAR_DOWN(nts_lib) {}
+
+TEST(nts_lib, record_decode_null) {
+ __u8 expected[4] = {0x80, 0, 0, 0};
+ record_bits *record;
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->record = malloc(4);
+ if (NULL == record->record) {
+ TEST_FAIL_MESSAGE("record value malloc");
+ return;
+ }
+ memcpy(record->record, expected, 4);
+ record->record_length = 4;
+
+ nts_record_parse(record);
+
+ TEST_ASSERT_TRUE(record->critical);
+ TEST_ASSERT_EQUAL_INT16(0, record->record_type);
+ TEST_ASSERT_EQUAL_INT16(0, record->body_length);
+ TEST_ASSERT_NULL(record->body);
+ record->body = NULL;
+
+ free(record->record);
+ free(record);
+}
+
+TEST(nts_lib, record_decode_u16) {
+ __u8 expected[6] = {0, port_negotiation, 0, 2, 0, 123};
+ record_bits *record;
+ int lints[1];
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->record = malloc(6);
+ if (NULL == record->record) {
+ TEST_FAIL_MESSAGE("record value malloc");
+ return;
+ }
+ memcpy(record->record, expected, 6);
+ record->record_length = 6;
+
+ nts_record_parse(record);
+ if (record->body_length & 1) {
+ TEST_FAIL_MESSAGE("odd byte out");
+ }
+ memcpy(lints, record->body, 2);
+
+ TEST_ASSERT_FALSE(record->critical);
+ TEST_ASSERT_EQUAL_INT16(port_negotiation, record->record_type);
+ TEST_ASSERT_EQUAL_INT16(2, record->body_length);
+ TEST_ASSERT_NOT_NULL(record->body);
+
+ TEST_ASSERT_EQUAL_INT16(123, ntohs(lints[0]));
+ record->body = NULL;
+
+ free(record->record);
+ free(record);
+}
+
+TEST(nts_lib, record_decode_u16s) {
+ __u8 expected[8] = {0, algorithm_negotiation, 0, 4,
+ 0, AEAD_AES_SIV_CMAC_512, 0, AEAD_CHACHA20_POLY1305};
+ record_bits *record;
+ int lints[2];
+ void *there;
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->record = malloc(8);
+ if (NULL == record->record) {
+ TEST_FAIL_MESSAGE("record value malloc");
+ return;
+ }
+ memcpy(record->record, expected, 8);
+ record->record_length = 8;
+
+ nts_record_parse(record);
+ there = record->body;
+ if (record->body_length & 1) {
+ TEST_FAIL_MESSAGE("odd byte out");
+ }
+ for (int count = 0; (count * 2) < record->body_length; count++) {
+ there = upf(there, &lints[count], 2);
+ }
+
+ TEST_ASSERT_FALSE(record->critical);
+ TEST_ASSERT_EQUAL_INT16(algorithm_negotiation, record->record_type);
+ TEST_ASSERT_EQUAL_INT16(4, record->body_length);
+ TEST_ASSERT_NOT_NULL(record->body);
+
+ TEST_ASSERT_EQUAL_INT16(AEAD_AES_SIV_CMAC_512, ntohs(lints[0]));
+ TEST_ASSERT_EQUAL_INT16(AEAD_CHACHA20_POLY1305, ntohs(lints[1]));
+ record->body = NULL;
+
+ free(record->record);
+ free(record);
+}
+
+TEST(nts_lib, record_decode_text) {
+ record_bits *record;
+ const char *expserv = "asus.internal.jamesb192.com";
+ __u8 expected[31] = {0, server_negotiation,
+ 0, 27,
+ 'a', 's', 'u', 's', '.', 'i', 'n', 't', 'e',
+ 'r', 'n', 'a', 'l', '.', 'j', 'a', 'm', 'e',
+ 's', 'b', '1', '9', '2', '.', 'c', 'o', 'm'
+ };
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->record = malloc(31);
+ if (NULL == record->record) {
+ TEST_FAIL_MESSAGE("record value malloc");
+ return;
+ }
+ memcpy(record->record, expected, 31);
+ record->record_length = 31;
+
+ nts_record_parse(record);
+
+ TEST_ASSERT_FALSE(record->critical);
+ TEST_ASSERT_EQUAL_INT16(server_negotiation, record->record_type);
+ TEST_ASSERT_EQUAL_INT16(27, record->body_length);
+ TEST_ASSERT_NOT_NULL(record->body);
+
+ TEST_ASSERT_EQUAL_STRING_LEN(expserv, record->body, 27);
+ record->body = NULL;
+
+ free(record->record);
+ free(record);
+}
+
+TEST(nts_lib, record_encode_null) {
+ __u8 expected[4] = {0x80, end_of_message, 0, 0};
+ record_bits *record;
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->critical = true;
+ record->body_length = 0;
+ record->record_type = end_of_message;
+
+ nts_record_form(record);
+
+ TEST_ASSERT_EQUAL_UINT16(4, record->record_length);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, record->record, 4);
+
+ free(record->body);
+ free(record);
+}
+TEST(nts_lib, record_encode_u16) {
+ __u8 expected[6] = {0, port_negotiation, 0, 2, 0, 123};
+ __u16 exp_port = htons(123);
+ record_bits *record;
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->critical = false;
+ record->body_length = 2;
+ record->record_type = port_negotiation;
+ record->body = malloc(2);
+ if (NULL == record->body) {
+ TEST_FAIL_MESSAGE("body malloc");
+ return;
+ }
+ memcpy(record->body, &exp_port, 2);
+
+ nts_record_form(record);
+
+ TEST_ASSERT_EQUAL_UINT16(6, record->record_length);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, record->record, 6);
+
+ free(record->body);
+ free(record);
+}
+
+TEST(nts_lib, record_encode_u16s) {
+ __u8 expected[8] = {0, algorithm_negotiation, 0, 4, 0, 2, 0, 4};
+ __u16 exp_algos[2] = {htons(2), htons(4)};
+ record_bits *record;
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->critical = false;
+ record->body_length = 4;
+ record->record_type = algorithm_negotiation;
+ record->body = malloc(4);
+ if (NULL == record->body) {
+ TEST_FAIL_MESSAGE("body malloc");
+ return;
+ }
+ memcpy(record->body, &exp_algos, 4);
+
+ nts_record_form(record);
+
+ TEST_ASSERT_EQUAL_UINT16(8, record->record_length);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, record->record, 8);
+
+ free(record->body);
+ free(record);
+}
+
+TEST(nts_lib, record_encode_text) {
+ const char *expserv = "asus.internal.jamesb192.com";
+ __u8 expected[31] = { 0, server_negotiation,
+ 0, 27,
+ 'a', 's', 'u', 's', '.', 'i', 'n', 't', 'e',
+ 'r', 'n', 'a', 'l', '.', 'j', 'a', 'm', 'e',
+ 's', 'b', '1', '9', '2', '.', 'c', 'o', 'm'
+ };
+ record_bits *record;
+
+ record = calloc(1, sizeof(record_bits));
+ if (NULL == record) {
+ TEST_FAIL_MESSAGE("record malloc");
+ return;
+ }
+ record->critical = false;
+ record->body_length = 27;
+ record->record_type = server_negotiation;
+ record->body = malloc(27);
+ if (NULL == record->body) {
+ TEST_FAIL_MESSAGE("body calloc");
+ return;
+ }
+ memcpy(record->body, expserv, 27);
+
+ nts_record_form(record);
+
+ TEST_ASSERT_EQUAL_UINT16(31, record->record_length);
+ TEST_ASSERT_EQUAL_UINT8_ARRAY(expected, record->record, 31);
+
+ free(record->body);
+ free(record);
+}
+
+/*TEST(nts_lib, existance) {
+ TEST_ASSERT_NOT_NULL(upf);
+ TEST_ASSERT_NOT_NULL(nts_record_form)
+ TEST_ASSERT_NOT_NULL(nts_record_parse)
+ TEST_ASSERT_NOT_NULL(nts_cookie_prep);
+ TEST_ASSERT_NOT_NULL(nts_cookie_clean);
+ TEST_ASSERT_NOT_NULL(nts_cookie_plaintext_parse);
+ TEST_ASSERT_NOT_NULL(nts_cookie_plaintext_form);
+}*/
+
+TEST_GROUP_RUNNER(nts_lib) {
+// RUN_TEST_CASE(nts_lib, existance);
+
+ RUN_TEST_CASE(nts_lib, record_decode_null);
+ RUN_TEST_CASE(nts_lib, record_decode_u16);
+ RUN_TEST_CASE(nts_lib, record_decode_u16s);
+ RUN_TEST_CASE(nts_lib, record_decode_text);
+
+ RUN_TEST_CASE(nts_lib, record_encode_null);
+ RUN_TEST_CASE(nts_lib, record_encode_u16);
+ RUN_TEST_CASE(nts_lib, record_encode_u16s);
+ RUN_TEST_CASE(nts_lib, record_encode_text);
+}
=====================================
tests/wscript
=====================================
@@ -101,6 +101,7 @@ def build(ctx):
"ntpd/leapsec.c",
"ntpd/restrict.c",
"ntpd/recvbuff.c",
+ "ntpd/nts_lib.c"
] + common_source
ctx.ntp_test(
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/52536ed60e319a5c3918b4cf1eef3df21788ec86...033d512f8a56d5234f162bb4d0a58b21fb55a532
--
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/compare/52536ed60e319a5c3918b4cf1eef3df21788ec86...033d512f8a56d5234f162bb4d0a58b21fb55a532
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/20190206/83d7d99d/attachment-0001.html>
More information about the vc
mailing list