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