Use hardware RNG for session passkey and PKC extra nonce (#11047)
* Use hardware RNG for session passkey and PKC extra nonce The admin session passkey and the Curve25519 extra nonce were drawn from Arduino random(), which is not a CSPRNG. Source them from HardwareRNG::fill, mirroring the signing path, and fall back to the seeded CSPRNG (CryptRNG) only when no hardware source is available. * AdminModule: make session passkey expiry rollover-safe session_time was compared as millis()/1000 seconds with additive thresholds, which breaks across the millis() wrap and could keep a stale admin session key valid. Store session_time in millis() and use Throttle::isWithinTimespanMs for the 150s refresh and 300s validity windows. * AdminModule: track session passkey validity with an explicit flag session_time == 0 was used as the uninitialized sentinel, but millis() is legitimately 0 in the first millisecond of uptime, so a passkey issued then would be treated as no session. Use a dedicated session_passkey_valid flag instead. * AdminModule: camelCase the session passkey validity flag --------- Co-authored-by: Ben Meadors <benmmeadors@gmail.com>
This commit is contained in:
co-authored by
GitHub
Ben Meadors
parent
ac027ec5ca
commit
d4aa7760cc
@@ -1,6 +1,7 @@
|
||||
#include "AdminModule.h"
|
||||
#include "Channels.h"
|
||||
#include "DisplayFormatters.h"
|
||||
#include "HardwareRNG.h"
|
||||
#include "MeshService.h"
|
||||
#include "NodeDB.h"
|
||||
#include "PositionPrecision.h"
|
||||
@@ -49,6 +50,9 @@
|
||||
#include "GPS.h"
|
||||
#endif
|
||||
|
||||
#include <RNG.h> // CryptRNG, the seeded CSPRNG used as fallback for the session passkey
|
||||
#include <Throttle.h> // rollover-safe elapsed-time checks for the session passkey
|
||||
|
||||
#if MESHTASTIC_EXCLUDE_GPS
|
||||
#include "modules/PositionModule.h"
|
||||
#endif
|
||||
@@ -1792,11 +1796,15 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP
|
||||
|
||||
void AdminModule::setPassKey(meshtastic_AdminMessage *res)
|
||||
{
|
||||
if (session_time == 0 || millis() / 1000 > session_time + 150) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
session_passkey[i] = random();
|
||||
}
|
||||
session_time = millis() / 1000;
|
||||
// Regenerate once there is no session yet or the current key is older than 150s. session_time
|
||||
// holds millis(); the Throttle check is rollover-safe, unlike the previous seconds comparison.
|
||||
if (!sessionPasskeyValid || !Throttle::isWithinTimespanMs(session_time, 150 * 1000UL)) {
|
||||
// Session passkey authenticates admin replies, so it must be unpredictable: prefer the
|
||||
// hardware RNG, falling back to the seeded CSPRNG only when no hardware source exists.
|
||||
if (!HardwareRNG::fill(session_passkey, sizeof(session_passkey)))
|
||||
CryptRNG.rand(session_passkey, sizeof(session_passkey));
|
||||
session_time = millis();
|
||||
sessionPasskeyValid = true;
|
||||
}
|
||||
memcpy(res->session_passkey.bytes, session_passkey, 8);
|
||||
res->session_passkey.size = 8;
|
||||
@@ -1809,7 +1817,8 @@ bool AdminModule::checkPassKey(meshtastic_AdminMessage *res)
|
||||
{ // check that the key in the packet is still valid
|
||||
printBytes("Incoming session key: ", res->session_passkey.bytes, 8);
|
||||
printBytes("Expected session key: ", session_passkey, 8);
|
||||
return (session_time + 300 > millis() / 1000 && res->session_passkey.size == 8 &&
|
||||
// Key is valid for 300s from issue; sessionPasskeyValid guards an unissued session.
|
||||
return (sessionPasskeyValid && Throttle::isWithinTimespanMs(session_time, 300 * 1000UL) && res->session_passkey.size == 8 &&
|
||||
memcmp(res->session_passkey.bytes, session_passkey, 8) == 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@ class AdminModule : public ProtobufModule<meshtastic_AdminMessage>, public Obser
|
||||
bool hasOpenEditTransaction = false;
|
||||
|
||||
uint8_t session_passkey[8] = {0};
|
||||
uint session_time = 0;
|
||||
uint32_t session_time = 0; // millis() when the current session passkey was issued
|
||||
bool sessionPasskeyValid = false; // separate flag: millis() 0 at boot is a valid issue time
|
||||
|
||||
void saveChanges(int saveWhat, bool shouldReboot = true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user