From e109e1be47f35d3f0a5163872cbe952bbc6ee65c Mon Sep 17 00:00:00 2001 From: Ravin Perera <33562092+ravinsp@users.noreply.github.com> Date: Fri, 4 Oct 2019 17:02:17 +0530 Subject: [PATCH] Improved contract loading validation. --- src/conf.cpp | 72 +++++++++++++++++++++++++++++++++++-------------- src/conf.h | 6 +++-- src/crypto.cpp | 28 ++++++++++--------- src/main.cpp | 33 ++++++++++++++--------- src/proc.cpp | 6 ++--- src/shared.cpp | 15 ++++++----- src/shared.h | 2 +- src/usr/usr.cpp | 4 +-- 8 files changed, 105 insertions(+), 61 deletions(-) diff --git a/src/conf.cpp b/src/conf.cpp index 712eda98..26b5a968 100644 --- a/src/conf.cpp +++ b/src/conf.cpp @@ -97,22 +97,28 @@ int load_config() if (d.ParseStream(isw).HasParseError()) { cerr << "Invalid config file format. Parser error at position " << d.GetErrorOffset() << endl; - return 0; + return -1; } else if (!is_schema_valid(d)) { cerr << "Invalid config file format.\n"; - return 0; + return -1; } //Check contract version. string cfgVersion = d["version"].GetString(); + if (cfgVersion.empty()) + { + cerr << "Contract config version missing.\n"; + return -1; + } + if (version_compare(cfgVersion, _HP_MIN_CONTRACT_VERSION_) == -1) { cerr << "Contract version too old. Minimum " << _HP_MIN_CONTRACT_VERSION_ << " required. " << cfgVersion << " found.\n"; - return 0; + return -1; } cfg.pubkeyb64 = d["pubkeyb64"].GetString(); @@ -135,7 +141,7 @@ int load_config() cfg.pubmaxsize = d["pubmaxsize"].GetInt(); cfg.pubmaxcpm = d["pubmaxcpm"].GetInt(); - return 1; + return 0; } void save_config() @@ -191,19 +197,33 @@ void set_contract_dir_paths(string basedir) ctx.configFile = ctx.configDir + "/hp.cfg"; ctx.histDir = basedir + "/hist"; ctx.stateDir = basedir + "/state"; - ctx.binDir = basedir + "/bin"; +} + +bool validate_contract_dir_paths() +{ + string dirs[4] = {ctx.contractDir, ctx.configFile, ctx.histDir, ctx.stateDir}; + + for (string dir : dirs) + { + if (!boost::filesystem::exists(dir)) + { + cerr << dir << " does not exist.\n"; + return false; + } + } + + return true; } int create_contract() { if (boost::filesystem::exists(ctx.contractDir)) { - cerr << "Contract dir already exists.\n"; - return 0; + cerr << "Contract dir already exists. Cannot create contract at the same location.\n"; + return -1; } boost::filesystem::create_directories(ctx.configDir); - boost::filesystem::create_directories(ctx.binDir); boost::filesystem::create_directories(ctx.histDir); boost::filesystem::create_directories(ctx.stateDir); @@ -215,7 +235,13 @@ int create_contract() cfg.pubmaxsize = 65536; cfg.pubmaxcpm = 100; save_config(); - return 1; + + cout << "Contract directory created at " << ctx.contractDir << endl; + + if (load_config() != 0) + return -1; + + return 0; } int clear_keys() @@ -223,26 +249,32 @@ int clear_keys() cfg.pubkeyb64 = ""; cfg.seckeyb64 = ""; save_config(); + return 0; } -int init(int argc, char **argv) +bool validate_config() { - if (ctx.command == "new") + if (cfg.pubkeyb64.empty() || cfg.seckeyb64.empty() || cfg.binary.empty() || cfg.listenip.empty() || + cfg.peerport == 0 || cfg.roundtime == 0 || cfg.pubport == 0 || cfg.pubmaxsize == 0 || cfg.pubmaxcpm == 0) { - if (!create_contract()) - return 0; + cerr << "Required configuration fields missing.\n"; + return false; } - if (!load_config()) - return 0; - - if (ctx.command == "rekey") + if (!boost::filesystem::exists(cfg.binary)) { - //Clear the keys. crpyto::init will automatically init the keys. - clear_keys(); + cerr << "Contract binary does not exist: " << cfg.binary << endl; + return false; } - return 1; + return true; +} + +int init() +{ + if (!validate_contract_dir_paths() || load_config() != 0 || !validate_config()) + return -1; + return 0; } } // namespace conf \ No newline at end of file diff --git a/src/conf.h b/src/conf.h index 5a424f7e..262d9bf4 100644 --- a/src/conf.h +++ b/src/conf.h @@ -24,7 +24,6 @@ struct ContractCtx string contractDir; string histDir; string stateDir; - string binDir; string configDir; string configFile; }; @@ -58,7 +57,10 @@ struct ContractConfig extern ContractCtx ctx; extern ContractConfig cfg; -int init(int argc, char **argv); +int init(); +int create_contract(); +int load_config(); +int clear_keys(); void set_contract_dir_paths(string basedir); void save_config(); diff --git a/src/crypto.cpp b/src/crypto.cpp index 34df78ed..bba8749f 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -24,7 +24,9 @@ string sign_b64(string &msg) { unsigned char sig[crypto_sign_BYTES]; crypto_sign_detached(sig, NULL, (unsigned char *)msg.data(), msg.size() + 1, conf::cfg.seckey); - return shared::base64_encode(sig, crypto_sign_BYTES); + string sigb64; + shared::base64_encode(sig, crypto_sign_BYTES, sigb64); + return sigb64; } bool verify(const unsigned char *msg, unsigned long long msg_len, const unsigned char *sig, const unsigned char *pubkey) @@ -66,13 +68,13 @@ int init() if (conf::cfg.pubkeyb64.empty() || conf::cfg.seckeyb64.empty()) { cerr << "Signing keys missing. Run with 'rekey' to generate new keys.\n"; - return 0; + return -1; } else { //Decode b64 keys into bytes and store in memory. - if (!b64pair_to_bin()) - return 0; + if (b64pair_to_bin() != 0) + return -1; //Sign and verify a sample to ensure we have a matching key pair. string msg = "hotpocket"; @@ -80,12 +82,12 @@ int init() if (!verify_b64(msg, sigb64, conf::cfg.pubkeyb64)) { cerr << "Invalid signing keys. Run with 'rekey' to generate new keys.\n"; - return 0; + return -1; } } } - return 1; + return 0; } void generate_crypto_keys() @@ -103,8 +105,8 @@ void generate_crypto_keys() void binpair_to_b64() { - conf::cfg.pubkeyb64 = shared::base64_encode(conf::cfg.pubkey, crypto_sign_PUBLICKEYBYTES); - conf::cfg.seckeyb64 = shared::base64_encode(conf::cfg.seckey, crypto_sign_SECRETKEYBYTES); + shared::base64_encode(conf::cfg.pubkey, crypto_sign_PUBLICKEYBYTES, conf::cfg.pubkeyb64); + shared::base64_encode(conf::cfg.seckey, crypto_sign_SECRETKEYBYTES, conf::cfg.seckeyb64); } int b64pair_to_bin() @@ -112,16 +114,16 @@ int b64pair_to_bin() unsigned char *decoded_pubkey = (unsigned char *)malloc(crypto_sign_PUBLICKEYBYTES); unsigned char *decoded_seckey = (unsigned char *)malloc(crypto_sign_SECRETKEYBYTES); - if (!shared::base64_decode(conf::cfg.pubkeyb64, decoded_pubkey, crypto_sign_PUBLICKEYBYTES)) + if (shared::base64_decode(conf::cfg.pubkeyb64, decoded_pubkey, crypto_sign_PUBLICKEYBYTES) != 0) { cerr << "Error decoding public key.\n"; - return 0; + return -1; } - if (!shared::base64_decode(conf::cfg.seckeyb64, decoded_seckey, crypto_sign_SECRETKEYBYTES)) + if (shared::base64_decode(conf::cfg.seckeyb64, decoded_seckey, crypto_sign_SECRETKEYBYTES) != 0) { cerr << "Error decoding secret key.\n"; - return 0; + return -1; } if (conf::cfg.pubkey != NULL) @@ -132,7 +134,7 @@ int b64pair_to_bin() conf::cfg.pubkey = decoded_pubkey; conf::cfg.seckey = decoded_seckey; - return 1; + return 0; } } // namespace crypto \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index fec2a090..cf6c989d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,34 +8,40 @@ #include "conf.h" #include "crypto.h" #include "usr/usr.h" -#include "proc.h" using namespace std; -using namespace shared; int parse_cmd(int argc, char **argv); int main(int argc, char **argv) { - if (!parse_cmd(argc, argv)) + if (parse_cmd(argc, argv) != 0) return -1; if (conf::ctx.command == "version") { cout << _HP_VERSION_ << endl; } + else if (conf::ctx.command == "new") + { + if (conf::create_contract() != 0 || crypto::init() != 0) + return -1; + } else { - bool initSuccess = conf::init(argc, argv) && crypto::init(); - if (!initSuccess) - { - cerr << "Init error\n"; + if (conf::init() != 0) return -1; - } - if (conf::ctx.command == "run") + if (conf::ctx.command == "rekey") { - usr::init(); + //Clear the keys. crpyto::init will init the keys. + if (conf::clear_keys() != 0 || crypto::init() != 0) + return -1; + } + else if (conf::ctx.command == "run") + { + if (crypto::init() != 0 || usr::init() != 0) + return -1; } } @@ -58,13 +64,14 @@ int parse_cmd(int argc, char **argv) else { conf::set_contract_dir_paths(argv[2]); - return 1; + + return 0; } } else if (command == "version") { if (argc == 2) - return 1; + return 0; } } @@ -74,5 +81,5 @@ int parse_cmd(int argc, char **argv) cout << "hpcore (command = run | new | rekey)\n"; cout << "Example: hpcore run ~/mycontract\n"; - return 0; + return -1; } \ No newline at end of file diff --git a/src/proc.cpp b/src/proc.cpp index ad10612c..3d6b0d7a 100644 --- a/src/proc.cpp +++ b/src/proc.cpp @@ -30,7 +30,7 @@ int exec_contract(ContractExecArgs &args) if (is_contract_running()) { cerr << "Contract process still running.\n"; - return 0; + return -1; } int pid = fork(); @@ -53,10 +53,10 @@ int exec_contract(ContractExecArgs &args) else { cerr << "fork() failed.\n"; - return 0; + return -1; } - return 1; + return 0; } /** diff --git a/src/shared.cpp b/src/shared.cpp index 84e9fbda..c961037e 100644 --- a/src/shared.cpp +++ b/src/shared.cpp @@ -6,7 +6,7 @@ using namespace std; namespace shared { -string base64_encode(unsigned char *bin, size_t bin_len) +int base64_encode(unsigned char *bin, size_t bin_len, string &encoded_string) { const size_t base64_max_len = sodium_base64_encoded_len(bin_len, sodium_base64_VARIANT_ORIGINAL); char base64_str[base64_max_len]; @@ -17,10 +17,11 @@ string base64_encode(unsigned char *bin, size_t bin_len) sodium_base64_VARIANT_ORIGINAL); if (encoded_str_char == NULL) - throw "Base64 Error: Failed to encode string"; + return -1; - string s(base64_str); - return s; + encoded_string.clear(); + encoded_string.append(base64_str, base64_max_len); + return 0; } int base64_decode(string base64_str, unsigned char *decoded, size_t decoded_len) @@ -33,10 +34,10 @@ int base64_decode(string base64_str, unsigned char *decoded, size_t decoded_len) "", &bin_len, &b64_end, sodium_base64_VARIANT_ORIGINAL)) { - return 0; + return -1; } - return 1; + return 0; } -} \ No newline at end of file +} // namespace shared \ No newline at end of file diff --git a/src/shared.h b/src/shared.h index fe28da3e..4655bdef 100644 --- a/src/shared.h +++ b/src/shared.h @@ -26,7 +26,7 @@ struct ContractUser } }; -string base64_encode(unsigned char *bin, size_t bin_len); +int base64_encode(unsigned char *bin, size_t bin_len, string &encoded_string); int base64_decode(string base64_str, unsigned char *decoded, size_t decoded_len); } // namespace usr diff --git a/src/usr/usr.cpp b/src/usr/usr.cpp index 7cf7c0e4..1e9f02ef 100644 --- a/src/usr/usr.cpp +++ b/src/usr/usr.cpp @@ -28,7 +28,7 @@ void create_user_challenge(string &msg, string &challenge) unsigned char challenge_bytes[USER_CHALLENGE_LEN]; randombytes_buf(challenge_bytes, USER_CHALLENGE_LEN); - challenge = base64_encode(challenge_bytes, USER_CHALLENGE_LEN); + base64_encode(challenge_bytes, USER_CHALLENGE_LEN, challenge); Document d; d.SetObject(); @@ -142,7 +142,7 @@ int read_contract_user_outputs() } } - return 1; + return 0; } int init()