upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBitflash <btf01@proton.me>2026-07-28 12:25:29 -0300
committerGitHub <noreply@github.com>2026-07-28 12:25:29 -0300
commit1d0314c0d220231afc56193ba66b70234fa24092 (patch)
tree622bfdb3f3f7d442b08d83fdf613d4ea717135d3 /src
parentebb793b0c513e5ee0298228b0185b4bada842513 (diff)
btfaddr: reject malformed descriptors instead of throwing (#8)
VerifyDescriptor() parses descriptors received from untrusted peers over Nostr relays. Only json::parse() was guarded; the field extractions (get<std::string>, get<uint64_t>) ran unguarded, so a descriptor with a wrong-typed field (e.g. a numeric "pubkey") threw an uncaught nlohmann::json::type_error -- a remotely triggerable crash vector. Validate each field's type up front and wrap the whole parse in try/catch so any malformed descriptor is rejected (return false), never thrown.
Diffstat (limited to 'src')
-rw-r--r--src/btfaddr.cpp70
1 files changed, 41 insertions, 29 deletions
diff --git a/src/btfaddr.cpp b/src/btfaddr.cpp
index 5f983bc..55bb6c5 100644
--- a/src/btfaddr.cpp
+++ b/src/btfaddr.cpp
@@ -214,35 +214,47 @@ bool VerifyDescriptor(void* ctxv, const std::string& jsonStr,
214 const unsigned char expect_pubkey[32], Descriptor& out) 214 const unsigned char expect_pubkey[32], Descriptor& out)
215{ 215{
216 secp256k1_context* ctx = (secp256k1_context*)ctxv; 216 secp256k1_context* ctx = (secp256k1_context*)ctxv;
217 json v; 217 // Descriptors arrive from untrusted peers (via Nostr relays). Guard the whole
218 try { v = json::parse(jsonStr); } catch (...) { return false; } 218 // parse: a malformed or wrong-typed field must be rejected, never throw.
219 if (!v.is_object()) return false; 219 try
220 if (!v.contains("pubkey") || !v.contains("enc") || !v.contains("meeting_node") 220 {
221 || !v.contains("created") || !v.contains("sig")) return false; 221 json v = json::parse(jsonStr);
222 222 if (!v.is_object()) return false;
223 unsigned char pubkey[32]; 223 if (!v.contains("pubkey") || !v.contains("enc") || !v.contains("meeting_node")
224 if (!HexDecode(v["pubkey"].get<std::string>(), pubkey, 32)) return false; 224 || !v.contains("created") || !v.contains("sig")) return false;
225 if (memcmp(pubkey, expect_pubkey, 32) != 0) return false; // descriptor is for a different key 225 // Reject wrong field types before extracting (json::get would otherwise throw).
226 226 if (!v["pubkey"].is_string() || !v["enc"].is_string() ||
227 std::string enc = v["enc"].get<std::string>(); 227 !v["meeting_node"].is_string() || !v["sig"].is_string() ||
228 std::string meeting_node = v["meeting_node"].get<std::string>(); 228 !v["created"].is_number_unsigned()) return false;
229 uint64_t created = v["created"].get<uint64_t>(); 229
230 230 unsigned char pubkey[32];
231 unsigned char sig[64]; 231 if (!HexDecode(v["pubkey"].get<std::string>(), pubkey, 32)) return false;
232 if (!HexDecode(v["sig"].get<std::string>(), sig, 64)) return false; 232 if (memcmp(pubkey, expect_pubkey, 32) != 0) return false; // descriptor is for a different key
233 233
234 unsigned char digest[32]; 234 std::string enc = v["enc"].get<std::string>();
235 DescriptorDigest(expect_pubkey, enc, meeting_node, created, digest); 235 std::string meeting_node = v["meeting_node"].get<std::string>();
236 236 uint64_t created = v["created"].get<uint64_t>();
237 secp256k1_xonly_pubkey xpub; 237
238 if (!secp256k1_xonly_pubkey_parse(ctx, &xpub, expect_pubkey)) return false; 238 unsigned char sig[64];
239 if (!secp256k1_schnorrsig_verify(ctx, sig, digest, 32, &xpub)) return false; 239 if (!HexDecode(v["sig"].get<std::string>(), sig, 64)) return false;
240 240
241 memcpy(out.pubkey, expect_pubkey, 32); 241 unsigned char digest[32];
242 out.enc = enc; 242 DescriptorDigest(expect_pubkey, enc, meeting_node, created, digest);
243 out.meeting_node = meeting_node; 243
244 out.created = created; 244 secp256k1_xonly_pubkey xpub;
245 return true; 245 if (!secp256k1_xonly_pubkey_parse(ctx, &xpub, expect_pubkey)) return false;
246 if (!secp256k1_schnorrsig_verify(ctx, sig, digest, 32, &xpub)) return false;
247
248 memcpy(out.pubkey, expect_pubkey, 32);
249 out.enc = enc;
250 out.meeting_node = meeting_node;
251 out.created = created;
252 return true;
253 }
254 catch (...)
255 {
256 return false; // malformed / wrong-typed descriptor -> reject, don't crash
257 }
246} 258}
247 259
248} // namespace btf 260} // namespace btf