[Git][NTPsec/ntpsec][master] First pass at cookies
Hal Murray
gitlab at mg.gitlab.com
Sun Feb 17 12:25:19 UTC 2019
Hal Murray pushed to branch master at NTPsec / ntpsec
Commits:
b0275b41 by Hal Murray at 2019-02-17T12:09:47Z
First pass at cookies
- - - - -
6 changed files:
- + devel/TODO-NTS
- include/nts.h
- ntpd/nts_client.c
- + ntpd/nts_cookie.c
- ntpd/nts_server.c
- ntpd/wscript
Changes:
=====================================
devel/TODO-NTS
=====================================
@@ -0,0 +1,18 @@
+flag for require NTS
+
+security level
+
+multithread msyslog
+
+fixup seccomp
+
+show NTS flag via ntpq
+ extra credit if we can find a place on the peers display
+show NTS statistics
+
+documentation:
+ HOWTO on NTS
+ HOWTO on certificates
+ glossary: https://letsencrypt.org/docs/glossary/
+
+client certificates
=====================================
include/nts.h
=====================================
@@ -6,8 +6,9 @@
#include <openssl/ssl.h>
-#define NTS_MAX_COOKIES 8 /* RFC 4.1.6 */
-#define NTS_COOKIELEN 128 /* placeholder - see RFC 6 */
+#define NTS_MAX_KEYLEN 64 /* used in cookies */
+#define NTS_MAX_COOKIELEN 192 /* see nts_cookie.c */
+#define NTS_MAX_COOKIES 8 /* RFC 4.1.6 */
#define FLAG_NTS 0x01u /* use NTS (network time security) */
#define FLAG_NTS_ASK 0x02u /* NTS, ask for specified server */
@@ -23,13 +24,14 @@ 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 IANA_AEAD_AES_SIV_CMAC_384 16
+#define IANA_AEAD_AES_SIV_CMAC_512 17
#define AEAD_AES_SIV_CMAC_256_KEYLEN 32
+#define AEAD_AES_SIV_CMAC_384_KEYLEN 48
+#define AEAD_AES_SIV_CMAC_512_KEYLEN 64
-#define NTS_MAX_KEYLEN 64
/* Client-side state per connection to server */
struct ntsstate_t {
int aead;
@@ -38,7 +40,7 @@ struct ntsstate_t {
int cookie_count;
int cookie_length;
bool valid[NTS_MAX_COOKIES];
- uint8_t cookies[NTS_MAX_COOKIES][NTS_COOKIELEN];
+ uint8_t cookies[NTS_MAX_COOKIES][NTS_MAX_COOKIELEN];
uint8_t c2s[NTS_MAX_KEYLEN], s2c[NTS_MAX_KEYLEN];
};
@@ -91,8 +93,8 @@ enum aead_ciphers {
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_256 = 15, /* RFC 5297 */
+ AEAD_AES_SIV_CMAC_384 = 16, /* These 3 are the ones we use */
AEAD_AES_SIV_CMAC_512 = 17,
AEAD_AES_128_CCM_8 = 18,
@@ -117,14 +119,21 @@ extern struct ntsconfig_t ntsconfig;
bool nts_server_init(void);
bool nts_client_init(void);
+bool nts_cookie_init(void);
void nts_log_ssl_error(void);
-int nts_get_key_length(int aead);
bool nts_load_ciphers(SSL_CTX *ctx);
bool nts_load_versions(SSL_CTX *ctx);
+
+int nts_get_key_length(int aead);
bool nts_make_keys(SSL *ssl, uint8_t *c2s, uint8_t *s2c, int keylen);
-int nts_make_cookie(uint8_t *cookie, uint16_t aead,
+
+int nts_make_cookie(uint8_t *cookie,
+ uint16_t aead,
uint8_t *c2s, uint8_t *s2c, int keylen);
+bool nts_unpack_cookie(uint8_t *cookie, int cookielen,
+ uint16_t *aead,
+ uint8_t *c2s, uint8_t *s2c, int *keylen);
#define NO_OLD_VERSIONS SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1
=====================================
ntpd/nts_client.c
=====================================
@@ -351,7 +351,7 @@ bool nts_client_process_response(struct peer* peer, SSL *ssl) {
peer->nts_state.aead = data;
break;
case nts_new_cookie:
- if (NTS_COOKIELEN < length) {
+ if (NTS_MAX_COOKIELEN < length) {
msyslog(LOG_ERR, "NTSc: NC cookie too big: %d", length);
return false;
}
=====================================
ntpd/nts_cookie.c
=====================================
@@ -0,0 +1,201 @@
+/*
+ * nts_cookie.c - Network Time Security (NTS) cookie processing
+ *
+ * Section references are to
+ * https://tools.ietf.org/html/draft-ietf-ntp-using-nts-for-ntp-15
+ *
+ * This follows section 6, Suggested Format for NTS Cookies
+ * It uses AEAD_AES_SIV_CMAC_256/384/512 from RFC 5297
+ * It is currently a stand-alone library
+ * but will probably migrate to OpenSSL/libcrypto.
+ *
+ * The selection is done by the key length.
+ *
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <openssl/rand.h>
+#include <aes_siv.h>
+
+#include "ntp_stdlib.h"
+#include "nts.h"
+
+/* Cookie format:
+ * cookie is I,N,CMAC,C
+ * I Key index, see below
+ * N nonce
+ * C is encrypt(K, N, P)
+ * P is AEAD, C2S, S2C
+ * length of C2S and S2C depends upon AEAD
+ * CMAC is 16 bytes
+ */
+
+/* K and I should be preserved across boots, and rotated every day or so.
+ * We need to support the old K/I for another day.
+ * Encryption within cookies uses AEAD_AES_SIV_CMAC_nnn. That's the
+ * same family of algorithims as NTS uses on the wire.
+ * The nnn is selected by the key length.
+ * 32 => 256
+ * 48 => 384
+ * 64 => 512
+ */
+
+/* Max length:
+ * 4 I
+ * 16 N
+ * 16 CMAC
+ * 4 AEAD
+ * 64 C2S NTS_MAX_KEYLEN
+ * 64 S2C NTS_MAX_KEYLEN
+ * ------
+ * 168
+ */
+
+/* cookies use same algorithms as wire */
+uint8_t K[NTS_MAX_KEYLEN];
+uint32_t I;
+
+AES_SIV_CTX* cookie_ctx; /* need one per thread */
+
+/* This determines which algorithm we use. */
+/* making this a variable rather than #define
+ * opens up the opportunity to pick one at run time. */
+int K_length = AEAD_AES_SIV_CMAC_256_KEYLEN;
+#define NONCE_LENGTH 16
+
+/* Associated data: aead (rounded up to 4) plus NONCE */
+#define AD_LENGTH 20
+#define AEAD_LENGTH 4
+
+bool nts_cookie_init(void) {
+ bool OK = true;
+#if (OPENSSL_VERSION_NUMBER > 0x1010100fL)
+ OK &= RAND_priv_bytes(K, sizeof(K));
+ OK &= RAND_bytes((uint8_t *)&I, sizeof(I));
+#else
+ OK &= RAND_bytes(K, sizeof(K));
+ OK &= RAND_bytes((uint8_t *)&I, sizeof(I));
+#endif
+ cookie_ctx = AES_SIV_CTX_new();
+ if (NULL == cookie_ctx)
+ OK = false;
+ return OK;
+}
+
+/* returns actual length */
+int nts_make_cookie(uint8_t *cookie,
+ uint16_t aead,
+ uint8_t *c2s, uint8_t *s2c, int keylen) {
+ uint8_t plaintext[NTS_MAX_COOKIELEN];
+ uint8_t *nonce;
+ int used, plainlength;
+ bool ok;
+
+ // ASSERT(keylen<NTS_MAX_KEYLEN);
+
+ uint8_t * finger;
+ uint32_t temp; /* keep 4 byte alignment */
+ size_t left;
+
+ /* collect plaintext
+ * separate buffer avoids encrypt in place
+ * but costs cache space
+ */
+ finger = plaintext;
+ temp = aead;
+ memcpy(finger, &temp, AEAD_LENGTH);
+ finger += AEAD_LENGTH;
+ memcpy(finger, c2s, keylen);
+ finger += keylen;
+ memcpy(finger, s2c, keylen);
+ finger += keylen;
+ plainlength = finger-plaintext;
+
+ /* collect associated data */
+ finger = cookie;
+
+ memcpy(finger, &I, sizeof(I));
+ finger += sizeof(I);
+
+ nonce = finger;
+ RAND_bytes(finger, NONCE_LENGTH);
+ finger += NONCE_LENGTH;
+
+ // require(AD_LENGTH==finger-cookie);
+
+ used = finger-cookie;
+ left = NTS_MAX_COOKIELEN-used;
+
+ ok = AES_SIV_Encrypt(cookie_ctx,
+ finger, &left, /* left: in: max out length, out: length used */
+ K, K_length,
+ nonce, NONCE_LENGTH,
+ plaintext, plainlength,
+ cookie, AD_LENGTH);
+ if (!ok) {
+ msyslog(LOG_ERR, "NTS: Error from AES_SIV_Encrypt");
+ exit(1);
+ }
+
+ used += left;
+ // ASSERT(length < NTS_MAX_COOKIELEN);
+ // Need to encrypt
+
+ return used;
+}
+
+/* can't decrypt in place - that would trash the unauthenticated packet */
+bool nts_unpack_cookie(uint8_t *cookie, int cookielen,
+ uint16_t *aead,
+ uint8_t *c2s, uint8_t *s2c, int *keylen) {
+ uint8_t *finger;
+ uint8_t plaintext[NTS_MAX_COOKIELEN];
+ uint8_t *nonce;
+ uint32_t temp;
+ size_t plainlength;
+ int cipherlength;
+ bool ok;
+
+ finger = cookie;
+ // FIXME should call routine to return key
+ if (0 != memcmp(finger, &I, sizeof(I)))
+ return false;
+ finger += sizeof(I);
+ nonce = finger;
+ finger += NONCE_LENGTH;
+
+ // require(AD_LENGTH==finger-cookie);
+
+ cipherlength = cookielen - AD_LENGTH;
+ plainlength = NTS_MAX_COOKIELEN;
+
+ ok = AES_SIV_Decrypt(cookie_ctx,
+ plaintext, &plainlength,
+ K, K_length,
+ nonce, NONCE_LENGTH,
+ finger, cipherlength,
+ cookie, AEAD_LENGTH);
+ if (!ok)
+ return false;
+
+ *keylen = (plainlength-AEAD_LENGTH)/2;
+ finger = plaintext;
+ memcpy(&temp, finger, AEAD_LENGTH);
+ *aead = temp;
+ finger += AEAD_LENGTH;
+ memcpy(c2s, finger, *keylen);
+ finger += *keylen;
+ memcpy(s2c, finger, *keylen);
+ finger += *keylen;
+
+ return true;
+}
+
+
+
+/* end */
=====================================
ntpd/nts_server.c
=====================================
@@ -36,6 +36,7 @@ static SSL_CTX *server_ctx = NULL;
void nts_init(void) {
bool ok = true;
+ ok &= nts_cookie_init();
if (ntsconfig.ntsenable)
ok &= nts_server_init();
ok &= nts_client_init();
@@ -148,7 +149,7 @@ void nts_ke_request(SSL *ssl) {
uint8_t buff[1000];
int bytes_read, bytes_written;
uint8_t c2s[NTS_MAX_KEYLEN], s2c[NTS_MAX_KEYLEN];
- uint8_t cookie[NTS_COOKIELEN];
+ uint8_t cookie[NTS_MAX_COOKIELEN];
int aead, keylen, cookielen;
struct BufCtl_t buf;
int used;
@@ -218,35 +219,21 @@ int create_listener(int port) {
return sock;
}
+/* returns key length, 0 if unknown arg */
int nts_get_key_length(int aead) {
switch (aead) {
case IANA_AEAD_AES_SIV_CMAC_256:
return AEAD_AES_SIV_CMAC_256_KEYLEN;
+ case IANA_AEAD_AES_SIV_CMAC_384:
+ return AEAD_AES_SIV_CMAC_384_KEYLEN;
+ case IANA_AEAD_AES_SIV_CMAC_512:
+ return AEAD_AES_SIV_CMAC_512_KEYLEN;
default:
msyslog(LOG_ERR, "NTS: Strange AEAD code: %d", aead);
- return 16;
+ return 0;
}
}
-// FIXME - this is a total hack to test pack/unpack
-/* returns actual length */
-int nts_make_cookie(uint8_t *cookie,
- uint16_t aead,
- uint8_t *c2s, uint8_t *s2c, int keylen) {
-
- int length = NTS_COOKIELEN/2;
-
- if (keylen < length)
- length = keylen;
- *cookie = aead & 0xFF;
- for (int i=0; i<length; i++) {
- *cookie++ = *c2s++^*s2c++;
- }
-
- return length;
-}
-
-
bool nts_load_versions(SSL_CTX *ctx) {
int minver, maxver;
minver = nts_translate_version(ntsconfig.mintls);
=====================================
ntpd/wscript
=====================================
@@ -59,6 +59,7 @@ def build(ctx):
"nts.c",
"nts_server.c",
"nts_client.c",
+ "nts_cookie.c",
"nts_lib.c",
]
@@ -67,7 +68,7 @@ def build(ctx):
includes=ctx.env.PLATFORM_INCLUDES,
source=libntpd_source,
target="libntpd_obj",
- use="SSL CRYPTO",
+ use="SSL CRYPTO AES_SIV",
)
ctx(
@@ -127,7 +128,7 @@ def build(ctx):
source=ntpd_source,
target="ntpd",
use="libntpd_obj ntp M parse RT CAP SECCOMP PTHREAD NTPD "
- "SSL CRYPTO DNS_SD %s SOCKET NSL SCF" % use_refclock,
+ "SSL CRYPTO AES_SIV DNS_SD %s SOCKET NSL SCF" % use_refclock,
)
ctx.manpage(8, "ntpd-man.adoc")
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/b0275b41016407ad20db0f7bdb3c14103c3acda4
--
View it on GitLab: https://gitlab.com/NTPsec/ntpsec/commit/b0275b41016407ad20db0f7bdb3c14103c3acda4
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/20190217/2167fa7d/attachment-0001.html>
More information about the vc
mailing list