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 }