mirror of
https://github.com/monero-project/monero.git
synced 2025-08-03 14:04:16 -04:00
Merge pull request #8344
70bbd25
core_rpc_server: new file: rpc_ssl.fingerprint (Jeffrey Ryan)
This commit is contained in:
commit
3a72c47445
4 changed files with 129 additions and 25 deletions
|
@ -151,6 +151,33 @@ namespace net_utils
|
|||
bool create_ec_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert);
|
||||
bool create_rsa_ssl_certificate(EVP_PKEY *&pkey, X509 *&cert);
|
||||
|
||||
/**
|
||||
* @brief Create a human-readable X509 certificate fingerprint
|
||||
*
|
||||
* Example output: "12:A3:92:19:87:D2:A2:A5:77:94:82:29:B9:5A:91:01:AB:5F:75:16:9A:BA:CD:3D:D3:69:3D:6A:87:DC:E8:0E"
|
||||
*
|
||||
* @param[in] cert The certificate which will be used to create the fingerprint
|
||||
* @param[in] fdig The digest algorithm to use, defaults to SHA-256 b/c that is what ssl_options_t uses
|
||||
* @return The human-readable fingerprint string
|
||||
*
|
||||
* @throw boost::system_error if there is an OpenSSL error
|
||||
*/
|
||||
std::string get_hr_ssl_fingerprint(const X509 *cert, const EVP_MD *fdig = EVP_sha256());
|
||||
|
||||
/**
|
||||
* @brief Create a human-readable fingerprint from the contents of an X509 certificate
|
||||
*
|
||||
* Should be equivalent to the command `openssl x509 -in <cert file> -fingerprint -sha256 -noout`
|
||||
* Example output: "12:A3:92:19:87:D2:A2:A5:77:94:82:29:B9:5A:91:01:AB:5F:75:16:9A:BA:CD:3D:D3:69:3D:6A:87:DC:E8:0E"
|
||||
*
|
||||
* @param[in] cert_path The path to an X509 certificate which will be used to create the fingerprint
|
||||
* @param[in] fdig The digest algorithm to use, defaults to SHA-256 b/c that is what ssl_options_t uses
|
||||
* @return The human-readable fingerprint string
|
||||
*
|
||||
* @throw boost::system_error if there is an OpenSSL error or file I/O error
|
||||
*/
|
||||
std::string get_hr_ssl_fingerprint_from_file(const std::string& cert_path, const EVP_MD *fdig = EVP_sha256());
|
||||
|
||||
//! Store private key for `ssl` at `base + ".key"` unencrypted and certificate for `ssl` at `base + ".crt"`.
|
||||
boost::system::error_code store_ssl_keys(boost::asio::ssl::context& ssl, const boost::filesystem::path& base);
|
||||
}
|
||||
|
|
|
@ -641,6 +641,56 @@ bool ssl_options_t::handshake(
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string get_hr_ssl_fingerprint(const X509 *cert, const EVP_MD *fdig)
|
||||
{
|
||||
unsigned int j;
|
||||
unsigned int n;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
std::string fingerprint;
|
||||
|
||||
CHECK_AND_ASSERT_THROW_MES(cert && fdig, "Pointer args to get_hr_ssl_fingerprint cannot be null");
|
||||
|
||||
if (!X509_digest(cert, fdig, md, &n))
|
||||
{
|
||||
const unsigned long ssl_err_val = static_cast<int>(ERR_get_error());
|
||||
const boost::system::error_code ssl_err_code = boost::asio::error::ssl_errors(static_cast<int>(ssl_err_val));
|
||||
MERROR("Failed to create SSL fingerprint: " << ERR_reason_error_string(ssl_err_val));
|
||||
throw boost::system::system_error(ssl_err_code, ERR_reason_error_string(ssl_err_val));
|
||||
}
|
||||
fingerprint.resize(n * 3 - 1);
|
||||
char *out = &fingerprint[0];
|
||||
for (j = 0; j < n; ++j)
|
||||
{
|
||||
snprintf(out, 3 + (j + 1 < n), "%02X%s", md[j], (j + 1 == n) ? "" : ":");
|
||||
out += 3;
|
||||
}
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
std::string get_hr_ssl_fingerprint_from_file(const std::string& cert_path, const EVP_MD *fdig) {
|
||||
// Open file for reading
|
||||
FILE* fp = fopen(cert_path.c_str(), "r");
|
||||
if (!fp)
|
||||
{
|
||||
const boost::system::error_code err_code(errno, boost::system::system_category());
|
||||
throw boost::system::system_error(err_code, "Failed to open certificate file '" + cert_path + "'");
|
||||
}
|
||||
std::unique_ptr<FILE, decltype(&fclose)> file(fp, &fclose);
|
||||
|
||||
// Extract certificate structure from file
|
||||
X509* ssl_cert_handle = PEM_read_X509(file.get(), NULL, NULL, NULL);
|
||||
if (!ssl_cert_handle) {
|
||||
const unsigned long ssl_err_val = static_cast<int>(ERR_get_error());
|
||||
const boost::system::error_code ssl_err_code = boost::asio::error::ssl_errors(static_cast<int>(ssl_err_val));
|
||||
MERROR("OpenSSL error occurred while loading certificate at '" + cert_path + "'");
|
||||
throw boost::system::system_error(ssl_err_code, ERR_reason_error_string(ssl_err_val));
|
||||
}
|
||||
std::unique_ptr<X509, decltype(&X509_free)> ssl_cert(ssl_cert_handle, &X509_free);
|
||||
|
||||
// Get the fingerprint from X509 structure
|
||||
return get_hr_ssl_fingerprint(ssl_cert.get(), fdig);
|
||||
}
|
||||
|
||||
bool ssl_support_from_string(ssl_support_t &ssl, boost::string_ref s)
|
||||
{
|
||||
if (s == "enabled")
|
||||
|
@ -705,6 +755,29 @@ boost::system::error_code store_ssl_keys(boost::asio::ssl::context& ssl, const b
|
|||
return boost::asio::error::ssl_errors(ERR_get_error());
|
||||
if (std::fclose(file.release()) != 0)
|
||||
return {errno, boost::system::system_category()};
|
||||
|
||||
// write SHA-256 fingerprint file
|
||||
const boost::filesystem::path fp_file{base.string() + ".fingerprint"};
|
||||
file.reset(std::fopen(fp_file.string().c_str(), "w"));
|
||||
if (!file)
|
||||
return {errno, boost::system::system_category()};
|
||||
const auto fp_perms = (boost::filesystem::owner_read | boost::filesystem::group_read | boost::filesystem::others_read);
|
||||
boost::filesystem::permissions(fp_file, fp_perms, error);
|
||||
if (error)
|
||||
return error;
|
||||
try
|
||||
{
|
||||
const std::string fingerprint = get_hr_ssl_fingerprint(ssl_cert);
|
||||
if (fingerprint.length() != fwrite(fingerprint.c_str(), sizeof(char), fingerprint.length(), file.get()))
|
||||
return {errno, boost::system::system_category()};
|
||||
}
|
||||
catch (const boost::system::system_error& fperr)
|
||||
{
|
||||
return fperr.code();
|
||||
}
|
||||
if (std::fclose(file.release()) != 0)
|
||||
return {errno, boost::system::system_category()};
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue