LCOV - code coverage report
Current view: top level - tests/unit - test_auth_transfer.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 95.6 % 114 109
Test Date: 2026-04-20 19:54:22 Functions: 100.0 % 12 12

            Line data    Source code
       1              : /**
       2              :  * @file test_auth_transfer.c
       3              :  * @brief Unit tests for P10-04 cross-DC authorization transfer.
       4              :  */
       5              : 
       6              : #include "test_helpers.h"
       7              : #include "infrastructure/auth_transfer.h"
       8              : #include "tl_serial.h"
       9              : #include "tl_registry.h"
      10              : #include "mock_socket.h"
      11              : #include "mock_crypto.h"
      12              : #include "mtproto_session.h"
      13              : #include "transport.h"
      14              : #include "api_call.h"
      15              : 
      16              : #include <stdlib.h>
      17              : #include <string.h>
      18              : 
      19              : #define CRC_auth_exportedAuthorization_t 0xb434e2b8u
      20              : #define CRC_auth_authorization_t         0x2ea2c0d4u
      21              : 
      22            3 : static void build_fake_encrypted_response(const uint8_t *payload, size_t plen,
      23              :                                           uint8_t *out, size_t *out_len) {
      24            3 :     TlWriter w; tl_writer_init(&w);
      25            3 :     uint8_t zeros24[24] = {0}; tl_write_raw(&w, zeros24, 24);
      26            3 :     uint8_t header[32] = {0};
      27            3 :     uint32_t plen32 = (uint32_t)plen;
      28            3 :     memcpy(header + 28, &plen32, 4);
      29            3 :     tl_write_raw(&w, header, 32);
      30            3 :     tl_write_raw(&w, payload, plen);
      31            3 :     size_t enc = w.len - 24;
      32            3 :     if (enc % 16 != 0) {
      33            2 :         uint8_t pad[16] = {0}; tl_write_raw(&w, pad, 16 - (enc % 16));
      34              :     }
      35            3 :     size_t dwords = w.len / 4;
      36            3 :     size_t off = 0;
      37            3 :     if (dwords < 0x7F) { out[0] = (uint8_t)dwords; off = 1; }
      38              :     else {
      39            0 :         out[0] = 0x7F;
      40            0 :         out[1] = (uint8_t)(dwords);
      41            0 :         out[2] = (uint8_t)(dwords >> 8);
      42            0 :         out[3] = (uint8_t)(dwords >> 16);
      43            0 :         off = 4;
      44              :     }
      45            3 :     memcpy(out + off, w.data, w.len);
      46            3 :     *out_len = off + w.len;
      47            3 :     tl_writer_free(&w);
      48            3 : }
      49              : 
      50            4 : static void fix_session(MtProtoSession *s) {
      51            4 :     mtproto_session_init(s);
      52            4 :     s->session_id = 0; /* match the zero session_id in fake encrypted frames */
      53            4 :     uint8_t k[256] = {0}; mtproto_session_set_auth_key(s, k);
      54            4 :     mtproto_session_set_salt(s, 0xBADCAFEDEADBEEFULL);
      55            4 : }
      56            4 : static void fix_transport(Transport *t) {
      57            4 :     transport_init(t); t->fd = 42; t->connected = 1; t->dc_id = 1;
      58            4 : }
      59            4 : static void fix_cfg(ApiConfig *cfg) {
      60            4 :     api_config_init(cfg); cfg->api_id = 12345; cfg->api_hash = "deadbeef";
      61            4 : }
      62              : 
      63            1 : static size_t make_exported_auth(uint8_t *buf, size_t max,
      64              :                                   int64_t id,
      65              :                                   const uint8_t *bytes, size_t blen) {
      66            1 :     TlWriter w; tl_writer_init(&w);
      67            1 :     tl_write_uint32(&w, CRC_auth_exportedAuthorization_t);
      68            1 :     tl_write_int64 (&w, id);
      69            1 :     tl_write_bytes (&w, bytes, blen);
      70            1 :     size_t n = w.len < max ? w.len : max;
      71            1 :     memcpy(buf, w.data, n);
      72            1 :     tl_writer_free(&w);
      73            1 :     return n;
      74              : }
      75              : 
      76            1 : static size_t make_authorization(uint8_t *buf, size_t max) {
      77            1 :     TlWriter w; tl_writer_init(&w);
      78            1 :     tl_write_uint32(&w, CRC_auth_authorization_t);
      79              :     /* Build a minimal auth.authorization — flags=0, user:userEmpty. */
      80            1 :     tl_write_uint32(&w, 0);                                  /* flags */
      81            1 :     tl_write_uint32(&w, 0xd3bc4b7au);                        /* userEmpty crc */
      82            1 :     tl_write_int64 (&w, 0);                                  /* id */
      83            1 :     size_t n = w.len < max ? w.len : max;
      84            1 :     memcpy(buf, w.data, n);
      85            1 :     tl_writer_free(&w);
      86            1 :     return n;
      87              : }
      88              : 
      89            1 : static void test_export_parses_id_and_bytes(void) {
      90            1 :     mock_socket_reset(); mock_crypto_reset();
      91              : 
      92              :     uint8_t token[32];
      93           33 :     for (size_t i = 0; i < sizeof(token); i++) token[i] = (uint8_t)(i * 7 + 1);
      94              : 
      95              :     uint8_t payload[512];
      96            1 :     size_t plen = make_exported_auth(payload, sizeof(payload),
      97              :                                       0xFEEDBEEFCAFEDEADLL,
      98              :                                       token, sizeof(token));
      99            1 :     uint8_t resp[1024]; size_t rlen = 0;
     100            1 :     build_fake_encrypted_response(payload, plen, resp, &rlen);
     101            1 :     mock_socket_set_response(resp, rlen);
     102              : 
     103              :     MtProtoSession s; Transport t; ApiConfig cfg;
     104            1 :     fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
     105              : 
     106            1 :     AuthExported out = {0};
     107            1 :     int rc = auth_transfer_export(&cfg, &s, &t, 4, &out, NULL);
     108            1 :     ASSERT(rc == 0, "export succeeds");
     109            1 :     ASSERT(out.id == (int64_t)0xFEEDBEEFCAFEDEADLL, "id parsed");
     110            1 :     ASSERT(out.bytes_len == sizeof(token), "bytes_len parsed");
     111            1 :     ASSERT(memcmp(out.bytes, token, sizeof(token)) == 0, "bytes round-trip");
     112              : }
     113              : 
     114            1 : static void test_export_rpc_error_surfaces(void) {
     115            1 :     mock_socket_reset(); mock_crypto_reset();
     116              : 
     117              :     uint8_t payload[128];
     118            1 :     TlWriter w; tl_writer_init(&w);
     119            1 :     tl_write_uint32(&w, TL_rpc_error);
     120            1 :     tl_write_int32 (&w, 400);
     121            1 :     tl_write_string(&w, "DC_ID_INVALID");
     122            1 :     memcpy(payload, w.data, w.len);
     123            1 :     size_t plen = w.len;
     124            1 :     tl_writer_free(&w);
     125              : 
     126            1 :     uint8_t resp[512]; size_t rlen = 0;
     127            1 :     build_fake_encrypted_response(payload, plen, resp, &rlen);
     128            1 :     mock_socket_set_response(resp, rlen);
     129              : 
     130              :     MtProtoSession s; Transport t; ApiConfig cfg;
     131            1 :     fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
     132              : 
     133            1 :     AuthExported out = {0};
     134            1 :     RpcError err = {0};
     135            1 :     int rc = auth_transfer_export(&cfg, &s, &t, 99, &out, &err);
     136            1 :     ASSERT(rc == -1, "rpc error propagates");
     137            1 :     ASSERT(err.error_code == 400, "error_code preserved");
     138            1 :     ASSERT(strcmp(err.error_msg, "DC_ID_INVALID") == 0, "error_msg preserved");
     139              : }
     140              : 
     141            1 : static void test_import_accepts_authorization(void) {
     142            1 :     mock_socket_reset(); mock_crypto_reset();
     143              : 
     144              :     uint8_t payload[512];
     145            1 :     size_t plen = make_authorization(payload, sizeof(payload));
     146            1 :     uint8_t resp[1024]; size_t rlen = 0;
     147            1 :     build_fake_encrypted_response(payload, plen, resp, &rlen);
     148            1 :     mock_socket_set_response(resp, rlen);
     149              : 
     150              :     MtProtoSession s; Transport t; ApiConfig cfg;
     151            1 :     fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
     152              : 
     153            1 :     AuthExported tok = {0};
     154            1 :     tok.id = 42;
     155            1 :     tok.bytes_len = 4;
     156            1 :     tok.bytes[0] = 1; tok.bytes[1] = 2; tok.bytes[2] = 3; tok.bytes[3] = 4;
     157              : 
     158            1 :     int rc = auth_transfer_import(&cfg, &s, &t, &tok, NULL);
     159            1 :     ASSERT(rc == 0, "import succeeds on auth.authorization");
     160              : }
     161              : 
     162            1 : static void test_import_rejects_empty_token(void) {
     163              :     ApiConfig cfg; MtProtoSession s; Transport t;
     164            1 :     fix_session(&s); fix_transport(&t); fix_cfg(&cfg);
     165              : 
     166            1 :     AuthExported tok = {0};                  /* bytes_len = 0 */
     167            1 :     ASSERT(auth_transfer_import(&cfg, &s, &t, &tok, NULL) == -1,
     168              :            "zero-length token rejected");
     169              : }
     170              : 
     171            1 : static void test_null_args(void) {
     172            1 :     ASSERT(auth_transfer_export(NULL, NULL, NULL, 2, NULL, NULL) == -1,
     173              :            "export rejects nulls");
     174            1 :     ASSERT(auth_transfer_import(NULL, NULL, NULL, NULL, NULL) == -1,
     175              :            "import rejects nulls");
     176              : }
     177              : 
     178            1 : void run_auth_transfer_tests(void) {
     179            1 :     RUN_TEST(test_export_parses_id_and_bytes);
     180            1 :     RUN_TEST(test_export_rpc_error_surfaces);
     181            1 :     RUN_TEST(test_import_accepts_authorization);
     182            1 :     RUN_TEST(test_import_rejects_empty_token);
     183            1 :     RUN_TEST(test_null_args);
     184            1 : }
        

Generated by: LCOV version 2.0-1