1 module requests.ssl_adapter; 2 3 version(staticssl) { 4 public import requests.ssl_adapter_static; 5 } else: 6 7 import std.stdio; 8 import std.string; 9 import std.format; 10 import std.typecons; 11 import core.stdc.stdlib; 12 import core.sys.posix.dlfcn; 13 import std.experimental.logger; 14 import core.stdc.config; 15 16 version(Windows) { 17 import core.sys.windows.windows; 18 alias DLSYM = GetProcAddress; 19 } else { 20 alias DLSYM = dlsym; 21 } 22 23 version(RequestsSkipSSL) 24 { 25 enum enableSSL = false; 26 } 27 else 28 { 29 enum enableSSL = true; 30 } 31 32 /* 33 * /usr/include/openssl/tls1.h:# define TLS_ANY_VERSION 0x10000 34 */ 35 36 immutable int TLS_ANY_VERSION = 0x10000; 37 immutable int TLS1_VERSION = 0x0301; 38 immutable int TLS1_2_VERSION = 0x0303; 39 40 struct SSL {}; 41 struct SSL_CTX {}; 42 struct SSL_METHOD {}; 43 44 // 45 // N - function name, R - return type, A - args 46 // 47 string SSL_Function_decl(string N, R, A...)() { 48 string F = "extern (C) @nogc nothrow %s function %s adapter_%s;".format(R.stringof, A.stringof, N); 49 return F; 50 } 51 string SSL_Function_set_i(string N, R, A...)() { 52 string F = "openssl.adapter_%s = cast(typeof(openssl.adapter_%s))DLSYM(cast(void*)openssl._libssl, \"%s\");".format(N, N, N); 53 return F; 54 } 55 string CRYPTO_Function_set_i(string N, R, A...)() { 56 string F = "openssl.adapter_%s = cast(typeof(openssl.adapter_%s))DLSYM(cast(void*)openssl._libcrypto, \"%s\");".format(N, N, N); 57 return F; 58 } 59 60 private alias Version = Tuple!(int, "major", int, "minor"); 61 62 immutable static OpenSSL openssl; 63 64 shared static this() { 65 version(OSX) { 66 enum loadFunction = "dlopen(lib.ptr, RTLD_LAZY)"; 67 immutable string[] libsslname = [ 68 "libssl.46.dylib", 69 "libssl.44.dylib", 70 "libssl.43.dylib", 71 "libssl.35.dylib", 72 "libssl.dylib", 73 ]; 74 immutable string[] libcryptoname = [ 75 "libcrypto.44.dylib", 76 "libcrypto.42.dylib", 77 "libcrypto.41.dylib", 78 "libcrypto.35.dylib", 79 "libcrypto.dylib", 80 ]; 81 } else 82 version(linux) { 83 enum loadFunction = "dlopen(lib.ptr, RTLD_LAZY)"; 84 immutable string[] libsslname = [ 85 "libssl.so.3", 86 "libssl.so.1.1", 87 "libssl.so.1.0.2", 88 "libssl.so.1.0.1", 89 "libssl.so.1.0.0", 90 "libssl.so", 91 ]; 92 immutable string[] libcryptoname = [ 93 "libcrypto.so.3", 94 "libcrypto.so.1.1", 95 "libcrypto.so.1.0.2", 96 "libcrypto.so.1.0.1", 97 "libcrypto.so.1.0.0", 98 "libcrypto.so", 99 ]; 100 } else 101 version(FreeBSD) { 102 enum loadFunction = "dlopen(lib.ptr, RTLD_LAZY)"; 103 immutable string[] libsslname = [ 104 "libssl.so.1.1", 105 "libssl.so.1.0.2", 106 "libssl.so.1.0.1", 107 "libssl.so.1.0.0", 108 "libssl.so", 109 ]; 110 immutable string[] libcryptoname = [ 111 "libcrypto.so.1.1", 112 "libcrypto.so.1.0.2", 113 "libcrypto.so.1.0.1", 114 "libcrypto.so.1.0.0", 115 "libcrypto.so", 116 ]; 117 } else 118 version(Windows) { 119 enum loadFunction = "LoadLibrary(lib.ptr)"; 120 immutable wstring[] libsslname = [ 121 "libssl32.dll"w, 122 "libssl-1_1"w, 123 "libssl-1_1-x64"w, 124 ]; 125 immutable wstring[] libcryptoname = [ 126 "libeay32.dll"w, 127 "libcrypto-1_1"w, 128 "libcrypto-1_1-x64"w, 129 ]; 130 } else { 131 debug(requests) trace("error loading openssl: unsupported system - first access over https will fail"); 132 return; 133 } 134 135 static if ( enableSSL && is(typeof(loadFunction)) ) { 136 foreach(lib; libsslname) { 137 openssl._libssl = cast(typeof(openssl._libssl))mixin(loadFunction); 138 if ( openssl._libssl !is null ) { 139 debug(requests) tracef("will use %s".format(lib)); 140 break; 141 } 142 } 143 foreach(lib; libcryptoname) { 144 openssl._libcrypto = cast(typeof(openssl._libcrypto))mixin(loadFunction); 145 if ( openssl._libcrypto !is null ) { 146 debug(requests) tracef("will use %s".format(lib)); 147 break; 148 } 149 } 150 } 151 152 if ( openssl._libssl is null ) { 153 debug(requests) trace("warning: failed to load libssl - first access over https will fail"); 154 return; 155 } 156 if ( openssl._libcrypto is null ) { 157 debug(requests) trace("warning: failed to load libcrypto - first access over https will fail"); 158 return; 159 } 160 openssl._ver = openssl.OpenSSL_version_detect(); 161 162 mixin(SSL_Function_set_i!("SSL_library_init", int)); 163 mixin(CRYPTO_Function_set_i!("OpenSSL_add_all_ciphers", void)); 164 mixin(CRYPTO_Function_set_i!("OpenSSL_add_all_digests", void)); 165 mixin(SSL_Function_set_i!("SSL_load_error_strings", void)); 166 167 mixin(SSL_Function_set_i!("OPENSSL_init_ssl", int, ulong, void*)); 168 mixin(CRYPTO_Function_set_i!("OPENSSL_init_crypto", int, ulong, void*)); 169 170 mixin(SSL_Function_set_i!("TLSv1_client_method", SSL_METHOD*)); 171 mixin(SSL_Function_set_i!("TLSv1_2_client_method", SSL_METHOD*)); 172 mixin(SSL_Function_set_i!("TLS_method", SSL_METHOD*)); 173 mixin(SSL_Function_set_i!("SSLv23_client_method", SSL_METHOD*)); 174 mixin(SSL_Function_set_i!("SSL_CTX_new", SSL_CTX*, SSL_METHOD*)); 175 mixin(SSL_Function_set_i!("SSL_CTX_set_default_verify_paths", int, SSL_CTX*)); 176 mixin(SSL_Function_set_i!("SSL_CTX_load_verify_locations", int, SSL_CTX*, char*, char*)); 177 mixin(SSL_Function_set_i!("SSL_CTX_set_verify", void, SSL_CTX*, int, void*)); 178 mixin(SSL_Function_set_i!("SSL_CTX_use_PrivateKey_file", int, SSL_CTX*, const char*, int)); 179 mixin(SSL_Function_set_i!("SSL_CTX_use_certificate_file", int, SSL_CTX*, const char*, int)); 180 mixin(SSL_Function_set_i!("SSL_CTX_set_cipher_list", int, SSL_CTX*, const char*)); 181 mixin(SSL_Function_set_i!("SSL_CTX_ctrl", c_long, SSL_CTX*, int, c_long, void*)); 182 mixin(SSL_Function_set_i!("SSL_new", SSL*, SSL_CTX*)); 183 mixin(SSL_Function_set_i!("SSL_set_fd", int, SSL*, int)); 184 mixin(SSL_Function_set_i!("SSL_connect", int, SSL*)); 185 mixin(SSL_Function_set_i!("SSL_write", int, SSL*, const void*, int)); 186 mixin(SSL_Function_set_i!("SSL_read", int, SSL*, void*, int)); 187 mixin(SSL_Function_set_i!("SSL_free", void, SSL*)); 188 mixin(SSL_Function_set_i!("SSL_CTX_free", void, SSL_CTX*)); 189 mixin(SSL_Function_set_i!("SSL_get_error", int, SSL*, int)); 190 mixin(SSL_Function_set_i!("SSL_ctrl", c_long, SSL*, int, c_long, void*)); 191 mixin(CRYPTO_Function_set_i!("ERR_reason_error_string", char*, c_ulong)); 192 mixin(CRYPTO_Function_set_i!("ERR_get_error", c_ulong)); 193 194 void delegate()[Version] init_matrix; 195 init_matrix[Version(1,0)] = &openssl.init1_0; 196 init_matrix[Version(1,1)] = &openssl.init1_1; 197 init_matrix[Version(2,0)] = &openssl.init1_1; 198 init_matrix[Version(0,2)] = &openssl.init1_1; // libressl >= 2.7.1 199 init_matrix[Version(0,3)] = &openssl.init1_1; // libressl >= 3.0.0 200 init_matrix[Version(3,0)] = &openssl.init1_1; // >=3.0 201 auto initVer = (ver) { 202 if (ver.major == 3 && ver.minor >= 1) // set 3.x to 3.0 for the init matrix 203 return Version(3, 0); 204 else 205 return ver; 206 }(openssl._ver); 207 auto init = init_matrix.get(initVer, null); 208 if ( init is null ) { 209 throw new Exception("loading openssl: unknown version %s for init".format(openssl._ver)); 210 } 211 init(); 212 } 213 214 struct OpenSSL { 215 216 private { 217 Version _ver; 218 void* _libssl; 219 void* _libcrypto; 220 221 // openssl 1.0.x init functions 222 mixin(SSL_Function_decl!("SSL_library_init", int)); 223 mixin(SSL_Function_decl!("OpenSSL_add_all_ciphers", void)); 224 mixin(SSL_Function_decl!("OpenSSL_add_all_digests", void)); 225 mixin(SSL_Function_decl!("SSL_load_error_strings", void)); 226 227 // openssl 1.1.x init functions 228 mixin(SSL_Function_decl!("OPENSSL_init_ssl", int, ulong, void*)); // fixed width 64 bit arg 229 mixin(SSL_Function_decl!("OPENSSL_init_crypto", int, ulong, void*)); // fixed width 64 bit arg 230 231 // all other functions 232 mixin(SSL_Function_decl!("TLSv1_client_method", SSL_METHOD*)); 233 mixin(SSL_Function_decl!("TLSv1_2_client_method", SSL_METHOD*)); 234 mixin(SSL_Function_decl!("TLS_method", SSL_METHOD*)); 235 mixin(SSL_Function_decl!("SSLv23_client_method", SSL_METHOD*)); 236 mixin(SSL_Function_decl!("SSL_CTX_new", SSL_CTX*, SSL_METHOD*)); 237 mixin(SSL_Function_decl!("SSL_CTX_set_default_verify_paths", int, SSL_CTX*)); 238 mixin(SSL_Function_decl!("SSL_CTX_load_verify_locations", int, SSL_CTX*, char*, char*)); 239 mixin(SSL_Function_decl!("SSL_CTX_set_verify", void, SSL_CTX*, int, void*)); 240 mixin(SSL_Function_decl!("SSL_CTX_use_PrivateKey_file", int, SSL_CTX*, const char*, int)); 241 mixin(SSL_Function_decl!("SSL_CTX_use_certificate_file", int, SSL_CTX*, const char*, int)); 242 mixin(SSL_Function_decl!("SSL_CTX_set_cipher_list", int, SSL_CTX*, const char*)); 243 mixin(SSL_Function_decl!("SSL_CTX_ctrl", c_long, SSL_CTX*, int, c_long, void*)); 244 mixin(SSL_Function_decl!("SSL_new", SSL*, SSL_CTX*)); 245 mixin(SSL_Function_decl!("SSL_set_fd", int, SSL*, int)); 246 mixin(SSL_Function_decl!("SSL_connect", int, SSL*)); 247 mixin(SSL_Function_decl!("SSL_write", int, SSL*, const void*, int)); 248 mixin(SSL_Function_decl!("SSL_read", int, SSL*, void*, int)); 249 mixin(SSL_Function_decl!("SSL_free", void, SSL*)); 250 mixin(SSL_Function_decl!("SSL_CTX_free", void, SSL_CTX*)); 251 mixin(SSL_Function_decl!("SSL_get_error", int, SSL*, int)); 252 mixin(SSL_Function_decl!("SSL_ctrl", c_long, SSL*, int, c_long, void*)); 253 mixin(SSL_Function_decl!("ERR_reason_error_string", char*, c_ulong)); 254 mixin(SSL_Function_decl!("ERR_get_error", c_ulong)); 255 } 256 257 Version reportVersion() const @nogc nothrow pure { 258 return _ver; 259 }; 260 261 private Version OpenSSL_version_detect() const { 262 c_ulong function() OpenSSL_version_num = cast(c_ulong function())DLSYM(cast(void*)_libcrypto, "OpenSSL_version_num".ptr); 263 if ( OpenSSL_version_num ) { 264 auto v = OpenSSL_version_num() & 0xffffffff; 265 return Version((v>>>28) & 0xff, (v>>>20) & 0xff); 266 } 267 return Version(1, 0); 268 } 269 270 private void init1_0() const { 271 adapter_SSL_library_init(); 272 adapter_OpenSSL_add_all_ciphers(); 273 adapter_OpenSSL_add_all_digests(); 274 adapter_SSL_load_error_strings(); 275 } 276 private void init1_1() const { 277 /** 278 Standard initialisation options 279 280 #define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L 281 282 # define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L 283 # define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L 284 # define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L 285 **/ 286 enum OPENSSL_INIT_LOAD_SSL_STRINGS = 0x00200000L; 287 enum OPENSSL_INIT_LOAD_CRYPTO_STRINGS = 0x00000002L; 288 enum OPENSSL_INIT_ADD_ALL_CIPHERS = 0x00000004L; 289 enum OPENSSL_INIT_ADD_ALL_DIGESTS = 0x00000008L; 290 adapter_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, null); 291 adapter_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, null); 292 } 293 294 SSL_METHOD* TLSv1_client_method() const { 295 if ( adapter_TLSv1_client_method is null ) { 296 throw new Exception("openssl not initialized - is it installed?"); 297 } 298 return adapter_TLSv1_client_method(); 299 } 300 SSL_METHOD* TLSv1_2_client_method() const { 301 if ( adapter_TLSv1_2_client_method is null ) { 302 throw new Exception("openssl not initialized - is it installed?"); 303 } 304 return adapter_TLSv1_2_client_method(); 305 } 306 SSL_METHOD* SSLv23_client_method() const { 307 if ( adapter_SSLv23_client_method is null ) { 308 throw new Exception("can't complete call to SSLv23_client_method"); 309 } 310 return adapter_SSLv23_client_method(); 311 } 312 SSL_METHOD* TLS_method() const { 313 if ( adapter_TLS_method !is null ) { 314 return adapter_TLS_method(); 315 } 316 if ( adapter_SSLv23_client_method !is null ) { 317 return adapter_SSLv23_client_method(); 318 } 319 throw new Exception("can't complete call to TLS_method"); 320 } 321 SSL_CTX* SSL_CTX_new(SSL_METHOD* method) const { 322 if ( adapter_SSL_CTX_new is null ) { 323 throw new Exception("openssl not initialized - is it installed?"); 324 } 325 return adapter_SSL_CTX_new(method); 326 } 327 int SSL_CTX_set_default_verify_paths(SSL_CTX* ctx) const @nogc nothrow { 328 return adapter_SSL_CTX_set_default_verify_paths(ctx); 329 } 330 int SSL_CTX_load_verify_locations(SSL_CTX* ctx, char* CAFile, char* CAPath) const @nogc nothrow { 331 return adapter_SSL_CTX_load_verify_locations(ctx, CAFile, CAPath); 332 } 333 void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, void* callback) const @nogc nothrow { 334 adapter_SSL_CTX_set_verify(ctx, mode, callback); 335 } 336 int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int type) const @nogc nothrow { 337 return adapter_SSL_CTX_use_PrivateKey_file(ctx, file, type); 338 } 339 int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int type) const @nogc nothrow { 340 return adapter_SSL_CTX_use_certificate_file(ctx, file, type); 341 } 342 int SSL_CTX_set_cipher_list(SSL_CTX* ssl_ctx, const char* c) const @nogc nothrow { 343 return adapter_SSL_CTX_set_cipher_list(ssl_ctx, c); 344 } 345 /* 346 * 347 * # define SSL_CTRL_SET_MIN_PROTO_VERSION 123 348 * # define SSL_CTRL_SET_MAX_PROTO_VERSION 124 349 */ 350 enum int SSL_CTRL_SET_MIN_PROTO_VERSION = 123; 351 enum int SSL_CTRL_SET_MAX_PROTO_VERSION = 124; 352 int SSL_CTX_set_min_proto_version(SSL_CTX* ctx, int v) const @nogc nothrow { 353 int r = cast(int)adapter_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, cast(c_long)v, null); 354 return r; 355 } 356 int SSL_CTX_set_max_proto_version(SSL_CTX* ctx, int v) const @nogc nothrow { 357 int r = cast(int)adapter_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, cast(c_long)v, null); 358 return r; 359 } 360 SSL* SSL_new(SSL_CTX* ctx) const @nogc nothrow { 361 return adapter_SSL_new(ctx); 362 } 363 int SSL_set_fd(SSL* ssl, int fd) const @nogc nothrow { 364 return adapter_SSL_set_fd(ssl, fd); 365 } 366 int SSL_connect(SSL* ssl) const @nogc nothrow { 367 return adapter_SSL_connect(ssl); 368 } 369 int SSL_read(SSL* ssl, void *b, int n) const @nogc nothrow { 370 return adapter_SSL_read(ssl, b, n); 371 } 372 int SSL_write(SSL* ssl, const void *b, int n) const @nogc nothrow { 373 return adapter_SSL_write(ssl, b, n); 374 } 375 void SSL_free(SSL* ssl) const @nogc nothrow @trusted { 376 adapter_SSL_free(ssl); 377 } 378 void SSL_CTX_free(SSL_CTX* ctx) const @nogc nothrow @trusted { 379 adapter_SSL_CTX_free(ctx); 380 } 381 int SSL_get_error(SSL* ssl, int err) const @nogc nothrow { 382 return adapter_SSL_get_error(ssl, err); 383 } 384 c_long SSL_set_tlsext_host_name(SSL* ssl, const char* host) const @nogc nothrow { 385 enum SSL_CTRL_SET_TLSEXT_HOSTNAME = 55; 386 enum TLSEXT_NAMETYPE_host_name = 0; 387 return adapter_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name, cast(void*)host); 388 } 389 char* ERR_reason_error_string(c_ulong code) const @nogc nothrow { 390 return adapter_ERR_reason_error_string(code); 391 } 392 c_ulong ERR_get_error() const @nogc nothrow { 393 return adapter_ERR_get_error(); 394 } 395 } 396 /* 397 int main() { 398 import std.socket; 399 400 auto v = openssl.reportVersion(); 401 writefln("openSSL v.%s.%s", v.major, v.minor); 402 openssl.SSL_library_init(); 403 writeln("InitSSL - ok"); 404 SSL_CTX* ctx = openssl.SSL_CTX_new(openssl.TLSv1_client_method()); 405 writefln("SSL_CTX_new = %x", ctx); 406 int r = openssl.adapter_SSL_CTX_set_default_verify_paths(ctx); 407 writefln("SSL_CTX_set_default_verify_paths = %d(%s)", r, r==1?"ok":"fail"); 408 r = openssl.adapter_SSL_CTX_load_verify_locations(ctx, cast(char*)null, cast(char*)null); 409 writefln("SSL_CTX_load_verify_locations - ok"); 410 openssl.SSL_CTX_set_verify(ctx, 0, null); 411 writefln("SSL_CTX_set_verify - ok"); 412 //r = openssl.SSL_CTX_use_PrivateKey_file(ctx, null, 0); 413 //writefln("SSL_CTX_use_PrivateKey_file = %d(%s)", r, r==1?"ok":"fail"); 414 //r = openssl.SSL_CTX_use_certificate_file(ctx, cast(char*), 0); 415 //writefln("SSL_CTX_use_certificate_file = %d(%s)", r, r==1?"ok":"fail"); 416 SSL* ssl = openssl.SSL_new(ctx); 417 writefln("SSL_new = %x", ssl); 418 auto s = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP); 419 Address[] a = getAddress("ns.od.ua", 443); 420 writeln(a[0]); 421 s.connect(a[0]); 422 r = openssl.SSL_set_fd(ssl, s.handle); 423 writefln("SSL_set_fd = %d(%s)", r, r==1?"ok":"fail"); 424 r = openssl.SSL_connect(ssl); 425 writefln("SSL_connect = %d(%s)", r, r==1?"ok":"fail"); 426 if ( r < 0 ) { 427 writefln("code: %d", openssl.SSL_get_error(ssl, r)); 428 } 429 string req = "GET / HTTP/1.0\n\n"; 430 r = openssl.SSL_write(ssl, cast(void*)req.ptr, cast(int)req.length); 431 writefln("SSL_write = %d", r); 432 do { 433 ubyte[] resp = new ubyte[](1024); 434 r = openssl.SSL_read(ssl, cast(void*)resp.ptr, cast(int)1024); 435 writefln("SSL_read = %d", r); 436 if ( r > 0 ) { 437 writeln(cast(string)resp); 438 } 439 } while(r > 0); 440 openssl.SSL_free(ssl); 441 openssl.SSL_CTX_free(ctx); 442 s.close(); 443 return 0; 444 } 445 */