You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by jo...@apache.org on 2015/08/31 16:39:18 UTC
mesos git commit: SSL: Made SSLTest fixture publicly accessible.
Repository: mesos
Updated Branches:
refs/heads/master d6685e492 -> 067034047
SSL: Made SSLTest fixture publicly accessible.
Refactored libprocess SSL tests to be available for reuse by other
projects.
Review: https://reviews.apache.org/r/37871
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/06703404
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/06703404
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/06703404
Branch: refs/heads/master
Commit: 067034047317bb42ad41d2d93851b373108987d3
Parents: d6685e4
Author: Jojy Varghese <jo...@mesosphere.io>
Authored: Mon Aug 31 09:37:48 2015 -0400
Committer: Joris Van Remoortere <jo...@gmail.com>
Committed: Mon Aug 31 10:38:23 2015 -0400
----------------------------------------------------------------------
3rdparty/libprocess/Makefile.am | 3 +-
3rdparty/libprocess/include/Makefile.am | 2 +
.../libprocess/include/process/ssl/gtest.hpp | 349 +++++++++++++++++++
.../include/process/ssl/utilities.hpp | 115 ++++++
3rdparty/libprocess/src/openssl_util.cpp | 262 --------------
3rdparty/libprocess/src/openssl_util.hpp | 111 ------
3rdparty/libprocess/src/ssl/utilities.cpp | 262 ++++++++++++++
3rdparty/libprocess/src/tests/ssl_tests.cpp | 313 +----------------
8 files changed, 732 insertions(+), 685 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/Makefile.am b/3rdparty/libprocess/Makefile.am
index 7ef5158..6361ac6 100644
--- a/3rdparty/libprocess/Makefile.am
+++ b/3rdparty/libprocess/Makefile.am
@@ -83,8 +83,7 @@ libprocess_la_SOURCES += \
src/libevent_ssl_socket.hpp \
src/openssl.cpp \
src/openssl.hpp \
- src/openssl_util.cpp \
- src/openssl_util.hpp
+ src/ssl/utilities.cpp
endif
libprocess_la_CPPFLAGS = \
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/include/Makefile.am
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/Makefile.am b/3rdparty/libprocess/include/Makefile.am
index 3b6108d..fcc62e9 100644
--- a/3rdparty/libprocess/include/Makefile.am
+++ b/3rdparty/libprocess/include/Makefile.am
@@ -57,6 +57,8 @@ nobase_include_HEADERS = \
process/sequence.hpp \
process/shared.hpp \
process/socket.hpp \
+ process/ssl/gtest.hpp \
+ process/ssl/utilities.hpp \
process/statistics.hpp \
process/system.hpp \
process/subprocess.hpp \
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/include/process/ssl/gtest.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/ssl/gtest.hpp b/3rdparty/libprocess/include/process/ssl/gtest.hpp
new file mode 100644
index 0000000..a6051b7
--- /dev/null
+++ b/3rdparty/libprocess/include/process/ssl/gtest.hpp
@@ -0,0 +1,349 @@
+/**
+ * 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 __PROCESS_SSL_TEST_HPP__
+#define __PROCESS_SSL_TEST_HPP__
+
+#ifdef USE_SSL_SOCKET
+
+#include <openssl/rsa.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include <process/io.hpp>
+#include <process/socket.hpp>
+
+#include <process/ssl/utilities.hpp>
+
+using std::map;
+using std::string;
+using std::vector;
+
+using namespace process;
+using namespace process::network;
+
+namespace process {
+namespace network {
+namespace openssl {
+
+// Forward declare the `reinitialize()` function since we want to
+// programatically change SSL flags during tests.
+void reinitialize();
+
+} // namespace openssl {
+} // namespace network {
+} // namespace process {
+
+
+/**
+ * A Test fixture that sets up SSL keys and certificates.
+ *
+ * This class sets up a private key and certificate pair at
+ * SSLTest::key_path and SSLTest::certificate_path.
+ * It also sets up an independent 'scrap' pair that can be used to
+ * test an invalid certificate authority chain. These can be found at
+ * SSLTest::scrap_key_path and SSLTest::scrap_certificate_path.
+ *
+ * There are some helper functions like SSLTest::setup_server and
+ * SSLTest::launch_client that factor out common behavior used in
+ * tests.
+ */
+class SSLTest : public ::testing::Test
+{
+protected:
+ SSLTest() : data("Hello World!") {}
+
+ /**
+ * @return The path to the authorized private key.
+ */
+ static const Path& key_path()
+ {
+ static Path path(path::join(os::getcwd(), "key.pem"));
+ return path;
+ }
+
+ /**
+ * @return The path to the authorized certificate.
+ */
+ static const Path& certificate_path()
+ {
+ static Path path(path::join(os::getcwd(), "cert.pem"));
+ return path;
+ }
+
+ /**
+ * @return The path to the unauthorized private key.
+ */
+ static const Path& scrap_key_path()
+ {
+ static Path path(path::join(os::getcwd(), "scrap_key.pem"));
+ return path;
+ }
+
+ /**
+ * @return The path to the unauthorized certificate.
+ */
+ static const Path& scrap_certificate_path()
+ {
+ static Path path(path::join(os::getcwd(), "scrap_cert.pem"));
+ return path;
+ }
+
+ static void cleanup_directories()
+ {
+ os::rm(key_path().value);
+ os::rm(certificate_path().value);
+ os::rm(scrap_key_path().value);
+ os::rm(scrap_certificate_path().value);
+ }
+
+ static void SetUpTestCase()
+ {
+ // We store the allocated objects in these results so that we can
+ // have a consolidated 'cleanup()' function. This makes all the
+ // 'EXIT()' calls more readable and less error prone.
+ Result<EVP_PKEY*> private_key = None();
+ Result<X509*> certificate = None();
+ Result<EVP_PKEY*> scrap_key = None();
+ Result<X509*> scrap_certificate = None();
+
+ auto cleanup = [&private_key, &certificate, &scrap_key, &scrap_certificate](
+ bool failure = true) {
+ if (private_key.isSome()) { EVP_PKEY_free(private_key.get()); }
+ if (certificate.isSome()) { X509_free(certificate.get()); }
+ if (scrap_key.isSome()) { EVP_PKEY_free(scrap_key.get()); }
+ if (scrap_certificate.isSome()) { X509_free(scrap_certificate.get()); }
+
+ // If we are under a failure condition, clean up any files we
+ // already generated. The expected behavior is that they will be
+ // cleaned up in 'TearDownTestCase()'; however, we call ABORT
+ // during 'SetUpTestCase()' failures.
+ if (failure) {
+ cleanup_directories();
+ }
+ };
+
+ // Generate the authority key.
+ private_key = openssl::generate_private_rsa_key();
+ if (private_key.isError()) {
+ ABORT("Could not generate private key: " + private_key.error());
+ }
+
+ // Figure out the hostname that 'INADDR_LOOPBACK' will bind to.
+ // Set the hostname of the certificate to this hostname so that
+ // hostname verification of the certificate will pass.
+ Try<string> hostname = net::getHostname(net::IP(INADDR_LOOPBACK));
+ if (hostname.isError()) {
+ cleanup();
+ ABORT("Could not determine hostname of 'INADDR_LOOPBACK': " +
+ hostname.error());
+ }
+
+ // Generate an authorized certificate.
+ certificate = openssl::generate_x509(
+ private_key.get(),
+ private_key.get(),
+ None(),
+ 1,
+ 365,
+ hostname.get());
+
+ if (certificate.isError()) {
+ cleanup();
+ ABORT("Could not generate certificate: " + certificate.error());
+ }
+
+ // Write the authority key to disk.
+ Try<Nothing> key_write =
+ openssl::write_key_file(private_key.get(), key_path());
+
+ if (key_write.isError()) {
+ cleanup();
+ ABORT("Could not write private key to disk: " + key_write.error());
+ }
+
+ // Write the authorized certificate to disk.
+ Try<Nothing> certificate_write =
+ openssl::write_certificate_file(certificate.get(), certificate_path());
+
+ if (certificate_write.isError()) {
+ cleanup();
+ ABORT("Could not write certificate to disk: " +
+ certificate_write.error());
+ }
+
+ // Generate a scrap key.
+ scrap_key = openssl::generate_private_rsa_key();
+ if (scrap_key.isError()) {
+ cleanup();
+ ABORT("Could not generate a scrap private key: " + scrap_key.error());
+ }
+
+ // Write the scrap key to disk.
+ key_write = openssl::write_key_file(scrap_key.get(), scrap_key_path());
+
+ if (key_write.isError()) {
+ cleanup();
+ ABORT("Could not write scrap key to disk: " + key_write.error());
+ }
+
+ // Generate a scrap certificate.
+ scrap_certificate =
+ openssl::generate_x509(scrap_key.get(), scrap_key.get());
+
+ if (scrap_certificate.isError()) {
+ cleanup();
+ ABORT("Could not generate a scrap certificate: " +
+ scrap_certificate.error());
+ }
+
+ // Write the scrap certificate to disk.
+ certificate_write = openssl::write_certificate_file(
+ scrap_certificate.get(),
+ scrap_certificate_path());
+
+ if (certificate_write.isError()) {
+ cleanup();
+ ABORT("Could not write scrap certificate to disk: " +
+ certificate_write.error());
+ }
+
+ // Since we successfully set up all our state, we call cleanup
+ // with failure set to 'false'.
+ cleanup(false);
+ }
+
+ static void TearDownTestCase()
+ {
+ // Clean up all the pem files we generated.
+ cleanup_directories();
+ }
+
+ virtual void SetUp()
+ {
+ // This unsets all the SSL environment variables. Necessary for
+ // ensuring a clean starting slate between tests.
+ os::unsetenv("SSL_ENABLED");
+ os::unsetenv("SSL_SUPPORT_DOWNGRADE");
+ os::unsetenv("SSL_CERT_FILE");
+ os::unsetenv("SSL_KEY_FILE");
+ os::unsetenv("SSL_VERIFY_CERT");
+ os::unsetenv("SSL_REQUIRE_CERT");
+ os::unsetenv("SSL_VERIFY_DEPTH");
+ os::unsetenv("SSL_CA_DIR");
+ os::unsetenv("SSL_CA_FILE");
+ os::unsetenv("SSL_CIPHERS");
+ os::unsetenv("SSL_ENABLE_SSL_V3");
+ os::unsetenv("SSL_ENABLE_TLS_V1_0");
+ os::unsetenv("SSL_ENABLE_TLS_V1_1");
+ os::unsetenv("SSL_ENABLE_TLS_V1_2");
+ }
+
+ /**
+ * Initializes a listening server.
+ *
+ * @param environment The SSL environment variables to launch the
+ * server socket with.
+ *
+ * @return Socket if successful otherwise an Error.
+ */
+ Try<Socket> setup_server(const map<string, string>& environment)
+ {
+ foreachpair (const string& name, const string& value, environment) {
+ os::setenv(name, value);
+ }
+ openssl::reinitialize();
+
+ const Try<Socket> create = Socket::create(Socket::SSL);
+ if (create.isError()) {
+ return Error(create.error());
+ }
+
+ Socket server = create.get();
+
+ // We need to explicitly bind to INADDR_LOOPBACK so the
+ // certificate we create in this test fixture can be verified.
+ Try<Address> bind = server.bind(Address(net::IP(INADDR_LOOPBACK), 0));
+ if (bind.isError()) {
+ return Error(bind.error());
+ }
+
+ const Try<Nothing> listen = server.listen(BACKLOG);
+ if (listen.isError()) {
+ return Error(listen.error());
+ }
+
+ return server;
+ }
+
+ /**
+ * Launches a test SSL client as a subprocess connecting to the
+ * server.
+ *
+ * The subprocess calls the 'ssl-client' binary with the provided
+ * environment.
+ *
+ * @param environment The SSL environment variables to launch the
+ * SSL client subprocess with.
+ * @param use_ssl_socket Whether the SSL client will try to connect
+ * using an SSL socket or a POLL socket.
+ *
+ * @return Subprocess if successful otherwise an Error.
+ */
+ Try<Subprocess> launch_client(
+ const map<string, string>& environment,
+ const Socket& server,
+ bool use_ssl_socket)
+ {
+ const Try<Address> address = server.address();
+ if (address.isError()) {
+ return Error(address.error());
+ }
+
+ // Set up arguments to be passed to the 'client-ssl' binary.
+ const vector<string> argv = {
+ "ssl-client",
+ "--use_ssl=" + stringify(use_ssl_socket),
+ "--server=127.0.0.1",
+ "--port=" + stringify(address.get().port),
+ "--data=" + data};
+
+ Result<string> path = os::realpath(BUILD_DIR);
+ if (!path.isSome()) {
+ return Error("Could not establish build directory path");
+ }
+
+ return subprocess(
+ path::join(path.get(), "ssl-client"),
+ argv,
+ Subprocess::PIPE(),
+ Subprocess::PIPE(),
+ Subprocess::FD(STDERR_FILENO),
+ None(),
+ environment);
+ }
+
+ static constexpr size_t BACKLOG = 5;
+
+ const string data;
+};
+
+#endif // USE_SSL_SOCKET
+
+#endif // __PROCESS_SSL_TEST_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/include/process/ssl/utilities.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/include/process/ssl/utilities.hpp b/3rdparty/libprocess/include/process/ssl/utilities.hpp
new file mode 100644
index 0000000..25d3a38
--- /dev/null
+++ b/3rdparty/libprocess/include/process/ssl/utilities.hpp
@@ -0,0 +1,115 @@
+/**
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+#ifndef __OPENSSL_UTIL_HPP__
+#define __OPENSSL_UTIL_HPP__
+
+#ifdef USE_SSL_SOCKET
+
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+#include <stout/nothing.hpp>
+#include <stout/path.hpp>
+#include <stout/try.hpp>
+
+namespace process {
+namespace network {
+namespace openssl {
+
+/**
+ * Generates an RSA key.
+ *
+ * The caller is responsible for calling `EVP_PKEY_free` on the
+ * returned EVP_PKEY.
+ * @see <a href="https://www.openssl.org/docs/crypto/RSA_generate_key.html">RSA_generate_key_ex</a> // NOLINT
+ *
+ * @param bits The modulus size used to generate the key.
+ * @param exponent The public exponent, an odd number.
+ *
+ * @return A pointer to an EVP_PKEY if successful otherwise an Error.
+ */
+Try<EVP_PKEY*> generate_private_rsa_key(
+ int bits = 2048,
+ unsigned long exponent = RSA_F4);
+
+
+/**
+ * Generates an X509 certificate.
+ *
+ * The X509 certificate is generated for the @param subject_key and
+ * signed by the @param sign_key. The caller is responsible for
+ * calling `X509_free` on the returned X509 object.
+ * The common name of the certificate will be set to @param hostname
+ * or that of the localhost if @param hostname is not provided.
+ * If a @param parent_certificate is provided, then the issuer name of
+ * the certificate will be set to the subject name of the
+ * @param parent_certificate. Otherwise, it is assumed this is a
+ * self-signed certificate in which case the @param subject_key must
+ * be the same as the @param sign_key, and the issuer name will be the
+ * same as the subject name.
+ *
+ * @param subject_key The key that will be made public by the
+ * certificate.
+ * @param sign_key The private key used to sign the certificate.
+ * @param parent_certificate An optional parent certificate that will
+ * be used to set the issuer name.
+ * @param serial The serial number of the certificate.
+ * @param days The number of days from the current time that the
+ * certificate will be valid.
+ * @param hostname An optional hostname used to set the common name of
+ * the certificate.
+ *
+ * @return A pointer to an X509 certificate if successful otherwise an
+ * Error.
+ */
+Try<X509*> generate_x509(
+ EVP_PKEY* subject_key,
+ EVP_PKEY* sign_key,
+ const Option<X509*>& parent_certificate = None(),
+ int serial = 1,
+ int days = 365,
+ Option<std::string> hostname = None());
+
+
+/**
+ * Writes a private key (EVP_PKEY) to a file on disk.
+ * @see <a href="https://www.openssl.org/docs/crypto/pem.html">PEM_write_PrivateKey</a> // NOLINT
+ *
+ * @param private_key The private key to write.
+ * @param path The file location to create the file.
+ *
+ * @return Nothing if successful otherwise an Error.
+ */
+Try<Nothing> write_key_file(EVP_PKEY* private_key, const Path& path);
+
+
+/**
+ * Writes an X509 certificate (X509) to a file on disk.
+ * @see <a href="https://www.openssl.org/docs/crypto/pem.html">PEM_write_X509</a> // NOLINT
+ *
+ * @param x509 The certificate to write.
+ * @param path The file location to create the file.
+ *
+ * @return Nothing if successful otherwise an Error.
+ */
+Try<Nothing> write_certificate_file(X509* x509, const Path& path);
+
+} // namespace openssl {
+} // namespace network {
+} // namespace process {
+
+#endif // USE_SSL_SOCKET
+
+#endif // __OPENSSL_UTIL_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/src/openssl_util.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/openssl_util.cpp b/3rdparty/libprocess/src/openssl_util.cpp
deleted file mode 100644
index 42b2860..0000000
--- a/3rdparty/libprocess/src/openssl_util.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-/**
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License
-*/
-
-#include "openssl_util.hpp"
-
-#include <openssl/err.h>
-#include <openssl/rsa.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
-#include <stout/net.hpp>
-#include <stout/stringify.hpp>
-
-// TODO(jmlvanre): Add higher level abstractions for key and
-// certificate generation.
-
-namespace process {
-namespace network {
-namespace openssl {
-
-Try<EVP_PKEY*> generate_private_rsa_key(int bits, unsigned long _exponent)
-{
- // Allocate the in-memory structure for the private key.
- EVP_PKEY* private_key = EVP_PKEY_new();
- if (private_key == NULL) {
- return Error("Failed to allocate key: EVP_PKEY_new");
- }
-
- // Allocate space for the exponent.
- BIGNUM* exponent = BN_new();
- if (exponent == NULL) {
- EVP_PKEY_free(private_key);
- return Error("Failed to allocate exponent: BN_new");
- }
-
- // Assign the exponent.
- if (BN_set_word(exponent, _exponent) != 1) {
- BN_free(exponent);
- EVP_PKEY_free(private_key);
- return Error("Failed to set exponent: BN_set_word");
- }
-
- // Allocate the in-memory structure for the key pair.
- RSA* rsa = RSA_new();
- if (rsa == NULL) {
- BN_free(exponent);
- EVP_PKEY_free(private_key);
- return Error("Failed to allocate RSA: RSA_new");
- }
-
- // Generate the RSA key pair.
- if (RSA_generate_key_ex(rsa, bits, exponent, NULL) != 1) {
- RSA_free(rsa);
- BN_free(exponent);
- EVP_PKEY_free(private_key);
- return Error(ERR_error_string(ERR_get_error(), NULL));
- }
-
- // We no longer need the exponent, so let's free it.
- BN_free(exponent);
-
- // Associate the RSA key with the private key. If this association
- // is successful, then the RSA key will be freed when the private
- // key is freed.
- if (EVP_PKEY_assign_RSA(private_key, rsa) != 1) {
- RSA_free(rsa);
- EVP_PKEY_free(private_key);
- return Error("Failed to assign RSA key: EVP_PKEY_assign_RSA");
- }
-
- return private_key;
-}
-
-
-Try<X509*> generate_x509(
- EVP_PKEY* subject_key,
- EVP_PKEY* sign_key,
- const Option<X509*>& parent_certificate,
- int serial,
- int days,
- Option<std::string> hostname)
-{
- Option<X509_NAME*> issuer_name = None();
- if (parent_certificate.isNone()) {
- // If there is no parent certificate, then the subject and
- // signing key must be the same.
- if (subject_key != sign_key) {
- return Error("Subject vs signing key mismatch");
- }
- } else {
- // If there is a parent certificate, then set the issuer name to
- // be that of the parent.
- issuer_name = X509_get_subject_name(parent_certificate.get());
-
- if (issuer_name.get() == NULL) {
- return Error("Failed to get subject name of parent certificate: "
- "X509_get_subject_name");
- }
- }
-
- // Allocate the in-memory structure for the certificate.
- X509* x509 = X509_new();
- if (x509 == NULL) {
- return Error("Failed to allocate certification: X509_new");
- }
-
- // Set the version to V3.
- if (X509_set_version(x509, 2) != 1) {
- X509_free(x509);
- return Error("Failed to set version: X509_set_version");
- }
-
- // Set the serial number.
- if (ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) {
- X509_free(x509);
- return Error("Failed to set serial number: ASN1_INTEGER_set");
- }
-
- // Make this certificate valid for 'days' number of days from now.
- if (X509_gmtime_adj(X509_get_notBefore(x509), 0) == NULL ||
- X509_gmtime_adj(X509_get_notAfter(x509),
- 60L * 60L * 24L * days) == NULL) {
- X509_free(x509);
- return Error("Failed to set valid days of certificate: X509_gmtime_adj");
- }
-
- // Set the public key for our certificate based on the subject key.
- if (X509_set_pubkey(x509, subject_key) != 1) {
- X509_free(x509);
- return Error("Failed to set public key: X509_set_pubkey");
- }
-
- // Figure out our hostname if one was not provided.
- if (hostname.isNone()) {
- const Try<std::string> _hostname = net::hostname();
- if (_hostname.isError()) {
- X509_free(x509);
- return Error("Failed to determine hostname");
- }
-
- hostname = _hostname.get();
- }
-
- // Grab the subject name of the new certificate.
- X509_NAME* name = X509_get_subject_name(x509);
- if (name == NULL) {
- X509_free(x509);
- return Error("Failed to get subject name: X509_get_subject_name");
- }
-
- // Set the country code, organization, and common name.
- if (X509_NAME_add_entry_by_txt(
- name,
- "C",
- MBSTRING_ASC,
- reinterpret_cast<const unsigned char*>("US"),
- -1,
- -1,
- 0) != 1) {
- X509_free(x509);
- return Error("Failed to set country code: X509_NAME_add_entry_by_txt");
- }
-
- if (X509_NAME_add_entry_by_txt(
- name,
- "O",
- MBSTRING_ASC,
- reinterpret_cast<const unsigned char*>("Test"),
- -1,
- -1,
- 0) != 1) {
- X509_free(x509);
- return Error("Failed to set organization name: X509_NAME_add_entry_by_txt");
- }
-
- if (X509_NAME_add_entry_by_txt(
- name,
- "CN",
- MBSTRING_ASC,
- reinterpret_cast<const unsigned char*>(hostname.get().c_str()),
- -1,
- -1,
- 0) != 1) {
- X509_free(x509);
- return Error("Failed to set common name: X509_NAME_add_entry_by_txt");
- }
-
- // Set the issuer name to be the same as the subject if it is not
- // already set (this is a self-signed certificate).
- if (issuer_name.isNone()) {
- issuer_name = name;
- }
-
- CHECK_SOME(issuer_name);
- if (X509_set_issuer_name(x509, issuer_name.get()) != 1) {
- X509_free(x509);
- return Error("Failed to set issuer name: X509_set_issuer_name");
- }
-
- // Sign the certificate with the sign key.
- if (X509_sign(x509, sign_key, EVP_sha1()) == 0) {
- X509_free(x509);
- return Error("Failed to sign certificate: X509_sign");
- }
-
- return x509;
-}
-
-
-Try<Nothing> write_key_file(EVP_PKEY* private_key, const Path& path)
-{
- // We use 'FILE*' here because it is an API requirement by openssl.
- FILE* file = fopen(path.value.c_str(), "wb");
- if (file == NULL) {
- return Error("Failed to open file '" + stringify(path) + "' for writing");
- }
-
- if (PEM_write_PrivateKey(file, private_key, NULL, NULL, 0, NULL, NULL) != 1) {
- fclose(file);
- return Error("Failed to write private key to file '" + stringify(path) +
- "': PEM_write_PrivateKey");
- }
-
- fclose(file);
-
- return Nothing();
-}
-
-
-Try<Nothing> write_certificate_file(X509* x509, const Path& path)
-{
- // We use 'FILE*' here because it is an API requirement by openssl.
- FILE* file = fopen(path.value.c_str(), "wb");
- if (file == NULL) {
- return Error("Failed to open file '" + stringify(path) + "' for writing");
- }
-
- if (PEM_write_X509(file, x509) != 1) {
- fclose(file);
- return Error("Failed to write certificate to file '" + stringify(path) +
- "': PEM_write_X509");
- }
-
- fclose(file);
-
- return Nothing();
-}
-
-} // namespace openssl {
-} // namespace network {
-} // namespace process {
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/src/openssl_util.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/openssl_util.hpp b/3rdparty/libprocess/src/openssl_util.hpp
deleted file mode 100644
index 0890b63..0000000
--- a/3rdparty/libprocess/src/openssl_util.hpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License
-*/
-
-#ifndef __OPENSSL_UTIL_HPP__
-#define __OPENSSL_UTIL_HPP__
-
-#include <openssl/ssl.h>
-#include <openssl/x509.h>
-
-#include <stout/nothing.hpp>
-#include <stout/path.hpp>
-#include <stout/try.hpp>
-
-namespace process {
-namespace network {
-namespace openssl {
-
-/**
- * Generates an RSA key.
- *
- * The caller is responsible for calling `EVP_PKEY_free` on the
- * returned EVP_PKEY.
- * @see <a href="https://www.openssl.org/docs/crypto/RSA_generate_key.html">RSA_generate_key_ex</a> // NOLINT
- *
- * @param bits The modulus size used to generate the key.
- * @param exponent The public exponent, an odd number.
- *
- * @return A pointer to an EVP_PKEY if successful otherwise an Error.
- */
-Try<EVP_PKEY*> generate_private_rsa_key(
- int bits = 2048,
- unsigned long exponent = RSA_F4);
-
-
-/**
- * Generates an X509 certificate.
- *
- * The X509 certificate is generated for the @param subject_key and
- * signed by the @param sign_key. The caller is responsible for
- * calling `X509_free` on the returned X509 object.
- * The common name of the certificate will be set to @param hostname
- * or that of the localhost if @param hostname is not provided.
- * If a @param parent_certificate is provided, then the issuer name of
- * the certificate will be set to the subject name of the
- * @param parent_certificate. Otherwise, it is assumed this is a
- * self-signed certificate in which case the @param subject_key must
- * be the same as the @param sign_key, and the issuer name will be the
- * same as the subject name.
- *
- * @param subject_key The key that will be made public by the
- * certificate.
- * @param sign_key The private key used to sign the certificate.
- * @param parent_certificate An optional parent certificate that will
- * be used to set the issuer name.
- * @param serial The serial number of the certificate.
- * @param days The number of days from the current time that the
- * certificate will be valid.
- * @param hostname An optional hostname used to set the common name of
- * the certificate.
- *
- * @return A pointer to an X509 certificate if successful otherwise an
- * Error.
- */
-Try<X509*> generate_x509(
- EVP_PKEY* subject_key,
- EVP_PKEY* sign_key,
- const Option<X509*>& parent_certificate = None(),
- int serial = 1,
- int days = 365,
- Option<std::string> hostname = None());
-
-
-/**
- * Writes a private key (EVP_PKEY) to a file on disk.
- * @see <a href="https://www.openssl.org/docs/crypto/pem.html">PEM_write_PrivateKey</a> // NOLINT
- *
- * @param private_key The private key to write.
- * @param path The file location to create the file.
- *
- * @return Nothing if successful otherwise an Error.
- */
-Try<Nothing> write_key_file(EVP_PKEY* private_key, const Path& path);
-
-
-/**
- * Writes an X509 certificate (X509) to a file on disk.
- * @see <a href="https://www.openssl.org/docs/crypto/pem.html">PEM_write_X509</a> // NOLINT
- *
- * @param x509 The certificate to write.
- * @param path The file location to create the file.
- *
- * @return Nothing if successful otherwise an Error.
- */
-Try<Nothing> write_certificate_file(X509* x509, const Path& path);
-
-} // namespace openssl {
-} // namespace network {
-} // namespace process {
-
-#endif // __OPENSSL_UTIL_HPP__
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/src/ssl/utilities.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/ssl/utilities.cpp b/3rdparty/libprocess/src/ssl/utilities.cpp
new file mode 100644
index 0000000..b244964
--- /dev/null
+++ b/3rdparty/libprocess/src/ssl/utilities.cpp
@@ -0,0 +1,262 @@
+/**
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+#include <process/ssl/utilities.hpp>
+
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+
+#include <stout/net.hpp>
+#include <stout/stringify.hpp>
+
+// TODO(jmlvanre): Add higher level abstractions for key and
+// certificate generation.
+
+namespace process {
+namespace network {
+namespace openssl {
+
+Try<EVP_PKEY*> generate_private_rsa_key(int bits, unsigned long _exponent)
+{
+ // Allocate the in-memory structure for the private key.
+ EVP_PKEY* private_key = EVP_PKEY_new();
+ if (private_key == NULL) {
+ return Error("Failed to allocate key: EVP_PKEY_new");
+ }
+
+ // Allocate space for the exponent.
+ BIGNUM* exponent = BN_new();
+ if (exponent == NULL) {
+ EVP_PKEY_free(private_key);
+ return Error("Failed to allocate exponent: BN_new");
+ }
+
+ // Assign the exponent.
+ if (BN_set_word(exponent, _exponent) != 1) {
+ BN_free(exponent);
+ EVP_PKEY_free(private_key);
+ return Error("Failed to set exponent: BN_set_word");
+ }
+
+ // Allocate the in-memory structure for the key pair.
+ RSA* rsa = RSA_new();
+ if (rsa == NULL) {
+ BN_free(exponent);
+ EVP_PKEY_free(private_key);
+ return Error("Failed to allocate RSA: RSA_new");
+ }
+
+ // Generate the RSA key pair.
+ if (RSA_generate_key_ex(rsa, bits, exponent, NULL) != 1) {
+ RSA_free(rsa);
+ BN_free(exponent);
+ EVP_PKEY_free(private_key);
+ return Error(ERR_error_string(ERR_get_error(), NULL));
+ }
+
+ // We no longer need the exponent, so let's free it.
+ BN_free(exponent);
+
+ // Associate the RSA key with the private key. If this association
+ // is successful, then the RSA key will be freed when the private
+ // key is freed.
+ if (EVP_PKEY_assign_RSA(private_key, rsa) != 1) {
+ RSA_free(rsa);
+ EVP_PKEY_free(private_key);
+ return Error("Failed to assign RSA key: EVP_PKEY_assign_RSA");
+ }
+
+ return private_key;
+}
+
+
+Try<X509*> generate_x509(
+ EVP_PKEY* subject_key,
+ EVP_PKEY* sign_key,
+ const Option<X509*>& parent_certificate,
+ int serial,
+ int days,
+ Option<std::string> hostname)
+{
+ Option<X509_NAME*> issuer_name = None();
+ if (parent_certificate.isNone()) {
+ // If there is no parent certificate, then the subject and
+ // signing key must be the same.
+ if (subject_key != sign_key) {
+ return Error("Subject vs signing key mismatch");
+ }
+ } else {
+ // If there is a parent certificate, then set the issuer name to
+ // be that of the parent.
+ issuer_name = X509_get_subject_name(parent_certificate.get());
+
+ if (issuer_name.get() == NULL) {
+ return Error("Failed to get subject name of parent certificate: "
+ "X509_get_subject_name");
+ }
+ }
+
+ // Allocate the in-memory structure for the certificate.
+ X509* x509 = X509_new();
+ if (x509 == NULL) {
+ return Error("Failed to allocate certification: X509_new");
+ }
+
+ // Set the version to V3.
+ if (X509_set_version(x509, 2) != 1) {
+ X509_free(x509);
+ return Error("Failed to set version: X509_set_version");
+ }
+
+ // Set the serial number.
+ if (ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) {
+ X509_free(x509);
+ return Error("Failed to set serial number: ASN1_INTEGER_set");
+ }
+
+ // Make this certificate valid for 'days' number of days from now.
+ if (X509_gmtime_adj(X509_get_notBefore(x509), 0) == NULL ||
+ X509_gmtime_adj(X509_get_notAfter(x509),
+ 60L * 60L * 24L * days) == NULL) {
+ X509_free(x509);
+ return Error("Failed to set valid days of certificate: X509_gmtime_adj");
+ }
+
+ // Set the public key for our certificate based on the subject key.
+ if (X509_set_pubkey(x509, subject_key) != 1) {
+ X509_free(x509);
+ return Error("Failed to set public key: X509_set_pubkey");
+ }
+
+ // Figure out our hostname if one was not provided.
+ if (hostname.isNone()) {
+ const Try<std::string> _hostname = net::hostname();
+ if (_hostname.isError()) {
+ X509_free(x509);
+ return Error("Failed to determine hostname");
+ }
+
+ hostname = _hostname.get();
+ }
+
+ // Grab the subject name of the new certificate.
+ X509_NAME* name = X509_get_subject_name(x509);
+ if (name == NULL) {
+ X509_free(x509);
+ return Error("Failed to get subject name: X509_get_subject_name");
+ }
+
+ // Set the country code, organization, and common name.
+ if (X509_NAME_add_entry_by_txt(
+ name,
+ "C",
+ MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>("US"),
+ -1,
+ -1,
+ 0) != 1) {
+ X509_free(x509);
+ return Error("Failed to set country code: X509_NAME_add_entry_by_txt");
+ }
+
+ if (X509_NAME_add_entry_by_txt(
+ name,
+ "O",
+ MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>("Test"),
+ -1,
+ -1,
+ 0) != 1) {
+ X509_free(x509);
+ return Error("Failed to set organization name: X509_NAME_add_entry_by_txt");
+ }
+
+ if (X509_NAME_add_entry_by_txt(
+ name,
+ "CN",
+ MBSTRING_ASC,
+ reinterpret_cast<const unsigned char*>(hostname.get().c_str()),
+ -1,
+ -1,
+ 0) != 1) {
+ X509_free(x509);
+ return Error("Failed to set common name: X509_NAME_add_entry_by_txt");
+ }
+
+ // Set the issuer name to be the same as the subject if it is not
+ // already set (this is a self-signed certificate).
+ if (issuer_name.isNone()) {
+ issuer_name = name;
+ }
+
+ CHECK_SOME(issuer_name);
+ if (X509_set_issuer_name(x509, issuer_name.get()) != 1) {
+ X509_free(x509);
+ return Error("Failed to set issuer name: X509_set_issuer_name");
+ }
+
+ // Sign the certificate with the sign key.
+ if (X509_sign(x509, sign_key, EVP_sha1()) == 0) {
+ X509_free(x509);
+ return Error("Failed to sign certificate: X509_sign");
+ }
+
+ return x509;
+}
+
+
+Try<Nothing> write_key_file(EVP_PKEY* private_key, const Path& path)
+{
+ // We use 'FILE*' here because it is an API requirement by openssl.
+ FILE* file = fopen(path.value.c_str(), "wb");
+ if (file == NULL) {
+ return Error("Failed to open file '" + stringify(path) + "' for writing");
+ }
+
+ if (PEM_write_PrivateKey(file, private_key, NULL, NULL, 0, NULL, NULL) != 1) {
+ fclose(file);
+ return Error("Failed to write private key to file '" + stringify(path) +
+ "': PEM_write_PrivateKey");
+ }
+
+ fclose(file);
+
+ return Nothing();
+}
+
+
+Try<Nothing> write_certificate_file(X509* x509, const Path& path)
+{
+ // We use 'FILE*' here because it is an API requirement by openssl.
+ FILE* file = fopen(path.value.c_str(), "wb");
+ if (file == NULL) {
+ return Error("Failed to open file '" + stringify(path) + "' for writing");
+ }
+
+ if (PEM_write_X509(file, x509) != 1) {
+ fclose(file);
+ return Error("Failed to write certificate to file '" + stringify(path) +
+ "': PEM_write_X509");
+ }
+
+ fclose(file);
+
+ return Nothing();
+}
+
+} // namespace openssl {
+} // namespace network {
+} // namespace process {
http://git-wip-us.apache.org/repos/asf/mesos/blob/06703404/3rdparty/libprocess/src/tests/ssl_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/tests/ssl_tests.cpp b/3rdparty/libprocess/src/tests/ssl_tests.cpp
index 7a316bc..ee30a02 100644
--- a/3rdparty/libprocess/src/tests/ssl_tests.cpp
+++ b/3rdparty/libprocess/src/tests/ssl_tests.cpp
@@ -14,22 +14,19 @@
#include <stdio.h>
-#include <openssl/rsa.h>
-#include <openssl/bio.h>
-#include <openssl/x509.h>
-#include <openssl/x509v3.h>
-
#include <process/future.hpp>
#include <process/gtest.hpp>
#include <process/io.hpp>
#include <process/socket.hpp>
#include <process/subprocess.hpp>
+#include <process/ssl/gtest.hpp>
+#include <process/ssl/utilities.hpp>
+
#include <stout/gtest.hpp>
#include <stout/os.hpp>
#include "openssl.hpp"
-#include "openssl_util.hpp"
using std::map;
using std::string;
@@ -38,18 +35,6 @@ using std::vector;
// We only run these tests if we have configured with '--enable-ssl'.
#ifdef USE_SSL_SOCKET
-namespace process {
-namespace network {
-namespace openssl {
-
-// Forward declare the `reinitialize()` function since we want to
-// programatically change SSL flags during tests.
-void reinitialize();
-
-} // namespace openssl {
-} // namespace network {
-} // namespace process {
-
using namespace process;
using namespace process::network;
@@ -98,298 +83,6 @@ Future<Nothing> await_subprocess(
}
-/**
- * A Test fixture that sets up SSL keys and certificates.
- *
- * This class sets up a private key and certificate pair at
- * SSLTest::key_path and SSLTest::certificate_path.
- * It also sets up an independent 'scrap' pair that can be used to
- * test an invalid certificate authority chain. These can be found at
- * SSLTest::scrap_key_path and SSLTest::scrap_certificate_path.
- *
- * There are some helper functions like SSLTest::setup_server and
- * SSLTest::launch_client that factor out common behavior used in
- * tests.
- */
-class SSLTest : public ::testing::Test
-{
-protected:
- SSLTest() : data("Hello World!") {}
-
- /**
- * @return The path to the authorized private key.
- */
- static const Path& key_path()
- {
- static Path path(path::join(os::getcwd(), "key.pem"));
- return path;
- }
-
- /**
- * @return The path to the authorized certificate.
- */
- static const Path& certificate_path()
- {
- static Path path(path::join(os::getcwd(), "cert.pem"));
- return path;
- }
-
- /**
- * @return The path to the unauthorized private key.
- */
- static const Path& scrap_key_path()
- {
- static Path path(path::join(os::getcwd(), "scrap_key.pem"));
- return path;
- }
-
- /**
- * @return The path to the unauthorized certificate.
- */
- static const Path& scrap_certificate_path()
- {
- static Path path(path::join(os::getcwd(), "scrap_cert.pem"));
- return path;
- }
-
- static void SetUpTestCase()
- {
- // We store the allocated objects in these results so that we can
- // have a consolidated 'cleanup()' function. This makes all the
- // 'EXIT()' calls more readable and less error prone.
- Result<EVP_PKEY*> private_key = None();
- Result<X509*> certificate = None();
- Result<EVP_PKEY*> scrap_key = None();
- Result<X509*> scrap_certificate = None();
-
- auto cleanup = [&private_key, &certificate, &scrap_key, &scrap_certificate](
- bool failure = true) {
- if (private_key.isSome()) { EVP_PKEY_free(private_key.get()); }
- if (certificate.isSome()) { X509_free(certificate.get()); }
- if (scrap_key.isSome()) { EVP_PKEY_free(scrap_key.get()); }
- if (scrap_certificate.isSome()) { X509_free(scrap_certificate.get()); }
-
- // If we are under a failure condition, clean up any files we
- // already generated. The expected behavior is that they will be
- // cleaned up in 'TearDownTestCase()'; however, we call ABORT
- // during 'SetUpTestCase()' failures.
- if (failure) {
- os::rm(key_path().value);
- os::rm(certificate_path().value);
- os::rm(scrap_key_path().value);
- os::rm(scrap_certificate_path().value);
- }
- };
-
- // Generate the authority key.
- private_key = openssl::generate_private_rsa_key();
- if (private_key.isError()) {
- ABORT("Could not generate private key: " + private_key.error());
- }
-
- // Figure out the hostname that 'INADDR_LOOPBACK' will bind to.
- // Set the hostname of the certificate to this hostname so that
- // hostname verification of the certificate will pass.
- Try<string> hostname = net::getHostname(net::IP(INADDR_LOOPBACK));
- if (hostname.isError()) {
- cleanup();
- ABORT("Could not determine hostname of 'INADDR_LOOPBACK': " +
- hostname.error());
- }
-
- // Generate an authorized certificate.
- certificate = openssl::generate_x509(
- private_key.get(),
- private_key.get(),
- None(),
- 1,
- 365,
- hostname.get());
-
- if (certificate.isError()) {
- cleanup();
- ABORT("Could not generate certificate: " + certificate.error());
- }
-
- // Write the authority key to disk.
- Try<Nothing> key_write =
- openssl::write_key_file(private_key.get(), key_path());
-
- if (key_write.isError()) {
- cleanup();
- ABORT("Could not write private key to disk: " + key_write.error());
- }
-
- // Write the authorized certificate to disk.
- Try<Nothing> certificate_write =
- openssl::write_certificate_file(certificate.get(), certificate_path());
-
- if (certificate_write.isError()) {
- cleanup();
- ABORT("Could not write certificate to disk: " +
- certificate_write.error());
- }
-
- // Generate a scrap key.
- scrap_key = openssl::generate_private_rsa_key();
- if (scrap_key.isError()) {
- cleanup();
- ABORT("Could not generate a scrap private key: " + scrap_key.error());
- }
-
- // Write the scrap key to disk.
- key_write = openssl::write_key_file(scrap_key.get(), scrap_key_path());
-
- if (key_write.isError()) {
- cleanup();
- ABORT("Could not write scrap key to disk: " + key_write.error());
- }
-
- // Generate a scrap certificate.
- scrap_certificate =
- openssl::generate_x509(scrap_key.get(), scrap_key.get());
-
- if (scrap_certificate.isError()) {
- cleanup();
- ABORT("Could not generate a scrap certificate: " +
- scrap_certificate.error());
- }
-
- // Write the scrap certificate to disk.
- certificate_write = openssl::write_certificate_file(
- scrap_certificate.get(),
- scrap_certificate_path());
-
- if (certificate_write.isError()) {
- cleanup();
- ABORT("Could not write scrap certificate to disk: " +
- certificate_write.error());
- }
-
- // Since we successfully set up all our state, we call cleanup
- // with failure set to 'false'.
- cleanup(false);
- }
-
- static void TearDownTestCase()
- {
- // Clean up all the pem files we generated.
- os::rm(key_path().value);
- os::rm(certificate_path().value);
- os::rm(scrap_key_path().value);
- os::rm(scrap_certificate_path().value);
- }
-
- virtual void SetUp()
- {
- // This unsets all the SSL environment variables. Necessary for
- // ensuring a clean starting slate between tests.
- os::unsetenv("SSL_ENABLED");
- os::unsetenv("SSL_SUPPORT_DOWNGRADE");
- os::unsetenv("SSL_CERT_FILE");
- os::unsetenv("SSL_KEY_FILE");
- os::unsetenv("SSL_VERIFY_CERT");
- os::unsetenv("SSL_REQUIRE_CERT");
- os::unsetenv("SSL_VERIFY_DEPTH");
- os::unsetenv("SSL_CA_DIR");
- os::unsetenv("SSL_CA_FILE");
- os::unsetenv("SSL_CIPHERS");
- os::unsetenv("SSL_ENABLE_SSL_V3");
- os::unsetenv("SSL_ENABLE_TLS_V1_0");
- os::unsetenv("SSL_ENABLE_TLS_V1_1");
- os::unsetenv("SSL_ENABLE_TLS_V1_2");
- }
-
- /**
- * Initializes a listening server.
- *
- * @param environment The SSL environment variables to launch the
- * server socket with.
- *
- * @return Socket if successful otherwise an Error.
- */
- Try<Socket> setup_server(const map<string, string>& environment)
- {
- foreachpair (const string& name, const string& value, environment) {
- os::setenv(name, value);
- }
- openssl::reinitialize();
-
- const Try<Socket> create = Socket::create(Socket::SSL);
- if (create.isError()) {
- return Error(create.error());
- }
-
- Socket server = create.get();
-
- // We need to explicitly bind to INADDR_LOOPBACK so the
- // certificate we create in this test fixture can be verified.
- Try<Address> bind = server.bind(Address(net::IP(INADDR_LOOPBACK), 0));
- if (bind.isError()) {
- return Error(bind.error());
- }
-
- const Try<Nothing> listen = server.listen(BACKLOG);
- if (listen.isError()) {
- return Error(listen.error());
- }
-
- return server;
- }
-
- /**
- * Launches a test SSL client as a subprocess connecting to the
- * server.
- *
- * The subprocess calls the 'ssl-client' binary with the provided
- * environment.
- *
- * @param environment The SSL environment variables to launch the
- * SSL client subprocess with.
- * @param use_ssl_socket Whether the SSL client will try to connect
- * using an SSL socket or a POLL socket.
- *
- * @return Subprocess if successful otherwise an Error.
- */
- Try<Subprocess> launch_client(
- const map<string, string>& environment,
- const Socket& server,
- bool use_ssl_socket)
- {
- const Try<Address> address = server.address();
- if (address.isError()) {
- return Error(address.error());
- }
-
- // Set up arguments to be passed to the 'client-ssl' binary.
- const vector<string> argv = {
- "ssl-client",
- "--use_ssl=" + stringify(use_ssl_socket),
- "--server=127.0.0.1",
- "--port=" + stringify(address.get().port),
- "--data=" + data};
-
- Result<string> path = os::realpath(BUILD_DIR);
- if (!path.isSome()) {
- return Error("Could not establish build directory path");
- }
-
- return subprocess(
- path::join(path.get(), "ssl-client"),
- argv,
- Subprocess::PIPE(),
- Subprocess::PIPE(),
- Subprocess::FD(STDERR_FILENO),
- None(),
- environment);
- }
-
- static constexpr size_t BACKLOG = 5;
-
- const string data;
-};
-
-
// Ensure that we can't create an SSL socket when SSL is not enabled.
TEST(SSL, Disabled)
{