wallet_rpc_server: fix ssl_allowed_fingerprints hex parsing
What changed, and why it matters
This commit fixes a bug in the Monero wallet's remote procedure call (RPC) server where SSL certificate fingerprints provided by users were not being properly decoded from hexadecimal text into raw bytes. Previously, the code treated each character of the hex string as a separate byte, which meant the fingerprint comparison would almost always fail or behave unpredictably. The fix properly decodes the hex string and validates its length. This is a security-relevant correctness bug because it could prevent certificate pinning from working as intended, but the commit itself does not describe an active exploit or vulnerability disclosure.
Treat as a low-to-moderate security fix. Users relying on ssl_allowed_fingerprints for daemon certificate pinning should upgrade, as prior versions likely failed to match fingerprints correctly. No emergency response is indicated absent an advisory or exploit disclosure.
Security signals we found
Incorrect hex decoding of security-critical input (SSL certificate fingerprints)
Certificate pinning bypass risk due to fingerprint mismatch
Input validation added (length check and hex parsing error handling)
Security-relevant correctness fix in RPC server authentication path
Evidence from the diff
In wallet_rpc_server.cpp, the loop processing req.ssl_allowed_fingerprints previously pushed each ASCII character of the fingerprint string as an individual uint8_t into a vector, rather than decoding the hex string. The patch replaces this with epee::from_hex_locale::to_vector(fp), adds exception handling that returns WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION with a descriptive error message, and enforces that the decoded vector size equals SSL_FINGERPRINT_SIZE. This ensures SSL fingerprint pinning is actually compared against the correct raw SHA-256 fingerprint bytes.
Changed components
src/wallet/wallet_rpc_server.cppWallet RPC server SSL/TLS certificate fingerprint verificationInspect captured patch +19 / −4
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 6691d55..0411518 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -4770,10 +4770,25 @@ namespace tools
ssl_allowed_fingerprints.reserve(req.ssl_allowed_fingerprints.size());
for (const std::string &fp: req.ssl_allowed_fingerprints)
{
- ssl_allowed_fingerprints.push_back({});
- std::vector<uint8_t> &v = ssl_allowed_fingerprints.back();
- for (auto c: fp)
- v.push_back(c);
+ std::vector<uint8_t> decoded;
+ try
+ {
+ decoded = epee::from_hex_locale::to_vector(fp);
+ }
+ catch (const std::exception &)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
+ er.message = "ssl_allowed_fingerprints[] entries must be hex-encoded SHA-256 values";
+ return false;
+ }
+
+ if (decoded.size() != SSL_FINGERPRINT_SIZE)
+ {
+ er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION;
+ er.message = "Each ssl_allowed_fingerprints[] entry must decode to exactly " BOOST_PP_STRINGIZE(SSL_FINGERPRINT_SIZE) " bytes";
+ return false;
+ }
+ ssl_allowed_fingerprints.emplace_back(std::move(decoded));
}
epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_enabled;
Why this scored 44/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.