61 lines
4.1 KiB
C
61 lines
4.1 KiB
C
/* dm_protocol — единый разбор тела DEVICE/GROUPS и сертификатов адресатов.
|
||
* DEVICE сохраняет существующий формат, включая пустой content type. GROUPS
|
||
* ставит старший бит data_len и помещает контекст перед ciphertext.
|
||
* Тело подписывается целиком, включая снимок; parser не проверяет подпись автора.
|
||
* Указатели view заимствуют входной буфер. SQL-функция encode вызывается в uasync. */
|
||
#ifndef UTUN_DM_PROTOCOL_H
|
||
#define UTUN_DM_PROTOCOL_H
|
||
|
||
#include "dm_identity.h"
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#define DM_TARGET_PROOF_SIZE 137 /* node:LE64,side:u8,x:32,ed:32,member_sig:64. */
|
||
#define DM_CONTEXT_FLAG 0x8000u /* Старший бит uint16 data_len; фактическая длина не более1040. */
|
||
#define DM_CONTEXT_MAX (1 + 2 * DM_PARTY_WIRE_SIZE + 2 + DM_TARGET_MAX * DM_TARGET_PROOF_SIZE)
|
||
#define DM_BODY_MAX (33 + 255 + 2 + DM_CONTEXT_MAX + 1024 + 16 + 56 + 64)
|
||
|
||
struct dm_message_view {
|
||
uint64_t conv, seq, timestamp, author; /* Общий префикс, native-endian. */
|
||
enum dm_mode mode;
|
||
struct dm_party parties[2]; /* Только GROUPS: сторона автора, другая сторона. */
|
||
uint16_t target_count; /* GROUPS: снимок включает автора. DEVICE: 0. */
|
||
const uint8_t* targets; /* target_count сертификатов по DM_TARGET_PROOF_SIZE. */
|
||
const uint8_t* content_type; /* Не NUL-строка, ровно content_type_size байт. */
|
||
uint8_t content_type_size;
|
||
const uint8_t* ciphertext; /* ciphertext_size байт, включая CCM tag. */
|
||
uint16_t ciphertext_size;
|
||
const uint8_t* media; /* UUID/size/hash:56 либо NULL. */
|
||
const uint8_t* signature; /* Подпись автора:64. */
|
||
size_t size; /* Длина тела; parser допускает хвост после него. */
|
||
};
|
||
|
||
/* 0/-1: проверить границы/форму тела и вернуть view. Выход не меняется при ошибке.
|
||
* Проверка точной длины, подписей и адресата — обязанность принимающего модуля. */
|
||
int dm_message_parse(const uint8_t* body, size_t available, struct dm_message_view* out);
|
||
|
||
/* 0/-1: GROUPS проверяет ID беседы, упорядоченный уникальный snapshot, обе стороны,
|
||
* наличие автора на стороне 0 и подписи удостоверений. DEVICE — пустая операция:
|
||
* ID/подпись конкретной пары проверяет dm_core. Ключи самих устройств связаны с node_id. */
|
||
int dm_message_verify_targets(const struct dm_message_view* view);
|
||
|
||
/* GROUPS: найти node в снимке, 0/1 — сторона, -1 — отсутствует. При успехе
|
||
* x/ed (если не NULL) получают по 32 байта. Для DEVICE всегда -1. */
|
||
int dm_message_target(const struct dm_message_view* view, uint64_t node, uint8_t x[32], uint8_t ed[32]);
|
||
/* 0/-1: прочитать node/side по индексу GROUPS-snapshot, без проверки подписи. */
|
||
int dm_message_target_at(const struct dm_message_view* view, unsigned index, struct dm_target* out);
|
||
|
||
/* 0/-1: сформировать контекст GROUPS (между data_len с флагом и ciphertext).
|
||
* VERSION=1:u8, parties:2*73,count:LE16,sorted certificates:count*137.
|
||
* Сторона 0 должна включать текущего отправителя. out меняется только при успехе;
|
||
* DM_CONTEXT_MAX достаточно. Источник включается, неизвестные устройства не ищутся. */
|
||
int dm_context_encode(struct UTUN_INSTANCE* inst, const struct dm_party parties[2],
|
||
uint8_t* out, size_t capacity, size_t* length);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
#endif
|