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