1 /**
2 	OpenSSL based SSL/TLS stream implementation
3 
4 	Copyright: © 2012-2014 Sönke Ludwig
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Sönke Ludwig
7 */
8 module vibe.stream.openssl;
9 version(Have_openssl):
10 import vibe.core.log;
11 import vibe.core.net;
12 import vibe.core.stream;
13 import vibe.core.sync;
14 import vibe.stream.tls;
15 import vibe.internal.interfaceproxy : InterfaceProxy;
16 
17 import std.algorithm;
18 import std.array;
19 import std.conv;
20 import std.exception;
21 import std.socket;
22 import std.string;
23 
24 import core.stdc.string : strlen;
25 import core.sync.mutex;
26 import core.thread;
27 
28 /**************************************************************************************************/
29 /* Public types                                                                                   */
30 /**************************************************************************************************/
31 
32 import deimos.openssl.bio;
33 import deimos.openssl.err;
34 import deimos.openssl.opensslv;
35 import deimos.openssl.rand;
36 import deimos.openssl.ssl;
37 import deimos.openssl.stack;
38 import deimos.openssl.x509v3;
39 
40 version (VibePragmaLib) {
41 	pragma(lib, "ssl");
42 	version (Windows) pragma(lib, "eay");
43 }
44 
45 version(VibeForceALPN) enum alpn_forced = true;
46 else enum alpn_forced = false;
47 enum haveALPN = OPENSSL_VERSION_NUMBER >= 0x10200000 || alpn_forced;
48 
49 // openssl/1.1.0 hack: provides a 1.0.x API in terms of the 1.1.x API
50 static if (OPENSSL_VERSION_AT_LEAST(1, 1, 0)) {
51 	extern(C) const(SSL_METHOD)* TLS_client_method();
52 	alias SSLv23_client_method = TLS_client_method;
53 
54 	extern(C) const(SSL_METHOD)* TLS_server_method();
55 	alias SSLv23_server_method = TLS_server_method;
56 
57 	// #define SSL_get_ex_new_index(l, p, newf, dupf, freef) \
58 	//    CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL, l, p, newf, dupf, freef)
59 
60 	extern(C) int CRYPTO_get_ex_new_index(int class_index, c_long argl, void *argp,
61 	                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
62 	                            CRYPTO_EX_free *free_func);
63 
64 	int SSL_get_ex_new_index(c_long argl, void *argp,
65 	                            CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
66 	                            CRYPTO_EX_free *free_func) {
67 		// # define CRYPTO_EX_INDEX_SSL              0
68 		return CRYPTO_get_ex_new_index(0, argl, argp, new_func, dup_func,
69 				free_func);
70 	}
71 
72 	extern(C) BIGNUM* BN_get_rfc3526_prime_2048(BIGNUM *bn);
73 
74 	alias get_rfc3526_prime_2048 = BN_get_rfc3526_prime_2048;
75 
76 	// #  define sk_num OPENSSL_sk_num
77 	static if (!is(typeof(OPENSSL_sk_num)))
78 	{
79 		extern(C) int OPENSSL_sk_num(const void *);
80 		extern(C) int sk_num(const(_STACK)* p) { return OPENSSL_sk_num(p); }
81 	}
82 
83 	// #  define sk_value OPENSSL_sk_value
84 	static if (!is(typeof(OPENSSL_sk_value)))
85 	{
86 		extern(C) void *OPENSSL_sk_value(const void *, int);
87 		extern(C) void* sk_value(const(_STACK)* p, int i) { return OPENSSL_sk_value(p, i); }
88 	}
89 
90 	static if (!is(typeof(OPENSSL_sk_free)))
91 	{
92 		// Version v1.x.x of the bindings don't have this,
93 		// but it's been available since v1.1.0
94 		private extern(C) void *OPENSSL_sk_free(const void *);
95 	}
96 
97 	private enum SSL_CTRL_SET_MIN_PROTO_VERSION = 123;
98 	private enum SSL_CTRL_SET_MAX_PROTO_VERSION = 124;
99 
100 	private int SSL_CTX_set_min_proto_version(ssl_ctx_st* ctx, int ver) {
101 		return cast(int) SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, ver, null);
102 	}
103 
104 	private int SSL_CTX_set_max_proto_version(ssl_ctx_st* ctx, int ver) {
105 		return cast(int) SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, ver, null);
106 	}
107 
108 	private int SSL_set_min_proto_version(ssl_st* s, int ver) {
109 		return cast(int) SSL_ctrl(s, SSL_CTRL_SET_MIN_PROTO_VERSION, ver, null);
110 	}
111 
112 	extern(C) nothrow {
113 		void BIO_set_init(BIO* bio, int init_) @trusted;
114 		int BIO_get_init(BIO* bio) @trusted;
115 		void BIO_set_data(BIO* bio, void* ptr) @trusted;
116 		void* BIO_get_data(BIO* bio) @trusted;
117 		void BIO_set_shutdown(BIO* bio, int shut) @trusted;
118 		int BIO_get_shutdown(BIO* bio) @trusted;
119 		void BIO_clear_flags(BIO* b, int flags) @trusted;
120 		int BIO_test_flags(BIO* b, int flags) @trusted;
121 		void BIO_set_flags(BIO* b, int flags) @trusted;
122 
123 		alias BIOMethWriteCallback = int function(BIO*, const(char)*, int);
124 		alias BIOMethReadCallback = int function(BIO*, const(char)*, int);
125 		alias BIOMethCtrlCallback = c_long function(BIO*, int, c_long, void*);
126 		alias BIOMethCreateCallback = int function(BIO*);
127 		alias BIOMethDestroyCallback = int function(BIO*);
128 
129 		int BIO_get_new_index();
130 		BIO_METHOD* BIO_meth_new(int type, const(char)* name);
131 		void BIO_meth_free(BIO_METHOD* biom);
132 		int BIO_meth_set_write(BIO_METHOD* biom, BIOMethWriteCallback cb);
133 		int BIO_meth_set_read(BIO_METHOD* biom, BIOMethReadCallback cb);
134 		int BIO_meth_set_ctrl(BIO_METHOD* biom, BIOMethCtrlCallback cb);
135 		int BIO_meth_set_create(BIO_METHOD* biom, BIOMethCreateCallback cb);
136 		int BIO_meth_set_destroy(BIO_METHOD* biom, BIOMethDestroyCallback cb);
137 	}
138 
139 	static if (OPENSSL_VERSION_AT_LEAST(3, 0, 0)) {
140 		extern (C) nothrow {
141 			X509 *SSL_get1_peer_certificate(const SSL *ssl);
142 			void ERR_new();
143 			void ERR_set_debug(const char *file, int line, const char *func);
144 			void ERR_set_error(int lib, int reason, const char *fmt, ...);
145 		}
146 
147 		alias SSL_get_peer_certificate = SSL_get1_peer_certificate;
148 	}
149 } else {
150 	private void BIO_set_init(BIO* b, int init_) @safe nothrow {
151 		b.init_ = 1;
152 	}
153 	private int BIO_get_init(BIO* b) @safe nothrow {
154 		return b.init_;
155 	}
156 	private void BIO_set_data(BIO* b, void* ptr) @safe nothrow {
157 		b.ptr = ptr;
158 	}
159 	private void* BIO_get_data(BIO* b) @safe nothrow {
160 		return b.ptr;
161 	}
162 	private void BIO_set_shutdown(BIO* b, int shut) @safe nothrow {
163 		b.shutdown = shut;
164 	}
165 	private int BIO_get_shutdown(BIO* b) @safe nothrow {
166 		return b.shutdown;
167 	}
168 	private void BIO_clear_flags(BIO *b, int flags) @safe nothrow {
169 		b.flags &= ~flags;
170 	}
171 	private int BIO_test_flags(BIO *b, int flags) @safe nothrow {
172 		return (b.flags & flags);
173 	}
174 	private void BIO_set_flags(BIO *b, int flags) @safe nothrow {
175 		b.flags |= flags;
176 	}
177 
178 	// OpenSSL 1.1 renamed `sk_*` to OpenSSL_sk_*`
179 	private alias OPENSSL_sk_free = sk_free;
180 
181 	// Temporary hack: Deimos OpenSSL v3.0.1 is missing bindings for OpenSSL v1.0.x
182 	// Until it's updated, we have duplicates here, see:
183 	// https://github.com/vibe-d/vibe.d/pull/2658
184 	// https://github.com/vibe-d/vibe.d/pull/2661
185 	extern(C) const(SSL_METHOD)* SSLv23_client_method();
186 	extern(C) const(SSL_METHOD)* SSLv23_server_method();
187 
188 	extern(C) int CRYPTO_num_locks();
189 	extern(C) void CRYPTO_set_locking_callback(
190 		void function(int mode, int type, const(char)* file, int line) func);
191 }
192 
193 // Copied from https://github.com/D-Programming-Deimos/openssl/pull/69
194 // Remove once we are depending on >= v3.0.2
195 static if (OPENSSL_VERSION_AT_LEAST(3, 0, 0))
196 {
197 	 // The argument type for `SSL_[CTX_][gs]et_options was changed between 1.1.1
198 	 // and 3.0.0, from `c_long` to `uint64_t`. See below commit.
199 	 // https://github.com/openssl/openssl/commit/56bd17830f2d5855b533d923d4e0649d3ed61d11
200 
201 	extern(C) nothrow {
202 		ulong SSL_CTX_get_options(const SSL_CTX* ctx);
203 		ulong SSL_get_options(const SSL* ssl);
204 		ulong SSL_CTX_clear_options(SSL_CTX* ctx, ulong op);
205 		ulong SSL_clear_options(SSL* ssl, ulong op);
206 		ulong SSL_CTX_set_options(SSL_CTX* ctx, ulong op);
207 		ulong SSL_set_options(SSL* ssl, ulong op);
208 	}
209 }
210 else static if (OPENSSL_VERSION_AT_LEAST(1, 1, 0))
211 {
212 	// Note: Despite the manuals listing the return type (as well as parameter)
213 	// as 'long', the `.h` was `unsigned long`.
214 
215 	extern(C) nothrow {
216 		c_ulong SSL_CTX_get_options(const SSL_CTX* ctx);
217 		c_ulong SSL_get_options(const SSL* ssl);
218 		c_ulong SSL_CTX_clear_options(SSL_CTX* ctx, c_ulong op);
219 		c_ulong SSL_clear_options(SSL* ssl, c_ulong op);
220 		c_ulong SSL_CTX_set_options(SSL_CTX* ctx, c_ulong op);
221 		c_ulong SSL_set_options(SSL* ssl, c_ulong op);
222 	}
223 }
224 else
225 {
226 	// Before v1.1.0, those were macros. See below commit.
227 	// https://github.com/openssl/openssl/commit/8106cb8b6d706079cbcabd4631f05e4526a316e1
228 
229 	extern(C) nothrow {
230 		c_ulong SSL_CTX_set_options()(SSL_CTX* ctx, c_ulong op) {
231 			return SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, op, null);
232 		}
233 		c_ulong SSL_CTX_clear_options()(SSL_CTX* ctx, c_ulong op) {
234 			return SSL_CTX_ctrl(ctx, SSL_CTRL_CLEAR_OPTIONS, op, null);
235 		}
236 		c_ulong SSL_CTX_get_options()(SSL_CTX* ctx) {
237 			return SSL_CTX_ctrl(ctx, SSL_CTRL_OPTIONS, 0, null);
238 		}
239 		c_ulong SSL_set_options()(SSL* ssl,op) {
240 			return SSL_ctrl(ssl, SSL_CTRL_OPTIONS, op, null);
241 		}
242 		c_ulong SSL_clear_options()(SSL* ssl, c_long op) {
243 			return SSL_ctrl(ssl, SSL_CTRL_CLEAR_OPTIONS, op, null);
244 		}
245 		c_ulong SSL_get_options()(SSL* ssl) {
246 			return SSL_ctrl(ssl, SSL_CTRL_OPTIONS, 0, null);
247 		}
248 	}
249 
250 	// The need for calling `CRYPTO_set_id_callback` / `CRYPTO_set_locking_callback`
251 	// was removed in OpenSSL 1.1.0, which are the only users of those callbacks
252 	// and mutexes.
253 	private __gshared InterruptibleTaskMutex[] g_cryptoMutexes;
254 
255 	private extern(C) c_ulong onCryptoGetThreadID() nothrow @safe
256 	{
257 		try {
258 			return cast(c_ulong)(cast(size_t)() @trusted { return cast(void*)Thread.getThis(); } () * 0x35d2c57);
259 		} catch (Exception e) {
260 			logWarn("OpenSSL: failed to get current thread ID: %s", e.msg);
261 			return 0;
262 		}
263 	}
264 
265 	private extern(C) void onCryptoLock(int mode, int n, const(char)* file, int line) nothrow @safe
266 	{
267 		try {
268 			enforce(n >= 0 && n < () @trusted { return g_cryptoMutexes; } ().length, "Mutex index out of range.");
269 			auto mutex = () @trusted { return g_cryptoMutexes[n]; } ();
270 			assert(mutex !is null);
271 			if (mode & CRYPTO_LOCK) mutex.lock();
272 			else mutex.unlock();
273 		} catch (Exception e) {
274 			logWarn("OpenSSL: failed to lock/unlock mutex: %s", e.msg);
275 		}
276 	}
277 }
278 
279 // Deimos had an incorrect translation for this define prior to 2.0.2+1.1.0h
280 // See https://github.com/D-Programming-Deimos/openssl/issues/63#issuecomment-840266138
281 static if (!is(typeof(GEN_DNS)))
282 {
283 	private enum GEN_DNS = GENERAL_NAME.GEN_DNS;
284 	private enum GEN_IPADD = GENERAL_NAME.GEN_IPADD;
285 }
286 
287 private int SSL_set_tlsext_host_name(ssl_st* s, const(char)* c) @trusted {
288 	return cast(int) SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, cast(void*)c);
289 }
290 
291 /**
292 	Creates an SSL/TLS tunnel within an existing stream.
293 
294 	Note: Be sure to call finalize before finalizing/closing the outer stream so that the SSL
295 		tunnel is properly closed first.
296 */
297 final class OpenSSLStream : TLSStream {
298 @safe:
299 
300 	private {
301 		InterfaceProxy!Stream m_stream;
302 		TLSContext m_tlsCtx;
303 		TLSStreamState m_state;
304 		SSLState m_tls;
305 		BIO* m_bio;
306 		ubyte[64] m_peekBuffer;
307 		TLSCertificateInformation m_peerCertificateInfo;
308 		X509* m_peerCertificate;
309 	}
310 
311 	this(InterfaceProxy!Stream underlying, OpenSSLContext ctx, TLSStreamState state, string peer_name = null, NetworkAddress peer_address = NetworkAddress.init, string[] alpn = null)
312 	{
313 		// sanity check to distinguish any error that might have slipped
314 		// somewhere else from errors generated here
315 		validateSSLErrors();
316 
317 		m_stream = underlying;
318 		m_state = state;
319 		m_tlsCtx = ctx;
320 		m_tls = ctx.createClientCtx();
321 		scope (failure) {
322 			() @trusted { SSL_free(m_tls); } ();
323 			m_tls = null;
324 		}
325 
326 		static if (OPENSSL_VERSION_AT_LEAST(1, 1, 0)) {
327 			if (!s_bio_methods) initBioMethods();
328 
329 			m_bio = () @trusted { return BIO_new(s_bio_methods); } ();
330 		} else
331 			m_bio = () @trusted { return BIO_new(&s_bio_methods); } ();
332 		enforce(m_bio !is null, "SSL failed: failed to create BIO structure.");
333 		BIO_set_init(m_bio, 1);
334 		BIO_set_data(m_bio, () @trusted { return cast(void*)this; } ()); // lifetime is shorter than this, so no GC.addRange needed.
335 		BIO_set_shutdown(m_bio, 0);
336 
337 		() @trusted { SSL_set_bio(m_tls, m_bio, m_bio); } ();
338 
339 		if (state != TLSStreamState.connected) {
340 			OpenSSLContext.VerifyData vdata;
341 			vdata.verifyDepth = ctx.maxCertChainLength;
342 			vdata.validationMode = ctx.peerValidationMode;
343 			vdata.callback = ctx.peerValidationCallback;
344 			vdata.peerName = peer_name;
345 			vdata.peerAddress = peer_address;
346 			checkSSLRet(() @trusted { return SSL_set_ex_data(m_tls, gs_verifyDataIndex, &vdata); } (), "Setting SSL user data");
347 			scope (exit) () @trusted { SSL_set_ex_data(m_tls, gs_verifyDataIndex, null); } ();
348 
349 			final switch (state) {
350 				case TLSStreamState.accepting:
351 					//SSL_set_accept_state(m_tls);
352 					checkSSLRet(() @trusted { return SSL_accept(m_tls); } (), "Accepting SSL tunnel");
353 					break;
354 				case TLSStreamState.connecting:
355 					// a client stream can override the default ALPN setting for this context
356 					if (alpn.length) setClientALPN(alpn);
357 					if (peer_name.length)
358 						SSL_set_tlsext_host_name(m_tls, peer_name.toStringz);
359 					//SSL_set_connect_state(m_tls);
360 					validateSSLErrors();
361 					checkSSLRet(() @trusted { return SSL_connect(m_tls); } (), "Connecting TLS tunnel");
362 					break;
363 				case TLSStreamState.connected:
364 					break;
365 			}
366 
367 			// ensure that the SSL tunnel gets terminated when an error happens during verification
368 			scope (failure) () @trusted { SSL_shutdown(m_tls); } ();
369 
370 			m_peerCertificate = () @trusted { return SSL_get_peer_certificate(m_tls); } ();
371 			if (m_peerCertificate) {
372 				readPeerCertInfo();
373 				auto result = () @trusted { return SSL_get_verify_result(m_tls); } ();
374 				if (result == X509_V_OK && (ctx.peerValidationMode & TLSPeerValidationMode.checkPeer)) {
375 					if (!verifyCertName(m_peerCertificate, GEN_DNS, vdata.peerName)) {
376 						version(Windows) import core.sys.windows.winsock2;
377 						else import core.sys.posix.netinet.in_;
378 
379 						logDiagnostic("TLS peer name '%s' couldn't be verified, trying IP address.", vdata.peerName);
380 						char* addr;
381 						int addrlen;
382 						switch (vdata.peerAddress.family) {
383 							default: break;
384 							case AF_INET:
385 								addr = cast(char*)&vdata.peerAddress.sockAddrInet4.sin_addr;
386 								addrlen = vdata.peerAddress.sockAddrInet4.sin_addr.sizeof;
387 								break;
388 							case AF_INET6:
389 								addr = cast(char*)&vdata.peerAddress.sockAddrInet6.sin6_addr;
390 								addrlen = vdata.peerAddress.sockAddrInet6.sin6_addr.sizeof;
391 								break;
392 						}
393 
394 						if (!verifyCertName(m_peerCertificate, GEN_IPADD, () @trusted { return addr[0 .. addrlen]; } ())) {
395 							logDiagnostic("Error validating TLS peer address");
396 							result = X509_V_ERR_APPLICATION_VERIFICATION;
397 						}
398 					}
399 				}
400 
401 				enforce(result == X509_V_OK, "Peer failed the certificate validation: "~to!string(result));
402 			} //else enforce(ctx.verifyMode < requireCert);
403 		}
404 	}
405 
406 	/** Read certificate info into the clientInformation field */
407 	private void readPeerCertInfo()
408 	{
409 		X509_NAME* name = () @trusted { return X509_get_subject_name(m_peerCertificate); } ();
410 
411 		int c = () @trusted { return X509_NAME_entry_count(name); } ();
412 		foreach (i; 0 .. c) {
413 			X509_NAME_ENTRY *e = () @trusted { return X509_NAME_get_entry(name, i); } ();
414 			ASN1_OBJECT *obj = () @trusted { return X509_NAME_ENTRY_get_object(e); } ();
415 			ASN1_STRING *val = () @trusted { return X509_NAME_ENTRY_get_data(e); } ();
416 
417 			auto longName = () @trusted { return OBJ_nid2ln(OBJ_obj2nid(obj)).to!string; } ();
418 			auto valStr = () @trusted { return cast(string)val.data[0 .. val.length]; } (); // FIXME: .idup?
419 
420 			m_peerCertificateInfo.subjectName.addField(longName, valStr);
421 		}
422 		m_peerCertificateInfo._x509 = m_peerCertificate;
423 	}
424 
425 	~this()
426 	{
427 		if (m_peerCertificate) () @trusted { X509_free(m_peerCertificate); } ();
428 		if (m_tls) () @trusted { SSL_free(m_tls); } ();
429 	}
430 
431 	@property bool empty()
432 	{
433 		return leastSize() == 0;
434 	}
435 
436 	@property ulong leastSize()
437 	{
438 		if(m_tls == null) return 0;
439 
440 		auto ret = () @trusted { return SSL_peek(m_tls, m_peekBuffer.ptr, 1); } ();
441 		if (ret != 0) // zero means the connection got closed
442 			checkSSLRet(ret, "Peeking TLS stream");
443 		return () @trusted { return SSL_pending(m_tls); } ();
444 	}
445 
446 	@property bool dataAvailableForRead()
447 	{
448 		return () @trusted { return SSL_pending(m_tls); } () > 0 || m_stream.dataAvailableForRead;
449 	}
450 
451 	const(ubyte)[] peek()
452 	{
453 		auto ret = checkSSLRet(() @trusted { return SSL_peek(m_tls, m_peekBuffer.ptr, m_peekBuffer.length); } (), "Peeking TLS stream");
454 		return ret > 0 ? m_peekBuffer[0 .. ret] : null;
455 	}
456 
457 	size_t read(scope ubyte[] dst, IOMode mode)
458 	{
459 		size_t nbytes = 0;
460 		if(m_tls == null)
461 			throw new Exception("Reading from closed stream");
462 
463 		while (dst.length > 0) {
464 			int readlen = min(dst.length, int.max);
465 			auto ret = checkSSLRet(() @trusted { return SSL_read(m_tls, dst.ptr, readlen); } (), "Reading from TLS stream");
466 			//logTrace("SSL read %d/%d", ret, dst.length);
467 			dst = dst[ret .. $];
468 			nbytes += ret;
469 
470 			if (mode == IOMode.immediate || mode == IOMode.once)
471 				break;
472 		}
473 
474 		return nbytes;
475 	}
476 
477 	alias read = Stream.read;
478 
479 	size_t write(in ubyte[] bytes_, IOMode mode)
480 	{
481 		const(ubyte)[] bytes = bytes_;
482 
483 		size_t nbytes = 0;
484 
485 		while (bytes.length > 0) {
486 			int writelen = min(bytes.length, int.max);
487 			auto ret = checkSSLRet(() @trusted { return SSL_write(m_tls, bytes.ptr, writelen); } (), "Writing to TLS stream");
488 			//logTrace("SSL write %s", cast(string)bytes[0 .. ret]);
489 			bytes = bytes[ret .. $];
490 			nbytes += ret;
491 
492 			if (mode == IOMode.immediate || mode == IOMode.once)
493 				break;
494 		}
495 
496 		return nbytes;
497 	}
498 
499 	alias write = Stream.write;
500 
501 	void flush()
502 	{
503 		m_stream.flush();
504 	}
505 
506 	void finalize()
507 	{
508 		if( !m_tls ) return;
509 		logTrace("OpenSSLStream finalize");
510 
511 		() @trusted {
512 			auto ret = SSL_shutdown(m_tls);
513 			if (ret != 0) checkSSLRet(ret, "SSL_shutdown");
514 			SSL_free(m_tls);
515 			ERR_clear_error();
516 		} ();
517 
518 		m_tls = null;
519 		m_stream = InterfaceProxy!Stream.init;
520 	}
521 
522 	private void validateSSLErrors()
523 	@safe {
524 		auto err = () @trusted { return ERR_get_error(); } ();
525 		if (err != SSL_ERROR_NONE) {
526 			throw new Exception("OpenSSL error occured previously: " ~ processSSLError(err));
527 		}
528 	}
529 
530 	private int checkSSLRet(int ret, string what)
531 	@safe {
532 		if (ret > 0) return ret;
533 
534 		auto err = () @trusted { return SSL_get_error(m_tls, ret); } ();
535 		string desc = processSSLError(err, what);
536 
537 		enforce(ret != 0, format("%s was unsuccessful with ret 0", what));
538 		enforce(ret >= 0, format("%s returned an error: %s", what, desc));
539 		return ret;
540 	}
541 
542 	private string processSSLError(c_ulong err, string what = "OpenSSL")
543 	@safe {
544 		string desc;
545 		switch (err) {
546 			default: desc = format("Unknown error (%s)", err); break;
547 			case SSL_ERROR_NONE: desc = "No error"; break;
548 			case SSL_ERROR_ZERO_RETURN: desc = "SSL/TLS tunnel closed"; break;
549 			case SSL_ERROR_WANT_READ: desc = "Need to block for read"; break;
550 			case SSL_ERROR_WANT_WRITE: desc = "Need to block for write"; break;
551 			case SSL_ERROR_WANT_CONNECT: desc = "Need to block for connect"; break;
552 			case SSL_ERROR_WANT_ACCEPT: desc = "Need to block for accept"; break;
553 			case SSL_ERROR_WANT_X509_LOOKUP: desc = "Need to block for certificate lookup"; break;
554 			case SSL_ERROR_SYSCALL:
555 				version (linux) {
556 					import core.sys.linux.errno : errno;
557 					import core.stdc.string : strerror;
558 
559 					desc = format("non-recoverable socket I/O error: %s (%s)", errno, (() @trusted => strerror(errno).to!string)());
560 				} else {
561 					desc = "non-recoverable socket I/O error";
562 				}
563 				break;
564 			case SSL_ERROR_SSL:
565 				throwSSL(what);
566 				assert(false);
567 		}
568 
569 		const(char)* file = null, data = null;
570 		int line;
571 		int flags;
572 		c_ulong eret;
573 		char[120] ebuf;
574 		while( (eret = () @trusted { return ERR_get_error_line_data(&file, &line, &data, &flags); } ()) != 0 ){
575 			() @trusted { ERR_error_string(eret, ebuf.ptr); } ();
576 			logDebug("%s error at %s:%d: %s (%s)", what,
577 				() @trusted { return to!string(file); } (), line,
578 				() @trusted { return to!string(ebuf.ptr); } (),
579 				flags & ERR_TXT_STRING ? () @trusted { return to!string(data); } () : "-");
580 		}
581 
582 		return desc;
583 	}
584 
585 	@property TLSCertificateInformation peerCertificate()
586 	{
587 		return m_peerCertificateInfo;
588 	}
589 
590 	@property X509* peerCertificateX509()
591 	{
592 		return m_peerCertificate;
593 	}
594 
595 	@property string alpn()
596 	const {
597 		static if (!haveALPN) assert(false, "OpenSSL support not compiled with ALPN enabled. Use VibeForceALPN.");
598 		else {
599 			// modified since C functions expects a NULL pointer
600 			const(ubyte)* data = null;
601 			uint datalen;
602 			string ret;
603 
604 			() @trusted {
605 				SSL_get0_alpn_selected(m_tls, &data, &datalen);
606 				ret = cast(string)data[0 .. datalen].idup;
607 			} ();
608 			logDebug("alpn selected: ", ret);
609 			return  ret;
610 		}
611 	}
612 
613 	/// Invoked by client to offer alpn
614 	private void setClientALPN(string[] alpn_list)
615 	{
616 		logDebug("SetClientALPN: ", alpn_list);
617 		import vibe.internal.allocator : dispose, makeArray, vibeThreadAllocator;
618 		ubyte[] alpn;
619 		size_t len;
620 		foreach (string alpn_val; alpn_list)
621 			len += alpn_val.length + 1;
622 		alpn = () @trusted { return vibeThreadAllocator.makeArray!ubyte(len); } ();
623 
624 		size_t i;
625 		foreach (string alpn_val; alpn_list)
626 		{
627 			alpn[i++] = cast(ubyte)alpn_val.length;
628 			alpn[i .. i+alpn_val.length] = cast(immutable(ubyte)[])alpn_val;
629 			i += alpn_val.length;
630 		}
631 		assert(i == len);
632 
633 
634 		() @trusted {
635             static if (haveALPN)
636                 SSL_set_alpn_protos(m_tls, cast(const char*) alpn.ptr, cast(uint) len);
637             vibeThreadAllocator.dispose(alpn);
638         } ();
639 	}
640 }
641 
642 private int enforceSSL(int ret, string message)
643 @safe {
644 	if (ret > 0) return ret;
645 	throwSSL(message);
646 	assert(false);
647 }
648 
649 private void throwSSL(string message)
650 @safe {
651 	c_ulong eret;
652 	const(char)* file = null, data = null;
653 	int line;
654 	int flags;
655 	string estr;
656 	char[120] ebuf = 0;
657 
658 	while ((eret = () @trusted { return ERR_get_error_line_data(&file, &line, &data, &flags); } ()) != 0) {
659 		() @trusted { ERR_error_string_n(eret, ebuf.ptr, ebuf.length); } ();
660 		estr = () @trusted { return ebuf.ptr.to!string; } ();
661 		// throw the last error code as an exception
662 		logDebug("OpenSSL error at %s:%d: %s (%s)",
663 			() @trusted { return file.to!string; } (), line, estr,
664 			flags & ERR_TXT_STRING ? () @trusted { return to!string(data); } () : "-");
665 		if (!() @trusted { return ERR_peek_error(); } ()) break;
666 	}
667 
668 	throw new Exception(format("%s: %s (%s)", message, estr, eret));
669 }
670 
671 
672 /**
673 	Encapsulates the configuration for an SSL tunnel.
674 
675 	Note that when creating an SSLContext with SSLContextKind.client, the
676 	peerValidationMode will be set to SSLPeerValidationMode.trustedCert,
677 	but no trusted certificate authorities are added by default. Use
678 	useTrustedCertificateFile to add those.
679 */
680 final class OpenSSLContext : TLSContext {
681 @safe:
682 
683 	private {
684 		TLSContextKind m_kind;
685 		TLSVersion m_version;
686 		ssl_ctx_st* m_ctx;
687 		TLSPeerValidationCallback m_peerValidationCallback;
688 		TLSPeerValidationMode m_validationMode;
689 		int m_verifyDepth;
690 		TLSServerNameCallback m_sniCallback;
691 		TLSALPNCallback m_alpnCallback;
692 	}
693 
694 
695 	this(TLSContextKind kind, TLSVersion ver = TLSVersion.any)
696 	{
697 		m_kind = kind;
698 		m_version = ver;
699 
700 		const(SSL_METHOD)* method;
701 		c_ulong veroptions = SSL_OP_NO_SSLv2;
702 		c_ulong options = SSL_OP_NO_COMPRESSION;
703 		static if (OPENSSL_VERSION_BEFORE(1, 1, 0))
704 			options |= SSL_OP_SINGLE_DH_USE|SSL_OP_SINGLE_ECDH_USE; // There are always enabled in OpenSSL 1.1.0.
705 		int minver = TLS1_VERSION;
706 		int maxver = TLS1_2_VERSION;
707 
708 		() @trusted {
709 		final switch (kind) {
710 			case TLSContextKind.client:
711 				final switch (ver) {
712 					case TLSVersion.any: method = SSLv23_client_method(); veroptions |= SSL_OP_NO_SSLv3; break;
713 					case TLSVersion.ssl3: throw new Exception("SSLv3 is not supported anymore");
714 					case TLSVersion.tls1: method = SSLv23_client_method(); veroptions |= SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2; maxver = TLS1_VERSION; break;
715 					case TLSVersion.tls1_1: method = SSLv23_client_method(); veroptions |= SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_2; minver = TLS1_1_VERSION; maxver = TLS1_1_VERSION; break;
716 					case TLSVersion.tls1_2: method = SSLv23_client_method(); veroptions |= SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1; minver = TLS1_2_VERSION; break;
717 					case TLSVersion.dtls1: method = DTLSv1_client_method(); minver = DTLS1_VERSION; maxver = DTLS1_VERSION; break;
718 				}
719 				break;
720 			case TLSContextKind.server:
721 			case TLSContextKind.serverSNI:
722 				final switch (ver) {
723 					case TLSVersion.any: method = SSLv23_server_method(); veroptions |= SSL_OP_NO_SSLv3; break;
724 					case TLSVersion.ssl3: throw new Exception("SSLv3 is not supported anymore");
725 					case TLSVersion.tls1: method = SSLv23_server_method(); veroptions |= SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2; maxver = TLS1_VERSION; break;
726 					case TLSVersion.tls1_1: method = SSLv23_server_method(); veroptions |= SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_2; minver = TLS1_1_VERSION; maxver = TLS1_1_VERSION; break;
727 					case TLSVersion.tls1_2: method = SSLv23_server_method(); veroptions |= SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1; minver = TLS1_2_VERSION; break;
728 					case TLSVersion.dtls1: method = DTLSv1_server_method(); minver = DTLS1_VERSION; maxver = DTLS1_VERSION; break;
729 				}
730 				options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
731 				break;
732 		}
733 		} ();
734 
735 		m_ctx = () @trusted { return SSL_CTX_new(method); } ();
736 		if (!m_ctx) {
737 			enforceSSL(0, "Failed to create SSL context");
738 			assert(false);
739 		}
740 
741 		static if (OPENSSL_VERSION_AT_LEAST(1, 1, 0)) {
742 			() @trusted { return SSL_CTX_set_min_proto_version(m_ctx, minver); }()
743 				.enforceSSL("Failed setting minimum protocol version");
744 			() @trusted { return SSL_CTX_set_max_proto_version(m_ctx, maxver); }()
745 				.enforceSSL("Failed setting maximum protocol version");
746 		} else {
747 			options |= veroptions;
748 		}
749 
750 		auto newopts = () @trusted { return SSL_CTX_set_options(m_ctx, options); }();
751 		if ((newopts & options) != options)
752 			logDiagnostic("Not all SSL options applied: passed 0x%08x vs applied 0x%08x", options, newopts);
753 
754 		if (kind == TLSContextKind.server) {
755 			setDHParams();
756 			setECDHCurve();
757 			guessSessionIDContext();
758 		}
759 
760 		setCipherList();
761 
762 		maxCertChainLength = 9;
763 		if (kind == TLSContextKind.client) peerValidationMode = TLSPeerValidationMode.trustedCert;
764 		else peerValidationMode = TLSPeerValidationMode.none;
765 
766 		// while it would be nice to use the system's certificate store, this
767 		// seems to be difficult to get right across all systems. The most
768 		// popular alternative is to use Mozilla's certificate store and
769 		// distribute it along with the library (e.g. in source code form.
770 
771 		/*version (Posix) {
772 			enforce(SSL_CTX_load_verify_locations(m_ctx, null, "/etc/ssl/certs"),
773 				"Failed to load system certificate store.");
774 		}
775 
776 		version (Windows) {
777 			auto store = CertOpenSystemStore(null, "ROOT");
778 			enforce(store !is null, "Failed to load system certificate store.");
779 			scope (exit) CertCloseStore(store, 0);
780 
781 			PCCERT_CONTEXT ctx;
782 			while((ctx = CertEnumCertificatesInStore(store, ctx)) !is null) {
783 				X509* x509cert;
784 				auto buffer = ctx.pbCertEncoded;
785 				auto len = ctx.cbCertEncoded;
786 				if (ctx.dwCertEncodingType & X509_ASN_ENCODING) {
787 					x509cert = d2i_X509(null, &buffer, len);
788 					X509_STORE_add_cert(SSL_CTX_get_cert_store(m_ctx), x509cert);
789 				}
790 			}
791 		}*/
792 	}
793 
794 	~this()
795 	{
796 		() @trusted { SSL_CTX_free(m_ctx); } ();
797 		m_ctx = null;
798 	}
799 
800 
801 	/// The kind of SSL context (client/server)
802 	@property TLSContextKind kind() const { return m_kind; }
803 
804 	/// Callback function invoked by server to choose alpn
805 	@property void alpnCallback(TLSALPNCallback alpn_chooser)
806 	{
807 		logDebug("Choosing ALPN callback");
808 		m_alpnCallback = alpn_chooser;
809 		static if (haveALPN) {
810 			logDebug("Call select cb");
811             () @trusted {
812 			    SSL_CTX_set_alpn_select_cb(m_ctx, &chooser, cast(void*)this);
813             } ();
814 		}
815 	}
816 
817 	/// Get the current ALPN callback function
818 	@property TLSALPNCallback alpnCallback() const { return m_alpnCallback; }
819 
820 	/// Invoked by client to offer alpn
821 	void setClientALPN(string[] alpn_list)
822 	{
823 		static if (!haveALPN) assert(false, "OpenSSL support not compiled with ALPN enabled. Use VibeForceALPN.");
824 		else {
825 			import vibe.internal.memory_legacy : allocArray, freeArray, manualAllocator;
826 			ubyte[] alpn;
827 			size_t len;
828 			foreach (string alpn_value; alpn_list)
829 				len += alpn_value.length + 1;
830             () @trusted {
831 			    alpn = allocArray!ubyte(manualAllocator(), len);
832             } ();
833 
834 			size_t i;
835 			foreach (string alpn_value; alpn_list)
836 			{
837                 () @trusted {
838                     alpn[i++] = cast(ubyte)alpn_value.length;
839                     alpn[i .. i+alpn_value.length] = cast(ubyte[])alpn_value;
840                 } ();
841 
842 				i += alpn_value.length;
843 			}
844 			assert(i == len);
845 
846             () @trusted {
847 			    SSL_CTX_set_alpn_protos(m_ctx, cast(const char*) alpn.ptr, cast(uint) len);
848 			    freeArray(manualAllocator(), alpn);
849             } ();
850 
851 		}
852 	}
853 
854 	/** Specifies the validation level of remote peers.
855 
856 		The default mode for TLSContextKind.client is
857 		TLSPeerValidationMode.trustedCert and the default for
858 		TLSContextKind.server is TLSPeerValidationMode.none.
859 	*/
860 	@property void peerValidationMode(TLSPeerValidationMode mode)
861 	{
862 		m_validationMode = mode;
863 
864 		int sslmode;
865 
866 		with (TLSPeerValidationMode) {
867 			if (mode == none) sslmode = SSL_VERIFY_NONE;
868 			else {
869 				sslmode |= SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
870 				if (mode & requireCert) sslmode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
871 			}
872 		}
873 
874 		() @trusted { SSL_CTX_set_verify(m_ctx, sslmode, &verify_callback); } ();
875 	}
876 	/// ditto
877 	@property TLSPeerValidationMode peerValidationMode() const { return m_validationMode; }
878 
879 
880 	/** The maximum length of an accepted certificate chain.
881 
882 		Any certificate chain longer than this will result in the SSL/TLS
883 		negitiation failing.
884 
885 		The default value is 9.
886 	*/
887 	@property void maxCertChainLength(int val)
888 	{
889 		m_verifyDepth = val;
890 		// + 1 to let the validation callback handle the error
891 		() @trusted { SSL_CTX_set_verify_depth(m_ctx, val + 1); } ();
892 	}
893 
894 	/// ditto
895 	@property int maxCertChainLength() const { return m_verifyDepth; }
896 
897 	/** An optional user callback for peer validation.
898 
899 		This callback will be called for each peer and each certificate of
900 		its certificate chain to allow overriding the validation decision
901 		based on the selected peerValidationMode (e.g. to allow invalid
902 		certificates or to reject valid ones). This is mainly useful for
903 		presenting the user with a dialog in case of untrusted or mismatching
904 		certificates.
905 	*/
906 	@property void peerValidationCallback(TLSPeerValidationCallback callback) { m_peerValidationCallback = callback; }
907 	/// ditto
908 	@property inout(TLSPeerValidationCallback) peerValidationCallback() inout { return m_peerValidationCallback; }
909 
910 	@property void sniCallback(TLSServerNameCallback callback)
911 	{
912 		m_sniCallback = callback;
913 		if (m_kind == TLSContextKind.serverSNI) {
914 			() @trusted {
915 				SSL_CTX_callback_ctrl(m_ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cast(OSSLCallback)&onContextForServerName);
916 				SSL_CTX_ctrl(m_ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, cast(void*)this);
917 			} ();
918 		}
919 	}
920 	@property inout(TLSServerNameCallback) sniCallback() inout { return m_sniCallback; }
921 
922 	private extern(C) alias OSSLCallback = void function();
923 	private static extern(C) int onContextForServerName(SSL *s, int *ad, void *arg)
924 	{
925 		auto ctx = () @trusted { return cast(OpenSSLContext)arg; } ();
926 		auto servername = () @trusted { return SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); } ();
927 		if (!servername) return SSL_TLSEXT_ERR_NOACK;
928 		auto newctx = cast(OpenSSLContext)ctx.m_sniCallback(() @trusted { return servername.to!string; } ());
929 		if (!newctx) return SSL_TLSEXT_ERR_NOACK;
930 		() @trusted { SSL_set_SSL_CTX(s, newctx.m_ctx); } ();
931 		return SSL_TLSEXT_ERR_OK;
932 	}
933 
934 	OpenSSLStream createStream(InterfaceProxy!Stream underlying, TLSStreamState state, string peer_name = null, NetworkAddress peer_address = NetworkAddress.init)
935 	{
936 		return new OpenSSLStream(underlying, this, state, peer_name, peer_address);
937 	}
938 
939 	/** Set the list of cipher specifications to use for SSL/TLS tunnels.
940 
941 		The list must be a colon separated list of cipher
942 		specifications as accepted by OpenSSL. Calling this function
943 		without argument will restore the default.
944 
945 		The default is derived from $(LINK https://wiki.mozilla.org/Security/Server_Side_TLS),
946 		using the "intermediate" list for TLSv1.2+ server contexts or using the
947 		"old compatibility" list otherwise.
948 
949 		See_also: $(LINK https://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT)
950 	*/
951 	void setCipherList(string list = null)
952 		@trusted
953 	{
954 		if (list is null) {
955 			if (m_kind == TLSContextKind.server && m_version == TLSVersion.tls1_2) {
956 				list = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:"
957 					~ "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
958 					~ "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
959 					~ "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:"
960 					~ "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
961 			} else {
962 				list =
963 					"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:"
964 					~ "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:"
965 					~ "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:"
966 					~ "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:"
967 					~ "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:"
968 					~ "ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:"
969 					~ "ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:"
970 					~ "ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:"
971 					~ "DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:"
972 					~ "AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA";
973 			}
974 		}
975 
976 		SSL_CTX_set_cipher_list(m_ctx, toStringz(list))
977 			.enforceSSL("Setting cipher list");
978 	}
979 
980 	/** Make up a context ID to assign to the SSL context.
981 
982 		This is required when doing client cert authentication, otherwise many
983 		connections will go aborted as the client tries to revive a session
984 		that it used to have on another machine.
985 
986 		The session ID context should be unique within a pool of servers.
987 		Currently, this is achieved by taking the hostname.
988 	*/
989 	private void guessSessionIDContext()
990 		@trusted
991 	{
992 		string contextID = Socket.hostName;
993 		SSL_CTX_set_session_id_context(m_ctx, cast(ubyte*)contextID.toStringz(), cast(uint)contextID.length);
994 	}
995 
996 	/** Set params to use for DH cipher.
997 	 *
998 	 * By default the 2048-bit prime from RFC 3526 is used.
999 	 *
1000 	 * Params:
1001 	 * pem_file = Path to a PEM file containing the DH parameters. Calling
1002 	 *    this function without argument will restore the default.
1003 	 */
1004 	void setDHParams(string pem_file=null)
1005 	@trusted {
1006 		DH* dh;
1007 		scope(exit) DH_free(dh);
1008 
1009 		if (pem_file is null) {
1010 			dh = enforce(DH_new(), "Unable to create DH structure.");
1011 			dh.p = get_rfc3526_prime_2048(null);
1012 			ubyte dh_generator = 2;
1013 			dh.g = BN_bin2bn(&dh_generator, dh_generator.sizeof, null);
1014 		} else {
1015 			import core.stdc.stdio : fclose, fopen;
1016 
1017 			auto f = enforce(fopen(toStringz(pem_file), "r"), "Failed to load dhparams file "~pem_file);
1018 			scope(exit) fclose(f);
1019 			dh = enforce(PEM_read_DHparams(f, null, null, null), "Failed to read dhparams file "~pem_file);
1020 		}
1021 
1022 		SSL_CTX_set_tmp_dh(m_ctx, dh);
1023 	}
1024 
1025 	/** Set the elliptic curve to use for ECDH cipher.
1026 	 *
1027 	 * By default a curve is either chosen automatically or  prime256v1 is used.
1028 	 *
1029 	 * Params:
1030 	 * curve = The short name of the elliptic curve to use. Calling this
1031 	 *    function without argument will restore the default.
1032 	 *
1033 	 */
1034 	void setECDHCurve(string curve = null)
1035 	@trusted {
1036 		// `SSL_CTX_set_ecdh_auto` are no longer available in v1.1.0,
1037 		// as it is always enabled by default.
1038 		// https://github.com/openssl/openssl/issues/1437
1039 		// https://github.com/openssl/openssl/commit/2ecb9f2d18614fb7b7b42830a358b7163ed43221
1040 		static if (OPENSSL_VERSION_NUMBER >= 0x10200000 && OPENSSL_VERSION_NUMBER < OPENSSL_MAKE_VERSION(1, 1, 0, 0)) {
1041 			// use automatic ecdh curve selection by default
1042 			if (curve is null) {
1043 				SSL_CTX_set_ecdh_auto(m_ctx, true);
1044 				return;
1045 			}
1046 			// but disable it when an explicit curve is given
1047 			SSL_CTX_set_ecdh_auto(m_ctx, false);
1048 		}
1049 
1050 		int nid;
1051 		if (curve is null)
1052 			nid = NID_X9_62_prime256v1;
1053 		else
1054 			nid = enforce(OBJ_sn2nid(toStringz(curve)), "Unknown ECDH curve '"~curve~"'.");
1055 
1056 		auto ecdh = enforce(EC_KEY_new_by_curve_name(nid), "Unable to create ECDH curve.");
1057 		SSL_CTX_set_tmp_ecdh(m_ctx, ecdh);
1058 		EC_KEY_free(ecdh);
1059 	}
1060 
1061 	/// Sets a certificate file to use for authenticating to the remote peer
1062 	void useCertificateChainFile(string path)
1063 	{
1064 		enforce(() @trusted { return SSL_CTX_use_certificate_chain_file(m_ctx, toStringz(path)); } (), "Failed to load certificate file " ~ path);
1065 	}
1066 
1067 	/// Sets the private key to use for authenticating to the remote peer based
1068 	/// on the configured certificate chain file.
1069 	void usePrivateKeyFile(string path)
1070 	{
1071 		enforce(() @trusted { return SSL_CTX_use_PrivateKey_file(m_ctx, toStringz(path), SSL_FILETYPE_PEM); } (), "Failed to load private key file " ~ path);
1072 	}
1073 
1074 	/** Sets the list of trusted certificates for verifying peer certificates.
1075 
1076 		If this is a server context, this also entails that the given
1077 		certificates are advertised to connecting clients during handshake.
1078 
1079 		On Linux, the system's root certificate authority list is usually
1080 		found at "/etc/ssl/certs/ca-certificates.crt",
1081 		"/etc/pki/tls/certs/ca-bundle.crt", or "/etc/ssl/ca-bundle.pem".
1082 	*/
1083 	void useTrustedCertificateFile(string path)
1084 	@trusted {
1085 		immutable cPath = toStringz(path);
1086 		enforce(SSL_CTX_load_verify_locations(m_ctx, cPath, null),
1087 			"Failed to load trusted certificate file " ~ path);
1088 
1089 		if (m_kind == TLSContextKind.server) {
1090 			auto certNames = enforce(SSL_load_client_CA_file(cPath),
1091 				"Failed to load client CA name list from file " ~ path);
1092 			SSL_CTX_set_client_CA_list(m_ctx, certNames);
1093 		}
1094 	}
1095 
1096 	private SSLState createClientCtx()
1097 	{
1098 		SSLState ret = () @trusted { return SSL_new(m_ctx); } ();
1099 		if (!ret) {
1100 			enforceSSL(0, "Failed to create SSL context");
1101 			assert(false);
1102 		}
1103 		return ret;
1104 	}
1105 
1106 	private static struct VerifyData {
1107 		int verifyDepth;
1108 		TLSPeerValidationMode validationMode;
1109 		TLSPeerValidationCallback callback;
1110 		string peerName;
1111 		NetworkAddress peerAddress;
1112 	}
1113 
1114 	private static extern(C) nothrow
1115 	int verify_callback(int valid, X509_STORE_CTX* ctx)
1116 	@trusted {
1117 		X509* err_cert = X509_STORE_CTX_get_current_cert(ctx);
1118 		int err = X509_STORE_CTX_get_error(ctx);
1119 		int depth = X509_STORE_CTX_get_error_depth(ctx);
1120 
1121 		SSL* ssl = cast(SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
1122 		VerifyData* vdata = cast(VerifyData*)SSL_get_ex_data(ssl, gs_verifyDataIndex);
1123 
1124 		char[1024] buf;
1125 		X509_NAME_oneline(X509_get_subject_name(err_cert), buf.ptr, 256);
1126 		buf[$-1] = 0;
1127 
1128 		try {
1129 			logDebug("validate callback for %s", buf.ptr.to!string);
1130 
1131 			if (depth > vdata.verifyDepth) {
1132 				logDiagnostic("SSL cert chain too long: %s vs. %s", depth, vdata.verifyDepth);
1133 				valid = false;
1134 				err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
1135 			}
1136 
1137 			if (err != X509_V_OK)
1138 				logDebug("SSL cert initial error: %s", X509_verify_cert_error_string(err).to!string);
1139 
1140 			if (!valid) {
1141 				switch (err) {
1142 					default: break;
1143 					case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
1144 					case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
1145 					case X509_V_ERR_CERT_UNTRUSTED:
1146 						assert(err_cert !is null);
1147 						X509_NAME_oneline(X509_get_issuer_name(err_cert), buf.ptr, buf.length);
1148 						buf[$-1] = 0;
1149 						logDebug("SSL cert not trusted or unknown issuer: %s", buf.ptr.to!string);
1150 						if (!(vdata.validationMode & TLSPeerValidationMode.checkTrust)) {
1151 							valid = true;
1152 							err = X509_V_OK;
1153 						}
1154 						break;
1155 				}
1156 			}
1157 
1158 			if (!(vdata.validationMode & TLSPeerValidationMode.checkCert)) {
1159 				valid = true;
1160 				err = X509_V_OK;
1161 			}
1162 
1163 			if (vdata.callback) {
1164 				TLSPeerValidationData pvdata;
1165 				// ...
1166 				if (!valid) {
1167 					if (vdata.callback(pvdata)) {
1168 						valid = true;
1169 						err = X509_V_OK;
1170 					}
1171 				} else {
1172 					if (!vdata.callback(pvdata)) {
1173 						logDebug("SSL application verification failed");
1174 						valid = false;
1175 						err = X509_V_ERR_APPLICATION_VERIFICATION;
1176 					}
1177 				}
1178 			}
1179 		} catch (Exception e) {
1180 			logWarn("SSL verification failed due to exception: %s", e.msg);
1181 			err = X509_V_ERR_APPLICATION_VERIFICATION;
1182 			valid = false;
1183 		}
1184 
1185 		X509_STORE_CTX_set_error(ctx, err);
1186 
1187 		logDebug("SSL validation result: %s (%s)", valid, err);
1188 
1189 		return valid;
1190 	}
1191 }
1192 
1193 alias SSLState = ssl_st*;
1194 
1195 /**************************************************************************************************/
1196 /* Private functions                                                                              */
1197 /**************************************************************************************************/
1198 
1199 private {
1200 	__gshared int gs_verifyDataIndex;
1201 }
1202 
1203 shared static this()
1204 {
1205 	static if (OPENSSL_VERSION_BEFORE(1, 1, 0))
1206 	{
1207 		logDebug("Initializing OpenSSL...");
1208 		// Not required as of OpenSSL 1.1.0, see:
1209 		// https://wiki.openssl.org/index.php/Library_Initialization
1210 		SSL_load_error_strings();
1211 		SSL_library_init();
1212 
1213 		g_cryptoMutexes.length = CRYPTO_num_locks();
1214 		// TODO: investigate if a normal Mutex is enough - not sure if BIO is called in a locked state
1215 		foreach (i; 0 .. g_cryptoMutexes.length)
1216 			g_cryptoMutexes[i] = new InterruptibleTaskMutex;
1217 		foreach (ref m; g_cryptoMutexes) {
1218 			assert(m !is null);
1219 		}
1220 
1221 		// Those two were removed in v1.1.0, see:
1222 		// https://github.com/openssl/openssl/issues/1260
1223 		CRYPTO_set_id_callback(&onCryptoGetThreadID);
1224 		CRYPTO_set_locking_callback(&onCryptoLock);
1225 		logDebug("... done.");
1226 	}
1227 
1228 	enforce(RAND_poll(), "Fatal: failed to initialize random number generator entropy (RAND_poll).");
1229 	gs_verifyDataIndex = SSL_get_ex_new_index(0, cast(void*)"VerifyData".ptr, null, null, null);
1230 }
1231 
1232 private bool verifyCertName(X509* cert, int field, in char[] value, bool allow_wildcards = true)
1233 @trusted {
1234 	bool delegate(in char[]) @safe str_match;
1235 
1236 	bool check_value(ASN1_STRING* str, int type) {
1237 		if (!str.data || !str.length) return false;
1238 
1239 		if (type > 0) {
1240 			if (type != str.type) return 0;
1241 			auto strstr = cast(string)str.data[0 .. str.length];
1242 			return type == V_ASN1_IA5STRING ? str_match(strstr) : strstr == value;
1243 		}
1244 
1245 		char* utfstr;
1246 		auto utflen = ASN1_STRING_to_UTF8(&utfstr, str);
1247 		enforce (utflen >= 0, "Error converting ASN1 string to UTF-8.");
1248 		scope (exit) OPENSSL_free(utfstr);
1249 		return str_match(utfstr[0 .. utflen]);
1250 	}
1251 
1252 	int cnid;
1253 	int alt_type;
1254 	final switch (field) {
1255 		case GEN_DNS:
1256 			cnid = NID_commonName;
1257 			alt_type = V_ASN1_IA5STRING;
1258 			str_match = allow_wildcards ? (in s) => matchWildcard(value, s) : (in s) => s.icmp(value) == 0;
1259 			break;
1260 		case GEN_IPADD:
1261 			cnid = 0;
1262 			alt_type = V_ASN1_OCTET_STRING;
1263 			str_match = (in s) => s == value;
1264 			break;
1265 	}
1266 
1267 	if (auto gens = cast(STACK_OF!GENERAL_NAME*)X509_get_ext_d2i(cert, NID_subject_alt_name, null, null)) {
1268 		// Somehow Deimos' bindings don't allow us to call `sk_GENERAL_NAMES_free`,
1269 		// as it takes a `stack_st_GENERAL_NAME*` which in C is just what
1270 		// `STACK_OF(GENERAL_NAME)` aliases to, but not in D (STACK_OF is a template).
1271 		// Since under the hood all stack APIs are untyped, just use `OPENSSL_sk_free`
1272 		// directly, see: https://man.openbsd.org/OPENSSL_sk_new.3
1273 		scope(exit) OPENSSL_sk_free(cast(_STACK*) gens);
1274 
1275 		foreach (i; 0 .. sk_GENERAL_NAME_num(gens)) {
1276 			auto gen = sk_GENERAL_NAME_value(gens, i);
1277 			if (gen.type != field) continue;
1278 			ASN1_STRING *cstr = field == GEN_DNS ? gen.d.dNSName : gen.d.iPAddress;
1279 			if (check_value(cstr, alt_type)) return true;
1280 		}
1281 		if (!cnid) return false;
1282 	}
1283 
1284 	X509_NAME* name = X509_get_subject_name(cert);
1285 	int i = -1;
1286 	while ((i = X509_NAME_get_index_by_NID(name, cnid, i)) >= 0) {
1287 		X509_NAME_ENTRY* ne = X509_NAME_get_entry(name, i);
1288 		ASN1_STRING* str = X509_NAME_ENTRY_get_data(ne);
1289 		if (check_value(str, -1)) return true;
1290 	}
1291 
1292 	return false;
1293 }
1294 
1295 private bool matchWildcard(const(char)[] str, const(char)[] pattern)
1296 @safe {
1297 	auto strparts = str.split(".");
1298 	auto patternparts = pattern.split(".");
1299 	if (strparts.length != patternparts.length) return false;
1300 
1301 	bool isValidChar(dchar ch) {
1302 		if (ch >= '0' && ch <= '9') return true;
1303 		if (ch >= 'a' && ch <= 'z') return true;
1304 		if (ch >= 'A' && ch <= 'Z') return true;
1305 		if (ch == '-' || ch == '.') return true;
1306 		return false;
1307 	}
1308 
1309 	if (!pattern.all!(c => isValidChar(c) || c == '*') || !str.all!(c => isValidChar(c)))
1310 		return false;
1311 
1312 	foreach (i; 0 .. strparts.length) {
1313 		import std.regex;
1314 		auto p = patternparts[i];
1315 		auto s = strparts[i];
1316 		if (!p.length || !s.length) return false;
1317 		auto rex = "^" ~ std.array.replace(p, "*", "[^.]*") ~ "$";
1318 		if (!match(s, rex)) return false;
1319 	}
1320 	return true;
1321 }
1322 
1323 unittest {
1324 	assert(matchWildcard("www.example.org", "*.example.org"));
1325 	assert(matchWildcard("www.example.org", "*w.example.org"));
1326 	assert(matchWildcard("www.example.org", "w*w.example.org"));
1327 	assert(matchWildcard("www.example.org", "*w*.example.org"));
1328 	assert(matchWildcard("test.abc.example.org", "test.*.example.org"));
1329 	assert(!matchWildcard("test.abc.example.org", "abc.example.org"));
1330 	assert(!matchWildcard("test.abc.example.org", ".abc.example.org"));
1331 	assert(!matchWildcard("abc.example.org", "a.example.org"));
1332 	assert(!matchWildcard("abc.example.org", "bc.example.org"));
1333 	assert(!matchWildcard("abcdexample.org", "abc.example.org"));
1334 }
1335 
1336 
1337 private nothrow @safe extern(C)
1338 {
1339 	import core.stdc.config;
1340 
1341 
1342 	int chooser(SSL* ssl, const(char)** output, ubyte* outlen, const(char) *input_, uint inlen, void* arg) {
1343 		const(char)[] input = () @trusted { return input_[0 .. inlen]; } ();
1344 
1345 		OpenSSLContext ctx = () @trusted { return cast(OpenSSLContext) arg; } ();
1346 		import vibe.utils.array : AllocAppender, AppenderResetMode;
1347 		size_t i;
1348 		size_t len;
1349 		Appender!(string[]) alpn_list;
1350 		while (i < inlen)
1351 		{
1352 			len = cast(size_t) input[i];
1353 			++i;
1354 			auto proto = input[i .. i+len];
1355 			i += len;
1356 			() @trusted { alpn_list ~= cast(string)proto; } ();
1357 		}
1358 
1359 		string alpn;
1360 
1361 		try { alpn = ctx.m_alpnCallback(alpn_list.data); } catch (Exception e) { }
1362 		if (alpn) {
1363 			i = 0;
1364 			while (i < inlen)
1365 			{
1366 				len = input[i];
1367 				++i;
1368 				auto proto = input[i .. i+len];
1369 				i += len;
1370 				if (proto == alpn) {
1371 					*output = &proto[0];
1372 					*outlen = cast(ubyte) proto.length;
1373 				}
1374 			}
1375 		}
1376 
1377 		if (!output) {
1378 			logError("None of the proposed ALPN were selected: %s / falling back on HTTP/1.1", input);
1379 			enum hdr = "http/1.1";
1380 			*output = &hdr[0];
1381 			*outlen = cast(ubyte)hdr.length;
1382 		}
1383 
1384 		return 0;
1385 	}
1386 
1387 	int onBioNew(BIO *b) nothrow
1388 	{
1389 		BIO_set_init(b, 0);
1390 		//b.num = -1;
1391 		BIO_set_data(b, null);
1392 		BIO_clear_flags(b, ~0);
1393 		return 1;
1394 	}
1395 
1396 	int onBioFree(BIO *b)
1397 	{
1398 		if( !b ) return 0;
1399 		if(BIO_get_shutdown(b)){
1400 			//if( b.init && b.ptr ) b.ptr.stream.free();
1401 			BIO_set_init(b, 0);
1402 			BIO_clear_flags(b, ~0);
1403 			BIO_set_data(b, null);
1404 		}
1405 		return 1;
1406 	}
1407 
1408 	int onBioRead(BIO *b, const(char)* outb, int outlen)
1409 	{
1410 		auto stream = () @trusted { return cast(OpenSSLStream)BIO_get_data(b); } ();
1411 
1412 		try {
1413 			outlen = min(outlen, stream.m_stream.leastSize);
1414 			stream.m_stream.read(() @trusted { return cast(ubyte[])outb[0 .. outlen]; } ());
1415 		} catch (Exception e) {
1416 			setSSLError("Error reading from underlying stream", e.msg);
1417 			return -1;
1418 		}
1419 		return outlen;
1420 	}
1421 
1422 	int onBioWrite(BIO *b, const(char) *inb, int inlen)
1423 	{
1424 		auto stream = () @trusted { return cast(OpenSSLStream)BIO_get_data(b); } ();
1425 		try {
1426 			stream.m_stream.write(() @trusted { return inb[0 .. inlen]; } ());
1427 		} catch (Exception e) {
1428 			setSSLError("Error writing to underlying stream", e.msg);
1429 			return -1;
1430 		}
1431 		return inlen;
1432 	}
1433 
1434 	c_long onBioCtrl(BIO *b, int cmd, c_long num, void *ptr)
1435 	{
1436 		auto stream = () @trusted { return cast(OpenSSLStream)BIO_get_data(b); } ();
1437 		c_long ret = 1;
1438 
1439 		switch(cmd){
1440 			case BIO_CTRL_GET_CLOSE: ret = BIO_get_shutdown(b); break;
1441 			case BIO_CTRL_SET_CLOSE:
1442 				logTrace("SSL set close %d", num);
1443 				BIO_set_shutdown(b, cast(int)num);
1444 				break;
1445 			case BIO_CTRL_PENDING:
1446 				try {
1447 					auto sz = stream.m_stream.leastSize; // FIXME: .peek.length should be sufficient here
1448 					return sz <= c_long.max ? cast(c_long)sz : c_long.max;
1449 				} catch( Exception e ){
1450 					setSSLError("Error reading from underlying stream", e.msg);
1451 					return -1;
1452 				}
1453 			case BIO_CTRL_WPENDING: return 0;
1454 			case BIO_CTRL_DUP:
1455 			case BIO_CTRL_FLUSH:
1456 				ret = 1;
1457 				break;
1458 			default:
1459 				ret = 0;
1460 				break;
1461 		}
1462 		return ret;
1463 	}
1464 
1465 	int onBioPuts(BIO *b, const(char) *s)
1466 	{
1467 		return onBioWrite(b, s, cast(int)() @trusted { return strlen(s); } ());
1468 	}
1469 }
1470 
1471 private void setSSLError(string msg, string submsg, int line = __LINE__, string file = __FILE__)
1472 @trusted nothrow {
1473 	import std.string : toStringz;
1474 	static if (is(typeof(ERR_new))) {
1475 		ERR_new();
1476 		ERR_set_debug(file.toStringz, line, "");
1477 		ERR_set_error(ERR_LIB_USER, 1, null);
1478 	} else {
1479 		ERR_put_error(ERR_LIB_USER, 0, 1, file.toStringz, line);
1480 	}
1481 	ERR_add_error_data(3, msg.toStringz, ": ".ptr, submsg.toStringz);
1482 }
1483 
1484 static if (OPENSSL_VERSION_AT_LEAST(1, 1, 0)) {
1485 	private BIO_METHOD* s_bio_methods;
1486 
1487 	private void initBioMethods()
1488 	@trusted {
1489 		s_bio_methods = BIO_meth_new(BIO_get_new_index(), "SslStream");
1490 
1491 		BIO_meth_set_write(s_bio_methods, &onBioWrite);
1492 		BIO_meth_set_read(s_bio_methods, &onBioRead);
1493 		BIO_meth_set_ctrl(s_bio_methods, &onBioCtrl);
1494 		BIO_meth_set_create(s_bio_methods, &onBioNew);
1495 		BIO_meth_set_destroy(s_bio_methods, &onBioFree);
1496 	}
1497 } else {
1498 	// OpenSSL 1.1.0 made BIO opaque, this is for older versions
1499 	//https://github.com/openssl/openssl/commit/a146ae55ba479a5c7aa2a6afba1b2b93102a152c
1500 	private BIO_METHOD s_bio_methods = {
1501 		57, "SslStream",
1502 		&onBioWrite,
1503 		&onBioRead,
1504 		&onBioPuts,
1505 		null, // &onBioGets
1506 		&onBioCtrl,
1507 		&onBioNew,
1508 		&onBioFree,
1509 		null, // &onBioCallbackCtrl
1510 	};
1511 }
1512 
1513 private nothrow extern(C):
1514 static if (haveALPN) {
1515 	alias ALPNCallback = int function(SSL *ssl, const(char) **output, ubyte* outlen, const(char) *input, uint inlen, void *arg);
1516 	void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, ALPNCallback cb, void *arg);
1517 	int SSL_set_alpn_protos(SSL *ssl, const char *data, uint len);
1518 	int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const char* protos, uint protos_len);
1519 	void SSL_get0_alpn_selected(const SSL *ssl, const ubyte** data, uint *len);
1520 }
1521 const(ssl_method_st)* TLSv1_2_server_method();