mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-03 19:05:06 -05:00
nts: add NTS-NTP server and client
Add support for the NTS NTP extension fields.
This commit is contained in:
174
nts_ntp_auth.c
Normal file
174
nts_ntp_auth.c
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
chronyd/chronyc - Programs for keeping computer clocks accurate.
|
||||
|
||||
**********************************************************************
|
||||
* Copyright (C) Miroslav Lichvar 2020
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
**********************************************************************
|
||||
|
||||
=======================================================================
|
||||
|
||||
NTS Authenticator and Encrypted Extension Fields extension field
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "sysincl.h"
|
||||
|
||||
#include "nts_ntp_auth.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "ntp_ext.h"
|
||||
#include "nts_ntp.h"
|
||||
#include "siv.h"
|
||||
#include "util.h"
|
||||
|
||||
struct AuthHeader {
|
||||
uint16_t nonce_length;
|
||||
uint16_t ciphertext_length;
|
||||
};
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_padding_length(int length)
|
||||
{
|
||||
return length % 4U ? 4 - length % 4U : 0;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
static int
|
||||
get_padded_length(int length)
|
||||
{
|
||||
return length + get_padding_length(length);
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
|
||||
const unsigned char *nonce, int nonce_length,
|
||||
const unsigned char *plaintext, int plaintext_length,
|
||||
int min_ef_length)
|
||||
{
|
||||
int auth_length, ciphertext_length, assoc_length;
|
||||
int nonce_padding, ciphertext_padding, additional_padding;
|
||||
unsigned char *ciphertext, *body;
|
||||
struct AuthHeader *header;
|
||||
|
||||
assert(sizeof (*header) == 4);
|
||||
|
||||
if (nonce_length <= 0 || plaintext_length < 0) {
|
||||
DEBUG_LOG("Invalid nonce/plaintext length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assoc_length = info->length;
|
||||
ciphertext_length = SIV_GetTagLength(siv) + plaintext_length;
|
||||
nonce_padding = get_padding_length(nonce_length);
|
||||
ciphertext_padding = get_padding_length(ciphertext_length);
|
||||
min_ef_length = get_padded_length(min_ef_length);
|
||||
|
||||
auth_length = sizeof (*header) + nonce_length + nonce_padding +
|
||||
ciphertext_length + ciphertext_padding;
|
||||
additional_padding = MAX(min_ef_length - auth_length - 4, 0);
|
||||
additional_padding = MAX(NTS_MIN_UNPADDED_NONCE_LENGTH - nonce_length - nonce_padding,
|
||||
additional_padding);
|
||||
auth_length += additional_padding;
|
||||
|
||||
if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_AUTH_AND_EEF, auth_length,
|
||||
(void **)&header)) {
|
||||
DEBUG_LOG("Could not add EF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
header->nonce_length = htons(nonce_length);
|
||||
header->ciphertext_length = htons(ciphertext_length);
|
||||
|
||||
body = (unsigned char *)(header + 1);
|
||||
ciphertext = body + nonce_length + nonce_padding;
|
||||
|
||||
memcpy(body, nonce, nonce_length);
|
||||
memset(body + nonce_length, 0, nonce_padding);
|
||||
|
||||
if (!SIV_Encrypt(siv, nonce, nonce_length, packet, assoc_length,
|
||||
plaintext, plaintext_length, ciphertext, ciphertext_length)) {
|
||||
DEBUG_LOG("SIV encrypt failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(ciphertext + ciphertext_length, 0, ciphertext_padding + additional_padding);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ================================================== */
|
||||
|
||||
int
|
||||
NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, int ef_start,
|
||||
unsigned char *plaintext, int buffer_length, int *plaintext_length)
|
||||
{
|
||||
unsigned int siv_tag_length, nonce_length, ciphertext_length;
|
||||
unsigned char *nonce, *ciphertext;
|
||||
int ef_type, ef_body_length;
|
||||
void *ef_body;
|
||||
struct AuthHeader *header;
|
||||
|
||||
if (!NEF_ParseField(packet, info->length, ef_start,
|
||||
NULL, &ef_type, &ef_body, &ef_body_length))
|
||||
return 0;
|
||||
|
||||
if (ef_type != NTP_EF_NTS_AUTH_AND_EEF)
|
||||
return 0;
|
||||
|
||||
header = ef_body;
|
||||
|
||||
nonce_length = ntohs(header->nonce_length);
|
||||
ciphertext_length = ntohs(header->ciphertext_length);
|
||||
|
||||
if (get_padded_length(nonce_length) +
|
||||
get_padded_length(ciphertext_length) > ef_body_length)
|
||||
return 0;
|
||||
|
||||
nonce = (unsigned char *)(header + 1);
|
||||
ciphertext = (unsigned char *)(header + 1) + get_padded_length(nonce_length);
|
||||
|
||||
siv_tag_length = SIV_GetTagLength(siv);
|
||||
|
||||
if (nonce_length < 1 ||
|
||||
ciphertext_length < siv_tag_length ||
|
||||
ciphertext_length - siv_tag_length > buffer_length) {
|
||||
DEBUG_LOG("Unexpected nonce/ciphertext length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ef_body_length < sizeof (*header) +
|
||||
NTS_MIN_UNPADDED_NONCE_LENGTH + get_padded_length(ciphertext_length)) {
|
||||
DEBUG_LOG("Missing padding");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*plaintext_length = ciphertext_length - siv_tag_length;
|
||||
|
||||
if (!SIV_Decrypt(siv, nonce, nonce_length, packet, info->length - ef_body_length - 4,
|
||||
ciphertext, ciphertext_length, plaintext, *plaintext_length)) {
|
||||
DEBUG_LOG("SIV decrypt failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user