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