diff options
Diffstat (limited to '')
-rw-r--r-- | src/jaegertracing/thrift/lib/cpp/src/thrift/transport/TSSLSocket.h | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/src/jaegertracing/thrift/lib/cpp/src/thrift/transport/TSSLSocket.h b/src/jaegertracing/thrift/lib/cpp/src/thrift/transport/TSSLSocket.h new file mode 100644 index 000000000..87a960147 --- /dev/null +++ b/src/jaegertracing/thrift/lib/cpp/src/thrift/transport/TSSLSocket.h @@ -0,0 +1,436 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 _THRIFT_TRANSPORT_TSSLSOCKET_H_ +#define _THRIFT_TRANSPORT_TSSLSOCKET_H_ 1 + +// Put this first to avoid WIN32 build failure +#include <thrift/transport/TSocket.h> + +#include <openssl/ssl.h> +#include <string> +#include <thrift/concurrency/Mutex.h> + +namespace apache { +namespace thrift { +namespace transport { + +class AccessManager; +class SSLContext; + +enum SSLProtocol { + SSLTLS = 0, // Supports SSLv2 and SSLv3 handshake but only negotiates at TLSv1_0 or later. +//SSLv2 = 1, // HORRIBLY INSECURE! + SSLv3 = 2, // Supports SSLv3 only - also horribly insecure! + TLSv1_0 = 3, // Supports TLSv1_0 or later. + TLSv1_1 = 4, // Supports TLSv1_1 or later. + TLSv1_2 = 5, // Supports TLSv1_2 or later. + LATEST = TLSv1_2 +}; + +#define TSSL_EINTR 0 +#define TSSL_DATA 1 + +/** + * Initialize OpenSSL library. This function, or some other + * equivalent function to initialize OpenSSL, must be called before + * TSSLSocket is used. If you set TSSLSocketFactory to use manual + * OpenSSL initialization, you should call this function or otherwise + * ensure OpenSSL is initialized yourself. + */ +void initializeOpenSSL(); +/** + * Cleanup OpenSSL library. This function should be called to clean + * up OpenSSL after use of OpenSSL functionality is finished. If you + * set TSSLSocketFactory to use manual OpenSSL initialization, you + * should call this function yourself or ensure that whatever + * initialized OpenSSL cleans it up too. + */ +void cleanupOpenSSL(); + +/** + * OpenSSL implementation for SSL socket interface. + */ +class TSSLSocket : public TSocket { +public: + ~TSSLSocket() override; + /** + * TTransport interface. + */ + bool isOpen() const override; + bool peek() override; + void open() override; + void close() override; + bool hasPendingDataToRead() override; + uint32_t read(uint8_t* buf, uint32_t len) override; + void write(const uint8_t* buf, uint32_t len) override; + uint32_t write_partial(const uint8_t* buf, uint32_t len) override; + void flush() override; + /** + * Set whether to use client or server side SSL handshake protocol. + * + * @param flag Use server side handshake protocol if true. + */ + void server(bool flag) { server_ = flag; } + /** + * Determine whether the SSL socket is server or client mode. + */ + bool server() const { return server_; } + /** + * Set AccessManager. + * + * @param manager Instance of AccessManager + */ + virtual void access(std::shared_ptr<AccessManager> manager) { access_ = manager; } + /** + * Set eventSafe flag if libevent is used. + */ + void setLibeventSafe() { eventSafe_ = true; } + /** + * Determines whether SSL Socket is libevent safe or not. + */ + bool isLibeventSafe() const { return eventSafe_; } + +protected: + /** + * Constructor. + */ + TSSLSocket(std::shared_ptr<SSLContext> ctx); + /** + * Constructor with an interrupt signal. + */ + TSSLSocket(std::shared_ptr<SSLContext> ctx, std::shared_ptr<THRIFT_SOCKET> interruptListener); + /** + * Constructor, create an instance of TSSLSocket given an existing socket. + * + * @param socket An existing socket + */ + TSSLSocket(std::shared_ptr<SSLContext> ctx, THRIFT_SOCKET socket); + /** + * Constructor, create an instance of TSSLSocket given an existing socket that can be interrupted. + * + * @param socket An existing socket + */ + TSSLSocket(std::shared_ptr<SSLContext> ctx, THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener); + /** + * Constructor. + * + * @param host Remote host name + * @param port Remote port number + */ + TSSLSocket(std::shared_ptr<SSLContext> ctx, std::string host, int port); + /** + * Constructor with an interrupt signal. + * + * @param host Remote host name + * @param port Remote port number + */ + TSSLSocket(std::shared_ptr<SSLContext> ctx, std::string host, int port, std::shared_ptr<THRIFT_SOCKET> interruptListener); + /** + * Authorize peer access after SSL handshake completes. + */ + virtual void authorize(); + /** + * Initiate SSL handshake if not already initiated. + */ + void initializeHandshake(); + /** + * Initiate SSL handshake params. + */ + void initializeHandshakeParams(); + /** + * Check if SSL handshake is completed or not. + */ + bool checkHandshake(); + /** + * Waits for an socket or shutdown event. + * + * @throw TTransportException::INTERRUPTED if interrupted is signaled. + * + * @return TSSL_EINTR if EINTR happened on the underlying socket + * TSSL_DATA if data is available on the socket. + */ + unsigned int waitForEvent(bool wantRead); + + bool server_; + SSL* ssl_; + std::shared_ptr<SSLContext> ctx_; + std::shared_ptr<AccessManager> access_; + friend class TSSLSocketFactory; + +private: + bool handshakeCompleted_; + int readRetryCount_; + bool eventSafe_; + + void init(); +}; + +/** + * SSL socket factory. SSL sockets should be created via SSL factory. + * The factory will automatically initialize and cleanup openssl as long as + * there is a TSSLSocketFactory instantiated, and as long as the static + * boolean manualOpenSSLInitialization_ is set to false, the default. + * + * If you would like to initialize and cleanup openssl yourself, set + * manualOpenSSLInitialization_ to true and TSSLSocketFactory will no + * longer be responsible for openssl initialization and teardown. + * + * It is the responsibility of the code using TSSLSocketFactory to + * ensure that the factory lifetime exceeds the lifetime of any sockets + * it might create. If this is not guaranteed, a socket may call into + * openssl after the socket factory has cleaned up openssl! This + * guarantee is unnecessary if manualOpenSSLInitialization_ is true, + * however, since it would be up to the consuming application instead. + */ +class TSSLSocketFactory { +public: + /** + * Constructor/Destructor + * + * @param protocol The SSL/TLS protocol to use. + */ + TSSLSocketFactory(SSLProtocol protocol = SSLTLS); + virtual ~TSSLSocketFactory(); + /** + * Create an instance of TSSLSocket with a fresh new socket. + */ + virtual std::shared_ptr<TSSLSocket> createSocket(); + /** + * Create an instance of TSSLSocket with a fresh new socket, which is interruptable. + */ + virtual std::shared_ptr<TSSLSocket> createSocket(std::shared_ptr<THRIFT_SOCKET> interruptListener); + /** + * Create an instance of TSSLSocket with the given socket. + * + * @param socket An existing socket. + */ + virtual std::shared_ptr<TSSLSocket> createSocket(THRIFT_SOCKET socket); + /** + * Create an instance of TSSLSocket with the given socket which is interruptable. + * + * @param socket An existing socket. + */ + virtual std::shared_ptr<TSSLSocket> createSocket(THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener); + /** + * Create an instance of TSSLSocket. + * + * @param host Remote host to be connected to + * @param port Remote port to be connected to + */ + virtual std::shared_ptr<TSSLSocket> createSocket(const std::string& host, int port); + /** + * Create an instance of TSSLSocket. + * + * @param host Remote host to be connected to + * @param port Remote port to be connected to + */ + virtual std::shared_ptr<TSSLSocket> createSocket(const std::string& host, int port, std::shared_ptr<THRIFT_SOCKET> interruptListener); + /** + * Set ciphers to be used in SSL handshake process. + * + * @param ciphers A list of ciphers + */ + virtual void ciphers(const std::string& enable); + /** + * Enable/Disable authentication. + * + * @param required Require peer to present valid certificate if true + */ + virtual void authenticate(bool required); + /** + * Load server certificate. + * + * @param path Path to the certificate file + * @param format Certificate file format + */ + virtual void loadCertificate(const char* path, const char* format = "PEM"); + /** + * Load private key. + * + * @param path Path to the private key file + * @param format Private key file format + */ + virtual void loadPrivateKey(const char* path, const char* format = "PEM"); + /** + * Load trusted certificates from specified file. + * + * @param path Path to trusted certificate file + */ + virtual void loadTrustedCertificates(const char* path, const char* capath = nullptr); + /** + * Default randomize method. + */ + virtual void randomize(); + /** + * Override default OpenSSL password callback with getPassword(). + */ + void overrideDefaultPasswordCallback(); + /** + * Set/Unset server mode. + * + * @param flag Server mode if true + */ + virtual void server(bool flag) { server_ = flag; } + /** + * Determine whether the socket is in server or client mode. + * + * @return true, if server mode, or, false, if client mode + */ + virtual bool server() const { return server_; } + /** + * Set AccessManager. + * + * @param manager The AccessManager instance + */ + virtual void access(std::shared_ptr<AccessManager> manager) { access_ = manager; } + static void setManualOpenSSLInitialization(bool manualOpenSSLInitialization) { + manualOpenSSLInitialization_ = manualOpenSSLInitialization; + } + +protected: + std::shared_ptr<SSLContext> ctx_; + + /** + * Override this method for custom password callback. It may be called + * multiple times at any time during a session as necessary. + * + * @param password Pass collected password to OpenSSL + * @param size Maximum length of password including NULL character + */ + virtual void getPassword(std::string& /* password */, int /* size */) {} + +private: + bool server_; + std::shared_ptr<AccessManager> access_; + static concurrency::Mutex mutex_; + static uint64_t count_; + THRIFT_EXPORT static bool manualOpenSSLInitialization_; + void setup(std::shared_ptr<TSSLSocket> ssl); + static int passwordCallback(char* password, int size, int, void* data); +}; + +/** + * SSL exception. + */ +class TSSLException : public TTransportException { +public: + TSSLException(const std::string& message) + : TTransportException(TTransportException::INTERNAL_ERROR, message) {} + + const char* what() const noexcept override { + if (message_.empty()) { + return "TSSLException"; + } else { + return message_.c_str(); + } + } +}; + +/** + * Wrap OpenSSL SSL_CTX into a class. + */ +class SSLContext { +public: + SSLContext(const SSLProtocol& protocol = SSLTLS); + virtual ~SSLContext(); + SSL* createSSL(); + SSL_CTX* get() { return ctx_; } + +private: + SSL_CTX* ctx_; +}; + +/** + * Callback interface for access control. It's meant to verify the remote host. + * It's constructed when application starts and set to TSSLSocketFactory + * instance. It's passed onto all TSSLSocket instances created by this factory + * object. + */ +class AccessManager { +public: + enum Decision { + DENY = -1, // deny access + SKIP = 0, // cannot make decision, move on to next (if any) + ALLOW = 1 // allow access + }; + /** + * Destructor + */ + virtual ~AccessManager() = default; + /** + * Determine whether the peer should be granted access or not. It's called + * once after the SSL handshake completes successfully, before peer certificate + * is examined. + * + * If a valid decision (ALLOW or DENY) is returned, the peer certificate is + * not to be verified. + * + * @param sa Peer IP address + * @return True if the peer is trusted, false otherwise + */ + virtual Decision verify(const sockaddr_storage& /* sa */) noexcept { return DENY; } + /** + * Determine whether the peer should be granted access or not. It's called + * every time a DNS subjectAltName/common name is extracted from peer's + * certificate. + * + * @param host Client mode: host name returned by TSocket::getHost() + * Server mode: host name returned by TSocket::getPeerHost() + * @param name SubjectAltName or common name extracted from peer certificate + * @param size Length of name + * @return True if the peer is trusted, false otherwise + * + * Note: The "name" parameter may be UTF8 encoded. + */ + virtual Decision verify(const std::string& /* host */, + const char* /* name */, + int /* size */) noexcept { + return DENY; + } + /** + * Determine whether the peer should be granted access or not. It's called + * every time an IP subjectAltName is extracted from peer's certificate. + * + * @param sa Peer IP address retrieved from the underlying socket + * @param data IP address extracted from certificate + * @param size Length of the IP address + * @return True if the peer is trusted, false otherwise + */ + virtual Decision verify(const sockaddr_storage& /* sa */, + const char* /* data */, + int /* size */) noexcept { + return DENY; + } +}; + +typedef AccessManager::Decision Decision; + +class DefaultClientAccessManager : public AccessManager { +public: + // AccessManager interface + Decision verify(const sockaddr_storage& sa) noexcept override; + Decision verify(const std::string& host, const char* name, int size) noexcept override; + Decision verify(const sockaddr_storage& sa, const char* data, int size) noexcept override; +}; +} +} +} + +#endif |