aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-12-02 16:31:16 -0500
committerJack Lloyd <[email protected]>2018-12-02 16:31:16 -0500
commit163e59f4af51f802c5e77fc0bb8c0901a7fa62ea (patch)
treed6d274f449efea663d236bd293f4e1bebf7fc7c4 /src
parent7bc0745c3ff2824f9a3607db19e7e1a3e563c5bc (diff)
parentc3cbf959aa628ae541e4009894b040ab242dd45e (diff)
Merge GH #1756 Support getting passphrase from the console
Diffstat (limited to 'src')
-rw-r--r--src/cli/cli.cpp45
-rw-r--r--src/cli/cli.h7
-rw-r--r--src/cli/psk.cpp6
-rw-r--r--src/cli/pubkey.cpp19
-rw-r--r--src/cli/tls_client.cpp2
-rw-r--r--src/cli/tls_http_server.cpp2
-rw-r--r--src/cli/tls_proxy.cpp2
-rw-r--r--src/cli/utils.cpp7
-rw-r--r--src/cli/x509.cpp16
-rw-r--r--src/lib/utils/os_utils.cpp101
-rw-r--r--src/lib/utils/os_utils.h27
11 files changed, 186 insertions, 48 deletions
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp
index f8ec55e7b..1918a4fbd 100644
--- a/src/cli/cli.cpp
+++ b/src/cli/cli.cpp
@@ -8,13 +8,10 @@
#include "argparse.h"
#include <botan/rng.h>
#include <botan/parsing.h>
+#include <botan/internal/os_utils.h>
#include <iostream>
#include <fstream>
-#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
- #include <termios.h>
-#endif
-
namespace Botan_CLI {
Command::Command(const std::string& cmd_spec) : m_spec(cmd_spec)
@@ -210,33 +207,35 @@ Botan::RandomNumberGenerator& Command::rng()
return *m_rng.get();
}
-std::string Command::get_passphrase(const std::string& prompt)
+std::string Command::get_passphrase_arg(const std::string& prompt, const std::string& opt_name)
{
- error_output() << prompt << ": " << std::flush;
- std::string pass;
+ const std::string s = get_arg(opt_name);
+ if(s != "-")
+ return s;
+ return get_passphrase(prompt);
+ }
-#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
+namespace {
- struct termios old_flags;
- int stdin_fd = fileno(stdin);
- ::tcgetattr(stdin_fd, &old_flags);
- struct termios noecho_flags = old_flags;
- noecho_flags.c_lflag &= ~ECHO;
- noecho_flags.c_lflag |= ECHONL;
+bool echo_suppression_supported()
+ {
+ auto echo = Botan::OS::suppress_echo_on_terminal();
+ return (echo != nullptr);
+ }
- if(::tcsetattr(stdin_fd, TCSANOW, &noecho_flags) != 0)
- throw CLI_Error("Clearing terminal echo bit failed");
+}
- std::getline(std::cin, pass);
+std::string Command::get_passphrase(const std::string& prompt)
+ {
+ if(echo_suppression_supported() == false)
+ error_output() << "Warning: terminal echo suppression not enabled for this platform\n";
- if(::tcsetattr(stdin_fd, TCSANOW, &old_flags) != 0)
- throw CLI_Error("Restoring terminal echo bit failed");
-#else
+ error_output() << prompt << ": " << std::flush;
+ std::string pass;
- // TODO equivalent for Windows ...
- std::getline(std::cin, pass);
+ auto echo_suppress = Botan::OS::suppress_echo_on_terminal();
-#endif
+ std::getline(std::cin, pass);
return pass;
}
diff --git a/src/cli/cli.h b/src/cli/cli.h
index fca8e5225..b6f6a3076 100644
--- a/src/cli/cli.h
+++ b/src/cli/cli.h
@@ -124,6 +124,13 @@ class Command
std::string get_arg(const std::string& opt_name) const;
+ /**
+ * Like get_arg but if the value is '-' then reads a passphrase from
+ * the terminal with echo suppressed.
+ */
+ std::string get_passphrase_arg(const std::string& prompt,
+ const std::string& opt_name);
+
/*
* Like get_arg() but if the argument was not specified or is empty, returns otherwise
*/
diff --git a/src/cli/psk.cpp b/src/cli/psk.cpp
index 45a5918d8..83b60225d 100644
--- a/src/cli/psk.cpp
+++ b/src/cli/psk.cpp
@@ -27,7 +27,7 @@ class PSK_Tool_Base : public Command
void go() override
{
const std::string db_filename = get_arg("db");
- const Botan::secure_vector<uint8_t> db_key = Botan::hex_decode_locked(get_arg("db_key"));
+ const Botan::secure_vector<uint8_t> db_key = Botan::hex_decode_locked(get_passphrase_arg("Database key", "db_key"));
std::shared_ptr<Botan::SQL_Database> db = std::make_shared<Botan::Sqlite3_Database>(db_filename);
Botan::Encrypted_PSK_Database_SQL psk(db_key, db, "psk");
@@ -53,8 +53,8 @@ class PSK_Tool_Set final : public PSK_Tool_Base
void psk_operation(Botan::PSK_Database& db) override
{
const std::string name = get_arg("name");
- Botan::secure_vector<uint8_t> key = Botan::hex_decode_locked(get_arg("psk"));
- db.set_vec(name, key);
+ const Botan::secure_vector<uint8_t> psk = Botan::hex_decode_locked(get_passphrase_arg("PSK", "psk"));
+ db.set_vec(name, psk);
}
};
diff --git a/src/cli/pubkey.cpp b/src/cli/pubkey.cpp
index 46655a6ae..6011c9701 100644
--- a/src/cli/pubkey.cpp
+++ b/src/cli/pubkey.cpp
@@ -60,7 +60,7 @@ class PK_Keygen final : public Command
throw CLI_Error_Unsupported("keygen", algo);
}
- const std::string pass = get_arg("passphrase");
+ const std::string pass = get_passphrase_arg("Key passphrase", "passphrase");
const bool der_out = flag_set("der-out");
const std::chrono::milliseconds pbe_millis(get_arg_sz("pbe-millis"));
@@ -168,11 +168,11 @@ class PK_Sign final : public Command
void go() override
{
- std::unique_ptr<Botan::Private_Key> key(
- Botan::PKCS8::load_key(
- get_arg("key"),
- rng(),
- get_arg("passphrase")));
+ const std::string key_file = get_arg("key");
+ const std::string passphrase = get_passphrase_arg("Passphrase for " + key_file, "passphrase");
+
+ Botan::DataSource_Stream input(key_file);
+ std::unique_ptr<Botan::Private_Key> key = Botan::PKCS8::load_key(input, passphrase);;
if(!key)
{
@@ -265,9 +265,10 @@ class PKCS8_Tool final : public Command
void go() override
{
- const std::string pass_in = get_arg("pass-in");
+ const std::string key_file = get_arg("key");
+ const std::string pass_in = get_passphrase_arg("Password for " + key_file, "pass-in");
- Botan::DataSource_Memory key_src(slurp_file(get_arg("key")));
+ Botan::DataSource_Memory key_src(slurp_file(key_file));
std::unique_ptr<Botan::Private_Key> key;
if(pass_in.empty())
@@ -296,7 +297,7 @@ class PKCS8_Tool final : public Command
}
else
{
- const std::string pass_out = get_arg("pass-out");
+ const std::string pass_out = get_passphrase_arg("Passphrase to encrypt key", "pass-out");
if(der_out)
{
diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp
index dfe874313..32ae4cea5 100644
--- a/src/cli/tls_client.cpp
+++ b/src/cli/tls_client.cpp
@@ -101,7 +101,7 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks
if(!sessions_db.empty())
{
#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
- const std::string sessions_passphrase = get_arg("session-db-pass");
+ const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass");
session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db));
#else
error_output() << "Ignoring session DB file, sqlite not enabled\n";
diff --git a/src/cli/tls_http_server.cpp b/src/cli/tls_http_server.cpp
index 6b5cefab4..cc59a71c3 100644
--- a/src/cli/tls_http_server.cpp
+++ b/src/cli/tls_http_server.cpp
@@ -531,7 +531,7 @@ class TLS_HTTP_Server final : public Command
if(!sessions_db.empty())
{
#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
- const std::string sessions_passphrase = get_arg("session-db-pass");
+ const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass");
session_mgr.reset(new Botan::TLS::Session_Manager_SQLite(sessions_passphrase, rng(), sessions_db));
#else
throw CLI_Error_Unsupported("Sqlite3 support not available");
diff --git a/src/cli/tls_proxy.cpp b/src/cli/tls_proxy.cpp
index 717bbc6c6..49ffbe376 100644
--- a/src/cli/tls_proxy.cpp
+++ b/src/cli/tls_proxy.cpp
@@ -453,7 +453,7 @@ class TLS_Proxy final : public Command
std::unique_ptr<Botan::TLS::Session_Manager> session_mgr;
#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
- const std::string sessions_passphrase = get_arg("session-db-pass");
+ const std::string sessions_passphrase = get_passphrase_arg("Session DB passphrase", "session-db-pass");
const std::string sessions_db = get_arg("session-db");
if(!sessions_db.empty())
diff --git a/src/cli/utils.cpp b/src/cli/utils.cpp
index 1a7639937..99471fba5 100644
--- a/src/cli/utils.cpp
+++ b/src/cli/utils.cpp
@@ -540,7 +540,7 @@ class Generate_Bcrypt final : public Command
void go() override
{
- const std::string password = get_arg("password");
+ const std::string password = get_passphrase_arg("Passphrase to hash", "password");
const size_t wf = get_arg_sz("work-factor");
if(wf < 4 || wf > 18)
@@ -574,7 +574,7 @@ class Check_Bcrypt final : public Command
void go() override
{
- const std::string password = get_arg("password");
+ const std::string password = get_passphrase_arg("Password to check", "password");
const std::string hash = get_arg("hash");
if(hash.length() != 60)
@@ -585,6 +585,9 @@ class Check_Bcrypt final : public Command
const bool ok = Botan::check_bcrypt(password, hash);
output() << "Password is " << (ok ? "valid" : "NOT valid") << std::endl;
+
+ if(ok == false)
+ set_return_code(1);
}
};
diff --git a/src/cli/x509.cpp b/src/cli/x509.cpp
index adae8285c..d894b99a4 100644
--- a/src/cli/x509.cpp
+++ b/src/cli/x509.cpp
@@ -45,23 +45,25 @@ class Sign_Cert final : public Command
void go() override
{
Botan::X509_Certificate ca_cert(get_arg("ca_cert"));
- std::unique_ptr<Botan::Private_Key> key;
- const std::string pass = get_arg("ca-key-pass");
+
+ const std::string key_file = get_arg("ca_key");
+ const std::string pass = get_passphrase_arg("Password for " + key_file, "ca-key-pass");
const std::string emsa = get_arg("emsa");
const std::string hash = get_arg("hash");
+ std::unique_ptr<Botan::Private_Key> key;
if(!pass.empty())
{
- key.reset(Botan::PKCS8::load_key(get_arg("ca_key"), rng(), pass));
+ key.reset(Botan::PKCS8::load_key(key_file, rng(), pass));
}
else
{
- key.reset(Botan::PKCS8::load_key(get_arg("ca_key"), rng()));
+ key.reset(Botan::PKCS8::load_key(key_file, rng()));
}
if(!key)
{
- throw CLI_Error("Failed to load key from " + get_arg("ca_key"));
+ throw CLI_Error("Failed to load key from " + key_file);
}
std::map<std::string, std::string> options;
@@ -251,7 +253,9 @@ class Gen_Self_Signed final : public Command
void go() override
{
- std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(get_arg("key"), rng(), get_arg("key-pass")));
+ const std::string key_file = get_arg("key");
+ const std::string passphrase = get_passphrase_arg("Passphrase for " + key_file, "key-pass");
+ std::unique_ptr<Botan::Private_Key> key(Botan::PKCS8::load_key(key_file, rng(), passphrase));
if(!key)
{
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
index ab9c73b0c..6bebbab58 100644
--- a/src/lib/utils/os_utils.cpp
+++ b/src/lib/utils/os_utils.cpp
@@ -1,6 +1,6 @@
/*
* OS and machine specific utility functions
-* (C) 2015,2016,2017 Jack Lloyd
+* (C) 2015,2016,2017,2018 Jack Lloyd
* (C) 2016 Daniel Neus
*
* Botan is released under the Simplified BSD License (see license.txt)
@@ -26,6 +26,8 @@
#include <setjmp.h>
#include <unistd.h>
#include <errno.h>
+ #include <termios.h>
+ #undef B0
#endif
#if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN)
@@ -470,4 +472,101 @@ int OS::run_cpu_instruction_probe(std::function<int ()> probe_fn)
return probe_result;
}
+std::unique_ptr<OS::Echo_Suppression> OS::suppress_echo_on_terminal()
+ {
+#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
+ class POSIX_Echo_Suppression : public Echo_Suppression
+ {
+ public:
+ POSIX_Echo_Suppression()
+ {
+ m_stdin_fd = fileno(stdin);
+ if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0)
+ throw System_Error("Getting terminal status failed", errno);
+
+ struct termios noecho_flags = m_old_termios;
+ noecho_flags.c_lflag &= ~ECHO;
+ noecho_flags.c_lflag |= ECHONL;
+
+ if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0)
+ throw System_Error("Clearing terminal echo bit failed", errno);
+ }
+
+ void reenable_echo() override
+ {
+ if(m_stdin_fd > 0)
+ {
+ if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0)
+ throw System_Error("Restoring terminal echo bit failed", errno);
+ m_stdin_fd = -1;
+ }
+ }
+
+ ~POSIX_Echo_Suppression()
+ {
+ try
+ {
+ reenable_echo();
+ }
+ catch(...)
+ {
+ }
+ }
+
+ private:
+ int m_stdin_fd;
+ struct termios m_old_termios;
+ };
+
+ return std::unique_ptr<Echo_Suppression>(new POSIX_Echo_Suppression);
+
+#elif defined(BOTAN_TARGET_OS_HAS_WIN32)
+
+ class Win32_Echo_Suppression : public Echo_Suppression
+ {
+ public:
+ Win32_Echo_Suppression()
+ {
+ m_input_handle = ::GetStdHandle(STD_INPUT_HANDLE);
+ if(::GetConsoleMode(m_input_handle, &m_console_state) == 0)
+ throw System_Error("Getting console mode failed", ::GetLastError());
+
+ DWORD new_mode = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ if(::SetConsoleMode(m_input_handle, new_mode) == 0)
+ throw System_Error("Setting console mode failed", ::GetLastError());
+ }
+
+ void reenable_echo() override
+ {
+ if(m_input_handle != INVALID_HANDLE_VALUE)
+ {
+ if(::SetConsoleMode(m_input_handle, m_console_state) == 0)
+ throw System_Error("Setting console mode failed", ::GetLastError());
+ m_input_handle = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ ~Win32_Echo_Suppression()
+ {
+ try
+ {
+ reenable_echo();
+ }
+ catch(...)
+ {
+ }
+ }
+
+ private:
+ HANDLE m_input_handle;
+ DWORD m_console_state;
+ };
+
+ return std::unique_ptr<Echo_Suppression>(new Win32_Echo_Suppression);
+#endif
+
+ // Not supported on this platform, return null
+ return std::unique_ptr<Echo_Suppression>();
+ }
+
}
diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h
index 778ace4e9..39e30fcb7 100644
--- a/src/lib/utils/os_utils.h
+++ b/src/lib/utils/os_utils.h
@@ -1,6 +1,6 @@
/*
* OS specific utility functions
-* (C) 2015,2016,2017 Jack Lloyd
+* (C) 2015,2016,2017,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -117,6 +117,31 @@ void free_locked_pages(void* ptr, size_t length);
*/
int BOTAN_TEST_API run_cpu_instruction_probe(std::function<int ()> probe_fn);
+/**
+* Represents a terminal state
+*/
+class BOTAN_UNSTABLE_API Echo_Suppression
+ {
+ public:
+ /**
+ * Reenable echo on this terminal. Can be safely called
+ * multiple times. May throw if an error occurs.
+ */
+ virtual void reenable_echo() = 0;
+
+ /**
+ * Implicitly calls reenable_echo, but swallows/ignored all
+ * errors which would leave the terminal in an invalid state.
+ */
+ virtual ~Echo_Suppression() = default;
+ };
+
+/**
+* Suppress echo on the terminal
+* Returns null if this operation is not supported on the current system.
+*/
+std::unique_ptr<Echo_Suppression> BOTAN_UNSTABLE_API suppress_echo_on_terminal();
+
}
}