From 112ef3796314122465f23215233d8b7dd7a15a0b Mon Sep 17 00:00:00 2001 From: Martin Schanzenbach Date: Thu, 3 Feb 2022 09:25:12 +0100 Subject: GNS: Rework GNS block wire format --- src/gnsrecord/gnsrecord_crypto.c | 311 ++++++++++++++++++-------------- src/gnsrecord/gnsrecord_crypto.h | 20 ++ src/gnsrecord/gnsrecord_misc.c | 19 +- src/gnsrecord/gnsrecord_serialization.c | 56 +++++- src/gnsrecord/gnunet-gnsrecord-tvg.c | 82 ++++----- src/gnsrecord/test_gnsrecord_crypto.c | 12 +- src/include/gnunet_gnsrecord_lib.h | 76 +++++--- 7 files changed, 337 insertions(+), 239 deletions(-) diff --git a/src/gnsrecord/gnsrecord_crypto.c b/src/gnsrecord/gnsrecord_crypto.c index 24f4c48ca..890ddb011 100644 --- a/src/gnsrecord/gnsrecord_crypto.c +++ b/src/gnsrecord/gnsrecord_crypto.c @@ -95,8 +95,8 @@ eddsa_symmetric_decrypt ( if (ctlen < 0) return GNUNET_SYSERR; if (0 != crypto_secretbox_open_detached (result, - block, // Ciphertext - ((unsigned char*) block) + ctlen, // TAG + ((unsigned char*) block) + crypto_secretbox_MACBYTES, // Ciphertext + block, // Tag ctlen, nonce, key)) { @@ -116,8 +116,8 @@ eddsa_symmetric_encrypt ( { if (size > crypto_secretbox_MESSAGEBYTES_MAX) return GNUNET_SYSERR; - crypto_secretbox_detached (result, // Ciphertext - result + size, // TAG + crypto_secretbox_detached (result + crypto_secretbox_MACBYTES, // Ciphertext + result, // TAG block, size, nonce, key); return GNUNET_OK; } @@ -180,6 +180,20 @@ GNR_derive_block_xsalsa_key (unsigned char *nonce, } +static ssize_t +block_get_size_ecdsa (const struct GNUNET_GNSRECORD_Data *rd, + unsigned int rd_count) +{ + ssize_t len; + + len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); + if (len < 0) + return -1; + len += sizeof(struct GNUNET_GNSRECORD_Block); + return len; +} + + /** * Sign name and records * @@ -189,20 +203,22 @@ GNR_derive_block_xsalsa_key (unsigned char *nonce, * @param label the name for the records * @param rd record data * @param rd_count number of records - * @return NULL on error (block too large) + * @param block the block result. Must be allocated sufficiently. + * @return GNUNET_SYSERR on error (otherwise GNUNET_OK) */ -static struct GNUNET_GNSRECORD_Block * +static enum GNUNET_GenericReturnValue block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count) + unsigned int rd_count, + struct GNUNET_GNSRECORD_Block **block) { ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); - struct GNUNET_GNSRECORD_Block *block; struct GNUNET_GNSRECORD_EcdsaBlock *ecblock; + struct GNRBlockPS *gnr_block; struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey; unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2]; unsigned char skey[GNUNET_CRYPTO_AES_KEY_LENGTH]; @@ -213,12 +229,12 @@ block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, if (payload_len < 0) { GNUNET_break (0); - return NULL; + return GNUNET_SYSERR; } if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE) { GNUNET_break (0); - return NULL; + return GNUNET_SYSERR; } /* convert relative to absolute times */ now = GNUNET_TIME_absolute_get (); @@ -236,31 +252,25 @@ block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, } } /* serialize */ + *block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + payload_len); + (*block)->size = htonl(sizeof (struct GNUNET_GNSRECORD_Block) + payload_len); rd_count_nbo = htonl (rd_count); { - char payload[sizeof(uint32_t) + payload_len]; + char payload[payload_len]; - GNUNET_memcpy (payload, - &rd_count_nbo, - sizeof(uint32_t)); GNUNET_assert (payload_len == GNUNET_GNSRECORD_records_serialize (rd_count, rdc, payload_len, - &payload[sizeof(uint32_t) - ])); - block = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Block) - + sizeof(uint32_t) - + payload_len); - ecblock = &block->ecdsa_block; - block->type = htonl (GNUNET_GNSRECORD_TYPE_PKEY); - ecblock->purpose.size = htonl (sizeof(uint32_t) - + payload_len - + sizeof(struct - GNUNET_CRYPTO_EccSignaturePurpose) - + sizeof(struct GNUNET_TIME_AbsoluteNBO)); - ecblock->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); - ecblock->expiration_time = GNUNET_TIME_absolute_hton (expire); + payload)); + gnr_block = GNUNET_malloc (sizeof (struct GNRBlockPS) + payload_len); + ecblock = &(*block)->ecdsa_block; + (*block)->type = htonl (GNUNET_GNSRECORD_TYPE_PKEY); + gnr_block->purpose.size = htonl (sizeof(struct GNRBlockPS) + payload_len); + gnr_block->purpose.purpose = + htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); + gnr_block->expiration_time = GNUNET_TIME_absolute_hton (expire); + ecblock->expiration_time = gnr_block->expiration_time; /* encrypt and sign */ dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key, label, @@ -272,26 +282,40 @@ block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, label, ecblock->expiration_time.abs_value_us__, pkey); - GNUNET_break (payload_len + sizeof(uint32_t) == + GNUNET_break (payload_len == ecdsa_symmetric_encrypt (payload, - payload_len - + sizeof(uint32_t), + payload_len, skey, ctr, &ecblock[1])); + GNUNET_memcpy (&gnr_block[1], &ecblock[1], payload_len); } if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign_ (dkey, - &ecblock->purpose, + &gnr_block->purpose, &ecblock->signature)) { GNUNET_break (0); + GNUNET_free (*block); GNUNET_free (dkey); - GNUNET_free (block); - return NULL; + return GNUNET_SYSERR; } GNUNET_free (dkey); - return block; + return GNUNET_OK; +} + +static ssize_t +block_get_size_eddsa (const struct GNUNET_GNSRECORD_Data *rd, + unsigned int rd_count) +{ + ssize_t len; + + len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); + if (len < 0) + return -1; + len += sizeof(struct GNUNET_GNSRECORD_Block); + len += crypto_secretbox_MACBYTES; + return len; } @@ -304,20 +328,22 @@ block_create_ecdsa (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key, * @param label the name for the records * @param rd record data * @param rd_count number of records - * @return NULL on error (block too large) + * @param block where to store the block. Must be allocated sufficiently. + * @return GNUNET_SYSERR on error (otherwise GNUNET_OK) */ -static struct GNUNET_GNSRECORD_Block * +enum GNUNET_GenericReturnValue block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key, const struct GNUNET_CRYPTO_EddsaPublicKey *pkey, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count) + unsigned int rd_count, + struct GNUNET_GNSRECORD_Block **block) { ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd); - struct GNUNET_GNSRECORD_Block *block; struct GNUNET_GNSRECORD_EddsaBlock *edblock; + struct GNRBlockPS *gnr_block; struct GNUNET_CRYPTO_EddsaPrivateScalar dkey; unsigned char nonce[crypto_secretbox_NONCEBYTES]; unsigned char skey[crypto_secretbox_KEYBYTES]; @@ -328,12 +354,12 @@ block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key, if (payload_len < 0) { GNUNET_break (0); - return NULL; + return GNUNET_SYSERR; } if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE) { GNUNET_break (0); - return NULL; + return GNUNET_SYSERR; } /* convert relative to absolute times */ now = GNUNET_TIME_absolute_get (); @@ -351,33 +377,32 @@ block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key, } } /* serialize */ + *block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + + payload_len + crypto_secretbox_MACBYTES); + (*block)->size = htonl(sizeof (struct GNUNET_GNSRECORD_Block) + + payload_len + crypto_secretbox_MACBYTES); rd_count_nbo = htonl (rd_count); { - char payload[sizeof(uint32_t) + payload_len]; + char payload[payload_len]; - GNUNET_memcpy (payload, - &rd_count_nbo, - sizeof(uint32_t)); GNUNET_assert (payload_len == GNUNET_GNSRECORD_records_serialize (rd_count, rdc, payload_len, - &payload[sizeof(uint32_t) - ])); - block = GNUNET_malloc (sizeof(struct GNUNET_GNSRECORD_Block) - + sizeof(uint32_t) - + payload_len - + crypto_secretbox_MACBYTES); - edblock = &block->eddsa_block; - block->type = htonl (GNUNET_GNSRECORD_TYPE_EDKEY); - edblock->purpose.size = htonl (sizeof(uint32_t) - + payload_len - + sizeof(struct - GNUNET_CRYPTO_EccSignaturePurpose) - + sizeof(struct GNUNET_TIME_AbsoluteNBO) - + crypto_secretbox_MACBYTES); - edblock->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); - edblock->expiration_time = GNUNET_TIME_absolute_hton (expire); + payload)); + gnr_block = GNUNET_malloc (sizeof (struct GNRBlockPS) + + payload_len + + crypto_secretbox_MACBYTES); + edblock = &(*block)->eddsa_block; + (*block)->type = htonl (GNUNET_GNSRECORD_TYPE_EDKEY); + gnr_block->purpose.size = + htonl (sizeof(struct GNRBlockPS) + + payload_len + + crypto_secretbox_MACBYTES); + gnr_block->purpose.purpose = + htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); + gnr_block->expiration_time = GNUNET_TIME_absolute_hton (expire); + edblock->expiration_time = gnr_block->expiration_time; /* encrypt and sign */ GNUNET_CRYPTO_eddsa_private_key_derive (key, label, @@ -392,38 +417,56 @@ block_create_eddsa (const struct GNUNET_CRYPTO_EddsaPrivateKey *key, pkey); GNUNET_break (GNUNET_OK == eddsa_symmetric_encrypt (payload, - payload_len - + sizeof(uint32_t), + payload_len, skey, nonce, &edblock[1])); + GNUNET_memcpy (&gnr_block[1], &edblock[1], + payload_len + crypto_secretbox_MACBYTES); + + GNUNET_CRYPTO_eddsa_sign_with_scalar (&dkey, + &gnr_block->purpose, + &edblock->signature); } - GNUNET_CRYPTO_eddsa_sign_with_scalar (&dkey, - &edblock->purpose, - &edblock->signature); - return block; + return GNUNET_OK; } +ssize_t +GNUNET_GNSRECORD_block_calculate_size (const struct + GNUNET_IDENTITY_PrivateKey *key, + const struct GNUNET_GNSRECORD_Data *rd, + unsigned int rd_count) +{ + struct GNUNET_IDENTITY_PublicKey pkey; + ssize_t res; -/** - * Sign name and records - * - * @param key the private key - * @param expire block expiration - * @param label the name for the records - * @param rd record data - * @param rd_count number of records - * @return NULL on error (block too large) - */ -struct GNUNET_GNSRECORD_Block * + GNUNET_IDENTITY_key_get_public (key, + &pkey); + switch (ntohl (key->type)) + { + case GNUNET_GNSRECORD_TYPE_PKEY: + res = block_get_size_ecdsa (rd, rd_count); + break; + case GNUNET_GNSRECORD_TYPE_EDKEY: + res = block_get_size_eddsa (rd, rd_count); + break; + default: + GNUNET_assert (0); + } + return -1; + +} + +enum GNUNET_GenericReturnValue GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count) + unsigned int rd_count, + struct GNUNET_GNSRECORD_Block **result) { struct GNUNET_IDENTITY_PublicKey pkey; - struct GNUNET_GNSRECORD_Block *res = NULL; + enum GNUNET_GenericReturnValue res = GNUNET_SYSERR; char *norm_label; GNUNET_IDENTITY_key_get_public (key, @@ -438,7 +481,8 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key, expire, norm_label, rd, - rd_count); + rd_count, + result); break; case GNUNET_GNSRECORD_TYPE_EDKEY: res = block_create_eddsa (&key->eddsa_key, @@ -446,7 +490,8 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key, expire, norm_label, rd, - rd_count); + rd_count, + result); break; default: GNUNET_assert (0); @@ -473,28 +518,17 @@ struct KeyCacheLine }; -/** - * Sign name and records, cache derived public key (also keeps the - * private key in static memory, so do not use this function if - * keeping the private key in the process'es RAM is a major issue). - * - * @param key the private key - * @param expire block expiration - * @param label the name for the records - * @param rd record data - * @param rd_count number of records - * @return NULL on error (block too large) - */ -struct GNUNET_GNSRECORD_Block * +enum GNUNET_GenericReturnValue GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count) + unsigned int rd_count, + struct GNUNET_GNSRECORD_Block **result) { const struct GNUNET_CRYPTO_EcdsaPrivateKey *key; struct GNUNET_CRYPTO_EddsaPublicKey edpubkey; - struct GNUNET_GNSRECORD_Block *res = NULL; + enum GNUNET_GenericReturnValue res = GNUNET_SYSERR; char *norm_label; norm_label = GNUNET_GNSRECORD_string_normalize (label); @@ -522,7 +556,8 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey, expire, norm_label, rd, - rd_count); + rd_count, + result); } else if (GNUNET_IDENTITY_TYPE_EDDSA == ntohl (pkey->type)) { @@ -533,7 +568,8 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey, expire, norm_label, rd, - rd_count); + rd_count, + result); } GNUNET_free (norm_label); return res; @@ -550,41 +586,55 @@ GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *pkey, enum GNUNET_GenericReturnValue GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block) { + struct GNRBlockPS *purp; + size_t payload_len = ntohl (block->size) + - sizeof (struct GNUNET_GNSRECORD_Block); + enum GNUNET_GenericReturnValue res = GNUNET_NO; + purp = GNUNET_malloc (sizeof (struct GNRBlockPS) + payload_len); + purp->purpose.size = htonl (sizeof (struct GNRBlockPS) + payload_len); + purp->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); + GNUNET_memcpy (&purp[1], &block[1], payload_len); + switch (ntohl (block->type)) { case GNUNET_GNSRECORD_TYPE_PKEY: - return GNUNET_CRYPTO_ecdsa_verify_ ( + purp->expiration_time = block->ecdsa_block.expiration_time; + res = GNUNET_CRYPTO_ecdsa_verify_ ( GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, - &block->ecdsa_block.purpose, + &purp->purpose, &block->ecdsa_block.signature, &block->ecdsa_block.derived_key); + break; case GNUNET_GNSRECORD_TYPE_EDKEY: - return GNUNET_CRYPTO_eddsa_verify_ ( + purp->expiration_time = block->eddsa_block.expiration_time; + res = GNUNET_CRYPTO_eddsa_verify_ ( GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, - &block->eddsa_block.purpose, + &purp->purpose, &block->eddsa_block.signature, &block->eddsa_block.derived_key); + break; default: - return GNUNET_NO; + res = GNUNET_NO; } + GNUNET_free (purp); + return res; } enum GNUNET_GenericReturnValue -block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_EcdsaBlock *block, +block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_Block *block, const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key, const char *label, GNUNET_GNSRECORD_RecordCallback proc, void *proc_cls) { - size_t payload_len = ntohl (block->purpose.size) - - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - - sizeof(struct GNUNET_TIME_AbsoluteNBO); + size_t payload_len = ntohl (block->size) - sizeof (struct + GNUNET_GNSRECORD_Block); unsigned char ctr[GNUNET_CRYPTO_AES_KEY_LENGTH / 2]; unsigned char key[GNUNET_CRYPTO_AES_KEY_LENGTH]; - if (ntohl (block->purpose.size) < + if (ntohl (block->size) < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof(struct GNUNET_TIME_AbsoluteNBO)) { @@ -594,20 +644,18 @@ block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_EcdsaBlock *block, GNR_derive_block_aes_key (ctr, key, label, - block->expiration_time.abs_value_us__, + block->ecdsa_block.expiration_time.abs_value_us__, zone_key); { char payload[payload_len]; - uint32_t rd_count; + unsigned int rd_count; GNUNET_break (payload_len == ecdsa_symmetric_decrypt (&block[1], payload_len, key, ctr, payload)); - GNUNET_memcpy (&rd_count, - payload, - sizeof(uint32_t)); - rd_count = ntohl (rd_count); + rd_count = GNUNET_GNSRECORD_records_deserialize_get_size (payload_len, + payload); if (rd_count > 2048) { /* limit to sane value */ @@ -620,8 +668,8 @@ block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_EcdsaBlock *block, struct GNUNET_TIME_Absolute now; if (GNUNET_OK != - GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof(uint32_t), - &payload[sizeof(uint32_t)], + GNUNET_GNSRECORD_records_deserialize (payload_len, + payload, rd_count, rd)) { @@ -699,20 +747,20 @@ block_decrypt_ecdsa (const struct GNUNET_GNSRECORD_EcdsaBlock *block, enum GNUNET_GenericReturnValue -block_decrypt_eddsa (const struct GNUNET_GNSRECORD_EddsaBlock *block, +block_decrypt_eddsa (const struct GNUNET_GNSRECORD_Block *block, const struct GNUNET_CRYPTO_EddsaPublicKey *zone_key, const char *label, GNUNET_GNSRECORD_RecordCallback proc, void *proc_cls) { - size_t payload_len = ntohl (block->purpose.size) - - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - - sizeof(struct GNUNET_TIME_AbsoluteNBO); + const struct GNUNET_GNSRECORD_EddsaBlock *edblock = &block->eddsa_block; + size_t payload_len = ntohl (block->size) - sizeof (struct + GNUNET_GNSRECORD_Block); unsigned char nonce[crypto_secretbox_NONCEBYTES]; unsigned char key[crypto_secretbox_KEYBYTES]; - if (ntohl (block->purpose.size) < + if (ntohl (block->size) < sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof(struct GNUNET_TIME_AbsoluteNBO)) { @@ -722,20 +770,19 @@ block_decrypt_eddsa (const struct GNUNET_GNSRECORD_EddsaBlock *block, GNR_derive_block_xsalsa_key (nonce, key, label, - block->expiration_time.abs_value_us__, + block->eddsa_block.expiration_time.abs_value_us__, zone_key); { char payload[payload_len]; - uint32_t rd_count; + unsigned int rd_count; GNUNET_break (GNUNET_OK == eddsa_symmetric_decrypt (&block[1], payload_len, key, nonce, payload)); - GNUNET_memcpy (&rd_count, - payload, - sizeof(uint32_t)); - rd_count = ntohl (rd_count); + payload_len -= crypto_secretbox_MACBYTES; + rd_count = GNUNET_GNSRECORD_records_deserialize_get_size (payload_len, + payload); if (rd_count > 2048) { /* limit to sane value */ @@ -748,8 +795,8 @@ block_decrypt_eddsa (const struct GNUNET_GNSRECORD_EddsaBlock *block, struct GNUNET_TIME_Absolute now; if (GNUNET_OK != - GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof(uint32_t), - &payload[sizeof(uint32_t)], + GNUNET_GNSRECORD_records_deserialize (payload_len, + payload, rd_count, rd)) { @@ -852,12 +899,12 @@ GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block, switch (ntohl (zone_key->type)) { case GNUNET_IDENTITY_TYPE_ECDSA: - res = block_decrypt_ecdsa (&block->ecdsa_block, + res = block_decrypt_ecdsa (block, &zone_key->ecdsa_key, norm_label, proc, proc_cls); break; case GNUNET_IDENTITY_TYPE_EDDSA: - res = block_decrypt_eddsa (&block->eddsa_block, + res = block_decrypt_eddsa (block, &zone_key->eddsa_key, norm_label, proc, proc_cls); break; diff --git a/src/gnsrecord/gnsrecord_crypto.h b/src/gnsrecord/gnsrecord_crypto.h index be762f1b5..79a7e6fb9 100644 --- a/src/gnsrecord/gnsrecord_crypto.h +++ b/src/gnsrecord/gnsrecord_crypto.h @@ -34,6 +34,26 @@ #include "gnunet_dnsparser_lib.h" #include "gnunet_tun_lib.h" +/** + * Information we have in an encrypted block with record data (i.e. in the DHT). + */ +struct GNRBlockPS +{ + /** + * Number of bytes signed; also specifies the number of bytes + * of encrypted data that follow. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Expiration time of the block. + */ + struct GNUNET_TIME_AbsoluteNBO expiration_time; + + /* followed by encrypted data */ +}; + + /** * Derive session key and iv from label and public key. * diff --git a/src/gnsrecord/gnsrecord_misc.c b/src/gnsrecord/gnsrecord_misc.c index c6f07ccd0..61604c730 100644 --- a/src/gnsrecord/gnsrecord_misc.c +++ b/src/gnsrecord/gnsrecord_misc.c @@ -334,24 +334,7 @@ GNUNET_GNSRECORD_is_zonekey_type (uint32_t type) size_t GNUNET_GNSRECORD_block_get_size (const struct GNUNET_GNSRECORD_Block *block) { - switch (ntohl (block->type)) - { - case GNUNET_GNSRECORD_TYPE_PKEY: - return sizeof (uint32_t) /* zone type */ - + sizeof (block->ecdsa_block) /* EcdsaBlock */ - + ntohl (block->ecdsa_block.purpose.size) /* Length of signed data */ - - sizeof (block->ecdsa_block.purpose); /* Purpose already in EcdsaBlock */ - break; - case GNUNET_GNSRECORD_TYPE_EDKEY: - return sizeof (uint32_t) /* zone type */ - + sizeof (block->eddsa_block) /* EddsaBlock */ - + ntohl (block->eddsa_block.purpose.size) /* Length of signed data */ - - sizeof (block->ecdsa_block.purpose); /* Purpose already in EcdsaBlock */ - - default: - return 0; - } - return 0; + return ntohl (block->size); } diff --git a/src/gnsrecord/gnsrecord_serialization.c b/src/gnsrecord/gnsrecord_serialization.c index cb6957605..eaa3a9ab2 100644 --- a/src/gnsrecord/gnsrecord_serialization.c +++ b/src/gnsrecord/gnsrecord_serialization.c @@ -60,17 +60,18 @@ struct NetworkRecord /** * Number of bytes in 'data', network byte order. */ - uint32_t data_size GNUNET_PACKED; + uint16_t data_size GNUNET_PACKED; /** - * Type of the GNS/DNS record, network byte order. + * Flags for the record, network byte order. */ - uint32_t record_type GNUNET_PACKED; + uint16_t flags GNUNET_PACKED; /** - * Flags for the record, network byte order. + * Type of the GNS/DNS record, network byte order. */ - uint32_t flags GNUNET_PACKED; + uint32_t record_type GNUNET_PACKED; + }; GNUNET_NETWORK_STRUCT_END @@ -169,9 +170,9 @@ GNUNET_GNSRECORD_records_serialize (unsigned int rd_count, rd[i].flags, (unsigned long long) rd[i].expiration_time); rec.expiration_time = GNUNET_htonll (rd[i].expiration_time); - rec.data_size = htonl ((uint32_t) rd[i].data_size); + rec.data_size = htons ((uint16_t) rd[i].data_size); rec.record_type = htonl (rd[i].record_type); - rec.flags = htonl (rd[i].flags); + rec.flags = htons (rd[i].flags); if ((off + sizeof(rec) > dest_size) || (off + sizeof(rec) < off)) { @@ -214,13 +215,48 @@ GNUNET_GNSRECORD_records_serialize (unsigned int rd_count, return dest_size; } +unsigned int +GNUNET_GNSRECORD_records_deserialize_get_size (size_t len, + const char *src) +{ + struct NetworkRecord rec; + struct NetworkRecord rec_zero; + size_t off; + unsigned int rd_count = 0; + + memset (&rec_zero, 0, sizeof (rec_zero)); + + off = 0; + for (off = 0; (off + sizeof(rec) <= len) && (off + sizeof(rec) >= off);) + { + /* + * If we have found a byte string of zeroes, we have reached + * the padding + */ + if (0 == GNUNET_memcmp (&rec, &rec_zero)) + break; + GNUNET_memcpy (&rec, + &src[off], + sizeof(rec)); + off += sizeof(rec); + if ((off + ntohs ((uint16_t) rec.data_size) > len) || + (off + ntohs ((uint16_t) rec.data_size) < off)) + { + GNUNET_break_op (0); + return 0; + } + off += ntohs ((uint16_t) rec.data_size); + rd_count++; + } + return rd_count; +} /** * Deserialize the given records to the given destination. * * @param len size of the serialized record data * @param src the serialized record data - * @param rd_count number of records in the rd array + * @param rd_count number of records parsed * @param dest where to put the data * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ @@ -246,9 +282,9 @@ GNUNET_GNSRECORD_records_deserialize (size_t len, &src[off], sizeof(rec)); dest[i].expiration_time = GNUNET_ntohll (rec.expiration_time); - dest[i].data_size = ntohl ((uint32_t) rec.data_size); + dest[i].data_size = ntohs ((uint16_t) rec.data_size); dest[i].record_type = ntohl (rec.record_type); - dest[i].flags = ntohl (rec.flags); + dest[i].flags = ntohs (rec.flags); off += sizeof(rec); if ((off + dest[i].data_size > len) || (off + dest[i].data_size < off)) diff --git a/src/gnsrecord/gnunet-gnsrecord-tvg.c b/src/gnsrecord/gnunet-gnsrecord-tvg.c index 91c6608cd..f9b83e48b 100644 --- a/src/gnsrecord/gnunet-gnsrecord-tvg.c +++ b/src/gnsrecord/gnunet-gnsrecord-tvg.c @@ -38,12 +38,12 @@ #define TEST_RRCOUNT 2 static char *d_pkey = -"50d7b652a4efeadff37396909785e5952171a02178c8e7d450fa907925fafd98"; + "50d7b652a4efeadff37396909785e5952171a02178c8e7d450fa907925fafd98"; static char *d_edkey = -"5af7020ee19160328832352bbc6a68a8d71a7cbe1b929969a7c66d415a0d8f65"; + "5af7020ee19160328832352bbc6a68a8d71a7cbe1b929969a7c66d415a0d8f65"; -int parsehex(char *src, char *dst, size_t dstlen, int invert) +int parsehex (char *src, char *dst, size_t dstlen, int invert) { char *line = src; char *data = line; @@ -51,7 +51,8 @@ int parsehex(char *src, char *dst, size_t dstlen, int invert) int read_byte; int data_len = 0; - while (sscanf(data, " %02x%n", &read_byte, &off) == 1) { + while (sscanf (data, " %02x%n", &read_byte, &off) == 1) + { if (invert) dst[dstlen - 1 - data_len++] = read_byte; else @@ -155,9 +156,9 @@ run_pkey (void) id_priv.type = htonl (GNUNET_GNSRECORD_TYPE_PKEY); GNUNET_CRYPTO_ecdsa_key_create (&id_priv.ecdsa_key); - parsehex(d_pkey, - (char*)&id_priv.ecdsa_key, - sizeof (id_priv.ecdsa_key), 1); + parsehex (d_pkey, + (char*) &id_priv.ecdsa_key, + sizeof (id_priv.ecdsa_key), 1); GNUNET_IDENTITY_key_get_public (&id_priv, &id_pub); @@ -204,16 +205,12 @@ run_pkey (void) rdata_size = GNUNET_GNSRECORD_records_get_size (TEST_RRCOUNT, rd); rdata = GNUNET_malloc (rdata_size); - rd_count_nbo = htonl (2); - GNUNET_memcpy (rdata, - &rd_count_nbo, - sizeof (uint32_t)); GNUNET_GNSRECORD_records_serialize (2, rd, rdata_size, - rdata + sizeof (uint32_t)); + rdata); fprintf (stdout, "RDATA:\n"); - print_bytes (rdata, rdata_size + sizeof (uint32_t), 8); + print_bytes (rdata, rdata_size, 8); fprintf (stdout, "\n"); expire = GNUNET_GNSRECORD_record_get_expiration_time (TEST_RRCOUNT, rd); GNR_derive_block_aes_key (ctr, @@ -235,26 +232,20 @@ run_pkey (void) fprintf (stdout, "Storage key (q):\n"); print_bytes (&query, sizeof (query), 8); fprintf (stdout, "\n"); - - rrblock = GNUNET_GNSRECORD_block_create (&id_priv, - expire, - TEST_RECORD_LABEL, - rd, - TEST_RRCOUNT); - size_t bdata_size = ntohl (rrblock->ecdsa_block.purpose.size) - - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - - sizeof(struct GNUNET_TIME_AbsoluteNBO); - size_t ecblock_size = ntohl (rrblock->ecdsa_block.purpose.size) - + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) - + sizeof(struct GNUNET_CRYPTO_EcdsaSignature); - size_t block_size = ecblock_size + sizeof (uint32_t); + GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create (&id_priv, + expire, + TEST_RECORD_LABEL, + rd, + TEST_RRCOUNT, + &rrblock)); + size_t bdata_size = ntohl(rrblock->size) - sizeof (struct GNUNET_GNSRECORD_Block); bdata = (char*) &(&rrblock->ecdsa_block)[1]; fprintf (stdout, "BDATA:\n"); print_bytes (bdata, bdata_size, 8); fprintf (stdout, "\n"); fprintf (stdout, "RRBLOCK:\n"); - print_bytes (rrblock, block_size, 8); + print_bytes (rrblock, ntohl(rrblock->size), 8); fprintf (stdout, "\n"); GNUNET_free (rdata); } @@ -309,9 +300,9 @@ run_edkey (void) id_priv.type = htonl (GNUNET_IDENTITY_TYPE_EDDSA); GNUNET_CRYPTO_eddsa_key_create (&id_priv.eddsa_key); - parsehex(d_edkey, - (char*)&id_priv.eddsa_key, - sizeof (id_priv.eddsa_key), 0); + parsehex (d_edkey, + (char*) &id_priv.eddsa_key, + sizeof (id_priv.eddsa_key), 0); GNUNET_IDENTITY_key_get_public (&id_priv, &id_pub); fprintf (stdout, @@ -358,17 +349,13 @@ run_edkey (void) rd); expire = GNUNET_GNSRECORD_record_get_expiration_time (TEST_RRCOUNT, rd); - rdata = GNUNET_malloc (sizeof (uint32_t) + rdata_size); - rd_count_nbo = htonl (2); - GNUNET_memcpy (rdata, - &rd_count_nbo, - sizeof (uint32_t)); + rdata = GNUNET_malloc (rdata_size); GNUNET_GNSRECORD_records_serialize (2, rd, rdata_size, - rdata + sizeof (uint32_t)); + rdata); fprintf (stdout, "RDATA:\n"); - print_bytes (rdata, rdata_size + sizeof (uint32_t), 8); + print_bytes (rdata, rdata_size, 8); fprintf (stdout, "\n"); GNR_derive_block_xsalsa_key (nonce, skey, @@ -389,25 +376,20 @@ run_edkey (void) print_bytes (&query, sizeof (query), 8); fprintf (stdout, "\n"); - rrblock = GNUNET_GNSRECORD_block_create (&id_priv, - expire, - TEST_RECORD_LABEL, - rd, - TEST_RRCOUNT); - size_t bdata_size = ntohl (rrblock->eddsa_block.purpose.size) - - sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) - - sizeof(struct GNUNET_TIME_AbsoluteNBO); - size_t ecblock_size = ntohl (rrblock->eddsa_block.purpose.size) - + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey) - + sizeof(struct GNUNET_CRYPTO_EddsaSignature); - size_t block_size = ecblock_size + sizeof (uint32_t); + GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create (&id_priv, + expire, + TEST_RECORD_LABEL, + rd, + TEST_RRCOUNT, + &rrblock)); + size_t bdata_size = ntohl(rrblock->size) - sizeof (struct GNUNET_GNSRECORD_Block); bdata = (char*) &(&rrblock->eddsa_block)[1]; fprintf (stdout, "BDATA:\n"); print_bytes (bdata, bdata_size, 8); fprintf (stdout, "\n"); fprintf (stdout, "RRBLOCK:\n"); - print_bytes (rrblock, block_size, 8); + print_bytes (rrblock, ntohl(rrblock->size), 8); fprintf (stdout, "\n"); GNUNET_free (rdata); } diff --git a/src/gnsrecord/test_gnsrecord_crypto.c b/src/gnsrecord/test_gnsrecord_crypto.c index 9e5a1aa7e..ee14fa904 100644 --- a/src/gnsrecord/test_gnsrecord_crypto.c +++ b/src/gnsrecord/test_gnsrecord_crypto.c @@ -123,12 +123,12 @@ test_with_type (struct GNUNET_IDENTITY_PrivateKey *privkey) s_rd = create_record (RECORDS); /* Create block */ - GNUNET_assert (NULL != (block = - GNUNET_GNSRECORD_block_create (privkey, - expire, - s_name, - s_rd, - RECORDS))); + GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_create (privkey, + expire, + s_name, + s_rd, + RECORDS, + &block)); GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_query_from_block (block, &query_block)); diff --git a/src/include/gnunet_gnsrecord_lib.h b/src/include/gnunet_gnsrecord_lib.h index 94e20323d..fdbac3cf5 100644 --- a/src/include/gnunet_gnsrecord_lib.h +++ b/src/include/gnunet_gnsrecord_lib.h @@ -61,6 +61,7 @@ extern "C" { /** * Flags that can be set for a record. + * MUST fit into 16 bit. */ enum GNUNET_GNSRECORD_Flags { @@ -70,10 +71,17 @@ enum GNUNET_GNSRECORD_Flags GNUNET_GNSRECORD_RF_NONE = 0, /** - * This is a private record of this peer and it should - * thus not be handed out to other peers. + * This record is critical. If it cannot be processed + * (for example beacuse the record type is unknown) + * resolution MUST fail */ - GNUNET_GNSRECORD_RF_PRIVATE = 2, + GNUNET_GNSRECORD_RF_CRITICAL = 1, + + /** + * This record should not be used unless all (other) records with an absolute + * expiration time have expired. + */ + GNUNET_GNSRECORD_RF_SHADOW_RECORD = 2, /** * This is a supplemental record. @@ -84,13 +92,14 @@ enum GNUNET_GNSRECORD_Flags * This expiration time of the record is a relative * time (not an absolute time). */ - GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION = 8, + GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION = 16384, /* 2^14 */ /** - * This record should not be used unless all (other) records with an absolute - * expiration time have expired. + * This is a private record of this peer and it should + * thus not be handed out to other peers. */ - GNUNET_GNSRECORD_RF_SHADOW_RECORD = 16 + GNUNET_GNSRECORD_RF_PRIVATE = 32768, /* 2^15 */ + /** * When comparing flags for record equality for removal, @@ -183,12 +192,6 @@ struct GNUNET_GNSRECORD_EcdsaBlock */ struct GNUNET_CRYPTO_EcdsaSignature signature; - /** - * Number of bytes signed; also specifies the number of bytes - * of encrypted data that follow. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - /** * Expiration time of the block. */ @@ -213,23 +216,26 @@ struct GNUNET_GNSRECORD_EddsaBlock */ struct GNUNET_CRYPTO_EddsaSignature signature; - /** - * Number of bytes signed; also specifies the number of bytes - * of encrypted data that follow. - */ - struct GNUNET_CRYPTO_EccSignaturePurpose purpose; - /** * Expiration time of the block. */ struct GNUNET_TIME_AbsoluteNBO expiration_time; + /* followed by encrypted data */ }; struct GNUNET_GNSRECORD_Block { + /** + * Size of the block. + */ + uint32_t size; + + /** + * The zone type (GNUNET_GNSRECORD_TYPE_PKEY) + */ uint32_t type; union @@ -387,6 +393,9 @@ GNUNET_GNSRECORD_records_serialize (unsigned int rd_count, const struct GNUNET_GNSRECORD_Data *rd, size_t dest_size, char *dest); +unsigned int +GNUNET_GNSRECORD_records_deserialize_get_size (size_t len, + const char *src); /** * Deserialize the given records to the given destination. @@ -502,6 +511,21 @@ GNUNET_GNSRECORD_query_from_public_key ( struct GNUNET_HashCode *query); +/** + * Get size of buffer for block creation. + * + * @param key the zone key + * @param rd record data + * @param rd_count number of records + * @return -1 on error (otherwise the length of the block) + */ +ssize_t +GNUNET_GNSRECORD_block_calculate_size (const struct + GNUNET_IDENTITY_PrivateKey *key, + const struct GNUNET_GNSRECORD_Data *rd, + unsigned int rd_count); + + /** * Sign name and records * @@ -510,13 +534,16 @@ GNUNET_GNSRECORD_query_from_public_key ( * @param label the name for the records * @param rd record data * @param rd_count number of records in @a rd + * @param result the block buffer. Will be allocated. + * @return GNUNET_OK on success */ -struct GNUNET_GNSRECORD_Block * +enum GNUNET_GenericReturnValue GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count); + unsigned int rd_count, + struct GNUNET_GNSRECORD_Block **block); /** @@ -529,13 +556,16 @@ GNUNET_GNSRECORD_block_create (const struct GNUNET_IDENTITY_PrivateKey *key, * @param label the name for the records * @param rd record data * @param rd_count number of records in @a rd + * @param result the block buffer. Will be allocated. + * @return GNUNET_OK on success. */ -struct GNUNET_GNSRECORD_Block * +enum GNUNET_GenericReturnValue GNUNET_GNSRECORD_block_create2 (const struct GNUNET_IDENTITY_PrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *label, const struct GNUNET_GNSRECORD_Data *rd, - unsigned int rd_count); + unsigned int rd_count, + struct GNUNET_GNSRECORD_Block **result); /** -- cgit v1.2.3