diff options
Diffstat (limited to 'src/btfaddr.cpp')
| -rw-r--r-- | src/btfaddr.cpp | 40 |
1 files changed, 26 insertions, 14 deletions
diff --git a/src/btfaddr.cpp b/src/btfaddr.cpp index ce2ac86..502220e 100644 --- a/src/btfaddr.cpp +++ b/src/btfaddr.cpp | |||
| @@ -319,20 +319,32 @@ bool VerifyDescriptor(void* ctxv, const std::string& jsonStr, | |||
| 319 | std::string onion; | 319 | std::string onion; |
| 320 | if (v.contains("onion")) | 320 | if (v.contains("onion")) |
| 321 | { | 321 | { |
| 322 | if (v["onion"].is_string() && v.contains("sig3") && v["sig3"].is_string()) | 322 | // A descriptor that carries an onion endpoint must prove it. The |
| 323 | { | 323 | // endpoint is covered by sig3 and only sig3, so any failure here -- |
| 324 | std::string onionNorm; | 324 | // missing sig3, bad hex, unnormalised endpoint, bad signature -- |
| 325 | std::string onionRaw = v["onion"].get<std::string>(); | 325 | // means the descriptor was tampered with, and a tampered |
| 326 | if (NormalizeOnionEndpoint(onionRaw, onionNorm) && onionNorm == onionRaw) | 326 | // descriptor is rejected outright. Upstream dropped just the onion |
| 327 | { | 327 | // and accepted the rest, which let any relay convert an onion |
| 328 | unsigned char sig3[64]; | 328 | // descriptor into a rendezvous-only one by deleting a field. |
| 329 | unsigned char digest3[32]; | 329 | // |
| 330 | DescriptorDigestV3(expect_pubkey, enc, meeting_node, onionNorm, created, digest3); | 330 | // Residual, by design: removing BOTH "onion" and "sig3" still |
| 331 | if (HexDecode(v["sig3"].get<std::string>(), sig3, 64) && | 331 | // verifies, because the result is indistinguishable from a peer |
| 332 | secp256k1_schnorrsig_verify(ctx, sig3, digest3, 32, &xpub)) | 332 | // that never had an onion endpoint. Closing that requires binding |
| 333 | onion = onionNorm; | 333 | // the onion into the primary sig (the V2 digest), which every |
| 334 | } | 334 | // upstream 1.2.18/1.2.19 verifier would reject -- an upstream |
| 335 | } | 335 | // protocol change, not something this fork can do unilaterally. |
| 336 | if (!v["onion"].is_string()) return false; | ||
| 337 | if (!v.contains("sig3") || !v["sig3"].is_string()) return false; | ||
| 338 | std::string onionNorm; | ||
| 339 | std::string onionRaw = v["onion"].get<std::string>(); | ||
| 340 | if (!NormalizeOnionEndpoint(onionRaw, onionNorm) || onionNorm != onionRaw) | ||
| 341 | return false; | ||
| 342 | unsigned char sig3[64]; | ||
| 343 | unsigned char digest3[32]; | ||
| 344 | DescriptorDigestV3(expect_pubkey, enc, meeting_node, onionNorm, created, digest3); | ||
| 345 | if (!HexDecode(v["sig3"].get<std::string>(), sig3, 64)) return false; | ||
| 346 | if (!secp256k1_schnorrsig_verify(ctx, sig3, digest3, 32, &xpub)) return false; | ||
| 347 | onion = onionNorm; | ||
| 336 | } | 348 | } |
| 337 | 349 | ||
| 338 | memcpy(out.pubkey, expect_pubkey, 32); | 350 | memcpy(out.pubkey, expect_pubkey, 32); |