// Ensure we can communicate between a POLL based socket and an SSL // socket if 'SSL_SUPPORT_DOWNGRADE' is enabled. TEST_F(SSLTest, ValidDowngrade) { Try<Socket> server = setup_server({ {"LIBPROCESS_SSL_ENABLED", "true"}, {"LIBPROCESS_SSL_SUPPORT_DOWNGRADE", "true"}, {"LIBPROCESS_SSL_KEY_FILE", key_path().string()}, {"LIBPROCESS_SSL_CERT_FILE", certificate_path().string()}, {"LIBPROCESS_SSL_REQUIRE_CERT", "true"}}); ASSERT_SOME(server); Try<Subprocess> client = launch_client({ {"LIBPROCESS_SSL_ENABLED", "false"}}, server.get(), false); ASSERT_SOME(client); Future<Socket> socket = server->accept(); AWAIT_ASSERT_READY(socket); // TODO(jmlvanre): Remove const copy. AWAIT_ASSERT_EQ(data, Socket(socket.get()).recv()); AWAIT_ASSERT_READY(Socket(socket.get()).send(data)); AWAIT_ASSERT_READY(await_subprocess(client.get(), 0)); }
TEST_F(SocketTest, Unix) { Try<unix::Socket> server = unix::Socket::create(); ASSERT_SOME(server); Try<unix::Socket> client = unix::Socket::create(); ASSERT_SOME(client); // Use a path in the temporary directory so it gets cleaned up. string path = path::join(sandbox.get(), "socket"); Try<unix::Address> address = unix::Address::create(path); ASSERT_SOME(address); ASSERT_SOME(server->bind(address.get())); ASSERT_SOME(server->listen(1)); Future<unix::Socket> accept = server->accept(); AWAIT_READY(client->connect(address.get())); AWAIT_READY(accept); unix::Socket socket = accept.get(); const string data = "Hello World!"; AWAIT_READY(client->send(data)); AWAIT_EQ(data, socket.recv(data.size())); AWAIT_READY(socket.send(data)); AWAIT_EQ(data, client->recv(data.size())); }
TEST_P(SSLTest, BasicSameProcessUnix) { os::setenv("LIBPROCESS_SSL_ENABLED", "true"); os::setenv("LIBPROCESS_SSL_KEY_FILE", key_path().string()); os::setenv("LIBPROCESS_SSL_CERT_FILE", certificate_path().string()); // NOTE: we must set LIBPROCESS_SSL_REQUIRE_CERT to false because we // don't have a hostname or IP to verify! os::setenv("LIBPROCESS_SSL_REQUIRE_CERT", "false"); os::setenv("LIBPROCESS_SSL_CA_DIR", os::getcwd()); os::setenv("LIBPROCESS_SSL_CA_FILE", certificate_path().string()); os::setenv("LIBPROCESS_SSL_VERIFY_IPADD", GetParam()); openssl::reinitialize(); Try<unix::Socket> server = unix::Socket::create(SocketImpl::Kind::SSL); ASSERT_SOME(server); Try<unix::Socket> client = unix::Socket::create(SocketImpl::Kind::SSL); ASSERT_SOME(client); // Use a path in the temporary directory so it gets cleaned up. string path = path::join(sandbox.get(), "socket"); Try<unix::Address> address = unix::Address::create(path); ASSERT_SOME(address); ASSERT_SOME(server->bind(address.get())); ASSERT_SOME(server->listen(BACKLOG)); Future<unix::Socket> accept = server->accept(); AWAIT_ASSERT_READY(client->connect(address.get())); // Wait for the server to have accepted the client connection. AWAIT_ASSERT_READY(accept); unix::Socket socket = accept.get(); // Send a message from the client to the server. const string data = "Hello World!"; AWAIT_ASSERT_READY(client->send(data)); // Verify the server received the message. AWAIT_ASSERT_EQ(data, socket.recv(data.size())); // Send the message back from the server to the client. AWAIT_ASSERT_READY(socket.send(data)); // Verify the client received the message. AWAIT_ASSERT_EQ(data, client->recv(data.size())); }
// Test a basic back-and-forth communication within the same OS // process. TEST_P(SSLTest, BasicSameProcess) { os::setenv("LIBPROCESS_SSL_ENABLED", "true"); os::setenv("LIBPROCESS_SSL_KEY_FILE", key_path().string()); os::setenv("LIBPROCESS_SSL_CERT_FILE", certificate_path().string()); os::setenv("LIBPROCESS_SSL_REQUIRE_CERT", "true"); os::setenv("LIBPROCESS_SSL_CA_DIR", os::getcwd()); os::setenv("LIBPROCESS_SSL_CA_FILE", certificate_path().string()); os::setenv("LIBPROCESS_SSL_VERIFY_IPADD", GetParam()); openssl::reinitialize(); Try<Socket> server = Socket::create(SocketImpl::Kind::SSL); ASSERT_SOME(server); Try<Socket> client = Socket::create(SocketImpl::Kind::SSL); ASSERT_SOME(client); // We need to explicitly bind to the loopback address so the // certificate we create in this test fixture can be verified. ASSERT_SOME(server->bind(Address::LOOPBACK_ANY())); ASSERT_SOME(server->listen(BACKLOG)); Try<Address> address = server->address(); ASSERT_SOME(address); Future<Socket> accept = server->accept(); AWAIT_ASSERT_READY(client->connect(address.get())); // Wait for the server to have accepted the client connection. AWAIT_ASSERT_READY(accept); Socket socket = accept.get(); // Send a message from the client to the server. const string data = "Hello World!"; AWAIT_ASSERT_READY(client->send(data)); // Verify the server received the message. AWAIT_ASSERT_EQ(data, socket.recv(data.size())); // Send the message back from the server to the client. AWAIT_ASSERT_READY(socket.send(data)); // Verify the client received the message. AWAIT_ASSERT_EQ(data, client->recv(data.size())); }
// This test verifies that if an EOF arrives on a socket when there is a // pending `recv()` call, the EOF will be correctly received. TEST_P(NetSocketTest, EOFAfterRecv) { Try<Socket> client = Socket::create(); ASSERT_SOME(client); const string data = "Lorem ipsum dolor sit amet"; Try<Socket> server = Socket::create(); ASSERT_SOME(server); Try<Address> server_address = server->bind(inet4::Address::ANY_ANY()); ASSERT_SOME(server_address); ASSERT_SOME(server->listen(1)); Future<Socket> server_accept = server->accept(); // Connect to the IP from the libprocess library, but use the port // from the `bind` call above. The libprocess IP will always report // a locally bindable IP, meaning it will also work for the server // socket above. // // NOTE: We do not use the server socket's address directly because // this contains a `0.0.0.0` IP. According to RFC1122, this is an // invalid address, except when used to resolve a host's address // for the first time. // See: https://tools.ietf.org/html/rfc1122#section-3.2.1.3 AWAIT_READY( client->connect(Address(process::address().ip, server_address->port))); AWAIT_READY(server_accept); Socket server_socket = server_accept.get(); AWAIT_READY(server_socket.send(data)); AWAIT_EXPECT_EQ(data, client->recv(data.size())); // Make the final `recv()` call before the socket is shutdown. Future<string> receive = client->recv(); server_socket.shutdown(Socket::Shutdown::READ_WRITE); AWAIT_EXPECT_EQ(string(), receive); }
// Ensure we CANNOT communicate between a POLL based socket and an // SSL socket if 'SSL_SUPPORT_DOWNGRADE' is not enabled. TEST_F(SSLTest, NoValidDowngrade) { Try<Socket> server = setup_server({ {"LIBPROCESS_SSL_ENABLED", "true"}, {"LIBPROCESS_SSL_SUPPORT_DOWNGRADE", "false"}, {"LIBPROCESS_SSL_KEY_FILE", key_path().string()}, {"LIBPROCESS_SSL_CERT_FILE", certificate_path().string()}, {"LIBPROCESS_SSL_REQUIRE_CERT", "true"}}); ASSERT_SOME(server); Try<Subprocess> client = launch_client({ {"LIBPROCESS_SSL_ENABLED", "false"}}, server.get(), false); ASSERT_SOME(client); Future<Socket> socket = server->accept(); AWAIT_ASSERT_FAILED(socket); AWAIT_ASSERT_READY(await_subprocess(client.get(), None())); }
// Ensure that key exchange using ECDHE algorithm works. TEST_F(SSLTest, ECDHESupport) { // Set up the default server environment variables. map<string, string> server_environment = { {"LIBPROCESS_SSL_ENABLED", "true"}, {"LIBPROCESS_SSL_KEY_FILE", key_path().string()}, {"LIBPROCESS_SSL_CERT_FILE", certificate_path().string()}, {"LIBPROCESS_SSL_CIPHERS", "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:" "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA"} }; // Set up the default client environment variables. map<string, string> client_environment = { {"LIBPROCESS_SSL_ENABLED", "true"}, {"LIBPROCESS_SSL_KEY_FILE", key_path().string()}, {"LIBPROCESS_SSL_CERT_FILE", certificate_path().string()}, {"LIBPROCESS_SSL_CIPHERS", "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:" "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA"} }; // Set up the server. Try<Socket> server = setup_server(server_environment); ASSERT_SOME(server); // Launch the client. Try<Subprocess> client = launch_client(client_environment, server.get(), true); ASSERT_SOME(client); Future<Socket> socket = server->accept(); AWAIT_ASSERT_READY(socket); // TODO(jmlvanre): Remove const copy. AWAIT_ASSERT_EQ(data, Socket(socket.get()).recv()); AWAIT_ASSERT_READY(Socket(socket.get()).send(data)); AWAIT_ASSERT_READY(await_subprocess(client.get(), 0)); }
// Ensure that a certificate that was not generated using the // certificate authority is NOT allowed to communicate when the // LIBPROCESS_SSL_VERIFY_CERT flag is enabled. TEST_F(SSLTest, VerifyBadCA) { Try<Socket> server = setup_server({ {"LIBPROCESS_SSL_ENABLED", "true"}, {"LIBPROCESS_SSL_KEY_FILE", key_path().string()}, {"LIBPROCESS_SSL_CERT_FILE", certificate_path().string()}, {"LIBPROCESS_SSL_VERIFY_CERT", "true"}}); ASSERT_SOME(server); Try<Subprocess> client = launch_client({ {"LIBPROCESS_SSL_ENABLED", "true"}, {"LIBPROCESS_SSL_KEY_FILE", scrap_key_path().string()}, {"LIBPROCESS_SSL_CERT_FILE", scrap_certificate_path().string()}, {"LIBPROCESS_SSL_REQUIRE_CERT", "false"}}, server.get(), true); ASSERT_SOME(client); Future<Socket> socket = server->accept(); AWAIT_ASSERT_FAILED(socket); AWAIT_ASSERT_READY(await_subprocess(client.get(), None())); }
protocol, stringify(protocol == server_protocol)); } // Set up the server. Try<Socket> server = setup_server(server_environment); ASSERT_SOME(server); // Launch the client with a POLL socket. Try<Subprocess> client = launch_client({ {"LIBPROCESS_SSL_ENABLED", "false"}}, server.get(), false); ASSERT_SOME(client); Future<Socket> socket = server->accept(); AWAIT_ASSERT_READY(socket); // TODO(jmlvanre): Remove const copy. AWAIT_ASSERT_EQ(data, Socket(socket.get()).recv()); AWAIT_ASSERT_READY(Socket(socket.get()).send(data)); AWAIT_ASSERT_READY(await_subprocess(client.get(), 0)); } } // For each protocol: ensure we CANNOT communicate between a POLL // based socket and an SSL socket if 'SSL_SUPPORT_DOWNGRADE' is not // enabled. TEST_F(SSLTest, NoValidDowngradeEachProtocol)