Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions fdbcli/fdbcli.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ enum {
OPT_DEBUG_TLS,
OPT_API_VERSION,
OPT_MEMORY,
OPT_USE_FUTURE_PROTOCOL_VERSION
OPT_USE_FUTURE_PROTOCOL_VERSION,
OPT_ENCRYPT
};

CSimpleOpt::SOption g_rgOptions[] = { { OPT_CONNFILE, "-C", SO_REQ_SEP },
Expand All @@ -132,6 +133,7 @@ CSimpleOpt::SOption g_rgOptions[] = { { OPT_CONNFILE, "-C", SO_REQ_SEP },
{ OPT_API_VERSION, "--api-version", SO_REQ_SEP },
{ OPT_MEMORY, "--memory", SO_REQ_SEP },
{ OPT_USE_FUTURE_PROTOCOL_VERSION, "--use-future-protocol-version", SO_NONE },
{ OPT_ENCRYPT, "--encrypt", SO_REQ_SEP },
TLS_OPTION_FLAGS,
SO_END_OF_OPTIONS };

Expand Down Expand Up @@ -506,6 +508,11 @@ static void printProgramUsage(const char* name) {
" --use-future-protocol-version\n"
" Use the simulated future protocol version to connect to the cluster.\n"
" This option can be used testing purposes only!\n"
" --encrypt PASSWORD\n"
" Encrypts the specified password and prints the encrypted password\n"
" with the `encrypted:' prefix. The encrypted password can be used\n"
" with --tls-password option. This option causes fdbcli to encrypt\n"
" the password and exit.\n"
" -v, --version Print FoundationDB CLI version information and exit.\n"
" -h, --help Display this help and exit.\n");
}
Expand Down Expand Up @@ -906,7 +913,6 @@ void LogCommand(std::string line, UID randomID, std::string errMsg) {
printf("%s\n", errMsg.c_str());
TraceEvent(SevInfo, "CLICommandLog", randomID).detail("Command", line).detail("Error", errMsg);
}

struct CLIOptions {
std::string program_name;
int exit_code = -1;
Expand All @@ -932,6 +938,7 @@ struct CLIOptions {
std::string tlsPassword;
bool tlsDisablePlainTextConnection = false;
uint64_t memLimit = 8uLL << 30;
Optional<std::string> encrypt;

std::vector<std::pair<std::string, std::string>> knobs;

Expand Down Expand Up @@ -1077,6 +1084,9 @@ struct CLIOptions {
knobs.emplace_back(knobName.get(), args.OptionArg());
break;
}
case OPT_ENCRYPT:
encrypt = args.OptionArg();
break;
case OPT_DEBUG_TLS:
debugTLS = true;
break;
Expand Down Expand Up @@ -2430,6 +2440,16 @@ int main(int argc, char** argv) {
if (opt.exit_code != -1)
return opt.exit_code;

if (opt.encrypt.present()) {
std::string encrypted;
if (!TLSConfig::encodePassword(opt.encrypt.get(), encrypted)) {
fprintf(stderr, "ERROR: Failed to encrypt password\n");
return 1;
}
printf("%s\n", encrypted.c_str());
return 0;
}

if (opt.trace) {
if (opt.traceDir.empty())
setNetworkOption(FDBNetworkOptions::TRACE_ENABLE);
Expand Down
75 changes: 75 additions & 0 deletions flow/TLSConfig.actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1037,3 +1037,78 @@ bool TLSPolicy::verify_peer(bool preverified, X509_STORE_CTX* store_ctx, const N

return verifier.isOk();
}
struct CryptoLibHandle {
void* lib = nullptr;
void* func = nullptr;

CryptoLibHandle(std::string_view funcName) {
const char* libName = "libnscipher-crypto.so";
lib = loadLibrary(libName);
if (!lib) {
TraceEvent(SevError, "ExternalLibLoadError").detail("Library", libName);
return;
}
func = loadFunction(lib, funcName.data());
if (!func) {
TraceEvent(SevError, "ExternalLibFunctionLoadError")
.detail("Function", funcName)
.detail("Library", libName);
fprintf(stderr, "ERROR: Failed to load '%s' function\n", funcName.data());
closeLibrary(lib);
lib = nullptr;
}
}
explicit operator bool() const { return func != nullptr; }
~CryptoLibHandle() {
if (lib)
closeLibrary(lib);
}
};

static bool processWithCrypto(std::string_view funcName, const std::string& input, std::string& output) {
constexpr int bufLen = 1024; // Assume max size of encrypted and decrypted password is 1024
CryptoLibHandle cryptoHandle(funcName);

if (!cryptoHandle) {
return false;
}

int outputLen = bufLen;

char buf[bufLen]{};

auto func = reinterpret_cast<int (*)(const char*, char*, int*)>(cryptoHandle.func);
if (int rc = func(input.c_str(), buf, &outputLen); rc != 0) {
fprintf(stderr, "ERROR: Failed to exec function (rc=%d)\n", rc);
TraceEvent(SevError, "ErrorExecFunction").detail("ReturnCode", rc);
return false;
}
output.assign(buf, outputLen);
return true;
}

constexpr std::string_view encryptedPrefix = "encrypted:";

bool TLSConfig::encodePassword(const std::string& plainPassword, std::string& encoded) {
if (processWithCrypto("crypt", plainPassword, encoded)) {
encoded.insert(0, encryptedPrefix);
return true;
}
return false;
}

void TLSConfig::setPassword(const std::string& password) {
if (password.size() > encryptedPrefix.size() && password.starts_with(encryptedPrefix)) {

std::string decoded;

if (processWithCrypto("decrypt", password.substr(encryptedPrefix.size()), decoded)) {
tlsPassword = std::move(decoded);
} else {
tlsPassword.clear();
TraceEvent(SevError, "FailedToDecryptPassword");
}
} else {
tlsPassword = password;
}
}
4 changes: 3 additions & 1 deletion flow/include/flow/TLSConfig.actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ class TLSConfig {

void setDisablePlainTextConnection(const bool val) { tlsDisablePlainTextConnection = val; }

void setPassword(const std::string& password) { tlsPassword = password; }
void setPassword(const std::string& password);

static bool encodePassword(const std::string& plainPassword, std::string& encoded);

void clearVerifyPeers() { tlsVerifyPeers.clear(); }

Expand Down