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