Skip to content
Snippets Groups Projects
Commit 18c31612 authored by Adrien Béraud's avatar Adrien Béraud
Browse files

tools: allow to use existing certificate/private key

parent a63c5d17
No related branches found
No related tags found
No related merge requests found
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
.SH SYNOPSIS .SH SYNOPSIS
.B dhtnode [-h] .B dhtnode [-h]
.B dhtnode [-v [-l \fIlogfile\fP]] [-i] [-d] [-n \fInetwork_id\fP] [-p \fIlocal_port\fP] [-b \fIbootstrap_host\fP[:\fIport\fP]] .B dhtnode [-v [-l \fIlogfile\fP]] [-i [--save-identity \fIfile\fP]] [-d] [-n \fInetwork_id\fP] [-p \fIlocal_port\fP] [-b \fIbootstrap_host\fP[:\fIport\fP]] [--certificate \fIfile\fP] [--privkey \fIfile\fP] [--privkey-password \fIpassword\fP]
.SH DESCRIPTION .SH DESCRIPTION
...@@ -60,6 +60,22 @@ Write log to syslog instead of stdout ...@@ -60,6 +60,22 @@ Write log to syslog instead of stdout
\fB-i\fP \fB-i\fP
Generate cryptographic identity for the node. Generate cryptographic identity for the node.
.TP
\fB--save-identity\fP \fIfile\fP
Save generated identity (certificate and private key) to given file prefix.
.TP
\fB--certificate\fP \fIfile\fP
Load identity certificate from given file.
.TP
\fB--privkey\fP \fIfile\fP
Load identity private key from given file.
.TP
\fB--privkey-password\fP \fIpassword\fP
Password to use for private key encryption or decryption (optional).
.TP .TP
\fB-d\fP \fB-d\fP
Run the program in daemon mode (will fork in the background). Run the program in daemon mode (will fork in the background).
......
...@@ -654,6 +654,7 @@ OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", co ...@@ -654,6 +654,7 @@ OPENDHT_PUBLIC Identity generateIdentity(const std::string& name = "dhtnode", co
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca); OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name, const Identity& ca, bool is_ca);
OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {}); OPENDHT_PUBLIC Identity generateEcIdentity(const std::string& name = "dhtnode", const Identity& ca = {});
OPENDHT_PUBLIC void saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password = {});
/** /**
* Performs SHA512, SHA256 or SHA1, depending on hash_length. * Performs SHA512, SHA256 or SHA1, depending on hash_length.
......
...@@ -31,6 +31,7 @@ extern "C" { ...@@ -31,6 +31,7 @@ extern "C" {
#include <random> #include <random>
#include <sstream> #include <sstream>
#include <fstream>
#include <stdexcept> #include <stdexcept>
#include <cassert> #include <cassert>
...@@ -1043,6 +1044,21 @@ generateEcIdentity(const std::string& name, const Identity& ca) { ...@@ -1043,6 +1044,21 @@ generateEcIdentity(const std::string& name, const Identity& ca) {
return generateEcIdentity(name, ca, !ca.first || !ca.second); return generateEcIdentity(name, ca, !ca.first || !ca.second);
} }
void
saveIdentity(const Identity& id, const std::string& path, const std::string& privkey_password)
{
{
auto ca_key_data = id.first->serialize(privkey_password);
std::ofstream key_file(path + ".pem");
key_file.write((char*)ca_key_data.data(), ca_key_data.size());
}
{
auto ca_key_data = id.second->getPacked();
std::ofstream crt_file(path + ".crt");
crt_file.write((char*)ca_key_data.data(), ca_key_data.size());
}
}
void void
setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity) setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
{ {
......
...@@ -56,7 +56,7 @@ void print_node_info(const std::shared_ptr<DhtRunner>& node, const dht_params& p ...@@ -56,7 +56,7 @@ void print_node_info(const std::shared_ptr<DhtRunner>& node, const dht_params& p
std::cout << "port " << port4 << std::endl; std::cout << "port " << port4 << std::endl;
else else
std::cout << "IPv4 port " << port4 << ", IPv6 port " << port6 << std::endl; std::cout << "IPv4 port " << port4 << ", IPv6 port " << port6 << std::endl;
if (params.generate_identity) if (params.id.first)
std::cout << "Public key ID " << node->getId() << std::endl; std::cout << "Public key ID " << node->getId() << std::endl;
} }
...@@ -395,7 +395,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params ...@@ -395,7 +395,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
node->cancelPut(id, std::stoul(rem, nullptr, 16)); node->cancelPut(id, std::stoul(rem, nullptr, 16));
} }
else if (op == "s") { else if (op == "s") {
if (not params.generate_identity) { if (not params.id.first) {
print_id_req(); print_id_req();
continue; continue;
} }
...@@ -410,7 +410,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params ...@@ -410,7 +410,7 @@ void cmd_loop(std::shared_ptr<DhtRunner>& node, dht_params& params
}); });
} }
else if (op == "e") { else if (op == "e") {
if (not params.generate_identity) { if (not params.id.first) {
print_id_req(); print_id_req();
continue; continue;
} }
...@@ -510,17 +510,20 @@ main(int argc, char **argv) ...@@ -510,17 +510,20 @@ main(int argc, char **argv)
auto node = std::make_shared<DhtRunner>(); auto node = std::make_shared<DhtRunner>();
try { try {
dht::crypto::Identity crt {}; if (not params.id.first and params.generate_identity) {
if (params.generate_identity) {
auto ca_tmp = dht::crypto::generateEcIdentity("DHT Node CA"); auto ca_tmp = dht::crypto::generateEcIdentity("DHT Node CA");
crt = dht::crypto::generateIdentity("DHT Node", ca_tmp); params.id = dht::crypto::generateIdentity("DHT Node", ca_tmp);
if (not params.save_identity.empty()) {
dht::crypto::saveIdentity(ca_tmp, params.save_identity + "_ca", params.privkey_pwd);
dht::crypto::saveIdentity(params.id, params.save_identity, params.privkey_pwd);
}
} }
dht::DhtRunner::Config config {}; dht::DhtRunner::Config config {};
config.dht_config.node_config.network = params.network; config.dht_config.node_config.network = params.network;
config.dht_config.node_config.maintain_storage = false; config.dht_config.node_config.maintain_storage = false;
config.dht_config.node_config.persist_path = params.persist_path; config.dht_config.node_config.persist_path = params.persist_path;
config.dht_config.id = crt; config.dht_config.id = params.id;
config.threaded = true; config.threaded = true;
config.proxy_server = params.proxyclient; config.proxy_server = params.proxyclient;
config.push_node_id = "dhtnode"; config.push_node_id = "dhtnode";
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <opendht.h> #include <opendht.h>
#include <opendht/log.h> #include <opendht/log.h>
#include <opendht/crypto.h>
#ifndef WIN32_NATIVE #ifndef WIN32_NATIVE
#include <getopt.h> #include <getopt.h>
#include <readline/readline.h> #include <readline/readline.h>
...@@ -87,26 +88,47 @@ bool isInfoHash(const dht::InfoHash& h) { ...@@ -87,26 +88,47 @@ bool isInfoHash(const dht::InfoHash& h) {
return true; return true;
} }
std::vector<uint8_t>
loadFile(const std::string& path)
{
std::vector<uint8_t> buffer;
std::ifstream file(path, std::ios::binary);
if (!file)
throw std::runtime_error("Can't read file: "+path);
file.seekg(0, std::ios::end);
auto size = file.tellg();
if (size > std::numeric_limits<unsigned>::max())
throw std::runtime_error("File is too big: "+path);
buffer.resize(size);
file.seekg(0, std::ios::beg);
if (!file.read((char*)buffer.data(), size))
throw std::runtime_error("Can't load file: "+path);
return buffer;
}
static const constexpr in_port_t DHT_DEFAULT_PORT = 4222; static const constexpr in_port_t DHT_DEFAULT_PORT = 4222;
struct dht_params { struct dht_params {
bool help {false}; // print help and exit bool help {false}; // print help and exit
bool version {false}; bool version {false};
bool log {false};
std::string logfile {};
bool syslog {false};
in_port_t port {0};
dht::NetId network {0};
bool generate_identity {false}; bool generate_identity {false};
bool daemonize {false}; bool daemonize {false};
bool service {false}; bool service {false};
bool peer_discovery {false}; bool peer_discovery {false};
bool log {false};
bool syslog {false};
std::string logfile {};
std::pair<std::string, std::string> bootstrap {}; std::pair<std::string, std::string> bootstrap {};
dht::NetId network {0};
in_port_t port {0};
in_port_t proxyserver {0}; in_port_t proxyserver {0};
std::string proxyclient {}; std::string proxyclient {};
std::string pushserver {}; std::string pushserver {};
std::string devicekey {}; std::string devicekey {};
std::string persist_path {}; std::string persist_path {};
dht::crypto::Identity id {};
std::string privkey_pwd {};
std::string save_identity {};
}; };
static const constexpr struct option long_options[] = { static const constexpr struct option long_options[] = {
...@@ -115,6 +137,10 @@ static const constexpr struct option long_options[] = { ...@@ -115,6 +137,10 @@ static const constexpr struct option long_options[] = {
{"net", required_argument, nullptr, 'n'}, {"net", required_argument, nullptr, 'n'},
{"bootstrap", required_argument, nullptr, 'b'}, {"bootstrap", required_argument, nullptr, 'b'},
{"identity", no_argument , nullptr, 'i'}, {"identity", no_argument , nullptr, 'i'},
{"save-identity", required_argument, nullptr, 'I'},
{"certificate", required_argument, nullptr, 'c'},
{"privkey", required_argument, nullptr, 'k'},
{"privkey-password", required_argument, nullptr, 'm'},
{"verbose", no_argument , nullptr, 'v'}, {"verbose", no_argument , nullptr, 'v'},
{"daemonize", no_argument , nullptr, 'd'}, {"daemonize", no_argument , nullptr, 'd'},
{"service", no_argument , nullptr, 's'}, {"service", no_argument , nullptr, 's'},
...@@ -134,6 +160,7 @@ dht_params ...@@ -134,6 +160,7 @@ dht_params
parseArgs(int argc, char **argv) { parseArgs(int argc, char **argv) {
dht_params params; dht_params params;
int opt; int opt;
std::string privkey;
while ((opt = getopt_long(argc, argv, "hidsvDp:n:b:f:l:", long_options, nullptr)) != -1) { while ((opt = getopt_long(argc, argv, "hidsvDp:n:b:f:l:", long_options, nullptr)) != -1) {
switch (opt) { switch (opt) {
case 'p': { case 'p': {
...@@ -201,10 +228,36 @@ parseArgs(int argc, char **argv) { ...@@ -201,10 +228,36 @@ parseArgs(int argc, char **argv) {
case 's': case 's':
params.service = true; params.service = true;
break; break;
case 'c': {
try {
params.id.second = std::make_shared<dht::crypto::Certificate>(loadFile(optarg));
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Error loading certificate: ") + e.what());
}
break;
}
case 'k':
privkey = optarg;
break;
case 'm':
params.privkey_pwd = optarg;
break;
case 'I':
params.save_identity = optarg;
break;
default: default:
break; break;
} }
} }
if (not privkey.empty()) {
try {
params.id.first = std::make_shared<dht::crypto::PrivateKey>(loadFile(privkey), params.privkey_pwd);
} catch (const std::exception& e) {
throw std::runtime_error(std::string("Error loading private key: ") + e.what());
}
}
if (params.save_identity.empty())
params.privkey_pwd.clear();
return params; return params;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment