Prior work:
1. Download OpenSSL D interface from https://github.com/D-Programming-Deimos/openssl and extract 2. install openssl-static (or other package inclued /usr/lib/libssl.a and /usr/lib/libcrypto.a) 3. before compile, put your source file into D-Programming-Deimos-openssl-xxx
or use -I/xxx/D-Programming-Deimos-openssl-xxx with compiler.

Example code:

//Server
import std.stdio;
import std.socket;
import std.algorithm;
import core.thread;
import deimos.openssl.ssl;
import deimos.openssl.err;
static import std.c.stdio;

const ListenAddress = "127.0.0.1";
const ListenPort = 10443;
const RecvSize = 1024;
const CertFile = "server_cert.pem";
const KeyFile = "server_key.pem";

class SSLConnection : Thread{
        Socket r;
        char[RecvSize] buf;
        uint len;
        SSL_CTX *ctx;
        SSL *ssl;
        
        this(Socket r, SSL_CTX *ctx){
                this.r = r;
                this.ctx = ctx;
                this.isDaemon(true);
                super(&run);
        }
        
        void run(){
                writeln("new connection from ", r.remoteAddress().toString());
                
                ssl = SSL_new(ctx);
                SSL_set_fd(ssl, r.handle());
                sslAssert(SSL_accept(ssl) != -1);
                
                while (r.isAlive()){
                        len = SSL_read(ssl, cast(void*) buf, RecvSize);
                        if (len <= 0){
                                break;
                        }
                        writeln("ssl read ", len, " bytes: ", buf[0 .. len]);
                        SSL_write(ssl, cast(const void*) buf[0 .. len], len);
                }
                
                if (r.isAlive()){
writeln("close connection from ", r.remoteAddress().toString());
                }
                SSL_free(ssl);
                r.close();
        }
}

void sslAssert(bool ret){
        if (!ret){
                ERR_print_errors_fp(std.c.stdio.stderr);
                throw new Exception("SSL_ERROR");
        }
}

void initSSL(){
        SSL_library_init();
        OpenSSL_add_all_algorithms();
        SSL_load_error_strings();
}

SSL_CTX *getCTX(string certfile, string keyfile){
        SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method());
        sslAssert(!(ctx is null));
sslAssert(SSL_CTX_use_certificate_file(ctx, cast(const char*) certfile, SSL_FILETYPE_PEM) > 0); sslAssert(SSL_CTX_use_PrivateKey_file(ctx, cast(const char*) keyfile, SSL_FILETYPE_PEM) > 0);
        sslAssert(SSL_CTX_check_private_key(ctx) > 0);
        return ctx;
}

int main(string[] args){
        initSSL();
        SSL_CTX *ctx = getCTX(CertFile, KeyFile);
        
        Socket s = new TcpSocket();
s.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
        s.bind(new InternetAddress(ListenAddress, ListenPort));
        s.listen(10);
        
        writef("listen %s:%d\n", ListenAddress, ListenPort);
        while (s.isAlive()){
                Thread ss = new SSLConnection(s.accept(), ctx);
                ss.start();
        }
        
        s.close();
        SSL_CTX_free(ctx);
        return 0;
}





//Client
import std.stdio;
import std.socket;
import std.algorithm;
import std.string;
import core.thread;
import core.memory;
import deimos.openssl.ssl;
import deimos.openssl.err;
import deimos.openssl.sha;
static import std.c.stdio;

const ConnectAddress = "127.0.0.1";
const ConnectPort = 10443;
const BufSize = 1024;
const msg = "test message";

void sslAssert(bool ret){
        if (!ret){
                ERR_print_errors_fp(std.c.stdio.stderr);
                throw new Exception("SSL_ERROR");
        }
}

string getSha256(string input){
        char[SHA256_DIGEST_LENGTH] hash;
        string hash_hex;
        SHA256_CTX *sha256 = new SHA256_CTX;
        SHA256_Init(sha256);
        SHA256_Update(sha256, cast(const void*) input, input.length);
        SHA256_Final(cast(ubyte*) hash, sha256);
        for(int i=0; i<SHA256_DIGEST_LENGTH; i++){
                hash_hex ~= format("%02x", hash[i]);
        }
        return hash_hex;
}

string getCertInfo(X509 *cert){
        char buf[BufSize];
        uint len;
        string data;
        BIO* strio = BIO_new(BIO_s_mem());
        X509_print(strio, cert);
        //BIO_ctrl(strio, BIO_C_FILE_SEEK, 0, null);
        while (true){
                len = BIO_gets(strio, cast(char*) buf, BufSize);
                if (len <= 0){
                        break;
                }
                data ~= buf[0 .. len];
        }
        BIO_free(strio);
        return data;
}

bool verifyCert(X509 *cert){
        X509_print_fp(std.c.stdio.stdout, cert);
        
        /* PEM_read... are broken
//std.c.stdio.FILE *fp = std.c.stdio.fopen(cast(char*) CertFile, "rb");
        BIO* lcertio = BIO_new_file(cast(char*) "server_cert.pem", "rb");
        X509* lcert = PEM_read_bio_X509(lcertio, null, null, null);
        writeln(X509_verify(lcert, X509_get_pubkey(cert)));
        X509_free(lcert);
        BIO_free(lcertio);*/
        
        string cert_hash = getSha256(getCertInfo(cert));
        writeln("sha256: ", cert_hash);
        
return true; //or return (cert_hash == some_const_value) to verify cert
}

int main(string[] args){
        char buf[BufSize];
        uint len;
        
        SSL_library_init();
        OpenSSL_add_all_algorithms();
        SSL_load_error_strings();
        
        SSL_CTX *ctx = SSL_CTX_new(SSLv3_client_method());
        sslAssert(!(ctx is null));
        
        Socket r = new TcpSocket();
        r.connect(new InternetAddress(ConnectAddress, ConnectPort));
        
        SSL *ssl = SSL_new(ctx);
        SSL_set_fd(ssl, r.handle());
        sslAssert(SSL_connect(ssl) != -1);
        
        if (!verifyCert(SSL_get_peer_certificate(ssl))){
                throw new Exception("verify cert failed");
        }
        
        SSL_write(ssl, cast(const char*) msg, msg.length);
        len = SSL_read(ssl, cast(void*) buf, BufSize);
        writef("get reply %d bytes: %s\n", len, buf[0 .. len]);
        
        SSL_free(ssl);
        r.close();
        
        SSL_CTX_free(ctx);
        return 0;
}



Build:
You need link ssl and crypto, in dmd, there are -L-lssl -L-lcrypto
ex:
dmd server.d -L-lssl -L-lcrypto -I/xxx/D-Programming-Deimos-openssl-xxx

Problem:
1. These example could not compile with rdmd on rhel6.
will error at ld like undefined reference to xxxx , xxyy, xxzz ...
2. PEM_read... are broken (ld error), the example use sha256 to verify certificate.

Reply via email to