OpenSSL, RSA and Winsock and C++ - c++

I found this source floating about the net and I was hoping someone could solve why this program simply shuts down instead of listening for a connection. This source was meant to open a server socket but, doesn't.
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
#include <stdio.h>
#include <winsock2.h>
#define PASSWORD "passme"
int main(int argc, char** argv)
{
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
return 0;
}
void serverThread()
{
// First, we need to initialize Winsock.
WSADATA wsadata;
int ret = WSAStartup(0x101, &wsadata);
if (ret != 0) {
printf("WSAStartup() failed with: %d!\n", GetLastError());
return;
}
// Next we need to create a server socket.
SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in sockaddrin;
// Internet socket
sockaddrin.sin_family = AF_INET;
// Accept any IP
sockaddrin.sin_addr.s_addr = INADDR_ANY;
// Use port 6789
sockaddrin.sin_port = htons(6789);
// Valid socket?
if (server == INVALID_SOCKET) {
printf("Error creating server socket!");
return;
}
// Now bind to the port
ret = bind(server, (sockaddr*) &(sockaddrin), sizeof(sockaddrin));
if (ret != 0) {
printf("Error binding to port!\n");
return;
}
// Start listening for connections
// Second param is max number of connections
ret = listen(server, 50);
if (ret != 0) {
printf("Error listening for connections!\n");
return;
}
// Set up to accept connections
SOCKET client;
sockaddr_in clientsockaddrin;
int len = sizeof(clientsockaddrin);
printf("Server ready to accept connections!\n");
while (1) {
// Block until a connection is ready
client = accept(server, (sockaddr*) &clientsockaddrin, &len);
printf("Connection recieved from %s!\n", inet_ntoa(clientsockaddrin.sin_addr));
// Notice that we use server_method instead of client_method
SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
BIO* bio = BIO_new_file("dh1024.pem", "r");
// Did we get a handle to the file?
if (bio == NULL) {
printf("Couldn't open DH param file!\n");
break;
}
// Read in the DH params.
DH* ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
// Free up the BIO object.
BIO_free(bio);
// Set up our SSL_CTX to use the DH parameters.
if (SSL_CTX_set_tmp_dh(ctx, ret) < 0) {
printf("Couldn't set DH parameters!\n");
break;
}
// Now we need to generate a RSA key for use.
// 1024-bit key. If you want to use something stronger, go ahead but it must be a power of 2. Upper limit should be 4096.
RSA* rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL);
// Set up our SSL_CTX to use the generated RSA key.
if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) {
printf("Couldn't set RSA key!\n");
// We don't break out here because it's not a requirement for the RSA key to be set. It does help to have it.
}
// Free up the RSA structure.
RSA_free(rsa);
SSL_CTX_set_cipher_list(ctx, "ALL");
// Set up our SSL object as before
SSL* ssl = SSL_new(ctx);
// Set up our BIO object to use the client socket
BIO* sslclient = BIO_new_socket(client, BIO_NOCLOSE);
// Set up our SSL object to use the BIO.
SSL_set_bio(ssl, sslclient, sslclient);
// Do SSL handshaking.
int r = SSL_accept(ssl);
// Something failed. Print out all the error information, since all of it may be relevant to the problem.
if (r != 1) {
printf("SSL_accept() returned %d\n", r);
printf("Error in SSL_accept(): %d\n", SSL_get_error(ssl, r));
char error[65535];
ERR_error_string_n(ERR_get_error(), error, 65535);
printf("Error: %s\n\n", error);
ERR_print_errors(sslclient);
int err = WSAGetLastError();
printf("WSA: %d\n", err);
break;
}
}
}
int password_callback(char* buffer, int num, int rwflag, void* userdata)
{
if (num < (strlen(PASSWORD) + 1)) {
return(0);
}
strcpy(buffer, PASSWORD);
return strlen(PASSWORD);
}
int verify_callback(int ok, X509_STORE_CTX* store)
{
char data[255];
if (!ok) {
X509* cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
printf("Error with certificate at depth: %d!\n", depth);
X509_NAME_oneline(X509_get_issuer_name(cert), data, 255);
printf("\tIssuer: %s\n", data);
X509_NAME_oneline(X509_get_subject_name(cert), data, 255);
printf("\tSubject: %s\n", data);
printf("\tError %d: %s\n", err, X509_verify_cert_error_string(err));
}
return ok;
}

You never start the ServerThread in main

Related

TLS 1.2 implementation in C++ Windows Application using OpenSSL

I have a windows application that works as a client and installed on multiple device and they can communicate with each other, Now I want to encrypt the communication. I tried to found out some methods like Microsoft's SSPI library and SChannel but didn't find an easy implementation, So I am trying with the OpenSSL.
I am trying to create a client and server using winsocket and enabling TLS communication using OpenSSL in Visual Studio 2019. THe problem is it gets connect to the server, the server prints the message connected to client and also client code show connected, but on SSL_Connect method it fails and shows no error in the client code! I also created a normal TCP socket server and try to connect it to this as well than also it fails after connecting.
What is going wrong! Here is my code:
Client:
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <errno.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <WS2tcpip.h>
#include <string>
#include <iostream>
#pragma comment (lib, "ws2_32.lib")
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
int OpenConnection(const char* hostname, int port)
{
int sd;
struct hostent* host;
struct sockaddr_in addr;
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
printf("winsock error");
return 0;
}
if ((host = gethostbyname(hostname)) == NULL)
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
closesocket(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{
const SSL_METHOD* method = TLS_client_method(); /* Create new client-method instance */
SSL_CTX* ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
// method = SSLv3_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void ShowCerts(SSL* ssl)
{
X509* cert;
char* line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if (cert != NULL)
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("No certificates.\n");
}
int main()
{
SSL_CTX* ctx;
int server;
SSL* ssl;
char buf[1024];
int bytes;
char hostname[] = "127.0.0.1";
char portnum[] = "54000";
char CertFile[] = "C:/Users/cert/Documents/testing/ec_crt.pem";
char KeyFile[] = "C:/Users/cert/Documents/testing/private-key.pem";
SSL_library_init();
ctx = InitCTX();
LoadCertificates(ctx, CertFile, KeyFile);
printf("clinet certificate loaded");
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if (SSL_connect(ssl) == FAIL) /* perform the connection */ {
printf("Connection failed");
ERR_print_errors_fp(stderr);
}
else
{
const char* msg = "Hello???";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
SSL_free(ssl); /* release connection state */
}
closesocket(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
SERVER:
//SSL-Server.c
#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <sys/types.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#include <WS2tcpip.h>
#include <string>
#pragma comment (lib, "ws2_32.lib")
#define FAIL -1
int OpenListener(int port)
{
int sd;
struct sockaddr_in addr;
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
printf("winsock error");
return 0;
}
sd = socket(PF_INET, SOCK_STREAM, 0);
ZeroMemory(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
perror("can't bind port");
abort();
}
if (listen(sd, 10) != 0)
{
perror("Can't configure listening port");
abort();
}
listen(sd, SOMAXCONN);
return sd;
}
SSL_CTX* InitServerCTX(void)
{
const SSL_METHOD* method = TLS_client_method(); /* Create new client-method instance */
SSL_CTX* ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
ctx = SSL_CTX_new(method); /* create new context from method */
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
//New lines
if (SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
ERR_print_errors_fp(stderr);
//End new lines
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
//New lines - Force the client-side have a certificate
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_verify_depth(ctx, 4);
//End new lines
}
void ShowCerts(SSL* ssl)
{
X509* cert;
char* line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if (cert != NULL)
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{
char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho = "<html><body><pre>%s</pre></body></html>\n\n";
if (SSL_accept(ssl) == FAIL) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if (bytes > 0)
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
// sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
closesocket(sd); /* close connection */
}
int main()
{
SSL_CTX* ctx;
int server;
char portnum[] = "54000";
char CertFile[] = "C:/Users/cert/Documents/testing/ec_crt.pem";
char KeyFile[] = "C:/Users/cert/Documents/testing/private-key.pem";
SSL_library_init();
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, CertFile, KeyFile); /* load certs */
printf("Certificate loaded");
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL* ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
//printf("Connection: %s:%d\n", inet_ntop(addr.sin_addr), ntohs(addr.sin_port));
printf("Connected");
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
closesocket(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
Maybe you need to use:
const SSL_METHOD* method = TLS_server_method();
in InitServerCtx()?

How to set a timeout for BIO_do_connect?

I found a SSL/TLS client example here, it works well.
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <string.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
#include <openssl/ssl.h>
#include <openssl/conf.h>
void connect(const char* host, int port) {
BIO* sbio, * out;
int len;
char tmpbuf[1024];
SSL_CTX* ctx;
SSL* ssl;
char server[200];
snprintf(server, sizeof(server), "%s:%d", host, port);
/* XXX Seed the PRNG if needed. */
ctx = SSL_CTX_new(TLS_client_method());
/* XXX Set verify paths and mode here. */
sbio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(sbio, &ssl);
if (ssl == NULL) {
fprintf(stderr, "Can't locate SSL pointer\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* Don't want any retries */
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
/* XXX We might want to do other things with ssl here */
/* An empty host part means the loopback address */
BIO_set_conn_hostname(sbio, server);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
if (BIO_do_connect(sbio) <= 0) {
fprintf(stderr, "Error connecting to server\n");
ERR_print_errors_fp(stderr);
exit(1);
}
int ret = 0;
if ((ret = BIO_do_handshake(sbio)) <= 0) {
fprintf(stderr, "Error establishing SSL connection\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* XXX Could examine ssl here to get connection info */
BIO_puts(sbio, "Hi, this message is from client c++");
for (;;) {
len = BIO_read(sbio, tmpbuf, 1024);
if (len <= 0) {
break;
}
BIO_write(out, tmpbuf, len);
}
BIO_free_all(sbio);
BIO_free(out);
}
int main() {
connect("127.0.0.1", 5555);
}
but i need to set a timeout for this connection. then i found How to set connection timeout and operation timeout in OpenSSL.
so i change the codes
if (BIO_do_connect(sbio) <= 0) {
fprintf(stderr, "Error connecting to server\n");
ERR_print_errors_fp(stderr);
exit(1);
}
to
{
BIO_set_nbio(sbio, 1);
if (1 > BIO_do_connect(sbio)) {
if (!BIO_should_retry(sbio)) {
fprintf(stderr, "Error: should not retry\n");
ERR_print_errors_fp(stderr);
exit(1);
}
int fdSocket = 0;
if (BIO_get_fd(sbio, &fdSocket) < 0) {
fprintf(stderr, "Error: can not get socket\n");
ERR_print_errors_fp(stderr);
exit(1);
}
struct timeval timeout;
fd_set connectionfds;
FD_ZERO(&connectionfds);
FD_SET(fdSocket, &connectionfds);
timeout.tv_usec = 0;
timeout.tv_sec = 4;
if (0 == select(fdSocket + 1, NULL, &connectionfds, NULL, &timeout)) {
fprintf(stderr, "Error: timeout\n");
ERR_print_errors_fp(stderr);
exit(1);
}
}
}
now BIO_do_handshake returns -1 and the program exits.
How can i set a timeout correctly for my ssl connection?
Please give me some advice! help me!
I think you should set a timeout for handshake, not connection. in your code the connection has no problem because "select" returned non-zero value. in fact BIO_do_connect does handshake after connection is available. BIO_do_connect and BIO_do_handshake are the same in header file.
# define BIO_do_connect(b) BIO_do_handshake(b)
So i think this problem is handshake. eg. you connect to a server which uses a normal tcp socket without ssl. the server will not send "server_hallo" and certificate. then the client will wait for these "server_hallo" and certificate. BIO_do_handshake returns -1 if the handshake progress is still not finished.
maybe you can use BIO_set_ssl_renegotiate_timeout to set a timeout.
I would go about this in two steps:
I would deal with connection setup on my own. That way you can use non-blocking socket, connect(2) and select(2) and have complete control over timing of this part.
I would also implement by own BIO. You can use an existing BIO and only implement read, write and puts methods. This will allow you to control socket accesses.
With this in place you can have total control over how much time you spend. You can implement different timeouts for session setup, renegotiation, normal operation...
The problem with BIO_set_nbio is that you set I/O to non blocking mode. So you have to process further steps in non blocking mode.
I made an example how to process the request with sleep and non blocking mode. Maybe it is a bit ugly. But it worked for me.
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <unistd.h>
#include <stdio.h>
void connect(const char* host, int port) {
const long timeout_nsec = 4 * (long)1000000000, dt_nsec = 100000;
char tmpbuf[1024];
char server[200];
snprintf(server, sizeof(server), "%s:%d", host, port);
struct timespec dt;
dt.tv_sec = 0;
dt.tv_nsec = dt_nsec;
/* XXX Seed the PRNG if needed. */
SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
/* XXX Set verify paths and mode here. */
BIO *sbio = BIO_new_ssl_connect(ctx);
SSL* ssl = nullptr;
BIO_get_ssl(sbio, &ssl);
if (ssl == NULL) {
fprintf(stderr, "Can't locate SSL pointer\n");
ERR_print_errors_fp(stderr);
exit(1);
}
/* Don't want any retries */
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
/* XXX We might want to do other things with ssl here */
/* An empty host part means the loopback address */
BIO_set_conn_hostname(sbio, server);
BIO *out = BIO_new_fp(stdout, BIO_NOCLOSE);
BIO_set_nbio(sbio, 1);
{
long time_remained = timeout_nsec;
while(1) {
int res = BIO_do_connect(sbio);
if (res <= 0 && BIO_should_retry(sbio)) {
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dt, NULL);
time_remained -= dt_nsec;
if (time_remained <= 0) {
fprintf(stderr, "Timeout\n");
exit(1);
}
continue;
}
if (res <= 0) {
fprintf(stderr, "BIO_do_connect error\n");
ERR_print_errors_fp(stderr);
exit(1);
}
break;
}
}
{
long time_remained = timeout_nsec;
while(1) {
int res = BIO_do_handshake(sbio);
if (res <= 0 && BIO_should_retry(sbio)) {
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dt, NULL);
time_remained -= dt_nsec;
if (time_remained <= 0) {
fprintf(stderr, "Timeout\n");
exit(1);
}
continue;
}
if (res <= 0) {
fprintf(stderr, "BIO_do_handshake error\n");
ERR_print_errors_fp(stderr);
exit(1);
}
break;
}
}
/* XXX Could examine ssl here to get connection info */
int a = BIO_puts(sbio, "Hi, this message is from client c++");
for (;;) {
int len = -1;
{
long time_remained = timeout_nsec;
while(1) {
len = BIO_read(sbio, tmpbuf, 1024);
if (len < 0 && BIO_should_retry(sbio)) {
clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &dt, NULL);
time_remained -= dt_nsec;
if (time_remained <= 0) {
fprintf(stderr, "Timeout\n");
exit(1);
}
continue;
}
if (len < 0) {
fprintf(stderr, "BIO_read error\n");
ERR_print_errors_fp(stderr);
exit(1);
}
break;
}
}
if (len == 0) {
break;
}
BIO_write(out, tmpbuf, len);
}
BIO_free_all(sbio);
BIO_free(out);
}
int main() {
connect("127.0.0.1", 5555);
}

how to protect against TLS GOLDENDOODLE with c++ and openssl?

have a simple web server made with C++ and openssl, and when running SSL Lab's SSL Server Test on it, it informs me that the server is vulnerable to GOLDENDOODLE and Sleeping POODLE (among other things, screenshot here),
i'm running libopenssl 1.1.1c, which is the latest openssl release as of writing, so i don't think it's a case of using an old outdated vulnerable TLS library, instead i'm probably just using it wrong,
hence the question: how do you protect against GOLDENDOODLE with openssl? here is the entire (vulnerable?) server source code:
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <thread>
#include <chrono>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
const uint16_t port=443;
int create_socket(const uint16_t port)
{
int s;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0)
{
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("Unable to bind");
exit(EXIT_FAILURE);
}
if (listen(s, 1) < 0)
{
perror("Unable to listen");
exit(EXIT_FAILURE);
}
return s;
}
void init_openssl()
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl()
{
EVP_cleanup();
}
SSL_CTX *create_context()
{
const SSL_METHOD *method;
SSL_CTX *ctx;
method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
if (!ctx)
{
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
void configure_context(SSL_CTX *ctx)
{
// - Congratulations! Your certificate and chain have been saved at:
// /etc/letsencrypt/live/fuviewer.ml/fullchain.pem
// Your key file has been saved at:
// /etc/letsencrypt/live/fuviewer.ml/privkey.pem
(void)ctx;
SSL_CTX_set_ecdh_auto(ctx, 1);
/* Set the key and cert */
// SSL_FILETYPE_PEM
if (SSL_CTX_use_certificate_chain_file(ctx, "fullchain.pem") <= 0)
{
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
if (SSL_CTX_use_PrivateKey_file(ctx, "privkey.pem", SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
}
int main(int argc, char **argv)
{
(void)argc;
(void)argv;
int sock;
SSL_CTX *ctx;
init_openssl();
ctx = create_context();
configure_context(ctx);
sock = create_socket(port);
std::cout << "server running!" << std::flush;
/* Handle connections */
while(1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
const char reply[] =
"HTTP/1.0 200 OK\r\n"
"Test-header: Yep\r\n"
"Content-Length: 3\r\n"
"\r\n"
"abc";
const auto reply_size=sizeof(reply)-1;
int client = accept(sock, (struct sockaddr*)&addr, &len);
if (client < 0)
{
perror("Unable to accept");
exit(EXIT_FAILURE);
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, client);
if (SSL_accept(ssl) <= 0)
{
ERR_print_errors_fp(stderr);
}
else
{
if(SSL_write(ssl, reply, reply_size)!=reply_size)
{
throw std::runtime_error("FAILED TO SEND ALL BYTES");
};
{
// openssl gets cranky if we don't try to read at least 1 byte, even tho we don't really want to..
uint8_t unused;
SSL_read(ssl,&unused,sizeof(unused));
}
SSL_shutdown(ssl);
//std::this_thread::sleep_for(std::chrono::seconds(1));
}
SSL_free(ssl);
close(client);
}
close(sock);
SSL_CTX_free(ctx);
cleanup_openssl();
}
While there are only few information about affected TLS stacks it looks like that OpenSSL should not be vulnerable, even when using CBC ciphers.
I think what you see instead is a false positive, which is triggered by your server not matching the expectations of the test. While I don't know how the GOLDENDOODLE detection by SSLLabs works I've looked at the original detection program from Tripwire.
And it looks like that this script expects a proper HTTP server at the other end, i.e. one which first reads the request and then sends the response. Only, your server does it the other way: first sending the response and reading (and ignoring) a bit of the request only after the response was sent. Such non-HTTP behavior is not taken into account (why should it) and confuses the detection which results in falsely reporting a non-existing problem.

epoll-based server fails (mutual authentication)

Based on the examples at http://simplestcodings.blogspot.com/2010/08/secure-server-client-using-openssl-in-c.html I have written the following epoll server code to replace the regular tcp sockets with SSL. My code is slightly modified to do mutual authentication and verify the certs since I add
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);.
My OS is Ubuntu 12.04.
I have also generated server cert, client cert, server key, client key, and of course cacert.pem files from the IBM tutorial http://pic.dhe.ibm.com/infocenter/lnxinfo/v3r0m0/index.jsp?topic=%2Fliaat%2Fliaatseccreatecskeycert.htm
I ran the single server - single client code and it runs perfectly fine. Inspired by this I wanted to see how the epoll server code would behave but then I ran into issues. Here is the code for the server
Code that does not work
//(c) 2014 enthusiasticgeek for stackoverflow - epollserver.cc
//============================================================================
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <errno.h>
#include <iostream>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
#define MAXEVENTS 64
SSL_CTX* InitServerCTX(void)
{ const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv23_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
static int
AibSocketNonBlocking (int sfd)
{
int flags, s;
flags = fcntl (sfd, F_GETFL, 0);
if (flags == -1)
{
perror ("fcntl");
return -1;
}
flags |= O_NONBLOCK;
s = fcntl (sfd, F_SETFL, flags);
if (s == -1)
{
perror ("fcntl");
return -1;
}
return 0;
}
static int
AibCreateAndBind (char *port)
{
struct addrinfo hints;
struct addrinfo *result, *rp;
int s, sfd;
memset (&hints, 0, sizeof (struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Return IPv4 and IPv6 choices */
hints.ai_socktype = SOCK_STREAM; /* We want a TCP socket */
hints.ai_flags = AI_PASSIVE; /* All interfaces */
s = getaddrinfo (NULL, port, &hints, &result);
if (s != 0)
{
fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (s));
return -1;
}
for (rp = result; rp != NULL; rp = rp->ai_next)
{
sfd = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (sfd == -1)
continue;
s = bind (sfd, rp->ai_addr, rp->ai_addrlen);
if (s == 0)
{
/* We managed to bind successfully! */
break;
}
close (sfd);
}
if (rp == NULL)
{
fprintf (stderr, "Could not bind\n");
return -1;
}
freeaddrinfo (result);
return sfd;
}
int
main (int argc, char *argv[])
{
SSL_CTX *ctx;
SSL_library_init();
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "/home/test/ssl/cert_files/servercert.pem", "/home/test/ssl/cert_files/serverkey.pem"); /* load certs */
int sfd, s;
int efd;
struct epoll_event aibevent;
struct epoll_event *aibevents;
if (argc != 2) {
fprintf (stderr, "Usage: %s [port]\n", argv[0]);
exit (EXIT_FAILURE);
}
char portt[sizeof (unsigned int)];
snprintf(portt,sizeof portt + 1,"%u",atoi(argv[1]));
printf("sizeof %s argv[1] = %d\n",argv[1], sizeof(argv[1]));
printf("sizeof %s portt = %d\n",portt, sizeof(portt));
sfd = AibCreateAndBind (portt);//argv[1]);
if (sfd == -1) {
abort ();
}
s = AibSocketNonBlocking (sfd);
if (s == -1) {
abort ();
}
s = listen (sfd, SOMAXCONN);
if (s == -1) {
perror ("listen");
abort ();
}
efd = epoll_create1 (0);
if (efd == -1) {
perror ("epoll_create");
abort ();
}
aibevent.data.fd = sfd;
aibevent.events = EPOLLIN | EPOLLET;
s = epoll_ctl (efd, EPOLL_CTL_ADD, sfd, &aibevent);
if (s == -1) {
perror ("epoll_ctl");
abort ();
}
// Buffer where events are returned
//events = static_cast<epoll_event*>(calloc (MAXEVENTS, sizeof event));
//aibevents = static_cast<epoll_event*>(malloc (MAXEVENTS * sizeof aibevent));
aibevents = new epoll_event[MAXEVENTS * sizeof aibevent];
// The event loop
while (true)
{
int n, i;
n = epoll_wait (efd, aibevents, MAXEVENTS, -1);
for (i = 0; i < n; i++)
{
if ((aibevents[i].events & EPOLLERR) ||
(aibevents[i].events & EPOLLHUP) ||
(!(aibevents[i].events & EPOLLIN)))
{
// An error has occured on this fd, or the socket is not
// ready for reading (why were we notified then?)
fprintf (stderr, "epoll error\n");
close (aibevents[i].data.fd);
continue;
} else if (sfd == aibevents[i].data.fd) {
// We have a notification on the listening socket, which
// means one or more incoming connections.
while (1)
{
struct sockaddr in_addr;
socklen_t in_len;
int infd;
char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
in_len = sizeof in_addr;
infd = accept (sfd, &in_addr, &in_len);
if (infd == -1)
{
if ((errno == EAGAIN) ||(errno == EWOULDBLOCK)) {
// We have processed all incoming
// connections.
break;
} else {
perror ("accept");
break;
}
}
s = getnameinfo (&in_addr, in_len,
hbuf, sizeof hbuf,
sbuf, sizeof sbuf,
NI_NUMERICHOST | NI_NUMERICSERV);
if (s == 0) {
printf("Accepted connection on descriptor %d "
"(host=%s, port=%s)\n", infd, hbuf, sbuf);
}
// Make the incoming socket non-blocking and add it to the
// list of fds to monitor.
s = AibSocketNonBlocking (infd);
if (s == -1) {
abort ();
}
aibevent.data.fd = infd;
aibevent.events = EPOLLIN | EPOLLET;
s = epoll_ctl (efd, EPOLL_CTL_ADD, infd, &aibevent);
if (s == -1) {
perror ("epoll_ctl");
abort ();
}
}
continue;
} else {
// We have data on the fd waiting to be read. Read and
// display it. We must read whatever data is available
// completely, as we are running in edge-triggered mode
// and won't get a notification again for the same
// data.
int done = 0;
int sd;
SSL *ssl;
while (1)
{
ssize_t count;
char buf[1024];
char reply[1024];
printf("Performing exchange.\n");
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, aibevents[i].data.fd); /* set connection socket to SSL state */
printf("Performing exchange 1.\n");
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) { /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
printf("Performing exchange Error 1.\n");
done = 1;
break;
} else {
ShowCerts(ssl); /* get any certificates */
count = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( count > 0 )
{
buf[count] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
} else {
ERR_print_errors_fp(stderr);
printf("Performing exchange Error 2.\n");
done = 1;
break;
}
}
sd = SSL_get_fd(ssl); /* get socket connection */
/*
count = read (aibevents[i].data.fd, buf, sizeof buf);
if (count == -1)
{
// If errno == EAGAIN, that means we have read all
// data. So go back to the main loop.
if (errno != EAGAIN)
{
perror ("read");
done = 1;
}
break;
}
else if (count == 0)
{
// End of file. The remote has closed the
// connection.
done = 1;
break;
}
// Write the buffer to standard output
s = write (1, buf, count);
if (s == -1)
{
perror ("write");
abort ();
}
printf(" read correctly (n > 0) n==%d\n",s);
printf("msg: %s\n", buf);
write(aibevents[i].data.fd, buf,s);
memset(buf,'\0', s);
*/
}
if (done)
{
printf("Freeing data.\n");
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
//printf ("Closed connection on descriptor %d\n",
// aibevents[i].data.fd);
// Closing the descriptor will make epoll remove it
// from the set of descriptors which are monitored.
//close (aibevents[i].data.fd);
}
}
}
}
//free (aibevents);
delete[] aibevents;
close (sfd);
SSL_CTX_free(ctx); /* release context */
return EXIT_SUCCESS;
}
The single server- single client code are listed below for reference. Note that I am using the same client code to interact with the epoll server.
Single server code. Works
//SSL-Single Server code that works ! used as a reference for epoll server
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
SSL_CTX* InitServerCTX(void)
{ const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv23_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
char *portnum;
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "/home/test/ssl/cert_files/servercert.pem", "/home/test/ssl/cert_files/serverkey.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
Single client code Works
// Single Client Code that works!
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
SSL_CTX_load_verify_locations(ctx,"/home/test/ssl/cert_files/cacert.pem",NULL);
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ const SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = SSLv23_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("No certificates.\n");
}
int main(int count, char *strings[])
{
SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
if ( count != 3 )
{
printf("Usage: %s <host/ip> <portnum>\n", strings[0]);
exit(0);
}
char* hostname=strings[1];//"127.0.0.1";
char* portnum=strings[2];//"3334";
char CertFile[] = "/home/test/ssl/cert_files/clientcert.pem";
char KeyFile[] = "/home/test/ssl/cert_files/clientkey.pem";
SSL_library_init();
ctx = InitCTX();
LoadCertificates(ctx, CertFile, KeyFile);
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ char *msg = "Hello???";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
I did compilation using
g++ -g <src>.cc -o <src> -lssl -lcrypto for each of the three files (I had a Makefile)
The error that see is
./tcpserver_epoll 3334
sizeof 3334 argv[1] = 4
sizeof 3334 portt = 4
Accepted connection on descriptor 5 (host=127.0.0.1, port=44716)
Performing exchange.
Performing exchange 1.
Performing exchange Error 1.
Freeing data.
Performing exchange.
Performing exchange 1.
3072792824:error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol:s23_srvr.c:628:
Performing exchange Error 1.
Freeing data.
I am wondering if I have to create multiple instances of SSL_CTX *ctx;. I am a bit lost. Any help is appreciated. Thanks.
Update: Thanks to everyone for guidance. I found an example here that closely matches what I want
http://bendecplusplus.googlecode.com/svn/trunk/ssl_mycode/epoll_ssl/server.c
http://bendecplusplus.googlecode.com/svn/trunk/ssl_mycode/epoll_ssl/client.c
Your code is very hard to read (how about proper indentation?) but I think the main problem is, that you consider a return of -1 from SSL_accept to be a fatal error.
According to the man page (which is true in this case) -1 can happen on fatal error or "It can also occur of action is need to continue the operation for non-blocking BIOs. Call SSL_get_error() with the return value ret to find out the reason.". So you have to check the error and if its SSL_ERROR_WANT_READ you have to wait the socket is readable and on SSL_ERROR_WANT_WRITE until its writable.
I am wondering if I have to create multiple instances of SSL_CTX *ctx;
No, you can use a single SSL_CTX*.
The SSL_CTX* is reference counted. It will be destroyed after the last SSL_free.
Since you are using a common SSL_CTX*, you should tune each SSL session with the non-context API calls. For example, SSL_set_cipher_list rather than SSL_CTX_set_cipher_list or SSL_use_certificate rather than SSL_CTX_use_certificate (unless, of course, its common).

How do I initialize the OpenSSL BIO object?

I have a tcp server which detects an incoming SSL connection (see here) and then does the following:
BIO* initialize(SSL_CTX *context, int socket){
BIO *bio = NULL;
SSL *ssl = SSL_new(context);
SSL_set_fd(ssl, socket);
if (SSL_accept(ssl) == -1){
return NULL; //error
}
//what do I do here??
bio = BIO_new_ssl(context, 1); //this seems wrong...
return bio;
}
I dont know how to create the BIO object and the documentation is really confusing. Any help is appreciated. Thanks!
This is an excerpt of an old student project of mine (circa 2006).
I hope it sheds some light on the question.
I do not use BIO_new_ssl() but SSL_set_bio().
SSL_CTX *ctx = setup_server_ctx("root.pem", NULL);
SSL_CTX *ssl = SSL_new(ctx);
if (NULL == ssl) {
fprintf(stderr, "Error creating SSL context.\n")
goto err;
}
BIO *acc = BIO_new_accept(port);
if (BIO_do_accept(acc) <= 0) {
fprintf(stderr, "Error accepting connection.\n");
goto err;
}
BIO *client = BIO_pop(acc);
SSL_set_bio(ssl, client, client);
if (0 >= SSL_accept(ssl)) {
fprintf(stderr, "Error accepting SSL connection\n");
goto end;
}
SSL_write(ssl, SOME_MESSAGE, strlen(SOME_MESSAGE));
char buf[BUF_SIZE + 1]= {0};
int ret = SSL_read(ssl, buf, BUF_SIZE);
if (ret <= 0) {
break;
}
/* do some more stuff */
SSL_get_shutdown(ssl);