Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tls: support BoringSSL private key async functionality #6326

Merged
merged 63 commits into from
Aug 22, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
3ab2e1d
tls: support BoringSSL private key async functionality.
ipuustin Mar 13, 2019
84b6fe1
tls: add BoringSSL private key operations provider manager support.
ipuustin Mar 27, 2019
127bff5
tests: add mock privateKeyOperationsManager() method.
ipuustin Mar 27, 2019
e58ddfd
tls: use typed config for private key provider configuration.
ipuustin Mar 28, 2019
8d91d59
tls: fixed handling of getPrivateKeyMethods() failure.
ipuustin Apr 3, 2019
0bd6f25
tls: change BoringSSL private key support to be certificate-based.
ipuustin Apr 15, 2019
5e01b30
tls: remove associateWithSsl(), fix tests.
ipuustin Apr 26, 2019
8717cb2
tls: rename the private key API to be more in line with BoringSSL.
ipuustin Apr 26, 2019
7f0e0bc
tls: make a failed private key method association fatal.
ipuustin Apr 30, 2019
4855c9e
tls: typo fix.
ipuustin May 6, 2019
b25f6a6
test: start testing private key methods (context and ssl_socket).
ipuustin May 6, 2019
b7f4fa3
dictionary: added words.
ipuustin May 9, 2019
f67c1a1
test: add a missing "override".
ipuustin May 10, 2019
b24ceb2
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin May 13, 2019
ce312ec
tls: close connection if async handshake fails.
ipuustin May 14, 2019
3eacd75
tests: add more tests for private key method error cases.
ipuustin May 14, 2019
81afc58
tls: remove status from private key method complete() callback.
ipuustin May 15, 2019
ccc8fbe
tests: update tests to the new API + cleanups.
ipuustin May 15, 2019
3e8a3c3
tls: add a check for having both private_key and private_key_method.
ipuustin May 15, 2019
59d93f6
tests: test having both private_key and private_key_method in certifi…
ipuustin May 15, 2019
eb1feaa
cert.proto: fix numbering to be contiguous.
ipuustin May 15, 2019
f7ccf0b
test: fail if provider doesn't return private key methods.
ipuustin May 27, 2019
dace6bb
test: rewrote rsa private key method logic.
ipuustin May 27, 2019
1c5630d
tests: fix a typo.
ipuustin May 27, 2019
c92dfd6
tests: private key method multi-cert tests.
ipuustin May 27, 2019
86ecba9
dispatcher: add a function for returning current thread id.
ipuustin May 28, 2019
3cbe3a5
ssl_socket: check the private key method callback thread id.
ipuustin May 28, 2019
976a469
tests: unique pointers, vectors, and cleanups.
ipuustin Jun 3, 2019
789368a
tls: cleanups.
ipuustin Jun 3, 2019
50d6450
tls: complete() -> onPrivateKeyMethodComplete()
ipuustin Jun 4, 2019
9146b40
tests: FIPS check, private key read from disk only once.
ipuustin Jun 4, 2019
8a688f6
tls: fix typos.
ipuustin Jun 4, 2019
455be73
tests: checkFips() implementation.
ipuustin Jun 5, 2019
14b6d33
tls: remove one of three TlsCertificateConfig constructors.
ipuustin Jun 5, 2019
cc54803
tests: remove use of old TlsCertificateConfigImpl constructor.
ipuustin Jun 5, 2019
12680f6
tls: remove PrivateKeyMethodConnection class.
ipuustin Jun 5, 2019
16ca2a1
tests: use higher-level RSA signing functions.
ipuustin Jun 5, 2019
6d5cf6f
tests: do not use locking in test providers.
ipuustin Jun 5, 2019
e3a66fe
docs: add an overview and some API documentation.
ipuustin Jun 6, 2019
6ac9b30
dictionary: add "TPM".
ipuustin Jun 6, 2019
caee5ad
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin Jun 6, 2019
1f1c997
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin Jun 10, 2019
2ef535f
tls: style cleanups.
ipuustin Jun 10, 2019
c4a5836
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin Jun 19, 2019
2498b0f
tls: reduce TlsCertificateConfigImpl constructors to one.
ipuustin Jun 18, 2019
cd28e08
tls: simplify private key method callback. Add some assumptions to th…
ipuustin Jun 18, 2019
d7e9e5a
Add transport_sockets/tls/private_key to unowned directories.
ipuustin Jun 19, 2019
9b31b1a
CODEOWNERS: add @PiotrSikora and @lizan to transport_sockets/tls.
ipuustin Jun 20, 2019
c9ec2bc
tests: merged RSA and ECDSA providers.
ipuustin Jun 24, 2019
9a321eb
tls: change from PrivateKeyMethod to PrivateKeyProvider.
ipuustin Jun 25, 2019
7ec959e
tests: change how the crypto error is done in private key method test.
ipuustin Jun 25, 2019
f35cca5
test: fix typo in comment.
ipuustin Jun 27, 2019
0a51246
tests: improved an error message.
ipuustin Jun 27, 2019
808d046
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin Jul 15, 2019
3f57152
tls: change "typedef" to "using".
ipuustin Jul 15, 2019
ed99c59
test: remove redundant return.
ipuustin Jul 15, 2019
4d1ceca
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin Jul 23, 2019
e4cab89
tests: annotated destructors with override.
ipuustin Jul 23, 2019
5db871c
tls: gather bools into an enum.
ipuustin Aug 12, 2019
e0e4ed7
Merge remote-tracking branch 'origin/master' into private-key-pr-1.3-…
ipuustin Aug 12, 2019
d28d44b
tests: update one new TlsCertificateConfigImpl constructor.
ipuustin Aug 12, 2019
b79e532
tls: modernize a for loop.
ipuustin Aug 12, 2019
abf8758
tls: various variable name and comment cleanups.
ipuustin Aug 22, 2019
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
7 changes: 7 additions & 0 deletions api/envoy/api/v2/auth/cert.proto
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ message TlsSessionTicketKeys {
repeated core.DataSource keys = 1 [(validate.rules).repeated .min_items = 1];
}

message PrivateKeyOperations {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these going to be BoringSSL specific or an opaque placeholder for both (incompatible) types of private key operations (OpenSSL engines and BoringSSL)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OpenSSL engines are much more than just private key operations, and I don't think treating them as alternatives is going to result in a clean API.

string private_key_provider = 1;
core.ConfigSource private_key_provider_config = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starting from first principles on this review (just noticed it when you tagged me). How come we need to use ConfigSource here? Wouldn't the correct thing be a typed config, i.e. an Any, similar to how we configure other extensions? I think the best example for what you're trying to integrate here is something like the gRPC credential extension, see https://github.com/envoyproxy/envoy/blob/master/source/common/grpc/google_grpc_creds_impl.h

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. I added a patch which does just that. I was bit unsure if the plan is to use the combined Struct/Any approach for new extension types, or just go with Any.

I'm currently thinking that the configuration conversion would be done in the private key provider extensions something like this:

Ssl::PrivateKeyOperationsProviderSharedPtr TestPrivateKeyOperationsFactory::createPrivateKeyOperationsProviderInstance(
    const envoy::api::v2::auth::PrivateKeyOperations& message,
    Server::Configuration::TransportSocketFactoryContext& private_key_provider_context) {
  ProtobufTypes::MessagePtr proto_config = std::make_unique<test::TestPrivateKeyOperationsProto>();

  Config::Utility::translateOpaqueConfig(message.typed_config(), ProtobufWkt::Struct(), *proto_config);
  const test::TestPrivateKeyOperationsProto config = MessageUtil::downcastAndValidate<const test::TestPrivateKeyOperationsProto&>(*proto_config);

  return std::make_shared<TestPrivateKeyOperationsProvider>(config);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you can factor some of this out into an extension factory base, you can see what was done for L7 filters at https://github.com/envoyproxy/envoy/blob/master/source/extensions/filters/http/common/factory_base.h.

}

message CertificateValidationContext {
// TLS certificate data containing certificate authority certificates to use in verifying
// a presented peer certificate (e.g. server certificate for clusters or client certificate
Expand Down Expand Up @@ -315,6 +320,8 @@ message CommonTlsContext {
repeated string alpn_protocols = 4;

reserved 5;

PrivateKeyOperations private_key_operations = 9;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems effectively a oneof with TlsCertificate.private_key. We can't promote it to a oneof without breaking the API, but should this field live next to that in this file and have a comment indicating the exclusive nature of these fields?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this should definitely be a part of TlsCertificate, so that it could be configured on a per-certificate basis.

Ideally, this would be a oneof between private_key and private_key_method, which works well for a lot of use cases (remote oracle, etc.) and is more generic, but it makes this use case (crypto in separate thread) a bit awkward, since then we would need to pass private_key to private_key_method via different means.

Thoughts?

(Using private_key_method instead of private_key_operations to align with the BoringSSL name of this feature, though I don't feel too strongly about it).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't do oneof for wire compat reasons anyway, so you have flexibility here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was under the impression that you can add oneof to non-repeatable fields and stay wire-compatible?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wire compatible yes, but it breaks Go language bindings. We've had a request from the gRPC team to avoid doing this gratuitously, this seems a reasonable accommodation to make. See #6271.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I wasn't aware of that, thanks! Yes, it makes sense to accommodate them (though, it's unfortunate that language bindings are source of this restriction).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll move the private key operations provider to TlsCertificate. I'll have to set up the SSL socket bit differentlythen (because I'll need to initialize the private key methods for each SSL_CTX).

}

message UpstreamTlsContext {
Expand Down
1 change: 1 addition & 0 deletions include/envoy/ssl/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ envoy_cc_library(
deps = [
":certificate_validation_context_config_interface",
":tls_certificate_config_interface",
"//include/envoy/ssl/private_key:private_key_interface",
],
)

Expand Down
7 changes: 7 additions & 0 deletions include/envoy/ssl/context_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include "envoy/common/pure.h"
#include "envoy/ssl/certificate_validation_context_config.h"
#include "envoy/ssl/private_key/private_key.h"
#include "envoy/ssl/tls_certificate_config.h"

namespace Envoy {
Expand Down Expand Up @@ -69,6 +70,12 @@ class ContextConfig {
* @param callback callback that is executed by context config.
*/
virtual void setSecretUpdateCallback(std::function<void()> callback) PURE;

/**
* @return the configured BoringSSL private key operations provider.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have any thoughts on how this can work for OpenSSL implementations?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't - private key operations are a BoringSSL concept. OpenSSL uses a bit similar mechanism called asynchronous mode, which makes almost all operations potentially asynchronous. It's up to the backend (an OpenSSL engine) to implement the operations in an asynchronous way. OpenSSL provides a file descriptor to tell when the operation is ready.

The benefit of OpenSSL model is that many more operations can be performed asynchronously and also the possibility to have dynamic shared objects (engines) with a specified ABI to run the asynchronous operations. Also, if an asynchronous engine isn't used, the library falls back to synchronous operation. The drawback is that the OpenSSL library needs to be dynamically linked to Envoy in order to load external engines. Also, the ASYNC API is not present in BoringSSL.

I wrote a patch on top of @bdecoste's OpenSSL Envoy patches some time back to enable the OpenSSL asynchronous mode:
ipuustin@41bc5be

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any hope of unifying these behind a common Envoy abstraction? That would be ideal, but obviously not if it needs to be a mega-project to make happen. Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's my understanding that the BoringSSL and OpenSLL support will be implemented as separate TLS extensions. This means that the way the library is used will stay "hidden" in the implementations. I think the abstraction could be done in two different possible scopes:

  1. Write support to loading OpenSSL Engines to OpenSSL TLS extension. Abstract the configuration and callback interface.
  2. Find functions corresponding to the BoringSSL private key ops from OpenSSL ASYNC API, and provide a way to do "OpenSSL mini-engines" which would have the same functionality as the BoringSSL private key operations.

The problem with the first item is that it's already pretty well abstracted: there is a bunch of OpenSSL engines out there, and the benefit of Envoy knowing about them would be mainly to pass them configuration values. Envoy can use the dynamic engines quite easily (the only requirement is linking the OpenSSL library dynamically into Envoy), and there is Dispatcher access from the Connection interface to the TLS extension to facilitate the async event channel. The OpenSSL engines can also be configured from outside Envoy, by using OpenSSL configuration files (see https://www.openssl.org/docs/man1.1.1/man5/config.html). Writing the OpenSSL TLS extension to use asynchronous mode from day one would be a good idea.

The second item would mean in a sense that there would be feature parity between OpenSSL and BoringSSL implementations regarding private key operations. The OpenSSL would be pretty handicapped in this case, since the async engine support is more complete than BoringSSL private key operations. Using the QAT HW acceleration as an example, OpenSSL QAT engine (https://github.com/intel/QAT_Engine) can accelerate also EDCHE and some crypto operations, while the BoringSSL private key support is limited to RSA decryption and RSA+ECDSA signing. I think people would gravitate using the full OpenSSL engines rather than writing the Envoy-specific OpenSSL "mini-engines".

TL;DR: it feels to me that having a common abstraction for OpenSSL engines and BoringSSL private key operations might not have enough benefits compared to letting the TLS extensions set up the asynchronous operations as they please. However, I've had only limited exposure to OpenSSL engines, so it could be there are other considerations that I'm not aware of. Maybe there would be a special Envoy configuration Protobuf type for the TLS extensions, so that they could be configured separately? This could mean OpenSSL protobuf configuration message having a submessage for setting up the requested OpenSSL engine(s).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ipuustin thanks for the analysis. My thinking was that if X wanted to write a new private key offload extension Y for X's HSM, then it would be nice to have Y work no matter whether you go with BoringSSL or OpenSSL TLS. If there are already a number of OpenSSL engines out there that only require a light wrapping for Envoy, and OpenSSL is strictly more expressive than BoringSSL, I think there's not much hope or point of reuse.

So, I think this is resolved, we go with your current approach. Thanks again for taking the time to provide such a detailed discussion.

*/
virtual const Envoy::Ssl::PrivateKeyOperationsProviderSharedPtr
privateKeyOperationsProvider() const PURE;
};

class ClientContextConfig : public virtual ContextConfig {
Expand Down
7 changes: 7 additions & 0 deletions include/envoy/ssl/context_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "envoy/ssl/context.h"
#include "envoy/ssl/context_config.h"
#include "envoy/ssl/private_key/private_key.h"
#include "envoy/stats/scope.h"

namespace Envoy {
Expand Down Expand Up @@ -38,6 +39,12 @@ class ContextManager {
* Iterate through all currently allocated contexts.
*/
virtual void iterateContexts(std::function<void(const Context&)> callback) PURE;

/**
* Access the private key operations manager, which is part of SSL
htuch marked this conversation as resolved.
Show resolved Hide resolved
* context manager.
*/
virtual PrivateKeyOperationsManager& privateKeyOperationsManager() PURE;
};

} // namespace Ssl
Expand Down
35 changes: 35 additions & 0 deletions include/envoy/ssl/private_key/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
licenses(["notice"]) # Apache 2

load(
"//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_package",
)

envoy_package()

envoy_cc_library(
name = "private_key_interface",
hdrs = ["private_key.h"],
external_deps = ["ssl"],
deps = [
":private_key_callbacks_interface",
"//include/envoy/event:dispatcher_interface",
"@envoy_api//envoy/api/v2/core:config_source_cc",
],
)

envoy_cc_library(
name = "private_key_config_interface",
hdrs = ["private_key_config.h"],
deps = [
":private_key_interface",
"//include/envoy/registry",
],
)

envoy_cc_library(
name = "private_key_callbacks_interface",
hdrs = ["private_key_callbacks.h"],
external_deps = ["ssl"],
)
82 changes: 82 additions & 0 deletions include/envoy/ssl/private_key/private_key.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once

#include <functional>
#include <string>

#include "envoy/api/v2/core/config_source.pb.h"
#include "envoy/common/pure.h"
#include "envoy/event/dispatcher.h"
#include "envoy/ssl/private_key/private_key_callbacks.h"

#include "openssl/ssl.h"

namespace Envoy {
namespace Server {
namespace Configuration {
class TransportSocketFactoryContext;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to break an include dependency loop?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's why this is needed -- Bazel will complain if this is done with a real dependency.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguably we could do some header refactoring to fix this, but I think this is OK if this is a one off.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Just for the record, the dep loop would be this:

    //include/envoy/ssl:context_manager_interface
    //include/envoy/ssl:context_config_interface
.-> //include/envoy/ssl:tls_certificate_config_interface
|   //include/envoy/ssl/private_key:private_key_interface
|   //include/envoy/server:transport_socket_config_interface
|   //include/envoy/secret:secret_manager_interface
|   //include/envoy/secret:secret_provider_interface
`-- //include/envoy/ssl:tls_certificate_config_interface

} // namespace Configuration
} // namespace Server

namespace Ssl {

typedef std::shared_ptr<SSL_PRIVATE_KEY_METHOD> PrivateKeyMethodSharedPtr;

class PrivateKeyOperations {
public:
virtual ~PrivateKeyOperations() {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= default for here and all destructors in throughout this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok.


/**
* Get the private key asynchronous methods from the provider, if the context can be handled by
* the provider.
* @param ssl a SSL connection object.
* @return private key methods, or nullptr if regular TLS processing should happen.
*/
virtual PrivateKeyMethodSharedPtr getPrivateKeyMethods(SSL* ssl) PURE;
};

typedef std::unique_ptr<PrivateKeyOperations> PrivateKeyOperationsPtr;

class PrivateKeyOperationsProvider {
public:
virtual ~PrivateKeyOperationsProvider() {}

/**
* Get a private key operations instance from the provider.
* @param cb a callbacks object, whose "complete" method will be invoked when the asynchronous
* processing is complete.
* @param dispatcher supplies the owning thread's dispatcher.
* @return the private key operations.
*/
virtual PrivateKeyOperationsPtr getPrivateKeyOperations(PrivateKeyOperationsCallbacks& cb,
Event::Dispatcher& dispatcher) PURE;
};

typedef std::shared_ptr<PrivateKeyOperationsProvider> PrivateKeyOperationsProviderSharedPtr;

/**
* A manager for finding correct user-provided functions for handling BoringSSL private key
* operations.
*/
class PrivateKeyOperationsManager {
public:
virtual ~PrivateKeyOperationsManager() {}

/**
* Finds and returns a private key operations provider for BoringSSL.
*
* @param config_source a protobuf message object containing a TLS config source.
* @param config_name a name that uniquely refers to the private key operations provider.
* @param private_key_provider_context context that provides components for creating and
* initializing connections for keyless TLS etc.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: ...connections using asynchronous private key operations.

* @return TlsPrivateKeyOperationsProvider the private key operations provider, or nullptr if
* no provider can be used with the context configuration.
*/
virtual PrivateKeyOperationsProviderSharedPtr createPrivateKeyOperationsProvider(
const envoy::api::v2::core::ConfigSource& config_source, const std::string& config_name,
Server::Configuration::TransportSocketFactoryContext& private_key_provider_context) PURE;
};

// typedef std::shared_ptr<PrivateKeyOperationsManager> PrivateKeyOperationsManagerSharedPtr;

} // namespace Ssl
} // namespace Envoy
30 changes: 30 additions & 0 deletions include/envoy/ssl/private_key/private_key_callbacks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include <functional>
#include <string>

#include "envoy/common/pure.h"

namespace Envoy {
namespace Ssl {

enum class PrivateKeyOperationStatus {
Success,
Failure,
};

class PrivateKeyOperationsCallbacks {
public:
virtual ~PrivateKeyOperationsCallbacks() {}

/**
* Callback function which is called when the asynchronous private key
* operation has been completed.
* @param status is "Success" or "Failure" depending on whether the private key operation was
* successful or not.
*/
virtual void complete(PrivateKeyOperationStatus status) PURE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit worried about the case where the connection (and SslSocket) goes away while waiting for the async handshake to complete, and then the complete() callback is called, resulting in crash.

Do we have any protections against that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally the idea was that the PrivateKeyOperations lifecycle would be tied to the SslSocket lifecycle. I'll have to do this bit differently now when the operations are tied to certificates (which may change on-the-fly if multiple certificate support is used).

};

} // namespace Ssl
} // namespace Envoy
22 changes: 22 additions & 0 deletions include/envoy/ssl/private_key/private_key_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "envoy/api/v2/core/config_source.pb.h"
#include "envoy/registry/registry.h"
#include "envoy/ssl/private_key/private_key.h"

namespace Envoy {
namespace Ssl {

// Base class which the private key operation provider implementations can register.

class PrivateKeyOperationsProviderInstanceFactory {
public:
virtual ~PrivateKeyOperationsProviderInstanceFactory() {}
virtual PrivateKeyOperationsProviderSharedPtr createPrivateKeyOperationsProviderInstance(
const std::string name, const envoy::api::v2::core::ConfigSource& config_source,
Server::Configuration::TransportSocketFactoryContext& private_key_provider_context) PURE;
virtual std::string name() const PURE;
};

} // namespace Ssl
} // namespace Envoy
5 changes: 5 additions & 0 deletions source/extensions/transport_sockets/tls/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ envoy_cc_library(
":utility_lib",
"//include/envoy/network:connection_interface",
"//include/envoy/network:transport_socket_interface",
"//include/envoy/ssl/private_key:private_key_callbacks_interface",
"//include/envoy/ssl/private_key:private_key_interface",
"//include/envoy/stats:stats_macros",
"//source/common/common:assert_lib",
"//source/common/common:empty_string",
Expand All @@ -59,6 +61,7 @@ envoy_cc_library(
"//include/envoy/secret:secret_provider_interface",
"//include/envoy/server:transport_socket_config_interface",
"//include/envoy/ssl:context_config_interface",
"//include/envoy/ssl/private_key:private_key_interface",
"//source/common/common:assert_lib",
"//source/common/common:empty_string",
"//source/common/config:datasource_lib",
Expand Down Expand Up @@ -91,13 +94,15 @@ envoy_cc_library(
"//include/envoy/ssl:context_config_interface",
"//include/envoy/ssl:context_interface",
"//include/envoy/ssl:context_manager_interface",
"//include/envoy/ssl/private_key:private_key_interface",
"//include/envoy/stats:stats_interface",
"//include/envoy/stats:stats_macros",
"//source/common/common:assert_lib",
"//source/common/common:base64_lib",
"//source/common/common:hex_lib",
"//source/common/common:utility_lib",
"//source/common/protobuf:utility_lib",
"//source/extensions/transport_sockets/tls/private_key:private_key_manager_lib",
"@envoy_api//envoy/admin/v2alpha:certs_cc",
],
)
Expand Down
17 changes: 17 additions & 0 deletions source/extensions/transport_sockets/tls/context_config_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,22 @@ getCertificateValidationContextConfigProvider(
}
}

Ssl::PrivateKeyOperationsProviderSharedPtr getPrivateKeyOperationsProvider(
const envoy::api::v2::auth::CommonTlsContext& config,
Server::Configuration::TransportSocketFactoryContext& factory_context) {

const auto private_key_operations_config = config.private_key_operations();

if (private_key_operations_config.private_key_provider() != "") {
return factory_context.sslContextManager()
.privateKeyOperationsManager()
.createPrivateKeyOperationsProvider(
private_key_operations_config.private_key_provider_config(),
private_key_operations_config.private_key_provider(), factory_context);
}
return nullptr;
}

} // namespace

ContextConfigImpl::ContextConfigImpl(
Expand All @@ -120,6 +136,7 @@ ContextConfigImpl::ContextConfigImpl(
tls_certificate_providers_(getTlsCertificateConfigProviders(config, factory_context)),
certificate_validation_context_provider_(
getCertificateValidationContextConfigProvider(config, factory_context, &default_cvc_)),
private_key_provider_(getPrivateKeyOperationsProvider(config, factory_context)),
min_protocol_version_(tlsVersionFromProto(config.tls_params().tls_minimum_protocol_version(),
default_min_protocol_version)),
max_protocol_version_(tlsVersionFromProto(config.tls_params().tls_maximum_protocol_version(),
Expand Down
6 changes: 6 additions & 0 deletions source/extensions/transport_sockets/tls/context_config_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "envoy/secret/secret_provider.h"
#include "envoy/server/transport_socket_config.h"
#include "envoy/ssl/context_config.h"
#include "envoy/ssl/private_key/private_key.h"

#include "common/common/empty_string.h"
#include "common/json/json_loader.h"
Expand Down Expand Up @@ -41,6 +42,10 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig {
certificateValidationContext() const override {
return validation_context_config_.get();
}
const Envoy::Ssl::PrivateKeyOperationsProviderSharedPtr
privateKeyOperationsProvider() const override {
return private_key_provider_;
}
unsigned minProtocolVersion() const override { return min_protocol_version_; };
unsigned maxProtocolVersion() const override { return max_protocol_version_; };

Expand Down Expand Up @@ -87,6 +92,7 @@ class ContextConfigImpl : public virtual Ssl::ContextConfig {
Common::CallbackHandle* tc_update_callback_handle_{};
Secret::CertificateValidationContextConfigProviderSharedPtr
certificate_validation_context_provider_;
Ssl::PrivateKeyOperationsProviderSharedPtr private_key_provider_;
// Handle for certificate validation context dynamic secret callback.
Common::CallbackHandle* cvc_update_callback_handle_{};
Common::CallbackHandle* cvc_validation_callback_handle_{};
Expand Down
3 changes: 2 additions & 1 deletion source/extensions/transport_sockets/tls/context_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ bool cbsContainsU16(CBS& cbs, uint16_t n) {
ContextImpl::ContextImpl(Stats::Scope& scope, const Envoy::Ssl::ContextConfig& config,
TimeSource& time_source)
: scope_(scope), stats_(generateStats(scope)), time_source_(time_source),
tls_max_version_(config.maxProtocolVersion()) {
tls_max_version_(config.maxProtocolVersion()),
private_key_provider_(config.privateKeyOperationsProvider()) {
const auto tls_certificates = config.tlsCertificates();
tls_contexts_.resize(std::max(1UL, tls_certificates.size()));

Expand Down
6 changes: 6 additions & 0 deletions source/extensions/transport_sockets/tls/context_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "envoy/ssl/context.h"
#include "envoy/ssl/context_config.h"
#include "envoy/ssl/private_key/private_key.h"
#include "envoy/stats/scope.h"
#include "envoy/stats/stats_macros.h"

Expand Down Expand Up @@ -73,6 +74,10 @@ class ContextImpl : public virtual Envoy::Ssl::Context {

SslStats& stats() { return stats_; }

Envoy::Ssl::PrivateKeyOperationsProviderSharedPtr getPrivateKeyOperationsProvider() {
return private_key_provider_;
}

// Ssl::Context
size_t daysUntilFirstCertExpires() const override;
Envoy::Ssl::CertificateDetailsPtr getCaCertInformation() const override;
Expand Down Expand Up @@ -159,6 +164,7 @@ class ContextImpl : public virtual Envoy::Ssl::Context {
std::string cert_chain_file_path_;
TimeSource& time_source_;
const unsigned tls_max_version_;
Ssl::PrivateKeyOperationsProviderSharedPtr private_key_provider_;
};

typedef std::shared_ptr<ContextImpl> ContextImplSharedPtr;
Expand Down
Loading