CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
GpgSelfCertStore.cpp
Go to the documentation of this file.
2#include "cdc_core/Raii.h"
3#include "cdc_log.h"
4#include "nvs.h"
5#include "nvs_flash.h"
6#include <algorithm>
7#include <cstdio>
8#include <cstring>
9
10static const char* TAG = "GPG_SCERT";
11
12namespace cdc::mod_gpg {
13
14namespace {
15constexpr const char* kNamespace = "gpg_selfcert";
16constexpr const char* kKeyPrefix = "ct_";
17
18bool hasKeyPrefix(const char* k) {
19 return k && std::strncmp(k, kKeyPrefix, 3) == 0;
20}
21} // namespace
22
23GpgSelfCertStore& GpgSelfCertStore::instance() {
24 static GpgSelfCertStore inst;
25 return inst;
26}
27
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]);
32}
33
34bool GpgSelfCertStore::readByName(const char* nvs_key, gpg_self_cert_t* out) {
35 if (!nvs_key || !out) return false;
36 ::cdc::core::NvsScope nvs(kNamespace, NVS_READONLY);
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);
41}
42
43bool GpgSelfCertStore::writeByName(const char* nvs_key, const gpg_self_cert_t& cert) {
44 if (!nvs_key) return false;
45 ::cdc::core::NvsScope nvs(kNamespace, NVS_READWRITE);
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;
49}
50
52 if (cert.sig_pkt_len == 0 || cert.sig_pkt_len > kGpgSelfCertSigMax) return false;
53
54 char name[16];
55 deriveKeyName(cert.issuer_fp_v4, name);
56
57 gpg_self_cert_t probe;
58 bool exists = readByName(name, &probe);
59 if (!exists && count() >= kMaxCerts) {
60 LOG_W(TAG, "Store full (%u certs)", static_cast<unsigned>(kMaxCerts));
61 return false;
62 }
63 return writeByName(name, cert);
64}
65
67 nvs_iterator_t it = nullptr;
68 if (nvs_entry_find("nvs", kNamespace, NVS_TYPE_BLOB, &it) != ESP_OK || !it) {
69 return 0;
70 }
71 uint8_t n = 0;
72 while (it != nullptr) {
73 nvs_entry_info_t info = {};
74 nvs_entry_info(it, &info);
75 if (hasKeyPrefix(info.key)) ++n;
76 if (n >= kMaxCerts) break;
77 if (nvs_entry_next(&it) != ESP_OK) break;
78 }
79 nvs_release_iterator(it);
80 return n;
81}
82
84 if (!out || max == 0) return 0;
85
86 nvs_iterator_t it = nullptr;
87 if (nvs_entry_find("nvs", kNamespace, NVS_TYPE_BLOB, &it) != ESP_OK || !it) {
88 return 0;
89 }
90
91 uint8_t n = 0;
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);
99 out[n].received_at = c.received_at;
100 ++n;
101 }
102 }
103 if (nvs_entry_next(&it) != ESP_OK) break;
104 }
105 nvs_release_iterator(it);
106
107 std::sort(out, out + n,
109 return a.received_at < b.received_at;
110 });
111 return n;
112}
113
114bool GpgSelfCertStore::resolveKeyName(uint8_t index, char out[16]) {
116 if (!buf) return false;
117 uint8_t n = listIndex(buf.get(), kMaxCerts);
118 if (index >= n) return false;
119 std::snprintf(out, 16, "%s", buf[index].nvs_key);
120 return true;
121}
122
124 if (!out) return false;
125 char name[16];
126 if (!resolveKeyName(index, name)) return false;
127 return readByName(name, out);
128}
129
130bool GpgSelfCertStore::deleteCert(uint8_t index) {
131 char name[16];
132 if (!resolveKeyName(index, name)) return false;
133
134 ::cdc::core::NvsScope nvs(kNamespace, NVS_READWRITE);
135 if (!nvs) return false;
136 if (nvs_erase_key(nvs, name) != ESP_OK) return false;
137 return nvs.commit() == ESP_OK;
138}
139
140} // namespace cdc::mod_gpg
static const char * TAG
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,...)
Definition cdc_log.h:146
RAII wrapper for an NVS handle.
Definition Raii.h:106
esp_err_t commit() noexcept
Commit pending writes. Caller checks the return value if needed.
Definition Raii.h:153
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).
Definition Raii.h:51
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.
uint32_t received_at
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.