HiveBrain v1.2.0
Get Started
← Back to all entries
snippetcMinor

Complete async OpenSSL example

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
asyncexamplecompleteopenssl

Problem

I am trying to create a fully async example of a client and server using SSL.

I think these are the required assumptions:

  • Connecting may require socket readability and writeability notifications.



  • When the socket is readable, SSL_write may need to be called depending on the result of the last call to SSL_write.



  • When the socket is writable, SSL_read may need to be called depending on the result of the last call to SSL_read.



  • If the last call to SSL_connect, SSL_write, or SLL_read returned SSL_ERROR_WANT_WRITE, then the application cannot write anything new with SSL_write until the last call is recalled.



  • On the connecting side, SSL_write cannot be called until SSL_connect succeeds.



Are there any others?

On the accepting side, how can I tell if the socket is ready for a call to SSL_write?

Here is an example that seems to work completely. Please tell me if anything is wrong with it.

  • It can be compiled with gcc ssl.c -lssl -lcrypto.



  • The client is run with ./a.out client.



  • The server is run with ./a.out server.



  • You can make a sample pem for use by the server with:



echo -e "\n\n\n\n\n\n" | /usr/bin/openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout cert.pem -out cert.pem -config openssl.cnf
openssl x509 -in cert.pem -outform DER -out cert.pem.crt


`#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

typedef enum {
CONTINUE,
BREAK,
NEITHER
} ACTION;

ACTION ssl_connect(SSL ssl, int wants_tcp_write, int* connecting) {
printf("calling SSL_connect\n");

int result = SSL_connect(ssl);
if (result == 0) {
long error = ERR_get_error();
const char* error_str = ERR_error_string(error, NULL);
printf("could not SSL_connect: %s\n", error_str);
return BREAK;
} else if (result

Solution

In terms of error handling, it seems to be much safer to call ERR_clear_error() before any call to SSL_read(), SSL_write(), SSL_accept, and so on. See one of the few reported cases where error management has messed up people.

Basically, each thread shares an error stack. While SSL_get_error() grab the latest error associated to a ssl session, it does not remove it. ERR_get_error does. You might be in a case where you are reading an error from a previous call. This API is really... dubious, for the least.

Context

StackExchange Code Review Q#108600, answer score: 3

Revisions (0)

No revisions yet.