April 07, 2012 openssl example for D | |
|---|---|
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. | |
April 07, 2012 Re: openssl example for D | |
|---|---|
Posted in reply to lzzll | On Saturday, 7 April 2012 at 17:55:29 UTC, lzzll wrote:
> 2. PEM_read... are broken (ld error), the example use sha256 to
> verify certificate.
What exactly are the error messages you get?
David
|
April 07, 2012 Re: openssl example for D | |
|---|---|
Posted in reply to David Nadlinger | > What exactly are the error messages you get? dmd test_client.d -w -L-lssl -L-lcrypto -L-ldl && ./test_client test_client.o: In function `_D11test_client10verifyCertFPS6deimos7openssl4x5097x509_stZb': test_client.d:(.text._D11test_client10verifyCertFPS6deimos7openssl4x5097x509_stZb+0x2e): undefined reference to `_D6deimos7openssl3pem65__T14DECLARE_PEM_rwVAyaa4_58353039TS6deimos7openssl4x5097x509_stZ67__T16DECLARE_PEM_readVAyaa4_58353039TS6deimos7openssl4x5097x509_stZ71__T20DECLARE_PEM_read_bioVAyaa4_58353039TS6deimos7openssl4x5097x509_stZ17PEM_read_bio_X509UNbPS6deimos7openssl3bio6bio_stPPS6deimos7openssl4x5097x509_stPUPaiiPvZiPvZPS6deimos7openssl4x5097x509_st' collect2: ld returned 1 exit status --- errorlevel 1 And sorry for a memory leak problem, add X509_free(cert); before return true; //or return (cert_hash == some_const_value) to verify cert can fix. |

Reply