mirror of
https://github.com/meshtastic/firmware.git
synced 2026-10-30 20:09:18 -04:00
The handshake's third message must be PKI-encrypted, and licensed operation neither sends nor decrypts PKI. A licensed node still opened a session, raised the security-number prompt, and waited until it timed out. A licensed node now refuses to start a session, from the admin message or the screen, and tells the client why. It ignores a remote node's request without a NAK, as a busy node does. The screen's node menu hides the Key Verification entry in licensed mode. Claude-Session: https://claude.ai/code/session_011DjtCrF8NLMGs9DtEVQkUK Co-authored-by: Claude <noreply@anthropic.com>
113 lines
3.6 KiB
C++
113 lines
3.6 KiB
C++
// Tests for KeyVerificationModule's refusal to run in licensed (ham) mode.
|
|
//
|
|
// Pinned: a licensed node starts no key verification session - neither one the user asks for
|
|
// (sendInitialRequest, reached from the admin INITIATE_VERIFICATION message and the screen menu)
|
|
// nor one a remote node requests (allocReply). The user is told why; the remote gets no reply and
|
|
// no NAK, as against a busy node.
|
|
//
|
|
// Why: the handshake's third message must be PKI-encrypted, and licensed operation neither sends
|
|
// nor decrypts PKI. Before this guard a licensed node opened the session, raised the security-number
|
|
// prompt, and then waited for a message that could never arrive until the session timed out.
|
|
//
|
|
// The refusal has to come before the module touches NodeDB, the router or the RNG. This suite runs
|
|
// with all three unset, so a regression that lets either path proceed fails here - as a crash on the
|
|
// first dereference if not an assertion - rather than passing silently.
|
|
|
|
#include "MeshTypes.h" // include BEFORE TestUtil.h
|
|
#include "TestUtil.h"
|
|
#include <unity.h>
|
|
|
|
#if !(MESHTASTIC_EXCLUDE_PKI)
|
|
|
|
#include "mesh/MeshService.h"
|
|
#include "mesh/NodeDB.h"
|
|
#include "mesh/Router.h"
|
|
#include "modules/KeyVerificationModule.h"
|
|
#include "support/MockMeshService.h"
|
|
|
|
namespace
|
|
{
|
|
constexpr NodeNum REMOTE_NODE = 0x22222222;
|
|
|
|
// Exposes the reply hook and the request slot MeshModule::callModules() would normally fill.
|
|
class TestKeyVerificationModule : public KeyVerificationModule
|
|
{
|
|
public:
|
|
using KeyVerificationModule::allocReply;
|
|
using MeshModule::currentRequest;
|
|
bool requestIgnored() const { return ignoreRequest; }
|
|
};
|
|
|
|
TestKeyVerificationModule *module;
|
|
MockMeshService *mockService;
|
|
} // namespace
|
|
|
|
void setUp(void)
|
|
{
|
|
owner = meshtastic_User_init_zero;
|
|
owner.is_licensed = true;
|
|
nodeDB = nullptr;
|
|
router = nullptr;
|
|
mockService = new MockMeshService();
|
|
service = mockService;
|
|
module = new TestKeyVerificationModule();
|
|
}
|
|
|
|
void tearDown(void)
|
|
{
|
|
TestKeyVerificationModule::currentRequest = nullptr;
|
|
delete module;
|
|
module = nullptr;
|
|
delete mockService;
|
|
mockService = nullptr;
|
|
service = nullptr;
|
|
owner = meshtastic_User_init_zero;
|
|
}
|
|
|
|
// The user's request (admin message or screen menu) is refused, and the client is told why.
|
|
void test_licensed_initiate_is_refused_and_reported(void)
|
|
{
|
|
TEST_ASSERT_FALSE_MESSAGE(module->sendInitialRequest(REMOTE_NODE), "a licensed node must not start key verification");
|
|
TEST_ASSERT_EQUAL_MESSAGE(1, mockService->notificationCount, "the client must be told why nothing happened");
|
|
}
|
|
|
|
// A remote node's request opens no session and gets no reply or NAK.
|
|
void test_licensed_incoming_request_gets_no_reply(void)
|
|
{
|
|
meshtastic_MeshPacket request = meshtastic_MeshPacket_init_zero;
|
|
request.from = REMOTE_NODE;
|
|
request.which_payload_variant = meshtastic_MeshPacket_decoded_tag;
|
|
request.decoded.portnum = meshtastic_PortNum_KEY_VERIFICATION_APP;
|
|
request.decoded.want_response = true;
|
|
TestKeyVerificationModule::currentRequest = &request;
|
|
|
|
TEST_ASSERT_NULL_MESSAGE(module->allocReply(), "a licensed node must not answer a key verification request");
|
|
TEST_ASSERT_TRUE_MESSAGE(module->requestIgnored(), "the refusal must not NAK the requester");
|
|
TEST_ASSERT_EQUAL(0, mockService->notificationCount);
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
initializeTestEnvironment();
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_licensed_initiate_is_refused_and_reported);
|
|
RUN_TEST(test_licensed_incoming_request_gets_no_reply);
|
|
exit(UNITY_END());
|
|
}
|
|
|
|
#else
|
|
|
|
void setUp(void) {}
|
|
void tearDown(void) {}
|
|
|
|
void setup()
|
|
{
|
|
initializeTestEnvironment();
|
|
UNITY_BEGIN();
|
|
exit(UNITY_END());
|
|
}
|
|
|
|
#endif
|
|
|
|
void loop() {}
|