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