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