diff options
author | lloyd <[email protected]> | 2014-11-12 01:23:55 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2014-11-12 01:23:55 +0000 |
commit | 8b0cbccc7b11e545ed27bc6d7bda04b5cf632e60 (patch) | |
tree | 7ea9368d6ccaa85337a63b55e8bd15efa46fd357 | |
parent | 67161b91163afad417f9483cb557b26c5f5f4bc0 (diff) |
Command line prog cleanup
31 files changed, 478 insertions, 522 deletions
diff --git a/src/cmd/apps.h b/src/cmd/apps.h index 48f1f770e..5f866938f 100644 --- a/src/cmd/apps.h +++ b/src/cmd/apps.h @@ -1,39 +1,64 @@ -#include <botan/auto_rng.h> -#include <botan/hex.h> #include <iostream> - +#include <functional> +#include <string> +#include <set> +#include <botan/hex.h> +#include <botan/auto_rng.h> #include "getopt.h" using namespace Botan; -int unimplemented(int argc, char* argv[], const char* what); - -#define UNIMPLEMENTED(main, prob) \ - int main(int argc, char* argv[]) { return unimplemented(argc, argv, prob); } - -#define DEFINE_APP(cmd) int cmd ## _main(int argc, char* argv[]); - -DEFINE_APP(asn1); -DEFINE_APP(base64); -DEFINE_APP(bcrypt); -DEFINE_APP(bzip); -DEFINE_APP(ca); -DEFINE_APP(cert_verify); -DEFINE_APP(dsa_sign); -DEFINE_APP(dsa_verify); -DEFINE_APP(factor); -DEFINE_APP(fpe); -DEFINE_APP(hash); -DEFINE_APP(is_prime); -DEFINE_APP(keygen); -DEFINE_APP(ocsp_check); -DEFINE_APP(pkcs10); -DEFINE_APP(read_ssh); -DEFINE_APP(rng); -DEFINE_APP(self_sig); -DEFINE_APP(speed); -DEFINE_APP(tls_client); -DEFINE_APP(tls_server); -DEFINE_APP(tls_server_asio); -DEFINE_APP(x509); +typedef std::function<int (int, char*[])> main_fn; + +class AppRegistrations + { + public: + void add(const std::string& name, main_fn fn) + { + m_cmds[name] = fn; + } + + bool has(const std::string& cmd) const + { + return m_cmds.count(cmd) > 0; + } + + std::set<std::string> all_apps() const + { + std::set<std::string> apps; + for(auto i : m_cmds) + apps.insert(i.first); + return apps; + } + + int run(const std::string& cmd, int argc, char* argv[]) const + { + auto i = m_cmds.find(cmd); + if(i != m_cmds.end()) + return i->second(argc, argv); + return -1; + } + + static AppRegistrations& instance() + { + static AppRegistrations s_apps; + return s_apps; + } + + class AppRegistration + { + public: + AppRegistration(const std::string& name, main_fn fn) + { + AppRegistrations::instance().add(name, fn); + } + }; + + private: + AppRegistrations() {} + + std::map<std::string, main_fn> m_cmds; + }; + +#define REGISTER_APP(nm) AppRegistrations::AppRegistration g_ ## nm ## _registration(#nm, nm) diff --git a/src/cmd/asn1.cpp b/src/cmd/asn1.cpp index 02b73e415..cb68b2fcc 100644 --- a/src/cmd/asn1.cpp +++ b/src/cmd/asn1.cpp @@ -1,6 +1,7 @@ #include "apps.h" #include <botan/bigint.h> +#include <botan/hex.h> #include <botan/der_enc.h> #include <botan/ber_dec.h> #include <botan/asn1_time.h> @@ -25,10 +26,6 @@ using namespace Botan; */ #define INITIAL_LEVEL 0 -void decode(BER_Decoder&, size_t); -void emit(const std::string&, size_t, size_t, const std::string& = ""); -std::string type_name(ASN1_Tag); - namespace { std::string url_encode(const std::vector<byte>& in) @@ -55,38 +52,63 @@ std::string url_encode(const std::vector<byte>& in) return out.str(); } -} - -int asn1_main(int argc, char* argv[]) +void emit(const std::string& type, size_t level, size_t length, const std::string& value = "") { - if(argc != 2) - { - std::cout << "Usage: " << argv[0] << " <file>\n"; - return 1; - } + const size_t LIMIT = 4*1024; + const size_t BIN_LIMIT = 1024; - try { - DataSource_Stream in(argv[1]); + std::ostringstream out; - if(!PEM_Code::matches(in)) - { - BER_Decoder decoder(in); - decode(decoder, INITIAL_LEVEL); - } - else - { - std::string label; // ignored - BER_Decoder decoder(PEM_Code::decode(in, label)); - decode(decoder, INITIAL_LEVEL); - } - } - catch(std::exception& e) + out << " d=" << std::setw(2) << level + << ", l=" << std::setw(4) << length << ": "; + + for(size_t i = INITIAL_LEVEL; i != level; ++i) + out << ' '; + + out << type; + + bool should_skip = false; + + if(value.length() > LIMIT) + should_skip = true; + + if((type == "OCTET STRING" || type == "BIT STRING") && value.length() > BIN_LIMIT) + should_skip = true; + + if(value != "" && !should_skip) { - std::cout << "Error: " << e.what() << "\n"; - return 2; + if(out.tellp() % 2 == 0) out << ' '; + + while(out.tellp() < 50) out << ' '; + + out << value; } - return 0; + std::cout << out.str() << "\n"; + } + +std::string type_name(ASN1_Tag type) + { + if(type == PRINTABLE_STRING) return "PRINTABLE STRING"; + if(type == NUMERIC_STRING) return "NUMERIC STRING"; + if(type == IA5_STRING) return "IA5 STRING"; + if(type == T61_STRING) return "T61 STRING"; + if(type == UTF8_STRING) return "UTF8 STRING"; + if(type == VISIBLE_STRING) return "VISIBLE STRING"; + if(type == BMP_STRING) return "BMP STRING"; + + if(type == UTC_TIME) return "UTC TIME"; + if(type == GENERALIZED_TIME) return "GENERALIZED TIME"; + + if(type == OCTET_STRING) return "OCTET STRING"; + if(type == BIT_STRING) return "BIT STRING"; + + if(type == ENUMERATED) return "ENUMERATED"; + if(type == INTEGER) return "INTEGER"; + if(type == NULL_TAG) return "NULL"; + if(type == OBJECT_ID) return "OBJECT"; + if(type == BOOLEAN) return "BOOLEAN"; + return "(UNKNOWN)"; } void decode(BER_Decoder& decoder, size_t level) @@ -184,7 +206,7 @@ void decode(BER_Decoder& decoder, size_t level) std::vector<byte> rep; /* If it's small, it's probably a number, not a hash */ - if(number.bits() <= 16) + if(number.bits() <= 20) rep = BigInt::encode(number, BigInt::Decimal); else rep = BigInt::encode(number, BigInt::Hexadecimal); @@ -283,62 +305,38 @@ void decode(BER_Decoder& decoder, size_t level) } } -void emit(const std::string& type, size_t level, size_t length, - const std::string& value) +int asn1(int argc, char* argv[]) { - const size_t LIMIT = 128; - const size_t BIN_LIMIT = 64; - - std::ostringstream out; - - out << " d=" << std::setw(2) << level - << ", l=" << std::setw(4) << length << ": "; - - for(size_t i = INITIAL_LEVEL; i != level; ++i) - out << ' '; - - out << type; - - bool should_skip = false; - - if(value.length() > LIMIT) - should_skip = true; - - if((type == "OCTET STRING" || type == "BIT STRING") && value.length() > BIN_LIMIT) - should_skip = true; - - if(value != "" && !should_skip) + if(argc != 2) { - if(out.tellp() % 2 == 0) out << ' '; + std::cout << "Usage: " << argv[0] << " <file>\n"; + return 1; + } - while(out.tellp() < 50) out << ' '; + try { + DataSource_Stream in(argv[1]); - out << value; + if(!PEM_Code::matches(in)) + { + BER_Decoder decoder(in); + decode(decoder, INITIAL_LEVEL); + } + else + { + std::string label; // ignored + BER_Decoder decoder(PEM_Code::decode(in, label)); + decode(decoder, INITIAL_LEVEL); + } + } + catch(std::exception& e) + { + std::cout << "Error: " << e.what() << "\n"; + return 2; } - std::cout << out.str() << "\n"; + return 0; } -std::string type_name(ASN1_Tag type) - { - if(type == PRINTABLE_STRING) return "PRINTABLE STRING"; - if(type == NUMERIC_STRING) return "NUMERIC STRING"; - if(type == IA5_STRING) return "IA5 STRING"; - if(type == T61_STRING) return "T61 STRING"; - if(type == UTF8_STRING) return "UTF8 STRING"; - if(type == VISIBLE_STRING) return "VISIBLE STRING"; - if(type == BMP_STRING) return "BMP STRING"; - - if(type == UTC_TIME) return "UTC TIME"; - if(type == GENERALIZED_TIME) return "GENERALIZED TIME"; - - if(type == OCTET_STRING) return "OCTET STRING"; - if(type == BIT_STRING) return "BIT STRING"; +REGISTER_APP(asn1); - if(type == ENUMERATED) return "ENUMERATED"; - if(type == INTEGER) return "INTEGER"; - if(type == NULL_TAG) return "NULL"; - if(type == OBJECT_ID) return "OBJECT"; - if(type == BOOLEAN) return "BOOLEAN"; - return "(UNKNOWN)"; - } +} diff --git a/src/cmd/base64.cpp b/src/cmd/base64.cpp index 34711857c..de9954bab 100644 --- a/src/cmd/base64.cpp +++ b/src/cmd/base64.cpp @@ -15,7 +15,9 @@ #include <botan/b64_filt.h> #include <botan/pipe.h> -int base64_main(int argc, char* argv[]) +namespace { + +int base64(int argc, char* argv[]) { if(argc < 2) { @@ -83,3 +85,7 @@ int base64_main(int argc, char* argv[]) } return 0; } + +REGISTER_APP(base64); + +} diff --git a/src/cmd/bcrypt.cpp b/src/cmd/bcrypt.cpp index 2b4b4e61d..30b0c425a 100644 --- a/src/cmd/bcrypt.cpp +++ b/src/cmd/bcrypt.cpp @@ -3,7 +3,9 @@ #if defined(BOTAN_HAS_BCRYPT) #include <botan/bcrypt.h> -int bcrypt_main(int argc, char* argv[]) +namespace { + +int bcrypt(int argc, char* argv[]) { if(argc == 2) { @@ -32,6 +34,9 @@ int bcrypt_main(int argc, char* argv[]) << " " << argv[0] << " password passhash\n"; return 1; } -#else -UNIMPLEMENTED(bcrypt_main, "bcrypt"); + +REGISTER_APP(bcrypt); + +} + #endif diff --git a/src/cmd/bzip.cpp b/src/cmd/bzip.cpp index 3b8c7cdc2..15403ea88 100644 --- a/src/cmd/bzip.cpp +++ b/src/cmd/bzip.cpp @@ -7,29 +7,16 @@ #include "apps.h" -#include <string> -#include <cstring> -#include <vector> -#include <fstream> -#include <iostream> -#include <botan/botan.h> - -/* -* If Bzip2 isn't included, we know nothing works at compile time, but -* we wait to fail at runtime. Otherwise I would get 2-3 mails a month -* about how this was failing to compile (even with an informative -* #error message explaining the situation) because bzip2 wasn't -* included in the build. -*/ - #if defined(BOTAN_HAS_COMPRESSOR_BZIP2) - #include <botan/bzip2.h> -#endif -const std::string SUFFIX = ".bz2"; +#include <botan/bzip2.h> + +namespace { -int bzip_main(int argc, char* argv[]) +int bzip2(int argc, char* argv[]) { + const std::string SUFFIX = ".bz2"; + if(argc < 2) { std::cout << "Usage: " << argv[0] @@ -37,7 +24,6 @@ int bzip_main(int argc, char* argv[]) return 1; } -#ifdef BOTAN_HAS_COMPRESSOR_BZIP2 std::vector<std::string> files; bool decompress = false, small = false; int level = 9; @@ -104,12 +90,14 @@ int bzip_main(int argc, char* argv[]) catch(std::exception& e) { std::cout << "Exception caught: " << e.what() << std::endl; - return 1; + return 2; } -#else - - std::cout << "Sorry, support for bzip2 not compiled into Botan\n"; -#endif return 1; } + +REGISTER_APP(bzip2); + +} + +#endif diff --git a/src/cmd/ca.cpp b/src/cmd/ca.cpp index 7dba4c7fe..453258ac6 100644 --- a/src/cmd/ca.cpp +++ b/src/cmd/ca.cpp @@ -1,14 +1,14 @@ #include "apps.h" + #if defined(BOTAN_HAS_X509_CERTIFICATES) #include <botan/x509_ca.h> -using namespace Botan; -#include <iostream> -#include <memory> -#include <chrono> +namespace { -int ca_main(int argc, char* argv[]) +int ca(int argc, char* argv[]) { + using namespace Botan; + if(argc != 5) { std::cout << "Usage: " << argv[0] << " <passphrase> " @@ -61,4 +61,9 @@ int ca_main(int argc, char* argv[]) } return 0; } + +REGISTER_APP(ca); + +} + #endif diff --git a/src/cmd/cert_verify.cpp b/src/cmd/cert_verify.cpp index daf7240f2..800ac8f6c 100644 --- a/src/cmd/cert_verify.cpp +++ b/src/cmd/cert_verify.cpp @@ -6,15 +6,17 @@ */ #include "apps.h" + #if defined(BOTAN_HAS_X509_CERTIFICATES) -#include <botan/x509cert.h> + #include <botan/x509path.h> -#include <iostream> -using namespace Botan; +namespace { -int cert_verify_main(int argc, char* argv[]) +int cert_verify(int argc, char* argv[]) { + using namespace Botan; + if(argc <= 2) { std::cout << "Usage: " << argv[0] << " subject.pem [CA certificates...]\n"; @@ -42,4 +44,9 @@ int cert_verify_main(int argc, char* argv[]) return 0; } + +} + +REGISTER_APP(cert_verify); + #endif diff --git a/src/cmd/dsa_sign.cpp b/src/cmd/dsa_sign.cpp index 365e91a37..edbf135c3 100644 --- a/src/cmd/dsa_sign.cpp +++ b/src/cmd/dsa_sign.cpp @@ -1,23 +1,20 @@ #include "apps.h" -#include <iostream> -#include <iomanip> -#include <fstream> -#include <string> -#include <memory> - -#include <botan/base64.h> -#include <botan/pubkey.h> #if defined(BOTAN_HAS_DSA) #include <botan/dsa.h> +#include <botan/pubkey.h> +#include <botan/base64.h> +#include <fstream> -using namespace Botan; - -const std::string SUFFIX = ".sig"; +namespace { -int dsa_sign_main(int argc, char* argv[]) +int dsa_sign(int argc, char* argv[]) { + using namespace Botan; + + const std::string SUFFIX = ".sig"; + if(argc != 4) { std::cout << "Usage: " << argv[0] << " keyfile messagefile passphrase" @@ -73,6 +70,9 @@ int dsa_sign_main(int argc, char* argv[]) } return 0; } -#else -UNIMPLEMENTED(dsa_sign_main, "DSA"); + +REGISTER_APP(dsa_sign); + +} + #endif diff --git a/src/cmd/dsa_ver.cpp b/src/cmd/dsa_ver.cpp index a5d0ca271..dddf34dbf 100644 --- a/src/cmd/dsa_ver.cpp +++ b/src/cmd/dsa_ver.cpp @@ -1,28 +1,17 @@ #include "apps.h" -#include <iostream> -#include <iomanip> -#include <fstream> -#include <cstdlib> -#include <string> -#include <memory> +#if defined(BOTAN_HAS_DSA) + +#include <fstream> #include <botan/pubkey.h> #include <botan/dsa.h> -#include <botan/b64_filt.h> +#include <botan/base64.h> + using namespace Botan; namespace { -secure_vector<byte> b64_decode(const std::string& in) - { - Pipe pipe(new Base64_Decoder); - pipe.process_msg(in); - return pipe.read_all(); - } - -} - -int dsa_verify_main(int argc, char* argv[]) +int dsa_verify(int argc, char* argv[]) { if(argc != 4) { @@ -59,7 +48,7 @@ int dsa_verify_main(int argc, char* argv[]) return 1; } - secure_vector<byte> sig = b64_decode(sigstr); + secure_vector<byte> sig = base64_decode(sigstr); PK_Verifier ver(*dsakey, "EMSA1(SHA-1)"); @@ -71,14 +60,26 @@ int dsa_verify_main(int argc, char* argv[]) const bool ok = ver.check_signature(sig); if(ok) + { std::cout << "Signature verified\n"; + return 0; + } else + { std::cout << "Signature did NOT verify\n"; + return 1; + } } catch(std::exception& e) { std::cout << "Exception caught: " << e.what() << std::endl; - return 1; + return 2; } - return 0; } + +REGISTER_APP(dsa_verify); + +} + +#endif + diff --git a/src/cmd/factor.cpp b/src/cmd/factor.cpp index 5f6d82f8c..b95b8ea95 100644 --- a/src/cmd/factor.cpp +++ b/src/cmd/factor.cpp @@ -11,12 +11,13 @@ #include <botan/reducer.h> #include <botan/numthry.h> -using namespace Botan; #include <algorithm> #include <iostream> #include <iterator> +using namespace Botan; + namespace { /* @@ -119,9 +120,7 @@ std::vector<BigInt> factorize(const BigInt& n_in, return factors; } -} - -int factor_main(int argc, char* argv[]) +int factor(int argc, char* argv[]) { if(argc != 2) { @@ -151,3 +150,7 @@ int factor_main(int argc, char* argv[]) } return 0; } + +REGISTER_APP(factor); + +} diff --git a/src/cmd/fpe.cpp b/src/cmd/fpe.cpp index d1e748b4c..088b10e82 100644 --- a/src/cmd/fpe.cpp +++ b/src/cmd/fpe.cpp @@ -1,14 +1,13 @@ #include "apps.h" #if defined(BOTAN_HAS_FPE_FE1) + #include <botan/fpe_fe1.h> #include <botan/sha160.h> +#include <stdexcept> using namespace Botan; -#include <iostream> -#include <stdexcept> - namespace { byte luhn_checksum(u64bit cc_number) @@ -102,9 +101,7 @@ u64bit decrypt_cc_number(u64bit enc_cc, return cc_derank(dec_cc); } -} - -int fpe_main(int argc, char* argv[]) +int fpe(int argc, char* argv[]) { if(argc != 4) { @@ -143,6 +140,10 @@ int fpe_main(int argc, char* argv[]) return 0; } -#else -UNIMPLEMENTED(fpe_main, "FPE"); + +REGISTER_APP(fpe); + +} + #endif + diff --git a/src/cmd/getopt.h b/src/cmd/getopt.h index a4f5f4d6f..4fecada2a 100644 --- a/src/cmd/getopt.h +++ b/src/cmd/getopt.h @@ -43,50 +43,30 @@ class OptionParser return is_set(key) ? value(key) : or_else; } - void parse(char* argv[]) + size_t int_value_or_else(const std::string& key, size_t or_else) const { - std::vector<std::string> args; - for(int j = 1; argv[j]; j++) - args.push_back(argv[j]); - - for(size_t j = 0; j != args.size(); j++) - { - std::string arg = args[j]; - - if(arg.size() > 2 && arg[0] == '-' && arg[1] == '-') - { - const std::string opt_name = arg.substr(0, arg.find('=')); - - arg = arg.substr(2); - - std::string::size_type mark = arg.find('='); - OptionFlag opt = find_option(arg.substr(0, mark)); - - if(opt.takes_arg()) - { - if(mark == std::string::npos) - throw std::runtime_error("Option " + opt_name + - " requires an argument"); - - std::string name = arg.substr(0, mark); - std::string value = arg.substr(mark+1); + return is_set(key) ? Botan::to_u32bit(value(key)) : or_else; + } - options[name] = value; - } - else - { - if(mark != std::string::npos) - throw std::runtime_error("Option " + opt_name + - " does not take an argument"); + void help(std::ostream& o, const char* cmd = nullptr) + { + o << "Usage: "; + if(cmd) + o << cmd << " "; - options[arg] = ""; - } - } - else - leftover.push_back(arg); + for(auto flag : flags) + { + o << flag.name(); + if(flag.takes_arg()) + o << "="; + o << " "; } + + o << "\n"; } + void parse(char* argv[]); + OptionParser(const std::string& opt_string) { std::vector<std::string> opts = Botan::split_on(opt_string, '|'); diff --git a/src/cmd/hash.cpp b/src/cmd/hash.cpp index 5c5705210..869eb5797 100644 --- a/src/cmd/hash.cpp +++ b/src/cmd/hash.cpp @@ -11,7 +11,9 @@ using namespace Botan; -int hash_main(int argc, char* argv[]) +namespace { + +int hash(int argc, char* argv[]) { if(argc < 3) { @@ -56,3 +58,7 @@ int hash_main(int argc, char* argv[]) } return 0; } + +REGISTER_APP(hash); + +} diff --git a/src/cmd/is_prime.cpp b/src/cmd/is_prime.cpp index 658401690..8bfa4421a 100644 --- a/src/cmd/is_prime.cpp +++ b/src/cmd/is_prime.cpp @@ -1,7 +1,9 @@ #include "apps.h" #include <botan/numthry.h> -int is_prime_main(int argc, char* argv[]) +namespace { + +int is_prime(int argc, char* argv[]) { if(argc != 2 && argc != 3) { @@ -31,3 +33,7 @@ int is_prime_main(int argc, char* argv[]) return 1; } } + +REGISTER_APP(is_prime); + +} diff --git a/src/cmd/keygen.cpp b/src/cmd/keygen.cpp index 40055f6cf..6aa74a08f 100644 --- a/src/cmd/keygen.cpp +++ b/src/cmd/keygen.cpp @@ -5,29 +5,74 @@ #include <cstdlib> #include <memory> +#if defined(BOTAN_HAS_RSA) #include <botan/rsa.h> +#endif + +#if defined(BOTAN_HAS_DSA) +#include <botan/dsa.h> +#endif + +#if defined(BOTAN_HAS_ECDSA) +#include <botan/ecdsa.h> +#endif + using namespace Botan; -int keygen_main(int argc, char* argv[]) +namespace { + +std::string dsa_group_for(size_t bits) + { + if(bits == 1024) + return "dsa/jce/1024"; + if(bits == 2048) + return "dsa/botan/2048"; + if(bits == 3072) + return "dsa/botan/3072"; + throw std::runtime_error("No registered DSA group for " + std::to_string(bits) + " bits"); + } + +Private_Key* gen_key(RandomNumberGenerator& rng, const std::string& algo, size_t bits) { - if(argc != 2 && argc != 3) +#if defined(BOTAN_HAS_RSA) + if(algo == "rsa") + return new RSA_PrivateKey(rng, bits); +#endif + +#if defined(BOTAN_HAS_DSA) + if(algo == "dsa") { - std::cout << "Usage: " << argv[0] << " bitsize [passphrase]" - << std::endl; - return 1; + DL_Group grp(dsa_group_for(bits)); + return new DSA_PrivateKey(rng, grp); } +#endif - const size_t bits = std::atoi(argv[1]); - if(bits < 1024 || bits > 16384) +#if defined(BOTAN_HAS_ECDSA) + if(algo == "ecdsa") { - std::cout << "Invalid argument for bitsize" << std::endl; - return 1; + EC_Group grp("secp" + std::to_string(bits) + "r1"); + return new ECDSA_PrivateKey(rng, grp); } +#endif + + throw std::runtime_error("Unknown algorithm " + algo); + } + + +int keygen(int argc, char* argv[]) + { + OptionParser opts("algo=|bits=|passphrase="); + opts.parse(argv); + + const std::string algo = opts.value_or_else("algo", "rsa"); + const size_t bits = opts.int_value_or_else("bits", 1024); + const std::string pass = opts.value_or_else("passphrase", ""); try { - std::ofstream pub("rsapub.pem"); - std::ofstream priv("rsapriv.pem"); + std::ofstream pub("public.pem"); + std::ofstream priv("private.pem"); + if(!priv || !pub) { std::cout << "Couldn't write output files" << std::endl; @@ -36,13 +81,16 @@ int keygen_main(int argc, char* argv[]) AutoSeeded_RNG rng; - RSA_PrivateKey key(rng, bits); - pub << X509::PEM_encode(key); + std::auto_ptr<Private_Key> key(gen_key(rng, algo, bits)); - if(argc == 2) - priv << PKCS8::PEM_encode(key); + pub << X509::PEM_encode(*key); + + if(pass == "") + priv << PKCS8::PEM_encode(*key); else - priv << PKCS8::PEM_encode(key, rng, argv[2]); + priv << PKCS8::PEM_encode(*key, rng, pass); + + std::cout << "Wrote " << bits << " bit " << algo << " key to public.pem / private.pem\n"; } catch(std::exception& e) { @@ -51,3 +99,7 @@ int keygen_main(int argc, char* argv[]) return 0; } + +REGISTER_APP(keygen); + +} diff --git a/src/cmd/main.cpp b/src/cmd/main.cpp index f04c7daee..65530b23a 100644 --- a/src/cmd/main.cpp +++ b/src/cmd/main.cpp @@ -30,12 +30,30 @@ namespace { int help(int , char* argv[]) { - std::cout << "Usage: " << argv[0] << " [subcommand]\n"; - std::cout << "version config speed cpuid bcrypt x509 factor tls_client tls_server asn1 base64 hash self_sig ...\n"; + std::cout << "Usage: " << argv[0] << " [subcommand] [subcommand-options]\n"; + + std::set<std::string> apps = AppRegistrations::instance().all_apps(); + + std::cout << "Available commands:\n"; + + size_t idx = 1; + for(auto&& app: apps) + { + std::cout << app; + + if(idx % 3 == 0) + std::cout << "\n"; + else + std::cout << std::string(18-app.size(), ' '); + + ++idx; + } + std::cout << "\n"; + return 1; } -int config_main(int argc, char* argv[]) +int config(int argc, char* argv[]) { if(argc != 2) { @@ -70,8 +88,9 @@ int config_main(int argc, char* argv[]) return 0; } +REGISTER_APP(config); -int version_main(int argc, char* argv[]) +int version(int argc, char* argv[]) { if(BOTAN_VERSION_MAJOR != version_major() || BOTAN_VERSION_MINOR != version_minor() || @@ -99,20 +118,39 @@ int version_main(int argc, char* argv[]) } else { - std::cout << "Usage: " << argv[0] << " [--full]\n"; + std::cout << "Usage: " << argv[0] << " version [--full]\n"; return 1; } return 0; } +REGISTER_APP(version); -} +int cpuid(int, char*[]) + { + CPUID::print(std::cout); + return 0; + } +REGISTER_APP(cpuid); -int unimplemented(int , char* argv[], const char* what) +#if defined(BOTAN_HAS_HTTP_UTIL) +int http_get(int argc, char* argv[]) { - std::cout << argv[0] << " command not implemented - library missing " << what << "\n"; - return 1; + if(argc != 2) + { + std::cout << "Usage " << argv[0] << " <url>\n"; + return 1; + } + + auto resp = HTTP::GET_sync(argv[2]); + std::cout << resp << "\n"; + return 0; } +REGISTER_APP(http_get); + +#endif + +} int main(int argc, char* argv[]) { @@ -125,59 +163,12 @@ int main(int argc, char* argv[]) const std::string cmd = argv[1]; - if(cmd == "help") + if(cmd == "help" || cmd == "-h") return help(argc, argv); - if(cmd == "config" && argc > 1) - return config_main(argc - 1, argv + 1); - - if(cmd == "version" && argc > 1) - return version_main(argc - 1, argv + 1); - - if(cmd == "cpuid") - { - CPUID::print(std::cout); - return 0; - } - -#if defined(BOTAN_HAS_HTTP_UTIL) - if(cmd == "http_get") - { - auto resp = HTTP::GET_sync(argv[2]); - std::cout << resp << "\n"; - } -#endif - -#define CALL_APP(cmdsym) \ - do { if(cmd == #cmdsym) { return cmdsym ##_main (argc - 1, argv + 1); } } while(0) - - CALL_APP(asn1); - CALL_APP(base64); - CALL_APP(bcrypt); - CALL_APP(bzip); - CALL_APP(dsa_sign); - CALL_APP(dsa_verify); - CALL_APP(factor); - CALL_APP(fpe); - CALL_APP(hash); - CALL_APP(is_prime); - CALL_APP(keygen); - CALL_APP(read_ssh); - CALL_APP(rng); - CALL_APP(speed); - -#if defined(BOTAN_HAS_TLS) - CALL_APP(tls_client); - CALL_APP(tls_server); - CALL_APP(tls_server_asio); -#endif - -#if defined(BOTAN_HAS_X509_CERTIFICATES) - CALL_APP(ca); - CALL_APP(pkcs10); - CALL_APP(self_sig); - CALL_APP(x509); -#endif + AppRegistrations& apps = AppRegistrations::instance(); + if(apps.has(cmd)) + return apps.run(cmd, argc - 1, argv + 1); std::cout << "Unknown command " << cmd << "\n"; return help(argc, argv); diff --git a/src/cmd/ocsp.cpp b/src/cmd/ocsp.cpp index a36dd73f6..dba49b600 100644 --- a/src/cmd/ocsp.cpp +++ b/src/cmd/ocsp.cpp @@ -1,15 +1,17 @@ #include "apps.h" -#if defined(BOTAN_HAS_X509_CERTIFICATES) + +#if defined(BOTAN_HAS_OCSP) + #include <botan/x509cert.h> #include <botan/certstor.h> #include <botan/x509path.h> #include <botan/ocsp.h> -#include <iostream> - using namespace Botan; -int ocsp_check_main(int argc, char* argv[]) +namespace { + +int ocsp_check(int argc, char* argv[]) { if(argc != 2) { @@ -37,4 +39,9 @@ int ocsp_check_main(int argc, char* argv[]) return 1; } } + +REGISTER_APP(ocsp_check); + +} + #endif diff --git a/src/cmd/pkcs10.cpp b/src/cmd/pkcs10.cpp index 2dad14575..0cdb47878 100644 --- a/src/cmd/pkcs10.cpp +++ b/src/cmd/pkcs10.cpp @@ -1,15 +1,17 @@ #include "apps.h" + #if defined(BOTAN_HAS_X509_CERTIFICATES) #include <botan/x509self.h> #include <botan/rsa.h> #include <botan/dsa.h> using namespace Botan; -#include <iostream> #include <fstream> #include <memory> -int pkcs10_main(int argc, char* argv[]) +namespace { + +int pkcs10(int argc, char* argv[]) { if(argc != 6) { @@ -47,4 +49,9 @@ int pkcs10_main(int argc, char* argv[]) } return 0; } + +REGISTER_APP(pkcs10); + +} + #endif diff --git a/src/cmd/read_ssh.cpp b/src/cmd/read_ssh.cpp deleted file mode 100644 index bca4a2a0a..000000000 --- a/src/cmd/read_ssh.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* -* (C) 2009 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -/* -* Example of reading SSH2 format public keys (see RFC 4716) -*/ - -#include "apps.h" - -#include <botan/x509_key.h> -#include <botan/filters.h> -#include <botan/loadstor.h> -#include <botan/rsa.h> -#include <botan/dsa.h> -#include <fstream> -#include <memory> - -using namespace Botan; - -namespace { - -u32bit read_u32bit(Pipe& pipe) - { - byte out[4] = { 0 }; - pipe.read(out, 4); - u32bit len = load_be<u32bit>(out, 0); - if(len > 10000) - throw Decoding_Error("Huge size in read_u32bit, something went wrong"); - return len; - } - -std::string read_string(Pipe& pipe) - { - u32bit len = read_u32bit(pipe); - - std::string out(len, 'X'); - pipe.read(reinterpret_cast<byte*>(&out[0]), len); - return out; - } - -BigInt read_bigint(Pipe& pipe) - { - u32bit len = read_u32bit(pipe); - - secure_vector<byte> buf(len); - pipe.read(&buf[0], len); - return BigInt::decode(buf); - } - -Public_Key* read_ssh_pubkey(const std::string& file) - { - std::ifstream in(file.c_str()); - - const std::string ssh_header = "---- BEGIN SSH2 PUBLIC KEY ----"; - const std::string ssh_trailer = "---- END SSH2 PUBLIC KEY ----"; - - std::string hex_bits; - - std::string line; - std::getline(in, line); - - if(line != ssh_header) - return nullptr; - - while(in.good()) - { - std::getline(in, line); - - if(line.find("Comment: ") == 0) - { - while(line[line.size()-1] == '\\') - std::getline(in, line); - std::getline(in, line); - } - - if(line == ssh_trailer) - break; - - hex_bits += line; - } - - Pipe pipe(new Base64_Decoder); - pipe.process_msg(hex_bits); - - std::string key_type = read_string(pipe); - - if(key_type != "ssh-rsa" && key_type != "ssh-dss") - return nullptr; - - if(key_type == "ssh-rsa") - { - BigInt e = read_bigint(pipe); - BigInt n = read_bigint(pipe); - return new RSA_PublicKey(n, e); - } - else if(key_type == "ssh-dss") - { - BigInt p = read_bigint(pipe); - BigInt q = read_bigint(pipe); - BigInt g = read_bigint(pipe); - BigInt y = read_bigint(pipe); - - return new DSA_PublicKey(DL_Group(p, q, g), y); - } - - return nullptr; - } - -} - -int read_ssh_main(int argc, char* argv[]) - { - if(argc != 2) - { - std::cout << "Usage: " << argv[0] << " file"; - return 1; - } - - const std::string filename = argv[1]; - std::unique_ptr<Public_Key> key(read_ssh_pubkey(filename)); - - if(!key) - { - std::cout << "Failed to read" << filename << "\n"; - return 1; - } - - std::cout << X509::PEM_encode(*key); - - return 0; - } diff --git a/src/cmd/rng.cpp b/src/cmd/rng.cpp index e2a7a8270..187fbad1e 100644 --- a/src/cmd/rng.cpp +++ b/src/cmd/rng.cpp @@ -7,7 +7,9 @@ #include "apps.h" #include <botan/libstate.h> -int rng_main(int argc, char* argv[]) +namespace { + +int rng(int argc, char* argv[]) { if(argc == 1) { @@ -49,3 +51,7 @@ int rng_main(int argc, char* argv[]) return 0; } + +REGISTER_APP(rng); + +} diff --git a/src/cmd/self_sig.cpp b/src/cmd/self_sig.cpp index 592a7f279..2bef9492d 100644 --- a/src/cmd/self_sig.cpp +++ b/src/cmd/self_sig.cpp @@ -1,15 +1,17 @@ #include "apps.h" + #if defined(BOTAN_HAS_X509_CERTIFICATES) #include <botan/x509self.h> #include <botan/rsa.h> #include <botan/dsa.h> using namespace Botan; -#include <iostream> #include <fstream> #include <memory> -int self_sig_main(int argc, char* argv[]) +namespace { + +int self_sig(int argc, char* argv[]) { if(argc != 7) { @@ -69,4 +71,9 @@ int self_sig_main(int argc, char* argv[]) return 0; } + +REGISTER_APP(self_sig); + +} + #endif diff --git a/src/cmd/speed/speed.cpp b/src/cmd/speed.cpp index e7e3e5ff7..9c6d8a585 100644 --- a/src/cmd/speed/speed.cpp +++ b/src/cmd/speed.cpp @@ -5,6 +5,7 @@ */ #include "speed.h" +#include "apps.h" #include <iostream> #include <iomanip> @@ -170,8 +171,6 @@ void time_transform(const std::string& algo, RandomNumberGenerator& rng) time_transform(std::move(tf), rng); } -} - void bench_algo(const std::string& algo, RandomNumberGenerator& rng, double seconds, @@ -193,7 +192,7 @@ void bench_algo(const std::string& algo, bench_pk(rng, algo, seconds); } -int speed_main(int argc, char* argv[]) +int speed(int argc, char* argv[]) { OptionParser opts("seconds=|buf-size="); opts.parse(argv); @@ -239,3 +238,7 @@ int speed_main(int argc, char* argv[]) return 0; } + +REGISTER_APP(speed); + +} diff --git a/src/cmd/speed.h b/src/cmd/speed.h new file mode 100644 index 000000000..97aa0ecc1 --- /dev/null +++ b/src/cmd/speed.h @@ -0,0 +1,11 @@ + +#ifndef BOTAN_CHECK_BENCHMARK_H__ +#define BOTAN_CHECK_BENCHMARK_H__ + +#include <botan/rng.h> +#include <string> + +void bench_pk(Botan::RandomNumberGenerator& rng, + const std::string& algo, double seconds); + +#endif diff --git a/src/cmd/speed/speed.h b/src/cmd/speed/speed.h deleted file mode 100644 index b4aabca8a..000000000 --- a/src/cmd/speed/speed.h +++ /dev/null @@ -1,25 +0,0 @@ - -#ifndef BOTAN_CHECK_BENCHMARK_H__ -#define BOTAN_CHECK_BENCHMARK_H__ - -#include "../apps.h" -#include <botan/rng.h> -#include <botan/transform.h> -#include <string> - -using namespace Botan; - -int speed_main(int argc, char* argv[]); - -void benchmark(double seconds, - size_t buf_size); - -void bench_algo(const std::string& algo_name, - RandomNumberGenerator& rng, - double seconds, - size_t buf_size); - -void bench_pk(RandomNumberGenerator& rng, - const std::string& algo, double seconds); - -#endif diff --git a/src/cmd/speed/pk_bench.cpp b/src/cmd/speed_pk.cpp index 6ebb366c5..6ebb366c5 100644 --- a/src/cmd/speed/pk_bench.cpp +++ b/src/cmd/speed_pk.cpp diff --git a/src/cmd/speed/timer.cpp b/src/cmd/timer.cpp index 9f3d34607..14eb47524 100644 --- a/src/cmd/speed/timer.cpp +++ b/src/cmd/timer.cpp @@ -8,31 +8,23 @@ #include <chrono> #include <iomanip> -Timer::Timer(const std::string& n, u32bit e_mul) : - name(n), event_mult(e_mul) - { - time_used = 0; - timer_start = 0; - event_count = 0; - } - void Timer::start() { stop(); - timer_start = get_clock(); + m_timer_start = get_clock(); } void Timer::stop() { - if(timer_start) + if(m_timer_start) { - u64bit now = get_clock(); + const u64bit now = get_clock(); - if(now > timer_start) - time_used += (now - timer_start); + if(now > m_timer_start) + m_time_used += (now - m_timer_start); - timer_start = 0; - ++event_count; + m_timer_start = 0; + ++m_event_count; } } diff --git a/src/cmd/speed/timer.h b/src/cmd/timer.h index 48d6b6805..8e3dc6b26 100644 --- a/src/cmd/speed/timer.h +++ b/src/cmd/timer.h @@ -14,25 +14,25 @@ class Timer public: static u64bit get_clock(); - Timer(const std::string& name, u32bit event_mult = 1); + Timer(const std::string& name, u32bit event_mult = 1) : + m_name(name), m_event_mult(event_mult) {} void start(); - void stop(); - u64bit value() { stop(); return time_used; } + u64bit value() { stop(); return m_time_used; } double seconds() { return milliseconds() / 1000.0; } double milliseconds() { return value() / 1000000.0; } double ms_per_event() { return milliseconds() / events(); } double seconds_per_event() { return seconds() / events(); } - u64bit events() const { return event_count * event_mult; } - std::string get_name() const { return name; } + u64bit events() const { return m_event_count * m_event_mult; } + std::string get_name() const { return m_name; } private: - std::string name; - u64bit time_used, timer_start; - u64bit event_count, event_mult; + std::string m_name; + u64bit m_time_used = 0, m_timer_start = 0; + u64bit m_event_count = 0, m_event_mult = 0; }; inline bool operator<(const Timer& x, const Timer& y) diff --git a/src/cmd/tls_client.cpp b/src/cmd/tls_client.cpp index 5df6e72c5..072d674ea 100644 --- a/src/cmd/tls_client.cpp +++ b/src/cmd/tls_client.cpp @@ -10,7 +10,6 @@ #endif #include <string> -#include <iostream> #include <memory> #include <sys/types.h> @@ -132,9 +131,7 @@ std::string protocol_chooser(const std::vector<std::string>& protocols) return "http/1.1"; } -} - -int tls_client_main(int argc, char* argv[]) +int tls_client(int argc, char* argv[]) { if(argc != 2 && argc != 3 && argc != 4) { @@ -272,4 +269,7 @@ int tls_client_main(int argc, char* argv[]) return 0; } +REGISTER_APP(tls_client); + +} #endif diff --git a/src/cmd/tls_server.cpp b/src/cmd/tls_server.cpp index 9db250859..fd9f7ef5d 100644 --- a/src/cmd/tls_server.cpp +++ b/src/cmd/tls_server.cpp @@ -15,9 +15,6 @@ using namespace Botan; using namespace std::placeholders; -#include <string> -#include <iostream> -#include <memory> #include <list> #include <sys/types.h> @@ -120,9 +117,7 @@ void alert_received(TLS::Alert alert, const byte[], size_t) std::cout << "Alert: " << alert.type_string() << "\n"; } -} - -int tls_server_main(int argc, char* argv[]) +int tls_server(int argc, char* argv[]) { int port = 4433; std::string transport = "tcp"; @@ -262,4 +257,8 @@ int tls_server_main(int argc, char* argv[]) return 0; } +REGISTER_APP(tls_server); + +} + #endif diff --git a/src/cmd/tls_server_asio.cpp b/src/cmd/tls_server_asio.cpp index f0847b9e0..33d743e4f 100644 --- a/src/cmd/tls_server_asio.cpp +++ b/src/cmd/tls_server_asio.cpp @@ -276,9 +276,7 @@ size_t choose_thread_count() return 2; } -} - -int tls_server_asio_main(int argc, char* argv[]) +int tls_server_asio(int argc, char* argv[]) { try { @@ -315,4 +313,8 @@ int tls_server_asio_main(int argc, char* argv[]) return 0; } +} + +REGISTER_APP(tls_server_asio); + #endif diff --git a/src/cmd/x509print.cpp b/src/cmd/x509print.cpp index c2c63021c..006c51de8 100644 --- a/src/cmd/x509print.cpp +++ b/src/cmd/x509print.cpp @@ -2,7 +2,9 @@ #if defined(BOTAN_HAS_X509_CERTIFICATES) #include <botan/x509cert.h> -int x509_main(int argc, char* argv[]) +namespace { + +int x509print(int argc, char* argv[]) { if(argc < 1) { @@ -16,4 +18,9 @@ int x509_main(int argc, char* argv[]) return 0; } + +REGISTER_APP(x509print); + +} + #endif |