Add ScopeExit to flow and remove scattered impls
This commit is contained in:
parent
e5de8ba260
commit
8789232df4
|
@ -24,7 +24,9 @@
|
|||
#include "flow/Arena.h"
|
||||
#include "flow/Error.h"
|
||||
#include "flow/IRandom.h"
|
||||
#include "flow/MkCert.h"
|
||||
#include "flow/Platform.h"
|
||||
#include "flow/ScopeExit.h"
|
||||
#include "flow/Trace.h"
|
||||
#include "flow/UnitTest.h"
|
||||
#include <type_traits>
|
||||
|
@ -35,16 +37,6 @@
|
|||
|
||||
namespace {
|
||||
|
||||
template <typename Func>
|
||||
class ExitGuard {
|
||||
std::decay_t<Func> fn;
|
||||
|
||||
public:
|
||||
ExitGuard(Func&& fn) : fn(std::forward<Func>(fn)) {}
|
||||
|
||||
~ExitGuard() { fn(); }
|
||||
};
|
||||
|
||||
[[noreturn]] void traceAndThrow(const char* type) {
|
||||
auto te = TraceEvent(SevWarnAlways, type);
|
||||
te.suppressFor(60);
|
||||
|
@ -53,68 +45,16 @@ public:
|
|||
0,
|
||||
};
|
||||
::ERR_error_string_n(err, buf, sizeof(buf));
|
||||
te.detail("OpenSSLError", buf);
|
||||
te.detail("OpenSSLError", static_cast<const char*>(buf));
|
||||
}
|
||||
throw digital_signature_ops_error();
|
||||
}
|
||||
|
||||
struct KeyPairRef {
|
||||
StringRef privateKey;
|
||||
StringRef publicKey;
|
||||
};
|
||||
|
||||
Standalone<KeyPairRef> generateEcdsaKeyPair() {
|
||||
auto params = std::add_pointer_t<EVP_PKEY>();
|
||||
{
|
||||
auto pctx = ::EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
|
||||
ASSERT(pctx);
|
||||
auto ctxGuard = ExitGuard([pctx]() { ::EVP_PKEY_CTX_free(pctx); });
|
||||
ASSERT_LT(0, ::EVP_PKEY_paramgen_init(pctx));
|
||||
ASSERT_LT(0, ::EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1));
|
||||
ASSERT_LT(0, ::EVP_PKEY_paramgen(pctx, ¶ms));
|
||||
ASSERT(params);
|
||||
}
|
||||
auto paramsGuard = ExitGuard([params]() { ::EVP_PKEY_free(params); });
|
||||
// keygen
|
||||
auto kctx = ::EVP_PKEY_CTX_new(params, nullptr);
|
||||
ASSERT(kctx);
|
||||
auto kctxGuard = ExitGuard([kctx]() { ::EVP_PKEY_CTX_free(kctx); });
|
||||
auto key = std::add_pointer_t<EVP_PKEY>();
|
||||
{
|
||||
ASSERT_LT(0, ::EVP_PKEY_keygen_init(kctx));
|
||||
ASSERT_LT(0, ::EVP_PKEY_keygen(kctx, &key));
|
||||
}
|
||||
ASSERT(key);
|
||||
auto keyGuard = ExitGuard([key]() { ::EVP_PKEY_free(key); });
|
||||
|
||||
auto ret = Standalone<KeyPairRef>{};
|
||||
auto& arena = ret.arena();
|
||||
{
|
||||
auto len = 0;
|
||||
len = ::i2d_PrivateKey(key, nullptr);
|
||||
ASSERT_LT(0, len);
|
||||
auto buf = new (arena) uint8_t[len];
|
||||
auto out = std::add_pointer_t<uint8_t>(buf);
|
||||
len = ::i2d_PrivateKey(key, &out);
|
||||
ret.privateKey = StringRef(buf, len);
|
||||
}
|
||||
{
|
||||
auto len = 0;
|
||||
len = ::i2d_PUBKEY(key, nullptr);
|
||||
ASSERT_LT(0, len);
|
||||
auto buf = new (arena) uint8_t[len];
|
||||
auto out = std::add_pointer_t<uint8_t>(buf);
|
||||
len = ::i2d_PUBKEY(key, &out);
|
||||
ret.publicKey = StringRef(buf, len);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Standalone<SignedAuthTokenRef> signToken(AuthTokenRef token, StringRef keyName, StringRef privateKeyDer) {
|
||||
auto ret = Standalone<SignedAuthTokenRef>{};
|
||||
auto arena = ret.arena();
|
||||
auto& arena = ret.arena();
|
||||
auto writer = ObjectWriter([&arena](size_t len) { return new (arena) uint8_t[len]; }, IncludeVersion());
|
||||
writer.serialize(token);
|
||||
auto tokenStr = writer.toStringRef();
|
||||
|
@ -124,11 +64,11 @@ Standalone<SignedAuthTokenRef> signToken(AuthTokenRef token, StringRef keyName,
|
|||
if (!key) {
|
||||
traceAndThrow("SignTokenBadKey");
|
||||
}
|
||||
auto keyGuard = ExitGuard([key]() { ::EVP_PKEY_free(key); });
|
||||
auto keyGuard = ScopeExit([key]() { ::EVP_PKEY_free(key); });
|
||||
auto mdctx = ::EVP_MD_CTX_create();
|
||||
if (!mdctx)
|
||||
traceAndThrow("SignTokenInitFail");
|
||||
auto mdctxGuard = ExitGuard([mdctx]() { ::EVP_MD_CTX_free(mdctx); });
|
||||
auto mdctxGuard = ScopeExit([mdctx]() { ::EVP_MD_CTX_free(mdctx); });
|
||||
if (1 != ::EVP_DigestSignInit(mdctx, nullptr, ::EVP_sha256() /*Parameterize?*/, nullptr, key))
|
||||
traceAndThrow("SignTokenInitFail");
|
||||
if (1 != ::EVP_DigestSignUpdate(mdctx, tokenStr.begin(), tokenStr.size()))
|
||||
|
@ -150,11 +90,11 @@ bool verifyToken(SignedAuthTokenRef signedToken, StringRef publicKeyDer) {
|
|||
auto key = ::d2i_PUBKEY(nullptr, &rawPubKeyDer, publicKeyDer.size());
|
||||
if (!key)
|
||||
traceAndThrow("VerifyTokenBadKey");
|
||||
auto keyGuard = ExitGuard([key]() { ::EVP_PKEY_free(key); });
|
||||
auto keyGuard = ScopeExit([key]() { ::EVP_PKEY_free(key); });
|
||||
auto mdctx = ::EVP_MD_CTX_create();
|
||||
if (!mdctx)
|
||||
traceAndThrow("VerifyTokenInitFail");
|
||||
auto mdctxGuard = ExitGuard([mdctx]() { ::EVP_MD_CTX_free(mdctx); });
|
||||
auto mdctxGuard = ScopeExit([mdctx]() { ::EVP_MD_CTX_free(mdctx); });
|
||||
if (1 != ::EVP_DigestVerifyInit(mdctx, nullptr, ::EVP_sha256(), nullptr, key))
|
||||
traceAndThrow("VerifyTokenInitFail");
|
||||
if (1 != ::EVP_DigestVerifyUpdate(mdctx, signedToken.token.begin(), signedToken.token.size()))
|
||||
|
@ -179,9 +119,10 @@ void forceLinkTokenSignTests() {}
|
|||
TEST_CASE("/fdbrpc/TokenSign") {
|
||||
const auto numIters = 100;
|
||||
for (auto i = 0; i < numIters; i++) {
|
||||
auto keyPair = generateEcdsaKeyPair();
|
||||
auto kpArena = Arena();
|
||||
auto keyPair = mkcert::KeyPairRef::make(kpArena);
|
||||
auto token = Standalone<AuthTokenRef>{};
|
||||
auto arena = token.arena();
|
||||
auto& arena = token.arena();
|
||||
auto& rng = *deterministicRandom();
|
||||
token.expiresAt = timer_monotonic() * (0.5 + rng.random01());
|
||||
if (auto setIp = rng.randomInt(0, 3)) {
|
||||
|
@ -206,15 +147,15 @@ TEST_CASE("/fdbrpc/TokenSign") {
|
|||
token.tenants.push_back(arena, genRandomStringRef());
|
||||
}
|
||||
auto keyName = genRandomStringRef();
|
||||
auto signedToken = signToken(token, keyName, keyPair.privateKey);
|
||||
const auto verifyExpectOk = verifyToken(signedToken, keyPair.publicKey);
|
||||
auto signedToken = signToken(token, keyName, keyPair.privateKeyDer);
|
||||
const auto verifyExpectOk = verifyToken(signedToken, keyPair.publicKeyDer);
|
||||
ASSERT(verifyExpectOk);
|
||||
// try tampering with signed token by adding one more tenant
|
||||
token.tenants.push_back(arena, genRandomStringRef());
|
||||
auto writer = ObjectWriter([&arena](size_t len) { return new (arena) uint8_t[len]; }, IncludeVersion());
|
||||
writer.serialize(token);
|
||||
signedToken.token = writer.toStringRef();
|
||||
const auto verifyExpectFail = verifyToken(signedToken, keyPair.publicKey);
|
||||
const auto verifyExpectFail = verifyToken(signedToken, keyPair.publicKeyDer);
|
||||
ASSERT(!verifyExpectFail);
|
||||
}
|
||||
printf("%d runs OK\n", numIters);
|
||||
|
|
|
@ -56,6 +56,7 @@ set(FLOW_SRCS
|
|||
Platform.h
|
||||
Profiler.actor.cpp
|
||||
Profiler.h
|
||||
ScopeExit.h
|
||||
SendBufferIterator.h
|
||||
SignalSafeUnwind.cpp
|
||||
SignalSafeUnwind.h
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "flow/Arena.h"
|
||||
#include "flow/IRandom.h"
|
||||
#include "flow/MkCert.h"
|
||||
#include "flow/ScopeExit.h"
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
@ -34,16 +35,6 @@
|
|||
|
||||
namespace {
|
||||
|
||||
template <typename Func>
|
||||
class ExitGuard {
|
||||
std::decay_t<Func> fn;
|
||||
|
||||
public:
|
||||
ExitGuard(Func&& fn) : fn(std::forward<Func>(fn)) {}
|
||||
|
||||
~ExitGuard() { fn(); }
|
||||
};
|
||||
|
||||
[[noreturn]] void traceAndThrow(const char* condition, const char* file, int line) {
|
||||
auto te = TraceEvent(SevWarnAlways, "ErrorTLSKeyOrCertGen");
|
||||
te.suppressFor(60).detail("File", file).detail("Line", line).detail("Condition", condition);
|
||||
|
@ -118,7 +109,7 @@ void printPrivateKey(FILE* out, StringRef privateKeyPem) {
|
|||
auto key = readPrivateKeyPem(privateKeyPem);
|
||||
auto bio = ::BIO_new_fp(out, BIO_NOCLOSE);
|
||||
OSSL_ASSERT(bio);
|
||||
auto bioGuard = ExitGuard([bio]() { ::BIO_free(bio); });
|
||||
auto bioGuard = ScopeExit([bio]() { ::BIO_free(bio); });
|
||||
OSSL_ASSERT(0 < ::EVP_PKEY_print_private(bio, key.get(), 0, nullptr));
|
||||
}
|
||||
|
||||
|
@ -127,17 +118,17 @@ std::shared_ptr<EVP_PKEY> makeEllipticCurveKeyPairNative() {
|
|||
{
|
||||
auto pctx = ::EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
|
||||
OSSL_ASSERT(pctx);
|
||||
auto ctxGuard = ExitGuard([pctx]() { ::EVP_PKEY_CTX_free(pctx); });
|
||||
auto ctxGuard = ScopeExit([pctx]() { ::EVP_PKEY_CTX_free(pctx); });
|
||||
OSSL_ASSERT(0 < ::EVP_PKEY_paramgen_init(pctx));
|
||||
OSSL_ASSERT(0 < ::EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1));
|
||||
OSSL_ASSERT(0 < ::EVP_PKEY_paramgen(pctx, ¶ms));
|
||||
OSSL_ASSERT(params);
|
||||
}
|
||||
auto paramsGuard = ExitGuard([params]() { ::EVP_PKEY_free(params); });
|
||||
auto paramsGuard = ScopeExit([params]() { ::EVP_PKEY_free(params); });
|
||||
// keygen
|
||||
auto kctx = ::EVP_PKEY_CTX_new(params, nullptr);
|
||||
OSSL_ASSERT(kctx);
|
||||
auto kctxGuard = ExitGuard([kctx]() { ::EVP_PKEY_CTX_free(kctx); });
|
||||
auto kctxGuard = ScopeExit([kctx]() { ::EVP_PKEY_CTX_free(kctx); });
|
||||
auto key = std::add_pointer_t<EVP_PKEY>();
|
||||
OSSL_ASSERT(0 < ::EVP_PKEY_keygen_init(kctx));
|
||||
OSSL_ASSERT(0 < ::EVP_PKEY_keygen(kctx, &key));
|
||||
|
@ -149,7 +140,7 @@ std::shared_ptr<X509> readX509CertPem(StringRef x509CertPem) {
|
|||
ASSERT(!x509CertPem.empty());
|
||||
auto bio_mem = ::BIO_new_mem_buf(x509CertPem.begin(), x509CertPem.size());
|
||||
OSSL_ASSERT(bio_mem);
|
||||
auto bioGuard = ExitGuard([bio_mem]() { ::BIO_free(bio_mem); });
|
||||
auto bioGuard = ScopeExit([bio_mem]() { ::BIO_free(bio_mem); });
|
||||
auto ret = ::PEM_read_bio_X509(bio_mem, nullptr, nullptr, nullptr);
|
||||
OSSL_ASSERT(ret);
|
||||
return std::shared_ptr<X509>(ret, &::X509_free);
|
||||
|
@ -159,7 +150,7 @@ std::shared_ptr<EVP_PKEY> readPrivateKeyPem(StringRef privateKeyPem) {
|
|||
ASSERT(!privateKeyPem.empty());
|
||||
auto bio_mem = ::BIO_new_mem_buf(privateKeyPem.begin(), privateKeyPem.size());
|
||||
OSSL_ASSERT(bio_mem);
|
||||
auto bioGuard = ExitGuard([bio_mem]() { ::BIO_free(bio_mem); });
|
||||
auto bioGuard = ScopeExit([bio_mem]() { ::BIO_free(bio_mem); });
|
||||
auto ret = ::PEM_read_bio_PrivateKey(bio_mem, nullptr, nullptr, nullptr);
|
||||
OSSL_ASSERT(ret);
|
||||
return std::shared_ptr<EVP_PKEY>(ret, &::EVP_PKEY_free);
|
||||
|
@ -168,7 +159,7 @@ std::shared_ptr<EVP_PKEY> readPrivateKeyPem(StringRef privateKeyPem) {
|
|||
StringRef writeX509CertPem(Arena& arena, const std::shared_ptr<X509>& nativeCert) {
|
||||
auto mem = ::BIO_new(::BIO_s_secmem());
|
||||
OSSL_ASSERT(mem);
|
||||
auto memGuard = ExitGuard([mem]() { ::BIO_free(mem); });
|
||||
auto memGuard = ScopeExit([mem]() { ::BIO_free(mem); });
|
||||
OSSL_ASSERT(::PEM_write_bio_X509(mem, nativeCert.get()));
|
||||
auto bioBuf = std::add_pointer_t<char>{};
|
||||
auto const len = ::BIO_get_mem_data(mem, &bioBuf);
|
||||
|
@ -181,7 +172,7 @@ StringRef writeX509CertPem(Arena& arena, const std::shared_ptr<X509>& nativeCert
|
|||
StringRef writePrivateKeyPem(Arena& arena, const std::shared_ptr<EVP_PKEY>& nativePrivateKey) {
|
||||
auto mem = ::BIO_new(::BIO_s_secmem());
|
||||
OSSL_ASSERT(mem);
|
||||
auto memGuard = ExitGuard([mem]() { ::BIO_free(mem); });
|
||||
auto memGuard = ScopeExit([mem]() { ::BIO_free(mem); });
|
||||
OSSL_ASSERT(::PEM_write_bio_PrivateKey(mem, nativePrivateKey.get(), nullptr, nullptr, 0, 0, nullptr));
|
||||
auto bioBuf = std::add_pointer_t<char>{};
|
||||
auto const len = ::BIO_get_mem_data(mem, &bioBuf);
|
||||
|
@ -223,7 +214,7 @@ CertAndKeyNative makeCertNative(CertSpecRef spec, CertAndKeyNative issuer) {
|
|||
auto nativeKeyPair = makeEllipticCurveKeyPairNative();
|
||||
auto newX = ::X509_new();
|
||||
OSSL_ASSERT(newX);
|
||||
auto x509Guard = ExitGuard([&newX]() {
|
||||
auto x509Guard = ScopeExit([&newX]() {
|
||||
if (newX)
|
||||
::X509_free(newX);
|
||||
});
|
||||
|
@ -262,7 +253,7 @@ CertAndKeyNative makeCertNative(CertSpecRef spec, CertAndKeyNative issuer) {
|
|||
auto extValue = entry.bytes.toString();
|
||||
auto ext = ::X509V3_EXT_conf(nullptr, &ctx, extName.c_str(), extValue.c_str());
|
||||
OSSL_ASSERT(ext);
|
||||
auto extGuard = ExitGuard([ext]() { ::X509_EXTENSION_free(ext); });
|
||||
auto extGuard = ScopeExit([ext]() { ::X509_EXTENSION_free(ext); });
|
||||
OSSL_ASSERT(::X509_add_ext(x, ext, -1));
|
||||
}
|
||||
OSSL_ASSERT(::X509_sign(x, (isSelfSigned ? nativeKeyPair.get() : issuer.privateKey.get()), ::EVP_sha256()));
|
||||
|
|
|
@ -26,9 +26,10 @@
|
|||
#include "flow/Arena.h"
|
||||
#include "flow/Error.h"
|
||||
#include "flow/MkCert.h"
|
||||
#include "flow/SimpleOpt.h"
|
||||
#include "flow/Platform.h"
|
||||
#include "flow/network.h"
|
||||
#include "flow/Platform.h"
|
||||
#include "flow/ScopeExit.h"
|
||||
#include "flow/SimpleOpt.h"
|
||||
#include "flow/TLSConfig.actor.h"
|
||||
#include "flow/Trace.h"
|
||||
|
||||
|
@ -196,8 +197,16 @@ int main(int argc, char** argv) {
|
|||
platformInit();
|
||||
Error::init();
|
||||
g_network = newNet2(TLSConfig());
|
||||
TraceEvent::setNetworkThread();
|
||||
openTraceFile(NetworkAddress(), 10 << 20, 10 << 20, ".", "mkcert");
|
||||
auto thread = std::thread([]() {
|
||||
TraceEvent::setNetworkThread();
|
||||
g_network->run();
|
||||
});
|
||||
auto cleanUpGuard = ScopeExit([&thread]() {
|
||||
flushTraceFileVoid();
|
||||
g_network->stop();
|
||||
thread.join();
|
||||
});
|
||||
|
||||
serverCertFile = abspath(serverCertFile);
|
||||
serverKeyFile = abspath(serverKeyFile);
|
||||
|
@ -223,12 +232,23 @@ int main(int argc, char** argv) {
|
|||
clientCaFile);
|
||||
|
||||
using FileStream = std::ofstream;
|
||||
auto checkStream = [](FileStream& fs, std::string_view filename) {
|
||||
if (!fs) {
|
||||
throw std::runtime_error(fmt::format("Cannot open '{}' for writing", filename));
|
||||
}
|
||||
};
|
||||
auto ofsServerCert = FileStream(serverCertFile, std::ofstream::out | std::ofstream::trunc);
|
||||
checkStream(ofsServerCert, serverCertFile);
|
||||
auto ofsServerKey = FileStream(serverKeyFile, std::ofstream::out | std::ofstream::trunc);
|
||||
checkStream(ofsServerKey, serverKeyFile);
|
||||
auto ofsServerCa = FileStream(serverCaFile, std::ofstream::out | std::ofstream::trunc);
|
||||
checkStream(ofsServerCa, serverCaFile);
|
||||
auto ofsClientCert = FileStream(clientCertFile, std::ofstream::out | std::ofstream::trunc);
|
||||
checkStream(ofsClientCert, clientCertFile);
|
||||
auto ofsClientKey = FileStream(clientKeyFile, std::ofstream::out | std::ofstream::trunc);
|
||||
checkStream(ofsClientKey, clientKeyFile);
|
||||
auto ofsClientCa = FileStream(clientCaFile, std::ofstream::out | std::ofstream::trunc);
|
||||
checkStream(ofsClientCa, clientCaFile);
|
||||
if (serverChainLen) {
|
||||
auto arena = Arena();
|
||||
auto specs = mkcert::makeCertChainSpec(arena, std::abs(serverChainLen), mkcert::ESide::Server);
|
||||
|
@ -269,10 +289,7 @@ int main(int argc, char** argv) {
|
|||
ofsClientCert.close();
|
||||
ofsClientKey.close();
|
||||
ofsClientCa.close();
|
||||
auto thread = std::thread([]() { g_network->run(); });
|
||||
flushTraceFileVoid();
|
||||
g_network->stop();
|
||||
thread.join();
|
||||
fmt::print("OK\n");
|
||||
return FDB_EXIT_SUCCESS;
|
||||
} catch (const Error& e) {
|
||||
fmt::print(stderr, "ERROR: {}\n", e.name());
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* ScopeExit.h
|
||||
*
|
||||
* This source file is part of the FoundationDB open source project
|
||||
*
|
||||
* Copyright 2013-2022 Apple Inc. and the FoundationDB project authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef FLOW_SCOPE_EXIT_H
|
||||
#define FLOW_SCOPE_EXIT_H
|
||||
#pragma once
|
||||
|
||||
// Execute lambda as this object goes out of scope
|
||||
template <typename Func>
|
||||
class ScopeExit {
|
||||
std::decay_t<Func> fn;
|
||||
|
||||
public:
|
||||
ScopeExit(Func&& fn) : fn(std::forward<Func>(fn)) {}
|
||||
|
||||
~ScopeExit() { fn(); }
|
||||
};
|
||||
|
||||
#endif /*FLOW_SCOPE_EXIT_H*/
|
Loading…
Reference in New Issue