]> git.ipfire.org Git - thirdparty/chrony.git/blob - siv_gnutls.c
ntp: add server support for KoD RATE
[thirdparty/chrony.git] / siv_gnutls.c
1 /*
2 chronyd/chronyc - Programs for keeping computer clocks accurate.
3
4 **********************************************************************
5 * Copyright (C) Miroslav Lichvar 2020, 2023
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 SIV ciphers using the GnuTLS library
25 */
26
27 #include "config.h"
28
29 #include "sysincl.h"
30
31 #include <gnutls/crypto.h>
32
33 #include "logging.h"
34 #include "memory.h"
35 #include "siv.h"
36
37 struct SIV_Instance_Record {
38 gnutls_cipher_algorithm_t algorithm;
39 gnutls_aead_cipher_hd_t cipher;
40 int min_nonce_length;
41 int max_nonce_length;
42 };
43
44 /* ================================================== */
45
46 static int instance_counter = 0;
47 static int gnutls_initialised = 0;
48
49 /* ================================================== */
50
51 static void
52 init_gnutls(void)
53 {
54 int r;
55
56 if (gnutls_initialised)
57 return;
58
59 r = gnutls_global_init();
60 if (r < 0)
61 LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
62
63 DEBUG_LOG("Initialised");
64 gnutls_initialised = 1;
65 }
66
67 /* ================================================== */
68
69 static void
70 deinit_gnutls(void)
71 {
72 assert(gnutls_initialised);
73 gnutls_global_deinit();
74 gnutls_initialised = 0;
75 DEBUG_LOG("Deinitialised");
76 }
77
78 /* ================================================== */
79
80 static gnutls_cipher_algorithm_t
81 get_cipher_algorithm(SIV_Algorithm algorithm)
82 {
83 switch (algorithm) {
84 case AEAD_AES_SIV_CMAC_256:
85 return GNUTLS_CIPHER_AES_128_SIV;
86 #if HAVE_GNUTLS_SIV_GCM
87 case AEAD_AES_128_GCM_SIV:
88 return GNUTLS_CIPHER_AES_128_SIV_GCM;
89 #endif
90 default:
91 return 0;
92 }
93 }
94
95 /* ================================================== */
96
97 SIV_Instance
98 SIV_CreateInstance(SIV_Algorithm algorithm)
99 {
100 gnutls_cipher_algorithm_t calgo;
101 SIV_Instance instance;
102
103 calgo = get_cipher_algorithm(algorithm);
104 if (calgo == 0)
105 return NULL;
106
107 if (instance_counter == 0)
108 init_gnutls();
109
110 /* Check if the cipher is actually supported */
111 if (gnutls_cipher_get_tag_size(calgo) == 0) {
112 if (instance_counter == 0)
113 deinit_gnutls();
114 return NULL;
115 }
116
117 instance = MallocNew(struct SIV_Instance_Record);
118 instance->algorithm = calgo;
119 instance->cipher = NULL;
120
121 switch (algorithm) {
122 case AEAD_AES_SIV_CMAC_256:
123 instance->min_nonce_length = 1;
124 instance->max_nonce_length = INT_MAX;
125 break;
126 case AEAD_AES_128_GCM_SIV:
127 instance->min_nonce_length = 12;
128 instance->max_nonce_length = 12;
129 break;
130 default:
131 assert(0);
132 }
133
134 instance_counter++;
135
136 return instance;
137 }
138
139 /* ================================================== */
140
141 void
142 SIV_DestroyInstance(SIV_Instance instance)
143 {
144 if (instance->cipher)
145 gnutls_aead_cipher_deinit(instance->cipher);
146 Free(instance);
147
148 instance_counter--;
149 if (instance_counter == 0)
150 deinit_gnutls();
151 }
152
153 /* ================================================== */
154
155 int
156 SIV_GetKeyLength(SIV_Algorithm algorithm)
157 {
158 gnutls_cipher_algorithm_t calgo = get_cipher_algorithm(algorithm);
159 int len;
160
161 if (calgo == 0)
162 return 0;
163
164 len = gnutls_cipher_get_key_size(calgo);
165 if (len == 0)
166 return 0;
167
168 if (len < 1 || len > SIV_MAX_KEY_LENGTH)
169 LOG_FATAL("Invalid key length");
170
171 return len;
172 }
173
174 /* ================================================== */
175
176 int
177 SIV_SetKey(SIV_Instance instance, const unsigned char *key, int length)
178 {
179 gnutls_aead_cipher_hd_t cipher;
180 gnutls_datum_t datum;
181 int r;
182
183 if (length <= 0 || length != gnutls_cipher_get_key_size(instance->algorithm))
184 return 0;
185
186 datum.data = (unsigned char *)key;
187 datum.size = length;
188
189 #ifdef HAVE_GNUTLS_AEAD_CIPHER_SET_KEY
190 if (instance->cipher) {
191 r = gnutls_aead_cipher_set_key(instance->cipher, &datum);
192 if (r < 0) {
193 DEBUG_LOG("Could not set cipher key : %s", gnutls_strerror(r));
194 return 0;
195 }
196
197 return 1;
198 }
199 #endif
200
201 /* Initialise a new cipher with the provided key */
202 r = gnutls_aead_cipher_init(&cipher, instance->algorithm, &datum);
203 if (r < 0) {
204 DEBUG_LOG("Could not initialise %s : %s", "cipher", gnutls_strerror(r));
205 return 0;
206 }
207
208 /* Destroy the previous cipher (if its key could not be changed directly) */
209 if (instance->cipher)
210 gnutls_aead_cipher_deinit(instance->cipher);
211
212 instance->cipher = cipher;
213
214 return 1;
215 }
216
217 /* ================================================== */
218
219 int
220 SIV_GetMinNonceLength(SIV_Instance instance)
221 {
222 return instance->min_nonce_length;
223 }
224
225 /* ================================================== */
226
227 int
228 SIV_GetMaxNonceLength(SIV_Instance instance)
229 {
230 return instance->max_nonce_length;
231 }
232
233 /* ================================================== */
234
235 int
236 SIV_GetTagLength(SIV_Instance instance)
237 {
238 int len;
239
240 len = gnutls_cipher_get_tag_size(instance->algorithm);
241
242 if (len < 1 || len > SIV_MAX_TAG_LENGTH)
243 LOG_FATAL("Invalid tag length");
244
245 return len;
246 }
247
248 /* ================================================== */
249
250 int
251 SIV_Encrypt(SIV_Instance instance,
252 const unsigned char *nonce, int nonce_length,
253 const void *assoc, int assoc_length,
254 const void *plaintext, int plaintext_length,
255 unsigned char *ciphertext, int ciphertext_length)
256 {
257 size_t clen = ciphertext_length;
258
259 if (!instance->cipher)
260 return 0;
261
262 if (nonce_length < instance->min_nonce_length ||
263 nonce_length > instance->max_nonce_length || assoc_length < 0 ||
264 plaintext_length < 0 || ciphertext_length < 0)
265 return 0;
266
267 assert(assoc && plaintext);
268
269 if (gnutls_aead_cipher_encrypt(instance->cipher,
270 nonce, nonce_length, assoc, assoc_length, 0,
271 plaintext, plaintext_length, ciphertext, &clen) < 0)
272 return 0;
273
274 if (clen != ciphertext_length)
275 return 0;
276
277 return 1;
278 }
279
280 /* ================================================== */
281
282 int
283 SIV_Decrypt(SIV_Instance instance,
284 const unsigned char *nonce, int nonce_length,
285 const void *assoc, int assoc_length,
286 const unsigned char *ciphertext, int ciphertext_length,
287 void *plaintext, int plaintext_length)
288 {
289 size_t plen = plaintext_length;
290
291 if (!instance->cipher)
292 return 0;
293
294 if (nonce_length < instance->min_nonce_length ||
295 nonce_length > instance->max_nonce_length || assoc_length < 0 ||
296 plaintext_length < 0 || ciphertext_length < 0)
297 return 0;
298
299 assert(assoc && plaintext);
300
301 if (gnutls_aead_cipher_decrypt(instance->cipher,
302 nonce, nonce_length, assoc, assoc_length, 0,
303 ciphertext, ciphertext_length, plaintext, &plen) < 0)
304 return 0;
305
306 if (plen != plaintext_length)
307 return 0;
308
309 return 1;
310 }