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