diff options
Diffstat (limited to 'src/gnsrecord/gnsrecord_crypto.c')
-rw-r--r-- | src/gnsrecord/gnsrecord_crypto.c | 997 |
1 files changed, 0 insertions, 997 deletions
diff --git a/src/gnsrecord/gnsrecord_crypto.c b/src/gnsrecord/gnsrecord_crypto.c deleted file mode 100644 index b5e8be82b..000000000 --- a/src/gnsrecord/gnsrecord_crypto.c +++ /dev/null | |||
@@ -1,997 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013, 2018 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file gnsrecord/gnsrecord_crypto.c | ||
23 | * @brief API for GNS record-related crypto | ||
24 | * @author Martin Schanzenbach | ||
25 | * @author Matthias Wachs | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "gnsrecord_crypto.h" | ||
29 | |||
30 | #define LOG(kind, ...) GNUNET_log_from (kind, "gnsrecord", __VA_ARGS__) | ||
31 | |||
32 | ssize_t | ||
33 | ecdsa_symmetric_decrypt ( | ||
34 | const void *block, | ||
35 | size_t size, | ||
36 | const unsigned char *key, | ||
37 | const unsigned char *ctr, | ||
38 | void *result) | ||
39 | { | ||
40 | gcry_cipher_hd_t handle; | ||
41 | int rc; | ||
42 | |||
43 | GNUNET_assert (0 == gcry_cipher_open (&handle, GCRY_CIPHER_AES256, | ||
44 | GCRY_CIPHER_MODE_CTR, 0)); | ||
45 | rc = gcry_cipher_setkey (handle, | ||
46 | key, | ||
47 | GNUNET_CRYPTO_AES_KEY_LENGTH); | ||
48 | GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); | ||
49 | rc = gcry_cipher_setctr (handle, | ||
50 | ctr, | ||
51 | GNUNET_CRYPTO_AES_KEY_LENGTH / 2); | ||
52 | GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); | ||
53 | GNUNET_assert (0 == gcry_cipher_decrypt (handle, result, size, block, size)); | ||
54 | gcry_cipher_close (handle); | ||
55 | return size; | ||
56 | } | ||
57 | |||
58 | |||
59 | ssize_t | ||
60 | ecdsa_symmetric_encrypt ( | ||
61 | const void *block, | ||
62 | size_t size, | ||
63 | const unsigned char *key, | ||
64 | const unsigned char *ctr, | ||
65 | void *result) | ||
66 | { | ||
67 | gcry_cipher_hd_t handle; | ||
68 | int rc; | ||
69 | |||
70 | GNUNET_assert (0 == gcry_cipher_open (&handle, GCRY_CIPHER_AES256, | ||
71 | GCRY_CIPHER_MODE_CTR, 0)); | ||
72 | rc = gcry_cipher_setkey (handle, | ||
73 | key, | ||
74 | GNUNET_CRYPTO_AES_KEY_LENGTH); | ||
75 | GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); | ||
76 | rc = gcry_cipher_setctr (handle, | ||
77 | ctr, | ||
78 | GNUNET_CRYPTO_AES_KEY_LENGTH / 2); | ||
79 | GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY)); | ||
80 | GNUNET_assert (0 == gcry_cipher_encrypt (handle, result, size, block, size)); | ||
81 | gcry_cipher_close (handle); | ||
82 | return size; | ||
83 | } | ||
84 | |||
85 | |||
86 | enum GNUNET_GenericReturnValue | ||
87 | eddsa_symmetric_decrypt ( | ||
88 | const void *block, | ||
89 | size_t size, | ||
90 | const unsigned char *key, | ||
91 | const unsigned char *nonce, | ||
92 | void *result) | ||
93 | { | ||
94 | ssize_t ctlen = size - crypto_secretbox_MACBYTES; | ||
95 | if (ctlen < 0) | ||
96 | return GNUNET_SYSERR; | ||
97 | if (0 != crypto_secretbox_open_detached (result, | ||
98 | ((unsigned char*) block) + crypto_secretbox_MACBYTES, // Ciphertext | ||
99 | block, // Tag | ||
100 | ctlen, | ||
101 | nonce, key)) | ||
102 | { | ||
103 | return GNUNET_SYSERR; | ||
104 | } | ||
105 | return GNUNET_OK; | ||
106 | } | ||
107 | |||
108 | |||
109 | enum GNUNET_GenericReturnValue | ||
110 | eddsa_symmetric_encrypt ( | ||
111 | const void *block, | ||
112 | size_t size, | ||
113 | const unsigned char *key, | ||
114 | const unsigned char *nonce, | ||
115 | void *result) | ||
116 | { | ||
117 | if (size > crypto_secretbox_MESSAGEBYTES_MAX) | ||
118 | return GNUNET_SYSERR; | ||
119 | crypto_secretbox_detached (result + crypto_secretbox_MACBYTES, // Ciphertext | ||
120 | result, // TAG | ||
121 | block, size, nonce, key); | ||
122 | return GNUNET_OK; | ||
123 | } | ||
124 | |||
125 | |||
126 | void | ||
127 | GNR_derive_block_aes_key (unsigned char *ctr, | ||
128 | unsigned char *key, | ||
129 | const char *label, | ||
130 | uint64_t exp, | ||
131 | const struct GNUNET_CRYPTO_EcdsaPublicKey *pub) | ||
132 | { | ||
133 | static const char ctx_key[] = "gns-aes-ctx-key"; | ||
134 | static const char ctx_iv[] = "gns-aes-ctx-iv"; | ||
135 | |||
136 | GNUNET_CRYPTO_kdf (key, GNUNET_CRYPTO_AES_KEY_LENGTH, | ||
137 | ctx_key, strlen (ctx_key), | ||
138 | pub, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey), | ||
139 | label, strlen (label), | ||
140 | NULL, 0); | ||
141 | memset (ctr, 0, GNUNET_CRYPTO_AES_KEY_LENGTH / 2); | ||
142 | /** 4 byte nonce **/ | ||
143 | GNUNET_CRYPTO_kdf (ctr, 4, | ||
144 | ctx_iv, strlen (ctx_iv), | ||
145 | pub, sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey), | ||
146 | label, strlen (label), | ||
147 | NULL, 0); | ||
148 | /** Expiration time 64 bit. **/ | ||
149 | memcpy (ctr + 4, &exp, sizeof (exp)); | ||
150 | /** Set counter part to 1 **/ | ||
151 | ctr[15] |= 0x01; | ||
152 | } | ||
153 | |||
154 | |||
155 | void | ||
156 | GNR_derive_block_xsalsa_key (unsigned char *nonce, | ||
157 | unsigned char *key, | ||
158 | const char *label, | ||
159 | uint64_t exp, | ||
160 | const struct GNUNET_CRYPTO_EddsaPublicKey *pub) | ||
161 | { | ||
162 | static const char ctx_key[] = "gns-xsalsa-ctx-key"; | ||
163 | static const char ctx_iv[] = "gns-xsalsa-ctx-iv"; | ||
164 | |||
165 | GNUNET_CRYPTO_kdf (key, crypto_secretbox_KEYBYTES, | ||
166 | ctx_key, strlen (ctx_key), | ||
167 | pub, sizeof(struct GNUNET_CRYPTO_EddsaPublicKey), | ||
168 | label, strlen (label), | ||
169 | NULL, 0); | ||
170 | memset (nonce, 0, crypto_secretbox_NONCEBYTES); | ||
171 | /** 16 byte nonce **/ | ||
172 | GNUNET_CRYPTO_kdf (nonce, (crypto_secretbox_NONCEBYTES - sizeof (exp)), | ||
173 | ctx_iv, strlen (ctx_iv), | ||
174 | pub, sizeof(struct GNUNET_CRYPTO_EddsaPublicKey), | ||
175 | label, strlen (label), | ||
176 | NULL, 0); | ||
177 | /** Expiration time 64 bit. **/ | ||
178 | memcpy (nonce + (crypto_secretbox_NONCEBYTES - sizeof (exp)), | ||
179 | &exp, sizeof (exp)); | ||
180 | } | ||
181 | |||
182 | |||
183 | static ssize_t | ||
184 | block_get_size_ecdsa (const struct GNUNET_GNSRECORD_Data *rd, | ||
185 | unsigned int rd_count) | ||
186 | { | ||
187 | ssize_t len; | ||
188 | |||
189 | len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | ||
190 | if (len < 0) | ||
191 | return -1; | ||
192 | len += sizeof(struct GNUNET_GNSRECORD_Block); | ||
193 | return len; | ||
194 | } | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Sign name and records | ||
199 | * | ||
200 | * @param key the private key | ||
201 | * @param pkey associated public key | ||
202 | * @param expire block expiration | ||
203 | * @param label the name for the records | ||
204 | * @param rd record data | ||
205 | * @param rd_count number of records | ||
206 | * @param block the block result. Must be allocated sufficiently. | ||
207 | * @return GNUNET_SYSERR on error (otherwise GNUNET_OK) | ||
208 | */ | ||
209 | static enum GNUNET_GenericReturnValue | ||
210 | block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, | ||
211 | const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey, | ||
212 | struct GNUNET_TIME_Absolute expire, | ||
213 | const char *label, | ||
214 | const struct GNUNET_GNSRECORD_Data *rd, | ||
215 | unsigned int rd_count, | ||
216 | struct GNUNET_GNSRECORD_Block **block) | ||
217 | { | ||
218 | ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, | ||
219 | rd); | ||
220 | struct GNUNET_GNSRECORD_EcdsaBlock *ecblock; | ||
221 | struct GNRBlockPS *gnr_block; | ||
222 | unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2]; | ||
223 | unsigned char skey[GNUNET_CRYPTO_AES_KEY_LENGTH]; | ||
224 | struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL (rd_count)]; | ||
225 | struct GNUNET_TIME_Absolute now; | ||
226 | |||
227 | if (payload_len < 0) | ||
228 | { | ||
229 | GNUNET_break (0); | ||
230 | return GNUNET_SYSERR; | ||
231 | } | ||
232 | if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE) | ||
233 | { | ||
234 | GNUNET_break (0); | ||
235 | return GNUNET_SYSERR; | ||
236 | } | ||
237 | /* convert relative to absolute times */ | ||
238 | now = GNUNET_TIME_absolute_get (); | ||
239 | for (unsigned int i = 0; i < rd_count; i++) | ||
240 | { | ||
241 | rdc[i] = rd[i]; | ||
242 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
243 | { | ||
244 | struct GNUNET_TIME_Relative t; | ||
245 | |||
246 | /* encrypted blocks must never have relative expiration times, convert! */ | ||
247 | rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | ||
248 | t.rel_value_us = rdc[i].expiration_time; | ||
249 | rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us; | ||
250 | } | ||
251 | } | ||
252 | /* serialize */ | ||
253 | *block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + payload_len); | ||
254 | (*block)->size = htonl(sizeof (struct GNUNET_GNSRECORD_Block) + payload_len); | ||
255 | { | ||
256 | char payload[payload_len]; | ||
257 | |||
258 | GNUNET_assert (payload_len == | ||
259 | GNUNET_GNSRECORD_records_serialize (rd_count, | ||
260 | rdc, | ||
261 | payload_len, | ||
262 | payload)); | ||
263 | gnr_block = GNUNET_malloc (sizeof (struct GNRBlockPS) + payload_len); | ||
264 | ecblock = &(*block)->ecdsa_block; | ||
265 | (*block)->type = htonl (GNUNET_GNSRECORD_TYPE_PKEY); | ||
266 | gnr_block->purpose.size = htonl (sizeof(struct GNRBlockPS) + payload_len); | ||
267 | gnr_block->purpose.purpose = | ||
268 | htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
269 | gnr_block->expiration_time = GNUNET_TIME_absolute_hton (expire); | ||
270 | ecblock->expiration_time = gnr_block->expiration_time; | ||
271 | /* encrypt and sign */ | ||
272 | GNUNET_CRYPTO_ecdsa_public_key_derive (pkey, | ||
273 | label, | ||
274 | "gns", | ||
275 | &ecblock->derived_key); | ||
276 | GNR_derive_block_aes_key (ctr, | ||
277 | skey, | ||
278 | label, | ||
279 | ecblock->expiration_time.abs_value_us__, | ||
280 | pkey); | ||
281 | GNUNET_assert (payload_len == | ||
282 | ecdsa_symmetric_encrypt (payload, | ||
283 | payload_len, | ||
284 | skey, | ||
285 | ctr, | ||
286 | &ecblock[1])); | ||
287 | GNUNET_memcpy (&gnr_block[1], &ecblock[1], payload_len); | ||
288 | } | ||
289 | if (GNUNET_OK != | ||
290 | GNUNET_CRYPTO_ecdsa_sign_derived (key, | ||
291 | label, | ||
292 | "gns", | ||
293 | &gnr_block->purpose, | ||
294 | &ecblock->signature)) | ||
295 | { | ||
296 | GNUNET_break (0); | ||
297 | GNUNET_free (*block); | ||
298 | GNUNET_free (gnr_block); | ||
299 | return GNUNET_SYSERR; | ||
300 | } | ||
301 | GNUNET_free (gnr_block); | ||
302 | return GNUNET_OK; | ||
303 | } | ||
304 | |||
305 | static ssize_t | ||
306 | block_get_size_eddsa (const struct GNUNET_GNSRECORD_Data *rd, | ||
307 | unsigned int rd_count) | ||
308 | { | ||
309 | ssize_t len; | ||
310 | |||
311 | len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); | ||
312 | if (len < 0) | ||
313 | return -1; | ||
314 | len += sizeof(struct GNUNET_GNSRECORD_Block); | ||
315 | len += crypto_secretbox_MACBYTES; | ||
316 | return len; | ||
317 | } | ||
318 | |||
319 | |||
320 | /** | ||
321 | * Sign name and records (EDDSA version) | ||
322 | * | ||
323 | * @param key the private key | ||
324 | * @param pkey associated public key | ||
325 | * @param expire block expiration | ||
326 | * @param label the name for the records | ||
327 | * @param rd record data | ||
328 | * @param rd_count number of records | ||
329 | * @param block where to store the block. Must be allocated sufficiently. | ||
330 | * @return GNUNET_SYSERR on error (otherwise GNUNET_OK) | ||
331 | */ | ||
332 | enum GNUNET_GenericReturnValue | ||
333 | block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key, | ||
334 | const struct GNUNET_CRYPTO_EddsaPublicKey *pkey, | ||
335 | struct GNUNET_TIME_Absolute expire, | ||
336 | const char *label, | ||
337 | const struct GNUNET_GNSRECORD_Data *rd, | ||
338 | unsigned int rd_count, | ||
339 | struct GNUNET_GNSRECORD_Block **block) | ||
340 | { | ||
341 | ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, | ||
342 | rd); | ||
343 | struct GNUNET_GNSRECORD_EddsaBlock *edblock; | ||
344 | struct GNRBlockPS *gnr_block; | ||
345 | unsigned char nonce[crypto_secretbox_NONCEBYTES]; | ||
346 | unsigned char skey[crypto_secretbox_KEYBYTES]; | ||
347 | struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL (rd_count)]; | ||
348 | struct GNUNET_TIME_Absolute now; | ||
349 | |||
350 | if (payload_len < 0) | ||
351 | { | ||
352 | GNUNET_break (0); | ||
353 | return GNUNET_SYSERR; | ||
354 | } | ||
355 | if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE) | ||
356 | { | ||
357 | GNUNET_break (0); | ||
358 | return GNUNET_SYSERR; | ||
359 | } | ||
360 | /* convert relative to absolute times */ | ||
361 | now = GNUNET_TIME_absolute_get (); | ||
362 | for (unsigned int i = 0; i < rd_count; i++) | ||
363 | { | ||
364 | rdc[i] = rd[i]; | ||
365 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
366 | { | ||
367 | struct GNUNET_TIME_Relative t; | ||
368 | |||
369 | /* encrypted blocks must never have relative expiration times, convert! */ | ||
370 | rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | ||
371 | t.rel_value_us = rdc[i].expiration_time; | ||
372 | rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us; | ||
373 | } | ||
374 | } | ||
375 | /* serialize */ | ||
376 | *block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) | ||
377 | + payload_len + crypto_secretbox_MACBYTES); | ||
378 | (*block)->size = htonl(sizeof (struct GNUNET_GNSRECORD_Block) | ||
379 | + payload_len + crypto_secretbox_MACBYTES); | ||
380 | { | ||
381 | char payload[payload_len]; | ||
382 | |||
383 | GNUNET_assert (payload_len == | ||
384 | GNUNET_GNSRECORD_records_serialize (rd_count, | ||
385 | rdc, | ||
386 | payload_len, | ||
387 | payload)); | ||
388 | gnr_block = GNUNET_malloc (sizeof (struct GNRBlockPS) | ||
389 | + payload_len | ||
390 | + crypto_secretbox_MACBYTES); | ||
391 | edblock = &(*block)->eddsa_block; | ||
392 | (*block)->type = htonl (GNUNET_GNSRECORD_TYPE_EDKEY); | ||
393 | gnr_block->purpose.size = | ||
394 | htonl (sizeof(struct GNRBlockPS) | ||
395 | + payload_len | ||
396 | + crypto_secretbox_MACBYTES); | ||
397 | gnr_block->purpose.purpose = | ||
398 | htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
399 | gnr_block->expiration_time = GNUNET_TIME_absolute_hton (expire); | ||
400 | edblock->expiration_time = gnr_block->expiration_time; | ||
401 | /* encrypt and sign */ | ||
402 | GNUNET_CRYPTO_eddsa_public_key_derive (pkey, | ||
403 | label, | ||
404 | "gns", | ||
405 | &edblock->derived_key); | ||
406 | GNR_derive_block_xsalsa_key (nonce, | ||
407 | skey, | ||
408 | label, | ||
409 | edblock->expiration_time.abs_value_us__, | ||
410 | pkey); | ||
411 | GNUNET_assert (GNUNET_OK == | ||
412 | eddsa_symmetric_encrypt (payload, | ||
413 | payload_len, | ||
414 | skey, | ||
415 | nonce, | ||
416 | &edblock[1])); | ||
417 | GNUNET_memcpy (&gnr_block[1], &edblock[1], | ||
418 | payload_len + crypto_secretbox_MACBYTES); | ||
419 | |||
420 | GNUNET_CRYPTO_eddsa_sign_derived (key, | ||
421 | label, | ||
422 | "gns", | ||
423 | &gnr_block->purpose, | ||
424 | &edblock->signature); | ||
425 | } | ||
426 | return GNUNET_OK; | ||
427 | } | ||
428 | |||
429 | ssize_t | ||
430 | GNUNET_GNSRECORD_block_calculate_size (const struct | ||
431 | GNUNET_IDENTITY_PrivateKey *key, | ||
432 | const struct GNUNET_GNSRECORD_Data *rd, | ||
433 | unsigned int rd_count) | ||
434 | { | ||
435 | struct GNUNET_IDENTITY_PublicKey pkey; | ||
436 | ssize_t res = -1; | ||
437 | |||
438 | GNUNET_IDENTITY_key_get_public (key, | ||
439 | &pkey); | ||
440 | switch (ntohl (key->type)) | ||
441 | { | ||
442 | case GNUNET_GNSRECORD_TYPE_PKEY: | ||
443 | res = block_get_size_ecdsa (rd, rd_count); | ||
444 | break; | ||
445 | case GNUNET_GNSRECORD_TYPE_EDKEY: | ||
446 | res = block_get_size_eddsa (rd, rd_count); | ||
447 | break; | ||
448 | default: | ||
449 | GNUNET_assert (0); | ||
450 | } | ||
451 | return res; | ||
452 | |||
453 | } | ||
454 | |||
455 | enum GNUNET_GenericReturnValue | ||
456 | GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key, | ||
457 | struct GNUNET_TIME_Absolute expire, | ||
458 | const char *label, | ||
459 | const struct GNUNET_GNSRECORD_Data *rd, | ||
460 | unsigned int rd_count, | ||
461 | struct GNUNET_GNSRECORD_Block **result) | ||
462 | { | ||
463 | struct GNUNET_IDENTITY_PublicKey pkey; | ||
464 | enum GNUNET_GenericReturnValue res = GNUNET_SYSERR; | ||
465 | char *norm_label; | ||
466 | |||
467 | GNUNET_IDENTITY_key_get_public (key, | ||
468 | &pkey); | ||
469 | norm_label = GNUNET_GNSRECORD_string_normalize (label); | ||
470 | |||
471 | switch (ntohl (key->type)) | ||
472 | { | ||
473 | case GNUNET_GNSRECORD_TYPE_PKEY: | ||
474 | res = block_create_ecdsa (&key->ecdsa_key, | ||
475 | &pkey.ecdsa_key, | ||
476 | expire, | ||
477 | norm_label, | ||
478 | rd, | ||
479 | rd_count, | ||
480 | result); | ||
481 | break; | ||
482 | case GNUNET_GNSRECORD_TYPE_EDKEY: | ||
483 | res = block_create_eddsa (&key->eddsa_key, | ||
484 | &pkey.eddsa_key, | ||
485 | expire, | ||
486 | norm_label, | ||
487 | rd, | ||
488 | rd_count, | ||
489 | result); | ||
490 | break; | ||
491 | default: | ||
492 | GNUNET_assert (0); | ||
493 | } | ||
494 | GNUNET_free (norm_label); | ||
495 | return res; | ||
496 | } | ||
497 | |||
498 | |||
499 | /** | ||
500 | * Line in cache mapping private keys to public keys. | ||
501 | */ | ||
502 | struct KeyCacheLine | ||
503 | { | ||
504 | /** | ||
505 | * A private key. | ||
506 | */ | ||
507 | struct GNUNET_CRYPTO_EcdsaPrivateKey key; | ||
508 | |||
509 | /** | ||
510 | * Associated public key. | ||
511 | */ | ||
512 | struct GNUNET_CRYPTO_EcdsaPublicKey pkey; | ||
513 | }; | ||
514 | |||
515 | |||
516 | enum GNUNET_GenericReturnValue | ||
517 | GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey, | ||
518 | struct GNUNET_TIME_Absolute expire, | ||
519 | const char *label, | ||
520 | const struct GNUNET_GNSRECORD_Data *rd, | ||
521 | unsigned int rd_count, | ||
522 | struct GNUNET_GNSRECORD_Block **result) | ||
523 | { | ||
524 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *key; | ||
525 | struct GNUNET_CRYPTO_EddsaPublicKey edpubkey; | ||
526 | enum GNUNET_GenericReturnValue res = GNUNET_SYSERR; | ||
527 | char *norm_label; | ||
528 | |||
529 | norm_label = GNUNET_GNSRECORD_string_normalize (label); | ||
530 | |||
531 | if (GNUNET_IDENTITY_TYPE_ECDSA == ntohl (pkey->type)) | ||
532 | { | ||
533 | key = &pkey->ecdsa_key; | ||
534 | #define CSIZE 64 | ||
535 | static struct KeyCacheLine cache[CSIZE]; | ||
536 | struct KeyCacheLine *line; | ||
537 | |||
538 | line = &cache[(*(unsigned int *) key) % CSIZE]; | ||
539 | if (0 != memcmp (&line->key, | ||
540 | key, | ||
541 | sizeof(*key))) | ||
542 | { | ||
543 | /* cache miss, recompute */ | ||
544 | line->key = *key; | ||
545 | GNUNET_CRYPTO_ecdsa_key_get_public (key, | ||
546 | &line->pkey); | ||
547 | } | ||
548 | #undef CSIZE | ||
549 | res = block_create_ecdsa (key, | ||
550 | &line->pkey, | ||
551 | expire, | ||
552 | norm_label, | ||
553 | rd, | ||
554 | rd_count, | ||
555 | result); | ||
556 | } | ||
557 | else if (GNUNET_IDENTITY_TYPE_EDDSA == ntohl (pkey->type)) | ||
558 | { | ||
559 | GNUNET_CRYPTO_eddsa_key_get_public (&pkey->eddsa_key, | ||
560 | &edpubkey); | ||
561 | res = block_create_eddsa (&pkey->eddsa_key, | ||
562 | &edpubkey, | ||
563 | expire, | ||
564 | norm_label, | ||
565 | rd, | ||
566 | rd_count, | ||
567 | result); | ||
568 | } | ||
569 | GNUNET_free (norm_label); | ||
570 | return res; | ||
571 | } | ||
572 | |||
573 | |||
574 | /** | ||
575 | * Check if a signature is valid. This API is used by the GNS Block | ||
576 | * to validate signatures received from the network. | ||
577 | * | ||
578 | * @param block block to verify | ||
579 | * @return #GNUNET_OK if the signature is valid | ||
580 | */ | ||
581 | enum GNUNET_GenericReturnValue | ||
582 | GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block) | ||
583 | { | ||
584 | struct GNRBlockPS *purp; | ||
585 | size_t payload_len = ntohl (block->size) | ||
586 | - sizeof (struct GNUNET_GNSRECORD_Block); | ||
587 | enum GNUNET_GenericReturnValue res = GNUNET_NO; | ||
588 | purp = GNUNET_malloc (sizeof (struct GNRBlockPS) + payload_len); | ||
589 | purp->purpose.size = htonl (sizeof (struct GNRBlockPS) + payload_len); | ||
590 | purp->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
591 | GNUNET_memcpy (&purp[1], | ||
592 | &block[1], | ||
593 | payload_len); | ||
594 | switch (ntohl (block->type)) | ||
595 | { | ||
596 | case GNUNET_GNSRECORD_TYPE_PKEY: | ||
597 | purp->expiration_time = block->ecdsa_block.expiration_time; | ||
598 | res = GNUNET_CRYPTO_ecdsa_verify_ ( | ||
599 | GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, | ||
600 | &purp->purpose, | ||
601 | &block->ecdsa_block.signature, | ||
602 | &block->ecdsa_block.derived_key); | ||
603 | break; | ||
604 | case GNUNET_GNSRECORD_TYPE_EDKEY: | ||
605 | purp->expiration_time = block->eddsa_block.expiration_time; | ||
606 | res = GNUNET_CRYPTO_eddsa_verify_ ( | ||
607 | GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, | ||
608 | &purp->purpose, | ||
609 | &block->eddsa_block.signature, | ||
610 | &block->eddsa_block.derived_key); | ||
611 | break; | ||
612 | default: | ||
613 | res = GNUNET_NO; | ||
614 | } | ||
615 | GNUNET_free (purp); | ||
616 | return res; | ||
617 | } | ||
618 | |||
619 | |||
620 | enum GNUNET_GenericReturnValue | ||
621 | block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_Block *block, | ||
622 | const struct | ||
623 | GNUNET_CRYPTO_EcdsaPublicKey *zone_key, | ||
624 | const char *label, | ||
625 | GNUNET_GNSRECORD_RecordCallback proc, | ||
626 | void *proc_cls) | ||
627 | { | ||
628 | size_t payload_len = ntohl (block->size) - sizeof (struct | ||
629 | GNUNET_GNSRECORD_Block); | ||
630 | unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2]; | ||
631 | unsigned char key[GNUNET_CRYPTO_AES_KEY_LENGTH]; | ||
632 | |||
633 | if (ntohl (block->size) < | ||
634 | sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) | ||
635 | + sizeof(struct GNUNET_TIME_AbsoluteNBO)) | ||
636 | { | ||
637 | GNUNET_break_op (0); | ||
638 | return GNUNET_SYSERR; | ||
639 | } | ||
640 | GNR_derive_block_aes_key (ctr, | ||
641 | key, | ||
642 | label, | ||
643 | block->ecdsa_block.expiration_time.abs_value_us__, | ||
644 | zone_key); | ||
645 | { | ||
646 | char payload[payload_len]; | ||
647 | unsigned int rd_count; | ||
648 | |||
649 | GNUNET_assert (payload_len == | ||
650 | ecdsa_symmetric_decrypt (&block[1], payload_len, | ||
651 | key, ctr, | ||
652 | payload)); | ||
653 | rd_count = GNUNET_GNSRECORD_records_deserialize_get_size (payload_len, | ||
654 | payload); | ||
655 | if (rd_count > 2048) | ||
656 | { | ||
657 | /* limit to sane value */ | ||
658 | GNUNET_break_op (0); | ||
659 | return GNUNET_SYSERR; | ||
660 | } | ||
661 | { | ||
662 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | ||
663 | unsigned int j; | ||
664 | struct GNUNET_TIME_Absolute now; | ||
665 | |||
666 | if (GNUNET_OK != | ||
667 | GNUNET_GNSRECORD_records_deserialize (payload_len, | ||
668 | payload, | ||
669 | rd_count, | ||
670 | rd)) | ||
671 | { | ||
672 | GNUNET_break_op (0); | ||
673 | return GNUNET_SYSERR; | ||
674 | } | ||
675 | /* hide expired records */ | ||
676 | now = GNUNET_TIME_absolute_get (); | ||
677 | j = 0; | ||
678 | for (unsigned int i = 0; i < rd_count; i++) | ||
679 | { | ||
680 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
681 | { | ||
682 | /* encrypted blocks must never have relative expiration times, skip! */ | ||
683 | GNUNET_break_op (0); | ||
684 | continue; | ||
685 | } | ||
686 | |||
687 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) | ||
688 | { | ||
689 | int include_record = GNUNET_YES; | ||
690 | /* Shadow record, figure out if we have a not expired active record */ | ||
691 | for (unsigned int k = 0; k < rd_count; k++) | ||
692 | { | ||
693 | if (k == i) | ||
694 | continue; | ||
695 | if (rd[i].expiration_time < now.abs_value_us) | ||
696 | include_record = GNUNET_NO; /* Shadow record is expired */ | ||
697 | if ((rd[k].record_type == rd[i].record_type) && | ||
698 | (rd[k].expiration_time >= now.abs_value_us) && | ||
699 | (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))) | ||
700 | { | ||
701 | include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */ | ||
702 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
703 | "Ignoring shadow record\n"); | ||
704 | break; | ||
705 | } | ||
706 | } | ||
707 | if (GNUNET_YES == include_record) | ||
708 | { | ||
709 | rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */ | ||
710 | if (j != i) | ||
711 | rd[j] = rd[i]; | ||
712 | j++; | ||
713 | } | ||
714 | } | ||
715 | else if (rd[i].expiration_time >= now.abs_value_us) | ||
716 | { | ||
717 | /* Include this record */ | ||
718 | if (j != i) | ||
719 | rd[j] = rd[i]; | ||
720 | j++; | ||
721 | } | ||
722 | else | ||
723 | { | ||
724 | struct GNUNET_TIME_Absolute at; | ||
725 | |||
726 | at.abs_value_us = rd[i].expiration_time; | ||
727 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
728 | "Excluding record that expired %s (%llu ago)\n", | ||
729 | GNUNET_STRINGS_absolute_time_to_string (at), | ||
730 | (unsigned long long) rd[i].expiration_time | ||
731 | - now.abs_value_us); | ||
732 | } | ||
733 | } | ||
734 | rd_count = j; | ||
735 | if (NULL != proc) | ||
736 | proc (proc_cls, | ||
737 | rd_count, | ||
738 | (0 != rd_count) ? rd : NULL); | ||
739 | } | ||
740 | } | ||
741 | return GNUNET_OK; | ||
742 | } | ||
743 | |||
744 | |||
745 | enum GNUNET_GenericReturnValue | ||
746 | block_decrypt_eddsa (const struct GNUNET_GNSRECORD_Block *block, | ||
747 | const struct | ||
748 | GNUNET_CRYPTO_EddsaPublicKey *zone_key, | ||
749 | const char *label, | ||
750 | GNUNET_GNSRECORD_RecordCallback proc, | ||
751 | void *proc_cls) | ||
752 | { | ||
753 | size_t payload_len = ntohl (block->size) - sizeof (struct | ||
754 | GNUNET_GNSRECORD_Block); | ||
755 | unsigned char nonce[crypto_secretbox_NONCEBYTES]; | ||
756 | unsigned char key[crypto_secretbox_KEYBYTES]; | ||
757 | |||
758 | if (ntohl (block->size) < | ||
759 | sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) | ||
760 | + sizeof(struct GNUNET_TIME_AbsoluteNBO)) | ||
761 | { | ||
762 | GNUNET_break_op (0); | ||
763 | return GNUNET_SYSERR; | ||
764 | } | ||
765 | GNR_derive_block_xsalsa_key (nonce, | ||
766 | key, | ||
767 | label, | ||
768 | block->eddsa_block.expiration_time.abs_value_us__, | ||
769 | zone_key); | ||
770 | { | ||
771 | char payload[payload_len]; | ||
772 | unsigned int rd_count; | ||
773 | |||
774 | GNUNET_assert (GNUNET_OK == | ||
775 | eddsa_symmetric_decrypt (&block[1], payload_len, | ||
776 | key, nonce, | ||
777 | payload)); | ||
778 | payload_len -= crypto_secretbox_MACBYTES; | ||
779 | rd_count = GNUNET_GNSRECORD_records_deserialize_get_size (payload_len, | ||
780 | payload); | ||
781 | if (rd_count > 2048) | ||
782 | { | ||
783 | /* limit to sane value */ | ||
784 | GNUNET_break_op (0); | ||
785 | return GNUNET_SYSERR; | ||
786 | } | ||
787 | { | ||
788 | struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL (rd_count)]; | ||
789 | unsigned int j; | ||
790 | struct GNUNET_TIME_Absolute now; | ||
791 | |||
792 | if (GNUNET_OK != | ||
793 | GNUNET_GNSRECORD_records_deserialize (payload_len, | ||
794 | payload, | ||
795 | rd_count, | ||
796 | rd)) | ||
797 | { | ||
798 | GNUNET_break_op (0); | ||
799 | return GNUNET_SYSERR; | ||
800 | } | ||
801 | /* hide expired records */ | ||
802 | now = GNUNET_TIME_absolute_get (); | ||
803 | j = 0; | ||
804 | for (unsigned int i = 0; i < rd_count; i++) | ||
805 | { | ||
806 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) | ||
807 | { | ||
808 | /* encrypted blocks must never have relative expiration times, skip! */ | ||
809 | GNUNET_break_op (0); | ||
810 | continue; | ||
811 | } | ||
812 | |||
813 | if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) | ||
814 | { | ||
815 | int include_record = GNUNET_YES; | ||
816 | /* Shadow record, figure out if we have a not expired active record */ | ||
817 | for (unsigned int k = 0; k < rd_count; k++) | ||
818 | { | ||
819 | if (k == i) | ||
820 | continue; | ||
821 | if (rd[i].expiration_time < now.abs_value_us) | ||
822 | include_record = GNUNET_NO; /* Shadow record is expired */ | ||
823 | if ((rd[k].record_type == rd[i].record_type) && | ||
824 | (rd[k].expiration_time >= now.abs_value_us) && | ||
825 | (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))) | ||
826 | { | ||
827 | include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */ | ||
828 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
829 | "Ignoring shadow record\n"); | ||
830 | break; | ||
831 | } | ||
832 | } | ||
833 | if (GNUNET_YES == include_record) | ||
834 | { | ||
835 | rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */ | ||
836 | if (j != i) | ||
837 | rd[j] = rd[i]; | ||
838 | j++; | ||
839 | } | ||
840 | } | ||
841 | else if (rd[i].expiration_time >= now.abs_value_us) | ||
842 | { | ||
843 | /* Include this record */ | ||
844 | if (j != i) | ||
845 | rd[j] = rd[i]; | ||
846 | j++; | ||
847 | } | ||
848 | else | ||
849 | { | ||
850 | struct GNUNET_TIME_Absolute at; | ||
851 | |||
852 | at.abs_value_us = rd[i].expiration_time; | ||
853 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
854 | "Excluding record that expired %s (%llu ago)\n", | ||
855 | GNUNET_STRINGS_absolute_time_to_string (at), | ||
856 | (unsigned long long) rd[i].expiration_time | ||
857 | - now.abs_value_us); | ||
858 | } | ||
859 | } | ||
860 | rd_count = j; | ||
861 | if (NULL != proc) | ||
862 | proc (proc_cls, | ||
863 | rd_count, | ||
864 | (0 != rd_count) ? rd : NULL); | ||
865 | } | ||
866 | } | ||
867 | return GNUNET_OK; | ||
868 | } | ||
869 | |||
870 | |||
871 | /** | ||
872 | * Decrypt block. | ||
873 | * | ||
874 | * @param block block to decrypt | ||
875 | * @param zone_key public key of the zone | ||
876 | * @param label the name for the records | ||
877 | * @param proc function to call with the result | ||
878 | * @param proc_cls closure for proc | ||
879 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was | ||
880 | * not well-formed | ||
881 | */ | ||
882 | enum GNUNET_GenericReturnValue | ||
883 | GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block, | ||
884 | const struct | ||
885 | GNUNET_IDENTITY_PublicKey *zone_key, | ||
886 | const char *label, | ||
887 | GNUNET_GNSRECORD_RecordCallback proc, | ||
888 | void *proc_cls) | ||
889 | { | ||
890 | enum GNUNET_GenericReturnValue res = GNUNET_SYSERR; | ||
891 | char *norm_label; | ||
892 | |||
893 | norm_label = GNUNET_GNSRECORD_string_normalize (label); | ||
894 | switch (ntohl (zone_key->type)) | ||
895 | { | ||
896 | case GNUNET_IDENTITY_TYPE_ECDSA: | ||
897 | res = block_decrypt_ecdsa (block, | ||
898 | &zone_key->ecdsa_key, norm_label, proc, | ||
899 | proc_cls); | ||
900 | break; | ||
901 | case GNUNET_IDENTITY_TYPE_EDDSA: | ||
902 | res = block_decrypt_eddsa (block, | ||
903 | &zone_key->eddsa_key, norm_label, proc, | ||
904 | proc_cls); | ||
905 | break; | ||
906 | default: | ||
907 | res = GNUNET_SYSERR; | ||
908 | } | ||
909 | GNUNET_free (norm_label); | ||
910 | return res; | ||
911 | } | ||
912 | |||
913 | |||
914 | /** | ||
915 | * Calculate the DHT query for a given @a label in a given @a zone. | ||
916 | * | ||
917 | * @param zone private key of the zone | ||
918 | * @param label label of the record | ||
919 | * @param query hash to use for the query | ||
920 | */ | ||
921 | void | ||
922 | GNUNET_GNSRECORD_query_from_private_key (const struct | ||
923 | GNUNET_IDENTITY_PrivateKey *zone, | ||
924 | const char *label, | ||
925 | struct GNUNET_HashCode *query) | ||
926 | { | ||
927 | char *norm_label; | ||
928 | struct GNUNET_IDENTITY_PublicKey pub; | ||
929 | |||
930 | norm_label = GNUNET_GNSRECORD_string_normalize (label); | ||
931 | switch (ntohl (zone->type)) | ||
932 | { | ||
933 | case GNUNET_GNSRECORD_TYPE_PKEY: | ||
934 | case GNUNET_GNSRECORD_TYPE_EDKEY: | ||
935 | |||
936 | GNUNET_IDENTITY_key_get_public (zone, | ||
937 | &pub); | ||
938 | GNUNET_GNSRECORD_query_from_public_key (&pub, | ||
939 | norm_label, | ||
940 | query); | ||
941 | break; | ||
942 | default: | ||
943 | GNUNET_assert (0); | ||
944 | } | ||
945 | GNUNET_free (norm_label); | ||
946 | } | ||
947 | |||
948 | |||
949 | /** | ||
950 | * Calculate the DHT query for a given @a label in a given @a zone. | ||
951 | * FIXME: We may want to plugin-ize this at some point. | ||
952 | * | ||
953 | * @param pub public key of the zone | ||
954 | * @param label label of the record | ||
955 | * @param query hash to use for the query | ||
956 | */ | ||
957 | void | ||
958 | GNUNET_GNSRECORD_query_from_public_key (const struct | ||
959 | GNUNET_IDENTITY_PublicKey *pub, | ||
960 | const char *label, | ||
961 | struct GNUNET_HashCode *query) | ||
962 | { | ||
963 | char *norm_label; | ||
964 | struct GNUNET_IDENTITY_PublicKey pd; | ||
965 | |||
966 | norm_label = GNUNET_GNSRECORD_string_normalize (label); | ||
967 | |||
968 | switch (ntohl (pub->type)) | ||
969 | { | ||
970 | case GNUNET_GNSRECORD_TYPE_PKEY: | ||
971 | pd.type = pub->type; | ||
972 | GNUNET_CRYPTO_ecdsa_public_key_derive (&pub->ecdsa_key, | ||
973 | norm_label, | ||
974 | "gns", | ||
975 | &pd.ecdsa_key); | ||
976 | GNUNET_CRYPTO_hash (&pd.ecdsa_key, | ||
977 | sizeof (pd.ecdsa_key), | ||
978 | query); | ||
979 | break; | ||
980 | case GNUNET_GNSRECORD_TYPE_EDKEY: | ||
981 | pd.type = pub->type; | ||
982 | GNUNET_CRYPTO_eddsa_public_key_derive (&pub->eddsa_key, | ||
983 | norm_label, | ||
984 | "gns", | ||
985 | &(pd.eddsa_key)); | ||
986 | GNUNET_CRYPTO_hash (&pd.eddsa_key, | ||
987 | sizeof (pd.eddsa_key), | ||
988 | query); | ||
989 | break; | ||
990 | default: | ||
991 | GNUNET_assert (0); | ||
992 | } | ||
993 | GNUNET_free (norm_label); | ||
994 | } | ||
995 | |||
996 | |||
997 | /* end of gnsrecord_crypto.c */ | ||