1 /*
2  * TLSConnection.actor.cpp
3  *
4  * This source file is part of the FoundationDB open source project
5  *
6  * Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #include <memory>
22 #include "flow/flow.h"
23 #include "flow/network.h"
24 #include "flow/Knobs.h"
25 #include "fdbrpc/TLSConnection.h"
26 #include "fdbrpc/ITLSPlugin.h"
27 #include "fdbrpc/LoadPlugin.h"
28 #include "fdbrpc/Platform.h"
29 #include "fdbrpc/IAsyncFile.h"
30 #include "flow/actorcompiler.h"  // This must be the last #include.
31 
32 // Name of specialized TLS Plugin
33 const char* tlsPluginName = "fdb-libressl-plugin";
34 
35 // Must not throw an exception from this function!
send_func(void * ctx,const uint8_t * buf,int len)36 static int send_func(void* ctx, const uint8_t* buf, int len) {
37 	TLSConnection* conn = (TLSConnection*)ctx;
38 
39 	try {
40 		SendBuffer sb;
41 		sb.bytes_sent = 0;
42 		sb.bytes_written = len;
43 		sb.data = buf;
44 		sb.next = 0;
45 
46 		int w = conn->conn->write( &sb );
47 		return w;
48 	} catch ( Error& e ) {
49 		TraceEvent("TLSConnectionSendError", conn->getDebugID()).suppressFor(1.0).detail("Peer", conn->getPeerAddress().toString()).error(e);
50 		return -1;
51 	} catch ( ... ) {
52 		TraceEvent("TLSConnectionSendError", conn->getDebugID()).suppressFor(1.0).detail("Peer", conn->getPeerAddress()).error( unknown_error() );
53 		return -1;
54 	}
55 }
56 
57 // Must not throw an exception from this function!
recv_func(void * ctx,uint8_t * buf,int len)58 static int recv_func(void* ctx, uint8_t* buf, int len) {
59 	TLSConnection* conn = (TLSConnection*)ctx;
60 
61 	try {
62 		int r = conn->conn->read( buf, buf + len );
63 		return r;
64 	} catch ( Error& e ) {
65 		TraceEvent("TLSConnectionRecvError", conn->getDebugID()).suppressFor(1.0).detail("Peer", conn->getPeerAddress()).error(e);
66 		return -1;
67 	} catch ( ... ) {
68 		TraceEvent("TLSConnectionRecvError", conn->getDebugID()).suppressFor(1.0).detail("Peer", conn->getPeerAddress()).error( unknown_error() );
69 		return -1;
70 	}
71 }
72 
handshake(TLSConnection * self)73 ACTOR static Future<Void> handshake( TLSConnection* self ) {
74 	loop {
75 		int r = self->session->handshake();
76 		if ( r == ITLSSession::SUCCESS ) break;
77 		if ( r == ITLSSession::FAILED ) {
78 			TraceEvent("TLSConnectionHandshakeError", self->getDebugID()).suppressFor(1.0).detail("Peer", self->getPeerAddress());
79 			throw connection_failed();
80 		}
81 		ASSERT( r == ITLSSession::WANT_WRITE || r == ITLSSession::WANT_READ );
82 		wait( r == ITLSSession::WANT_WRITE ? self->conn->onWritable() : self->conn->onReadable() );
83 	}
84 
85 	TraceEvent("TLSConnectionHandshakeSuccessful", self->getDebugID()).suppressFor(1.0).detail("Peer", self->getPeerAddress());
86 
87 	return Void();
88 }
89 
TLSConnection(Reference<IConnection> const & conn,Reference<ITLSPolicy> const & policy,bool is_client,std::string host)90 TLSConnection::TLSConnection( Reference<IConnection> const& conn, Reference<ITLSPolicy> const& policy, bool is_client, std::string host) : conn(conn), write_wants(0), read_wants(0), uid(conn->getDebugID()) {
91 	const char * serverName = host.empty() ? NULL : host.c_str();
92 	session = Reference<ITLSSession>( policy->create_session(is_client, serverName, send_func, this, recv_func, this, (void*)&uid) );
93 	if ( !session ) {
94 		// If session is NULL, we're trusting policy->create_session
95 		// to have used its provided logging function to have logged
96 		// the error
97 		throw tls_error();
98 	}
99 	handshook = handshake(this);
100 }
101 
onWritable()102 Future<Void> TLSConnection::onWritable() {
103 	if ( !handshook.isReady() )
104 		return handshook;
105 	return
106 		write_wants == ITLSSession::WANT_READ ? conn->onReadable() :
107 		write_wants == ITLSSession::WANT_WRITE ? conn->onWritable() :
108 		Void();
109 }
110 
onReadable()111 Future<Void> TLSConnection::onReadable() {
112 	if ( !handshook.isReady() )
113 		return handshook;
114 	return
115 		read_wants == ITLSSession::WANT_READ ? conn->onReadable() :
116 		read_wants == ITLSSession::WANT_WRITE ? conn->onWritable() :
117 		Void();
118 }
119 
read(uint8_t * begin,uint8_t * end)120 int TLSConnection::read( uint8_t* begin, uint8_t* end ) {
121 	if ( !handshook.isReady() ) return 0;
122 	handshook.get();
123 
124 	read_wants = 0;
125 	int r = session->read( begin, end - begin );
126 	if ( r > 0 )
127 		return r;
128 
129 	if ( r == ITLSSession::FAILED ) throw connection_failed();
130 
131 	ASSERT( r == ITLSSession::WANT_WRITE || r == ITLSSession::WANT_READ );
132 
133 	read_wants = r;
134 	return 0;
135 }
136 
write(SendBuffer const * buffer,int limit)137 int TLSConnection::write( SendBuffer const* buffer, int limit ) {
138 	ASSERT(limit > 0);
139 
140 	if ( !handshook.isReady() ) return 0;
141 	handshook.get();
142 
143 	write_wants = 0;
144 	int toSend = std::min(limit, buffer->bytes_written - buffer->bytes_sent);
145 	ASSERT(toSend);
146 	int w = session->write( buffer->data + buffer->bytes_sent, toSend );
147 	if ( w > 0 )
148 		return w;
149 
150 	if ( w == ITLSSession::FAILED ) throw connection_failed();
151 
152 	ASSERT( w == ITLSSession::WANT_WRITE || w == ITLSSession::WANT_READ );
153 
154 	write_wants = w;
155 	return 0;
156 }
157 
wrap(Reference<ITLSPolicy> policy,bool is_client,Future<Reference<IConnection>> c,std::string host)158 ACTOR Future<Reference<IConnection>> wrap( Reference<ITLSPolicy> policy, bool is_client, Future<Reference<IConnection>> c, std::string host) {
159 	Reference<IConnection> conn = wait(c);
160 	return Reference<IConnection>(new TLSConnection( conn, policy, is_client, host ));
161 }
162 
accept()163 Future<Reference<IConnection>> TLSListener::accept() {
164 	return wrap( options->get_policy(TLSOptions::POLICY_VERIFY_PEERS), false, listener->accept(), "");
165 }
166 
TLSNetworkConnections(Reference<TLSOptions> options)167 TLSNetworkConnections::TLSNetworkConnections( Reference<TLSOptions> options ) : options(options) {
168 	network = INetworkConnections::net();
169 	g_network->setGlobal(INetwork::enumGlobal::enNetworkConnections, (flowGlobalType) this);
170 }
171 
connect(NetworkAddress toAddr,std::string host)172 Future<Reference<IConnection>> TLSNetworkConnections::connect( NetworkAddress toAddr, std::string host) {
173 	if ( toAddr.isTLS() ) {
174 		NetworkAddress clearAddr( toAddr.ip, toAddr.port, toAddr.isPublic(), false );
175 		TraceEvent("TLSConnectionConnecting").suppressFor(1.0).detail("ToAddr", toAddr);
176 		// For FDB<->FDB connections, we don't have hostnames and can't verify IP
177 		// addresses against certificates, so we have our own peer verifying logic
178 		// to use. For FDB<->external system connections, we can use the standard
179 		// hostname-based certificate verification logic.
180 		if (host.empty() || host == toAddr.ip.toString())
181 			return wrap(options->get_policy(TLSOptions::POLICY_VERIFY_PEERS), true, network->connect(clearAddr), std::string(""));
182 		else
183 			return wrap( options->get_policy(TLSOptions::POLICY_NO_VERIFY_PEERS), true, network->connect( clearAddr ), host );
184 	}
185 	return network->connect( toAddr );
186 }
187 
resolveTCPEndpoint(std::string host,std::string service)188 Future<std::vector<NetworkAddress>> TLSNetworkConnections::resolveTCPEndpoint( std::string host, std::string service) {
189 	return network->resolveTCPEndpoint( host, service );
190 }
191 
listen(NetworkAddress localAddr)192 Reference<IListener> TLSNetworkConnections::listen( NetworkAddress localAddr ) {
193 	if ( localAddr.isTLS() ) {
194 		NetworkAddress clearAddr( localAddr.ip, localAddr.port, localAddr.isPublic(), false );
195 		TraceEvent("TLSConnectionListening").detail("OnAddr", localAddr);
196 		return Reference<IListener>(new TLSListener( options, network->listen( clearAddr ) ));
197 	}
198 	return network->listen( localAddr );
199 }
200 
201 // 5MB for loading files into memory
202 #define CERT_FILE_MAX_SIZE (5 * 1024 * 1024)
203 
set_cert_file(std::string const & cert_file)204 void TLSOptions::set_cert_file( std::string const& cert_file ) {
205 	try {
206 		TraceEvent("TLSConnectionSettingCertFile").detail("CertFilePath", cert_file);
207 		policyInfo.cert_path = cert_file;
208 		set_cert_data( readFileBytes( cert_file, CERT_FILE_MAX_SIZE ) );
209 	} catch ( Error& e) {
210 		TraceEvent(SevError, "TLSOptionsSetCertFileError").detail("Filename", cert_file).error(e).GetLastError();
211 		throw;
212 	}
213 }
214 
set_ca_file(std::string const & ca_file)215 void TLSOptions::set_ca_file(std::string const& ca_file) {
216 	try {
217 		TraceEvent("TLSConnectionSettingCAFile").detail("CAPath", ca_file);
218 		policyInfo.ca_path = ca_file;
219 		set_ca_data(readFileBytes(ca_file, CERT_FILE_MAX_SIZE));
220 	}
221 	catch (Error& e) {
222 		TraceEvent(SevError, "TLSOptionsSetCertAError").detail("Filename", ca_file).error(e).GetLastError();
223 		throw;
224 	}
225 }
226 
set_ca_data(std::string const & ca_data)227 void TLSOptions::set_ca_data(std::string const& ca_data) {
228 	if (!policyVerifyPeersSet.get() || !policyVerifyPeersNotSet.get())
229 		init_plugin();
230 
231 	TraceEvent("TLSConnectionSettingCAData").detail("CADataSize", ca_data.size());
232 	policyInfo.ca_contents = Standalone<StringRef>(ca_data);
233 	if (!policyVerifyPeersSet.get()->set_ca_data((const uint8_t*)&ca_data[0], ca_data.size()))
234 		throw tls_error();
235 	if (!policyVerifyPeersNotSet.get()->set_ca_data((const uint8_t*)&ca_data[0], ca_data.size()))
236 		throw tls_error();
237 
238 	ca_set = true;
239 }
240 
set_cert_data(std::string const & cert_data)241 void TLSOptions::set_cert_data( std::string const& cert_data ) {
242 	if (!policyVerifyPeersSet.get() || !policyVerifyPeersNotSet.get())
243 		init_plugin();
244 
245 	TraceEvent("TLSConnectionSettingCertData").detail("CertDataSize", cert_data.size());
246 	policyInfo.cert_contents = Standalone<StringRef>(cert_data);
247 	if ( !policyVerifyPeersSet.get()->set_cert_data( (const uint8_t*)&cert_data[0], cert_data.size() ) )
248 		throw tls_error();
249 	if (!policyVerifyPeersNotSet.get()->set_cert_data((const uint8_t*)&cert_data[0], cert_data.size()))
250 		throw tls_error();
251 
252 	certs_set = true;
253 }
254 
set_key_password(std::string const & password)255 void TLSOptions::set_key_password(std::string const& password) {
256 	TraceEvent("TLSConnectionSettingPassword");
257 	policyInfo.keyPassword = password;
258 }
259 
set_key_file(std::string const & key_file)260 void TLSOptions::set_key_file( std::string const& key_file ) {
261 	try {
262 		TraceEvent("TLSConnectionSettingKeyFile").detail("KeyFilePath", key_file);
263 		policyInfo.key_path = key_file;
264 		set_key_data( readFileBytes( key_file, CERT_FILE_MAX_SIZE ) );
265 	} catch ( Error& e) {
266 		TraceEvent(SevError, "TLSOptionsSetKeyFileError").detail("Filename", key_file).error(e).GetLastError();
267 		throw;
268 	}
269 }
270 
set_key_data(std::string const & key_data)271 void TLSOptions::set_key_data( std::string const& key_data ) {
272 	if (!policyVerifyPeersSet.get() || !policyVerifyPeersNotSet.get())
273 		init_plugin();
274 	const char *passphrase = policyInfo.keyPassword.empty() ? NULL : policyInfo.keyPassword.c_str();
275 	TraceEvent("TLSConnectionSettingKeyData").detail("KeyDataSize", key_data.size());
276 	policyInfo.key_contents = Standalone<StringRef>(key_data);
277 	if ( !policyVerifyPeersSet.get()->set_key_data( (const uint8_t*)&key_data[0], key_data.size(), passphrase) )
278 		throw tls_error();
279 	if (!policyVerifyPeersNotSet.get()->set_key_data((const uint8_t*)&key_data[0], key_data.size(), passphrase))
280 		throw tls_error();
281 
282 	key_set = true;
283 }
284 
set_verify_peers(std::vector<std::string> const & verify_peers)285 void TLSOptions::set_verify_peers( std::vector<std::string> const& verify_peers ) {
286 	if (!policyVerifyPeersSet.get())
287 		init_plugin();
288 	{
289 		TraceEvent e("TLSConnectionSettingVerifyPeers");
290 		for (int i = 0; i < verify_peers.size(); i++)
291 			e.detail(std::string("Value" + std::to_string(i)).c_str(), verify_peers[i].c_str());
292 	}
293 	std::unique_ptr<const uint8_t *[]> verify_peers_arr(new const uint8_t*[verify_peers.size()]);
294 	std::unique_ptr<int[]> verify_peers_len(new int[verify_peers.size()]);
295 	for (int i = 0; i < verify_peers.size(); i++) {
296 		verify_peers_arr[i] = (const uint8_t *)&verify_peers[i][0];
297 		verify_peers_len[i] = verify_peers[i].size();
298 	}
299 
300 	if (!policyVerifyPeersSet.get()->set_verify_peers(verify_peers.size(), verify_peers_arr.get(), verify_peers_len.get()))
301 		throw tls_error();
302 
303 	policyInfo.verify_peers = verify_peers;
304 	verify_peers_set = true;
305 }
306 
register_network()307 void TLSOptions::register_network() {
308 	// Simulation relies upon being able to call this multiple times, and have it override g_network
309 	// each time it's called.
310 	new TLSNetworkConnections( Reference<TLSOptions>::addRef( this ) );
311 }
312 
readEntireFile(std::string filename)313 ACTOR static Future<ErrorOr<Standalone<StringRef>>> readEntireFile( std::string filename ) {
314 	state Reference<IAsyncFile> file = wait(IAsyncFileSystem::filesystem()->open(filename, IAsyncFile::OPEN_READONLY | IAsyncFile::OPEN_UNCACHED, 0));
315 	state int64_t filesize = wait(file->size());
316 	state Standalone<StringRef> buf = makeString(filesize);
317 	int rc = wait(file->read(mutateString(buf), filesize, 0));
318 	if (rc != filesize) {
319 		// File modified during read, probably.  The mtime should change, and thus we'll be called again.
320 		return tls_error();
321 	}
322 	return buf;
323 }
324 
watchFileForChanges(std::string filename,AsyncVar<Standalone<StringRef>> * contents_var)325 ACTOR static Future<Void> watchFileForChanges( std::string filename, AsyncVar<Standalone<StringRef>> *contents_var ) {
326 	state std::time_t lastModTime = wait(IAsyncFileSystem::filesystem()->lastWriteTime(filename));
327 	loop {
328 		wait(delay(FLOW_KNOBS->TLS_CERT_REFRESH_DELAY_SECONDS));
329 		std::time_t modtime = wait(IAsyncFileSystem::filesystem()->lastWriteTime(filename));
330 		if (lastModTime != modtime) {
331 			lastModTime = modtime;
332 			ErrorOr<Standalone<StringRef>> contents = wait(readEntireFile(filename));
333 			if (contents.present()) {
334 				contents_var->set(contents.get());
335 			}
336 		}
337 	}
338 }
339 
reloadConfigurationOnChange(TLSOptions::PolicyInfo * pci,Reference<ITLSPlugin> plugin,AsyncVar<Reference<ITLSPolicy>> * realVerifyPeersPolicy,AsyncVar<Reference<ITLSPolicy>> * realNoVerifyPeersPolicy)340 ACTOR static Future<Void> reloadConfigurationOnChange( TLSOptions::PolicyInfo *pci, Reference<ITLSPlugin> plugin, AsyncVar<Reference<ITLSPolicy>> *realVerifyPeersPolicy, AsyncVar<Reference<ITLSPolicy>> *realNoVerifyPeersPolicy ) {
341 	if (FLOW_KNOBS->TLS_CERT_REFRESH_DELAY_SECONDS <= 0) {
342 		return Void();
343 	}
344 	loop {
345 		// Early in bootup, the filesystem might not be initialized yet.  Wait until it is.
346 		if (IAsyncFileSystem::filesystem() != nullptr) {
347 			break;
348 		}
349 		wait(delay(1.0));
350 	}
351 	state int mismatches = 0;
352 	state AsyncVar<Standalone<StringRef>> ca_var;
353 	state AsyncVar<Standalone<StringRef>> key_var;
354 	state AsyncVar<Standalone<StringRef>> cert_var;
355 	state std::vector<Future<Void>> lifetimes;
356 	if (!pci->ca_path.empty()) lifetimes.push_back(watchFileForChanges(pci->ca_path, &ca_var));
357 	if (!pci->key_path.empty()) lifetimes.push_back(watchFileForChanges(pci->key_path, &key_var));
358 	if (!pci->cert_path.empty()) lifetimes.push_back(watchFileForChanges(pci->cert_path, &cert_var));
359 	loop {
360 		state Future<Void> ca_changed = ca_var.onChange();
361 		state Future<Void> key_changed = key_var.onChange();
362 		state Future<Void> cert_changed = cert_var.onChange();
363 		wait( ca_changed || key_changed || cert_changed );
364 		if (ca_changed.isReady()) {
365 			TraceEvent(SevInfo, "TLSRefreshCAChanged").detail("path", pci->ca_path).detail("length", ca_var.get().size());
366 			pci->ca_contents = ca_var.get();
367 		}
368 		if (key_changed.isReady()) {
369 			TraceEvent(SevInfo, "TLSRefreshKeyChanged").detail("path", pci->key_path).detail("length", key_var.get().size());
370 			pci->key_contents = key_var.get();
371 		}
372 		if (cert_changed.isReady()) {
373 			TraceEvent(SevInfo, "TLSRefreshCertChanged").detail("path", pci->cert_path).detail("length", cert_var.get().size());
374 			pci->cert_contents = cert_var.get();
375 		}
376 		bool rc = true;
377 		Reference<ITLSPolicy> verifypeers = Reference<ITLSPolicy>(plugin->create_policy());
378 		Reference<ITLSPolicy> noverifypeers = Reference<ITLSPolicy>(plugin->create_policy());
379 		loop {
380 			// Don't actually loop.  We're just using loop/break as a `goto err`.
381 			// This loop always ends with an unconditional break.
382 			rc = verifypeers->set_ca_data(pci->ca_contents.begin(), pci->ca_contents.size());
383 			if (!rc) break;
384 			rc = verifypeers->set_key_data(pci->key_contents.begin(), pci->key_contents.size(), pci->keyPassword.c_str());
385 			if (!rc) break;
386 			rc = verifypeers->set_cert_data(pci->cert_contents.begin(), pci->cert_contents.size());
387 			if (!rc) break;
388 			{
389 				std::unique_ptr<const uint8_t *[]> verify_peers_arr(new const uint8_t*[pci->verify_peers.size()]);
390 				std::unique_ptr<int[]> verify_peers_len(new int[pci->verify_peers.size()]);
391 				for (int i = 0; i < pci->verify_peers.size(); i++) {
392 					verify_peers_arr[i] = (const uint8_t *)&pci->verify_peers[i][0];
393 					verify_peers_len[i] = pci->verify_peers[i].size();
394 				}
395 				rc = verifypeers->set_verify_peers(pci->verify_peers.size(), verify_peers_arr.get(), verify_peers_len.get());
396 				if (!rc) break;
397 			}
398 			rc = noverifypeers->set_ca_data(pci->ca_contents.begin(), pci->ca_contents.size());
399 			if (!rc) break;
400 			rc = noverifypeers->set_key_data(pci->key_contents.begin(), pci->key_contents.size(), pci->keyPassword.c_str());
401 			if (!rc) break;
402 			rc = noverifypeers->set_cert_data(pci->cert_contents.begin(), pci->cert_contents.size());
403 			if (!rc) break;
404 			break;
405 		}
406 
407 		if (rc) {
408 			TraceEvent(SevInfo, "TLSCertificateRefreshSucceeded");
409 			realVerifyPeersPolicy->set(verifypeers);
410 			realNoVerifyPeersPolicy->set(noverifypeers);
411 			mismatches = 0;
412 		} else {
413 			// Some files didn't match up, they should in the future, and we'll retry then.
414 			mismatches++;
415 			TraceEvent(SevWarn, "TLSCertificateRefreshMismatch").detail("mismatches", mismatches);
416 		}
417 	}
418 }
419 
420 const char *defaultCertFileName = "fdb.pem";
421 
get_policy(PolicyType type)422 Reference<ITLSPolicy> TLSOptions::get_policy(PolicyType type) {
423 	if ( !certs_set ) {
424 		if ( !platform::getEnvironmentVar( "FDB_TLS_CERTIFICATE_FILE", policyInfo.cert_path ) )
425 			policyInfo.cert_path = fileExists(defaultCertFileName) ? defaultCertFileName : joinPath(platform::getDefaultConfigPath(), defaultCertFileName);
426 		set_cert_file( policyInfo.cert_path );
427 	}
428 	if ( !key_set ) {
429 		if ( policyInfo.keyPassword.empty() )
430 			platform::getEnvironmentVar( "FDB_TLS_PASSWORD", policyInfo.keyPassword );
431 		if ( !platform::getEnvironmentVar( "FDB_TLS_KEY_FILE", policyInfo.key_path ) )
432 			policyInfo.key_path = fileExists(defaultCertFileName) ? defaultCertFileName : joinPath(platform::getDefaultConfigPath(), defaultCertFileName);
433 		set_key_file( policyInfo.key_path );
434 	}
435 	if( !verify_peers_set ) {
436 		std::string verify_peers;
437 		if (platform::getEnvironmentVar("FDB_TLS_VERIFY_PEERS", verify_peers))
438 			set_verify_peers({ verify_peers });
439 		else
440 			set_verify_peers({ std::string("Check.Valid=1")});
441 	}
442 	if (!ca_set) {
443 		if (platform::getEnvironmentVar("FDB_TLS_CA_FILE", policyInfo.ca_path))
444 			set_ca_file(policyInfo.ca_path);
445 	}
446 
447 	if (!configurationReloader.present()) {
448 		configurationReloader = reloadConfigurationOnChange(&policyInfo, plugin, &policyVerifyPeersSet, &policyVerifyPeersNotSet);
449 	}
450 
451 	Reference<ITLSPolicy> policy;
452 	switch (type) {
453 	case POLICY_VERIFY_PEERS:
454 		policy = policyVerifyPeersSet.get();
455 		break;
456 	case POLICY_NO_VERIFY_PEERS:
457 		policy = policyVerifyPeersNotSet.get();
458 		break;
459 	default:
460 		ASSERT_ABORT(0);
461 	}
462 	return policy;
463 }
464 
init_plugin()465 void TLSOptions::init_plugin() {
466 
467 	TraceEvent("TLSConnectionLoadingPlugin").detail("Plugin", tlsPluginName);
468 
469 	plugin = loadPlugin<ITLSPlugin>( tlsPluginName );
470 
471 	if ( !plugin ) {
472 		TraceEvent(SevError, "TLSConnectionPluginInitError").detail("Plugin", tlsPluginName).GetLastError();
473 		throw tls_error();
474 	}
475 
476 	policyVerifyPeersSet = AsyncVar<Reference<ITLSPolicy>>(Reference<ITLSPolicy>(plugin->create_policy()));
477 	if ( !policyVerifyPeersSet.get()) {
478 		// Hopefully create_policy logged something with the log func
479 		TraceEvent(SevError, "TLSConnectionCreatePolicyVerifyPeersSetError");
480 		throw tls_error();
481 	}
482 
483 	policyVerifyPeersNotSet = AsyncVar<Reference<ITLSPolicy>>(Reference<ITLSPolicy>(plugin->create_policy()));
484 	if (!policyVerifyPeersNotSet.get()) {
485 		// Hopefully create_policy logged something with the log func
486 		TraceEvent(SevError, "TLSConnectionCreatePolicyVerifyPeersNotSetError");
487 		throw tls_error();
488 	}
489 }
490 
enabled()491 bool TLSOptions::enabled() {
492 	return policyVerifyPeersSet.get().isValid() && policyVerifyPeersNotSet.get().isValid();
493 }
494