diff options
Diffstat (limited to 'src/nostr.cpp')
| -rw-r--r-- | src/nostr.cpp | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/src/nostr.cpp b/src/nostr.cpp index 47f001c..fbae1a6 100644 --- a/src/nostr.cpp +++ b/src/nostr.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include "headers.h" | 6 | #include "headers.h" |
| 7 | #include <openssl/ssl.h> | 7 | #include <openssl/ssl.h> |
| 8 | #include <openssl/err.h> | 8 | #include <openssl/err.h> |
| 9 | #include <openssl/x509.h> | ||
| 9 | // We link libsecp256k1 statically (without this the header assumes DLL import). | 10 | // We link libsecp256k1 statically (without this the header assumes DLL import). |
| 10 | // Both makefiles also pass -DSECP256K1_STATIC; the guard keeps that from | 11 | // Both makefiles also pass -DSECP256K1_STATIC; the guard keeps that from |
| 11 | // warning while leaving this file correct if built without the flag. | 12 | // warning while leaving this file correct if built without the flag. |
| @@ -568,11 +569,39 @@ public: | |||
| 568 | { | 569 | { |
| 569 | sslctx = SSL_CTX_new(TLS_client_method()); | 570 | sslctx = SSL_CTX_new(TLS_client_method()); |
| 570 | if (!sslctx) return false; | 571 | if (!sslctx) return false; |
| 572 | |||
| 573 | // SSL_CTX_new defaults to SSL_VERIFY_NONE with no trust store | ||
| 574 | // loaded, so until now every wss:// relay connection was accepted | ||
| 575 | // without looking at the certificate at all -- any on-path | ||
| 576 | // attacker could impersonate a relay. Our own events are signed, | ||
| 577 | // so a MITM cannot forge them, but it could drop the rendezvous | ||
| 578 | // registration (leaving the pool unreachable to miners) or answer | ||
| 579 | // subscriptions with whatever it liked. | ||
| 580 | if (!SSL_CTX_set_default_verify_paths(sslctx)) | ||
| 581 | return error("Nostr: no system CA store available, refusing %s", host.c_str()); | ||
| 582 | SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, NULL); | ||
| 583 | SSL_CTX_set_min_proto_version(sslctx, TLS1_2_VERSION); | ||
| 584 | |||
| 571 | ssl = SSL_new(sslctx); | 585 | ssl = SSL_new(sslctx); |
| 586 | if (!ssl) return false; | ||
| 572 | SSL_set_fd(ssl, (int)hSocket); | 587 | SSL_set_fd(ssl, (int)hSocket); |
| 573 | SSL_set_tlsext_host_name(ssl, host.c_str()); // SNI | 588 | SSL_set_tlsext_host_name(ssl, host.c_str()); // SNI |
| 589 | |||
| 590 | // Verifying the chain is not enough on its own: without this the | ||
| 591 | // relay could present any certificate a trusted CA ever issued, | ||
| 592 | // for any name. SSL_set1_host binds the check to the host we asked | ||
| 593 | // for. | ||
| 594 | if (!SSL_set1_host(ssl, host.c_str())) | ||
| 595 | return error("Nostr: cannot pin verification to %s", host.c_str()); | ||
| 596 | |||
| 574 | if (SSL_connect(ssl) != 1) | 597 | if (SSL_connect(ssl) != 1) |
| 598 | { | ||
| 599 | long nVerify = SSL_get_verify_result(ssl); | ||
| 600 | if (nVerify != X509_V_OK) | ||
| 601 | return error("Nostr: certificate for %s rejected: %s", | ||
| 602 | host.c_str(), X509_verify_cert_error_string(nVerify)); | ||
| 575 | return error("Nostr: TLS handshake with %s failed", host.c_str()); | 603 | return error("Nostr: TLS handshake with %s failed", host.c_str()); |
| 604 | } | ||
| 576 | } | 605 | } |
| 577 | 606 | ||
| 578 | // WebSocket handshake (HTTP Upgrade) | 607 | // WebSocket handshake (HTTP Upgrade) |