diff options
-rw-r--r-- | src/include/gnunet_crypto_lib.h | 1 | ||||
-rw-r--r-- | src/namestore/namestore_api_common.c | 242 |
2 files changed, 125 insertions, 118 deletions
diff --git a/src/include/gnunet_crypto_lib.h b/src/include/gnunet_crypto_lib.h index 96bbdc214..4d4455af4 100644 --- a/src/include/gnunet_crypto_lib.h +++ b/src/include/gnunet_crypto_lib.h | |||
@@ -727,6 +727,7 @@ GNUNET_CRYPTO_hmac_derive_key (struct GNUNET_CRYPTO_AuthKey *key, | |||
727 | const struct GNUNET_CRYPTO_AesSessionKey *rkey, | 727 | const struct GNUNET_CRYPTO_AesSessionKey *rkey, |
728 | const void *salt, size_t salt_len, ...); | 728 | const void *salt, size_t salt_len, ...); |
729 | 729 | ||
730 | |||
730 | /** | 731 | /** |
731 | * @brief Derive key | 732 | * @brief Derive key |
732 | * @param result buffer for the derived key, allocated by caller | 733 | * @param result buffer for the derived key, allocated by caller |
diff --git a/src/namestore/namestore_api_common.c b/src/namestore/namestore_api_common.c index bfab39384..397a649aa 100644 --- a/src/namestore/namestore_api_common.c +++ b/src/namestore/namestore_api_common.c | |||
@@ -314,6 +314,36 @@ GNUNET_NAMESTORE_record_get_expiration_time (unsigned int rd_count, | |||
314 | 314 | ||
315 | 315 | ||
316 | /** | 316 | /** |
317 | * Derive session key and iv from label and public key. | ||
318 | * | ||
319 | * @param iv initialization vector to initialize | ||
320 | * @param skey session key to initialize | ||
321 | * @param label label to use for KDF | ||
322 | * @param pub public key to use for KDF | ||
323 | */ | ||
324 | static void | ||
325 | derive_block_aes_key (struct GNUNET_CRYPTO_AesInitializationVector *iv, | ||
326 | struct GNUNET_CRYPTO_AesSessionKey *skey, | ||
327 | const char *label, | ||
328 | const struct GNUNET_CRYPTO_EccPublicKey *pub) | ||
329 | { | ||
330 | static const char ctx_key[] = "gns-aes-ctx-key"; | ||
331 | static const char ctx_iv[] = "gns-aes-ctx-iv"; | ||
332 | |||
333 | GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_AesSessionKey), | ||
334 | pub, sizeof (struct GNUNET_CRYPTO_EccPublicKey), | ||
335 | label, strlen (label), | ||
336 | ctx_key, strlen (ctx_key), | ||
337 | NULL, 0); | ||
338 | GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_AesInitializationVector), | ||
339 | pub, sizeof (struct GNUNET_CRYPTO_EccPublicKey), | ||
340 | label, strlen (label), | ||
341 | ctx_iv, strlen (ctx_iv), | ||
342 | NULL, 0); | ||
343 | } | ||
344 | |||
345 | |||
346 | /** | ||
317 | * Sign name and records | 347 | * Sign name and records |
318 | * | 348 | * |
319 | * @param key the private key | 349 | * @param key the private key |
@@ -321,6 +351,7 @@ GNUNET_NAMESTORE_record_get_expiration_time (unsigned int rd_count, | |||
321 | * @param label the name for the records | 351 | * @param label the name for the records |
322 | * @param rd record data | 352 | * @param rd record data |
323 | * @param rd_count number of records | 353 | * @param rd_count number of records |
354 | * @return NULL on error (block too large) | ||
324 | */ | 355 | */ |
325 | struct GNUNET_NAMESTORE_Block * | 356 | struct GNUNET_NAMESTORE_Block * |
326 | GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EccPrivateKey *key, | 357 | GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EccPrivateKey *key, |
@@ -329,8 +360,51 @@ GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EccPrivateKey *key, | |||
329 | const struct GNUNET_NAMESTORE_RecordData *rd, | 360 | const struct GNUNET_NAMESTORE_RecordData *rd, |
330 | unsigned int rd_count) | 361 | unsigned int rd_count) |
331 | { | 362 | { |
332 | GNUNET_break (0); | 363 | size_t payload_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); |
333 | return NULL; | 364 | char payload[sizeof (uint32_t) + payload_len]; |
365 | struct GNUNET_NAMESTORE_Block *block; | ||
366 | struct GNUNET_CRYPTO_EccPublicKey pkey; | ||
367 | struct GNUNET_CRYPTO_EccPrivateKey *dkey; | ||
368 | struct GNUNET_CRYPTO_AesInitializationVector iv; | ||
369 | struct GNUNET_CRYPTO_AesSessionKey skey; | ||
370 | uint32_t rd_count_nbo; | ||
371 | |||
372 | if (payload_len > GNUNET_NAMESTORE_MAX_VALUE_SIZE) | ||
373 | return NULL; | ||
374 | rd_count_nbo = htonl (rd_count); | ||
375 | memcpy (payload, &rd_count_nbo, sizeof (uint32_t)); | ||
376 | GNUNET_assert (payload_len == | ||
377 | GNUNET_NAMESTORE_records_serialize (rd_count, rd, | ||
378 | payload_len, &payload[sizeof (uint32_t)])); | ||
379 | block = GNUNET_malloc (sizeof (struct GNUNET_NAMESTORE_Block) + | ||
380 | sizeof (uint32_t) + payload_len); | ||
381 | block->purpose.size = htonl (sizeof (uint32_t) + payload_len + | ||
382 | sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + | ||
383 | sizeof (struct GNUNET_TIME_AbsoluteNBO)); | ||
384 | block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
385 | block->expiration_time = GNUNET_TIME_absolute_hton (expire); | ||
386 | dkey = GNUNET_CRYPTO_ecc_key_derive (key, | ||
387 | label, | ||
388 | "gns"); | ||
389 | GNUNET_CRYPTO_ecc_key_get_public (dkey, | ||
390 | &block->derived_key); | ||
391 | GNUNET_CRYPTO_ecc_key_get_public (key, | ||
392 | &pkey); | ||
393 | derive_block_aes_key (&iv, &skey, label, &pkey); | ||
394 | GNUNET_break (payload_len + sizeof (uint32_t) == | ||
395 | GNUNET_CRYPTO_aes_encrypt (payload, payload_len + sizeof (uint32_t), | ||
396 | &skey, &iv, | ||
397 | &block[1])); | ||
398 | if (GNUNET_OK != | ||
399 | GNUNET_CRYPTO_ecc_sign (dkey, | ||
400 | &block->purpose, | ||
401 | &block->signature)) | ||
402 | { | ||
403 | GNUNET_break (0); | ||
404 | GNUNET_free (block); | ||
405 | return NULL; | ||
406 | } | ||
407 | return block; | ||
334 | } | 408 | } |
335 | 409 | ||
336 | 410 | ||
@@ -343,9 +417,11 @@ GNUNET_NAMESTORE_block_create (const struct GNUNET_CRYPTO_EccPrivateKey *key, | |||
343 | */ | 417 | */ |
344 | int | 418 | int |
345 | GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block) | 419 | GNUNET_NAMESTORE_block_verify (const struct GNUNET_NAMESTORE_Block *block) |
346 | { | 420 | { |
347 | GNUNET_break (0); | 421 | return GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, |
348 | return GNUNET_SYSERR; | 422 | &block->purpose, |
423 | &block->signature, | ||
424 | &block->derived_key); | ||
349 | } | 425 | } |
350 | 426 | ||
351 | 427 | ||
@@ -367,125 +443,55 @@ GNUNET_NAMESTORE_block_decrypt (const struct GNUNET_NAMESTORE_Block *block, | |||
367 | GNUNET_NAMESTORE_RecordCallback proc, | 443 | GNUNET_NAMESTORE_RecordCallback proc, |
368 | void *proc_cls) | 444 | void *proc_cls) |
369 | { | 445 | { |
370 | GNUNET_break (0); | 446 | size_t payload_len = ntohl (block->purpose.size) - |
371 | return GNUNET_SYSERR; | 447 | sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) - |
372 | } | 448 | sizeof (struct GNUNET_TIME_AbsoluteNBO); |
373 | 449 | struct GNUNET_CRYPTO_AesInitializationVector iv; | |
374 | 450 | struct GNUNET_CRYPTO_AesSessionKey skey; | |
375 | #if OLD | 451 | |
376 | /** | 452 | if (ntohl (block->purpose.size) < |
377 | * Sign name and records | 453 | sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) - |
378 | * | 454 | sizeof (struct GNUNET_TIME_AbsoluteNBO)) |
379 | * @param key the private key | ||
380 | * @param expire block expiration | ||
381 | * @param name the name | ||
382 | * @param rd record data | ||
383 | * @param rd_count number of records | ||
384 | * @param signature where to store the signature | ||
385 | */ | ||
386 | void | ||
387 | GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_EccPrivateKey *key, | ||
388 | struct GNUNET_TIME_Absolute expire, | ||
389 | const char *name, | ||
390 | const struct GNUNET_NAMESTORE_RecordData *rd, | ||
391 | unsigned int rd_count, | ||
392 | struct GNUNET_CRYPTO_EccSignature *signature) | ||
393 | |||
394 | { | ||
395 | struct GNUNET_CRYPTO_EccPrivateKey *dkey; | ||
396 | struct GNUNET_CRYPTO_EccSignaturePurpose *sig_purpose; | ||
397 | struct GNUNET_TIME_AbsoluteNBO expire_nbo; | ||
398 | size_t rd_ser_len; | ||
399 | size_t name_len; | ||
400 | struct GNUNET_TIME_AbsoluteNBO *expire_tmp; | ||
401 | char * name_tmp; | ||
402 | char * rd_tmp; | ||
403 | int res; | ||
404 | uint32_t sig_len; | ||
405 | |||
406 | dkey = GNUNET_CRYPTO_ecc_key_derive (key, name, "gns"); | ||
407 | name_len = strlen (name) + 1; | ||
408 | expire_nbo = GNUNET_TIME_absolute_hton (expire); | ||
409 | rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); | ||
410 | { | ||
411 | char rd_ser[rd_ser_len]; | ||
412 | |||
413 | GNUNET_assert (rd_ser_len == | ||
414 | GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); | ||
415 | sig_len = sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len; | ||
416 | sig_purpose = GNUNET_malloc (sig_len); | ||
417 | sig_purpose->size = htonl (sig_len); | ||
418 | sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
419 | expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; | ||
420 | memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); | ||
421 | name_tmp = (char *) &expire_tmp[1]; | ||
422 | memcpy (name_tmp, name, name_len); | ||
423 | rd_tmp = &name_tmp[name_len]; | ||
424 | memcpy (rd_tmp, rd_ser, rd_ser_len); | ||
425 | GNUNET_assert (GNUNET_OK == | ||
426 | GNUNET_CRYPTO_ecc_sign (dkey, sig_purpose, signature)); | ||
427 | GNUNET_free (sig_purpose); | ||
428 | } | ||
429 | GNUNET_CRYPTO_ecc_key_free (dkey); | ||
430 | } | ||
431 | |||
432 | |||
433 | /** | ||
434 | * Check if a signature is valid. This API is used by the GNS Block | ||
435 | * to validate signatures received from the network. | ||
436 | * | ||
437 | * @param derived_key derived key of the zone and the label | ||
438 | * @param freshness time set for block expiration | ||
439 | * @param rd_count number of entries in 'rd' array | ||
440 | * @param rd array of records with data to store | ||
441 | * @param signature signature for all the records in the zone under the given name | ||
442 | * @return GNUNET_OK if the signature is valid | ||
443 | */ | ||
444 | int | ||
445 | GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_EccPublicKey *derived_key, | ||
446 | const struct GNUNET_TIME_Absolute freshness, | ||
447 | unsigned int rd_count, | ||
448 | const struct GNUNET_NAMESTORE_RecordData *rd, | ||
449 | const struct GNUNET_CRYPTO_EccSignature *signature) | ||
450 | { | ||
451 | size_t rd_ser_len; | ||
452 | size_t name_len; | ||
453 | char *name_tmp; | ||
454 | char *rd_ser; | ||
455 | struct GNUNET_CRYPTO_EccSignaturePurpose *sig_purpose; | ||
456 | struct GNUNET_TIME_AbsoluteNBO *expire_tmp; | ||
457 | struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton (freshness); | ||
458 | uint32_t sig_len; | ||
459 | |||
460 | GNUNET_assert (NULL != public_key); | ||
461 | GNUNET_assert (NULL != name); | ||
462 | GNUNET_assert (NULL != rd); | ||
463 | GNUNET_assert (NULL != signature); | ||
464 | name_len = strlen (name) + 1; | ||
465 | if (name_len > MAX_NAME_LEN) | ||
466 | { | 455 | { |
467 | GNUNET_break (0); | 456 | GNUNET_break_op (0); |
468 | return GNUNET_SYSERR; | 457 | return GNUNET_SYSERR; |
469 | } | 458 | } |
470 | rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); | 459 | derive_block_aes_key (&iv, &skey, label, zone_key); |
471 | sig_len = sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len; | ||
472 | { | 460 | { |
473 | char sig_buf[sig_len] GNUNET_ALIGN; | 461 | char payload[payload_len]; |
474 | 462 | uint32_t rd_count; | |
475 | sig_purpose = (struct GNUNET_CRYPTO_EccSignaturePurpose *) sig_buf; | 463 | |
476 | sig_purpose->size = htonl (sig_len); | 464 | GNUNET_break (payload_len == |
477 | sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | 465 | GNUNET_CRYPTO_aes_decrypt (&block[1], payload_len, |
478 | expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; | 466 | &skey, &iv, |
479 | memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); | 467 | payload)); |
480 | name_tmp = (char *) &expire_tmp[1]; | 468 | memcpy (&rd_count, |
481 | memcpy (name_tmp, name, name_len); | 469 | payload, |
482 | rd_ser = &name_tmp[name_len]; | 470 | sizeof (uint32_t)); |
483 | GNUNET_assert (rd_ser_len == | 471 | rd_count = ntohl (rd_count); |
484 | GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); | 472 | if (rd_count > 2048) |
485 | return GNUNET_CRYPTO_ecc_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, sig_purpose, signature, public_key); | 473 | { |
474 | /* limit to sane value */ | ||
475 | GNUNET_break_op (0); | ||
476 | return GNUNET_SYSERR; | ||
477 | } | ||
478 | { | ||
479 | struct GNUNET_NAMESTORE_RecordData rd[rd_count]; | ||
480 | |||
481 | if (GNUNET_OK != | ||
482 | GNUNET_NAMESTORE_records_deserialize (payload_len - sizeof (uint32_t), | ||
483 | &payload[sizeof (uint32_t)], | ||
484 | rd_count, | ||
485 | rd)) | ||
486 | { | ||
487 | GNUNET_break_op (0); | ||
488 | return GNUNET_SYSERR; | ||
489 | } | ||
490 | proc (proc_cls, rd_count, rd); | ||
491 | } | ||
486 | } | 492 | } |
493 | return GNUNET_OK; | ||
487 | } | 494 | } |
488 | #endif | ||
489 | 495 | ||
490 | 496 | ||
491 | /** | 497 | /** |