Repository: kudu Updated Branches: refs/heads/master 8a2ea8bdd -> 72b2ffdac
TLS-negotiation [7/n]: Add TLS helper classes for handling tunneled TLS handshakes The new TLS negotiation protocol calls for tunneling the TLS handshake through negotiation protobufs. The existing SSL socket helper classes were not built with this in mind. This commit introduces new helpers, largely based off the existing versions. A followup commit will switch KRPC to use the new classes and remove the old. Change-Id: I6776dbdc488eee56f7273cdd8bcd2b2b8c1ffa04 Reviewed-on: http://gerrit.cloudera.org:8080/5761 Tested-by: Kudu Jenkins Reviewed-by: Alexey Serbin <[email protected]> Reviewed-by: Todd Lipcon <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/kudu/repo Commit: http://git-wip-us.apache.org/repos/asf/kudu/commit/72b2ffda Tree: http://git-wip-us.apache.org/repos/asf/kudu/tree/72b2ffda Diff: http://git-wip-us.apache.org/repos/asf/kudu/diff/72b2ffda Branch: refs/heads/master Commit: 72b2ffdace5ffe0aff925392230e3cbd3813e326 Parents: 8a2ea8b Author: Dan Burkert <[email protected]> Authored: Fri Jan 20 16:14:41 2017 -0800 Committer: Todd Lipcon <[email protected]> Committed: Thu Jan 26 17:41:00 2017 +0000 ---------------------------------------------------------------------- src/kudu/rpc/rpc-test-base.h | 74 +------------- src/kudu/security/CMakeLists.txt | 8 +- src/kudu/security/openssl_util.cc | 21 ++++ src/kudu/security/openssl_util.h | 16 ++- src/kudu/security/security-test-util.h | 97 ++++++++++++++++++ src/kudu/security/tls_context.cc | 133 +++++++++++++++++++++++++ src/kudu/security/tls_context.h | 62 ++++++++++++ src/kudu/security/tls_handshake-test.cc | 76 ++++++++++++++ src/kudu/security/tls_handshake.cc | 144 +++++++++++++++++++++++++++ src/kudu/security/tls_handshake.h | 98 ++++++++++++++++++ src/kudu/security/tls_socket.cc | 123 +++++++++++++++++++++++ src/kudu/security/tls_socket.h | 54 ++++++++++ 12 files changed, 832 insertions(+), 74 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/rpc/rpc-test-base.h ---------------------------------------------------------------------- diff --git a/src/kudu/rpc/rpc-test-base.h b/src/kudu/rpc/rpc-test-base.h index 8122a1b..ff194bb 100644 --- a/src/kudu/rpc/rpc-test-base.h +++ b/src/kudu/rpc/rpc-test-base.h @@ -37,6 +37,7 @@ #include "kudu/rpc/rtest.service.h" #include "kudu/rpc/service_if.h" #include "kudu/rpc/service_pool.h" +#include "kudu/security/security-test-util.h" #include "kudu/util/env.h" #include "kudu/util/faststring.h" #include "kudu/util/mem_tracker.h" @@ -317,75 +318,6 @@ const char *GenericCalculatorService::kFirstString = const char *GenericCalculatorService::kSecondString = "2222222222222222222222222222222222222222222222222222222222222222222222"; -// Writes the test SSL certificate into a temporary file. -inline Status CreateSSLServerCert(const std::string& file_path) { - static const char* test_server_cert = R"( ------BEGIN CERTIFICATE----- -MIIEejCCA2KgAwIBAgIJAKMdvDR5PL82MA0GCSqGSIb3DQEBBQUAMIGEMQswCQYD -VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j -aXNjbzERMA8GA1UEChMIQ2xvdWRlcmExEjAQBgNVBAMTCWxvY2FsaG9zdDEhMB8G -CSqGSIb3DQEJARYSaGVucnlAY2xvdWRlcmEuY29tMB4XDTEzMDkyMjAwMjUxOFoX -DTQxMDIwNzAwMjUxOFowgYQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9y -bmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMREwDwYDVQQKEwhDbG91ZGVyYTES -MBAGA1UEAxMJbG9jYWxob3N0MSEwHwYJKoZIhvcNAQkBFhJoZW5yeUBjbG91ZGVy -YS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCoUj3pMQ2ELkrz -zq+koixljVFBAEEqwUWSjA+GEKwfFb/UPRjeO/wrKndp2r83jc6KRt66rvAIl8cr -b54yTOsJ/ZcARrjTwG3IG8Tely/54ZQyH0ImdJyEbCSoI04zX3ovjlppz3g5xanj -WmpAh6pzPgBOTfisCLMPD70xQ8F//QWZdNatoly54STkTWoJv/Oll/UpXcBY8JOR -+ytX82eGgG4F8YoQqmbjrrN5JAmqLRiBAkr3WUena6ekqJBalJRzex/Wh8a9XEV7 -9HFVVngBhezsOJgf81hzBzzhULKfxuXl8uaUj3Z9cZg39CDsyz+ULYbsPm8VoMUI -VCf7MUVTAgMBAAGjgewwgekwHQYDVR0OBBYEFK94kea7jIKQawAIb+0DqsA1rf6n -MIG5BgNVHSMEgbEwga6AFK94kea7jIKQawAIb+0DqsA1rf6noYGKpIGHMIGEMQsw -CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy -YW5jaXNjbzERMA8GA1UEChMIQ2xvdWRlcmExEjAQBgNVBAMTCWxvY2FsaG9zdDEh -MB8GCSqGSIb3DQEJARYSaGVucnlAY2xvdWRlcmEuY29tggkAox28NHk8vzYwDAYD -VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAEtkPPncCnN2IFVJvz04K+VsX -b6w3qwPynQKc67+++JkNb3TYKrh/0UVM1NrEOu3TGplqOrKgAlITuaWNqNOSBu1R -WJtrz85YkonED5awjjuALVEY82+c7pOXkuv5G5421RINfRn2hNzgw8VFb5CEvxHH -jER80Vx6UGKr/S649qTQ8AzVzTwWS86VsGI2azAD7D67G/IDGf+0P7FsXonKY+vl -vKzkfaO1+qEOLtDHV9mwlsxl3Re/MNym4ExWHi9txynCNiRZHqWoZUS+KyYqIR2q -seCrQwgi1Fer9Ekd5XNjWjigC3VC3SjMqWaxeKbZ2/AuABJMz5xSiRkgwphXEQ== ------END CERTIFICATE----- - )"; - RETURN_NOT_OK(WriteStringToFile(Env::Default(), test_server_cert, file_path)); - return Status::OK(); -} - -// Writes the test SSL private key into a temporary file. -inline Status CreateSSLPrivateKey(const std::string& file_path) { - static const char* test_private_key = R"( ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAqFI96TENhC5K886vpKIsZY1RQQBBKsFFkowPhhCsHxW/1D0Y -3jv8Kyp3adq/N43Oikbeuq7wCJfHK2+eMkzrCf2XAEa408BtyBvE3pcv+eGUMh9C -JnSchGwkqCNOM196L45aac94OcWp41pqQIeqcz4ATk34rAizDw+9MUPBf/0FmXTW -raJcueEk5E1qCb/zpZf1KV3AWPCTkfsrV/NnhoBuBfGKEKpm466zeSQJqi0YgQJK -91lHp2unpKiQWpSUc3sf1ofGvVxFe/RxVVZ4AYXs7DiYH/NYcwc84VCyn8bl5fLm -lI92fXGYN/Qg7Ms/lC2G7D5vFaDFCFQn+zFFUwIDAQABAoIBABNTpiIxbLDhs998 -uvQ3XsumR08kXVcwa/GgvWOSZIEJOUaAYWubDaBTNvTjlhMl6DI+YvKihZMnAkp9 -fXefF1nFUWJJvI0ryi8w6RD54RtbCG4c4raRqysVU7wumZsSenAdc0o09UQE6zXc -uth/+1VSKCzVjRkLwquXDg0rD3vHfQHWQvQlzwUh3OACA3LfLezVqzrEB02YVRxm -xwg5veeMg6Aod8vsvsajry9eE0hKeFGonRANerL9lwZxzD2ZjU2fSEJYY3xxKVgi -o+QVTKaAt9pivOs10YVZDcIDH0xmDpxAkaLb5ZAbnjwhf7WGYgEm8VruAHkJxyXX -yPf3rpkCgYEA0dp/Xv5KBIkD6JJao8hnhtP5x9U7o/pTzRxaO3WUflvTI6DtC0nk -cTOwFVs4WljT76T937q2x4stuX0woHzvIaZ6wwZ2vv81ikDY6pE8eLWsH/xFAmkx -HBfkSijFgJV6EpTqUnFD7QKU89tzWrh/kxaMO1WgFaBhxPPs3K1LDTUCgYEAzVW5 -3yjfVHNgjWTeAbnbToGvUihOidvIvS5cVo5q0Dhfabz0tiXFxAoQUGErUGPC8Nu2 -n/HxTI3b0PbCCwjBsDNqX2kzxTSe5aTGIrBUWbped1bxme8jggXuWYbg8vvLpsYf -wAJPxnGIxW/v/aftHUhbTIuVfZX2+UnilrwiwWcCgYEAg8paz4eXaH277KVtMwq6 -qZwac/tgNz0Qv/GcYVcYaLq2QNvhwoMnakhxvxfIrkS25PuTTJxwCaVIlAMhNMkB -TPrGghBfJtgUAb1z/Ow1NAG0FWpS1I7HfsMqZcBxOK2nOmA3QItNg11pujQJn+Ha -jL9OVj0SCkLs48nk6ToTtjkCgYEAh8YCtNwq6IWuN3CWGCAUMpIwIqxCWof48Zch -OZ7MZEiSVrG6QmMxpRJefTfzUyHUOj2eQZ7SxqMa0c8IuhEdOeyVjudaczD7TLAq -z68252oDovfbo8Tr/sL7OzmjryfuHqXtQqKEq5xRKvR8hYavlGhO7otx2uv5thcz -/CYE+UsCgYAsgewfzbcBqJwsAUs98DK99EU8VqKuaYlU5wNvAVb27O6sVeysSokM -G1TGIXJPphA3dSAe4Pf/j4ff/eGaS20FAFhs4BPpw0fAeCHpmD0BjIba0lxBS/gY -dc+JVPKL8Fe4a8fmsI6ndcZQ9qpOdZM5WOD0ldKRc+SsrYKkTmOOJQ== ------END RSA PRIVATE KEY----- - )"; - RETURN_NOT_OK(WriteStringToFile(Env::Default(), test_private_key, file_path)); - return Status::OK(); -} - class RpcTestBase : public KuduTest { public: RpcTestBase() @@ -418,8 +350,8 @@ class RpcTestBase : public KuduTest { if (enable_ssl) { std::string server_cert_path = GetTestPath("server-cert.pem"); std::string private_key_path = GetTestPath("server-key.pem"); - CHECK_OK(CreateSSLServerCert(server_cert_path)); - CHECK_OK(CreateSSLPrivateKey(private_key_path)); + CHECK_OK(security::CreateSSLServerCert(server_cert_path)); + CHECK_OK(security::CreateSSLPrivateKey(private_key_path)); FLAGS_rpc_ssl_server_certificate = server_cert_path; FLAGS_rpc_ssl_private_key = private_key_path; FLAGS_rpc_ssl_certificate_authority = server_cert_path; http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/CMakeLists.txt ---------------------------------------------------------------------- diff --git a/src/kudu/security/CMakeLists.txt b/src/kudu/security/CMakeLists.txt index d20b73b..ce06fb4 100644 --- a/src/kudu/security/CMakeLists.txt +++ b/src/kudu/security/CMakeLists.txt @@ -35,7 +35,10 @@ set(SECURITY_SRCS openssl_util.cc ${PORTED_X509_CHECK_HOST_CC} ssl_factory.cc - ssl_socket.cc) + ssl_socket.cc + tls_context.cc + tls_handshake.cc + tls_socket.cc) set(SECURITY_LIBS gutil @@ -65,6 +68,7 @@ if (NOT NO_TESTS) security-test ${KUDU_MIN_TEST_LIBS}) - ADD_KUDU_TEST(test/mini_kdc-test) ADD_KUDU_TEST(test/cert_management-test) + ADD_KUDU_TEST(test/mini_kdc-test) + ADD_KUDU_TEST(tls_handshake-test) endif() http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/openssl_util.cc ---------------------------------------------------------------------- diff --git a/src/kudu/security/openssl_util.cc b/src/kudu/security/openssl_util.cc index e460611..be6a821 100644 --- a/src/kudu/security/openssl_util.cc +++ b/src/kudu/security/openssl_util.cc @@ -31,6 +31,7 @@ #include "kudu/gutil/strings/substitute.h" #include "kudu/util/debug/leakcheck_disabler.h" +#include "kudu/util/errno.h" #include "kudu/util/mutex.h" #include "kudu/util/status.h" #include "kudu/util/thread.h" @@ -114,6 +115,26 @@ string GetOpenSSLErrors() { return serr.str(); } +string GetSSLErrorDescription(int error_code) { + switch (error_code) { + case SSL_ERROR_NONE: return ""; + case SSL_ERROR_ZERO_RETURN: return "SSL_ERROR_ZERO_RETURN"; + case SSL_ERROR_WANT_READ: return "SSL_ERROR_WANT_READ"; + case SSL_ERROR_WANT_WRITE: return "SSL_ERROR_WANT_WRITE"; + case SSL_ERROR_WANT_CONNECT: return "SSL_ERROR_WANT_CONNECT"; + case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT"; + case SSL_ERROR_WANT_X509_LOOKUP: return "SSL_ERROR_WANT_X509_LOOKUP"; + case SSL_ERROR_SYSCALL: { + string queued_error = GetOpenSSLErrors(); + if (!queued_error.empty()) { + return queued_error; + } + return kudu::ErrnoToString(errno); + }; + default: return GetOpenSSLErrors(); + } +} + namespace { // Writing the private key from an EVP_PKEY has a different http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/openssl_util.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/openssl_util.h b/src/kudu/security/openssl_util.h index 426f0a1..ab3567c 100644 --- a/src/kudu/security/openssl_util.h +++ b/src/kudu/security/openssl_util.h @@ -57,9 +57,23 @@ namespace security { // Safe to call multiple times. void InitializeOpenSSL(); -// Fetch the last error message from the OpenSSL library. +// Fetches errors from the OpenSSL error error queue, and stringifies them. +// +// The error queue will be empty after this method returns. +// +// See man(3) ERR_get_err for more discussion. std::string GetOpenSSLErrors(); +// Returns a string representation of the provided error code, which must be +// from a prior call to the SSL_get_error function. +// +// If necessary, the OpenSSL error queue may be inspected and emptied as part of +// this call, and/or 'errno' may be inspected. As a result, this method should +// only be used directly after the error occurs, and from the same thread. +// +// See man(3) SSL_get_error for more discussion. +std::string GetSSLErrorDescription(int error_code); + // A generic wrapper for OpenSSL structures. template <typename T> using c_unique_ptr = std::unique_ptr<T, std::function<void(T*)>>; http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/security-test-util.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/security-test-util.h b/src/kudu/security/security-test-util.h new file mode 100644 index 0000000..b9ea0b2 --- /dev/null +++ b/src/kudu/security/security-test-util.h @@ -0,0 +1,97 @@ +// 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. + +#pragma once + +#include <string> + +#include "kudu/util/env.h" +#include "kudu/util/status.h" + +namespace kudu { +namespace security { + +static Status CreateSSLServerCert(const std::string& file_path) { + static const char* test_server_cert = R"( +-----BEGIN CERTIFICATE----- +MIIEejCCA2KgAwIBAgIJAKMdvDR5PL82MA0GCSqGSIb3DQEBBQUAMIGEMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5j +aXNjbzERMA8GA1UEChMIQ2xvdWRlcmExEjAQBgNVBAMTCWxvY2FsaG9zdDEhMB8G +CSqGSIb3DQEJARYSaGVucnlAY2xvdWRlcmEuY29tMB4XDTEzMDkyMjAwMjUxOFoX +DTQxMDIwNzAwMjUxOFowgYQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9y +bmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMREwDwYDVQQKEwhDbG91ZGVyYTES +MBAGA1UEAxMJbG9jYWxob3N0MSEwHwYJKoZIhvcNAQkBFhJoZW5yeUBjbG91ZGVy +YS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCoUj3pMQ2ELkrz +zq+koixljVFBAEEqwUWSjA+GEKwfFb/UPRjeO/wrKndp2r83jc6KRt66rvAIl8cr +b54yTOsJ/ZcARrjTwG3IG8Tely/54ZQyH0ImdJyEbCSoI04zX3ovjlppz3g5xanj +WmpAh6pzPgBOTfisCLMPD70xQ8F//QWZdNatoly54STkTWoJv/Oll/UpXcBY8JOR ++ytX82eGgG4F8YoQqmbjrrN5JAmqLRiBAkr3WUena6ekqJBalJRzex/Wh8a9XEV7 +9HFVVngBhezsOJgf81hzBzzhULKfxuXl8uaUj3Z9cZg39CDsyz+ULYbsPm8VoMUI +VCf7MUVTAgMBAAGjgewwgekwHQYDVR0OBBYEFK94kea7jIKQawAIb+0DqsA1rf6n +MIG5BgNVHSMEgbEwga6AFK94kea7jIKQawAIb+0DqsA1rf6noYGKpIGHMIGEMQsw +CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy +YW5jaXNjbzERMA8GA1UEChMIQ2xvdWRlcmExEjAQBgNVBAMTCWxvY2FsaG9zdDEh +MB8GCSqGSIb3DQEJARYSaGVucnlAY2xvdWRlcmEuY29tggkAox28NHk8vzYwDAYD +VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAEtkPPncCnN2IFVJvz04K+VsX +b6w3qwPynQKc67+++JkNb3TYKrh/0UVM1NrEOu3TGplqOrKgAlITuaWNqNOSBu1R +WJtrz85YkonED5awjjuALVEY82+c7pOXkuv5G5421RINfRn2hNzgw8VFb5CEvxHH +jER80Vx6UGKr/S649qTQ8AzVzTwWS86VsGI2azAD7D67G/IDGf+0P7FsXonKY+vl +vKzkfaO1+qEOLtDHV9mwlsxl3Re/MNym4ExWHi9txynCNiRZHqWoZUS+KyYqIR2q +seCrQwgi1Fer9Ekd5XNjWjigC3VC3SjMqWaxeKbZ2/AuABJMz5xSiRkgwphXEQ== +-----END CERTIFICATE----- + )"; + RETURN_NOT_OK(WriteStringToFile(Env::Default(), test_server_cert, file_path)); + return Status::OK(); +} + +// Writes the test SSL private key into a temporary file. +static Status CreateSSLPrivateKey(const std::string& file_path) { + static const char* test_private_key = R"( +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAqFI96TENhC5K886vpKIsZY1RQQBBKsFFkowPhhCsHxW/1D0Y +3jv8Kyp3adq/N43Oikbeuq7wCJfHK2+eMkzrCf2XAEa408BtyBvE3pcv+eGUMh9C +JnSchGwkqCNOM196L45aac94OcWp41pqQIeqcz4ATk34rAizDw+9MUPBf/0FmXTW +raJcueEk5E1qCb/zpZf1KV3AWPCTkfsrV/NnhoBuBfGKEKpm466zeSQJqi0YgQJK +91lHp2unpKiQWpSUc3sf1ofGvVxFe/RxVVZ4AYXs7DiYH/NYcwc84VCyn8bl5fLm +lI92fXGYN/Qg7Ms/lC2G7D5vFaDFCFQn+zFFUwIDAQABAoIBABNTpiIxbLDhs998 +uvQ3XsumR08kXVcwa/GgvWOSZIEJOUaAYWubDaBTNvTjlhMl6DI+YvKihZMnAkp9 +fXefF1nFUWJJvI0ryi8w6RD54RtbCG4c4raRqysVU7wumZsSenAdc0o09UQE6zXc +uth/+1VSKCzVjRkLwquXDg0rD3vHfQHWQvQlzwUh3OACA3LfLezVqzrEB02YVRxm +xwg5veeMg6Aod8vsvsajry9eE0hKeFGonRANerL9lwZxzD2ZjU2fSEJYY3xxKVgi +o+QVTKaAt9pivOs10YVZDcIDH0xmDpxAkaLb5ZAbnjwhf7WGYgEm8VruAHkJxyXX +yPf3rpkCgYEA0dp/Xv5KBIkD6JJao8hnhtP5x9U7o/pTzRxaO3WUflvTI6DtC0nk +cTOwFVs4WljT76T937q2x4stuX0woHzvIaZ6wwZ2vv81ikDY6pE8eLWsH/xFAmkx +HBfkSijFgJV6EpTqUnFD7QKU89tzWrh/kxaMO1WgFaBhxPPs3K1LDTUCgYEAzVW5 +3yjfVHNgjWTeAbnbToGvUihOidvIvS5cVo5q0Dhfabz0tiXFxAoQUGErUGPC8Nu2 +n/HxTI3b0PbCCwjBsDNqX2kzxTSe5aTGIrBUWbped1bxme8jggXuWYbg8vvLpsYf +wAJPxnGIxW/v/aftHUhbTIuVfZX2+UnilrwiwWcCgYEAg8paz4eXaH277KVtMwq6 +qZwac/tgNz0Qv/GcYVcYaLq2QNvhwoMnakhxvxfIrkS25PuTTJxwCaVIlAMhNMkB +TPrGghBfJtgUAb1z/Ow1NAG0FWpS1I7HfsMqZcBxOK2nOmA3QItNg11pujQJn+Ha +jL9OVj0SCkLs48nk6ToTtjkCgYEAh8YCtNwq6IWuN3CWGCAUMpIwIqxCWof48Zch +OZ7MZEiSVrG6QmMxpRJefTfzUyHUOj2eQZ7SxqMa0c8IuhEdOeyVjudaczD7TLAq +z68252oDovfbo8Tr/sL7OzmjryfuHqXtQqKEq5xRKvR8hYavlGhO7otx2uv5thcz +/CYE+UsCgYAsgewfzbcBqJwsAUs98DK99EU8VqKuaYlU5wNvAVb27O6sVeysSokM +G1TGIXJPphA3dSAe4Pf/j4ff/eGaS20FAFhs4BPpw0fAeCHpmD0BjIba0lxBS/gY +dc+JVPKL8Fe4a8fmsI6ndcZQ9qpOdZM5WOD0ldKRc+SsrYKkTmOOJQ== +-----END RSA PRIVATE KEY----- + )"; + RETURN_NOT_OK(WriteStringToFile(Env::Default(), test_private_key, file_path)); + return Status::OK(); +} + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_context.cc ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_context.cc b/src/kudu/security/tls_context.cc new file mode 100644 index 0000000..be8e3b6 --- /dev/null +++ b/src/kudu/security/tls_context.cc @@ -0,0 +1,133 @@ +// 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. + +#include "kudu/security/tls_context.h" + +#include <string> + +#include <openssl/err.h> +#include <openssl/ssl.h> + +#include "kudu/gutil/strings/substitute.h" +#include "kudu/security/openssl_util.h" +#include "kudu/security/tls_handshake.h" +#include "kudu/util/status.h" + +using strings::Substitute; +using std::string; + +namespace kudu { +namespace security { + +template<> struct SslTypeTraits<SSL> { + static constexpr auto free = &SSL_free; +}; +template<> struct SslTypeTraits<SSL_CTX> { + static constexpr auto free = &SSL_CTX_free; +}; + +TlsContext::TlsContext() { + security::InitializeOpenSSL(); +} + +Status TlsContext::Init() { + CHECK(!ctx_); + + // NOTE: 'SSLv23 method' sounds like it would enable only SSLv2 and SSLv3, but in fact + // this is a sort of wildcard which enables all methods (including TLSv1 and later). + // We explicitly disable SSLv2 and SSLv3 below so that only TLS methods remain. + // See the discussion on https://trac.torproject.org/projects/tor/ticket/11598 for more + // info. + ctx_ = ssl_make_unique(SSL_CTX_new(SSLv23_method())); + if (!ctx_) { + return Status::RuntimeError("failed to create TLS context", GetOpenSSLErrors()); + } + SSL_CTX_set_mode(ctx_.get(), SSL_MODE_AUTO_RETRY); + + // Disable SSLv2 and SSLv3 which are vulnerable to various issues such as POODLE. + // We support versions back to TLSv1.0 since OpenSSL on RHEL 6.4 and earlier does not + // not support TLSv1.1 or later. + // + // Disable SSL/TLS compression to free up CPU resources and be less prone + // to attacks exploiting the compression feature: + // https://tools.ietf.org/html/rfc7525#section-3.3 + SSL_CTX_set_options(ctx_.get(), + SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | + SSL_OP_NO_COMPRESSION); + SSL_CTX_set_verify(ctx_.get(), + SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, nullptr); + return Status::OK(); +} + +Status TlsContext::LoadCertificate(const string& certificate_path) { + ERR_clear_error(); + errno = 0; + if (SSL_CTX_use_certificate_file(ctx_.get(), certificate_path.c_str(), SSL_FILETYPE_PEM) != 1) { + return Status::NotFound(Substitute("failed to load certificate file: '$0'", certificate_path), + GetOpenSSLErrors()); + } + return Status::OK(); +} + +Status TlsContext::LoadPrivateKey(const string& key_path) { + ERR_clear_error(); + errno = 0; + if (SSL_CTX_use_PrivateKey_file(ctx_.get(), key_path.c_str(), SSL_FILETYPE_PEM) != 1) { + return Status::NotFound(Substitute("failed to load private key file: '$0'", key_path), + GetOpenSSLErrors()); + } + return Status::OK(); +} + +Status TlsContext::LoadCertificateAuthority(const string& certificate_path) { + ERR_clear_error(); + errno = 0; + if (SSL_CTX_load_verify_locations(ctx_.get(), certificate_path.c_str(), nullptr) != 1) { + return Status::NotFound(Substitute("failed to load certificate authority file: '$0'", + certificate_path), + GetOpenSSLErrors()); + } + return Status::OK(); +} + +Status TlsContext::InitiateHandshake(TlsHandshakeType handshake_type, + TlsHandshake* handshake) const { + CHECK(ctx_); + CHECK(!handshake->ssl_); + handshake->adopt_ssl(ssl_make_unique(SSL_new(ctx_.get()))); + if (!handshake->ssl_) { + return Status::RuntimeError("failed to create SSL handle", GetOpenSSLErrors()); + } + + SSL_set_bio(handshake->ssl(), + BIO_new(BIO_s_mem()), + BIO_new(BIO_s_mem())); + + switch (handshake_type) { + case TlsHandshakeType::SERVER: + SSL_set_accept_state(handshake->ssl()); + break; + case TlsHandshakeType::CLIENT: + SSL_set_connect_state(handshake->ssl()); + break; + } + + return Status::OK(); +} + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_context.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_context.h b/src/kudu/security/tls_context.h new file mode 100644 index 0000000..5ba3c0e --- /dev/null +++ b/src/kudu/security/tls_context.h @@ -0,0 +1,62 @@ +// 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. + +#pragma once + +#include <functional> +#include <string> + +#include "kudu/security/openssl_util.h" +#include "kudu/security/tls_handshake.h" +#include "kudu/util/status.h" + +namespace kudu { +namespace security { + +// TlsContext wraps data required by the OpenSSL library for creating TLS +// protected channels. A single TlsContext instance should be used per server or +// client instance. +class TlsContext { + + public: + + TlsContext(); + + ~TlsContext() = default; + + Status Init(); + + // Load the server certificate. + Status LoadCertificate(const std::string& certificate_path); + + // Load the private key for the server certificate. + Status LoadPrivateKey(const std::string& key_path); + + // Load the certificate authority. + Status LoadCertificateAuthority(const std::string& certificate_path); + + // Initiates a new TlsHandshake instance. + Status InitiateHandshake(TlsHandshakeType handshake_type, TlsHandshake* handshake) const; + + private: + + // Owned SSL context. + c_unique_ptr<SSL_CTX> ctx_; +}; + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_handshake-test.cc ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_handshake-test.cc b/src/kudu/security/tls_handshake-test.cc new file mode 100644 index 0000000..08f32ba --- /dev/null +++ b/src/kudu/security/tls_handshake-test.cc @@ -0,0 +1,76 @@ +// 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. + +#include "kudu/security/tls_handshake.h" + +#include <string> + +#include <gtest/gtest.h> + +#include "kudu/security/security-test-util.h" +#include "kudu/security/tls_context.h" +#include "kudu/util/test_util.h" + +namespace kudu { +namespace security { + +class TestTlsHandshake : public KuduTest {}; + +TEST_F(TestTlsHandshake, TestHandshake) { + string cert_path = GetTestPath("cert.pem"); + string key_path = GetTestPath("key.pem"); + ASSERT_OK(CreateSSLServerCert(cert_path)); + ASSERT_OK(CreateSSLPrivateKey(key_path)); + + TlsContext tls_context; + ASSERT_OK(tls_context.Init()); + ASSERT_OK(tls_context.LoadCertificate(cert_path)); + ASSERT_OK(tls_context.LoadPrivateKey(key_path)); + ASSERT_OK(tls_context.LoadCertificateAuthority(cert_path)); + + TlsHandshake server; + TlsHandshake client; + + tls_context.InitiateHandshake(TlsHandshakeType::SERVER, &server); + tls_context.InitiateHandshake(TlsHandshakeType::CLIENT, &client); + + string buf1; + string buf2; + + // Client sends Hello + ASSERT_TRUE(client.Continue(buf1, &buf2).IsIncomplete()); + ASSERT_GT(buf2.size(), 0); + + // Server receives client Hello, and sends server Hello + ASSERT_TRUE(server.Continue(buf2, &buf1).IsIncomplete()); + ASSERT_GT(buf1.size(), 0); + + // Client receives server Hello and sends client Finished + ASSERT_TRUE(client.Continue(buf1, &buf2).IsIncomplete()); + ASSERT_GT(buf2.size(), 0); + + // Server receives client Finished and sends server Finished + ASSERT_OK(server.Continue(buf2, &buf1)); + ASSERT_GT(buf1.size(), 0); + + // Client receives server Finished + ASSERT_OK(client.Continue(buf1, &buf2)); + ASSERT_EQ(buf2.size(), 0); +} + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_handshake.cc ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_handshake.cc b/src/kudu/security/tls_handshake.cc new file mode 100644 index 0000000..926861f --- /dev/null +++ b/src/kudu/security/tls_handshake.cc @@ -0,0 +1,144 @@ +// 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. + +#include "kudu/security/tls_handshake.h" + +#include <memory> +#include <string> + +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <openssl/x509.h> +#include <openssl/x509v3.h> + +#include "kudu/security/tls_socket.h" +#include "kudu/util/net/sockaddr.h" +#include "kudu/util/status.h" + +#if OPENSSL_VERSION_NUMBER < 0x10002000L +#include "kudu/security/x509_check_host.h" +#endif // OPENSSL_VERSION_NUMBER + +using std::string; +using std::unique_ptr; + +namespace kudu { +namespace security { + +template<> struct SslTypeTraits<X509> { + static constexpr auto free = &X509_free; +}; + +Status TlsHandshake::Continue(const string& recv, string* send) { + CHECK(ssl_); + ERR_clear_error(); + + BIO* rbio = SSL_get_rbio(ssl_.get()); + int n = BIO_write(rbio, recv.data(), recv.size()); + DCHECK_EQ(n, recv.size()); + DCHECK_EQ(BIO_ctrl_pending(rbio), recv.size()); + + int rc = SSL_do_handshake(ssl_.get()); + if (rc != 1) { + int ssl_err = SSL_get_error(ssl_.get(), rc); + // WANT_READ and WANT_WRITE indicate that the handshake is not yet complete. + if (ssl_err != SSL_ERROR_WANT_READ && ssl_err != SSL_ERROR_WANT_WRITE) { + return Status::RuntimeError("TLS Handshake error", GetSSLErrorDescription(ssl_err)); + } + } + + BIO* wbio = SSL_get_wbio(ssl_.get()); + int pending = BIO_ctrl_pending(wbio); + + send->resize(pending); + BIO_read(wbio, &(*send)[0], send->size()); + DCHECK_EQ(BIO_ctrl_pending(wbio), 0); + + if (rc == 1) { + // The handshake is done, but in the case of the server, we still need to + // send the final response to the client. + DCHECK_GE(send->size(), 0); + return Status::OK(); + } + DCHECK_GT(send->size(), 0); + return Status::Incomplete("TLS Handshake incomplete"); +} + +Status TlsHandshake::Verify(const Socket& socket) const { + DCHECK(SSL_is_init_finished(ssl_.get())); + CHECK(ssl_); + ERR_clear_error(); + + // Verify if the handshake was successful. + int rc = SSL_get_verify_result(ssl_.get()); + if (rc != X509_V_OK) { + return Status::NotAuthorized("SSL_get_verify_result()", X509_verify_cert_error_string(rc)); + } + + // Get the peer certificate. + c_unique_ptr<X509> cert = ssl_make_unique(SSL_get_peer_certificate(ssl_.get())); + if (!cert && (SSL_get_verify_mode(ssl_.get()) & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)) { + return Status::NotAuthorized("Handshake failed: unable to retreive peer certificate"); + } + + // Get the peer's hostname + Sockaddr peer_addr; + if (!socket.GetPeerAddress(&peer_addr).ok()) { + return Status::NotAuthorized( + "TLS certificate hostname verification failed: unable to get peer address"); + } + string peer_hostname; + RETURN_NOT_OK_PREPEND(peer_addr.LookupHostname(&peer_hostname), + "TLS certificate hostname verification failed: unable to lookup peer hostname"); + + // Check if the hostname matches with either the Common Name or any of the Subject Alternative + // Names of the certificate. + int match = X509_check_host(cert.get(), + peer_hostname.c_str(), + peer_hostname.length(), + 0, + nullptr); + if (match == 0) { + return Status::NotAuthorized("TLS certificate hostname verification failed"); + } + if (match < 0) { + return Status::RuntimeError("TLS certificate hostname verification error", GetOpenSSLErrors()); + } + DCHECK_EQ(match, 1); + return Status::OK(); +} + +Status TlsHandshake::Finish(unique_ptr<Socket>* socket) { + RETURN_NOT_OK(Verify(**socket)); + + int fd = (*socket)->Release(); + + // Give the socket to the SSL instance. This will automatically free the + // read and write memory BIO instances. + int ret = SSL_set_fd(ssl_.get(), fd); + if (ret != 1) { + return Status::RuntimeError("TLS handshake error", GetOpenSSLErrors()); + } + + // Transfer the SSL instance to the socket. + socket->reset(new TlsSocket(fd, std::move(ssl_))); + + return Status::OK(); +} + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_handshake.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_handshake.h b/src/kudu/security/tls_handshake.h new file mode 100644 index 0000000..a138c76 --- /dev/null +++ b/src/kudu/security/tls_handshake.h @@ -0,0 +1,98 @@ +// 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. + +#pragma once + +#include <memory> +#include <string> + +#include "kudu/security/openssl_util.h" +#include "kudu/util/net/socket.h" +#include "kudu/util/status.h" + +namespace kudu { + +class Socket; + +namespace security { + +enum class TlsHandshakeType { + // The local endpoint is the TLS client (initiator). + CLIENT, + // The local endpoint is the TLS server (acceptor). + SERVER, +}; + +// TlsHandshake manages an ongoing TLS handshake between a client and server. +// +// TlsHandshake instances are default constructed, but must be initialized +// before use using TlsContext::InitiateHandshake. +class TlsHandshake { + public: + + TlsHandshake() = default; + ~TlsHandshake() = default; + + // Continue or start a new handshake. + // + // 'recv' should contain the input buffer from the remote end, or an empty + // string when the handshake is new. + // + // 'send' should contain the output buffer which must be sent to the remote + // end. + // + // Returns Status::OK when the handshake is complete, however the 'send' + // buffer may contain a message which must still be transmitted to the remote + // end. If the send buffer is empty after this call and the return is + // Status::OK, the socket should immediately be wrapped in the TLS channel + // using 'Finish'. If the send buffer is not empty, the message should be sent + // to the remote end, and then the socket should be wrapped using 'Finish'. + // + // Returns Status::Incomplete when the handshake must continue for another + // round of messages. + // + // Returns any other status code on error. + Status Continue(const std::string& recv, std::string* send); + + // Finishes the handshake, wrapping the provided socket in the negotiated TLS + // channel. This 'TlsHandshake' instance should not be used again after + // calling this. + Status Finish(std::unique_ptr<Socket>* socket); + + private: + friend class TlsContext; + + // Set the SSL to use during the handshake. Called once by + // TlsContext::InitiateHandshake before starting the handshake processes. + void adopt_ssl(c_unique_ptr<SSL> ssl) { + CHECK(!ssl_); + ssl_ = std::move(ssl); + } + + SSL* ssl() { + return ssl_.get(); + } + + // Verifies that the handshake is valid for the provided socket. + Status Verify(const Socket& socket) const; + + // Owned SSL handle. + c_unique_ptr<SSL> ssl_; +}; + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_socket.cc ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_socket.cc b/src/kudu/security/tls_socket.cc new file mode 100644 index 0000000..20b023e --- /dev/null +++ b/src/kudu/security/tls_socket.cc @@ -0,0 +1,123 @@ +// 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. + +#include "kudu/security/tls_socket.h" + +#include <openssl/err.h> +#include <openssl/ssl.h> + +#include "kudu/security/openssl_util.h" + +namespace kudu { +namespace security { + +TlsSocket::TlsSocket(int fd, c_unique_ptr<SSL> ssl) + : Socket(fd), + ssl_(std::move(ssl)) { +} + +TlsSocket::~TlsSocket() { + ignore_result(Close()); +} + +Status TlsSocket::Write(const uint8_t *buf, int32_t amt, int32_t *nwritten) { + CHECK(ssl_); + ERR_clear_error(); + errno = 0; + int32_t bytes_written = SSL_write(ssl_.get(), buf, amt); + if (bytes_written <= 0) { + auto error_code = SSL_get_error(ssl_.get(), bytes_written); + if (error_code == SSL_ERROR_WANT_WRITE) { + // Socket not ready to write yet. + *nwritten = 0; + return Status::OK(); + } + return Status::NetworkError("TlsSocket::Write", GetSSLErrorDescription(error_code)); + } + *nwritten = bytes_written; + return Status::OK(); +} + +Status TlsSocket::Writev(const struct ::iovec *iov, int iov_len, int32_t *nwritten) { + CHECK(ssl_); + ERR_clear_error(); + int32_t total_written = 0; + // Allows packets to be aggresively be accumulated before sending. + RETURN_NOT_OK(SetTcpCork(1)); + Status write_status = Status::OK(); + for (int i = 0; i < iov_len; ++i) { + int32_t frame_size = iov[i].iov_len; + // Don't return before unsetting TCP_CORK. + write_status = Write(static_cast<uint8_t*>(iov[i].iov_base), frame_size, nwritten); + total_written += *nwritten; + if (*nwritten < frame_size) break; + } + RETURN_NOT_OK(SetTcpCork(0)); + *nwritten = total_written; + return write_status; +} + +Status TlsSocket::Recv(uint8_t *buf, int32_t amt, int32_t *nread) { + CHECK(ssl_); + ERR_clear_error(); + int32_t bytes_read = SSL_read(ssl_.get(), buf, amt); + if (bytes_read <= 0) { + if (bytes_read == 0 && SSL_get_shutdown(ssl_.get()) == SSL_RECEIVED_SHUTDOWN) { + return Status::NetworkError("TlsSocket::Recv", "received remote shutdown", ESHUTDOWN); + } + auto error_code = SSL_get_error(ssl_.get(), bytes_read); + if (error_code == SSL_ERROR_WANT_READ) { + // Nothing available to read yet. + *nread = 0; + return Status::OK(); + } + return Status::NetworkError("TlsSocket::Recv", GetSSLErrorDescription(error_code)); + } + *nread = bytes_read; + return Status::OK(); +} + +Status TlsSocket::Close() { + ERR_clear_error(); + errno = 0; + + if (!ssl_) { + // Socket is already closed. + return Status::OK(); + } + + // Start the TLS shutdown processes. We don't care about waiting for the + // response, since the underlying socket will not be reused. + int32_t ret = SSL_shutdown(ssl_.get()); + Status ssl_shutdown; + if (ret >= 0) { + ssl_shutdown = Status::OK(); + } else { + auto error_code = SSL_get_error(ssl_.get(), ret); + ssl_shutdown = Status::NetworkError("TlsSocket::Close", GetSSLErrorDescription(error_code)); + } + + ssl_.reset(); + ERR_remove_state(0); + + // Close the underlying socket. + RETURN_NOT_OK(Socket::Close()); + return ssl_shutdown; +} + +} // namespace security +} // namespace kudu http://git-wip-us.apache.org/repos/asf/kudu/blob/72b2ffda/src/kudu/security/tls_socket.h ---------------------------------------------------------------------- diff --git a/src/kudu/security/tls_socket.h b/src/kudu/security/tls_socket.h new file mode 100644 index 0000000..70da1e2 --- /dev/null +++ b/src/kudu/security/tls_socket.h @@ -0,0 +1,54 @@ +// 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. + +#pragma once + +#include "kudu/security/openssl_util.h" +#include "kudu/util/net/socket.h" +#include "kudu/util/status.h" + +struct ssl_st; +typedef ssl_st SSL; + +namespace kudu { +namespace security { + +class TlsSocket : public Socket { + public: + + ~TlsSocket() override; + + Status Write(const uint8_t *buf, int32_t amt, int32_t *nwritten) override; + + Status Writev(const struct ::iovec *iov, int iov_len, int32_t *nwritten) override; + + Status Recv(uint8_t *buf, int32_t amt, int32_t *nread) override; + + Status Close() override; + + private: + + friend class TlsHandshake; + + TlsSocket(int fd, c_unique_ptr<SSL> ssl); + + // Owned SSL handle. + c_unique_ptr<SSL> ssl_; +}; + +} // namespace security +} // namespace kudu
