1 /**
2 	This is CLIENT only at this point. Don't try to
3 	bind/accept with these.
4 
5 	FIXME: Windows isn't implemented
6 
7 	On Windows, it uses Microsoft schannel so it doesn't
8 	need openssl or gnutls as a dependency.
9 
10 	On other platforms, it uses the openssl api, which should
11 	work with both openssl and gnutls.
12 
13 
14 	btw, interesting:
15 	http://msdn.microsoft.com/en-us/library/windows/desktop/aa364510%28v=vs.85%29.aspx
16 */
17 module sslsocket;
18 
19 
20 public import std.socket;
21 
22 // see also:
23 // http://msdn.microsoft.com/en-us/library/aa380536%28v=vs.85%29.aspx
24 
25 // import deimos.openssl.ssl;
26 
27 version=use_openssl;
28 
29 version(use_openssl) {
30 	alias SslClientSocket = OpenSslSocket;
31 
32 	extern(C) {
33 		int SSL_library_init();
34 		void OpenSSL_add_all_ciphers();
35 		void OpenSSL_add_all_digests();
36 		void SSL_load_error_strings();
37 
38 		struct SSL {}
39 		struct SSL_CTX {}
40 		struct SSL_METHOD {}
41 
42 		SSL_CTX* SSL_CTX_new(const SSL_METHOD* method);
43 		SSL* SSL_new(SSL_CTX*);
44 		int SSL_pending(SSL*);
45 		int SSL_set_fd(SSL*, int);
46 		int SSL_connect(SSL*);
47 		int SSL_write(SSL*, const void*, int);
48 		int SSL_read(SSL*, void*, int);
49 		void SSL_free(SSL*);
50 		void SSL_CTX_free(SSL_CTX*);
51 
52 		void SSL_set_verify(SSL*, int, void*);
53 		enum SSL_VERIFY_NONE = 0;
54 
55 		SSL_METHOD* SSLv3_client_method();
56 		SSL_METHOD* TLS_client_method();
57 		SSL_METHOD* SSLv23_client_method();
58 
59 		void ERR_print_errors_fp(FILE*);
60 	}
61 
62 	import core.stdc.stdio;
63 
64 	shared static this() {
65 		SSL_library_init();
66 		OpenSSL_add_all_ciphers();
67 		OpenSSL_add_all_digests();
68 		SSL_load_error_strings();
69 	}
70 
71 	pragma(lib, "crypto");
72 	pragma(lib, "ssl");
73 
74 	class OpenSslSocket : Socket {
75 		private SSL* ssl;
76 		private SSL_CTX* ctx;
77 		private void initSsl(bool verifyPeer) {
78 			ctx = SSL_CTX_new(SSLv23_client_method());
79 			assert(ctx !is null);
80 
81 			ssl = SSL_new(ctx);
82 			if(!verifyPeer)
83 				SSL_set_verify(ssl, SSL_VERIFY_NONE, null);
84 			SSL_set_fd(ssl, cast(int) this.handle);
85 		}
86 
87 		bool dataPending() {
88 			return SSL_pending(ssl) > 0;
89 		}
90 
91 		@trusted
92 		override void connect(Address to) {
93 			super.connect(to);
94 			if(SSL_connect(ssl) == -1) {
95 				ERR_print_errors_fp(stderr);
96 				int i;
97 				printf("wtf\n");
98 				scanf("%d\n", i);
99 				throw new Exception("ssl connect");
100 			}
101 		}
102 		
103 		@trusted
104 		override ptrdiff_t send(const(void)[] buf, SocketFlags flags) {
105 			auto retval = SSL_write(ssl, buf.ptr, cast(uint) buf.length);
106 			if(retval == -1) {
107 				ERR_print_errors_fp(stderr);
108 				int i;
109 				printf("wtf\n");
110 				scanf("%d\n", i);
111 				throw new Exception("ssl send");
112 			}
113 			return retval;
114 
115 		}
116 		override ptrdiff_t send(const(void)[] buf) {
117 			return send(buf, SocketFlags.NONE);
118 		}
119 		@trusted
120 		override ptrdiff_t receive(void[] buf, SocketFlags flags) {
121 			auto retval = SSL_read(ssl, buf.ptr, cast(int)buf.length);
122 			if(retval == -1) {
123 				ERR_print_errors_fp(stderr);
124 				int i;
125 				printf("wtf\n");
126 				scanf("%d\n", i);
127 				throw new Exception("ssl send");
128 			}
129 			return retval;
130 		}
131 		override ptrdiff_t receive(void[] buf) {
132 			return receive(buf, SocketFlags.NONE);
133 		}
134 
135 		this(AddressFamily af, SocketType type = SocketType.STREAM, bool verifyPeer = true) {
136 			super(af, type);
137 			initSsl(verifyPeer);
138 		}
139 
140 		this(socket_t sock, AddressFamily af) {
141 			super(sock, af);
142 			initSsl(true);
143 		}
144 
145 		~this() {
146 			SSL_free(ssl);
147 			SSL_CTX_free(ctx);
148 		}
149 	}
150 }
151 
152 version(ssl_test)
153 void main() {
154 	auto sock = new SslClientSocket(AddressFamily.INET);
155 	sock.connect(new InternetAddress("localhost", 443));
156 	sock.send("GET / HTTP/1.0\r\n\r\n");
157 	import std.stdio;
158 	char[1024] buffer;
159 	writeln(buffer[0 .. sock.receive(buffer)]);
160 }