+struct Reference {
+ Reference() : ptr(NULL) {}
+ explicit Reference( P* ptr ) : ptr(ptr) {}
+ static Reference addRef( P* ptr ) { ptr->addref(); return Reference(ptr); }
+
+ Reference(const Reference& r) : ptr(r.getPtr()) { if (ptr) addref(ptr); }
+ Reference(Reference && r) : ptr(r.getPtr()) { r.ptr = NULL; }
+
+ template
+ Reference(const Reference& r) : ptr(r.getPtr()) { if (ptr) addref(ptr); }
+ template
+ Reference(Reference && r) : ptr(r.getPtr()) { r.setPtrUnsafe(NULL); }
+
+ ~Reference() { if (ptr) delref(ptr); }
+ Reference& operator=(const Reference& r) {
+ P* oldPtr = ptr;
+ P* newPtr = r.ptr;
+ if (oldPtr != newPtr) {
+ if (newPtr) addref(newPtr);
+ ptr = newPtr;
+ if (oldPtr) delref(oldPtr);
+ }
+ return *this;
+ }
+ Reference& operator=(Reference&& r) {
+ P* oldPtr = ptr;
+ P* newPtr = r.ptr;
+ if (oldPtr != newPtr) {
+ r.ptr = NULL;
+ ptr = newPtr;
+ if (oldPtr) delref(oldPtr);
+ }
+ return *this;
+ }
+
+ void clear() {
+ P* oldPtr = ptr;
+ if (oldPtr) {
+ ptr = NULL;
+ delref(oldPtr);
+ }
+ }
+
+ P* operator->() const { return ptr; }
+ P& operator*() const { return *ptr; }
+ P* getPtr() const { return ptr; }
+
+ void setPtrUnsafe( P* p ) { ptr = p; }
+
+ P* extractPtr() { auto *p = ptr; ptr = NULL; return p; }
+
+ bool boolean_test() const { return ptr != 0; }
+private:
+ P *ptr;
+};
+
+template
+bool operator==( const Reference& lhs, const Reference
& rhs ) {
+ return lhs.getPtr() == rhs.getPtr();
+}
+
+#endif /* FDB_REFERENCE_COUNTED_H */
diff --git a/FDBLibTLS/local.mk b/FDBLibTLS/local.mk
new file mode 100644
index 0000000000..0b6eac817c
--- /dev/null
+++ b/FDBLibTLS/local.mk
@@ -0,0 +1,11 @@
+FDBLibTLS_CFLAGS := -fPIC -I/usr/local/include -I$(BOOSTDIR)
+FDBLibTLS_STATIC_LIBS := -ltls -lssl -lcrypto
+FDBLibTLS_LDFLAGS := -L/usr/local/lib -static-libstdc++ -static-libgcc -lrt
+FDBLibTLS_LDFLAGS += -Wl,-soname,FDBLibTLS.so -Wl,--version-script=FDBLibTLS/FDBLibTLS.map
+
+# The plugin isn't a typical library, so it feels more sensible to have a copy
+# of it in bin/.
+bin/FDBLibTLS.$(DLEXT): lib/libFDBLibTLS.$(DLEXT)
+ @cp $< $@
+
+TARGETS += bin/FDBLibTLS.$(DLEXT)
diff --git a/FDBLibTLS/plugin-test.cpp b/FDBLibTLS/plugin-test.cpp
new file mode 100644
index 0000000000..6dfc79c8c9
--- /dev/null
+++ b/FDBLibTLS/plugin-test.cpp
@@ -0,0 +1,565 @@
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "ITLSPlugin.h"
+#include "ReferenceCounted.h"
+
+#include "FDBLibTLSPlugin.h"
+
+#define TESTDATA "./testdata/"
+
+static std::string load_file(std::string path)
+{
+ std::ifstream fs(path);
+ std::stringstream ss;
+
+ ss << fs.rdbuf();
+ fs.close();
+
+ return ss.str();
+}
+
+struct FDBLibTLSClientServerTest {
+ FDBLibTLSClientServerTest(bool client_success, bool server_success, std::string client_path, std::string server_path, std::string client_verify, std::string server_verify):
+ client_success(client_success), server_success(server_success), client_verify(client_verify), server_verify(server_verify) {
+ client_data = load_file(TESTDATA + client_path);
+ server_data = load_file(TESTDATA + server_path);
+ }
+ ~FDBLibTLSClientServerTest() {}
+
+ bool client_success;
+ bool server_success;
+
+ std::string client_data;
+ std::string client_verify;
+ std::string server_data;
+ std::string server_verify;
+};
+
+struct FDBLibTLSPluginTest {
+ FDBLibTLSPluginTest(Reference plugin, ITLSLogFunc logf);
+ ~FDBLibTLSPluginTest();
+
+ Reference plugin;
+ ITLSLogFunc logf;
+
+ boost::circular_buffer client_buffer;
+ boost::circular_buffer server_buffer;
+
+ int circular_read(boost::circular_buffer *cb, uint8_t* buf, int len);
+ int circular_write(boost::circular_buffer *cb, const uint8_t* buf, int len);
+ int client_read(uint8_t* buf, int len);
+ int client_write(const uint8_t* buf, int len);
+ int server_read(uint8_t* buf, int len);
+ int server_write(const uint8_t* buf, int len);
+
+ Reference create_policy(void);
+ Reference create_client_session(Reference policy);
+ Reference create_server_session(Reference policy);
+
+ void circular_reset(void);
+ void circular_self_test(void);
+
+ int client_server_test(FDBLibTLSClientServerTest const& cst);
+ int set_cert_data_test(void);
+};
+
+FDBLibTLSPluginTest::FDBLibTLSPluginTest(Reference plugin, ITLSLogFunc logf) :
+ plugin(plugin), logf(logf)
+{
+ circular_reset();
+ circular_self_test();
+}
+
+FDBLibTLSPluginTest::~FDBLibTLSPluginTest()
+{
+}
+
+int FDBLibTLSPluginTest::circular_read(boost::circular_buffer *cb, uint8_t* buf, int len)
+{
+ int n = 0;
+
+ for (n = 0; n < len; n++) {
+ if (cb->empty())
+ break;
+ buf[n] = (*cb)[0];
+ cb->pop_front();
+ }
+
+ return n;
+}
+
+int FDBLibTLSPluginTest::circular_write(boost::circular_buffer *cb, const uint8_t* buf, int len)
+{
+ int n = 0;
+
+ for (n = 0; n < len; n++) {
+ if (cb->full())
+ break;
+ cb->push_back(buf[n]);
+ }
+
+ return n;
+}
+
+int FDBLibTLSPluginTest::client_read(uint8_t* buf, int len)
+{
+ // Read bytes from the server from the client's buffer.
+ return circular_read(&client_buffer, buf, len);
+}
+
+int FDBLibTLSPluginTest::client_write(const uint8_t* buf, int len)
+{
+ // Write bytes from the client into the server's buffer.
+ return circular_write(&server_buffer, buf, len);
+}
+
+int FDBLibTLSPluginTest::server_read(uint8_t* buf, int len)
+{
+ // Read bytes from the client from the server's buffer.
+ return circular_read(&server_buffer, buf, len);
+}
+
+int FDBLibTLSPluginTest::server_write(const uint8_t* buf, int len)
+{
+ // Write bytes from the server into the client's buffer.
+ return circular_write(&client_buffer, buf, len);
+}
+
+void FDBLibTLSPluginTest::circular_reset()
+{
+ client_buffer = boost::circular_buffer(1024);
+ server_buffer = boost::circular_buffer(1024);
+}
+
+void FDBLibTLSPluginTest::circular_self_test()
+{
+ uint8_t buf[1024] = {1, 2, 3};
+
+ std::cerr << "INFO: running circular buffer self tests...\n";
+
+ assert(server_read(buf, 3) == 0);
+
+ buf[0] = 1, buf[1] = 2, buf[2] = 3;
+ assert(client_write(buf, 2) == 2);
+
+ buf[0] = buf[1] = buf[2] = 255;
+ assert(server_read(buf, 3) == 2);
+ assert(buf[0] == 1 && buf[1] == 2 && buf[2] == 255);
+
+ assert(client_write(buf, 1024) == 1024);
+ assert(client_write(buf, 1) == 0);
+ assert(server_read(buf, 1) == 1);
+ assert(client_write(buf, 1) == 1);
+ assert(client_write(buf, 1) == 0);
+ assert(server_read(buf, 1024) == 1024);
+ assert(server_read(buf, 1024) == 0);
+
+ assert(client_read(buf, 3) == 0);
+
+ buf[0] = 1, buf[1] = 2, buf[2] = 3;
+ assert(server_write(buf, 2) == 2);
+
+ buf[0] = buf[1] = buf[2] = 255;
+ assert(client_read(buf, 3) == 2);
+ assert(buf[0] == 1 && buf[1] == 2 && buf[2] == 255);
+
+ assert(server_write(buf, 1024) == 1024);
+ assert(server_write(buf, 1) == 0);
+ assert(client_read(buf, 1) == 1);
+ assert(server_write(buf, 1) == 1);
+ assert(server_write(buf, 1) == 0);
+ assert(client_read(buf, 1024) == 1024);
+ assert(client_read(buf, 1024) == 0);
+}
+
+Reference FDBLibTLSPluginTest::create_policy(void)
+{
+ return Reference(plugin->create_policy((ITLSLogFunc)logf));
+}
+
+static int client_send_func(void* ctx, const uint8_t* buf, int len) {
+ FDBLibTLSPluginTest *pt = (FDBLibTLSPluginTest *)ctx;
+ try {
+ return pt->client_write(buf, len);
+ } catch ( const std::runtime_error& e ) {
+ return -1;
+ }
+}
+
+static int client_recv_func(void* ctx, uint8_t* buf, int len) {
+ FDBLibTLSPluginTest *pt = (FDBLibTLSPluginTest *)ctx;
+ try {
+ return pt->client_read(buf, len);
+ } catch ( const std::runtime_error& e ) {
+ return -1;
+ }
+}
+
+Reference FDBLibTLSPluginTest::create_client_session(Reference policy)
+{
+ return Reference(policy->create_session(true, client_send_func, this, client_recv_func, this, NULL));
+}
+
+static int server_send_func(void* ctx, const uint8_t* buf, int len) {
+ FDBLibTLSPluginTest *pt = (FDBLibTLSPluginTest *)ctx;
+ try {
+ return pt->server_write(buf, len);
+ } catch ( const std::runtime_error& e ) {
+ return -1;
+ }
+}
+
+static int server_recv_func(void* ctx, uint8_t* buf, int len) {
+ FDBLibTLSPluginTest *pt = (FDBLibTLSPluginTest *)ctx;
+ try {
+ return pt->server_read(buf, len);
+ } catch ( const std::runtime_error& e ) {
+ return -1;
+ }
+}
+
+Reference FDBLibTLSPluginTest::create_server_session(Reference policy)
+{
+ return Reference(policy->create_session(false, server_send_func, this, server_recv_func, this, NULL));
+}
+
+int FDBLibTLSPluginTest::client_server_test(FDBLibTLSClientServerTest const& cst)
+{
+ circular_reset();
+
+ Reference client_policy = create_policy();
+ if (!client_policy->set_cert_data((const uint8_t*)&cst.client_data[0], cst.client_data.size())) {
+ std::cerr << "FAIL: failed to set client cert data\n";
+ return 1;
+ }
+ if (!client_policy->set_key_data((const uint8_t*)&cst.client_data[0], cst.client_data.size())) {
+ std::cerr << "FAIL: failed to set client key data\n";
+ return 1;
+ }
+ if (!client_policy->set_verify_peers((const uint8_t*)&cst.client_verify[0], cst.client_verify.size())) {
+ std::cerr << "FAIL: failed to set client key data\n";
+ return 1;
+ }
+
+ Reference server_policy = create_policy();
+ if (!server_policy->set_cert_data((const uint8_t*)&cst.server_data[0], cst.server_data.size())) {
+ std::cerr << "FAIL: failed to set server cert data\n";
+ return 1;
+ }
+ if (!server_policy->set_key_data((const uint8_t*)&cst.server_data[0], cst.server_data.size())) {
+ std::cerr << "FAIL: failed to set server key data\n";
+ return 1;
+ }
+ if (!server_policy->set_verify_peers((const uint8_t*)&cst.server_verify[0], cst.server_verify.size())) {
+ std::cerr << "FAIL: failed to set client key data\n";
+ return 1;
+ }
+
+ Reference client_session = create_client_session(client_policy);
+ Reference server_session = create_server_session(server_policy);
+
+ if (client_session.getPtr() == NULL || server_session.getPtr() == NULL)
+ return 1;
+
+ std::cerr << "INFO: starting TLS handshake...\n";
+
+ bool client_done = false, server_done = false;
+ bool client_failed = false, server_failed = false;
+ int rc, i = 0;
+ do {
+ if (!client_done) {
+ rc = client_session->handshake();
+ if (rc == ITLSSession::SUCCESS) {
+ client_done = true;
+ } else if (rc == ITLSSession::FAILED) {
+ if (cst.client_success) {
+ std::cerr << "FAIL: failed to complete client handshake\n";
+ return 1;
+ } else {
+ std::cerr << "INFO: failed to complete client handshake (as expected)\n";
+ client_failed = true;
+ client_done = true;
+ }
+ } else if (rc != ITLSSession::WANT_READ && rc != ITLSSession::WANT_WRITE) {
+ std::cerr << "FAIL: client handshake returned unknown value: " << rc << "\n";
+ return 1;
+ }
+ }
+ if (!server_done) {
+ rc = server_session->handshake();
+ if (rc == ITLSSession::SUCCESS) {
+ server_done = true;
+ } else if (rc == ITLSSession::FAILED) {
+ if (cst.server_success) {
+ std::cerr << "FAIL: failed to complete server handshake\n";
+ return 1;
+ } else {
+ std::cerr << "INFO: failed to complete server handshake (as expected)\n";
+ server_failed = true;
+ server_done = true;
+ }
+ } else if (rc != ITLSSession::WANT_READ && rc != ITLSSession::WANT_WRITE) {
+ std::cerr << "FAIL: server handshake returned unknown value: " << rc << "\n";
+ return 1;
+ }
+ }
+ } while (i++ < 100 && (!client_done || !server_done));
+
+ if (!client_done || !server_done) {
+ std::cerr << "FAIL: failed to complete handshake\n";
+ return 1;
+ }
+
+ if (!cst.client_success && !client_failed)
+ std::cerr << "FAIL: client handshake succeeded when it should have failed\n";
+ if (!cst.server_success && !server_failed)
+ std::cerr << "FAIL: server handshake succeeded when it should have failed\n";
+ if (!cst.client_success || !cst.server_success)
+ return 0;
+
+ std::cerr << "INFO: handshake completed successfully\n";
+
+ //
+ // Write on client and read on server.
+ //
+ std::cerr << "INFO: starting client write test...\n";
+
+ std::string client_msg("FDBLibTLSPlugin Client Write Test");
+ std::string server_msg;
+ size_t cn = 0, sn = 0;
+ uint8_t buf[16];
+
+ client_done = false, server_done = false;
+ i = 0;
+ do {
+ if (!client_done) {
+ rc = client_session->write((const uint8_t*)&client_msg[cn], client_msg.size()-cn);
+ if (rc > 0) {
+ cn += rc;
+ if (cn >= client_msg.size())
+ client_done = true;
+ } else if (rc == ITLSSession::FAILED) {
+ std::cerr << "FAIL: failed to complete client write\n";
+ return 1;
+ } else if (rc != ITLSSession::WANT_READ && rc != ITLSSession::WANT_WRITE) {
+ std::cerr << "FAIL: client write returned unknown value: " << rc << "\n";
+ return 1;
+ }
+ }
+ if (!server_done) {
+ rc = server_session->read(buf, sizeof(buf));
+ if (rc > 0) {
+ sn += rc;
+ for (int j = 0; j < rc; j++)
+ server_msg += buf[j];
+ if (sn >= client_msg.size())
+ server_done = true;
+ } else if (rc == ITLSSession::FAILED) {
+ std::cerr << "FAIL: failed to complete server read\n";
+ return 1;
+ } else if (rc != ITLSSession::WANT_READ && rc != ITLSSession::WANT_WRITE) {
+ std::cerr << "FAIL: server read returned unknown value: " << rc << "\n";
+ return 1;
+ }
+ }
+ } while (i++ < 100 && (!client_done || !server_done));
+
+ if (client_msg != server_msg) {
+ std::cerr << "FAIL: got client msg '" << server_msg << "' want '" << client_msg << "'\n";
+ return 1;
+ }
+
+ std::cerr << "INFO: client write test completed successfully\n";
+
+ //
+ // Write on server and read on client.
+ //
+ std::cerr << "INFO: starting server write test...\n";
+
+ server_msg = "FDBLibTLSPlugin Server Write Test";
+ client_msg.clear();
+ cn = 0, sn = 0;
+
+ client_done = false, server_done = false;
+ i = 0;
+ do {
+ if (!server_done) {
+ rc = server_session->write((const uint8_t*)&server_msg[cn], server_msg.size()-cn);
+ if (rc > 0) {
+ cn += rc;
+ if (cn >= server_msg.size())
+ server_done = true;
+ } else if (rc == ITLSSession::FAILED) {
+ std::cerr << "FAIL: failed to complete server write\n";
+ return 1;
+ } else if (rc != ITLSSession::WANT_READ && rc != ITLSSession::WANT_WRITE) {
+ std::cerr << "FAIL: server write returned unknown value: " << rc << "\n";
+ return 1;
+ }
+ }
+ if (!client_done) {
+ rc = client_session->read(buf, sizeof(buf));
+ if (rc > 0) {
+ sn += rc;
+ for (int j = 0; j < rc; j++)
+ client_msg += buf[j];
+ if (sn >= server_msg.size())
+ client_done = true;
+ } else if (rc == ITLSSession::FAILED) {
+ std::cerr << "FAIL: failed to complete client read\n";
+ return 1;
+ } else if (rc != ITLSSession::WANT_READ && rc != ITLSSession::WANT_WRITE) {
+ std::cerr << "FAIL: client read returned unknown value: " << rc << "\n";
+ return 1;
+ }
+ }
+ } while (i++ < 100 && (!client_done || !server_done));
+
+ if (server_msg != client_msg) {
+ std::cerr << "FAIL: got server msg '" << client_msg << "' want '" << server_msg << "'\n";
+ return 1;
+ }
+
+ std::cerr << "INFO: server write test completed successfully\n";
+
+ return 0;
+}
+
+static void logf(const char* event, void* uid, int is_error, ...) {
+ va_list args;
+
+ std::string log_type ("INFO");
+ if (is_error)
+ log_type = "ERROR";
+
+ std::cerr << log_type << ": " << event;
+
+ va_start(args, is_error);
+
+ const char *s = va_arg(args, const char *);
+ while (s != NULL) {
+ std::cerr << " " << s;
+ s = va_arg(args, const char *);
+ }
+
+ std::cerr << "\n";
+
+ va_end(args);
+}
+
+int main(int argc, char **argv)
+{
+ void *pluginSO = NULL;
+ void *(*getPlugin)(const char*);
+ int failed = 0;
+
+ if (argc != 2) {
+ std::cerr << "usage: " << argv[0] << " \n";
+ exit(1);
+ }
+
+ pluginSO = dlopen(argv[1], RTLD_LAZY | RTLD_LOCAL);
+ if (pluginSO == NULL) {
+ std::cerr << "failed to load plugin '" << argv[1] << "': " << dlerror() << "\n";
+ exit(1);
+ }
+
+ getPlugin = (void*(*)(const char*))dlsym( pluginSO, "get_plugin" );
+ if (getPlugin == NULL) {
+ std::cerr << "plugin '" << argv[1] << "' does not provide get_plugin()\n";
+ exit(1);
+ }
+
+ Reference plugin = Reference((ITLSPlugin *)getPlugin(ITLSPlugin::get_plugin_type_name_and_version()));
+
+ std::vector tests = {
+ // Valid - all use single root CA.
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-1-server.pem", "", ""),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-2-server.pem", "", ""),
+ FDBLibTLSClientServerTest(true, true, "test-2-client.pem", "test-2-server.pem", "", ""),
+ FDBLibTLSClientServerTest(true, true, "test-2-client.pem", "test-1-server.pem", "", ""),
+
+ // Certificates terminate at different intermediate CAs.
+ FDBLibTLSClientServerTest(false, false, "test-4-client.pem", "test-5-server.pem", "", ""),
+ FDBLibTLSClientServerTest(false, false, "test-5-client.pem", "test-4-server.pem", "", ""),
+ FDBLibTLSClientServerTest(true, true, "test-4-client.pem", "test-5-server.pem",
+ "Check.Valid=0", "Check.Valid=0"),
+ FDBLibTLSClientServerTest(true, true, "test-5-client.pem", "test-4-server.pem",
+ "Check.Valid=0", "Check.Valid=0"),
+
+ // Expired certificates.
+ FDBLibTLSClientServerTest(false, false, "test-1-client.pem", "test-3-server.pem", "", ""),
+ FDBLibTLSClientServerTest(false, false, "test-3-client.pem", "test-1-server.pem", "", ""),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-3-server.pem", "Check.Unexpired=0", ""),
+ FDBLibTLSClientServerTest(true, true, "test-3-client.pem", "test-1-server.pem", "", "Check.Unexpired=0"),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-3-server.pem", "Check.Valid=0", ""),
+ FDBLibTLSClientServerTest(true, true, "test-3-client.pem", "test-1-server.pem", "", "Check.Valid=0"),
+
+ // Match on specific subject and/or issuer.
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-1-server.pem", "C=US", ""),
+ FDBLibTLSClientServerTest(false, true, "test-1-client.pem", "test-2-server.pem", "C=US", ""),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-2-server.pem", "C=AU", ""),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\80 \\<\\01\\+\\02=\\03\\>", ""),
+ FDBLibTLSClientServerTest(false, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\80 \\<\\01\\+\\02=\\04\\>", ""),
+ FDBLibTLSClientServerTest(false, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\81 \\<\\01\\+\\02=\\04\\>", ""),
+ FDBLibTLSClientServerTest(false, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\80 \\<\\01\\+\\02=\\04", ""),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\80 \\<\\01\\+\\02=\\03\\>",
+ "CN=FDB LibTLS Plugin Test Client 1"),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-1-server.pem",
+ "", "CN=FDB LibTLS Plugin Test Client 1"),
+ FDBLibTLSClientServerTest(true, false, "test-2-client.pem", "test-1-server.pem",
+ "", "O=Apple Pty Limited,OU=FDC Team"),
+ FDBLibTLSClientServerTest(true, true, "test-2-client.pem", "test-1-server.pem",
+ "O=Apple Inc.,OU=FDB Team", "O=Apple Pty Limited,OU=FDB Team"),
+ FDBLibTLSClientServerTest(false, false, "test-2-client.pem", "test-1-server.pem",
+ "O=Apple Inc.,OU=FDC Team", "O=Apple Pty Limited,OU=FDC Team"),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-1-server.pem",
+ "I.C=US,I.ST=California,I.L=Cupertino,I.O=Apple Inc.,I.OU=FDB Team",
+ "I.C=US,I.ST=California,I.L=Cupertino,I.O=Apple Inc.,I.OU=FDB Team"),
+ FDBLibTLSClientServerTest(false, false, "test-1-client.pem", "test-1-server.pem",
+ "I.C=US,I.ST=California,I.L=Cupertino,I.O=Apple Inc.,I.OU=FDC Team",
+ "I.C=US,I.ST=California,I.L=Cupertino,I.O=Apple Inc.,I.OU=FDC Team"),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-1-server.pem",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 1",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 1"),
+ FDBLibTLSClientServerTest(false, true, "test-1-client.pem", "test-1-server.pem",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 2",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 1"),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-2-server.pem",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 2",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 1"),
+ FDBLibTLSClientServerTest(true, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\80 \\<\\01\\+\\02=\\03\\>,I.CN=FDB LibTLS Plugin Test Intermediate CA 2",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 1,O=Apple Inc.,I.C=US,S.C=US"),
+ FDBLibTLSClientServerTest(false, true, "test-1-client.pem", "test-2-server.pem",
+ "CN=FDB LibTLS Plugin Test Server 2\\, \\80 \\<\\01\\+\\02=\\03\\>,I.CN=FDB LibTLS Plugin Test Intermediate CA 1",
+ "I.CN=FDB LibTLS Plugin Test Intermediate CA 1,O=Apple Inc.,I.C=US,S.C=US"),
+ };
+
+ FDBLibTLSPluginTest *pt = new FDBLibTLSPluginTest(plugin, (ITLSLogFunc)logf);
+
+ int test_num = 1;
+ for (auto &test: tests) {
+ std::cerr << "== Test " << test_num++ << " ==\n";
+ failed |= pt->client_server_test(test);
+ }
+
+ delete pt;
+
+ return (failed);
+}
diff --git a/FDBLibTLS/scripts/make-test-certs.sh b/FDBLibTLS/scripts/make-test-certs.sh
new file mode 100755
index 0000000000..2f603a5608
--- /dev/null
+++ b/FDBLibTLS/scripts/make-test-certs.sh
@@ -0,0 +1,159 @@
+#!/bin/sh
+
+set -e
+set -u
+
+readonly SUBJECT="/C=US/ST=California/L=Cupertino/O=Apple Inc./OU=FDB Team/CN=FDB LibTLS Plugin Test"
+readonly SUBJECT_ALT="/C=AU/ST=New South Wales/L=Sydney/O=Apple Pty Limited/OU=FDB Team/CN=FDB LibTLS Plugin Test"
+
+readonly TMPDIR=$(mktemp -d)
+
+cleanup() {
+ rm -rf "${TMPDIR}"
+}
+
+trap cleanup EXIT INT
+
+make_bundle() {
+ local bundle_file=$1;
+ local key_file=$2;
+ shift 2;
+
+ printf '' > "${bundle_file}"
+ for f in $@; do
+ openssl x509 -nameopt oneline -subject -issuer -noout -in "${TMPDIR}/${f}" >> "${bundle_file}"
+ done
+ for f in $@; do
+ cat "${TMPDIR}/${f}" >> "${bundle_file}"
+ done
+ cat "${TMPDIR}/${key_file}" >> "${bundle_file}"
+}
+
+echo '100001' > "${TMPDIR}/certserial"
+
+cat > "${TMPDIR}/openssl.cnf" <")" -keyout "${TMPDIR}/server-2.key" \
+ -out "${TMPDIR}/server-2.csr"
+openssl x509 -req -days 3650 -CA "${TMPDIR}/ca-int-2.crt" -CAkey "${TMPDIR}/ca-int-2.key" \
+ -extfile "${TMPDIR}/openssl.cnf" -extensions fdb_v3_other \
+ -CAcreateserial -in "${TMPDIR}/server-2.csr" -out "${TMPDIR}/server-2.crt"
+
+# Server 3 (expired).
+openssl req -new -days 1 -nodes -newkey rsa:2048 -sha256 \
+ -subj "${SUBJECT} Server 3" -keyout "${TMPDIR}/server-3.key" \
+ -out "${TMPDIR}/server-3.csr"
+cp /dev/null "${TMPDIR}/certindex"
+printf "y\ny\n" | openssl ca -cert "${TMPDIR}/ca-int-1.crt" -keyfile "${TMPDIR}/ca-int-1.key" \
+ -startdate 20170101000000Z -enddate 20171231000000Z \
+ -config "${TMPDIR}/openssl.cnf" -notext \
+ -in "${TMPDIR}/server-3.csr" -out "${TMPDIR}/server-3.crt"
+
+# Client 1.
+openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
+ -subj "${SUBJECT} Client 1" -keyout "${TMPDIR}/client-1.key" \
+ -out "${TMPDIR}/client-1.csr"
+openssl x509 -req -days 3650 -CA "${TMPDIR}/ca-int-1.crt" -CAkey "${TMPDIR}/ca-int-1.key" \
+ -extfile "${TMPDIR}/openssl.cnf" -extensions fdb_v3_other \
+ -CAcreateserial -in "${TMPDIR}/client-1.csr" -out "${TMPDIR}/client-1.crt"
+
+# Client 2.
+openssl req -new -days 3650 -nodes -newkey rsa:2048 -sha256 \
+ -subj "$(printf "${SUBJECT_ALT} Client 2, \200 <\001+\002=\003>")" -keyout "${TMPDIR}/client-2.key" \
+ -out "${TMPDIR}/client-2.csr"
+openssl x509 -req -days 3650 -CA "${TMPDIR}/ca-int-2.crt" -CAkey "${TMPDIR}/ca-int-2.key" \
+ -extfile "${TMPDIR}/openssl.cnf" -extensions fdb_v3_other \
+ -CAcreateserial -in "${TMPDIR}/client-2.csr" -out "${TMPDIR}/client-2.crt"
+
+# Client 3 (expired).
+openssl req -new -days 1 -nodes -newkey rsa:2048 -sha256 \
+ -subj "${SUBJECT} Client 3" -keyout "${TMPDIR}/client-3.key" \
+ -out "${TMPDIR}/client-3.csr"
+cp /dev/null "${TMPDIR}/certindex"
+printf "y\ny\n" | openssl ca -cert "${TMPDIR}/ca-int-1.crt" -keyfile "${TMPDIR}/ca-int-1.key" \
+ -startdate 20170101000000Z -enddate 20171231000000Z \
+ -config "${TMPDIR}/openssl.cnf" \
+ -in "${TMPDIR}/client-3.csr" -out "${TMPDIR}/client-3.crt"
+
+#
+# Test Bundles
+#
+
+make_bundle 'test-1-server.pem' 'server-1.key' 'server-1.crt' 'ca-int-1.crt' 'ca-root.crt'
+make_bundle 'test-1-client.pem' 'client-1.key' 'client-1.crt' 'ca-int-1.crt' 'ca-root.crt'
+make_bundle 'test-2-server.pem' 'server-2.key' 'server-2.crt' 'ca-int-2.crt' 'ca-root.crt'
+make_bundle 'test-2-client.pem' 'client-2.key' 'client-2.crt' 'ca-int-2.crt' 'ca-root.crt'
+
+# Expired client/server.
+make_bundle 'test-3-client.pem' 'client-3.key' 'client-3.crt' 'ca-int-1.crt' 'ca-root.crt'
+make_bundle 'test-3-server.pem' 'server-3.key' 'server-3.crt' 'ca-int-1.crt' 'ca-root.crt'
+
+# Bundles that terminate at intermediate 1.
+make_bundle 'test-4-server.pem' 'server-1.key' 'server-1.crt' 'ca-int-1.crt'
+make_bundle 'test-4-client.pem' 'client-1.key' 'client-1.crt' 'ca-int-1.crt'
+
+# Bundles that terminate at intermediate 2.
+make_bundle 'test-5-server.pem' 'server-2.key' 'server-2.crt' 'ca-int-2.crt'
+make_bundle 'test-5-client.pem' 'client-2.key' 'client-2.crt' 'ca-int-2.crt'
diff --git a/FDBLibTLS/testdata/test-1-client.pem b/FDBLibTLS/testdata/test-1-client.pem
new file mode 100644
index 0000000000..085f7e35ea
--- /dev/null
+++ b/FDBLibTLS/testdata/test-1-client.pem
@@ -0,0 +1,106 @@
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Client 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIJALOPTrQGpeslMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMTAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGIMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5vMRMwEQYDVQQKDApB
+cHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEoMCYGA1UEAwwfRkRCIExpYlRM
+UyBQbHVnaW4gVGVzdCBDbGllbnQgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALVkdxOmWcd959NyirJ1iz7q5fkjdRUV+88KMMehQWc3f50GJIQ+eZo+
+7RhwVE+n8nd0i5iGfyY6LRuupdwoQUxoZ/5rUIDGKspNO62DVRW+tZqzpEa1+ub5
+75BMoc7I7l9sXDkuiMu1OYcPNKMv4F3mf+B3ourLqjUekKlUv8XIZXAvN+R19HlR
+FM8vs8rnhQXx7iWVP91frDvyD8G7lOf6R7R4homnB37kLom8WU+fCmcyA6em0qX0
+JeVP6xk2qXU1cMs7DL8WftdrWHv+a73/l4hytQHo5OvtGaLZhpPYpC/FMSaFHVSM
+irWSFK+ZtvaLi3LXc2HGANMokjPoRf8CAwEAAaNgMF4wHQYDVR0OBBYEFPtTL9KZ
+jn49cLediy1ixz7AXOI3MB8GA1UdIwQYMBaAFCXTF7f83Hd7xm9gR+O4QrvjNo8Q
+MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBBQUAA4IB
+AQA17a4d/tSWIlTkIfkrXziD21+1OsN6/dUrWQK7kxtEe21QXIutccW4bwpM0JDB
+M+bZiWkdgQ15+ZotX5UXlBcx9WWDU5RqSO06hhXu5b8gZwfVF4Od6tBdVxkn4KbU
+0YujOZrL8fDOrQHqCO7nhNlYgcEn7bKF5wjtOoiKhtA9sLSIZQR5g32kkJXXGvcY
+lLWMXygEg9FMQoldW9RHq4GbUiYEeqEq6k4S7cE03R1lvmQEOOAJ2S7LnaS4UHQT
+GmW6uvLnJJrG4HB9JGE+y1e9M+C7Enzhi39RGd8ylignGimkdw/1UEWnvKGCqoU7
+ufWGF7eUV8dCqO+jYghIY8rA
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpeshMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyOwdOcYcH3wYou13CchsXh3lLWA85E550tT6/WwDnslQjiMZHFrKvUT2
+B8CUOR3Fr+4RG+cdw80rgojYEUuHKwmIGyjo5IotdaYbWzf6mvYThlIPPudCCkSU
+CTtqPv8Oq4QdIpCxHdix0MINKu7c+qt1rUwnDFQSv/gHhVnNxT4r8pwVp6T4hwka
+2YQaRNjzUuuFinMub0UtxnUX0rH8X5STlOSVn4Ksjo0OhQzsGEYDx86jVAXjgGcb
+2CgGGctgq04hVrngP5ahT1Xeh9YycMlQJXsckJJBxfUJebIjANSRyzxI5fYt+ZkY
+qoG5VLPREUQknxcpbT7Rsj0n+k0RhwIDAQABo2MwYTAdBgNVHQ4EFgQUJdMXt/zc
+d3vGb2BH47hCu+M2jxAwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAGwW7bRqB7aYUGsD1MOE9d5slp6Iw6wKyNLdg+mzoV+iCV2ZM7ejNRButiAy
+vPOxSQwXcibLm/g599e+LY1TiI1XXPbL2bFnTcnThqpHHFe+eRrDgqxO8qJyrcBp
+EfyMCJWq7jFg4bWoYTpLeC/RAKyi9fxlqY1NzQCp1bG3LiaDJ5VJd4uwkgX2a0yN
+3e0XEFNi7r4u4IHejwFjKWrDg8sstjbY+XOYC4EVQyUsbzeKZKSqnOdR2Jv1QZHH
+5O24G/efIFpsA6MVUOfRk0eq0RfKX7CdHn2a5p8aC6E6YMDhXL6xo146n49t9sYD
+HMUnfG6AEboTBa/l+zwCG/u4f/Y=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIJALfRa36cuemYMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMScwJQYDVQQDDB5GREIgTGliVExTIFBsdWdpbiBU
+ZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/J+sL
+7POoXNdzYRsMZCI5juxMPOVue5vU2QPU9z/PHBsBICX6tVsCnkzk5CLdM6TxofgX
+F+MqRKxtcIqxBcKjjVecJlqHuNY+jS2r8UjcoQm+EQ5RsBWu8yaSnXIiZTccQNjB
+5T2awwt9Ptbn946MZfq6oEnn4ZPByu9/nCrlk7QXTkuGdpTnC6paQWt/lVxZfELM
+i0g76/K/f3e2Lv9UCvlxKOwFMye9XjwF3ekEmUuio5JZEdn+LIs9zB1zehFhGlYB
+TUXnkZ0LTOPbH9OxsOli04n31/n7UbYq1BSuoiXx5A2eHOunMppa0NDg7oXmDSKE
+A1zo+QtIu1YPXaLdAgMBAAGjYzBhMB0GA1UdDgQWBBSeq0aNrc7mMaWHm8eCndN/
+w0I8qTAfBgNVHSMEGDAWgBSeq0aNrc7mMaWHm8eCndN/w0I8qTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAIOw1jC39
+VW+1fqGT+n44Y6Oh66lAowIvi/BEOW1I4iPAjkr0g6FbbdKeq0VLL7aMMu+q/AOv
+UETv7MdVh9xjTLqWZGN0R3Lr/n6ButI3E7MLKL5ByLNCoOhF42aBLINkpKSNFRrQ
+40iNoHm3BaNRLKS7poCk5HFkEMjvxdQ1AenNbUa21DTh7y9arHF4CPfi8Ity29jW
+ED8jYK/+bWIaO+YhGkRh8UuD3o5WnOti+9QK56qxkPtkqVTh9vMVHfD0DgVeLvMN
+nZpTplLTfhjzyFJELwE/U+HJ6KIslmqwarJ1Sla+1gHCmJEbzbsrnb6bLtrHtXCZ
+XvmR6B5iRkDVpw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1ZHcTplnHfefT
+coqydYs+6uX5I3UVFfvPCjDHoUFnN3+dBiSEPnmaPu0YcFRPp/J3dIuYhn8mOi0b
+rqXcKEFMaGf+a1CAxirKTTutg1UVvrWas6RGtfrm+e+QTKHOyO5fbFw5LojLtTmH
+DzSjL+Bd5n/gd6Lqy6o1HpCpVL/FyGVwLzfkdfR5URTPL7PK54UF8e4llT/dX6w7
+8g/Bu5Tn+ke0eIaJpwd+5C6JvFlPnwpnMgOnptKl9CXlT+sZNql1NXDLOwy/Fn7X
+a1h7/mu9/5eIcrUB6OTr7Rmi2YaT2KQvxTEmhR1UjIq1khSvmbb2i4ty13NhxgDT
+KJIz6EX/AgMBAAECggEAEm2Mc2CZCl1OKfsfABZU+SVgC7mAcY30MQp1/jHxtQy8
+WDWBjDXUoMj3yV3QEu+bAGvEqtAvJrEOWBucGgu05pBM0FoSqaJ4QmkqQOxwvm7L
+gFXzwINIZCLMJbrDTYC4RtV5YQ3LM/bLS19OF64Lez6piyJcWMIsHo1mYO2NNgiD
+7f1x1uQw46Q0YHWeoHY58MPfmgfKsqnJDWc8cCuU9fJOWeU4dVrfW8dh9WVAoLZ7
+qAM5vvap11Qk8RXaRnmLjxN6H1M7iVNfcLVNKfG6XOBBepYjZr/qMkuN3ONuqBHl
+fC3Zia2zQZRfiuPspX0KhjCfYAKbIZC6oyrQM2uXgQKBgQDoD5voZiCOeGXJEMUk
+9JV4V8A96aE0xxy+OHMogVpysxBO4V0Nh0krSLTt9NXnpjawZQ+3pLQ4+2J2XM2e
+fJuJJ7Z+Mhjv6epnMM7FoxK1VF7oe+LE7Yk/kg/moCuVS/XhLdQrhZVBJhfEADS3
+oFybf7Q6rJYtN3OYsiFymyneHwKBgQDIGsY5kGdmx27LS5rPMwdw632TF8G5BGbu
+C3ty7LYkOWb/9/V4cuWjW4eLJQqCWbJQrzOvg0coxwXLUuEQik+IP2IkF0YlRS43
+VJuULwOxi3Cbj51RoapHhmYTO9fe2A1N9oJMAqEUHY1q/r9txPcguRWyuH2Yv9Ih
+OzHnc2DcIQKBgQCGW0MxMq/2zM5hs0vxMYq4ulWbgwDKxd1mZNiHwxzS+8mdYe22
+P3WlkdrvSqnuDNXtGxYWhU2zEBjZ3rFN6WdD6bJHLkox3YTRafjNhLT4N3kbsV6C
+FeU44SBDrsiNEAWz8gy9hgH8TknEOTpMdpQnk7CNqA7q7wgGiFvFNwDukQKBgG7i
+R03Gs0XE5aRJtPN0N39fPyqvU24O/mqSekno2dWg6W6WHLQuFwo6whVc5UHuKl2D
+eISdnmT+RDuzJXxg6El7tgqByyEEAOQwQjYPB2Du/+tz3Z1KlG0mEJI/6xNVbany
+G6m7Gz9mUOMlXzaYmsjLRzbN/OsUAIDhqHm0+cuBAoGAZCND80akS3xr3yC87GyX
+aA0RoHXbdB6dbP8Y6XYDXR4QFIA4kXwY5cCLaZA/0hP5FOzDhORmaoaPM8vUdNyb
+IYvbw2H6tODiU5oICWY6+HQQ2nXikucI4HDYDLbsiV2htZkEmBYWLilYq0Tb8jC5
+u+ehIIvZYLqKaY1GaKmF86A=
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-1-server.pem b/FDBLibTLS/testdata/test-1-server.pem
new file mode 100644
index 0000000000..b280c8c641
--- /dev/null
+++ b/FDBLibTLS/testdata/test-1-server.pem
@@ -0,0 +1,106 @@
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Server 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIJALOPTrQGpesjMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMTAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGIMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5vMRMwEQYDVQQKDApB
+cHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEoMCYGA1UEAwwfRkRCIExpYlRM
+UyBQbHVnaW4gVGVzdCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAJp26QAmlMusO7C8Py/I117r3kHvB+My5kIrj8g9sKpktwTzmsJGpvJU
+EaKISEdBsJHLGnZJhwIhr/+MG4WDEM4oFNCtBQZznV3wjIQWq1w4IO8/f3+nBPpW
+f14fjs1E911Uo/ZOL9bxvh1SIHkS6itgJi+tgVPx7C3s3W3mC5nU3omsE+Rx4DDm
+KUq1kyN1ELBIAceQ4wTmQ5B8dv6MSW7zt8Jdrhfhg2GJIPPB6XUZJ2yIOvgu55GW
+J5sMPa0uNDfCsWJ37fzFm+XJ/D96t7x8I49IyfzbIgcU9JYFlcqkryvKh5IpQGGm
+H/I6adIWa5xWpMhB2PA6kgtDD07Hu2sCAwEAAaNgMF4wHQYDVR0OBBYEFJ7S+FUz
+9ngzH/TNPVeM/cE7LeBGMB8GA1UdIwQYMBaAFCXTF7f83Hd7xm9gR+O4QrvjNo8Q
+MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBBQUAA4IB
+AQAx6WHwikVFAH0TRYCznwO6He+0t2pnlyfrI+24N28tzupMSrRPs086UbLgHLz1
+lbkYdheeOkLPzjWi5vfymL1Oua3E2iAXWEpMb4Sg7E5SVHp9yt6gZ0DTVwR+Gcu7
+uooroidAG3OFeOXL5ivU5J5ipaoEAiLprpKxtPzo4z/TxIqw3kJISC56qw9VTJNQ
+TQZvneUecykdIZuH61ih0cJLe5WRkEs/63Dgl8TBYiVDbvBSGRbsXoAXcspVlc2x
+XOLey5IVJ4/TH5ZBobShC6J1KrjZTNYvUgc44CocOgrc0ePPiQzB7JXxR1H8ATGl
+yKjWqT2PkrfHmjdcmsi2GIVt
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpeshMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyOwdOcYcH3wYou13CchsXh3lLWA85E550tT6/WwDnslQjiMZHFrKvUT2
+B8CUOR3Fr+4RG+cdw80rgojYEUuHKwmIGyjo5IotdaYbWzf6mvYThlIPPudCCkSU
+CTtqPv8Oq4QdIpCxHdix0MINKu7c+qt1rUwnDFQSv/gHhVnNxT4r8pwVp6T4hwka
+2YQaRNjzUuuFinMub0UtxnUX0rH8X5STlOSVn4Ksjo0OhQzsGEYDx86jVAXjgGcb
+2CgGGctgq04hVrngP5ahT1Xeh9YycMlQJXsckJJBxfUJebIjANSRyzxI5fYt+ZkY
+qoG5VLPREUQknxcpbT7Rsj0n+k0RhwIDAQABo2MwYTAdBgNVHQ4EFgQUJdMXt/zc
+d3vGb2BH47hCu+M2jxAwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAGwW7bRqB7aYUGsD1MOE9d5slp6Iw6wKyNLdg+mzoV+iCV2ZM7ejNRButiAy
+vPOxSQwXcibLm/g599e+LY1TiI1XXPbL2bFnTcnThqpHHFe+eRrDgqxO8qJyrcBp
+EfyMCJWq7jFg4bWoYTpLeC/RAKyi9fxlqY1NzQCp1bG3LiaDJ5VJd4uwkgX2a0yN
+3e0XEFNi7r4u4IHejwFjKWrDg8sstjbY+XOYC4EVQyUsbzeKZKSqnOdR2Jv1QZHH
+5O24G/efIFpsA6MVUOfRk0eq0RfKX7CdHn2a5p8aC6E6YMDhXL6xo146n49t9sYD
+HMUnfG6AEboTBa/l+zwCG/u4f/Y=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIJALfRa36cuemYMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMScwJQYDVQQDDB5GREIgTGliVExTIFBsdWdpbiBU
+ZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/J+sL
+7POoXNdzYRsMZCI5juxMPOVue5vU2QPU9z/PHBsBICX6tVsCnkzk5CLdM6TxofgX
+F+MqRKxtcIqxBcKjjVecJlqHuNY+jS2r8UjcoQm+EQ5RsBWu8yaSnXIiZTccQNjB
+5T2awwt9Ptbn946MZfq6oEnn4ZPByu9/nCrlk7QXTkuGdpTnC6paQWt/lVxZfELM
+i0g76/K/f3e2Lv9UCvlxKOwFMye9XjwF3ekEmUuio5JZEdn+LIs9zB1zehFhGlYB
+TUXnkZ0LTOPbH9OxsOli04n31/n7UbYq1BSuoiXx5A2eHOunMppa0NDg7oXmDSKE
+A1zo+QtIu1YPXaLdAgMBAAGjYzBhMB0GA1UdDgQWBBSeq0aNrc7mMaWHm8eCndN/
+w0I8qTAfBgNVHSMEGDAWgBSeq0aNrc7mMaWHm8eCndN/w0I8qTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAIOw1jC39
+VW+1fqGT+n44Y6Oh66lAowIvi/BEOW1I4iPAjkr0g6FbbdKeq0VLL7aMMu+q/AOv
+UETv7MdVh9xjTLqWZGN0R3Lr/n6ButI3E7MLKL5ByLNCoOhF42aBLINkpKSNFRrQ
+40iNoHm3BaNRLKS7poCk5HFkEMjvxdQ1AenNbUa21DTh7y9arHF4CPfi8Ity29jW
+ED8jYK/+bWIaO+YhGkRh8UuD3o5WnOti+9QK56qxkPtkqVTh9vMVHfD0DgVeLvMN
+nZpTplLTfhjzyFJELwE/U+HJ6KIslmqwarJ1Sla+1gHCmJEbzbsrnb6bLtrHtXCZ
+XvmR6B5iRkDVpw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCadukAJpTLrDuw
+vD8vyNde695B7wfjMuZCK4/IPbCqZLcE85rCRqbyVBGiiEhHQbCRyxp2SYcCIa//
+jBuFgxDOKBTQrQUGc51d8IyEFqtcOCDvP39/pwT6Vn9eH47NRPddVKP2Ti/W8b4d
+UiB5EuorYCYvrYFT8ewt7N1t5guZ1N6JrBPkceAw5ilKtZMjdRCwSAHHkOME5kOQ
+fHb+jElu87fCXa4X4YNhiSDzwel1GSdsiDr4LueRliebDD2tLjQ3wrFid+38xZvl
+yfw/ere8fCOPSMn82yIHFPSWBZXKpK8ryoeSKUBhph/yOmnSFmucVqTIQdjwOpIL
+Qw9Ox7trAgMBAAECggEAOZAMvsCh/NDfobpVddJL6JTPzBRvBQ1H3+rp9z5+ItHL
+nq3Fw5aeynnn5IETJnLlgT+GSgSWqoWxV/N3oia40YsATs/bqo7VW1e0ldj43TIR
+m/c25XRxl3U6m/H4vqhv4rkTLUvv6hNGvRiI/3W8DJQVRvlK0+S5FlhKIJV1R0sH
+tp5vmaPp09Ln+NVno3u3iaYkVgVME4Ukul2i03sQ9OgvZSBCaVr//fMpiPdBeeN6
+QY6XHjeGQRnP/UdzMYJ4Qz1yovL1ntneaTMdz/GkKuAFoNNh8Vr2kiEskW17OWPB
+ZGcIT6YpBEPo34xXUhUQt7ylFPxGH+zZyHZ3vb8j6QKBgQDJPeu/iPg+M5nz5gO5
+ge9gzYrhxK/1mwbFlD7qt1NjOSm6xWxUcss3STjuG7jB0c+NopIUoq/egsUnxrRm
+4l17uOCYNLbhTJ2ynfv6QnUMxW5Xkve3DkLa2bze/fhMUywTy8N4A7z0+y35qzm3
+lY4rLmQOQKPkmqWRnxU1u8fjFQKBgQDEfpOZ0fp2D/1gTG+D+/zrMEbjnNn3ZO8I
+wrjoXwRxcRggt7lJhxgQpwtDr98IqYkDzX7bvyMFJuyTii3NM6NYycpA1pHX70B/
+xMvOcrgJnIUAoJ7nl43Or7s8bFTPDLaD9PNGHjrlkF3JOXqSKEbw367jHVOa4SYr
+OjrogjrEfwKBgQDHU2a7ax5+9btqggx0ZQfGOTBzmM60lZ3qe4CqGXUl1YvIrB01
+tBImq4cRCTJB/9/1qO3KNK2/1oUTddRgB5ySnDcRaz0tASc9sQ/Q/JxVTwSRB0gG
+78A2Zu6VbLbQWp1Q6kWtDP7PJC+QmRFtDlwn1yZRm6L6HlcaWpi2hU1iVQKBgCEu
+ashv8Aad3qCzZ6V3GReyOFZZd2lSjxcAou8ClKJ/gZ6Mx+pFuOee/cT5XwV8c5nD
+yuda2JQXJZ4omGFtlej5coEOeuRnD5JD7lK3hqKA3ujjNtJPAnBjto+Wj5/DOtL/
+u1Ec6782aNABN9SUnp4wd7z8h9DAsoxcMfRvgXMLAoGBAJ9gGttfqZbuPz9V0rAo
+p05SPPado1i5+2dUOScIbNB6+vQij9IlR2Tzu1T9DwzrBqTDPPmSggeA/JXeTvh6
+Skb9fDukizeDfwPYUN2gljhiJEqFdpRBr5vP0lFi291+a0jMW1zldrumxCcGKMyU
+D5ReKLp/zSQSQi/Wt4FF1II7
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-2-client.pem b/FDBLibTLS/testdata/test-2-client.pem
new file mode 100644
index 0000000000..25083c63d4
--- /dev/null
+++ b/FDBLibTLS/testdata/test-2-client.pem
@@ -0,0 +1,106 @@
+subject= C = AU, ST = New South Wales, L = Sydney, O = Apple Pty Limited, OU = FDB Team, CN = "FDB LibTLS Plugin Test Client 2, \C2\80 <\01+\02=\03>"
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIJALOPTrQGpesmMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMjAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGdMQswCQYDVQQGEwJBVTEYMBYG
+A1UECAwPTmV3IFNvdXRoIFdhbGVzMQ8wDQYDVQQHDAZTeWRuZXkxGjAYBgNVBAoM
+EUFwcGxlIFB0eSBMaW1pdGVkMREwDwYDVQQLDAhGREIgVGVhbTE0MDIGA1UEAwwr
+RkRCIExpYlRMUyBQbHVnaW4gVGVzdCBDbGllbnQgMiwgwoAgPAErAj0DPjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALanLExQi/yK2PRyu6Mvdw2MRxUs
+26kJftYuK7KtYyltTO3vtj4kNKg1vZI1eezhqr2Ta/1DzE76eLVs8EOW0LAb5oWM
+zXdYBXBX4vG+K7pYfjuvZUd6jfX2bHW10xC96HgDTfRn6dof8GR0fILJ6DoEcyI3
+82xnKKxTsgAuXU4uvcsl0g0F78nXuIbk8ZktTV3LIdbOCIcLQfG7DdDyAfEA0T7Q
+Vg6eeLknIUvPePxyWkUdYeSCDP2d+3NIlHMxNPmH1q3+fCsEsy/kqdVO9e6KrZla
+CKqnc6yYTXvTffpPepC3Igz678iGg3dv9rLj0i4fyTr4tEOTJebO9Ka3TbMCAwEA
+AaNgMF4wHQYDVR0OBBYEFKO2/D1IhG8KWFwR6OdyoFqEzIWAMB8GA1UdIwQYMBaA
+FJFP+HFpDrD0BRU0yE606s6xkqFBMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD
+AgeAMA0GCSqGSIb3DQEBBQUAA4IBAQAQV3FjsvZvwi5Oi/oSc7Du/BQS9nQ/D4j6
+IeYpd3M0y50awZB83BReYrhdC907xKkLRD0R8oEPDEg5SaSj3vRML4kaUUqnEINW
+4JQtv4wNO9CagYriGg8ygQa0xd683svHeXDet3ov11XN/Ms8lfDiOUp2291HgeTW
+8hqn1DaNfZrCb3EkdoNThwVKIUzQtEPBuPkLE+XT8kZP5d8KHmv8/9L39NdZY32d
+fzKGBeCxZ34pQS0cTap3rZ02nDfV2vNevODRyuqdhs7EQps2Oe1IfPB9GSE0OFUQ
+tdphxSjsv1BcHpTwBDpIITKarnceMIKxQjcZU3yPv5ibIaGCgZOt
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpesiMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEApTSBCiUb0amf+QRV2WY6b3bK93D/PSrm4KR/2m2V0lciU1DAk00/kZ52
+ZIZmq8g9EaE2+CaDtU0fMvDZpaZD+vTFRwsx4varehq0ZwX9Wt25i/3G/eGLNlD3
+9E4tDNruK5UQjum4nJ0SV+AdFEGkSfeU3ZJEHYH0NrcbyAUbh0KeWCSwHiYiFJJf
+gBYwRq/HdKNoS/4YvLXzTLR7BSm3YcqWlO5tdkJ2lcT/7Th/Hq1TCW/FKwdQJJBq
+JrbOYGlMrf1pLO7Drei/xhsYkwTQ899MhSjkBRhc+401p41Mky0n8wLkuPJGhoY3
+9QUOjT+Rmvq5yryg0eWGiFquk6Ru5QIDAQABo2MwYTAdBgNVHQ4EFgQUkU/4cWkO
+sPQFFTTITrTqzrGSoUEwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAJfCHU7dm2/2ASyt3wyxivQLxlV6FsEZcF7HcpbbxuB73frGOL4kEoOxvr2X
+fBGyjlPMotbc1MeAalAv+hVHdcAcBFPF7lxtYiV6D7YI5T5yVbWSASG3+DMAiW6S
+GdQi2eyeh00nH7Y1IkW+yaky0enBtWLzrw+XzHl6xT6DIEJnir//PNxvgXTJ5sjk
+6eFAm8HJIqkNQmgfChMQfUH6nm66WwULW6I117RCSkXhIgxZ7wzDq8bXcEdXCrZk
+yy5ket9OiVpbd38JgdYirBLmCQVq0uDOOPLz4ZJmNCzQzEt+38AAK2azAk/eb8W9
+JaKWH+5V8lhlyGw1zQKdNEP/wg8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIJALfRa36cuemYMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMScwJQYDVQQDDB5GREIgTGliVExTIFBsdWdpbiBU
+ZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/J+sL
+7POoXNdzYRsMZCI5juxMPOVue5vU2QPU9z/PHBsBICX6tVsCnkzk5CLdM6TxofgX
+F+MqRKxtcIqxBcKjjVecJlqHuNY+jS2r8UjcoQm+EQ5RsBWu8yaSnXIiZTccQNjB
+5T2awwt9Ptbn946MZfq6oEnn4ZPByu9/nCrlk7QXTkuGdpTnC6paQWt/lVxZfELM
+i0g76/K/f3e2Lv9UCvlxKOwFMye9XjwF3ekEmUuio5JZEdn+LIs9zB1zehFhGlYB
+TUXnkZ0LTOPbH9OxsOli04n31/n7UbYq1BSuoiXx5A2eHOunMppa0NDg7oXmDSKE
+A1zo+QtIu1YPXaLdAgMBAAGjYzBhMB0GA1UdDgQWBBSeq0aNrc7mMaWHm8eCndN/
+w0I8qTAfBgNVHSMEGDAWgBSeq0aNrc7mMaWHm8eCndN/w0I8qTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAIOw1jC39
+VW+1fqGT+n44Y6Oh66lAowIvi/BEOW1I4iPAjkr0g6FbbdKeq0VLL7aMMu+q/AOv
+UETv7MdVh9xjTLqWZGN0R3Lr/n6ButI3E7MLKL5ByLNCoOhF42aBLINkpKSNFRrQ
+40iNoHm3BaNRLKS7poCk5HFkEMjvxdQ1AenNbUa21DTh7y9arHF4CPfi8Ity29jW
+ED8jYK/+bWIaO+YhGkRh8UuD3o5WnOti+9QK56qxkPtkqVTh9vMVHfD0DgVeLvMN
+nZpTplLTfhjzyFJELwE/U+HJ6KIslmqwarJ1Sla+1gHCmJEbzbsrnb6bLtrHtXCZ
+XvmR6B5iRkDVpw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC2pyxMUIv8itj0
+crujL3cNjEcVLNupCX7WLiuyrWMpbUzt77Y+JDSoNb2SNXns4aq9k2v9Q8xO+ni1
+bPBDltCwG+aFjM13WAVwV+Lxviu6WH47r2VHeo319mx1tdMQveh4A030Z+naH/Bk
+dHyCyeg6BHMiN/NsZyisU7IALl1OLr3LJdINBe/J17iG5PGZLU1dyyHWzgiHC0Hx
+uw3Q8gHxANE+0FYOnni5JyFLz3j8clpFHWHkggz9nftzSJRzMTT5h9at/nwrBLMv
+5KnVTvXuiq2ZWgiqp3OsmE170336T3qQtyIM+u/IhoN3b/ay49IuH8k6+LRDkyXm
+zvSmt02zAgMBAAECggEAU2sYHSZwOH+FRGcd8RJdcg+N60rYa2QNzG27wVfUwPfN
+OaHP/qN0dRpOIPdRXvFVlE0+9aVAKxXTiTBers+zMascZgP/VrEZksxgtn1e5TVD
+OakKPVHogdvwfvXylmPVRvJjaOsIb3lExew5bVYfPFgJ6Sfagbi/Z6y1z8VdEbYb
+mI34KSZA4bBAMAHPZLa9TGEx/vbPsBlqpU6k8lcoy3cTkO5fCZW4ZZIpwBwef4uJ
+UozhRgtTtRBiUpk0F9IoOXonZY1Dtpg+HcDMti/FYgahBVe1hadJ+lbVTxH6GxyI
+NJYvptdq5S99UOoJDmCCih0v0ZCUNYWoO0I0vzNncQKBgQDemN7es2fIBstiPjOf
+p103DF5j9Uxq5YH9B3wli0CXf6Z2w5uosONoJWgJZKsHJ6f+YSuHsoE/eCrFF3U9
+lxT9Nie/wYYIGedly/VR143aCdiTXI44m5gxXgwaUcjvY1DpWyEAAmr5XNdoyZ5n
+LNTvOTb4vVo9SgDU7II7rdpRmwKBgQDSD9aBtIy/650suQK/9RiXRU0Kg7LXXVM5
+lavPgLvH55lufJeGSa8+ofCNeo31N4AaVuU4lkGeny9tLNBQbYAoyAz0lf51qK7B
+1u5JqBDyRrIpdkqwbT0FT1pu1LA3+Qg0KQBrTCnOx+YyyVSivR4YMZzJjmwZGKMg
+BWOi0PzhyQKBgGR44dfpaIWbs39zjf+ZHnTza0N4+/YgA60/DKUxloULRArFPeRF
+e0+N2siqnJvNJYGnQGuugbIxPjTZ4rxbDklAgW6HHkVX099Z0TAQuGFbIltZYoRg
+jrBxv8q9cZHD5Uh/LoT/kmNdqYkNwCbX0IDt9UcOyMVzOq7g1eO0FB/TAoGBAMaG
+tWIsMwGHOip0SAcHKtB8bI1NXo5v4yH/NDuOHOqXFcj383S02uzEu8XaV6Ozalx6
+V3SdfTLem0IBIneApajlOGlIAQ9N9qu358ixECMJcYQCCiCnfQ4xqvQoCss7judN
+ANpnRvPotMS2xkhvl6uh594NvlgRksnGjh3oibcRAoGBAJKiu5ajmIkelzAhFMEC
+Slxhg/E+djJ1/SG/FaF8zIyTOxre/QUvmTwFKtHe6A5EfKQo9GCTuHuAcJ1U7eQP
+l2BoY0POqJFpw3s/QOt4g/pOz0YjD9GD6awL5WDfO++s4mnI1Snc3wcu99N4Klax
+htsaEUECJBUF0ZpIFad73s2f
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-2-server.pem b/FDBLibTLS/testdata/test-2-server.pem
new file mode 100644
index 0000000000..788cf3c217
--- /dev/null
+++ b/FDBLibTLS/testdata/test-2-server.pem
@@ -0,0 +1,106 @@
+subject= C = AU, ST = New South Wales, L = Sydney, O = Apple Pty Limited, OU = FDB Team, CN = "FDB LibTLS Plugin Test Server 2, \C2\80 <\01+\02=\03>"
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIJALOPTrQGpeskMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMjAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGdMQswCQYDVQQGEwJBVTEYMBYG
+A1UECAwPTmV3IFNvdXRoIFdhbGVzMQ8wDQYDVQQHDAZTeWRuZXkxGjAYBgNVBAoM
+EUFwcGxlIFB0eSBMaW1pdGVkMREwDwYDVQQLDAhGREIgVGVhbTE0MDIGA1UEAwwr
+RkRCIExpYlRMUyBQbHVnaW4gVGVzdCBTZXJ2ZXIgMiwgwoAgPAErAj0DPjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAolQZIGMeL5w/Bu2X6lHWjO58u
++HUDtBmr37So4jazhZBSFDBg+QlRMiYGLev9EhvCrUsVcRwtvtcuMI3wfKl7qgbi
+ZX8zmrzZ3YJo9U47NzCa05faOl8uSBvuXuXUBLU342WFP8XDB1W8yOBQMK73xoFv
+DkcxURx9ZtOhdC3EgYKrFqOB1Azl1DB4gLV3h9rHW5QpQ8SqD9CyggcDBpDeZQIP
++4l5YFE9Nb4kEUTscz2wGn4TdHMmcnVpfUxp1Y2o8Umvh4llXHIPhximGb3JJ4QQ
+Sir4ZXeeoooWoJG0sdlqVLroKav/VMGtEu9LyfbrNdKnTJq3ceVQ+HJ2hlMCAwEA
+AaNgMF4wHQYDVR0OBBYEFH61Z8O9vFsVdhM4MBU3poX2UMTEMB8GA1UdIwQYMBaA
+FJFP+HFpDrD0BRU0yE606s6xkqFBMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD
+AgeAMA0GCSqGSIb3DQEBBQUAA4IBAQCVbxlLGIBCo6/XXjqoMyZc7uQZJj7pGnwh
+nIMs2izCLfax8j+QrThO2Qjn03zT/WF8eG6ibPbjgnw3VFwCkV6oQ+BXG6Yt0xqP
+4rz1LzxSio6HSm26gSk4SQUsVoAtz3OImoTCFVfz+Mixe87pyVXXEEtCYvfU74H9
+I1WGyNkWAxiJbqeIxF5PKoc3EdnT5mfdC6sdeGm7t2neeS8PDFQtJ4UfVIEK5z1C
+MOfQILNkLX2nBYxNqKpV66zf68VZNN9002ZH2FITGqImpj74BEws3sheiuZySdoI
+wnAwRnymIMfAmkf9C7Q2ugId0YMMyesaWrIwSlXlJOHGsA1VrBRD
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpesiMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEApTSBCiUb0amf+QRV2WY6b3bK93D/PSrm4KR/2m2V0lciU1DAk00/kZ52
+ZIZmq8g9EaE2+CaDtU0fMvDZpaZD+vTFRwsx4varehq0ZwX9Wt25i/3G/eGLNlD3
+9E4tDNruK5UQjum4nJ0SV+AdFEGkSfeU3ZJEHYH0NrcbyAUbh0KeWCSwHiYiFJJf
+gBYwRq/HdKNoS/4YvLXzTLR7BSm3YcqWlO5tdkJ2lcT/7Th/Hq1TCW/FKwdQJJBq
+JrbOYGlMrf1pLO7Drei/xhsYkwTQ899MhSjkBRhc+401p41Mky0n8wLkuPJGhoY3
+9QUOjT+Rmvq5yryg0eWGiFquk6Ru5QIDAQABo2MwYTAdBgNVHQ4EFgQUkU/4cWkO
+sPQFFTTITrTqzrGSoUEwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAJfCHU7dm2/2ASyt3wyxivQLxlV6FsEZcF7HcpbbxuB73frGOL4kEoOxvr2X
+fBGyjlPMotbc1MeAalAv+hVHdcAcBFPF7lxtYiV6D7YI5T5yVbWSASG3+DMAiW6S
+GdQi2eyeh00nH7Y1IkW+yaky0enBtWLzrw+XzHl6xT6DIEJnir//PNxvgXTJ5sjk
+6eFAm8HJIqkNQmgfChMQfUH6nm66WwULW6I117RCSkXhIgxZ7wzDq8bXcEdXCrZk
+yy5ket9OiVpbd38JgdYirBLmCQVq0uDOOPLz4ZJmNCzQzEt+38AAK2azAk/eb8W9
+JaKWH+5V8lhlyGw1zQKdNEP/wg8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIJALfRa36cuemYMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMScwJQYDVQQDDB5GREIgTGliVExTIFBsdWdpbiBU
+ZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/J+sL
+7POoXNdzYRsMZCI5juxMPOVue5vU2QPU9z/PHBsBICX6tVsCnkzk5CLdM6TxofgX
+F+MqRKxtcIqxBcKjjVecJlqHuNY+jS2r8UjcoQm+EQ5RsBWu8yaSnXIiZTccQNjB
+5T2awwt9Ptbn946MZfq6oEnn4ZPByu9/nCrlk7QXTkuGdpTnC6paQWt/lVxZfELM
+i0g76/K/f3e2Lv9UCvlxKOwFMye9XjwF3ekEmUuio5JZEdn+LIs9zB1zehFhGlYB
+TUXnkZ0LTOPbH9OxsOli04n31/n7UbYq1BSuoiXx5A2eHOunMppa0NDg7oXmDSKE
+A1zo+QtIu1YPXaLdAgMBAAGjYzBhMB0GA1UdDgQWBBSeq0aNrc7mMaWHm8eCndN/
+w0I8qTAfBgNVHSMEGDAWgBSeq0aNrc7mMaWHm8eCndN/w0I8qTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAIOw1jC39
+VW+1fqGT+n44Y6Oh66lAowIvi/BEOW1I4iPAjkr0g6FbbdKeq0VLL7aMMu+q/AOv
+UETv7MdVh9xjTLqWZGN0R3Lr/n6ButI3E7MLKL5ByLNCoOhF42aBLINkpKSNFRrQ
+40iNoHm3BaNRLKS7poCk5HFkEMjvxdQ1AenNbUa21DTh7y9arHF4CPfi8Ity29jW
+ED8jYK/+bWIaO+YhGkRh8UuD3o5WnOti+9QK56qxkPtkqVTh9vMVHfD0DgVeLvMN
+nZpTplLTfhjzyFJELwE/U+HJ6KIslmqwarJ1Sla+1gHCmJEbzbsrnb6bLtrHtXCZ
+XvmR6B5iRkDVpw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwKJUGSBjHi+cP
+wbtl+pR1ozufLvh1A7QZq9+0qOI2s4WQUhQwYPkJUTImBi3r/RIbwq1LFXEcLb7X
+LjCN8Hype6oG4mV/M5q82d2CaPVOOzcwmtOX2jpfLkgb7l7l1AS1N+NlhT/FwwdV
+vMjgUDCu98aBbw5HMVEcfWbToXQtxIGCqxajgdQM5dQweIC1d4fax1uUKUPEqg/Q
+soIHAwaQ3mUCD/uJeWBRPTW+JBFE7HM9sBp+E3RzJnJ1aX1MadWNqPFJr4eJZVxy
+D4cYphm9ySeEEEoq+GV3nqKKFqCRtLHZalS66Cmr/1TBrRLvS8n26zXSp0yat3Hl
+UPhydoZTAgMBAAECggEAVD60NlLYduXzVNfDtVuHEFNGOjSOYfepc/V8gLubo6lr
+IMAAI7rcnpYUM5cU8x0OQfRyR8wzUdSWxfWzBs6R78PSZoRzIcgeIl7Wzn0/g3BS
+To5czuxwqgBKQAFZpPQmZDwcJfr5qqxAn8IvFweCoMqiRlhELcvqDIP0XxWBqDjc
+TNJ988XzZXQmJbjjpWOkUBy2Uqz8lZt8MmxKFpW7SW4tBJwPphnorgjWfjCV/VEh
+ORio0rG74NHFo4f1TSrdU2BcB2cbVJ4B+bcUYRdvYmS5bmokhGF8vir0l43gUEdz
+Fyk6MaPrTI6cinqzenm3q/0eRvNhBE56U0tiGLn14QKBgQDkCkt1Y4LEboSwsVYl
+IXriStqj9p9MOizihh0enhzRXTTQuLX82fNi+bh1LAluwv290Q57pvKa+hB/YciB
+o4s7QfSojxQY9DxqvXN7CvxPWXHTyFY5sL4Rm807+C/a9rd39MxBynz9u/7YRvsA
+s8v8Y/01qIHnTo+mpDvu6HttWwKBgQDFwdRkgstuE+dXZZe8g1ivh3RNPa968TE3
+b8rzF9/nOJV7f6B/n6YEmHD/cHF5mm1bR+zt/jtf1NCRMpazchw3vT3JzQZYMDnM
+SD6vxTs5rG47QLiNyTIRmmD4gsEWBpyvoyP8E/9QdfDT1bWI5zZnky9CquRlN+cu
+J1bTsefEaQKBgGJsRxFNd91MThztDV9NSfptkFyAT1TZLxI+DEdwusNqVSdY8cNG
+VpP7cC+yaAfURSwuFPAtqDxXfdNc4uuBKNDUsMInrubuUz1Gs5cBsNCWrFhZ+U1B
+CWgUNMqTXiRFo/40PAyRVs003NOAH0m4UGyIw3rrVdX9xGaKMAv3b35NAoGATkkl
+I4UDs1f9xQNaxi3Y9ePRjqJUzX6d1SxUU1eoM4ia5IDpsJwqxLb0RKrmwRT5JaGb
+kbuLFazRxCkar38E3Kv1weWAFXlB6DTRXBPgFjzEhoBgjwCO6ZkLulVIysdjT8Rt
+gmUINXn7FGENtFyTlP0XQHUWZVt0ETlRjgxni8ECgYBYv6MoSr0iPjQpxeKvwFDz
+d9zE+ZXN+3GwtkI340lKRSc/f0Uq1TlC2w+DzjyyXcrBwubMQKTKcQQSH9f3YbMu
+DuxVE9AXdlQ1gSQHGjS0qUWwsS/8Xcjk8ZuduAXPGr/MsvsW+FbbZqG8qdZTeMHu
+MSTpOxu9HXC8SHML+y0cpw==
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-3-client.pem b/FDBLibTLS/testdata/test-3-client.pem
new file mode 100644
index 0000000000..959e3c34fd
--- /dev/null
+++ b/FDBLibTLS/testdata/test-3-client.pem
@@ -0,0 +1,150 @@
+subject=
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+Certificate:
+ Data:
+ Version: 1 (0x0)
+ Serial Number: 1048578 (0x100002)
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: C=US, ST=California, L=Cupertino, O=Apple Inc., OU=FDB Team, CN=FDB LibTLS Plugin Test Intermediate CA 1
+ Validity
+ Not Before: Jan 1 00:00:00 2017 GMT
+ Not After : Dec 31 00:00:00 2017 GMT
+ Subject:
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ Public-Key: (2048 bit)
+ Modulus:
+ 00:e4:6f:67:4b:e7:d2:1b:0a:ec:f8:92:ae:1e:d4:
+ e9:00:6b:47:83:ad:4e:9e:e2:cc:52:b0:8a:04:46:
+ 57:1f:f7:32:37:cc:f0:cd:ec:c0:b9:b9:27:b4:19:
+ 33:a1:21:a7:4c:a2:6c:c7:56:31:c4:6a:4f:5f:fb:
+ 92:6c:22:8f:c4:eb:3f:d1:2b:06:c7:7b:6b:90:83:
+ 37:d3:59:1c:c0:da:de:85:a1:dc:e6:9d:e1:d8:fc:
+ 6f:d4:c0:b4:6e:37:3d:d2:d7:4e:4e:04:09:6a:fb:
+ 9f:d3:cf:b1:80:db:7a:78:97:65:e1:bc:8d:5a:fa:
+ ec:b1:b6:ee:3f:c9:03:83:ab:0a:9a:8e:03:29:88:
+ 42:14:50:80:11:a7:d5:2d:87:c8:bd:25:32:9e:55:
+ fb:22:ef:9c:64:a8:a4:62:3b:d6:86:43:1a:22:a3:
+ 1c:4b:ee:af:30:70:d3:9c:aa:da:b6:87:61:78:87:
+ 32:0c:0b:b7:44:16:9b:44:1b:4e:6d:f3:98:99:f8:
+ ed:ae:41:02:5d:52:9a:98:49:c3:24:24:0b:18:7b:
+ bf:40:ce:37:65:0f:32:0c:1c:5a:47:4b:b0:3f:db:
+ 17:b6:89:68:99:3c:0e:70:84:92:5c:33:cb:6d:2e:
+ 67:c8:af:47:41:87:bd:37:87:88:00:65:1f:7e:7b:
+ d9:09
+ Exponent: 65537 (0x10001)
+ Signature Algorithm: sha256WithRSAEncryption
+ 0b:5a:f7:7e:e5:93:4b:25:dc:01:eb:20:37:cb:bd:a9:71:3a:
+ af:6d:73:d9:9e:3c:8b:5c:6d:74:45:76:72:02:64:7e:e6:41:
+ bf:29:d7:cd:f8:a7:2d:87:32:6d:25:3f:14:11:2b:95:5a:2e:
+ a8:8b:ba:b1:f9:52:79:b4:5b:ea:fe:b0:ee:b0:9c:14:53:ba:
+ 5d:64:aa:b9:d9:ca:17:b2:99:da:34:18:31:56:83:d9:21:8f:
+ 20:9e:6a:7f:09:41:2f:36:fa:ab:e7:d1:6c:76:50:d4:51:69:
+ b9:93:ae:9a:eb:8a:6f:a9:91:21:58:a9:3d:53:e8:c1:2c:6f:
+ 88:25:65:03:8a:90:9c:8e:58:5d:9a:e2:67:8e:6a:f6:11:19:
+ 24:8d:89:b7:11:5e:a8:dc:21:35:7a:9a:78:8a:94:c2:29:84:
+ bb:b7:a5:8e:04:79:dc:db:9d:d7:a7:a3:b7:39:e6:c3:a5:be:
+ 83:ad:59:3a:ee:ea:4a:8a:bd:6e:71:c9:e4:a7:46:d5:a3:fd:
+ a0:b1:a3:54:8d:bc:01:fb:68:4c:5a:a2:f5:79:44:f7:b9:e9:
+ 7b:db:91:91:74:5b:68:f6:3a:b2:70:ee:e6:49:f4:f1:a6:53:
+ 66:13:ce:2f:9e:88:45:66:34:ae:fc:0d:14:02:6f:6a:c9:ac:
+ b5:3f:89:bc
+-----BEGIN CERTIFICATE-----
+MIIDCDCCAfACAxAAAjANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UEBhMCVVMxEzAR
+BgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUN1cGVydGlubzETMBEGA1UECgwK
+QXBwbGUgSW5jLjERMA8GA1UECwwIRkRCIFRlYW0xMTAvBgNVBAMMKEZEQiBMaWJU
+TFMgUGx1Z2luIFRlc3QgSW50ZXJtZWRpYXRlIENBIDEwHhcNMTcwMTAxMDAwMDAw
+WhcNMTcxMjMxMDAwMDAwWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA5G9nS+fSGwrs+JKuHtTpAGtHg61OnuLMUrCKBEZXH/cyN8zwzezAubkntBkz
+oSGnTKJsx1YxxGpPX/uSbCKPxOs/0SsGx3trkIM301kcwNrehaHc5p3h2Pxv1MC0
+bjc90tdOTgQJavuf08+xgNt6eJdl4byNWvrssbbuP8kDg6sKmo4DKYhCFFCAEafV
+LYfIvSUynlX7Iu+cZKikYjvWhkMaIqMcS+6vMHDTnKratodheIcyDAu3RBabRBtO
+bfOYmfjtrkECXVKamEnDJCQLGHu/QM43ZQ8yDBxaR0uwP9sXtolomTwOcISSXDPL
+bS5nyK9HQYe9N4eIAGUffnvZCQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQALWvd+
+5ZNLJdwB6yA3y72pcTqvbXPZnjyLXG10RXZyAmR+5kG/KdfN+KcthzJtJT8UESuV
+Wi6oi7qx+VJ5tFvq/rDusJwUU7pdZKq52coXspnaNBgxVoPZIY8gnmp/CUEvNvqr
+59FsdlDUUWm5k66a64pvqZEhWKk9U+jBLG+IJWUDipCcjlhdmuJnjmr2ERkkjYm3
+EV6o3CE1epp4ipTCKYS7t6WOBHnc253Xp6O3OebDpb6DrVk67upKir1uccnkp0bV
+o/2gsaNUjbwB+2hMWqL1eUT3uel725GRdFto9jqycO7mSfTxplNmE84vnohFZjSu
+/A0UAm9qyay1P4m8
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpeshMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyOwdOcYcH3wYou13CchsXh3lLWA85E550tT6/WwDnslQjiMZHFrKvUT2
+B8CUOR3Fr+4RG+cdw80rgojYEUuHKwmIGyjo5IotdaYbWzf6mvYThlIPPudCCkSU
+CTtqPv8Oq4QdIpCxHdix0MINKu7c+qt1rUwnDFQSv/gHhVnNxT4r8pwVp6T4hwka
+2YQaRNjzUuuFinMub0UtxnUX0rH8X5STlOSVn4Ksjo0OhQzsGEYDx86jVAXjgGcb
+2CgGGctgq04hVrngP5ahT1Xeh9YycMlQJXsckJJBxfUJebIjANSRyzxI5fYt+ZkY
+qoG5VLPREUQknxcpbT7Rsj0n+k0RhwIDAQABo2MwYTAdBgNVHQ4EFgQUJdMXt/zc
+d3vGb2BH47hCu+M2jxAwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAGwW7bRqB7aYUGsD1MOE9d5slp6Iw6wKyNLdg+mzoV+iCV2ZM7ejNRButiAy
+vPOxSQwXcibLm/g599e+LY1TiI1XXPbL2bFnTcnThqpHHFe+eRrDgqxO8qJyrcBp
+EfyMCJWq7jFg4bWoYTpLeC/RAKyi9fxlqY1NzQCp1bG3LiaDJ5VJd4uwkgX2a0yN
+3e0XEFNi7r4u4IHejwFjKWrDg8sstjbY+XOYC4EVQyUsbzeKZKSqnOdR2Jv1QZHH
+5O24G/efIFpsA6MVUOfRk0eq0RfKX7CdHn2a5p8aC6E6YMDhXL6xo146n49t9sYD
+HMUnfG6AEboTBa/l+zwCG/u4f/Y=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIJALfRa36cuemYMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMScwJQYDVQQDDB5GREIgTGliVExTIFBsdWdpbiBU
+ZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/J+sL
+7POoXNdzYRsMZCI5juxMPOVue5vU2QPU9z/PHBsBICX6tVsCnkzk5CLdM6TxofgX
+F+MqRKxtcIqxBcKjjVecJlqHuNY+jS2r8UjcoQm+EQ5RsBWu8yaSnXIiZTccQNjB
+5T2awwt9Ptbn946MZfq6oEnn4ZPByu9/nCrlk7QXTkuGdpTnC6paQWt/lVxZfELM
+i0g76/K/f3e2Lv9UCvlxKOwFMye9XjwF3ekEmUuio5JZEdn+LIs9zB1zehFhGlYB
+TUXnkZ0LTOPbH9OxsOli04n31/n7UbYq1BSuoiXx5A2eHOunMppa0NDg7oXmDSKE
+A1zo+QtIu1YPXaLdAgMBAAGjYzBhMB0GA1UdDgQWBBSeq0aNrc7mMaWHm8eCndN/
+w0I8qTAfBgNVHSMEGDAWgBSeq0aNrc7mMaWHm8eCndN/w0I8qTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAIOw1jC39
+VW+1fqGT+n44Y6Oh66lAowIvi/BEOW1I4iPAjkr0g6FbbdKeq0VLL7aMMu+q/AOv
+UETv7MdVh9xjTLqWZGN0R3Lr/n6ButI3E7MLKL5ByLNCoOhF42aBLINkpKSNFRrQ
+40iNoHm3BaNRLKS7poCk5HFkEMjvxdQ1AenNbUa21DTh7y9arHF4CPfi8Ity29jW
+ED8jYK/+bWIaO+YhGkRh8UuD3o5WnOti+9QK56qxkPtkqVTh9vMVHfD0DgVeLvMN
+nZpTplLTfhjzyFJELwE/U+HJ6KIslmqwarJ1Sla+1gHCmJEbzbsrnb6bLtrHtXCZ
+XvmR6B5iRkDVpw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDkb2dL59IbCuz4
+kq4e1OkAa0eDrU6e4sxSsIoERlcf9zI3zPDN7MC5uSe0GTOhIadMomzHVjHEak9f
++5JsIo/E6z/RKwbHe2uQgzfTWRzA2t6FodzmneHY/G/UwLRuNz3S105OBAlq+5/T
+z7GA23p4l2XhvI1a+uyxtu4/yQODqwqajgMpiEIUUIARp9Uth8i9JTKeVfsi75xk
+qKRiO9aGQxoioxxL7q8wcNOcqtq2h2F4hzIMC7dEFptEG05t85iZ+O2uQQJdUpqY
+ScMkJAsYe79AzjdlDzIMHFpHS7A/2xe2iWiZPA5whJJcM8ttLmfIr0dBh703h4gA
+ZR9+e9kJAgMBAAECggEBAKC87x+PQN18g6CpfdH+GPINiuXR9ieBCSsKRCOb50R7
+6Z8wGyWbeUV2TsTAkv7HsnQPOqHNOfmuoKm2WKK0cxuqOV6SexO0+cxXONoDs2LU
+342ChvDTmY7YmkxHSO7g+iS5EcV9u67G3gDp/Unhpjzis3Ly/ThOpmyqftztMgbb
+6KKfgGi3VL+fZ2x8gQt0II2QcO6GIzrPcn9ruEM6tXJhQ50YaSCeCmseKBvKuWPW
+b/Gj7wgYhsiMW+nt8QjVam99eCQ6Q94CsapWRdGpj1Nrd4ISREbqr8x4fmcbiSO6
+6HZyUidxZIxr2Y4/BTd/BiIqXXdKAMoCVElmyE09P4ECgYEA9IkOkHq1jDLAmppd
+fNSC/ndmITS0imvwzTTubXKOTn3yZHVxk2/ld83aauGA3UwAueW4Hh0hJdIWqC0d
+IyaNj3EhcVbidyYwvXdChlPuQ1uccu/earhzsbaFwqNoLVgMrPcB5QcMKUs2/s4Q
+tBXOqNlFjDZ+bkHQyGXtFYJzknECgYEA7yUcJqf2jB5e4LWG4Se4zD1E/ccZH3t8
+nhuXa6nDsx2trZBknHpQmc85WzbBITD+LRaamlYpnB1Ueiyr7/Efamtls7NvnoQN
+14cNFnnj5HooTHJHgNBuL/M3hr/q8uK4lR6bu/DOfzUfRGowX3pj+POB01ObPdm8
+BUTFwmfJTBkCgYEAkakqccmGZxK8Q9t7oKX9uZJp1ZHNkT6m27WR6MP6HKtNPaXv
+l4Fp0KlgV5Yn6qohLJq3x8hWPG8ea+MjnhKS9ETRRPAaShsHoXRuvhE0tg7V7GkR
+tcRVtiAhIUWxAoGWW1lvWXuPNPHGupUIwhzTUyTJFrJHMWom8Zg1V0CzkyECgYEA
+0JpPXwzejEUlv9+4owhyM34ygyg8KvEduBEbWWfBdKmryR2OFczAKBrRzlYJy3kg
+DpaMD5qfOzV+bgAvjuKG496A3WrlL6HDLUD50qRKfQ9tvZll8+BcbWk8A0e/m1TX
+bARCFoOsrNvaxWPXhEGPmSZYFc31OdOHJhViZ/z+Y2kCgYEAphx6cPXLMcgv0ivj
+SgIG09vo3hGA5r06FkLtGL677CTvYsk/Equ5TkG0AIJ0acY9wiabk6zyM/9XjRAp
+Nf8qYzhaMxJiyw+JEXmud4Dc41DqjGm9bLV4tKSR+7xzPBP9Q/QLxfRvArBOKhiX
+L5fWmM5SQAoHsf124DTKckNirLI=
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-3-server.pem b/FDBLibTLS/testdata/test-3-server.pem
new file mode 100644
index 0000000000..27759468f9
--- /dev/null
+++ b/FDBLibTLS/testdata/test-3-server.pem
@@ -0,0 +1,101 @@
+subject=
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIIDCDCCAfACAxAAATANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UEBhMCVVMxEzAR
+BgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUN1cGVydGlubzETMBEGA1UECgwK
+QXBwbGUgSW5jLjERMA8GA1UECwwIRkRCIFRlYW0xMTAvBgNVBAMMKEZEQiBMaWJU
+TFMgUGx1Z2luIFRlc3QgSW50ZXJtZWRpYXRlIENBIDEwHhcNMTcwMTAxMDAwMDAw
+WhcNMTcxMjMxMDAwMDAwWjAAMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA43+uFNDYKXQQ4fmSencxdm/mfM6FAlGwRBWotptutznfH0N+ulp5RhjRcbGb
+AHwPOBBNEBSIV3LhdPXep3NcmSkfaMdnPEgrurI0DLYbxZryEXdJZyoueT+w4TNx
+I5mNlZDKD5bH5rhV/dUAmK/+LpWuxWraWYaHBZBsuqpb0MF6IZJAN9Ve9JiKHeiY
+6ecz/o9XIrFFeWKMncHwBV1taPPoG2Ksjv8UlqqehrYXG+md958MXf69dkuQJLCS
+rojPOkhUroixvGiXJBRSFCyVhQxPCLyASsEv8qPEKMUiW4oY3w5R9RQmw97AHlA1
+7xB4mGZTZEjUIOYDdd8LyuRpawIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAHMAsm
+zLtFnDaYaOgJdPpi9VAUkZpbSXcA3a02PzOvLN9VV1Fogf1+F0zYFlWbiYGIwcI4
+3YfuFr97/e0uEQd6pwGc8/a63q+CunGz+HPStWZm+2ZgmJhBH6i1RwmhA9rH6rGK
+j2UghYIYT83gn6S2XSfUwzV8gCw+JjJwczcjGpOf9dRCAEsRDcRwUX7rI16cE2tZ
+SLzYB/Kg3wSnUXTKXRJfg6VbVRPFXHQlRYpOxe2z5LWoTEo2uYuHgYO+DzSO9pEj
+WgyKBwcc+L3zIZFYCqc9EN//QrLlXsiwSDVMvtzVnzvIQKcGF7OE22NyojTaMzQL
+2h8UA9W0Mew5PTSl
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpeshMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyOwdOcYcH3wYou13CchsXh3lLWA85E550tT6/WwDnslQjiMZHFrKvUT2
+B8CUOR3Fr+4RG+cdw80rgojYEUuHKwmIGyjo5IotdaYbWzf6mvYThlIPPudCCkSU
+CTtqPv8Oq4QdIpCxHdix0MINKu7c+qt1rUwnDFQSv/gHhVnNxT4r8pwVp6T4hwka
+2YQaRNjzUuuFinMub0UtxnUX0rH8X5STlOSVn4Ksjo0OhQzsGEYDx86jVAXjgGcb
+2CgGGctgq04hVrngP5ahT1Xeh9YycMlQJXsckJJBxfUJebIjANSRyzxI5fYt+ZkY
+qoG5VLPREUQknxcpbT7Rsj0n+k0RhwIDAQABo2MwYTAdBgNVHQ4EFgQUJdMXt/zc
+d3vGb2BH47hCu+M2jxAwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAGwW7bRqB7aYUGsD1MOE9d5slp6Iw6wKyNLdg+mzoV+iCV2ZM7ejNRButiAy
+vPOxSQwXcibLm/g599e+LY1TiI1XXPbL2bFnTcnThqpHHFe+eRrDgqxO8qJyrcBp
+EfyMCJWq7jFg4bWoYTpLeC/RAKyi9fxlqY1NzQCp1bG3LiaDJ5VJd4uwkgX2a0yN
+3e0XEFNi7r4u4IHejwFjKWrDg8sstjbY+XOYC4EVQyUsbzeKZKSqnOdR2Jv1QZHH
+5O24G/efIFpsA6MVUOfRk0eq0RfKX7CdHn2a5p8aC6E6YMDhXL6xo146n49t9sYD
+HMUnfG6AEboTBa/l+zwCG/u4f/Y=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIJALfRa36cuemYMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgYcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMScwJQYDVQQDDB5GREIgTGliVExTIFBsdWdpbiBU
+ZXN0IFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC/J+sL
+7POoXNdzYRsMZCI5juxMPOVue5vU2QPU9z/PHBsBICX6tVsCnkzk5CLdM6TxofgX
+F+MqRKxtcIqxBcKjjVecJlqHuNY+jS2r8UjcoQm+EQ5RsBWu8yaSnXIiZTccQNjB
+5T2awwt9Ptbn946MZfq6oEnn4ZPByu9/nCrlk7QXTkuGdpTnC6paQWt/lVxZfELM
+i0g76/K/f3e2Lv9UCvlxKOwFMye9XjwF3ekEmUuio5JZEdn+LIs9zB1zehFhGlYB
+TUXnkZ0LTOPbH9OxsOli04n31/n7UbYq1BSuoiXx5A2eHOunMppa0NDg7oXmDSKE
+A1zo+QtIu1YPXaLdAgMBAAGjYzBhMB0GA1UdDgQWBBSeq0aNrc7mMaWHm8eCndN/
+w0I8qTAfBgNVHSMEGDAWgBSeq0aNrc7mMaWHm8eCndN/w0I8qTAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAIOw1jC39
+VW+1fqGT+n44Y6Oh66lAowIvi/BEOW1I4iPAjkr0g6FbbdKeq0VLL7aMMu+q/AOv
+UETv7MdVh9xjTLqWZGN0R3Lr/n6ButI3E7MLKL5ByLNCoOhF42aBLINkpKSNFRrQ
+40iNoHm3BaNRLKS7poCk5HFkEMjvxdQ1AenNbUa21DTh7y9arHF4CPfi8Ity29jW
+ED8jYK/+bWIaO+YhGkRh8UuD3o5WnOti+9QK56qxkPtkqVTh9vMVHfD0DgVeLvMN
+nZpTplLTfhjzyFJELwE/U+HJ6KIslmqwarJ1Sla+1gHCmJEbzbsrnb6bLtrHtXCZ
+XvmR6B5iRkDVpw==
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDjf64U0NgpdBDh
++ZJ6dzF2b+Z8zoUCUbBEFai2m263Od8fQ366WnlGGNFxsZsAfA84EE0QFIhXcuF0
+9d6nc1yZKR9ox2c8SCu6sjQMthvFmvIRd0lnKi55P7DhM3EjmY2VkMoPlsfmuFX9
+1QCYr/4ula7FatpZhocFkGy6qlvQwXohkkA31V70mIod6Jjp5zP+j1cisUV5Yoyd
+wfAFXW1o8+gbYqyO/xSWqp6Gthcb6Z33nwxd/r12S5AksJKuiM86SFSuiLG8aJck
+FFIULJWFDE8IvIBKwS/yo8QoxSJbihjfDlH1FCbD3sAeUDXvEHiYZlNkSNQg5gN1
+3wvK5GlrAgMBAAECggEAAVjMKwthfD1XrD7SAy+Zd14KO0rttqnNJVoLealJ6oPJ
+MmIv6eKHPUcAVm/6vvH9FRPjoOi+NeZUN2ENRGiGb9GygehMUCsNNzm+3SRm3bCh
+JkFSie3SAJ3D6lFnphJOqEgHKjh2ToNg3vPX4Q+JrbTtJ/YN/OGzAvFr81721DGO
+L7Hs6foBHKrLeibbguVRdc5zc/WtWjGPFhNAmR9qincM3Q9DrUUHjbJzTS1UXDVT
+zssTUTZe9TLd4buqHjLLfmiPoTV8qzv5l4RwkmuuLIT+5mO7X41glwdOkBfk+Cum
+BZjrjgTDXbqLNXjMsvXkG1hCZQ6qwdT4GINYlYSiQQKBgQD4pJf7xLaX53rj+LDc
+HY3TbWDdyS7h7cq4ZoKa1xPt4Va3xIAIst20edTr6tBYtNygjFZwIkPFYGwdGKVK
+CqbpzTxVl8p5I3uoUmIFDo8hX7ChLC928K9lfD62agU85ZfP9Vly4zvDG2sIvxpw
+HUY/96VhdSG3fssWYvg3dYUGCQKBgQDqOuyrcTHaZujFMN+MIuUExgYOMS0R0O4T
+zCMtWIEkjntSk4CBMsHSb/dZH3CbFB90GjS+WklfTBd6kZ8tBO35vtM6nz5NPCEr
+2umqJR5hijHV2tB98qV9qJttJrH/z0VKuuZBa14S1rJwGpX9ZoOULwcOGK3VC9pQ
+YnH7Wdjw0wKBgFtBZXqE7xL/ZS4IVzjiK+xeJ4Ae13MaKB3XmbWknG7hFkep+ee3
+ZgFX+ZqAeukjsBnIh+zt1nu5cNSY+Akdsbb7mVo8tJYTPM5BNjJu7n8sNJJiuiTo
+HyebGxUuAjAgf8BWZvbwiT2JcZYrNVPSmrbdeDg1miNTiMv1lO4d1q2pAoGBANq8
+oFwSX24IAIR1+a2SwLDOhMUoI2Cp7ktKrecg6alL7drVqIH+9oYgzarK84u/JQh1
+mJ/TDQYTtzFdYHrYSaybCgOKxtG1v3yG+QNNmquYNKXzrBSSTv2kQVGTe1LbK2h4
+VaLuM3IAUa7jBQMZgvMVX89IOL3mTcAXzz3dT/zFAoGBAI/pVbABfPihWZ1MrmTN
+pnRmQ0461J0WGT+fIgAPR+R+umckHaOVAGiSQomfNrUBbsydoZYu/by7GhIGsDeO
+8XKwEP/HLRrABvZu4KLTxa+qTnW/t6BSIfFwQmrNMofxcFRbdzNAODKjyaJG2dqT
+ksg9s2SxReRrGOeb43CAw5SC
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-4-client.pem b/FDBLibTLS/testdata/test-4-client.pem
new file mode 100644
index 0000000000..87f088b96b
--- /dev/null
+++ b/FDBLibTLS/testdata/test-4-client.pem
@@ -0,0 +1,80 @@
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Client 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIJALOPTrQGpeslMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMTAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGIMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5vMRMwEQYDVQQKDApB
+cHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEoMCYGA1UEAwwfRkRCIExpYlRM
+UyBQbHVnaW4gVGVzdCBDbGllbnQgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBALVkdxOmWcd959NyirJ1iz7q5fkjdRUV+88KMMehQWc3f50GJIQ+eZo+
+7RhwVE+n8nd0i5iGfyY6LRuupdwoQUxoZ/5rUIDGKspNO62DVRW+tZqzpEa1+ub5
+75BMoc7I7l9sXDkuiMu1OYcPNKMv4F3mf+B3ourLqjUekKlUv8XIZXAvN+R19HlR
+FM8vs8rnhQXx7iWVP91frDvyD8G7lOf6R7R4homnB37kLom8WU+fCmcyA6em0qX0
+JeVP6xk2qXU1cMs7DL8WftdrWHv+a73/l4hytQHo5OvtGaLZhpPYpC/FMSaFHVSM
+irWSFK+ZtvaLi3LXc2HGANMokjPoRf8CAwEAAaNgMF4wHQYDVR0OBBYEFPtTL9KZ
+jn49cLediy1ixz7AXOI3MB8GA1UdIwQYMBaAFCXTF7f83Hd7xm9gR+O4QrvjNo8Q
+MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBBQUAA4IB
+AQA17a4d/tSWIlTkIfkrXziD21+1OsN6/dUrWQK7kxtEe21QXIutccW4bwpM0JDB
+M+bZiWkdgQ15+ZotX5UXlBcx9WWDU5RqSO06hhXu5b8gZwfVF4Od6tBdVxkn4KbU
+0YujOZrL8fDOrQHqCO7nhNlYgcEn7bKF5wjtOoiKhtA9sLSIZQR5g32kkJXXGvcY
+lLWMXygEg9FMQoldW9RHq4GbUiYEeqEq6k4S7cE03R1lvmQEOOAJ2S7LnaS4UHQT
+GmW6uvLnJJrG4HB9JGE+y1e9M+C7Enzhi39RGd8ylignGimkdw/1UEWnvKGCqoU7
+ufWGF7eUV8dCqO+jYghIY8rA
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpeshMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyOwdOcYcH3wYou13CchsXh3lLWA85E550tT6/WwDnslQjiMZHFrKvUT2
+B8CUOR3Fr+4RG+cdw80rgojYEUuHKwmIGyjo5IotdaYbWzf6mvYThlIPPudCCkSU
+CTtqPv8Oq4QdIpCxHdix0MINKu7c+qt1rUwnDFQSv/gHhVnNxT4r8pwVp6T4hwka
+2YQaRNjzUuuFinMub0UtxnUX0rH8X5STlOSVn4Ksjo0OhQzsGEYDx86jVAXjgGcb
+2CgGGctgq04hVrngP5ahT1Xeh9YycMlQJXsckJJBxfUJebIjANSRyzxI5fYt+ZkY
+qoG5VLPREUQknxcpbT7Rsj0n+k0RhwIDAQABo2MwYTAdBgNVHQ4EFgQUJdMXt/zc
+d3vGb2BH47hCu+M2jxAwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAGwW7bRqB7aYUGsD1MOE9d5slp6Iw6wKyNLdg+mzoV+iCV2ZM7ejNRButiAy
+vPOxSQwXcibLm/g599e+LY1TiI1XXPbL2bFnTcnThqpHHFe+eRrDgqxO8qJyrcBp
+EfyMCJWq7jFg4bWoYTpLeC/RAKyi9fxlqY1NzQCp1bG3LiaDJ5VJd4uwkgX2a0yN
+3e0XEFNi7r4u4IHejwFjKWrDg8sstjbY+XOYC4EVQyUsbzeKZKSqnOdR2Jv1QZHH
+5O24G/efIFpsA6MVUOfRk0eq0RfKX7CdHn2a5p8aC6E6YMDhXL6xo146n49t9sYD
+HMUnfG6AEboTBa/l+zwCG/u4f/Y=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1ZHcTplnHfefT
+coqydYs+6uX5I3UVFfvPCjDHoUFnN3+dBiSEPnmaPu0YcFRPp/J3dIuYhn8mOi0b
+rqXcKEFMaGf+a1CAxirKTTutg1UVvrWas6RGtfrm+e+QTKHOyO5fbFw5LojLtTmH
+DzSjL+Bd5n/gd6Lqy6o1HpCpVL/FyGVwLzfkdfR5URTPL7PK54UF8e4llT/dX6w7
+8g/Bu5Tn+ke0eIaJpwd+5C6JvFlPnwpnMgOnptKl9CXlT+sZNql1NXDLOwy/Fn7X
+a1h7/mu9/5eIcrUB6OTr7Rmi2YaT2KQvxTEmhR1UjIq1khSvmbb2i4ty13NhxgDT
+KJIz6EX/AgMBAAECggEAEm2Mc2CZCl1OKfsfABZU+SVgC7mAcY30MQp1/jHxtQy8
+WDWBjDXUoMj3yV3QEu+bAGvEqtAvJrEOWBucGgu05pBM0FoSqaJ4QmkqQOxwvm7L
+gFXzwINIZCLMJbrDTYC4RtV5YQ3LM/bLS19OF64Lez6piyJcWMIsHo1mYO2NNgiD
+7f1x1uQw46Q0YHWeoHY58MPfmgfKsqnJDWc8cCuU9fJOWeU4dVrfW8dh9WVAoLZ7
+qAM5vvap11Qk8RXaRnmLjxN6H1M7iVNfcLVNKfG6XOBBepYjZr/qMkuN3ONuqBHl
+fC3Zia2zQZRfiuPspX0KhjCfYAKbIZC6oyrQM2uXgQKBgQDoD5voZiCOeGXJEMUk
+9JV4V8A96aE0xxy+OHMogVpysxBO4V0Nh0krSLTt9NXnpjawZQ+3pLQ4+2J2XM2e
+fJuJJ7Z+Mhjv6epnMM7FoxK1VF7oe+LE7Yk/kg/moCuVS/XhLdQrhZVBJhfEADS3
+oFybf7Q6rJYtN3OYsiFymyneHwKBgQDIGsY5kGdmx27LS5rPMwdw632TF8G5BGbu
+C3ty7LYkOWb/9/V4cuWjW4eLJQqCWbJQrzOvg0coxwXLUuEQik+IP2IkF0YlRS43
+VJuULwOxi3Cbj51RoapHhmYTO9fe2A1N9oJMAqEUHY1q/r9txPcguRWyuH2Yv9Ih
+OzHnc2DcIQKBgQCGW0MxMq/2zM5hs0vxMYq4ulWbgwDKxd1mZNiHwxzS+8mdYe22
+P3WlkdrvSqnuDNXtGxYWhU2zEBjZ3rFN6WdD6bJHLkox3YTRafjNhLT4N3kbsV6C
+FeU44SBDrsiNEAWz8gy9hgH8TknEOTpMdpQnk7CNqA7q7wgGiFvFNwDukQKBgG7i
+R03Gs0XE5aRJtPN0N39fPyqvU24O/mqSekno2dWg6W6WHLQuFwo6whVc5UHuKl2D
+eISdnmT+RDuzJXxg6El7tgqByyEEAOQwQjYPB2Du/+tz3Z1KlG0mEJI/6xNVbany
+G6m7Gz9mUOMlXzaYmsjLRzbN/OsUAIDhqHm0+cuBAoGAZCND80akS3xr3yC87GyX
+aA0RoHXbdB6dbP8Y6XYDXR4QFIA4kXwY5cCLaZA/0hP5FOzDhORmaoaPM8vUdNyb
+IYvbw2H6tODiU5oICWY6+HQQ2nXikucI4HDYDLbsiV2htZkEmBYWLilYq0Tb8jC5
+u+ehIIvZYLqKaY1GaKmF86A=
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-4-server.pem b/FDBLibTLS/testdata/test-4-server.pem
new file mode 100644
index 0000000000..e80346e9b2
--- /dev/null
+++ b/FDBLibTLS/testdata/test-4-server.pem
@@ -0,0 +1,80 @@
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Server 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 1
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIJALOPTrQGpesjMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMTAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGIMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5vMRMwEQYDVQQKDApB
+cHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEoMCYGA1UEAwwfRkRCIExpYlRM
+UyBQbHVnaW4gVGVzdCBTZXJ2ZXIgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAJp26QAmlMusO7C8Py/I117r3kHvB+My5kIrj8g9sKpktwTzmsJGpvJU
+EaKISEdBsJHLGnZJhwIhr/+MG4WDEM4oFNCtBQZznV3wjIQWq1w4IO8/f3+nBPpW
+f14fjs1E911Uo/ZOL9bxvh1SIHkS6itgJi+tgVPx7C3s3W3mC5nU3omsE+Rx4DDm
+KUq1kyN1ELBIAceQ4wTmQ5B8dv6MSW7zt8Jdrhfhg2GJIPPB6XUZJ2yIOvgu55GW
+J5sMPa0uNDfCsWJ37fzFm+XJ/D96t7x8I49IyfzbIgcU9JYFlcqkryvKh5IpQGGm
+H/I6adIWa5xWpMhB2PA6kgtDD07Hu2sCAwEAAaNgMF4wHQYDVR0OBBYEFJ7S+FUz
+9ngzH/TNPVeM/cE7LeBGMB8GA1UdIwQYMBaAFCXTF7f83Hd7xm9gR+O4QrvjNo8Q
+MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBBQUAA4IB
+AQAx6WHwikVFAH0TRYCznwO6He+0t2pnlyfrI+24N28tzupMSrRPs086UbLgHLz1
+lbkYdheeOkLPzjWi5vfymL1Oua3E2iAXWEpMb4Sg7E5SVHp9yt6gZ0DTVwR+Gcu7
+uooroidAG3OFeOXL5ivU5J5ipaoEAiLprpKxtPzo4z/TxIqw3kJISC56qw9VTJNQ
+TQZvneUecykdIZuH61ih0cJLe5WRkEs/63Dgl8TBYiVDbvBSGRbsXoAXcspVlc2x
+XOLey5IVJ4/TH5ZBobShC6J1KrjZTNYvUgc44CocOgrc0ePPiQzB7JXxR1H8ATGl
+yKjWqT2PkrfHmjdcmsi2GIVt
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpeshMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyOwdOcYcH3wYou13CchsXh3lLWA85E550tT6/WwDnslQjiMZHFrKvUT2
+B8CUOR3Fr+4RG+cdw80rgojYEUuHKwmIGyjo5IotdaYbWzf6mvYThlIPPudCCkSU
+CTtqPv8Oq4QdIpCxHdix0MINKu7c+qt1rUwnDFQSv/gHhVnNxT4r8pwVp6T4hwka
+2YQaRNjzUuuFinMub0UtxnUX0rH8X5STlOSVn4Ksjo0OhQzsGEYDx86jVAXjgGcb
+2CgGGctgq04hVrngP5ahT1Xeh9YycMlQJXsckJJBxfUJebIjANSRyzxI5fYt+ZkY
+qoG5VLPREUQknxcpbT7Rsj0n+k0RhwIDAQABo2MwYTAdBgNVHQ4EFgQUJdMXt/zc
+d3vGb2BH47hCu+M2jxAwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAGwW7bRqB7aYUGsD1MOE9d5slp6Iw6wKyNLdg+mzoV+iCV2ZM7ejNRButiAy
+vPOxSQwXcibLm/g599e+LY1TiI1XXPbL2bFnTcnThqpHHFe+eRrDgqxO8qJyrcBp
+EfyMCJWq7jFg4bWoYTpLeC/RAKyi9fxlqY1NzQCp1bG3LiaDJ5VJd4uwkgX2a0yN
+3e0XEFNi7r4u4IHejwFjKWrDg8sstjbY+XOYC4EVQyUsbzeKZKSqnOdR2Jv1QZHH
+5O24G/efIFpsA6MVUOfRk0eq0RfKX7CdHn2a5p8aC6E6YMDhXL6xo146n49t9sYD
+HMUnfG6AEboTBa/l+zwCG/u4f/Y=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCadukAJpTLrDuw
+vD8vyNde695B7wfjMuZCK4/IPbCqZLcE85rCRqbyVBGiiEhHQbCRyxp2SYcCIa//
+jBuFgxDOKBTQrQUGc51d8IyEFqtcOCDvP39/pwT6Vn9eH47NRPddVKP2Ti/W8b4d
+UiB5EuorYCYvrYFT8ewt7N1t5guZ1N6JrBPkceAw5ilKtZMjdRCwSAHHkOME5kOQ
+fHb+jElu87fCXa4X4YNhiSDzwel1GSdsiDr4LueRliebDD2tLjQ3wrFid+38xZvl
+yfw/ere8fCOPSMn82yIHFPSWBZXKpK8ryoeSKUBhph/yOmnSFmucVqTIQdjwOpIL
+Qw9Ox7trAgMBAAECggEAOZAMvsCh/NDfobpVddJL6JTPzBRvBQ1H3+rp9z5+ItHL
+nq3Fw5aeynnn5IETJnLlgT+GSgSWqoWxV/N3oia40YsATs/bqo7VW1e0ldj43TIR
+m/c25XRxl3U6m/H4vqhv4rkTLUvv6hNGvRiI/3W8DJQVRvlK0+S5FlhKIJV1R0sH
+tp5vmaPp09Ln+NVno3u3iaYkVgVME4Ukul2i03sQ9OgvZSBCaVr//fMpiPdBeeN6
+QY6XHjeGQRnP/UdzMYJ4Qz1yovL1ntneaTMdz/GkKuAFoNNh8Vr2kiEskW17OWPB
+ZGcIT6YpBEPo34xXUhUQt7ylFPxGH+zZyHZ3vb8j6QKBgQDJPeu/iPg+M5nz5gO5
+ge9gzYrhxK/1mwbFlD7qt1NjOSm6xWxUcss3STjuG7jB0c+NopIUoq/egsUnxrRm
+4l17uOCYNLbhTJ2ynfv6QnUMxW5Xkve3DkLa2bze/fhMUywTy8N4A7z0+y35qzm3
+lY4rLmQOQKPkmqWRnxU1u8fjFQKBgQDEfpOZ0fp2D/1gTG+D+/zrMEbjnNn3ZO8I
+wrjoXwRxcRggt7lJhxgQpwtDr98IqYkDzX7bvyMFJuyTii3NM6NYycpA1pHX70B/
+xMvOcrgJnIUAoJ7nl43Or7s8bFTPDLaD9PNGHjrlkF3JOXqSKEbw367jHVOa4SYr
+OjrogjrEfwKBgQDHU2a7ax5+9btqggx0ZQfGOTBzmM60lZ3qe4CqGXUl1YvIrB01
+tBImq4cRCTJB/9/1qO3KNK2/1oUTddRgB5ySnDcRaz0tASc9sQ/Q/JxVTwSRB0gG
+78A2Zu6VbLbQWp1Q6kWtDP7PJC+QmRFtDlwn1yZRm6L6HlcaWpi2hU1iVQKBgCEu
+ashv8Aad3qCzZ6V3GReyOFZZd2lSjxcAou8ClKJ/gZ6Mx+pFuOee/cT5XwV8c5nD
+yuda2JQXJZ4omGFtlej5coEOeuRnD5JD7lK3hqKA3ujjNtJPAnBjto+Wj5/DOtL/
+u1Ec6782aNABN9SUnp4wd7z8h9DAsoxcMfRvgXMLAoGBAJ9gGttfqZbuPz9V0rAo
+p05SPPado1i5+2dUOScIbNB6+vQij9IlR2Tzu1T9DwzrBqTDPPmSggeA/JXeTvh6
+Skb9fDukizeDfwPYUN2gljhiJEqFdpRBr5vP0lFi291+a0jMW1zldrumxCcGKMyU
+D5ReKLp/zSQSQi/Wt4FF1II7
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-5-client.pem b/FDBLibTLS/testdata/test-5-client.pem
new file mode 100644
index 0000000000..a7b8ef6235
--- /dev/null
+++ b/FDBLibTLS/testdata/test-5-client.pem
@@ -0,0 +1,80 @@
+subject= C = AU, ST = New South Wales, L = Sydney, O = Apple Pty Limited, OU = FDB Team, CN = "FDB LibTLS Plugin Test Client 2, \C2\80 <\01+\02=\03>"
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIJALOPTrQGpesmMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMjAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGdMQswCQYDVQQGEwJBVTEYMBYG
+A1UECAwPTmV3IFNvdXRoIFdhbGVzMQ8wDQYDVQQHDAZTeWRuZXkxGjAYBgNVBAoM
+EUFwcGxlIFB0eSBMaW1pdGVkMREwDwYDVQQLDAhGREIgVGVhbTE0MDIGA1UEAwwr
+RkRCIExpYlRMUyBQbHVnaW4gVGVzdCBDbGllbnQgMiwgwoAgPAErAj0DPjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALanLExQi/yK2PRyu6Mvdw2MRxUs
+26kJftYuK7KtYyltTO3vtj4kNKg1vZI1eezhqr2Ta/1DzE76eLVs8EOW0LAb5oWM
+zXdYBXBX4vG+K7pYfjuvZUd6jfX2bHW10xC96HgDTfRn6dof8GR0fILJ6DoEcyI3
+82xnKKxTsgAuXU4uvcsl0g0F78nXuIbk8ZktTV3LIdbOCIcLQfG7DdDyAfEA0T7Q
+Vg6eeLknIUvPePxyWkUdYeSCDP2d+3NIlHMxNPmH1q3+fCsEsy/kqdVO9e6KrZla
+CKqnc6yYTXvTffpPepC3Igz678iGg3dv9rLj0i4fyTr4tEOTJebO9Ka3TbMCAwEA
+AaNgMF4wHQYDVR0OBBYEFKO2/D1IhG8KWFwR6OdyoFqEzIWAMB8GA1UdIwQYMBaA
+FJFP+HFpDrD0BRU0yE606s6xkqFBMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD
+AgeAMA0GCSqGSIb3DQEBBQUAA4IBAQAQV3FjsvZvwi5Oi/oSc7Du/BQS9nQ/D4j6
+IeYpd3M0y50awZB83BReYrhdC907xKkLRD0R8oEPDEg5SaSj3vRML4kaUUqnEINW
+4JQtv4wNO9CagYriGg8ygQa0xd683svHeXDet3ov11XN/Ms8lfDiOUp2291HgeTW
+8hqn1DaNfZrCb3EkdoNThwVKIUzQtEPBuPkLE+XT8kZP5d8KHmv8/9L39NdZY32d
+fzKGBeCxZ34pQS0cTap3rZ02nDfV2vNevODRyuqdhs7EQps2Oe1IfPB9GSE0OFUQ
+tdphxSjsv1BcHpTwBDpIITKarnceMIKxQjcZU3yPv5ibIaGCgZOt
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpesiMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEApTSBCiUb0amf+QRV2WY6b3bK93D/PSrm4KR/2m2V0lciU1DAk00/kZ52
+ZIZmq8g9EaE2+CaDtU0fMvDZpaZD+vTFRwsx4varehq0ZwX9Wt25i/3G/eGLNlD3
+9E4tDNruK5UQjum4nJ0SV+AdFEGkSfeU3ZJEHYH0NrcbyAUbh0KeWCSwHiYiFJJf
+gBYwRq/HdKNoS/4YvLXzTLR7BSm3YcqWlO5tdkJ2lcT/7Th/Hq1TCW/FKwdQJJBq
+JrbOYGlMrf1pLO7Drei/xhsYkwTQ899MhSjkBRhc+401p41Mky0n8wLkuPJGhoY3
+9QUOjT+Rmvq5yryg0eWGiFquk6Ru5QIDAQABo2MwYTAdBgNVHQ4EFgQUkU/4cWkO
+sPQFFTTITrTqzrGSoUEwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAJfCHU7dm2/2ASyt3wyxivQLxlV6FsEZcF7HcpbbxuB73frGOL4kEoOxvr2X
+fBGyjlPMotbc1MeAalAv+hVHdcAcBFPF7lxtYiV6D7YI5T5yVbWSASG3+DMAiW6S
+GdQi2eyeh00nH7Y1IkW+yaky0enBtWLzrw+XzHl6xT6DIEJnir//PNxvgXTJ5sjk
+6eFAm8HJIqkNQmgfChMQfUH6nm66WwULW6I117RCSkXhIgxZ7wzDq8bXcEdXCrZk
+yy5ket9OiVpbd38JgdYirBLmCQVq0uDOOPLz4ZJmNCzQzEt+38AAK2azAk/eb8W9
+JaKWH+5V8lhlyGw1zQKdNEP/wg8=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC2pyxMUIv8itj0
+crujL3cNjEcVLNupCX7WLiuyrWMpbUzt77Y+JDSoNb2SNXns4aq9k2v9Q8xO+ni1
+bPBDltCwG+aFjM13WAVwV+Lxviu6WH47r2VHeo319mx1tdMQveh4A030Z+naH/Bk
+dHyCyeg6BHMiN/NsZyisU7IALl1OLr3LJdINBe/J17iG5PGZLU1dyyHWzgiHC0Hx
+uw3Q8gHxANE+0FYOnni5JyFLz3j8clpFHWHkggz9nftzSJRzMTT5h9at/nwrBLMv
+5KnVTvXuiq2ZWgiqp3OsmE170336T3qQtyIM+u/IhoN3b/ay49IuH8k6+LRDkyXm
+zvSmt02zAgMBAAECggEAU2sYHSZwOH+FRGcd8RJdcg+N60rYa2QNzG27wVfUwPfN
+OaHP/qN0dRpOIPdRXvFVlE0+9aVAKxXTiTBers+zMascZgP/VrEZksxgtn1e5TVD
+OakKPVHogdvwfvXylmPVRvJjaOsIb3lExew5bVYfPFgJ6Sfagbi/Z6y1z8VdEbYb
+mI34KSZA4bBAMAHPZLa9TGEx/vbPsBlqpU6k8lcoy3cTkO5fCZW4ZZIpwBwef4uJ
+UozhRgtTtRBiUpk0F9IoOXonZY1Dtpg+HcDMti/FYgahBVe1hadJ+lbVTxH6GxyI
+NJYvptdq5S99UOoJDmCCih0v0ZCUNYWoO0I0vzNncQKBgQDemN7es2fIBstiPjOf
+p103DF5j9Uxq5YH9B3wli0CXf6Z2w5uosONoJWgJZKsHJ6f+YSuHsoE/eCrFF3U9
+lxT9Nie/wYYIGedly/VR143aCdiTXI44m5gxXgwaUcjvY1DpWyEAAmr5XNdoyZ5n
+LNTvOTb4vVo9SgDU7II7rdpRmwKBgQDSD9aBtIy/650suQK/9RiXRU0Kg7LXXVM5
+lavPgLvH55lufJeGSa8+ofCNeo31N4AaVuU4lkGeny9tLNBQbYAoyAz0lf51qK7B
+1u5JqBDyRrIpdkqwbT0FT1pu1LA3+Qg0KQBrTCnOx+YyyVSivR4YMZzJjmwZGKMg
+BWOi0PzhyQKBgGR44dfpaIWbs39zjf+ZHnTza0N4+/YgA60/DKUxloULRArFPeRF
+e0+N2siqnJvNJYGnQGuugbIxPjTZ4rxbDklAgW6HHkVX099Z0TAQuGFbIltZYoRg
+jrBxv8q9cZHD5Uh/LoT/kmNdqYkNwCbX0IDt9UcOyMVzOq7g1eO0FB/TAoGBAMaG
+tWIsMwGHOip0SAcHKtB8bI1NXo5v4yH/NDuOHOqXFcj383S02uzEu8XaV6Ozalx6
+V3SdfTLem0IBIneApajlOGlIAQ9N9qu358ixECMJcYQCCiCnfQ4xqvQoCss7judN
+ANpnRvPotMS2xkhvl6uh594NvlgRksnGjh3oibcRAoGBAJKiu5ajmIkelzAhFMEC
+Slxhg/E+djJ1/SG/FaF8zIyTOxre/QUvmTwFKtHe6A5EfKQo9GCTuHuAcJ1U7eQP
+l2BoY0POqJFpw3s/QOt4g/pOz0YjD9GD6awL5WDfO++s4mnI1Snc3wcu99N4Klax
+htsaEUECJBUF0ZpIFad73s2f
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/testdata/test-5-server.pem b/FDBLibTLS/testdata/test-5-server.pem
new file mode 100644
index 0000000000..7003635905
--- /dev/null
+++ b/FDBLibTLS/testdata/test-5-server.pem
@@ -0,0 +1,80 @@
+subject= C = AU, ST = New South Wales, L = Sydney, O = Apple Pty Limited, OU = FDB Team, CN = "FDB LibTLS Plugin Test Server 2, \C2\80 <\01+\02=\03>"
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+subject= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Intermediate CA 2
+issuer= C = US, ST = California, L = Cupertino, O = Apple Inc., OU = FDB Team, CN = FDB LibTLS Plugin Test Root CA
+-----BEGIN CERTIFICATE-----
+MIIEEzCCAvugAwIBAgIJALOPTrQGpeskMA0GCSqGSIb3DQEBBQUAMIGRMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTExMC8GA1UE
+AwwoRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBJbnRlcm1lZGlhdGUgQ0EgMjAeFw0x
+ODA0MDcxNDE2MDJaFw0yODA0MDQxNDE2MDJaMIGdMQswCQYDVQQGEwJBVTEYMBYG
+A1UECAwPTmV3IFNvdXRoIFdhbGVzMQ8wDQYDVQQHDAZTeWRuZXkxGjAYBgNVBAoM
+EUFwcGxlIFB0eSBMaW1pdGVkMREwDwYDVQQLDAhGREIgVGVhbTE0MDIGA1UEAwwr
+RkRCIExpYlRMUyBQbHVnaW4gVGVzdCBTZXJ2ZXIgMiwgwoAgPAErAj0DPjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALAolQZIGMeL5w/Bu2X6lHWjO58u
++HUDtBmr37So4jazhZBSFDBg+QlRMiYGLev9EhvCrUsVcRwtvtcuMI3wfKl7qgbi
+ZX8zmrzZ3YJo9U47NzCa05faOl8uSBvuXuXUBLU342WFP8XDB1W8yOBQMK73xoFv
+DkcxURx9ZtOhdC3EgYKrFqOB1Azl1DB4gLV3h9rHW5QpQ8SqD9CyggcDBpDeZQIP
++4l5YFE9Nb4kEUTscz2wGn4TdHMmcnVpfUxp1Y2o8Umvh4llXHIPhximGb3JJ4QQ
+Sir4ZXeeoooWoJG0sdlqVLroKav/VMGtEu9LyfbrNdKnTJq3ceVQ+HJ2hlMCAwEA
+AaNgMF4wHQYDVR0OBBYEFH61Z8O9vFsVdhM4MBU3poX2UMTEMB8GA1UdIwQYMBaA
+FJFP+HFpDrD0BRU0yE606s6xkqFBMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQD
+AgeAMA0GCSqGSIb3DQEBBQUAA4IBAQCVbxlLGIBCo6/XXjqoMyZc7uQZJj7pGnwh
+nIMs2izCLfax8j+QrThO2Qjn03zT/WF8eG6ibPbjgnw3VFwCkV6oQ+BXG6Yt0xqP
+4rz1LzxSio6HSm26gSk4SQUsVoAtz3OImoTCFVfz+Mixe87pyVXXEEtCYvfU74H9
+I1WGyNkWAxiJbqeIxF5PKoc3EdnT5mfdC6sdeGm7t2neeS8PDFQtJ4UfVIEK5z1C
+MOfQILNkLX2nBYxNqKpV66zf68VZNN9002ZH2FITGqImpj74BEws3sheiuZySdoI
+wnAwRnymIMfAmkf9C7Q2ugId0YMMyesaWrIwSlXlJOHGsA1VrBRD
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIJALOPTrQGpesiMA0GCSqGSIb3DQEBBQUAMIGHMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJQ3VwZXJ0aW5v
+MRMwEQYDVQQKDApBcHBsZSBJbmMuMREwDwYDVQQLDAhGREIgVGVhbTEnMCUGA1UE
+AwweRkRCIExpYlRMUyBQbHVnaW4gVGVzdCBSb290IENBMB4XDTE4MDQwNzE0MTYw
+MVoXDTI4MDQwNDE0MTYwMVowgZExCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRIwEAYDVQQHDAlDdXBlcnRpbm8xEzARBgNVBAoMCkFwcGxlIEluYy4x
+ETAPBgNVBAsMCEZEQiBUZWFtMTEwLwYDVQQDDChGREIgTGliVExTIFBsdWdpbiBU
+ZXN0IEludGVybWVkaWF0ZSBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEApTSBCiUb0amf+QRV2WY6b3bK93D/PSrm4KR/2m2V0lciU1DAk00/kZ52
+ZIZmq8g9EaE2+CaDtU0fMvDZpaZD+vTFRwsx4varehq0ZwX9Wt25i/3G/eGLNlD3
+9E4tDNruK5UQjum4nJ0SV+AdFEGkSfeU3ZJEHYH0NrcbyAUbh0KeWCSwHiYiFJJf
+gBYwRq/HdKNoS/4YvLXzTLR7BSm3YcqWlO5tdkJ2lcT/7Th/Hq1TCW/FKwdQJJBq
+JrbOYGlMrf1pLO7Drei/xhsYkwTQ899MhSjkBRhc+401p41Mky0n8wLkuPJGhoY3
+9QUOjT+Rmvq5yryg0eWGiFquk6Ru5QIDAQABo2MwYTAdBgNVHQ4EFgQUkU/4cWkO
+sPQFFTTITrTqzrGSoUEwHwYDVR0jBBgwFoAUnqtGja3O5jGlh5vHgp3Tf8NCPKkw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQAD
+ggEBAJfCHU7dm2/2ASyt3wyxivQLxlV6FsEZcF7HcpbbxuB73frGOL4kEoOxvr2X
+fBGyjlPMotbc1MeAalAv+hVHdcAcBFPF7lxtYiV6D7YI5T5yVbWSASG3+DMAiW6S
+GdQi2eyeh00nH7Y1IkW+yaky0enBtWLzrw+XzHl6xT6DIEJnir//PNxvgXTJ5sjk
+6eFAm8HJIqkNQmgfChMQfUH6nm66WwULW6I117RCSkXhIgxZ7wzDq8bXcEdXCrZk
+yy5ket9OiVpbd38JgdYirBLmCQVq0uDOOPLz4ZJmNCzQzEt+38AAK2azAk/eb8W9
+JaKWH+5V8lhlyGw1zQKdNEP/wg8=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCwKJUGSBjHi+cP
+wbtl+pR1ozufLvh1A7QZq9+0qOI2s4WQUhQwYPkJUTImBi3r/RIbwq1LFXEcLb7X
+LjCN8Hype6oG4mV/M5q82d2CaPVOOzcwmtOX2jpfLkgb7l7l1AS1N+NlhT/FwwdV
+vMjgUDCu98aBbw5HMVEcfWbToXQtxIGCqxajgdQM5dQweIC1d4fax1uUKUPEqg/Q
+soIHAwaQ3mUCD/uJeWBRPTW+JBFE7HM9sBp+E3RzJnJ1aX1MadWNqPFJr4eJZVxy
+D4cYphm9ySeEEEoq+GV3nqKKFqCRtLHZalS66Cmr/1TBrRLvS8n26zXSp0yat3Hl
+UPhydoZTAgMBAAECggEAVD60NlLYduXzVNfDtVuHEFNGOjSOYfepc/V8gLubo6lr
+IMAAI7rcnpYUM5cU8x0OQfRyR8wzUdSWxfWzBs6R78PSZoRzIcgeIl7Wzn0/g3BS
+To5czuxwqgBKQAFZpPQmZDwcJfr5qqxAn8IvFweCoMqiRlhELcvqDIP0XxWBqDjc
+TNJ988XzZXQmJbjjpWOkUBy2Uqz8lZt8MmxKFpW7SW4tBJwPphnorgjWfjCV/VEh
+ORio0rG74NHFo4f1TSrdU2BcB2cbVJ4B+bcUYRdvYmS5bmokhGF8vir0l43gUEdz
+Fyk6MaPrTI6cinqzenm3q/0eRvNhBE56U0tiGLn14QKBgQDkCkt1Y4LEboSwsVYl
+IXriStqj9p9MOizihh0enhzRXTTQuLX82fNi+bh1LAluwv290Q57pvKa+hB/YciB
+o4s7QfSojxQY9DxqvXN7CvxPWXHTyFY5sL4Rm807+C/a9rd39MxBynz9u/7YRvsA
+s8v8Y/01qIHnTo+mpDvu6HttWwKBgQDFwdRkgstuE+dXZZe8g1ivh3RNPa968TE3
+b8rzF9/nOJV7f6B/n6YEmHD/cHF5mm1bR+zt/jtf1NCRMpazchw3vT3JzQZYMDnM
+SD6vxTs5rG47QLiNyTIRmmD4gsEWBpyvoyP8E/9QdfDT1bWI5zZnky9CquRlN+cu
+J1bTsefEaQKBgGJsRxFNd91MThztDV9NSfptkFyAT1TZLxI+DEdwusNqVSdY8cNG
+VpP7cC+yaAfURSwuFPAtqDxXfdNc4uuBKNDUsMInrubuUz1Gs5cBsNCWrFhZ+U1B
+CWgUNMqTXiRFo/40PAyRVs003NOAH0m4UGyIw3rrVdX9xGaKMAv3b35NAoGATkkl
+I4UDs1f9xQNaxi3Y9ePRjqJUzX6d1SxUU1eoM4ia5IDpsJwqxLb0RKrmwRT5JaGb
+kbuLFazRxCkar38E3Kv1weWAFXlB6DTRXBPgFjzEhoBgjwCO6ZkLulVIysdjT8Rt
+gmUINXn7FGENtFyTlP0XQHUWZVt0ETlRjgxni8ECgYBYv6MoSr0iPjQpxeKvwFDz
+d9zE+ZXN+3GwtkI340lKRSc/f0Uq1TlC2w+DzjyyXcrBwubMQKTKcQQSH9f3YbMu
+DuxVE9AXdlQ1gSQHGjS0qUWwsS/8Xcjk8ZuduAXPGr/MsvsW+FbbZqG8qdZTeMHu
+MSTpOxu9HXC8SHML+y0cpw==
+-----END PRIVATE KEY-----
diff --git a/FDBLibTLS/verify-test.cpp b/FDBLibTLS/verify-test.cpp
new file mode 100644
index 0000000000..406f69577c
--- /dev/null
+++ b/FDBLibTLS/verify-test.cpp
@@ -0,0 +1,137 @@
+#include
+#include
+#include
+
+#include
+
+#include "ITLSPlugin.h"
+#include "ReferenceCounted.h"
+
+#include "FDBLibTLSPlugin.h"
+#include "FDBLibTLSPolicy.h"
+
+struct FDBLibTLSVerifyTest {
+ FDBLibTLSVerifyTest(std::string input):
+ input(input), valid(false), verify_cert(true), verify_time(true), subject_criteria({}), issuer_criteria({}) {};
+ FDBLibTLSVerifyTest(std::string input, bool verify_cert, bool verify_time, std::map subject, std::map issuer):
+ input(input), valid(true), verify_cert(verify_cert), verify_time(verify_time), subject_criteria(subject), issuer_criteria(issuer) {};
+ ~FDBLibTLSVerifyTest() {};
+
+ int run();
+
+ std::string input;
+
+ bool valid;
+ bool verify_cert;
+ bool verify_time;
+
+ std::map subject_criteria;
+ std::map issuer_criteria;
+};
+
+static std::string printable( std::string const& val ) {
+ static char const digits[] = "0123456789ABCDEF";
+ std::string s;
+
+ for ( int i = 0; i < val.size(); i++ ) {
+ uint8_t b = val[i];
+ if (b >= 32 && b < 127 && b != '\\')
+ s += (char)b;
+ else if (b == '\\')
+ s += "\\\\";
+ else {
+ s += "\\x";
+ s += digits[(b >> 4) & 15];
+ s += digits[b & 15];
+ }
+ }
+ return s;
+}
+
+static std::string criteriaToString(std::map const& criteria) {
+ std::string s;
+ for (auto &pair: criteria) {
+ s += "{" + std::to_string(pair.first) + ":" + printable(pair.second) + "}";
+ }
+ return "{" + s + "}";
+}
+
+static void logf(const char* event, void* uid, int is_error, ...) {
+}
+
+int FDBLibTLSVerifyTest::run() {
+ FDBLibTLSPlugin *plugin = new FDBLibTLSPlugin();
+ FDBLibTLSPolicy *policy = new FDBLibTLSPolicy(Reference::addRef(plugin), (ITLSLogFunc)logf);
+
+ bool rc = policy->set_verify_peers((const uint8_t *)input.c_str(), input.size());
+ if (rc != valid) {
+ if (valid) {
+ std::cerr << "FAIL: Verify test failed, but should have succeeded - '" << input << "'\n";
+ return 1;
+ } else {
+ std::cerr << "FAIL: Verify test should have failed, but succeeded - '" << input << "'\n";
+ return 1;
+ }
+ }
+ if (policy->verify_cert != verify_cert) {
+ std::cerr << "FAIL: Got verify cert " << policy->verify_cert << ", want " << verify_cert << "\n";
+ return 1;
+ }
+ if (policy->verify_time != verify_time) {
+ std::cerr << "FAIL: Got verify time " << policy->verify_time << ", want " << verify_time << "\n";
+ return 1;
+ }
+ if (policy->subject_criteria != subject_criteria) {
+ std::cerr << "FAIL: Got subject criteria " << criteriaToString(policy->subject_criteria) << ", want " << criteriaToString(subject_criteria) << "\n";
+ return 1;
+ }
+ if (policy->issuer_criteria != issuer_criteria) {
+ std::cerr << "FAIL: Got issuer criteria " << criteriaToString(policy->issuer_criteria) << ", want " << criteriaToString(issuer_criteria) << "\n";
+ return 1;
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ int failed = 0;
+
+ std::vector tests = {
+ FDBLibTLSVerifyTest("", true, true, {}, {}),
+ FDBLibTLSVerifyTest("Check.Valid=1", true, true, {}, {}),
+ FDBLibTLSVerifyTest("Check.Valid=0", false, true, {}, {}),
+ FDBLibTLSVerifyTest("Check.Unexpired=1", true, true, {}, {}),
+ FDBLibTLSVerifyTest("Check.Unexpired=0", true, false, {}, {}),
+ FDBLibTLSVerifyTest("Check.Valid=1,Check.Unexpired=0", true, false, {}, {}),
+ FDBLibTLSVerifyTest("Check.Unexpired=0,Check.Valid=0", false, false, {}, {}),
+ FDBLibTLSVerifyTest("Check.Unexpired=0,I.C=US,C=US,S.O=XYZCorp\\, LLC", true, false,
+ {{NID_countryName, "US"}, {NID_organizationName, "XYZCorp, LLC"}}, {{NID_countryName, "US"}}),
+ FDBLibTLSVerifyTest("Check.Unexpired=0,I.C=US,C=US,S.O=XYZCorp\\= LLC", true, false,
+ {{NID_countryName, "US"}, {NID_organizationName, "XYZCorp= LLC"}}, {{NID_countryName, "US"}}),
+ FDBLibTLSVerifyTest("Check.Unexpired=0,I.C=US,C=US,S.O=XYZCorp=LLC", true, false,
+ {{NID_countryName, "US"}, {NID_organizationName, "XYZCorp=LLC"}}, {{NID_countryName, "US"}}),
+ FDBLibTLSVerifyTest("I.C=US,C=US,Check.Unexpired=0,S.O=XYZCorp=LLC", true, false,
+ {{NID_countryName, "US"}, {NID_organizationName, "XYZCorp=LLC"}}, {{NID_countryName, "US"}}),
+ FDBLibTLSVerifyTest("I.C=US,C=US,S.O=XYZCorp\\, LLC", true, true,
+ {{NID_countryName, "US"}, {NID_organizationName, "XYZCorp, LLC"}}, {{NID_countryName, "US"}}),
+ FDBLibTLSVerifyTest("C=\\,S=abc", true, true, {{NID_countryName, ",S=abc"}}, {}),
+ FDBLibTLSVerifyTest("CN=\\61\\62\\63", true, true, {{NID_commonName, "abc"}}, {}),
+ FDBLibTLSVerifyTest("CN=a\\62c", true, true, {{NID_commonName, "abc"}}, {}),
+ FDBLibTLSVerifyTest("CN=a\\01c", true, true, {{NID_commonName, "a\001c"}}, {}),
+
+ // Invalid cases.
+ FDBLibTLSVerifyTest("Check.Invalid=0"),
+ FDBLibTLSVerifyTest("Valid=1"),
+ FDBLibTLSVerifyTest("C= US,S=abc"),
+ FDBLibTLSVerifyTest("C=#US,S=abc"),
+ FDBLibTLSVerifyTest("C=abc,S=\\"),
+ FDBLibTLSVerifyTest("XYZ=abc"),
+ FDBLibTLSVerifyTest("GN=abc"),
+ FDBLibTLSVerifyTest("CN=abc,Check.Expired=1"),
+ };
+
+ for (auto &test: tests)
+ failed |= test.run();
+
+ return (failed);
+}
diff --git a/Makefile b/Makefile
index cfba0e6601..702570cc29 100644
--- a/Makefile
+++ b/Makefile
@@ -92,7 +92,7 @@ STATIC_LIBS :=
VPATH += $(addprefix :,$(filter-out lib,$(patsubst -L%,%,$(filter -L%,$(LDFLAGS)))))
CS_PROJECTS := flow/actorcompiler flow/coveragetool fdbclient/vexillographer
-CPP_PROJECTS := flow fdbrpc fdbclient fdbbackup fdbserver fdbcli bindings/c bindings/java fdbmonitor bindings/flow/tester bindings/flow
+CPP_PROJECTS := flow fdbrpc fdbclient fdbbackup fdbserver fdbcli bindings/c bindings/java fdbmonitor bindings/flow/tester bindings/flow FDBLibTLS
OTHER_PROJECTS := bindings/python bindings/ruby bindings/go
CS_MK_GENERATED := $(CS_PROJECTS:=/generated.mk)
@@ -148,7 +148,7 @@ clean: $(CLEAN_TARGETS) docpreview_clean
@echo "Cleaning toplevel"
@rm -rf $(OBJDIR)
@rm -rf $(DEPSDIR)
- @rm -rf lib/libstdc++.a
+ @rm -rf lib/
@rm -rf bin/coverage.*.xml
targets:
diff --git a/build/Dockerfile b/build/Dockerfile
index feed88dda5..a5b69e6c5f 100644
--- a/build/Dockerfile
+++ b/build/Dockerfile
@@ -2,7 +2,7 @@ FROM ubuntu:15.04
RUN sed -i -e 's/archive.ubuntu.com\|security.ubuntu.com/old-releases.ubuntu.com/g' -e 's/us\.old/old/g' /etc/apt/sources.list && apt-get clean && apt-get update
-RUN apt-get --no-install-recommends install -y --force-yes bzip2 ca-certificates=20141019 adduser apt base-files base-passwd bash binutils build-essential cpp cpp-4.9 dpkg dos2unix fakeroot findutils g++=4:4.9.2-2ubuntu2 g++-4.9=4.9.2-10ubuntu13 gawk=1:4.1.1+dfsg-1 gcc-5-base gcc=4:4.9.2-2ubuntu2 gcc-4.9=4.9.2-10ubuntu13 gcc-4.9-base:amd64=4.9.2-10ubuntu13 gcc-5-base:amd64=5.1~rc1-0ubuntu1 gdb git golang golang-go golang-go-linux-amd64 golang-src grep gzip hostname java-common libasan1 liblsan0 libtsan0 libubsan0 libcilkrts5 libgcc-4.9-dev libstdc++-4.9-dev libgl1-mesa-dri libgl1-mesa-glx libmono-system-xml-linq4.0-cil libmono-system-data-datasetextensions4.0-cil libstdc++-4.9-pic locales login m4 make makedev mawk mono-dmcs npm openjdk-8-jdk passwd python-distlib python-gevent python-greenlet python-html5lib python-minimal python-pip python-pkg-resources python-requests python-setuptools python-six python-urllib3 python-yaml python2.7 python2.7-minimal rpm rpm2cpio ruby ruby2.1 rubygems-integration sed tar texinfo tzdata-java udev unzip util-linux valgrind vim wget golang-go.tools curl sphinx-common
+RUN apt-get --no-install-recommends install -y --force-yes bzip2 ca-certificates=20141019 adduser apt base-files base-passwd bash binutils build-essential cpp cpp-4.9 dpkg dos2unix fakeroot findutils g++=4:4.9.2-2ubuntu2 g++-4.9=4.9.2-10ubuntu13 gawk=1:4.1.1+dfsg-1 gcc-5-base gcc=4:4.9.2-2ubuntu2 gcc-4.9=4.9.2-10ubuntu13 gcc-4.9-base:amd64=4.9.2-10ubuntu13 gcc-5-base:amd64=5.1~rc1-0ubuntu1 gdb git golang golang-go golang-go-linux-amd64 golang-src grep gzip hostname java-common libasan1 liblsan0 libtsan0 libubsan0 libcilkrts5 libgcc-4.9-dev libstdc++-4.9-dev libgl1-mesa-dri libgl1-mesa-glx libmono-system-xml-linq4.0-cil libmono-system-data-datasetextensions4.0-cil libstdc++-4.9-pic locales login m4 make makedev mawk mono-dmcs npm openjdk-8-jdk passwd python-distlib python-gevent python-greenlet python-html5lib python-minimal python-pip python-pkg-resources python-requests python-setuptools python-six python-urllib3 python-yaml python2.7 python2.7-minimal rpm rpm2cpio ruby ruby2.1 rubygems-integration sed tar texinfo tzdata-java udev unzip util-linux valgrind vim wget golang-go.tools curl sphinx-common gnupg
RUN adduser --disabled-password --gecos '' fdb && chown -R fdb /opt && chmod -R 0777 /opt
@@ -14,10 +14,16 @@ USER root
RUN pip install boto3==1.1.1
-RUN npm install -g npm@3.4.1
-
RUN ln -s /usr/bin/nodejs /usr/bin/node
+RUN cd /opt/ && wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.6.4.tar.gz &&\
+ wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-2.6.4.tar.gz.asc &&\
+ wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl.asc &&\
+ gpg --import libressl.asc && gpg --verify libressl-2.6.4.tar.gz.asc libressl-2.6.4.tar.gz &&\
+ tar -xzf libressl-2.6.4.tar.gz && cd libressl-2.6.4 &&\
+ ./configure CFLAGS="-fPIC -O3" && make -j4 && make install &&\
+ cd /opt/ # && rm -r libressl-2.6.4/ libressl-2.6.4.tar.gz libressl-2.6.4.tar.gz.asc libressl.asc
+
RUN LANGUAGE=en_US.UTF-8 LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 locale-gen en_US.UTF-8
RUN dpkg-reconfigure locales