CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
CapabilityChecker.cpp
Go to the documentation of this file.
4
5#include <cctype>
6
7namespace cdc::plugin_manager {
8
9namespace {
10
11// ESP-IDF NVS namespace identifier is bounded to 15 chars + NUL.
12constexpr size_t NVS_NAMESPACE_MAX_LEN = 15;
13
14// rmem slot name fits the on-chip 16-byte name field minus trailing NUL.
15constexpr size_t RMEM_NAME_MAX_LEN = HOST_RMEM_NAME_MAX;
16
17// Plugin linear memory and runtime structures live in PSRAM (Fast Interpreter).
18// This range-checks the manifest's linear_memory_kb; the operand+frame stack is
19// a fixed 64 KB allocated in Plugin.cpp.
20constexpr uint32_t LINEAR_MEMORY_MIN_KB = 16;
21constexpr uint32_t LINEAR_MEMORY_MAX_KB = 4096;
22
23// 8-4-4-4-12 lowercase hex with dashes, e.g. "0000180a-0000-1000-8000-00805f9b34fb".
24bool isValidUuid128(const std::string& s)
25{
26 static constexpr size_t kLen = 36;
27 static constexpr size_t kDashPos[] = {8, 13, 18, 23};
28 if (s.size() != kLen) return false;
29 for (size_t pos : kDashPos) if (s[pos] != '-') return false;
30 for (size_t i = 0; i < kLen; ++i) {
31 if (i == 8 || i == 13 || i == 18 || i == 23) continue;
32 char c = s[i];
33 bool digit = (c >= '0' && c <= '9');
34 bool lower = (c >= 'a' && c <= 'f');
35 if (!digit && !lower) return false;
36 }
37 return true;
38}
39
40} // namespace
41
43{
47 "plugin needs API " + m.host_api_level_min +
48 ", firmware provides " + std::string(HOST_API_LEVEL_STR) };
49 }
50
51 if (m.linear_memory_kb < LINEAR_MEMORY_MIN_KB ||
52 m.linear_memory_kb > LINEAR_MEMORY_MAX_KB) {
54 "linear_memory_kb out of [" +
55 std::to_string(LINEAR_MEMORY_MIN_KB) + ", " +
56 std::to_string(LINEAR_MEMORY_MAX_KB) + "]" };
57 }
58
59 for (const std::string& name : m.capabilities.rmem) {
60 if (name.empty() || name.size() > RMEM_NAME_MAX_LEN) {
62 "rmem name '" + name + "' must be 1-" +
63 std::to_string(RMEM_NAME_MAX_LEN) + " chars" };
64 }
65 }
66
67 for (const std::string& name : m.capabilities.ecc) {
68 if (name.empty() || name.size() > HOST_ECC_NAME_MAX) {
70 "ecc name '" + name + "' must be 1-" +
71 std::to_string(HOST_ECC_NAME_MAX) + " chars" };
72 }
73 }
74
75 for (uint8_t pin : m.capabilities.gpio_pins) {
76 if (gpio_policy::isBlocked(pin)) {
78 "GPIO " + std::to_string(pin) + " is reserved by firmware hardware" };
79 }
80 if (!gpio_policy::isAllowed(pin)) {
82 "GPIO " + std::to_string(pin) + " not on plugin whitelist" };
83 }
84 }
85
86 for (uint8_t pin : m.capabilities.pwm_pins) {
87 if (gpio_policy::isBlocked(pin)) {
89 "PWM pin " + std::to_string(pin) + " is reserved by firmware hardware" };
90 }
91 if (!gpio_policy::isAllowed(pin)) {
93 "PWM pin " + std::to_string(pin) + " not on plugin whitelist" };
94 }
95 }
96
97 for (uint8_t pin : m.capabilities.adc_pins) {
98 if (gpio_policy::isBlocked(pin)) {
100 "ADC pin " + std::to_string(pin) + " is reserved by firmware hardware" };
101 }
102 if (!gpio_policy::isAllowed(pin)) {
104 "ADC pin " + std::to_string(pin) + " not on plugin whitelist" };
105 }
106 }
107
108 for (uint8_t bus : m.capabilities.i2c_bus) {
109 // Bus 0 is the internal charger + IO expander bus. Plugins must never
110 // touch it - that bus controls power and IO expansion.
111 if (bus == 0) {
113 "I2C bus 0 is reserved for internal hardware" };
114 }
115 }
116
117 if (!m.capabilities.nvs_namespace.empty()) {
118 const auto& ns = m.capabilities.nvs_namespace;
119 if (ns.size() > NVS_NAMESPACE_MAX_LEN) {
121 "nvs_namespace exceeds " +
122 std::to_string(NVS_NAMESPACE_MAX_LEN) + " chars" };
123 }
124 const bool prefixOk = ns.rfind("plg_", 0) == 0 ||
125 ns.rfind("plugin_", 0) == 0;
126 if (!prefixOk) {
128 "nvs_namespace must start with 'plg_' or 'plugin_'" };
129 }
130 for (char c : ns) {
131 bool ok = (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_';
132 if (!ok) {
134 "nvs_namespace must be [a-z0-9_]" };
135 }
136 }
137 } else if (!m.capabilities.rmem.empty()) {
139 "nvs_namespace required when persistent state used" };
140 }
141
142 for (const auto& uuid : m.capabilities.ble_service_uuids) {
143 if (!isValidUuid128(uuid)) {
145 "ble_service_uuid '" + uuid +
146 "' not a 128-bit lowercase UUID" };
147 }
148 }
149
150 return { CapabilityResult::Ok, {} };
151}
152
153} // namespace cdc::plugin_manager
Load-time validation of plugin capabilities + manifest sanity.
Single source of truth for plugin-accessible GPIO pins.
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]
static CapabilityCheckResult validate(const PluginManifest &manifest)
#define HOST_ECC_NAME_MAX
Definition host_api.h:281
#define HOST_RMEM_NAME_MAX
Definition host_api.h:249
CDC Badge OS plugin host API - canonical C ABI contract.
#define HOST_API_LEVEL_MAJOR
Definition host_api.h:28
#define HOST_API_LEVEL_STR
Definition host_api.h:30
#define HOST_API_LEVEL_MINOR
Definition host_api.h:29
std::vector< std::string > ble_service_uuids