10static const char*
TAG =
"GPG_SCERT";
15constexpr const char* kNamespace =
"gpg_selfcert";
16constexpr const char* kKeyPrefix =
"ct_";
18bool hasKeyPrefix(
const char* k) {
19 return k && std::strncmp(k, kKeyPrefix, 3) == 0;
24 static GpgSelfCertStore inst;
28void GpgSelfCertStore::deriveKeyName(
const uint8_t issuer_fp_v4[20],
char out[16]) {
29 std::snprintf(out, 16,
"%s%02x%02x%02x%02x",
30 kKeyPrefix, issuer_fp_v4[0], issuer_fp_v4[1],
31 issuer_fp_v4[2], issuer_fp_v4[3]);
34bool GpgSelfCertStore::readByName(
const char* nvs_key, gpg_self_cert_t* out) {
35 if (!nvs_key || !out)
return false;
37 if (!nvs)
return false;
38 size_t expected =
sizeof(gpg_self_cert_t);
39 if (nvs_get_blob(nvs, nvs_key, out, &expected) != ESP_OK)
return false;
40 return expected ==
sizeof(gpg_self_cert_t);
43bool GpgSelfCertStore::writeByName(
const char* nvs_key,
const gpg_self_cert_t& cert) {
44 if (!nvs_key)
return false;
46 if (!nvs)
return false;
47 if (nvs_set_blob(nvs, nvs_key, &cert,
sizeof(cert)) != ESP_OK)
return false;
48 return nvs.commit() == ESP_OK;
58 bool exists = readByName(
name, &probe);
63 return writeByName(
name, cert);
67 nvs_iterator_t it =
nullptr;
68 if (nvs_entry_find(
"nvs", kNamespace, NVS_TYPE_BLOB, &it) != ESP_OK || !it) {
72 while (it !=
nullptr) {
73 nvs_entry_info_t info = {};
74 nvs_entry_info(it, &info);
75 if (hasKeyPrefix(info.key)) ++n;
77 if (nvs_entry_next(&it) != ESP_OK)
break;
79 nvs_release_iterator(it);
84 if (!out || max == 0)
return 0;
86 nvs_iterator_t it =
nullptr;
87 if (nvs_entry_find(
"nvs", kNamespace, NVS_TYPE_BLOB, &it) != ESP_OK || !it) {
92 while (it !=
nullptr && n < max) {
93 nvs_entry_info_t info = {};
94 nvs_entry_info(it, &info);
95 if (hasKeyPrefix(info.key)) {
97 if (readByName(info.key, &c)) {
98 std::snprintf(out[n].nvs_key,
sizeof(out[n].nvs_key),
"%s", info.key);
103 if (nvs_entry_next(&it) != ESP_OK)
break;
105 nvs_release_iterator(it);
107 std::sort(out, out + n,
114bool GpgSelfCertStore::resolveKeyName(uint8_t index,
char out[16]) {
116 if (!buf)
return false;
118 if (index >= n)
return false;
119 std::snprintf(out, 16,
"%s", buf[index].nvs_key);
124 if (!out)
return false;
126 if (!resolveKeyName(index,
name))
return false;
127 return readByName(
name, out);
132 if (!resolveKeyName(index,
name))
return false;
135 if (!nvs)
return false;
136 if (nvs_erase_key(nvs,
name) != ESP_OK)
return false;
137 return nvs.
commit() == ESP_OK;
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]
Shared RAII wrappers for firmware resources.
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_W(tag, fmt,...)
RAII wrapper for an NVS handle.
esp_err_t commit() noexcept
Commit pending writes. Caller checks the return value if needed.
uint8_t count()
Number of stored certifications.
static GpgSelfCertStore & instance()
uint8_t listIndex(gpg_self_cert_index_entry_t *out, uint8_t max)
Build the sorted index (oldest first).
bool getCert(uint8_t index, gpg_self_cert_t *out)
Load one certification by sorted index (0..count()-1).
bool deleteCert(uint8_t index)
Remove one certification by sorted index. No-op if out of range.
static constexpr uint8_t kMaxCerts
Hard ceiling. Past this addCert rejects further inserts.
bool addCert(const gpg_self_cert_t &cert)
Persist a certification. Replaces an existing entry from the same issuer.
PsramUniquePtr< T > psramAlloc(std::size_t count) noexcept
Allocate count elements of T in PSRAM (8-bit capable region).
constexpr size_t kGpgSelfCertSigMax
Maximum length of a stored certification signature packet body (Tag 2).
Sort entry exposing a stable ordered index over the NVS blobs.
One third-party certification received over the badge's own key.
uint32_t received_at
Receive timestamp (RTC).
uint16_t sig_pkt_len
Length of sig_pkt.
uint8_t issuer_fp_v4[20]
Issuer (signer) v4 fingerprint.