1 module smtp.ssl; 2 3 version(ssl) { 4 5 import std.algorithm; 6 import std.stdio; 7 import std.conv; 8 import std.socket; 9 10 import deimos.openssl.ssl; 11 import deimos.openssl.conf; 12 import deimos.openssl.err; 13 import deimos.openssl.ssl; 14 15 } 16 17 /++ 18 Encryption methods for use with SSL 19 +/ 20 enum EncryptionMethod : uint { 21 None = 0, // No encryption is used 22 23 SSLv2 = 1, // SSL version 2 encryption 24 SSLv23 = 2, // SSL version 23 encryption 25 SSLv3 = 3, // SSL version 3 encryption 26 27 TLSv1 = 4, // TLS version 1 encryption 28 } 29 30 version(ssl) { 31 /++ 32 Initializes OpenSSL library 33 +/ 34 void initializeSSL() { 35 OPENSSL_config(""); 36 SSL_library_init(); 37 SSL_load_error_strings(); 38 } 39 40 /++ 41 SSL-encrypted socket-based transport 42 +/ 43 class SocketSSL { 44 45 private: 46 bool m_verified; 47 bool m_ready; 48 49 SSL_METHOD *encmethod; 50 SSL_CTX* ctx; 51 SSL *ssl; 52 X509* certificate; 53 54 public: 55 56 @property bool ready() { return m_ready; } 57 @property bool certificateIsVerified() { return m_verified; } 58 59 this(Socket socket, EncryptionMethod enctype = EncryptionMethod.SSLv3) { 60 initializeSSL(); 61 62 // Creating SSL context 63 final switch (enctype) { 64 case EncryptionMethod.SSLv2: 65 version(ssl_no_ssl2) { return; } else { 66 encmethod = cast(SSL_METHOD*)SSLv2_client_method(); 67 break; 68 } 69 case EncryptionMethod.SSLv23: 70 encmethod = cast(SSL_METHOD*)SSLv23_client_method(); 71 break; 72 case EncryptionMethod.SSLv3: 73 encmethod = cast(SSL_METHOD*)SSLv3_client_method(); 74 break; 75 case EncryptionMethod.TLSv1: 76 encmethod = cast(SSL_METHOD*)TLSv1_client_method(); 77 break; 78 case EncryptionMethod.None: 79 return; 80 } 81 ctx = SSL_CTX_new(cast(const(SSL_METHOD*))(encmethod)); 82 if (ctx == null) { 83 writeln("SSL context creation error"); 84 return; 85 } 86 87 // Creating secure data stream 88 ssl = SSL_new(ctx); 89 if (ssl == null) { 90 return; 91 } 92 SSL_set_fd(ssl, socket.handle); 93 94 // Making SSL handshake 95 auto ret = SSL_connect(ssl); 96 if (ret != 1) { 97 return; 98 } 99 100 // Get certificate 101 certificate = SSL_get_peer_certificate(ssl); 102 if (certificate == null) { 103 return; 104 } 105 106 m_ready = true; 107 108 // Verify certificate 109 long verificationResult = SSL_get_verify_result(ssl); 110 if (verificationResult != X509_V_OK) { 111 m_verified = false; 112 } else { 113 m_verified = true; 114 } 115 } 116 117 /++ 118 Method encrypts data and writes it into channel 119 +/ 120 bool write(in char[] data) { 121 return SSL_write(ssl, data.ptr, to!(int)(data.length)) >= 0; 122 } 123 124 /++ 125 Methods reads data from channel and returns it in an unencrypted presentation 126 +/ 127 string read() { 128 char[1024] buf; 129 int ret = SSL_read(ssl, buf.ptr, buf.length); 130 if (ret < 0) { 131 return ""; 132 } else { 133 for(int index = buf.length - 1; index--; index > 0) { 134 if (buf[index] == '\n' && buf[index - 1] == '\r') { 135 return to!string(buf[0 .. index + 1]); 136 } 137 } 138 return to!string(buf); 139 } 140 } 141 142 ~ this() { 143 if (m_ready) SSL_shutdown(this.ssl); 144 145 if (certificate != null) X509_free(certificate); 146 if (ssl != null) SSL_free(ssl); 147 if (ctx != null) SSL_CTX_free(ctx); 148 } 149 }; 150 }