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