]> git.ipfire.org Git - thirdparty/chrony.git/blob - nts_ntp_auth.c
cmdmon: save NTS cookies and server keys on dump command
[thirdparty/chrony.git] / nts_ntp_auth.c
1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2020
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 **********************************************************************
21
22 =======================================================================
23
24 NTS Authenticator and Encrypted Extension Fields extension field
25 */
26
27 #include "config.h"
28
29 #include "sysincl.h"
30
31 #include "nts_ntp_auth.h"
32
33 #include "logging.h"
34 #include "ntp_ext.h"
35 #include "nts_ntp.h"
36 #include "siv.h"
37 #include "util.h"
38
39 struct AuthHeader {
40 uint16_t nonce_length;
41 uint16_t ciphertext_length;
42 };
43
44 /* ================================================== */
45
46 static int
47 get_padding_length(int length)
48 {
49 return length % 4U ? 4 - length % 4U : 0;
50 }
51
52 /* ================================================== */
53
54 static int
55 get_padded_length(int length)
56 {
57 return length + get_padding_length(length);
58 }
59
60 /* ================================================== */
61
62 int
63 NNA_GenerateAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv,
64 const unsigned char *nonce, int nonce_length,
65 const unsigned char *plaintext, int plaintext_length,
66 int min_ef_length)
67 {
68 int auth_length, ciphertext_length, assoc_length;
69 int nonce_padding, ciphertext_padding, additional_padding;
70 unsigned char *ciphertext, *body;
71 struct AuthHeader *header;
72
73 assert(sizeof (*header) == 4);
74
75 if (nonce_length <= 0 || plaintext_length < 0) {
76 DEBUG_LOG("Invalid nonce/plaintext length");
77 return 0;
78 }
79
80 assoc_length = info->length;
81 ciphertext_length = SIV_GetTagLength(siv) + plaintext_length;
82 nonce_padding = get_padding_length(nonce_length);
83 ciphertext_padding = get_padding_length(ciphertext_length);
84 min_ef_length = get_padded_length(min_ef_length);
85
86 auth_length = sizeof (*header) + nonce_length + nonce_padding +
87 ciphertext_length + ciphertext_padding;
88 additional_padding = MAX(min_ef_length - auth_length - 4, 0);
89 additional_padding = MAX(NTS_MIN_UNPADDED_NONCE_LENGTH - nonce_length - nonce_padding,
90 additional_padding);
91 auth_length += additional_padding;
92
93 if (!NEF_AddBlankField(packet, info, NTP_EF_NTS_AUTH_AND_EEF, auth_length,
94 (void **)&header)) {
95 DEBUG_LOG("Could not add EF");
96 return 0;
97 }
98
99 header->nonce_length = htons(nonce_length);
100 header->ciphertext_length = htons(ciphertext_length);
101
102 body = (unsigned char *)(header + 1);
103 ciphertext = body + nonce_length + nonce_padding;
104
105 memcpy(body, nonce, nonce_length);
106 memset(body + nonce_length, 0, nonce_padding);
107
108 if (!SIV_Encrypt(siv, nonce, nonce_length, packet, assoc_length,
109 plaintext, plaintext_length, ciphertext, ciphertext_length)) {
110 DEBUG_LOG("SIV encrypt failed");
111 return 0;
112 }
113
114 memset(ciphertext + ciphertext_length, 0, ciphertext_padding + additional_padding);
115
116 return 1;
117 }
118
119 /* ================================================== */
120
121 int
122 NNA_DecryptAuthEF(NTP_Packet *packet, NTP_PacketInfo *info, SIV_Instance siv, int ef_start,
123 unsigned char *plaintext, int buffer_length, int *plaintext_length)
124 {
125 unsigned int siv_tag_length, nonce_length, ciphertext_length;
126 unsigned char *nonce, *ciphertext;
127 int ef_type, ef_body_length;
128 void *ef_body;
129 struct AuthHeader *header;
130
131 if (!NEF_ParseField(packet, info->length, ef_start,
132 NULL, &ef_type, &ef_body, &ef_body_length))
133 return 0;
134
135 if (ef_type != NTP_EF_NTS_AUTH_AND_EEF)
136 return 0;
137
138 header = ef_body;
139
140 nonce_length = ntohs(header->nonce_length);
141 ciphertext_length = ntohs(header->ciphertext_length);
142
143 if (get_padded_length(nonce_length) +
144 get_padded_length(ciphertext_length) > ef_body_length)
145 return 0;
146
147 nonce = (unsigned char *)(header + 1);
148 ciphertext = (unsigned char *)(header + 1) + get_padded_length(nonce_length);
149
150 siv_tag_length = SIV_GetTagLength(siv);
151
152 if (nonce_length < 1 ||
153 ciphertext_length < siv_tag_length ||
154 ciphertext_length - siv_tag_length > buffer_length) {
155 DEBUG_LOG("Unexpected nonce/ciphertext length");
156 return 0;
157 }
158
159 if (ef_body_length < sizeof (*header) +
160 NTS_MIN_UNPADDED_NONCE_LENGTH + get_padded_length(ciphertext_length)) {
161 DEBUG_LOG("Missing padding");
162 return 0;
163 }
164
165 *plaintext_length = ciphertext_length - siv_tag_length;
166
167 if (!SIV_Decrypt(siv, nonce, nonce_length, packet, info->length - ef_body_length - 4,
168 ciphertext, ciphertext_length, plaintext, *plaintext_length)) {
169 DEBUG_LOG("SIV decrypt failed");
170 return 0;
171 }
172
173 return 1;
174 }