Skip to content

Commit 6eebfad

Browse files
committed
Initial Checkin
Simple XREP server REQ client.
0 parents  commit 6eebfad

File tree

7 files changed

+389
-0
lines changed

7 files changed

+389
-0
lines changed

Makefile

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
CC = g++
2+
CFLAGS = -g
3+
LDFLAGS = -lzmq -lssl
4+
5+
all: tlsserver tlsclient
6+
7+
tlsserver: tlsserver.cpp tlszmq.cpp
8+
$(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@
9+
10+
tlsclient: tlsclient.cpp tlszmq.cpp
11+
$(CC) $^ $(CFLAGS) $(LDFLAGS) -o $@
12+
13+
clean:
14+
rm tlsclient
15+
rm tlsserver

server.crt

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIICATCCAWoCCQCcIw4uCLJ7bTANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
3+
VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
4+
cyBQdHkgTHRkMB4XDTEyMDkwNzEwNDUxOFoXDTEzMDkwNzEwNDUxOFowRTELMAkG
5+
A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
6+
IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAshGG
7+
ftj0ZtYLl+BwNroGQwDGDkvWRgOPKGsrUtV1RDKnEThXS69SDEOUWS0kb7Y9joAa
8+
roJHX7KmtxKzHFRNsi+zbqz4bm7vGBYsteVtd9mOwsRIZqSOLUKcdjUL0JKvJ/nL
9+
DkijARJg9luDBYt7t/+Wcl7+t+hZLKsFRStEd/cCAwEAATANBgkqhkiG9w0BAQUF
10+
AAOBgQCP77PstQTH/AB/90Pgx4rAeJ3fL1sSJJV7xsCRRDKuu2MiEC/16nUScspJ
11+
gfztlodgrR47Sf+5sP38v1OzS96dzaJwW2VLge6BahpfRoGAL8p/NyquZmXa+trt
12+
4vWHxJEZXLQrduuFNBliGtkeNAfzZCXW/SbYAL87yGwN6YMp0A==
13+
-----END CERTIFICATE-----

server.key

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
-----BEGIN RSA PRIVATE KEY-----
2+
MIICXQIBAAKBgQCyEYZ+2PRm1guX4HA2ugZDAMYOS9ZGA48oaytS1XVEMqcROFdL
3+
r1IMQ5RZLSRvtj2OgBqugkdfsqa3ErMcVE2yL7NurPhubu8YFiy15W132Y7CxEhm
4+
pI4tQpx2NQvQkq8n+csOSKMBEmD2W4MFi3u3/5ZyXv636FksqwVFK0R39wIDAQAB
5+
AoGAWHLeFJndZEtDvO/trTFftN5ogmdnCqXv8QqynVWMBxEF7UbIDb8LCS50PItw
6+
wtCJ6QN2vWHW5BEQQHVYZGT3pgtAABXkOF2tiu+vI4YTV43zeZkjUKa0Eszyj2xD
7+
wGlP9FEjxoerKHTGW1s81I5RmmBSFdQpkP/YWJ13PuUNrbECQQDe5R85QI8vVB8N
8+
wQ88VQ2GmCN/Ht8CUUyUYHk37HdEYKmbt83Ph9nTN7g55BUtSHnF8Z+HLImsIy7R
9+
Xz0DSI1fAkEAzIQD/S4naQS3a8Jb4xIQZVNoBSInqwIpC75VL53QYC3IKddUe9Ra
10+
Eqrhnws8sBh74179Povv7LnKT3QvtdMEaQJBAIQnoyil3393R+Y2xlrGLvvTbpBr
11+
dFwCaf47aQPAX0KacVWTWCKo8HysN72TPv8XTqQPS7+wp3v5bEPVTO6KcM8CQE68
12+
eIitjzCoRzFuZ0/ZcYSBAugPCTSWJVVHFqa5XDLbDVfGddkinPbY4PoJKnklQ/T6
13+
agb9ewYpVREXyxJ2RhkCQQCEnD6mAJQaPBKVI24gWuCWbDzH+xuOTz5JtoIuhPsv
14+
imptcLdE0RhiWJookqWh8iFMRZQx2NkM7n7Bbkm+np/8
15+
-----END RSA PRIVATE KEY-----

tlsclient.cpp

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include "tlszmq.h"
2+
//#include <stdio.h>
3+
//#include <string>
4+
#include <zmq.hpp>
5+
6+
// Simple REP server
7+
int main(int argc, char* argv[]) {
8+
try {
9+
zmq::context_t ctx(1);
10+
zmq::socket_t s1(ctx,ZMQ_REQ);
11+
s1.connect ("tcp://localhost:5555");
12+
TLSZmq *tls = new TLSZmq();
13+
bool loop = true;
14+
zmq::message_t request (12);
15+
memcpy(request.data(), "hello world!", 12);
16+
tls->send(&request);
17+
while (loop == true) {
18+
tls->update();
19+
20+
// If we need to send to the network, do so
21+
if(tls->needs_write()) {
22+
zmq::message_t *data = tls->get_data();
23+
s1.send(*data);
24+
25+
// Push message to TLS and update
26+
zmq::message_t response;
27+
s1.recv (&response);
28+
tls->put_data(&response);
29+
tls->update();
30+
31+
delete data;
32+
}
33+
34+
// If there is app data, retrieve it
35+
if(tls->can_recv()) {
36+
zmq::message_t *data = tls->recv();
37+
printf("Received: %s\n", (char *)(data->data()), data->size());
38+
loop = false;
39+
delete data;
40+
}
41+
}
42+
delete tls;
43+
}
44+
catch(std::exception &e) {
45+
printf ("An error occurred: %s\n", e.what());
46+
return 1;
47+
}
48+
return 0;
49+
}

tlsserver.cpp

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#include "tlszmq.h"
2+
#include <string>
3+
#include <map>
4+
#include <zmq.hpp>
5+
6+
// Simple REP server
7+
int main(int argc, char* argv[]) {
8+
try {
9+
zmq::context_t ctx(1);
10+
zmq::socket_t s1(ctx,ZMQ_ROUTER);
11+
s1.bind ("tcp://*:5555");
12+
std::string s_crt("server.crt");
13+
std::string s_key("server.key");
14+
std::map<std::string, TLSZmq*> conns;
15+
16+
while (true) {
17+
// Wait for a message
18+
zmq::message_t identifier(0);
19+
20+
// Retrieve or create the TLSZmq handler for this client
21+
s1.recv (&identifier);
22+
std::string ident (static_cast<char*>(identifier.data()), identifier.size());
23+
TLSZmq *tls;
24+
if(conns.find(ident) == conns.end()) {
25+
tls = new TLSZmq(s_crt.c_str(), s_key.c_str());
26+
conns[ident] = tls;
27+
} else {
28+
tls = conns[ident];
29+
}
30+
31+
// Ignore seperator
32+
zmq::message_t request(0);
33+
s1.recv (&request);
34+
35+
// Push message on to TLS and update
36+
s1.recv (&request);
37+
tls->put_data(&request);
38+
tls->update();
39+
40+
// If there is app data, retrieve it
41+
if(tls->can_recv()) {
42+
zmq::message_t *data = tls->recv();
43+
printf("Received: %s\n",static_cast<char*>(data->data()));
44+
zmq::message_t response(8);
45+
snprintf ((char *) response.data(), 8 ,"Got it!");
46+
tls->send(&response);
47+
tls->update();
48+
delete data;
49+
}
50+
51+
// If we need to send to the network, do so
52+
if(tls->needs_write()) {
53+
zmq::message_t *data = tls->get_data();
54+
s1.send(identifier, ZMQ_SNDMORE);
55+
request.rebuild(0); // reuse request as delimiter
56+
s1.send(request, ZMQ_SNDMORE);
57+
s1.send(*data);
58+
}
59+
}
60+
}
61+
catch(std::exception &e) {
62+
printf ("An error occurred: %s\n", e.what());
63+
return 1;
64+
}
65+
return 0;
66+
}

tlszmq.cpp

+189
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
#include <stdexcept>
2+
#include <openssl/ssl.h>
3+
#include <openssl/err.h>
4+
#include "tlszmq.h"
5+
6+
TLSZmq::TLSZmq()
7+
{
8+
init_(init_ctx_(SSLv3_client_method ()));
9+
SSL_set_connect_state(ssl);
10+
}
11+
12+
TLSZmq::TLSZmq(
13+
const char *certificate,
14+
const char *key)
15+
{
16+
// In server mode we probably want to actually create a context
17+
// once per run rather than per-session as in this example.
18+
SSL_CTX *ctxt = init_ctx_(SSLv3_server_method ());
19+
// This could do with some error checking!
20+
SSL_CTX_use_certificate_file(ctxt, certificate, SSL_FILETYPE_PEM);
21+
SSL_CTX_use_PrivateKey_file(ctxt, key, SSL_FILETYPE_PEM);
22+
init_(ctxt);
23+
SSL_set_accept_state(ssl);
24+
}
25+
26+
TLSZmq::~TLSZmq() {
27+
SSL_free(ssl);
28+
delete ssl_to_app;
29+
delete app_to_ssl;
30+
delete zmq_to_ssl;
31+
delete ssl_to_zmq;
32+
}
33+
34+
void TLSZmq::update()
35+
{
36+
// Copy the data from the ZMQ message to the memory BIO
37+
if (zmq_to_ssl->size() > 0) {
38+
int rc = BIO_write(rbio, zmq_to_ssl->data(), zmq_to_ssl->size());
39+
printf("DEBUG: %d written to BIO\n", rc);
40+
zmq_to_ssl->rebuild(0);
41+
}
42+
43+
// If we have app data to send, push it through SSL write, which
44+
// will hit the memory BIO.
45+
if (app_to_ssl->size() > 0) {
46+
int rc = SSL_write(ssl, app_to_ssl->data(), app_to_ssl->size());
47+
48+
if (!continue_ssl_(rc)) {
49+
throw std::runtime_error("An SSL error occured.");
50+
}
51+
52+
printf("DEBUG: %d written to SSL\n", rc);
53+
if( rc == app_to_ssl->size() ) {
54+
app_to_ssl->rebuild(0);
55+
}
56+
}
57+
58+
net_read_();
59+
net_write_();
60+
}
61+
62+
bool TLSZmq::can_recv() {
63+
return ssl_to_app->size() > 0;
64+
}
65+
66+
bool TLSZmq::needs_write() {
67+
return ssl_to_zmq->size() > 0;
68+
}
69+
70+
zmq::message_t *TLSZmq::recv() {
71+
zmq::message_t *msg = new zmq::message_t(ssl_to_app->size());
72+
memcpy (msg->data(), ssl_to_app->data(), ssl_to_app->size());
73+
ssl_to_app->rebuild(0);
74+
return msg;
75+
}
76+
77+
zmq::message_t *TLSZmq::get_data() {
78+
zmq::message_t *msg = new zmq::message_t(ssl_to_zmq->size());
79+
memcpy (msg->data(), ssl_to_zmq->data(), ssl_to_zmq->size());
80+
ssl_to_zmq->rebuild(0);
81+
return msg;
82+
}
83+
84+
void TLSZmq::put_data(zmq::message_t *msg) {
85+
zmq_to_ssl->rebuild(msg->data(), msg->size(), NULL, NULL);
86+
}
87+
88+
void TLSZmq::send(zmq::message_t *msg) {
89+
app_to_ssl->rebuild(msg->data(), msg->size(), NULL, NULL);
90+
}
91+
92+
SSL_CTX *TLSZmq::init_ctx_(SSL_METHOD *meth) {
93+
OpenSSL_add_all_algorithms();
94+
SSL_library_init();
95+
SSL_load_error_strings();
96+
ERR_load_BIO_strings();
97+
98+
SSL_CTX *ctxt = SSL_CTX_new (meth);
99+
if(!ctxt) {
100+
ERR_print_errors_fp(stderr);
101+
}
102+
103+
return ctxt;
104+
}
105+
106+
void TLSZmq::init_(SSL_CTX *ctxt)
107+
{
108+
ssl = SSL_new(ctxt);
109+
110+
rbio = BIO_new(BIO_s_mem());
111+
wbio = BIO_new(BIO_s_mem());
112+
SSL_set_bio(ssl, rbio, wbio);
113+
114+
ssl_to_app = new zmq::message_t(0);
115+
app_to_ssl = new zmq::message_t(0);
116+
zmq_to_ssl = new zmq::message_t(0);
117+
ssl_to_zmq = new zmq::message_t(0);
118+
}
119+
120+
void TLSZmq::net_write_() {
121+
std::string nwrite;
122+
// Read any data to be written to the network from the memory BIO
123+
while (1) {
124+
char readto[1024];
125+
int read = BIO_read(wbio, readto, 1024);
126+
127+
if (read > 0) {
128+
size_t cur_size = nwrite.length();
129+
nwrite.resize(cur_size + read);
130+
std::copy(readto, readto + read, nwrite.begin() + cur_size);
131+
}
132+
133+
if (static_cast<size_t>(read) != 1024 || read == 0) break;
134+
}
135+
136+
if (!nwrite.empty()) {
137+
printf("DEBUG: %d read from BIO\n", (int)nwrite.length());
138+
ssl_to_zmq->rebuild(nwrite.length());
139+
memcpy(ssl_to_zmq->data(), nwrite.c_str(), nwrite.length());
140+
}
141+
}
142+
143+
void TLSZmq::net_read_() {
144+
std::string aread;
145+
// Read data for the application from the encrypted connection and place it in the string for the app to read
146+
while (1) {
147+
char readto[1024];
148+
int read = SSL_read(ssl, readto, 1024);
149+
150+
if (!continue_ssl_(read)) {
151+
throw std::runtime_error("An SSL error occured.");
152+
}
153+
154+
if (read > 0) {
155+
size_t cur_size = aread.length();
156+
aread.resize(cur_size + read);
157+
std::copy(readto, readto + read, aread.begin() + cur_size);
158+
}
159+
160+
if (static_cast<size_t>(read) != 1024 || read == 0) break;
161+
}
162+
163+
if (!aread.empty()) {
164+
ssl_to_app->rebuild(aread.length());
165+
memcpy(ssl_to_app->data(), aread.c_str(), aread.length());
166+
}
167+
}
168+
169+
bool TLSZmq::continue_ssl_(int rc) {
170+
int err = SSL_get_error(ssl, rc);
171+
172+
if (err == SSL_ERROR_NONE || err == SSL_ERROR_WANT_READ) {
173+
return true;
174+
}
175+
176+
if (err == SSL_ERROR_SYSCALL) {
177+
ERR_print_errors_fp(stderr);
178+
perror("DEBUG: syscall error: ");
179+
return false;
180+
}
181+
182+
if (err == SSL_ERROR_SSL) {
183+
ERR_print_errors_fp(stderr);
184+
return false;
185+
}
186+
return true;
187+
}
188+
189+

tlszmq.h

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Quick and dirty class to wrap data in TLS for use over ZeroMQ
3+
* Based on code from http://funcptr.net/2012/04/08/openssl-as-a-filter-%28or-non-blocking-openssl%29/
4+
*/
5+
6+
#include <openssl/ssl.h>
7+
#include <zmq.hpp>
8+
9+
class TLSZmq {
10+
public:
11+
TLSZmq();
12+
TLSZmq( const char *certificate,
13+
const char *key);
14+
virtual ~TLSZmq();
15+
16+
void update();
17+
18+
bool can_recv();
19+
bool needs_write();
20+
21+
zmq::message_t *recv();
22+
zmq::message_t *get_data();
23+
void put_data(zmq::message_t *msg);
24+
void send(zmq::message_t *msg);
25+
26+
private:
27+
void init_(SSL_CTX *ctxt);
28+
SSL_CTX *init_ctx_(SSL_METHOD *meth);
29+
30+
bool continue_ssl_(int function_return);
31+
void net_read_();
32+
void net_write_();
33+
34+
SSL * ssl;
35+
BIO * rbio;
36+
BIO * wbio;
37+
38+
zmq::message_t *app_to_ssl;
39+
zmq::message_t *ssl_to_app;
40+
zmq::message_t *ssl_to_zmq;
41+
zmq::message_t *zmq_to_ssl;
42+
};

0 commit comments

Comments
 (0)