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