1 module mail.socket; 2 3 import std.conv : to; 4 import std.socket; 5 6 import deimos.openssl.conf; 7 import deimos.openssl.err; 8 import deimos.openssl.ssl; 9 10 enum EncryptionMethod : uint 11 { 12 None, // No encryption is used 13 // SSLv23, // SSL version 3 but rollback to 2 14 // SSLv3, // SSL version 3 encryption 15 TLSv1, // TLS version 1 encryption 16 TLSv1_1, // TLS version 1.1 encryption 17 TLSv1_2, // TLS version 1.2 encryption 18 } 19 20 class Socket 21 { 22 private 23 { 24 bool _open; 25 string _host; 26 ushort _port; 27 TcpSocket _sock; 28 char[4096] _buff; 29 30 bool _secure; 31 bool _verified; 32 33 SSL_METHOD* _sslMethod; 34 SSL_CTX* _sslCtx; 35 SSL* _ssl; 36 X509* _x509; 37 } 38 39 public: 40 @property bool isOpen() const 41 { 42 return _open; 43 } 44 45 @property bool isSecure() const 46 { 47 return _secure; 48 } 49 50 @property bool isCertVerified() const 51 { 52 return _verified; 53 } 54 55 @property string hostName() const 56 { 57 return _sock.hostName; 58 } 59 60 public: 61 this(string host, ushort port) 62 { 63 _host = host; 64 _port = port; 65 _sock = new TcpSocket(); 66 } 67 68 ~this() 69 { 70 SSLEnd(); 71 } 72 73 bool connect() 74 { 75 try 76 { 77 auto ai = getAddress(_host, _port); 78 if (ai.length) 79 { 80 _sock.connect(ai[0]); 81 return _open = true; 82 } 83 } 84 catch (Throwable) {} 85 return false; 86 } 87 88 void disconnect() 89 { 90 if (_sock !is null) 91 { 92 _open = false; 93 _sock.shutdown(SocketShutdown.BOTH); 94 _sock.close(); 95 } 96 } 97 98 bool SSLbegin(EncryptionMethod encMethod = EncryptionMethod.TLSv1_2) 99 { 100 import std.stdio; 101 102 // Init 103 OPENSSL_config(""); 104 SSL_library_init(); 105 SSL_load_error_strings(); 106 107 final switch (encMethod) 108 { 109 // case EncryptionMethod.SSLv23: 110 // _sslMethod = cast(SSL_METHOD*) SSLv23_client_method(); 111 // break; 112 // case EncryptionMethod.SSLv3: 113 // _sslMethod = cast(SSL_METHOD*) SSLv3_client_method(); 114 // break; 115 case EncryptionMethod.TLSv1: 116 _sslMethod = cast(SSL_METHOD*) TLSv1_client_method(); 117 break; 118 case EncryptionMethod.TLSv1_1: 119 _sslMethod = cast(SSL_METHOD*) TLSv1_2_client_method(); 120 break; 121 case EncryptionMethod.TLSv1_2: 122 _sslMethod = cast(SSL_METHOD*) TLSv1_2_client_method(); 123 break; 124 case EncryptionMethod.None: 125 return false; 126 } 127 128 _sslCtx = SSL_CTX_new(cast(const(SSL_METHOD*))(_sslMethod)); 129 if (_sslCtx is null) 130 return false; 131 132 // Stream 133 _ssl = SSL_new(_sslCtx); 134 if (_ssl is null) 135 return false; 136 137 version (Win64) 138 SSL_set_fd(_ssl, cast(int) _sock.handle); 139 else 140 SSL_set_fd(_ssl, _sock.handle); 141 142 // Handshake 143 if (SSL_connect(_ssl) != 1) 144 return false; 145 146 _x509 = SSL_get_peer_certificate(_ssl); 147 148 if (_x509 is null) 149 return false; 150 151 _secure = true; 152 153 // Verify 154 if (SSL_get_verify_result(_ssl) != X509_V_OK) 155 { 156 _verified = false; 157 } 158 else 159 { 160 _verified = true; 161 } 162 return _secure; 163 } 164 165 void SSLEnd() 166 { 167 if (_secure) 168 { 169 _secure = false; 170 SSL_shutdown(_ssl); 171 } 172 173 if (_x509 !is null) 174 { 175 X509_free(_x509); 176 _x509 = null; 177 } 178 179 if (_ssl !is null) 180 { 181 SSL_free(_ssl); 182 _ssl = null; 183 } 184 185 if (_sslCtx !is null) 186 { 187 SSL_CTX_free(_sslCtx); 188 _sslCtx = null; 189 } 190 } 191 192 bool send(string data) 193 { 194 if (_secure) 195 { 196 return SSL_write(_ssl, data.ptr, data.length.to!int) >= 0; 197 } 198 return _sock.send(data) == data.length; 199 } 200 201 string receive() 202 { 203 int len; 204 if (_secure) 205 { 206 len = SSL_read(_ssl, _buff.ptr, _buff.length); 207 if (len < 0) 208 { 209 len = 0; 210 } 211 } 212 else 213 { 214 len = cast(int) _sock.receive(_buff); 215 } 216 return _buff[0 .. len].to!string; 217 } 218 }