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 "libssl-3"w, 125 "libssl-3-x64"w, 126 ]; 127 immutable wstring[] libcryptoname = [ 128 "libeay32.dll"w, 129 "libcrypto-1_1"w, 130 "libcrypto-1_1-x64"w, 131 "libcrypto-3"w, 132 "libcrypto-3-x64"w, 133 ]; 134 } else { 135 debug(requests) trace("error loading openssl: unsupported system - first access over https will fail"); 136 return; 137 } 138 139 static if ( enableSSL && is(typeof(loadFunction)) ) { 140 foreach(lib; libsslname) { 141 openssl._libssl = cast(typeof(openssl._libssl))mixin(loadFunction); 142 if ( openssl._libssl !is null ) { 143 debug(requests) tracef("will use %s".format(lib)); 144 break; 145 } 146 } 147 foreach(lib; libcryptoname) { 148 openssl._libcrypto = cast(typeof(openssl._libcrypto))mixin(loadFunction); 149 if ( openssl._libcrypto !is null ) { 150 debug(requests) tracef("will use %s".format(lib)); 151 break; 152 } 153 } 154 } 155 156 if ( openssl._libssl is null ) { 157 debug(requests) trace("warning: failed to load libssl - first access over https will fail"); 158 return; 159 } 160 if ( openssl._libcrypto is null ) { 161 debug(requests) trace("warning: failed to load libcrypto - first access over https will fail"); 162 return; 163 } 164 openssl._ver = openssl.OpenSSL_version_detect(); 165 166 mixin(SSL_Function_set_i!("SSL_library_init", int)); 167 mixin(CRYPTO_Function_set_i!("OpenSSL_add_all_ciphers", void)); 168 mixin(CRYPTO_Function_set_i!("OpenSSL_add_all_digests", void)); 169 mixin(SSL_Function_set_i!("SSL_load_error_strings", void)); 170 171 mixin(SSL_Function_set_i!("OPENSSL_init_ssl", int, ulong, void*)); 172 mixin(CRYPTO_Function_set_i!("OPENSSL_init_crypto", int, ulong, void*)); 173 174 mixin(SSL_Function_set_i!("TLSv1_client_method", SSL_METHOD*)); 175 mixin(SSL_Function_set_i!("TLSv1_2_client_method", SSL_METHOD*)); 176 mixin(SSL_Function_set_i!("TLS_method", SSL_METHOD*)); 177 mixin(SSL_Function_set_i!("SSLv23_client_method", SSL_METHOD*)); 178 mixin(SSL_Function_set_i!("SSL_CTX_new", SSL_CTX*, SSL_METHOD*)); 179 mixin(SSL_Function_set_i!("SSL_CTX_set_default_verify_paths", int, SSL_CTX*)); 180 mixin(SSL_Function_set_i!("SSL_CTX_load_verify_locations", int, SSL_CTX*, char*, char*)); 181 mixin(SSL_Function_set_i!("SSL_CTX_set_verify", void, SSL_CTX*, int, void*)); 182 mixin(SSL_Function_set_i!("SSL_CTX_use_PrivateKey_file", int, SSL_CTX*, const char*, int)); 183 mixin(SSL_Function_set_i!("SSL_CTX_use_certificate_file", int, SSL_CTX*, const char*, int)); 184 mixin(SSL_Function_set_i!("SSL_CTX_set_cipher_list", int, SSL_CTX*, const char*)); 185 mixin(SSL_Function_set_i!("SSL_CTX_ctrl", c_long, SSL_CTX*, int, c_long, void*)); 186 mixin(SSL_Function_set_i!("SSL_new", SSL*, SSL_CTX*)); 187 mixin(SSL_Function_set_i!("SSL_set_fd", int, SSL*, int)); 188 mixin(SSL_Function_set_i!("SSL_connect", int, SSL*)); 189 mixin(SSL_Function_set_i!("SSL_write", int, SSL*, const void*, int)); 190 mixin(SSL_Function_set_i!("SSL_read", int, SSL*, void*, int)); 191 mixin(SSL_Function_set_i!("SSL_free", void, SSL*)); 192 mixin(SSL_Function_set_i!("SSL_CTX_free", void, SSL_CTX*)); 193 mixin(SSL_Function_set_i!("SSL_get_error", int, SSL*, int)); 194 mixin(SSL_Function_set_i!("SSL_ctrl", c_long, SSL*, int, c_long, void*)); 195 mixin(CRYPTO_Function_set_i!("ERR_reason_error_string", char*, c_ulong)); 196 mixin(CRYPTO_Function_set_i!("ERR_get_error", c_ulong)); 197 198 void delegate()[Version] init_matrix; 199 init_matrix[Version(1,0)] = &openssl.init1_0; 200 init_matrix[Version(1,1)] = &openssl.init1_1; 201 init_matrix[Version(2,0)] = &openssl.init1_1; 202 init_matrix[Version(0,2)] = &openssl.init1_1; // libressl >= 2.7.1 203 init_matrix[Version(0,3)] = &openssl.init1_1; // libressl >= 3.0.0 204 init_matrix[Version(3,0)] = &openssl.init1_1; // >=3.0 205 auto initVer = (ver) { 206 if (ver.major == 3 && ver.minor >= 1) // set 3.x to 3.0 for the init matrix 207 return Version(3, 0); 208 else 209 return ver; 210 }(openssl._ver); 211 auto init = init_matrix.get(initVer, null); 212 if ( init is null ) { 213 throw new Exception("loading openssl: unknown version %s for init".format(openssl._ver)); 214 } 215 init(); 216 } 217 218 struct OpenSSL { 219 220 private { 221 Version _ver; 222 void* _libssl; 223 void* _libcrypto; 224 225 // openssl 1.0.x init functions 226 mixin(SSL_Function_decl!("SSL_library_init", int)); 227 mixin(SSL_Function_decl!("OpenSSL_add_all_ciphers", void)); 228 mixin(SSL_Function_decl!("OpenSSL_add_all_digests", void)); 229 mixin(SSL_Function_decl!("SSL_load_error_strings", void)); 230 231 // openssl 1.1.x init functions 232 mixin(SSL_Function_decl!("OPENSSL_init_ssl", int, ulong, void*)); // fixed width 64 bit arg 233 mixin(SSL_Function_decl!("OPENSSL_init_crypto", int, ulong, void*)); // fixed width 64 bit arg 234 235 // all other functions 236 mixin(SSL_Function_decl!("TLSv1_client_method", SSL_METHOD*)); 237 mixin(SSL_Function_decl!("TLSv1_2_client_method", SSL_METHOD*)); 238 mixin(SSL_Function_decl!("TLS_method", SSL_METHOD*)); 239 mixin(SSL_Function_decl!("SSLv23_client_method", SSL_METHOD*)); 240 mixin(SSL_Function_decl!("SSL_CTX_new", SSL_CTX*, SSL_METHOD*)); 241 mixin(SSL_Function_decl!("SSL_CTX_set_default_verify_paths", int, SSL_CTX*)); 242 mixin(SSL_Function_decl!("SSL_CTX_load_verify_locations", int, SSL_CTX*, char*, char*)); 243 mixin(SSL_Function_decl!("SSL_CTX_set_verify", void, SSL_CTX*, int, void*)); 244 mixin(SSL_Function_decl!("SSL_CTX_use_PrivateKey_file", int, SSL_CTX*, const char*, int)); 245 mixin(SSL_Function_decl!("SSL_CTX_use_certificate_file", int, SSL_CTX*, const char*, int)); 246 mixin(SSL_Function_decl!("SSL_CTX_set_cipher_list", int, SSL_CTX*, const char*)); 247 mixin(SSL_Function_decl!("SSL_CTX_ctrl", c_long, SSL_CTX*, int, c_long, void*)); 248 mixin(SSL_Function_decl!("SSL_new", SSL*, SSL_CTX*)); 249 mixin(SSL_Function_decl!("SSL_set_fd", int, SSL*, int)); 250 mixin(SSL_Function_decl!("SSL_connect", int, SSL*)); 251 mixin(SSL_Function_decl!("SSL_write", int, SSL*, const void*, int)); 252 mixin(SSL_Function_decl!("SSL_read", int, SSL*, void*, int)); 253 mixin(SSL_Function_decl!("SSL_free", void, SSL*)); 254 mixin(SSL_Function_decl!("SSL_CTX_free", void, SSL_CTX*)); 255 mixin(SSL_Function_decl!("SSL_get_error", int, SSL*, int)); 256 mixin(SSL_Function_decl!("SSL_ctrl", c_long, SSL*, int, c_long, void*)); 257 mixin(SSL_Function_decl!("ERR_reason_error_string", char*, c_ulong)); 258 mixin(SSL_Function_decl!("ERR_get_error", c_ulong)); 259 } 260 261 Version reportVersion() const @nogc nothrow pure { 262 return _ver; 263 }; 264 265 private Version OpenSSL_version_detect() const { 266 c_ulong function() OpenSSL_version_num = cast(c_ulong function())DLSYM(cast(void*)_libcrypto, "OpenSSL_version_num".ptr); 267 if ( OpenSSL_version_num ) { 268 auto v = OpenSSL_version_num() & 0xffffffff; 269 return Version((v>>>28) & 0xff, (v>>>20) & 0xff); 270 } 271 return Version(1, 0); 272 } 273 274 private void init1_0() const { 275 adapter_SSL_library_init(); 276 adapter_OpenSSL_add_all_ciphers(); 277 adapter_OpenSSL_add_all_digests(); 278 adapter_SSL_load_error_strings(); 279 } 280 private void init1_1() const { 281 /** 282 Standard initialisation options 283 284 #define OPENSSL_INIT_LOAD_SSL_STRINGS 0x00200000L 285 286 # define OPENSSL_INIT_LOAD_CRYPTO_STRINGS 0x00000002L 287 # define OPENSSL_INIT_ADD_ALL_CIPHERS 0x00000004L 288 # define OPENSSL_INIT_ADD_ALL_DIGESTS 0x00000008L 289 **/ 290 enum OPENSSL_INIT_LOAD_SSL_STRINGS = 0x00200000L; 291 enum OPENSSL_INIT_LOAD_CRYPTO_STRINGS = 0x00000002L; 292 enum OPENSSL_INIT_ADD_ALL_CIPHERS = 0x00000004L; 293 enum OPENSSL_INIT_ADD_ALL_DIGESTS = 0x00000008L; 294 adapter_OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, null); 295 adapter_OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, null); 296 } 297 298 SSL_METHOD* TLSv1_client_method() const { 299 if ( adapter_TLSv1_client_method is null ) { 300 throw new Exception("openssl not initialized - is it installed?"); 301 } 302 return adapter_TLSv1_client_method(); 303 } 304 SSL_METHOD* TLSv1_2_client_method() const { 305 if ( adapter_TLSv1_2_client_method is null ) { 306 throw new Exception("openssl not initialized - is it installed?"); 307 } 308 return adapter_TLSv1_2_client_method(); 309 } 310 SSL_METHOD* SSLv23_client_method() const { 311 if ( adapter_SSLv23_client_method is null ) { 312 throw new Exception("can't complete call to SSLv23_client_method"); 313 } 314 return adapter_SSLv23_client_method(); 315 } 316 SSL_METHOD* TLS_method() const { 317 if ( adapter_TLS_method !is null ) { 318 return adapter_TLS_method(); 319 } 320 if ( adapter_SSLv23_client_method !is null ) { 321 return adapter_SSLv23_client_method(); 322 } 323 throw new Exception("can't complete call to TLS_method"); 324 } 325 SSL_CTX* SSL_CTX_new(SSL_METHOD* method) const { 326 if ( adapter_SSL_CTX_new is null ) { 327 throw new Exception("openssl not initialized - is it installed?"); 328 } 329 return adapter_SSL_CTX_new(method); 330 } 331 int SSL_CTX_set_default_verify_paths(SSL_CTX* ctx) const @nogc nothrow { 332 return adapter_SSL_CTX_set_default_verify_paths(ctx); 333 } 334 int SSL_CTX_load_verify_locations(SSL_CTX* ctx, char* CAFile, char* CAPath) const @nogc nothrow { 335 return adapter_SSL_CTX_load_verify_locations(ctx, CAFile, CAPath); 336 } 337 void SSL_CTX_set_verify(SSL_CTX* ctx, int mode, void* callback) const @nogc nothrow { 338 adapter_SSL_CTX_set_verify(ctx, mode, callback); 339 } 340 int SSL_CTX_use_PrivateKey_file(SSL_CTX* ctx, const char* file, int type) const @nogc nothrow { 341 return adapter_SSL_CTX_use_PrivateKey_file(ctx, file, type); 342 } 343 int SSL_CTX_use_certificate_file(SSL_CTX* ctx, const char* file, int type) const @nogc nothrow { 344 return adapter_SSL_CTX_use_certificate_file(ctx, file, type); 345 } 346 int SSL_CTX_set_cipher_list(SSL_CTX* ssl_ctx, const char* c) const @nogc nothrow { 347 return adapter_SSL_CTX_set_cipher_list(ssl_ctx, c); 348 } 349 /* 350 * 351 * # define SSL_CTRL_SET_MIN_PROTO_VERSION 123 352 * # define SSL_CTRL_SET_MAX_PROTO_VERSION 124 353 */ 354 enum int SSL_CTRL_SET_MIN_PROTO_VERSION = 123; 355 enum int SSL_CTRL_SET_MAX_PROTO_VERSION = 124; 356 int SSL_CTX_set_min_proto_version(SSL_CTX* ctx, int v) const @nogc nothrow { 357 int r = cast(int)adapter_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MIN_PROTO_VERSION, cast(c_long)v, null); 358 return r; 359 } 360 int SSL_CTX_set_max_proto_version(SSL_CTX* ctx, int v) const @nogc nothrow { 361 int r = cast(int)adapter_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_MAX_PROTO_VERSION, cast(c_long)v, null); 362 return r; 363 } 364 SSL* SSL_new(SSL_CTX* ctx) const @nogc nothrow { 365 return adapter_SSL_new(ctx); 366 } 367 int SSL_set_fd(SSL* ssl, int fd) const @nogc nothrow { 368 return adapter_SSL_set_fd(ssl, fd); 369 } 370 int SSL_connect(SSL* ssl) const @nogc nothrow { 371 return adapter_SSL_connect(ssl); 372 } 373 int SSL_read(SSL* ssl, void *b, int n) const @nogc nothrow { 374 return adapter_SSL_read(ssl, b, n); 375 } 376 int SSL_write(SSL* ssl, const void *b, int n) const @nogc nothrow { 377 return adapter_SSL_write(ssl, b, n); 378 } 379 void SSL_free(SSL* ssl) const @nogc nothrow @trusted { 380 adapter_SSL_free(ssl); 381 } 382 void SSL_CTX_free(SSL_CTX* ctx) const @nogc nothrow @trusted { 383 adapter_SSL_CTX_free(ctx); 384 } 385 int SSL_get_error(SSL* ssl, int err) const @nogc nothrow { 386 return adapter_SSL_get_error(ssl, err); 387 } 388 c_long SSL_set_tlsext_host_name(SSL* ssl, const char* host) const @nogc nothrow { 389 enum SSL_CTRL_SET_TLSEXT_HOSTNAME = 55; 390 enum TLSEXT_NAMETYPE_host_name = 0; 391 return adapter_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME,TLSEXT_NAMETYPE_host_name, cast(void*)host); 392 } 393 char* ERR_reason_error_string(c_ulong code) const @nogc nothrow { 394 return adapter_ERR_reason_error_string(code); 395 } 396 c_ulong ERR_get_error() const @nogc nothrow { 397 return adapter_ERR_get_error(); 398 } 399 } 400 /* 401 int main() { 402 import std.socket; 403 404 auto v = openssl.reportVersion(); 405 writefln("openSSL v.%s.%s", v.major, v.minor); 406 openssl.SSL_library_init(); 407 writeln("InitSSL - ok"); 408 SSL_CTX* ctx = openssl.SSL_CTX_new(openssl.TLSv1_client_method()); 409 writefln("SSL_CTX_new = %x", ctx); 410 int r = openssl.adapter_SSL_CTX_set_default_verify_paths(ctx); 411 writefln("SSL_CTX_set_default_verify_paths = %d(%s)", r, r==1?"ok":"fail"); 412 r = openssl.adapter_SSL_CTX_load_verify_locations(ctx, cast(char*)null, cast(char*)null); 413 writefln("SSL_CTX_load_verify_locations - ok"); 414 openssl.SSL_CTX_set_verify(ctx, 0, null); 415 writefln("SSL_CTX_set_verify - ok"); 416 //r = openssl.SSL_CTX_use_PrivateKey_file(ctx, null, 0); 417 //writefln("SSL_CTX_use_PrivateKey_file = %d(%s)", r, r==1?"ok":"fail"); 418 //r = openssl.SSL_CTX_use_certificate_file(ctx, cast(char*), 0); 419 //writefln("SSL_CTX_use_certificate_file = %d(%s)", r, r==1?"ok":"fail"); 420 SSL* ssl = openssl.SSL_new(ctx); 421 writefln("SSL_new = %x", ssl); 422 auto s = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP); 423 Address[] a = getAddress("ns.od.ua", 443); 424 writeln(a[0]); 425 s.connect(a[0]); 426 r = openssl.SSL_set_fd(ssl, s.handle); 427 writefln("SSL_set_fd = %d(%s)", r, r==1?"ok":"fail"); 428 r = openssl.SSL_connect(ssl); 429 writefln("SSL_connect = %d(%s)", r, r==1?"ok":"fail"); 430 if ( r < 0 ) { 431 writefln("code: %d", openssl.SSL_get_error(ssl, r)); 432 } 433 string req = "GET / HTTP/1.0\n\n"; 434 r = openssl.SSL_write(ssl, cast(void*)req.ptr, cast(int)req.length); 435 writefln("SSL_write = %d", r); 436 do { 437 ubyte[] resp = new ubyte[](1024); 438 r = openssl.SSL_read(ssl, cast(void*)resp.ptr, cast(int)1024); 439 writefln("SSL_read = %d", r); 440 if ( r > 0 ) { 441 writeln(cast(string)resp); 442 } 443 } while(r > 0); 444 openssl.SSL_free(ssl); 445 openssl.SSL_CTX_free(ctx); 446 s.close(); 447 return 0; 448 } 449 */