upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/main/identity.c
blob: 1dab415f3fef3c4aa0ba2100b6cbb5add8d23fef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#include "identity.h"
#include "config.h"
#include "esp_log.h"
#include "lwip/ip4_addr.h"
#include "mbedtls/md.h"
#include "secp256k1.h"
#include "secp256k1_extrakeys.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

static const char *TAG = "identity";
static tollgate_identity_t s_identity;

static int hex_to_bytes(const char *hex, uint8_t *out, size_t out_len)
{
    if (strlen(hex) != out_len * 2) return 0;
    for (size_t i = 0; i < out_len; i++) {
        unsigned int byte;
        if (sscanf(hex + i * 2, "%02x", &byte) != 1) return 0;
        out[i] = (uint8_t)byte;
    }
    return 1;
}

static void bytes_to_hex(const uint8_t *bytes, size_t len, char *hex)
{
    for (size_t i = 0; i < len; i++)
        sprintf(hex + i * 2, "%02x", bytes[i]);
    hex[len * 2] = '\0';
}

static void tollgate_derive(const uint8_t nsec[32], const char *label,
                            uint32_t index, uint8_t *out, size_t out_len)
{
    size_t label_len = strlen(label);
    size_t msg_len = label_len + 4;
    uint8_t *msg = (uint8_t *)malloc(msg_len);
    memcpy(msg, label, label_len);
    msg[label_len]     = (uint8_t)(index & 0xff);
    msg[label_len + 1] = (uint8_t)((index >> 8) & 0xff);
    msg[label_len + 2] = (uint8_t)((index >> 16) & 0xff);
    msg[label_len + 3] = (uint8_t)((index >> 24) & 0xff);

    uint8_t hmac[64];
    mbedtls_md_hmac(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512),
                    nsec, 32, msg, msg_len, hmac);
    free(msg);

    memcpy(out, hmac, out_len);
}

esp_err_t identity_init(const char *nsec_hex)
{
    memset(&s_identity, 0, sizeof(s_identity));

    if (!nsec_hex || strlen(nsec_hex) != 64) {
        ESP_LOGE(TAG, "Invalid nsec: must be 64 hex chars");
        return ESP_ERR_INVALID_ARG;
    }

    strncpy(s_identity.nsec_hex, nsec_hex, sizeof(s_identity.nsec_hex) - 1);

    if (!hex_to_bytes(nsec_hex, s_identity.nsec, 32)) {
        ESP_LOGE(TAG, "Failed to parse nsec hex");
        return ESP_ERR_INVALID_ARG;
    }

    secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
    if (!ctx) {
        ESP_LOGE(TAG, "Failed to create secp256k1 context");
        return ESP_ERR_NO_MEM;
    }

    secp256k1_pubkey pubkey;
    if (!secp256k1_ec_pubkey_create(ctx, &pubkey, s_identity.nsec)) {
        ESP_LOGE(TAG, "Invalid nsec: secp256k1 key creation failed");
        secp256k1_context_destroy(ctx);
        return ESP_ERR_INVALID_ARG;
    }

    secp256k1_xonly_pubkey xonly;
    secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly, NULL, &pubkey);
    uint8_t npub_bytes[32];
    secp256k1_xonly_pubkey_serialize(ctx, npub_bytes, &xonly);
    bytes_to_hex(npub_bytes, 32, s_identity.npub_hex);

    tollgate_derive(s_identity.nsec, "sta-mac", 0, s_identity.sta_mac, 6);
    s_identity.sta_mac[0] = (s_identity.sta_mac[0] | 0x02) & 0xFE;

    tollgate_derive(s_identity.nsec, "ap-mac", 0, s_identity.ap_mac, 6);
    s_identity.ap_mac[0] = (s_identity.ap_mac[0] | 0x02) & 0xFE;

    snprintf(s_identity.ap_ssid, sizeof(s_identity.ap_ssid),
             "TollGate-%02X%02X%02X",
             s_identity.ap_mac[3], s_identity.ap_mac[4], s_identity.ap_mac[5]);

    uint8_t b3 = s_identity.ap_mac[3];
    uint8_t b4 = s_identity.ap_mac[4];
    uint8_t b5 = s_identity.ap_mac[5];
    uint8_t subnet = (b4 ^ b5) % 200 + 10;
    IP4_ADDR(&s_identity.ap_ip, 10, b3, subnet, 1);
    snprintf(s_identity.ap_ip_str, sizeof(s_identity.ap_ip_str),
             IPSTR, IP2STR(&s_identity.ap_ip));

    secp256k1_context_destroy(ctx);
    s_identity.initialized = true;

    ESP_LOGI(TAG, "Identity: npub=%s", s_identity.npub_hex);
    ESP_LOGI(TAG, "  STA MAC: %02X:%02X:%02X:%02X:%02X:%02X",
             s_identity.sta_mac[0], s_identity.sta_mac[1], s_identity.sta_mac[2],
             s_identity.sta_mac[3], s_identity.sta_mac[4], s_identity.sta_mac[5]);
    ESP_LOGI(TAG, "  AP  MAC: %02X:%02X:%02X:%02X:%02X:%02X",
             s_identity.ap_mac[0], s_identity.ap_mac[1], s_identity.ap_mac[2],
             s_identity.ap_mac[3], s_identity.ap_mac[4], s_identity.ap_mac[5]);
    ESP_LOGI(TAG, "  SSID: %s, AP IP: %s", s_identity.ap_ssid, s_identity.ap_ip_str);

    return ESP_OK;
}

const tollgate_identity_t *identity_get(void)
{
    return &s_identity;
}