aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/epee/include/net/abstract_tcp_server2.inl8
m---------external/randomx0
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp2
-rw-r--r--src/blockchain_utilities/blockchain_utilities.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl6
-rw-r--r--src/daemon/rpc_command_executor.cpp22
-rw-r--r--src/gen_ssl_cert/CMakeLists.txt49
-rw-r--r--src/gen_ssl_cert/gen_ssl_cert.cpp254
9 files changed, 326 insertions, 18 deletions
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index e1777b1c4..5d12f9466 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -984,7 +984,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
boost::asio::ip::tcp::resolver::query query(address, boost::lexical_cast<std::string>(port), boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_.open(endpoint.protocol());
- acceptor_.set_option(boost::asio::ip::tcp::acceptor::linger(true, 0));
+#if !defined(_WIN32)
+ acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+#endif
acceptor_.bind(endpoint);
acceptor_.listen();
boost::asio::ip::tcp::endpoint binded_endpoint = acceptor_.local_endpoint();
@@ -1018,7 +1020,9 @@ PRAGMA_WARNING_DISABLE_VS(4355)
boost::asio::ip::tcp::resolver::query query(address_ipv6, boost::lexical_cast<std::string>(port_ipv6), boost::asio::ip::tcp::resolver::query::canonical_name);
boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
acceptor_ipv6.open(endpoint.protocol());
- acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::linger(true, 0));
+#if !defined(_WIN32)
+ acceptor_ipv6.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
+#endif
acceptor_ipv6.set_option(boost::asio::ip::v6_only(true));
acceptor_ipv6.bind(endpoint);
acceptor_ipv6.listen();
diff --git a/external/randomx b/external/randomx
-Subproject b53f0ed145c1a51df6ca0708a215089b76d0c05
+Subproject 53af68c34a43f5bdb659f90cc27b6b2da7fd77f
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9bab56200..f332af3d3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -129,6 +129,7 @@ add_subdirectory(cryptonote_protocol)
if(NOT IOS)
add_subdirectory(simplewallet)
add_subdirectory(gen_multisig)
+ add_subdirectory(gen_ssl_cert)
add_subdirectory(daemonizer)
add_subdirectory(daemon)
add_subdirectory(blockchain_utilities)
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 8e2b5bebf..f978ef307 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -2994,8 +2994,6 @@ bool BlockchainLMDB::get_tx_blob(const crypto::hash& h, cryptonote::blobdata &bd
return false;
else if (get_result)
throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx from hash", get_result).c_str()));
- else if (result1.mv_size == 0)
- return false;
bd.assign(reinterpret_cast<char*>(result0.mv_data), result0.mv_size);
bd.append(reinterpret_cast<char*>(result1.mv_data), result1.mv_size);
diff --git a/src/blockchain_utilities/blockchain_utilities.h b/src/blockchain_utilities/blockchain_utilities.h
index 78487b995..e8615cf86 100644
--- a/src/blockchain_utilities/blockchain_utilities.h
+++ b/src/blockchain_utilities/blockchain_utilities.h
@@ -33,7 +33,7 @@
// bounds checking is done before writing to buffer, but buffer size
// should be a sensible maximum
-#define BUFFER_SIZE 1000000
+#define BUFFER_SIZE (2 * 1024 * 1024)
#define CHUNK_SIZE_WARNING_THRESHOLD 500000
#define NUM_BLOCKS_PER_CHUNK 1
#define BLOCKCHAIN_RAW "blockchain.raw"
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index bc5c8d6de..35b2d2a39 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -1723,7 +1723,7 @@ skip:
return false;
}
const uint32_t local_stripe = tools::get_pruning_stripe(m_core.get_blockchain_pruning_seed());
- if (m_sync_pruned_blocks && peer_stripe == local_stripe)
+ if (m_sync_pruned_blocks && local_stripe && next_stripe != local_stripe)
{
MDEBUG(context << "We can sync pruned blocks off this peer, not dropping");
return false;
@@ -1836,7 +1836,7 @@ skip:
next_block_height = next_needed_height;
else
next_block_height = context.m_last_response_height - context.m_needed_objects.size() + 1;
- bool stripe_proceed_main = ((m_sync_pruned_blocks && peer_stripe == local_stripe) || add_stripe == 0 || peer_stripe == 0 || add_stripe == peer_stripe) && (next_block_height < bc_height + BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS || next_needed_height < bc_height + BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS);
+ bool stripe_proceed_main = ((m_sync_pruned_blocks && local_stripe && add_stripe != local_stripe) || add_stripe == 0 || peer_stripe == 0 || add_stripe == peer_stripe) && (next_block_height < bc_height + BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS || next_needed_height < bc_height + BLOCK_QUEUE_FORCE_DOWNLOAD_NEAR_BLOCKS);
bool stripe_proceed_secondary = tools::has_unpruned_block(next_block_height, context.m_remote_blockchain_height, context.m_pruning_seed);
bool proceed = stripe_proceed_main || (queue_proceed && stripe_proceed_secondary);
if (!stripe_proceed_main && !stripe_proceed_secondary && should_drop_connection(context, tools::get_pruning_stripe(next_block_height, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES)))
@@ -2043,7 +2043,7 @@ skip:
const uint32_t peer_stripe = tools::get_pruning_stripe(context.m_pruning_seed);
const uint32_t first_stripe = tools::get_pruning_stripe(span.first, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
const uint32_t last_stripe = tools::get_pruning_stripe(span.first + span.second - 1, context.m_remote_blockchain_height, CRYPTONOTE_PRUNING_LOG_STRIPES);
- if ((first_stripe && peer_stripe != first_stripe) || (last_stripe && peer_stripe != last_stripe))
+ if ((((first_stripe && peer_stripe != first_stripe) || (last_stripe && peer_stripe != last_stripe)) && !m_sync_pruned_blocks) || (m_sync_pruned_blocks && req.prune))
{
MDEBUG(context << "We need full data, but the peer does not have it, dropping peer");
return false;
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index 75c54d048..273d78619 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -91,14 +91,15 @@ namespace {
<< "height: " << boost::lexical_cast<std::string>(header.height) << std::endl
<< "depth: " << boost::lexical_cast<std::string>(header.depth) << std::endl
<< "hash: " << header.hash << std::endl
- << "difficulty: " << header.wide_difficulty << std::endl
- << "cumulative difficulty: " << header.wide_cumulative_difficulty << std::endl
+ << "difficulty: " << cryptonote::difficulty_type(header.wide_difficulty) << std::endl
+ << "cumulative difficulty: " << cryptonote::difficulty_type(header.wide_cumulative_difficulty) << std::endl
<< "POW hash: " << header.pow_hash << std::endl
<< "block size: " << header.block_size << std::endl
<< "block weight: " << header.block_weight << std::endl
<< "long term weight: " << header.long_term_weight << std::endl
<< "num txes: " << header.num_txes << std::endl
- << "reward: " << cryptonote::print_money(header.reward);
+ << "reward: " << cryptonote::print_money(header.reward) << std::endl
+ << "miner tx hash: " << header.miner_tx_hash;
}
std::string get_human_time_ago(time_t t, time_t now)
@@ -356,8 +357,8 @@ bool t_rpc_command_executor::show_difficulty() {
tools::success_msg_writer() << "BH: " << res.height
<< ", TH: " << res.top_block_hash
- << ", DIFF: " << res.wide_difficulty
- << ", CUM_DIFF: " << res.wide_cumulative_difficulty
+ << ", DIFF: " << cryptonote::difficulty_type(res.wide_difficulty)
+ << ", CUM_DIFF: " << cryptonote::difficulty_type(res.wide_cumulative_difficulty)
<< ", HR: " << cryptonote::difficulty_type(res.wide_difficulty) / res.target << " H/s";
return true;
@@ -770,7 +771,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u
<< ", size: " << header.block_size << ", weight: " << header.block_weight << " (long term " << header.long_term_weight << "), transactions: " << header.num_txes << std::endl
<< "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl
<< "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl
- << "difficulty: " << header.wide_difficulty << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl;
+ << "difficulty: " << cryptonote::difficulty_type(header.wide_difficulty) << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl;
first = false;
}
@@ -961,10 +962,11 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash,
if (1 == res.txs.size())
{
// only available for new style answers
+ bool pruned = res.txs.front().prunable_as_hex.empty() && res.txs.front().prunable_hash != epee::string_tools::pod_to_hex(crypto::null_hash);
if (res.txs.front().in_pool)
tools::success_msg_writer() << "Found in pool";
else
- tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height << (res.txs.front().prunable_as_hex.empty() ? " (pruned)" : "");
+ tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height << (pruned ? " (pruned)" : "");
}
const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front();
@@ -1902,7 +1904,7 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip, size_t above
const auto &chain = chains[idx];
const uint64_t start_height = (chain.height - chain.length + 1);
tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
- << " deep), diff " << chain.wide_difficulty << ": " << chain.block_hash;
+ << " deep), diff " << cryptonote::difficulty_type(chain.wide_difficulty) << ": " << chain.block_hash;
}
}
else
@@ -1915,7 +1917,7 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip, size_t above
tools::success_msg_writer() << "Found alternate chain with tip " << tip;
uint64_t start_height = (chain.height - chain.length + 1);
tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1)
- << " deep), diff " << chain.wide_difficulty << ":";
+ << " deep), diff " << cryptonote::difficulty_type(chain.wide_difficulty) << ":";
for (const std::string &block_id: chain.block_hashes)
tools::msg_writer() << " " << block_id;
tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block;
@@ -2019,7 +2021,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks)
}
}
- tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.wide_difficulty << ", cum. diff " << ires.wide_cumulative_difficulty
+ tools::msg_writer() << "Height: " << ires.height << ", diff " << cryptonote::difficulty_type(ires.wide_difficulty) << ", cum. diff " << cryptonote::difficulty_type(ires.wide_cumulative_difficulty)
<< ", target " << ires.target << " sec" << ", dyn fee " << cryptonote::print_money(feres.fee) << "/" << (hfres.enabled ? "byte" : "kB");
if (nblocks > 0)
diff --git a/src/gen_ssl_cert/CMakeLists.txt b/src/gen_ssl_cert/CMakeLists.txt
new file mode 100644
index 000000000..471df021b
--- /dev/null
+++ b/src/gen_ssl_cert/CMakeLists.txt
@@ -0,0 +1,49 @@
+# Copyright (c) 2017-2019, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set(gen_ssl_cert_sources
+ gen_ssl_cert.cpp)
+
+monero_add_executable(gen_ssl_cert
+ ${gen_ssl_cert_sources})
+target_link_libraries(gen_ssl_cert
+ PRIVATE
+ common
+ epee
+ version
+ ${EPEE_READLINE}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY}
+ ${CMAKE_THREAD_LIBS_INIT}
+ ${EXTRA_LIBRARIES})
+add_dependencies(gen_ssl_cert
+ version)
+set_property(TARGET gen_ssl_cert
+ PROPERTY
+ OUTPUT_NAME "monero-gen-ssl-cert")
+install(TARGETS gen_ssl_cert DESTINATION bin)
diff --git a/src/gen_ssl_cert/gen_ssl_cert.cpp b/src/gen_ssl_cert/gen_ssl_cert.cpp
new file mode 100644
index 000000000..7a9b01700
--- /dev/null
+++ b/src/gen_ssl_cert/gen_ssl_cert.cpp
@@ -0,0 +1,254 @@
+// Copyright (c) 2019, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <boost/program_options.hpp>
+#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <openssl/ssl.h>
+#include <openssl/pem.h>
+#include "include_base_utils.h"
+#include "file_io_utils.h"
+#include "net/net_ssl.h"
+#include "crypto/crypto.h"
+#include "common/util.h"
+#include "common/i18n.h"
+#include "common/command_line.h"
+#include "common/scoped_message_writer.h"
+#include "common/password.h"
+#include "version.h"
+
+namespace po = boost::program_options;
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "gen_ssl_cert"
+
+namespace gencert
+{
+ const char* tr(const char* str)
+ {
+ return i18n_translate(str, "tools::gen_ssl_cert");
+ }
+
+}
+
+namespace
+{
+ const command_line::arg_descriptor<std::string> arg_certificate_filename = {"certificate-filename", gencert::tr("Filename to save the certificate"), ""};
+ const command_line::arg_descriptor<std::string> arg_private_key_filename = {"private-key-filename", gencert::tr("Filename to save the private key"), ""};
+ const command_line::arg_descriptor<std::string> arg_passphrase = {"passphrase", gencert::tr("Passphrase with which to encrypt the private key"), ""};
+ const command_line::arg_descriptor<std::string> arg_passphrase_file = {"passphrase-file", gencert::tr("File containing the passphrase with which to encrypt the private key"), ""};
+ const command_line::arg_descriptor<bool> arg_prompt_for_passphrase = {"prompt-for-passphrase", gencert::tr("Prompt for a passphrase with which to encrypt the private key"), false};
+}
+
+// adapted from openssl's apps/x509.c
+static std::string get_fingerprint(X509 *cert, const EVP_MD *fdig)
+{
+ unsigned int j;
+ unsigned int n;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ std::string fingerprint;
+
+ if (!X509_digest(cert, fdig, md, &n))
+ {
+ tools::fail_msg_writer() << tr("Failed to create fingerprint: ") << ERR_reason_error_string(ERR_get_error());
+ return fingerprint;
+ }
+ 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;
+}
+
+int main(int argc, char* argv[])
+{
+ TRY_ENTRY();
+
+ tools::on_startup();
+
+ po::options_description desc_cmd_only("Command line options");
+ po::options_description desc_cmd_sett("Command line options and settings options");
+
+ command_line::add_arg(desc_cmd_sett, arg_certificate_filename);
+ command_line::add_arg(desc_cmd_sett, arg_private_key_filename);
+ command_line::add_arg(desc_cmd_sett, arg_passphrase);
+ command_line::add_arg(desc_cmd_sett, arg_passphrase_file);
+ command_line::add_arg(desc_cmd_sett, arg_prompt_for_passphrase);
+
+ command_line::add_arg(desc_cmd_only, command_line::arg_help);
+ command_line::add_arg(desc_cmd_only, command_line::arg_version);
+
+ po::options_description desc_options("Allowed options");
+ desc_options.add(desc_cmd_only).add(desc_cmd_sett);
+
+ po::variables_map vm;
+ bool r = command_line::handle_error_helper(desc_options, [&]()
+ {
+ po::store(po::parse_command_line(argc, argv, desc_options), vm);
+ po::notify(vm);
+ return true;
+ });
+ if (!r)
+ return 1;
+
+ if (command_line::get_arg(vm, command_line::arg_help))
+ {
+ std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL << ENDL;
+ std::cout << desc_options << std::endl;
+ return 0;
+ }
+ if (command_line::get_arg(vm, command_line::arg_version))
+ {
+ std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL;
+ return 0;
+ }
+
+ const std::string certificate_filename = command_line::get_arg(vm, arg_certificate_filename);
+ if (certificate_filename.empty())
+ {
+ tools::fail_msg_writer() << gencert::tr("Argument is needed: ") << "--" << arg_certificate_filename.name;
+ return 1;
+ }
+ const std::string private_key_filename = command_line::get_arg(vm, arg_private_key_filename);
+ if (private_key_filename.empty())
+ {
+ tools::fail_msg_writer() << gencert::tr("Argument is needed: ") << "--" << arg_private_key_filename.name;
+ return 1;
+ }
+
+ epee::wipeable_string private_key_passphrase;
+ if (command_line::get_arg(vm, arg_prompt_for_passphrase))
+ {
+ auto pwd_container = tools::password_container::prompt(true, "Enter passphrase for the new SSL private key");
+ if (!pwd_container)
+ {
+ tools::fail_msg_writer() << gencert::tr("Failed to read passphrase");
+ return 1;
+ }
+ private_key_passphrase = pwd_container->password();
+ }
+ else if (!command_line::is_arg_defaulted(vm, arg_passphrase_file))
+ {
+ std::string passphrase_file = command_line::get_arg(vm, arg_passphrase_file);
+ if (!passphrase_file.empty())
+ {
+ std::string passphrase;
+ if (!epee::file_io_utils::load_file_to_string(passphrase_file, passphrase))
+ {
+ MERROR("Failed to load passphrase");
+ return 1;
+ }
+
+ // Remove line breaks the user might have inserted
+ boost::trim_right_if(passphrase, boost::is_any_of("\r\n"));
+ private_key_passphrase = passphrase;
+ memwipe(&passphrase[0], passphrase.size());
+ }
+ }
+ else
+ {
+ private_key_passphrase = command_line::get_arg(vm, arg_passphrase);
+ }
+ if (private_key_passphrase.empty())
+ tools::msg_writer(epee::console_color_yellow) << (boost::format(tr("Empty passphrase, the private key will be saved to disk unencrypted, use --%s to set a passphrase or --%s to prompt for one")) % arg_passphrase.name % arg_prompt_for_passphrase.name).str();
+
+ EVP_PKEY *pkey;
+ X509 *cert;
+ r = epee::net_utils::create_rsa_ssl_certificate(pkey, cert);
+ if (!r)
+ {
+ tools::fail_msg_writer() << gencert::tr("Failed to create certificate");
+ return 1;
+ }
+
+ // write cert
+ BIO *bio_cert = BIO_new(BIO_s_mem());
+ r = PEM_write_bio_X509(bio_cert, cert);
+ if (!r)
+ {
+ BIO_free(bio_cert);
+ tools::fail_msg_writer() << gencert::tr("Failed to write certificate: ") << ERR_reason_error_string(ERR_get_error());
+ return 1;
+ }
+ BUF_MEM *buf = NULL;
+ BIO_get_mem_ptr(bio_cert, &buf);
+ if (!buf || !buf->data || !buf->length)
+ {
+ BIO_free(bio_cert);
+ tools::fail_msg_writer() << gencert::tr("Failed to write certificate: ") << ERR_reason_error_string(ERR_get_error());
+ return 1;
+ }
+ const std::string certificate(std::string(buf->data, buf->length));
+ BIO_free(bio_cert);
+
+ // write private key
+ BIO *bio_pkey = BIO_new(BIO_s_mem());
+ r = PEM_write_bio_PKCS8PrivateKey(bio_pkey, pkey, private_key_passphrase.empty() ? NULL : EVP_aes_128_cfb(), private_key_passphrase.data(), private_key_passphrase.size(), NULL, NULL);
+ if (!r)
+ {
+ BIO_free(bio_pkey);
+ tools::fail_msg_writer() << gencert::tr("Failed to write private key: ") << ERR_reason_error_string(ERR_get_error());
+ return 1;
+ }
+ buf = NULL;
+ BIO_get_mem_ptr(bio_pkey, &buf);
+ if (!buf || !buf->data || !buf->length)
+ {
+ BIO_free(bio_pkey);
+ tools::fail_msg_writer() << gencert::tr("Failed to write private key: ") << ERR_reason_error_string(ERR_get_error());
+ return 1;
+ }
+ const std::string private_key(std::string(buf->data, buf->length));
+ BIO_free(bio_pkey);
+
+ // write files
+ tools::set_strict_default_file_permissions(true);
+ r = epee::file_io_utils::save_string_to_file(certificate_filename, certificate);
+ if (!r)
+ {
+ tools::fail_msg_writer() << gencert::tr("Failed to save certificate file");
+ return 1;
+ }
+ r = epee::file_io_utils::save_string_to_file(private_key_filename, private_key);
+ if (!r)
+ {
+ tools::fail_msg_writer() << gencert::tr("Failed to save private key file");
+ return 1;
+ }
+
+ tools::success_msg_writer() << tr("New certificate created:");
+ tools::success_msg_writer() << tr("Certificate: ") << certificate_filename;
+ tools::success_msg_writer() << tr("SHA-256 Fingerprint: ") << get_fingerprint(cert, EVP_sha256());
+ tools::success_msg_writer() << tr("Private key: ") << private_key_filename << " (" << (private_key_passphrase.empty() ? "unencrypted" : "encrypted") << ")";
+
+ return 0;
+ CATCH_ENTRY_L0("main", 1);
+}