#define NKE_RECORD_COOKIE 5
#define NKE_RECORD_NTPV4_SERVER_NEGOTIATION 6
#define NKE_RECORD_NTPV4_PORT_NEGOTIATION 7
+#define NKE_RECORD_COMPLIANT_128GCM_EXPORT 1024
#define NKE_NEXT_PROTOCOL_NTPV4 0
int got_response;
int resolving_name;
+ int compliant_128gcm;
NKE_Context context;
NKE_Cookie cookies[NKE_MAX_COOKIES];
int num_cookies;
{
NKSN_Instance session = inst->session;
uint16_t data[2];
- int length;
+ int i, length;
NKSN_BeginMessage(session);
length * sizeof (data[0])))
return 0;
+ for (i = 0; i < length; i++) {
+ if (data[i] == htons(AEAD_AES_128_GCM_SIV)) {
+ if (!NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0))
+ return 0;
+ break;
+ }
+ }
+
if (!NKSN_EndMessage(session))
return 0;
assert(sizeof (data) % sizeof (uint16_t) == 0);
assert(sizeof (uint16_t) == 2);
+ inst->compliant_128gcm = 0;
inst->num_cookies = 0;
inst->ntp_address.ip_addr.family = IPADDR_UNSPEC;
inst->ntp_address.port = 0;
aead_algorithm = ntohs(data[0]);
inst->context.algorithm = aead_algorithm;
break;
+ case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
+ if (length != 0) {
+ DEBUG_LOG("Non-empty compliant-128gcm record");
+ error = 1;
+ break;
+ }
+ DEBUG_LOG("Compliant AES-128-GCM-SIV export");
+ inst->compliant_128gcm = 1;
+ break;
case NKE_RECORD_ERROR:
if (length == 2)
DEBUG_LOG("NTS-KE error %d", ntohs(data[0]));
exporter_algorithm = inst->context.algorithm;
/* With AES-128-GCM-SIV, set the algorithm ID in the RFC5705 key exporter
- context incorrectly for compatibility with older chrony servers */
- if (exporter_algorithm == AEAD_AES_128_GCM_SIV)
+ context incorrectly for compatibility with older chrony servers unless
+ the server confirmed support for the compliant context */
+ if (exporter_algorithm == AEAD_AES_128_GCM_SIV && !inst->compliant_128gcm)
exporter_algorithm = AEAD_AES_SIV_CMAC_256;
if (!NKSN_GetKeys(inst->session, inst->context.algorithm, exporter_algorithm,
/* ================================================== */
static int
-prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_algorithm)
+prepare_response(NKSN_Instance session, int error, int next_protocol, int aead_algorithm,
+ int compliant_128gcm)
{
SIV_Algorithm exporter_algorithm;
NKE_Context context;
if (!NKSN_AddRecord(session, 1, NKE_RECORD_AEAD_ALGORITHM, &datum, sizeof (datum)))
return 0;
+ if (compliant_128gcm) {
+ if (!NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0))
+ return 0;
+ }
+
if (CNF_GetNTPPort() != NTP_PORT) {
datum = htons(CNF_GetNTPPort());
if (!NKSN_AddRecord(session, 1, NKE_RECORD_NTPV4_PORT_NEGOTIATION, &datum, sizeof (datum)))
exporter_algorithm = aead_algorithm;
/* With AES-128-GCM-SIV, set the algorithm ID in the RFC5705 key exporter
- context incorrectly for compatibility with older chrony clients */
- if (exporter_algorithm == AEAD_AES_128_GCM_SIV)
+ context incorrectly for compatibility with older chrony clients unless
+ the client requested the compliant context */
+ if (exporter_algorithm == AEAD_AES_128_GCM_SIV && !compliant_128gcm)
exporter_algorithm = AEAD_AES_SIV_CMAC_256;
if (!NKSN_GetKeys(session, aead_algorithm, exporter_algorithm,
int next_protocol_records = 0, aead_algorithm_records = 0;
int next_protocol_values = 0, aead_algorithm_values = 0;
int next_protocol = -1, aead_algorithm = -1, error = -1;
+ int compliant_128gcm = 0;
int i, critical, type, length;
uint16_t data[NKE_MAX_RECORD_BODY_LENGTH / sizeof (uint16_t)];
aead_algorithm = ntohs(data[i]);
}
break;
+ case NKE_RECORD_COMPLIANT_128GCM_EXPORT:
+ if (length != 0) {
+ error = NKE_ERROR_BAD_REQUEST;
+ break;
+ }
+ compliant_128gcm = 1;
+ break;
case NKE_RECORD_ERROR:
case NKE_RECORD_WARNING:
case NKE_RECORD_COOKIE:
error = NKE_ERROR_BAD_REQUEST;
}
- if (!prepare_response(session, error, next_protocol, aead_algorithm))
+ if (!prepare_response(session, error, next_protocol, aead_algorithm, compliant_128gcm))
return 0;
return 1;
if (random() % 2) {
length = random() % (sizeof (data) + 1);
- TEST_CHECK(NKSN_AddRecord(session, 0, 1000 + random() % 1000, data, length));
+ TEST_CHECK(NKSN_AddRecord(session, 0, 2000 + random() % 1000, data, length));
}
+ if (random() % 2)
+ TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0));
+
if (index != 8) {
for (i = 0; i < NKE_MAX_COOKIES; i++) {
length = (random() % sizeof (data) + 1) / 4 * 4;
if (index == 8) {
length = random() % (sizeof (data) + 1);
- TEST_CHECK(NKSN_AddRecord(session, 1, 1000 + random() % 1000, data, length));
+ TEST_CHECK(NKSN_AddRecord(session, 1, 2000 + random() % 1000, data, length));
}
if (random() % 2) {
TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_NTPV4_PORT_NEGOTIATION, data, length));
}
+ if (random() % 2)
+ TEST_CHECK(NKSN_AddRecord(session, 0, NKE_RECORD_COMPLIANT_128GCM_EXPORT, NULL, 0));
+
if (random() % 2) {
length = random() % (sizeof (data) + 1);
- TEST_CHECK(NKSN_AddRecord(session, 0, 1000 + random() % 1000, data, length));
+ TEST_CHECK(NKSN_AddRecord(session, 0, 2000 + random() % 1000, data, length));
}
TEST_CHECK(NKSN_EndMessage(session));