digitalmars.D - openssl example for D
- lzzll (211/211) Apr 07 2012 Prior work:
- David Nadlinger (3/5) Apr 07 2012 What exactly are the error messages you get?
- lzzll (15/16) Apr 07 2012 dmd test_client.d -w -L-lssl -L-lcrypto -L-ldl && ./test_client
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.
Apr 07 2012
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
Apr 07 2012
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_client10verifyCertFPS6deimos7openssl4x 097x509_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.
Apr 07 2012