Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions src/dnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <openssl/ssl.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#endif
Expand All @@ -36,6 +37,7 @@ struct socket {
int avail_bytes; /* Available bytes in buffer */
char *bufptr; /* Pointer to Internal buffer */
char *buf; /* The buffer. */
char errstr[256]; /* Last error description (TLS or system) */
#ifdef HAVE_LIBSSL
SSL_CTX *ctx; /* OpenSSL CTX struct, used for TLS */
SSL *ssl; /* OpenSSL SSL struct, used for TLS */
Expand Down Expand Up @@ -108,6 +110,7 @@ dnetConnect(const char *hostname, unsigned int port)
if (sd > 0) {
if (connect(sd, (SA *)&sin, sizeof(SIN)) >= 0) {
ret = xmalloc(sizeof(struct socket));
memset(ret, 0, sizeof(struct socket));
ret->sock = sd;
ret->buf = xmalloc(MAXSOCKBUF);
ret->bufptr = ret->buf;
Expand Down Expand Up @@ -154,6 +157,23 @@ _genRandomSeed(void)
}
#endif

#ifdef HAVE_LIBSSL
/**
* Records the last OpenSSL error into the socket so that it can be
* retrieved later with dnetGetErr().
*/
static void
_setSslErr(dsocket *sd)
{
unsigned long err = ERR_get_error();
if (err) {
ERR_error_string_n(err, sd->errstr, sizeof(sd->errstr));
} else {
snprintf(sd->errstr, sizeof(sd->errstr), "unknown OpenSSL error");
}
}
#endif

/**
* This will allow you to use TLS over an existing connection.
* Will return error if a connection has not already been established.
Expand All @@ -169,21 +189,35 @@ dnetUseTls(dsocket *sd)

SSL_load_error_strings();
if (SSL_library_init() == -1) {
_setSslErr(sd);
return ERROR;
}
_genRandomSeed();
sd->ctx = SSL_CTX_new(TLSv1_client_method());
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
/*
* TLS_client_method() negotiates the highest version mutually
* supported with the server. The deprecated version-specific
* TLSv1_client_method() pins the protocol to TLS 1.0, which
* modern servers (and modern system OpenSSL configs) reject.
*/
sd->ctx = SSL_CTX_new(TLS_client_method());
#else
sd->ctx = SSL_CTX_new(SSLv23_client_method());
#endif
if (!sd->ctx) {
_setSslErr(sd);
return ERROR;
}
sd->ssl = SSL_new(sd->ctx);
if (!sd->ssl) {
_setSslErr(sd);
SSL_CTX_free(sd->ctx);
sd->ctx = NULL;
return ERROR;
}
SSL_set_fd(sd->ssl, sd->sock);
if (SSL_connect(sd->ssl) == -1) {
_setSslErr(sd);
SSL_CTX_free(sd->ctx);
SSL_free(sd->ssl);
sd->ssl = NULL;
Expand Down Expand Up @@ -445,12 +479,16 @@ dnetEof(dsocket *sd)
}

/**
* Returns the error string from the system which is
* determined by errnum (errno).
* Returns the error string describing the last error on the socket.
* Prefers the TLS/OpenSSL error recorded by dnetUseTls() and falls
* back to the system errno string.
*/
char *
dnetGetErr(dsocket *sd)
{
if (sd->errstr[0] != '\0') {
return sd->errstr;
}
return strerror(sd->errnum);
}

Expand Down