Browse Source

Bind signed file descriptors to atomic DM enqueue and receive

master
evgeny 1 day ago
parent
commit
5e9a9059c8
  1. 24
      src/dm/dm_core.c
  2. 10
      src/dm/dm_core.h

24
src/dm/dm_core.c

@ -296,6 +296,16 @@ static int dm_build_body(struct dm_state* dm, const struct dm_conv* c, uint64_t
}
uint8_t ct_len = (uint8_t)strnlen(ct, 255);
const uint8_t* media = NULL;
if (!strcmp(ct, "file")) {
if (data_len <= DM_MEDIA_DESC_SIZE) {
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: file message lacks descriptor/name", DM_ID);
return -1;
}
media = data;
data += DM_MEDIA_DESC_SIZE;
data_len -= DM_MEDIA_DESC_SIZE;
}
uint64_t conv_num = (uint64_t)strtoull(c->conv_id, NULL, 10);
uint8_t nonce[DM_NONCE_SIZE];
dm_build_nonce(conv_num, dm->inst->node_id, seq, nonce);
@ -311,7 +321,7 @@ static int dm_build_body(struct dm_state* dm, const struct dm_conv* c, uint64_t
}
uint64_t author = dm->inst->node_id;
size_t body_len = DM_MSG_FIXED_HDR + ct_len + 2 + enc_len + DM_MSG_SIG_SIZE;
size_t body_len = DM_MSG_FIXED_HDR + ct_len + 2 + enc_len + (media ? DM_MEDIA_DESC_SIZE : 0) + DM_MSG_SIG_SIZE;
uint8_t* body = u_malloc(body_len);
if (!body) { u_free(enc); return -1; }
size_t off = 0;
@ -324,6 +334,7 @@ static int dm_build_body(struct dm_state* dm, const struct dm_conv* c, uint64_t
uint16_t el = (uint16_t)enc_len;
memcpy(body + off, &el, 2); off += 2;
memcpy(body + off, enc, enc_len); off += enc_len;
if (media) { memcpy(body + off, media, DM_MEDIA_DESC_SIZE); off += DM_MEDIA_DESC_SIZE; }
/* подпись по всем полям до sig */
if (sc_ed25519_sign(dm->inst->my_ed25519_privkey, body, off, body + off) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_DM, "%s: message signing failed", DM_ID);
@ -349,6 +360,12 @@ int dm_verify_message(struct UTUN_INSTANCE* inst, uint64_t recipient, const uint
memcpy(&author, msg + 24, 8);
if (!recipient || !author || author == recipient || !seq || seq > INT64_MAX ||
conv != dm_derive_conv_id(author, recipient)) goto invalid;
const uint8_t* media = dm_message_media(msg, len);
if (media) {
uint64_t size;
memcpy(&size, media + 16, 8);
if (size > DM_MEDIA_MAX_SIZE) goto invalid;
}
uint8_t x[32], ed[32];
if (dm_node_pubkeys(&view, author, x, ed) != 0 ||
sc_ed25519_verify(ed, msg, len - DM_MSG_SIG_SIZE, msg + len - DM_MSG_SIG_SIZE) != SC_OK) goto invalid;
@ -453,7 +470,7 @@ int dm_accept_message(struct UTUN_INSTANCE* inst, const uint8_t* msg, size_t len
uint64_t ts;
memcpy(&ts, msg + 16, 8);
if (ts > c.last_ts) c.last_ts = ts;
if (inserted < 0 || dm_conv_save(dm, &c) != 0 || dm_exec(dm, "COMMIT") != 0) {
if (inserted < 0 || dm_conv_save(dm, &c) != 0 || dm_media_track(inst, 0, msg, len) != 0 || dm_exec(dm, "COMMIT") != 0) {
dm_exec(dm, "ROLLBACK");
return -1;
}
@ -734,7 +751,8 @@ int dm_send(struct UTUN_INSTANCE* inst, const char* conv_id, const char* content
if (dm_exec(dm, "BEGIN IMMEDIATE") != 0) { u_free(body); return -1; }
c.last_out_seq = seq;
if (ts > c.last_ts) c.last_ts = ts;
if (dm_store_message(dm, conv_id, 1, body, len) != 1 || dm_conv_save(dm, &c) != 0) goto rollback;
if (dm_store_message(dm, conv_id, 1, body, len) != 1 || dm_conv_save(dm, &c) != 0 ||
dm_media_track(inst, 1, body, len) != 0) goto rollback;
int rc = sqlite3_prepare_v2(dm->db, "INSERT INTO dm_outbox(conv_id,seq,body) VALUES(?,?,?)", -1, &st, NULL);
if (rc == SQLITE_OK) {
sqlite3_bind_text(st, 1, conv_id, -1, SQLITE_STATIC);

10
src/dm/dm_core.h

@ -17,6 +17,7 @@
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "dm_media.h"
struct UTUN_INSTANCE;
@ -25,7 +26,8 @@ extern "C" {
#endif
/* ── Каноническое тело DM-сообщения (общий wire-формат dm_core и dm_mailbox) ──
* [conv_id:8][seq:8][ts:8][author:8][ct_len:1][ct:ct_len][data_len:2][data_enc:data_len][sig:64]
* [conv_id:8][seq:8][ts:8][author:8][ct_len:1][ct:ct_len][data_len:2][data_enc:data_len][media?:56][sig:64]
* media присутствует только для ct="file", подписан вместе с сообщением.
* data_enc — AES-256-CCM (шифротекст + tag), sig — Ed25519 автора по всем полям до sig. */
#define DM_MSG_FIXED_HDR 33 /* conv_id+seq+ts+author(32) + ct_len(1) — до ct */
#define DM_MSG_SIG_SIZE 64
@ -41,7 +43,8 @@ static inline int dm_msg_len(const uint8_t* msg, size_t avail, size_t* out_len)
uint16_t data_len;
memcpy(&data_len, msg + DM_MSG_FIXED_HDR + ct_len, 2);
if (data_len < 16 || data_len > DM_DATA_MAX + 16) return 0;
size_t total = (size_t)DM_MSG_FIXED_HDR + ct_len + 2 + data_len + DM_MSG_SIG_SIZE;
size_t media_len = ct_len == 4 && !memcmp(msg + DM_MSG_FIXED_HDR, "file", 4) ? DM_MEDIA_DESC_SIZE : 0;
size_t total = (size_t)DM_MSG_FIXED_HDR + ct_len + 2 + data_len + media_len + DM_MSG_SIG_SIZE;
if (avail < total) return 0;
*out_len = total;
return 1;
@ -75,7 +78,8 @@ int dm_start(struct UTUN_INSTANCE* inst, uint64_t peer_node_id,
/* Отправить сообщение в беседу. Шифрует, подписывает, сохраняет локально и
* доставляет (прямое соединение при доступности пира, иначе mailbox).
* conv_id — строковое представление (как в dm_conversations.conv_id). */
* conv_id — строковое представление (как в dm_conversations.conv_id).
* Для ct="file" data=[descriptor:56][basename:utf8], только после подготовки dm_media. */
int dm_send(struct UTUN_INSTANCE* inst, const char* conv_id, const char* content_type,
const uint8_t* data, uint32_t data_len);

Loading…
Cancel
Save