firmware/src/mesh/Channels.cpp

321 lines
12 KiB
C++
Raw Normal View History

2021-02-16 07:41:52 +00:00
#include "Channels.h"
#include "CryptoEngine.h"
#include "DisplayFormatters.h"
2021-02-22 03:16:38 +00:00
#include "NodeDB.h"
#include "RadioInterface.h"
#include "configuration.h"
2021-02-16 07:41:52 +00:00
#include <assert.h>
#include "mqtt/MQTT.h"
2021-02-16 07:41:52 +00:00
/// 16 bytes of random PSK for our _public_ default channel that all devices power up on (AES128)
static const uint8_t defaultpsk[] = {0xd4, 0xf1, 0xbb, 0x3a, 0x20, 0x29, 0x07, 0x59,
0xf0, 0xbc, 0xff, 0xab, 0xcf, 0x4e, 0x69, 0x01};
2021-02-16 07:41:52 +00:00
Channels channels;
2021-03-13 05:14:27 +00:00
const char *Channels::adminChannel = "admin";
const char *Channels::gpioChannel = "gpio";
const char *Channels::serialChannel = "serial";
const char *Channels::mqttChannel = "mqtt";
2021-03-13 05:14:27 +00:00
2021-02-23 02:10:35 +00:00
uint8_t xorHash(const uint8_t *p, size_t len)
2021-02-22 04:57:26 +00:00
{
uint8_t code = 0;
2021-03-08 07:20:43 +00:00
for (size_t i = 0; i < len; i++)
2021-02-22 04:57:26 +00:00
code ^= p[i];
return code;
}
2021-02-23 02:10:35 +00:00
/** Given a channel number, return the (0 to 255) hash for that channel.
* The hash is just an xor of the channel name followed by the channel PSK being used for encryption
* If no suitable channel could be found, return -1
*/
int16_t Channels::generateHash(ChannelIndex channelNum)
{
auto k = getKey(channelNum);
if (k.length < 0)
return -1; // invalid
else {
2021-02-23 06:35:34 +00:00
const char *name = getName(channelNum);
uint8_t h = xorHash((const uint8_t *)name, strlen(name));
2021-02-23 02:10:35 +00:00
h ^= xorHash(k.bytes, k.length);
return h;
}
}
2021-02-16 07:41:52 +00:00
/**
* Validate a channel, fixing any errors as needed
*/
meshtastic_Channel &Channels::fixupChannel(ChannelIndex chIndex)
2021-02-16 07:41:52 +00:00
{
meshtastic_Channel &ch = getByIndex(chIndex);
2021-02-16 07:41:52 +00:00
2021-02-22 03:16:38 +00:00
ch.index = chIndex; // Preinit the index so it be ready to share with the phone (we'll never change it later)
2021-02-16 07:41:52 +00:00
2021-02-22 03:16:38 +00:00
if (!ch.has_settings) {
2021-02-16 07:41:52 +00:00
// No settings! Must disable and skip
ch.role = meshtastic_Channel_Role_DISABLED;
2021-02-22 03:16:38 +00:00
memset(&ch.settings, 0, sizeof(ch.settings));
ch.has_settings = true;
2021-02-16 07:41:52 +00:00
} else {
meshtastic_ChannelSettings &meshtastic_channelSettings = ch.settings;
2021-02-16 07:41:52 +00:00
// Convert the old string "Default" to our new short representation
if (strcmp(meshtastic_channelSettings.name, "Default") == 0)
*meshtastic_channelSettings.name = '\0';
2021-02-16 07:41:52 +00:00
}
2021-02-22 04:57:26 +00:00
hashes[chIndex] = generateHash(chIndex);
2021-02-22 03:16:38 +00:00
return ch;
2021-02-16 07:41:52 +00:00
}
/**
* Write a default channel to the specified channel index
*/
2021-02-22 03:16:38 +00:00
void Channels::initDefaultChannel(ChannelIndex chIndex)
2021-02-16 07:41:52 +00:00
{
meshtastic_Channel &ch = getByIndex(chIndex);
meshtastic_ChannelSettings &channelSettings = ch.settings;
meshtastic_Config_LoRaConfig &loraConfig = config.lora;
2021-02-16 07:41:52 +00:00
loraConfig.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST; // Default to Long Range & Fast
loraConfig.use_preset = true;
loraConfig.tx_power = 0; // default
2021-02-16 07:41:52 +00:00
uint8_t defaultpskIndex = 1;
channelSettings.psk.bytes[0] = defaultpskIndex;
channelSettings.psk.size = 1;
strncpy(channelSettings.name, "", sizeof(channelSettings.name));
2024-02-22 18:32:01 +00:00
channelSettings.module_settings.position_precision = 32; // default to sending location on the primary channel
channelSettings.has_module_settings = true;
2021-02-16 07:41:52 +00:00
2021-02-22 03:16:38 +00:00
ch.has_settings = true;
ch.role = meshtastic_Channel_Role_PRIMARY;
2021-02-16 07:41:52 +00:00
}
2021-02-23 02:10:35 +00:00
CryptoKey Channels::getKey(ChannelIndex chIndex)
2021-02-16 07:41:52 +00:00
{
meshtastic_Channel &ch = getByIndex(chIndex);
const meshtastic_ChannelSettings &channelSettings = ch.settings;
2021-02-22 03:16:38 +00:00
assert(ch.has_settings);
2021-02-16 07:41:52 +00:00
2021-02-23 02:10:35 +00:00
CryptoKey k;
memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros
if (ch.role == meshtastic_Channel_Role_DISABLED) {
2021-02-23 02:10:35 +00:00
k.length = -1; // invalid
} else {
memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size);
k.length = channelSettings.psk.size;
if (k.length == 0) {
if (ch.role == meshtastic_Channel_Role_SECONDARY) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Unset PSK for secondary channel %s. using primary key\n", ch.settings.name);
2021-02-23 02:10:35 +00:00
k = getKey(primaryIndex);
} else {
2022-12-30 02:41:37 +00:00
LOG_WARN("User disabled encryption\n");
}
2021-02-23 02:10:35 +00:00
} else if (k.length == 1) {
// Convert the short single byte variants of psk into variant that can be used more generally
uint8_t pskIndex = k.bytes[0];
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Expanding short PSK #%d\n", pskIndex);
2021-02-23 02:10:35 +00:00
if (pskIndex == 0)
k.length = 0; // Turn off encryption
2022-10-19 13:39:06 +00:00
else if (oemStore.oem_aes_key.size > 1) {
// Use the OEM key
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Using OEM Key with %d bytes\n", oemStore.oem_aes_key.size);
2023-01-21 13:34:29 +00:00
memcpy(k.bytes, oemStore.oem_aes_key.bytes, oemStore.oem_aes_key.size);
2022-10-19 13:39:06 +00:00
k.length = oemStore.oem_aes_key.size;
// Bump up the last byte of PSK as needed
uint8_t *last = k.bytes + oemStore.oem_aes_key.size - 1;
*last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
if (k.length < 16) {
2022-12-30 02:41:37 +00:00
LOG_WARN("OEM provided a too short AES128 key - padding\n");
2022-10-19 13:39:06 +00:00
k.length = 16;
} else if (k.length < 32 && k.length != 16) {
2022-12-30 02:41:37 +00:00
LOG_WARN("OEM provided a too short AES256 key - padding\n");
2022-10-19 13:39:06 +00:00
k.length = 32;
}
} else {
2021-02-23 02:10:35 +00:00
memcpy(k.bytes, defaultpsk, sizeof(defaultpsk));
k.length = sizeof(defaultpsk);
// Bump up the last byte of PSK as needed
uint8_t *last = k.bytes + sizeof(defaultpsk) - 1;
*last = *last + pskIndex - 1; // index of 1 means no change vs defaultPSK
}
} else if (k.length < 16) {
// Error! The user specified only the first few bits of an AES128 key. So by convention we just pad the rest of the
// key with zeros
2022-12-30 02:41:37 +00:00
LOG_WARN("User provided a too short AES128 key - padding\n");
2021-02-23 02:10:35 +00:00
k.length = 16;
} else if (k.length < 32 && k.length != 16) {
// Error! The user specified only the first few bits of an AES256 key. So by convention we just pad the rest of the
// key with zeros
2022-12-30 02:41:37 +00:00
LOG_WARN("User provided a too short AES256 key - padding\n");
2021-02-23 02:10:35 +00:00
k.length = 32;
2021-02-16 07:41:52 +00:00
}
}
2021-02-23 02:10:35 +00:00
return k;
}
/** Given a channel index, change to use the crypto key specified by that index
*/
int16_t Channels::setCrypto(ChannelIndex chIndex)
{
CryptoKey k = getKey(chIndex);
if (k.length < 0)
return -1;
else {
// Tell our crypto engine about the psk
crypto->setKey(k);
return getHash(chIndex);
}
2021-02-16 07:41:52 +00:00
}
void Channels::initDefaults()
{
2021-03-11 05:02:00 +00:00
channelFile.channels_count = MAX_NUM_CHANNELS;
for (int i = 0; i < channelFile.channels_count; i++)
2021-02-16 07:41:52 +00:00
fixupChannel(i);
initDefaultChannel(0);
}
void Channels::onConfigChanged()
{
// Make sure the phone hasn't mucked anything up
2021-03-11 05:02:00 +00:00
for (int i = 0; i < channelFile.channels_count; i++) {
const meshtastic_Channel &ch = fixupChannel(i);
2021-02-16 07:41:52 +00:00
if (ch.role == meshtastic_Channel_Role_PRIMARY)
2021-02-16 07:41:52 +00:00
primaryIndex = i;
}
if (channels.anyMqttEnabled() && mqtt && !mqtt->isEnabled()) {
LOG_DEBUG("MQTT is enabled on at least one channel, so set MQTT thread to run immediately\n");
mqtt->start();
}
2021-02-16 07:41:52 +00:00
}
meshtastic_Channel &Channels::getByIndex(ChannelIndex chIndex)
2021-02-16 07:41:52 +00:00
{
2023-01-07 12:16:58 +00:00
// remove this assert cause malformed packets can make our firmware reboot here.
if (chIndex < channelFile.channels_count) { // This should be equal to MAX_NUM_CHANNELS
meshtastic_Channel *ch = channelFile.channels + chIndex;
2023-01-07 12:16:58 +00:00
return *ch;
} else {
2023-01-21 13:34:29 +00:00
LOG_ERROR("Invalid channel index %d > %d, malformed packet received?\n", chIndex, channelFile.channels_count);
2023-01-07 12:16:58 +00:00
static meshtastic_Channel *ch = (meshtastic_Channel *)malloc(sizeof(meshtastic_Channel));
memset(ch, 0, sizeof(meshtastic_Channel));
2023-01-07 12:16:58 +00:00
// ch.index -1 means we don't know the channel locally and need to look it up by settings.name
// not sure this is handled right everywhere
ch->index = -1;
return *ch;
}
2021-02-16 07:41:52 +00:00
}
meshtastic_Channel &Channels::getByName(const char *chName)
2022-12-28 14:30:23 +00:00
{
for (ChannelIndex i = 0; i < getNumChannels(); i++) {
if (strcasecmp(getGlobalId(i), chName) == 0) {
2022-12-28 14:30:23 +00:00
return channelFile.channels[i];
}
}
return getByIndex(getPrimaryIndex());
}
void Channels::setChannel(const meshtastic_Channel &c)
2021-02-22 03:16:38 +00:00
{
meshtastic_Channel &old = getByIndex(c.index);
2021-02-16 07:41:52 +00:00
// if this is the new primary, demote any existing roles
if (c.role == meshtastic_Channel_Role_PRIMARY)
for (int i = 0; i < getNumChannels(); i++)
if (channelFile.channels[i].role == meshtastic_Channel_Role_PRIMARY)
channelFile.channels[i].role = meshtastic_Channel_Role_SECONDARY;
2021-02-16 07:41:52 +00:00
old = c; // slam in the new settings/role
}
bool Channels::anyMqttEnabled()
{
for (int i = 0; i < getNumChannels(); i++)
if (channelFile.channels[i].role != meshtastic_Channel_Role_DISABLED && channelFile.channels[i].has_settings &&
(channelFile.channels[i].settings.downlink_enabled || channelFile.channels[i].settings.uplink_enabled))
return true;
return false;
}
2021-02-16 07:41:52 +00:00
const char *Channels::getName(size_t chIndex)
{
// Convert the short "" representation for Default into a usable string
const meshtastic_ChannelSettings &channelSettings = getByIndex(chIndex).settings;
2021-02-16 07:41:52 +00:00
const char *channelName = channelSettings.name;
if (!*channelName) { // emptystring
2022-05-07 10:31:21 +00:00
// Per mesh.proto spec, if bandwidth is specified we must ignore modemPreset enum, we assume that in that case
// the app effed up and forgot to set channelSettings.name
if (config.lora.use_preset) {
channelName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
2023-01-21 13:34:29 +00:00
} else {
channelName = "Custom";
}
2021-02-16 07:41:52 +00:00
}
return channelName;
}
bool Channels::hasDefaultChannel()
{
// If we don't use a preset or the default frequency slot, or we override the frequency, we don't have a default channel
if (!config.lora.use_preset || !RadioInterface::uses_default_frequency_slot || config.lora.override_frequency)
return false;
// Check if any of the channels are using the default name and PSK
for (size_t i = 0; i < getNumChannels(); i++) {
const auto &ch = getByIndex(i);
if (ch.settings.psk.size == 1 && ch.settings.psk.bytes[0] == 1) {
const char *name = getName(i);
const char *presetName = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false);
// Check if the name is the default derived from the modem preset
if (strcmp(name, presetName) == 0)
return true;
}
}
return false;
}
2021-02-22 04:57:26 +00:00
/** Given a channel hash setup crypto for decoding that channel (or the primary channel if that channel is unsecured)
*
* This method is called before decoding inbound packets
*
* @return false if the channel hash or channel is invalid
2021-02-22 04:57:26 +00:00
*/
bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash)
2021-02-23 02:10:35 +00:00
{
if (chIndex > getNumChannels() || getHash(chIndex) != channelHash) {
2022-12-30 02:41:37 +00:00
// LOG_DEBUG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex),
// channelHash);
return false;
} else {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Using channel %d (hash 0x%x)\n", chIndex, channelHash);
setCrypto(chIndex);
return true;
}
2021-02-23 02:10:35 +00:00
}
2021-02-22 04:57:26 +00:00
/** Given a channel index setup crypto for encoding that channel (or the primary channel if that channel is unsecured)
*
* This method is called before encoding outbound packets
*
* @eturn the (0 to 255) hash for that channel - if no suitable channel could be found, return -1
*/
2021-02-23 02:10:35 +00:00
int16_t Channels::setActiveByIndex(ChannelIndex channelIndex)
{
return setCrypto(channelIndex);
}