arsd/sslsocket.d

166 lines
3.6 KiB
D

/* *
Don't use this file anymore. The maintained version is in http2.d, just use that.
Old docs below:
This is CLIENT only at this point. Don't try to
bind/accept with these.
FIXME: Windows isn't implemented
On Windows, it uses Microsoft schannel so it doesn't
need openssl or gnutls as a dependency.
On other platforms, it uses the openssl api, which should
work with both openssl and gnutls.
btw, interesting:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa364510%28v=vs.85%29.aspx
*/
module sslsocket;
import std.socket;
// see also:
// http://msdn.microsoft.com/en-us/library/aa380536%28v=vs.85%29.aspx
// import deimos.openssl.ssl;
version=use_openssl;
version(use_openssl) {
alias SslClientSocket = OpenSslSocket;
extern(C) {
int SSL_library_init();
void OpenSSL_add_all_ciphers();
void OpenSSL_add_all_digests();
void SSL_load_error_strings();
struct SSL {}
struct SSL_CTX {}
struct SSL_METHOD {}
SSL_CTX* SSL_CTX_new(const SSL_METHOD* method);
SSL* SSL_new(SSL_CTX*);
int SSL_pending(SSL*);
int SSL_set_fd(SSL*, int);
int SSL_connect(SSL*);
int SSL_write(SSL*, const void*, int);
int SSL_read(SSL*, void*, int);
void SSL_free(SSL*);
void SSL_CTX_free(SSL_CTX*);
void SSL_set_verify(SSL*, int, void*);
enum SSL_VERIFY_NONE = 0;
SSL_METHOD* SSLv3_client_method();
SSL_METHOD* TLS_client_method();
SSL_METHOD* SSLv23_client_method();
void ERR_print_errors_fp(FILE*);
}
import core.stdc.stdio;
shared static this() {
SSL_library_init();
OpenSSL_add_all_ciphers();
OpenSSL_add_all_digests();
SSL_load_error_strings();
}
pragma(lib, "crypto");
pragma(lib, "ssl");
class OpenSslSocket : Socket {
private SSL* ssl;
private SSL_CTX* ctx;
private void initSsl(bool verifyPeer) {
ctx = SSL_CTX_new(SSLv23_client_method());
assert(ctx !is null);
ssl = SSL_new(ctx);
if(!verifyPeer)
SSL_set_verify(ssl, SSL_VERIFY_NONE, null);
SSL_set_fd(ssl, cast(int) this.handle);
}
bool dataPending() {
return SSL_pending(ssl) > 0;
}
@trusted
override void connect(Address to) {
super.connect(to);
if(SSL_connect(ssl) == -1) {
ERR_print_errors_fp(stderr);
int i;
printf("wtf\n");
scanf("%d\n", &i);
throw new Exception("ssl connect");
}
}
@trusted
override ptrdiff_t send(scope const(void)[] buf, SocketFlags flags) {
auto retval = SSL_write(ssl, buf.ptr, cast(uint) buf.length);
if(retval == -1) {
ERR_print_errors_fp(stderr);
int i;
printf("wtf\n");
scanf("%d\n", &i);
throw new Exception("ssl send");
}
return retval;
}
override ptrdiff_t send(scope const(void)[] buf) {
return send(buf, SocketFlags.NONE);
}
@trusted
override ptrdiff_t receive(scope void[] buf, SocketFlags flags) {
auto retval = SSL_read(ssl, buf.ptr, cast(int)buf.length);
if(retval == -1) {
ERR_print_errors_fp(stderr);
int i;
printf("wtf\n");
scanf("%d\n", &i);
throw new Exception("ssl send");
}
return retval;
}
override ptrdiff_t receive(scope void[] buf) {
return receive(buf, SocketFlags.NONE);
}
this(AddressFamily af, SocketType type = SocketType.STREAM, bool verifyPeer = true) {
super(af, type);
initSsl(verifyPeer);
}
this(socket_t sock, AddressFamily af) {
super(sock, af);
initSsl(true);
}
~this() {
SSL_free(ssl);
SSL_CTX_free(ctx);
}
}
}
version(ssl_test)
void main() {
auto sock = new SslClientSocket(AddressFamily.INET);
sock.connect(new InternetAddress("localhost", 443));
sock.send("GET / HTTP/1.0\r\n\r\n");
import std.stdio;
char[1024] buffer;
writeln(buffer[0 .. sock.receive(buffer)]);
}