Commit b0275b41 authored by Hal Murray's avatar Hal Murray

First pass at cookies

parent e0c05c8f
Pipeline #47880199 failed with stage
in 60 minutes and 16 seconds
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
......@@ -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
......
......@@ -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;
}
......
/*
* 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 */
......@@ -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);
......
......@@ -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")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment