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();