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