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