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