Skip to content
This repository has been archived by the owner on Nov 20, 2024. It is now read-only.

Commit

Permalink
tls: support fallback for private key provider (#232)
Browse files Browse the repository at this point in the history
* api: revert the private_key_provider_list and add fallback field to ProviderKeyProvider api (#29184)

* Revert "api: introduce the private key provider list field (#28215)"

This reverts commit b24ea1e.

Signed-off-by: He Jie Xu <[email protected]>

* Add fallback to PrivateKeyProvider

Signed-off-by: He Jie Xu <[email protected]>

---------

Signed-off-by: He Jie Xu <[email protected]>

* tls: support fallback for private key provider

Signed-off-by: Giantcroc <[email protected]>

* fix sgx

Signed-off-by: Giantcroc <[email protected]>

---------

Signed-off-by: He Jie Xu <[email protected]>
Signed-off-by: Giantcroc <[email protected]>
Co-authored-by: Alex Xu <[email protected]>
  • Loading branch information
2 people authored and gyohuangxin committed Dec 20, 2023
1 parent 0af28e0 commit caa5f7a
Show file tree
Hide file tree
Showing 20 changed files with 155 additions and 59 deletions.
32 changes: 5 additions & 27 deletions api/envoy/extensions/transport_sockets/tls/v3/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -178,23 +178,14 @@ message PrivateKeyProvider {
oneof config_type {
google.protobuf.Any typed_config = 3 [(udpa.annotations.sensitive) = true];
}
}

// [#not-implemented-hide:]
// Provides a list of private key providers. Envoy will find out an available private
// key provider from the list on order. If there is none of available private key provider,
// it may fallback to BoringSSL default implementation based on the `fallback` fallback.
message PrivateKeyProviderList {
// A list of private key providers, and at least one private key provider provided.
repeated PrivateKeyProvider private_key_provider = 1 [(validate.rules).repeated = {min_items: 1}];

// If there is no available private key provider from the list, Envoy will fallback to
// the BoringSSL default implementation when the `fallback` is true. The default value
// is `false`.
bool fallback = 2;
// If the private key provider isn't available (eg. the required hardware capability doesn't existed),
// Envoy will fallback to the BoringSSL default implementation when the `fallback` is true.
// The default value is `false`.
bool fallback = 4;
}

// [#next-free-field: 10]
// [#next-free-field: 9]
message TlsCertificate {
option (udpa.annotations.versioning).previous_message_type = "envoy.api.v2.auth.TlsCertificate";

Expand Down Expand Up @@ -249,19 +240,6 @@ message TlsCertificate {
// error.
PrivateKeyProvider private_key_provider = 6;

// [#not-implemented-hide:]
// This provides a list of BoringSSL private key method provider. Envoy will find out
// an available private key method provider. It may fallback to BoringSSL default implementation
// when there is no available one. All the private key provider will share the same private key
// in the :ref:`private_key <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.private_key>` field,
// so the :ref:`private_key <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.private_key>` field
// must be specified when the `proviate_key_provider_list` field is used. The old :ref:`private_key_provider
// <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.private_key_provider>` field will be
// deprecated. If both :ref:`private_key_provider <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.private_key_provider>`
// and `private_key_provider_list` are provided, the old
// :ref:`private_key_provider <envoy_v3_api_field_extensions.transport_sockets.tls.v3.TlsCertificate.private_key_provider>` will be ignored.
PrivateKeyProviderList private_key_provider_list = 9;

// The password to decrypt the TLS private key. If this field is not set, it is assumed that the
// TLS private key is not password encrypted.
config.core.v3.DataSource password = 3 [(udpa.annotations.sensitive) = true];
Expand Down
8 changes: 8 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,13 @@ removed_config_or_runtime:
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`

new_features:
- area: tls
change: |
added fallback :ref:`fallback
<envoy_v3_api_field_extensions.transport_sockets.tls.v3.PrivateKeyProvider.fallback>`
to support private key provider to fallback to boringssl tls handshake.
If the private key provider isn't available (eg. the required hardware capability doesn't existed),
Envoy will fallback to the BoringSSL default implementation when the fallback is true.
The default value is false.
deprecated:
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,8 @@ bool CryptoMbPrivateKeyMethodProvider::checkFips() {
return false;
}

bool CryptoMbPrivateKeyMethodProvider::isAvailable() { return initialized_; }

Ssl::BoringSslPrivateKeyMethodSharedPtr
CryptoMbPrivateKeyMethodProvider::getBoringSslPrivateKeyMethod() {
return method_;
Expand All @@ -522,7 +524,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider(
stats_(generateCryptoMbStats("cryptomb", factory_context.statsScope())) {

if (!ipp->mbxIsCryptoMbApplicable(0)) {
throw EnvoyException("Multi-buffer CPU instructions not available.");
ENVOY_LOG(warn, "Multi-buffer CPU instructions not available.");
return;
}

std::chrono::milliseconds poll_delay =
Expand Down Expand Up @@ -565,7 +568,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider(
key_size = 4096;
break;
default:
throw EnvoyException("Only RSA keys of 1024, 2048, 3072, and 4096 bits are supported.");
ENVOY_LOG(warn, "Only RSA keys of 1024, 2048, 3072, and 4096 bits are supported.");
return;
}

// If longer keys are ever supported, remember to change the signature buffer to be larger.
Expand Down Expand Up @@ -619,6 +623,8 @@ CryptoMbPrivateKeyMethodProvider::CryptoMbPrivateKeyMethodProvider(
ENVOY_LOG(debug, "Created CryptoMb Queue for thread {}", d.name());
return std::make_shared<ThreadLocalData>(poll_delay, key_type, key_size, ipp, d, stats_);
});

initialized_ = true;
}

namespace {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class CryptoMbPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodPro
Event::Dispatcher& dispatcher) override;
void unregisterPrivateKeyMethod(SSL* ssl) override;
bool checkFips() override;
bool isAvailable() override;
Ssl::BoringSslPrivateKeyMethodSharedPtr getBoringSslPrivateKeyMethod() override;

static int connectionIndex();
Expand All @@ -191,6 +192,8 @@ class CryptoMbPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodPro
ThreadLocal::TypedSlotPtr<ThreadLocalData> tls_;

CryptoMbStats stats_;

bool initialized_{};
};

} // namespace CryptoMb
Expand Down
16 changes: 11 additions & 5 deletions contrib/cryptomb/private_key_providers/test/config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ TEST_F(CryptoMbConfigTest, CreateRsa1024) {
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(false, provider->checkFips());
EXPECT_EQ(provider->isAvailable(), true);
Ssl::BoringSslPrivateKeyMethodSharedPtr method = provider->getBoringSslPrivateKeyMethod();
EXPECT_NE(nullptr, method);

Expand All @@ -96,7 +97,9 @@ TEST_F(CryptoMbConfigTest, CreateRsa2048) {
private_key: { "filename": "{{ test_rundir }}/contrib/cryptomb/private_key_providers/test/test_data/rsa-2048.pem" }
)EOF";

EXPECT_NE(nullptr, createWithConfig(yaml));
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), true);
}

TEST_F(CryptoMbConfigTest, CreateRsa2048WithExponent3) {
Expand Down Expand Up @@ -146,8 +149,9 @@ TEST_F(CryptoMbConfigTest, CreateRsa512) {
private_key: { "filename": "{{ test_rundir }}/contrib/cryptomb/private_key_providers/test/test_data/rsa-512.pem" }
)EOF";

EXPECT_THROW_WITH_MESSAGE(createWithConfig(yaml), EnvoyException,
"Only RSA keys of 1024, 2048, 3072, and 4096 bits are supported.");
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), false);
}

TEST_F(CryptoMbConfigTest, CreateEcdsaP256) {
Expand Down Expand Up @@ -266,6 +270,7 @@ TEST_F(CryptoMbConfigTest, CreateOneMillisecondPollDelay) {

Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), true);
CryptoMbPrivateKeyMethodProvider* cryptomb_provider =
dynamic_cast<CryptoMbPrivateKeyMethodProvider*>(provider.get());
EXPECT_EQ(cryptomb_provider->getPollDelayForTest(), std::chrono::microseconds(1000));
Expand All @@ -282,6 +287,7 @@ TEST_F(CryptoMbConfigTest, CreateTwoMillisecondPollDelay) {

Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), true);
CryptoMbPrivateKeyMethodProvider* cryptomb_provider =
dynamic_cast<CryptoMbPrivateKeyMethodProvider*>(provider.get());
EXPECT_EQ(cryptomb_provider->getPollDelayForTest(), std::chrono::microseconds(2000));
Expand Down Expand Up @@ -309,8 +315,8 @@ TEST_F(CryptoMbConfigTest, CreateNotSupportedInstructionSet) {
poll_delay: 0.02s
)EOF";

EXPECT_THROW_WITH_MESSAGE(createWithConfig(yaml, false), EnvoyException,
"Multi-buffer CPU instructions not available.");
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml, false);
EXPECT_EQ(provider->isAvailable(), false);
}

} // namespace CryptoMb
Expand Down
5 changes: 4 additions & 1 deletion contrib/qat/private_key_providers/source/qat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ QatManager::QatManager(LibQatCryptoSharedPtr libqat) {
libqat_ = libqat;
CpaStatus status = libqat_->icpSalUserStart("SSL");
if (status != CPA_STATUS_SUCCESS) {
throw EnvoyException("Failed to start QAT device.");
ENVOY_LOG(warn, "Failed to start QAT device.");
qat_is_supported = false;
}
}

Expand Down Expand Up @@ -64,6 +65,8 @@ int QatManager::connectionIndex() { CONSTRUCT_ON_FIRST_USE(int, createIndex());

int QatManager::contextIndex() { CONSTRUCT_ON_FIRST_USE(int, createIndex()); }

bool QatManager::checkQatDevice() { return qat_is_supported; }

QatHandle::~QatHandle() {
if (polling_thread_ == nullptr) {
return;
Expand Down
3 changes: 3 additions & 0 deletions contrib/qat/private_key_providers/source/qat.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,11 @@ class QatManager : public std::enable_shared_from_this<QatManager>,
static int connectionIndex();
static int contextIndex();

bool checkQatDevice();

private:
LibQatCryptoSharedPtr libqat_{};
bool qat_is_supported{true};
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ QatPrivateKeyMethodProvider::getBoringSslPrivateKeyMethod() {
}

bool QatPrivateKeyMethodProvider::checkFips() { return false; }
bool QatPrivateKeyMethodProvider::isAvailable() { return initialized_; }

QatPrivateKeyConnection::QatPrivateKeyConnection(Ssl::PrivateKeyConnectionCallbacks& cb,
Event::Dispatcher& dispatcher, QatHandle& handle,
Expand Down Expand Up @@ -355,6 +356,10 @@ QatPrivateKeyMethodProvider::QatPrivateKeyMethodProvider(

ASSERT(manager_);

if (!manager_->checkQatDevice()) {
return;
}

std::chrono::milliseconds poll_delay =
std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(conf, poll_delay, 5));

Expand All @@ -370,20 +375,23 @@ QatPrivateKeyMethodProvider::QatPrivateKeyMethodProvider(

if (EVP_PKEY_id(pkey.get()) != EVP_PKEY_RSA) {
// TODO(ipuustin): add support also to ECDSA keys.
throw EnvoyException("Only RSA keys are supported.");
ENVOY_LOG(warn, "Only RSA keys are supported.");
return;
}
pkey_ = std::move(pkey);

section_ = std::make_shared<QatSection>(libqat);
if (!section_->startSection(api_, poll_delay)) {
throw EnvoyException("Failed to start QAT.");
ENVOY_LOG(warn, "Failed to start QAT.");
return;
}

method_ = std::make_shared<SSL_PRIVATE_KEY_METHOD>();
method_->sign = privateKeySign;
method_->decrypt = privateKeyDecrypt;
method_->complete = privateKeyComplete;

initialized_ = true;
ENVOY_LOG(info, "initialized QAT private key provider");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class QatPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodProvider
Event::Dispatcher& dispatcher) override;
void unregisterPrivateKeyMethod(SSL* ssl) override;
bool checkFips() override;
bool isAvailable() override;
Ssl::BoringSslPrivateKeyMethodSharedPtr getBoringSslPrivateKeyMethod() override;

private:
Expand All @@ -56,6 +57,7 @@ class QatPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodProvider
Api::Api& api_;
bssl::UniquePtr<EVP_PKEY> pkey_;
LibQatCryptoSharedPtr libqat_{};
bool initialized_{};
};

} // namespace Qat
Expand Down
17 changes: 13 additions & 4 deletions contrib/qat/private_key_providers/test/config_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ TEST_F(QatConfigTest, CreateRsa1024) {
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(false, provider->checkFips());
EXPECT_EQ(provider->isAvailable(), true);
Ssl::BoringSslPrivateKeyMethodSharedPtr method = provider->getBoringSslPrivateKeyMethod();
EXPECT_NE(nullptr, method);
}
Expand All @@ -100,7 +101,9 @@ TEST_F(QatConfigTest, CreateRsa2048) {
private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/rsa-2048.pem" }
)EOF";

EXPECT_NE(nullptr, createWithConfig(yaml));
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), true);
}

TEST_F(QatConfigTest, CreateRsa3072) {
Expand All @@ -112,7 +115,9 @@ TEST_F(QatConfigTest, CreateRsa3072) {
private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/rsa-3072.pem" }
)EOF";

EXPECT_NE(nullptr, createWithConfig(yaml));
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), true);
}

TEST_F(QatConfigTest, CreateRsa4096) {
Expand All @@ -124,7 +129,9 @@ TEST_F(QatConfigTest, CreateRsa4096) {
private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/rsa-4096.pem" }
)EOF";

EXPECT_NE(nullptr, createWithConfig(yaml));
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), true);
}

TEST_F(QatConfigTest, CreateEcdsaP256) {
Expand All @@ -136,7 +143,9 @@ TEST_F(QatConfigTest, CreateEcdsaP256) {
private_key: { "filename": "{{ test_rundir }}/contrib/qat/private_key_providers/test/test_data/ecdsa-p256.pem" }
)EOF";

EXPECT_THROW_WITH_MESSAGE(createWithConfig(yaml), EnvoyException, "Only RSA keys are supported.");
Ssl::PrivateKeyMethodProviderSharedPtr provider = createWithConfig(yaml);
EXPECT_NE(nullptr, provider);
EXPECT_EQ(provider->isAvailable(), false);
}

TEST_F(QatConfigTest, CreateMissingPrivateKeyFile) {
Expand Down
6 changes: 3 additions & 3 deletions contrib/qat/private_key_providers/test/ops_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,9 @@ TEST_F(QatProviderRsaTest, TestQatDeviceInit) {

// no device found
libqat_->icpSalUserStart_return_value_ = CPA_STATUS_FAIL;
EXPECT_THROW_WITH_REGEX(
std::make_shared<QatPrivateKeyMethodProvider>(conf, factory_context_, libqat_),
EnvoyException, "Failed to start QAT device.");
Ssl::PrivateKeyMethodProviderSharedPtr provider =
std::make_shared<QatPrivateKeyMethodProvider>(conf, factory_context_, libqat_);
EXPECT_EQ(provider->isAvailable(), false);
delete private_key;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ void SgxPrivateKeyMethodProvider::registerPrivateKeyMethod(SSL* ssl,
}

bool SgxPrivateKeyMethodProvider::checkFips() { return true; }
bool SgxPrivateKeyMethodProvider::isAvailable() { return true; }

Ssl::BoringSslPrivateKeyMethodSharedPtr
SgxPrivateKeyMethodProvider::getBoringSslPrivateKeyMethod() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class SgxPrivateKeyMethodProvider : public virtual Ssl::PrivateKeyMethodProvider
void unregisterPrivateKeyMethod(SSL* ssl) override;

bool checkFips() override;
bool isAvailable() override;

Ssl::BoringSslPrivateKeyMethodSharedPtr getBoringSslPrivateKeyMethod() override;

Expand Down
6 changes: 6 additions & 0 deletions envoy/ssl/private_key/private_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ class PrivateKeyMethodProvider {
*/
virtual bool checkFips() PURE;

/**
* Check whether the private key method is available.
* @return true if the private key method is available, false if not.
*/
virtual bool isAvailable() PURE;

#ifdef OPENSSL_IS_BORINGSSL
/**
* Get the private key methods from the provider.
Expand Down
Loading

0 comments on commit caa5f7a

Please sign in to comment.