Skip to content

Commit

Permalink
Merge pull request #257 from esabol/issue-63-set-ssl-libgearman-patch…
Browse files Browse the repository at this point in the history
…-for-php

Issue #63: Add set_ssl API to libgearman for PHP extension and other potential uses
  • Loading branch information
SpamapS committed Feb 10, 2020
2 parents 71d0fef + c00b207 commit a40856d
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 24 deletions.
7 changes: 7 additions & 0 deletions libgearman-1.0/client.h
Expand Up @@ -171,6 +171,13 @@ int gearman_client_timeout(gearman_client_st *client);
GEARMAN_API
void gearman_client_set_timeout(gearman_client_st *client, int timeout);

/**
* See gearman_universal_set_ssl() for details.
*/
GEARMAN_API
void gearman_client_set_ssl(gearman_client_st *client, bool ssl,
const char *ca_file, const char *certificate, const char *key_file);

/**
* Get the application context for a client.
*
Expand Down
7 changes: 7 additions & 0 deletions libgearman-1.0/worker.h
Expand Up @@ -179,6 +179,13 @@ int gearman_worker_timeout(gearman_worker_st *worker);
GEARMAN_API
void gearman_worker_set_timeout(gearman_worker_st *worker, int timeout);

/**
* See gearman_universal_set_ssl() for details.
*/
GEARMAN_API
void gearman_worker_set_ssl(gearman_worker_st *worker, bool ssl,
const char *ca_file, const char *certificate, const char *key_file);

/**
* Get the application context for a worker.
*
Expand Down
7 changes: 3 additions & 4 deletions libgearman-server/io.cc
Expand Up @@ -152,7 +152,6 @@ static size_t _connection_read(gearman_server_con_st *con, void *data, size_t da
break;

case SSL_ERROR_SYSCALL:

if (errno) // If errno is really set, then let our normal error logic handle.
{
read_size= SOCKET_ERROR;
Expand All @@ -163,7 +162,7 @@ static size_t _connection_read(gearman_server_con_st *con, void *data, size_t da
case SSL_ERROR_SSL:
default:
{ // All other errors
char errorString[SSL_ERROR_SIZE];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(ssl_error, errorString, sizeof(errorString));
ret= GEARMAND_LOST_CONNECTION;
gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "SSL failure(%s) errno:%d", errorString, errno);
Expand Down Expand Up @@ -343,7 +342,7 @@ static gearmand_error_t _connection_flush(gearman_server_con_st *con)
case SSL_ERROR_SSL:
default:
{
char errorString[SSL_ERROR_SIZE];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(ssl_error, errorString, sizeof(errorString));
_connection_close(connection);
return gearmand_log_gerror(GEARMAN_DEFAULT_LOG_PARAM, GEARMAND_LOST_CONNECTION, "SSL failure(%s)",
Expand Down Expand Up @@ -797,7 +796,7 @@ gearmand_error_t gearman_io_recv(gearman_server_con_st *con, bool recv_data)
connection->recv_buffer_ptr= connection->recv_buffer;

size_t recv_size= _connection_read(con, connection->recv_buffer + connection->recv_buffer_size,
GEARMAND_RECV_BUFFER_SIZE - connection->recv_buffer_size, ret);
GEARMAND_RECV_BUFFER_SIZE - connection->recv_buffer_size, ret);
if (gearmand_failed(ret))
{
// GEARMAND_LOST_CONNECTION is not worth a warning, clients/workers just
Expand Down
20 changes: 14 additions & 6 deletions libgearman-server/plugins/protocol/gear/protocol.cc
Expand Up @@ -374,8 +374,8 @@ static gearmand_error_t _gear_con_add(gearman_server_con_st *connection)
int accept_error;
while ((accept_error= SSL_accept(connection->_ssl)) != SSL_SUCCESS)
{
int wolfssl_error;
switch (wolfssl_error= SSL_get_error(connection->_ssl, accept_error))
int ssl_error;
switch (ssl_error= SSL_get_error(connection->_ssl, accept_error))
{
case SSL_ERROR_NONE:
break;
Expand All @@ -393,10 +393,12 @@ static gearmand_error_t _gear_con_add(gearman_server_con_st *connection)
case SSL_ERROR_SSL:
case SSL_ERROR_ZERO_RETURN:
default:
char wolfssl_error_buffer[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(wolfssl_error, wolfssl_error_buffer, sizeof(wolfssl_error_buffer));
return gearmand_log_gerror(GEARMAN_DEFAULT_LOG_PARAM, GEARMAND_LOST_CONNECTION, "%s(%d)",
wolfssl_error_buffer, wolfssl_error);
{
char ssl_error_buffer[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(ssl_error, ssl_error_buffer, sizeof(ssl_error_buffer));
return gearmand_log_gerror(GEARMAN_DEFAULT_LOG_PARAM, GEARMAND_LOST_CONNECTION, "%s(%d)",
ssl_error_buffer, ssl_error);
}
}
}
gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "GearSSL connection made: %s:%s", connection->host(), connection->port());
Expand Down Expand Up @@ -512,6 +514,12 @@ gearmand_error_t Gear::start(gearmand_st *gearmand)
}
gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Loading certificate key : %s", _ssl_key.c_str());

if (SSL_CTX_check_private_key(gearmand->ctx_ssl()) != SSL_SUCCESS)
{
gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "SSL_CTX_check_private_key() cannot check certificate %s", _ssl_key.c_str());
}
gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Checking certificate key : %s", _ssl_key.c_str());

assert(gearmand->ctx_ssl());
}
#endif
Expand Down
9 changes: 9 additions & 0 deletions libgearman/client.cc
Expand Up @@ -546,6 +546,15 @@ void gearman_client_set_timeout(gearman_client_st *client_shell, int timeout)
}
}

void gearman_client_set_ssl(gearman_client_st *client_shell, bool ssl,
const char *ca_file, const char *certificate, const char *key_file)
{
if (client_shell && client_shell->impl())
{
gearman_universal_set_ssl(client_shell->impl()->universal, ssl, ca_file, certificate, key_file);
}
}

void *gearman_client_context(const gearman_client_st *client_shell)
{
if (client_shell and client_shell->impl())
Expand Down
8 changes: 5 additions & 3 deletions libgearman/connection.cc
Expand Up @@ -680,10 +680,12 @@ gearman_return_t gearman_connection_st::enable_ssl()
if (SSL_set_fd(_ssl, fd) != SSL_SUCCESS)
{
close_socket();
char errorString[SSL_ERROR_SIZE];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(SSL_get_error(_ssl, 0), errorString, sizeof(errorString));
return gearman_error(universal, GEARMAN_COULD_NOT_CONNECT, errorString);
}

SSL_set_connect_state(_ssl);
}
#endif

Expand Down Expand Up @@ -872,7 +874,7 @@ gearman_return_t gearman_connection_st::flush()
case SSL_ERROR_SSL:
default:
{
char errorString[80];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(ssl_error, errorString, sizeof(errorString));
close_socket();
return gearman_universal_set_error(universal, GEARMAN_LOST_CONNECTION, GEARMAN_AT, "SSL failure(%s)", errorString);
Expand Down Expand Up @@ -1186,7 +1188,7 @@ size_t gearman_connection_st::recv_socket(void *data, size_t data_size, gearman_
case SSL_ERROR_SSL:
default:
{
char errorString[80];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(ssl_error, errorString, sizeof(errorString));
close_socket();
return gearman_universal_set_error(universal, GEARMAN_LOST_CONNECTION, GEARMAN_AT, "SSL failure(%s)", errorString);
Expand Down
67 changes: 66 additions & 1 deletion libgearman/interface/universal.hpp
Expand Up @@ -46,6 +46,8 @@
#include "libgearman/assert.hpp"
#include "libgearman/ssl.h"

#include <cstring>

enum universal_options_t
{
GEARMAN_UNIVERSAL_NON_BLOCKING,
Expand All @@ -68,12 +70,18 @@ struct gearman_universal_st : public error_st
bool non_blocking;
bool no_new_data;
bool _ssl;
struct gearman_vector_st *_ssl_ca_file;
struct gearman_vector_st *_ssl_certificate;
struct gearman_vector_st *_ssl_key;

Options() :
dont_track_packets{false},
non_blocking{false},
no_new_data{false},
_ssl{false}
_ssl{false},
_ssl_ca_file{NULL},
_ssl_certificate{NULL},
_ssl_key{NULL}
{ }
} options;
gearman_verbose_t verbose;
Expand Down Expand Up @@ -208,6 +216,11 @@ struct gearman_universal_st : public error_st

const char* ssl_ca_file() const
{
if (options._ssl_ca_file && options._ssl_ca_file->size())
{
return options._ssl_ca_file->c_str();
}

if (getenv("GEARMAND_CA_CERTIFICATE"))
{
return getenv("GEARMAND_CA_CERTIFICATE");
Expand All @@ -216,8 +229,27 @@ struct gearman_universal_st : public error_st
return GEARMAND_CA_CERTIFICATE;
}

void ssl_ca_file(const char* ssl_ca_file_)
{
gearman_string_free(options._ssl_ca_file);
size_t ssl_ca_file_size_ = 0;
if (ssl_ca_file_ && (ssl_ca_file_size_ = strlen(ssl_ca_file_)))
{
options._ssl_ca_file = gearman_string_create(NULL, ssl_ca_file_, ssl_ca_file_size_);
}
else
{
options._ssl_ca_file = NULL;
}
}

const char* ssl_certificate() const
{
if (options._ssl_certificate && options._ssl_certificate->size())
{
return options._ssl_certificate->c_str();
}

if (getenv("GEARMAN_CLIENT_PEM"))
{
return getenv("GEARMAN_CLIENT_PEM");
Expand All @@ -226,8 +258,27 @@ struct gearman_universal_st : public error_st
return GEARMAN_CLIENT_PEM;
}

void ssl_certificate(const char *ssl_certificate_)
{
gearman_string_free(options._ssl_certificate);
size_t ssl_certificate_size_ = 0;
if (ssl_certificate_ && (ssl_certificate_size_ = strlen(ssl_certificate_)))
{
options._ssl_certificate = gearman_string_create(NULL, ssl_certificate_, ssl_certificate_size_);
}
else
{
options._ssl_certificate = NULL;
}
}

const char* ssl_key() const
{
if (options._ssl_key && options._ssl_key->size())
{
return options._ssl_key->c_str();
}

if (getenv("GEARMAN_CLIENT_KEY"))
{
return getenv("GEARMAN_CLIENT_KEY");
Expand All @@ -236,6 +287,20 @@ struct gearman_universal_st : public error_st
return GEARMAN_CLIENT_KEY;
}

void ssl_key(const char *ssl_key_)
{
gearman_string_free(options._ssl_key);
size_t ssl_key_size_ = 0;
if (ssl_key_ && (ssl_key_size_ = strlen(ssl_key_)))
{
options._ssl_key = gearman_string_create(NULL, ssl_key_, ssl_key_size_);
}
else
{
options._ssl_key = NULL;
}
}

private:
bool init_ssl();

Expand Down
38 changes: 37 additions & 1 deletion libgearman/universal.cc
Expand Up @@ -183,6 +183,15 @@ void gearman_universal_set_timeout(gearman_universal_st &self, int timeout)
self.timeout= timeout;
}

void gearman_universal_set_ssl(gearman_universal_st &self, bool ssl,
const char *ca_file, const char *certificate, const char *key_file)
{
self.ssl(ssl);
self.ssl_ca_file(ca_file);
self.ssl_certificate(certificate);
self.ssl_key(key_file);
}

void gearman_set_log_fn(gearman_universal_st &self, gearman_log_fn *function,
void *context, gearman_verbose_t verbose)
{
Expand Down Expand Up @@ -470,6 +479,27 @@ bool gearman_universal_st::init_ssl()
if (ssl())
{
#if defined(HAVE_SSL) && HAVE_SSL
// Check these files exist or not to avoid coredump.
FILE *file = NULL;
if ((file = fopen(ssl_ca_file(), "r")) == NULL)
{
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to open CA certificate %s (%d: %s)", ssl_ca_file(), errno, strerror(errno));
return false;
}
fclose(file);
if ((file = fopen(ssl_certificate(), "r")) == NULL)
{
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to open certificate %s (%d: %s)", ssl_certificate(), errno, strerror(errno));
return false;
}
fclose(file);
if ((file = fopen(ssl_key(), "r")) == NULL)
{
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to open certificate key %s (%d: %s)", ssl_key(), errno, strerror(errno));
return false;
}
fclose(file);

SSL_load_error_strings();
SSL_library_init();

Expand All @@ -479,7 +509,7 @@ bool gearman_universal_st::init_ssl()
if ((_ctx_ssl= SSL_CTX_new(TLS_client_method())) == NULL)
#endif
{
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "CyaTLSv1_client_method() failed");
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "TLS_client_method() failed");
return false;
}

Expand All @@ -500,6 +530,12 @@ bool gearman_universal_st::init_ssl()
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to load certificate key %s", ssl_key());
return false;
}

if (SSL_CTX_check_private_key(_ctx_ssl) != SSL_SUCCESS)
{
gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to check private key");
return false;
}
#endif // defined(HAVE_SSL) && HAVE_SSL
}

Expand Down
3 changes: 3 additions & 0 deletions libgearman/universal.hpp
Expand Up @@ -57,6 +57,9 @@ void gearman_universal_set_timeout(gearman_universal_st &self, int timeout);

int gearman_universal_timeout(gearman_universal_st &self);

void gearman_universal_set_ssl(gearman_universal_st &self, bool ssl,
const char *ca_file, const char *certificate, const char *key_file);

void gearman_universal_set_namespace(gearman_universal_st &self, const char *namespace_key, size_t namespace_key_size);

gearman_return_t cancel_job(gearman_universal_st& universal,
Expand Down
4 changes: 2 additions & 2 deletions libtest/client.cc
Expand Up @@ -382,7 +382,7 @@ bool SimpleClient::message(const char* ptr, const size_t len)
case SSL_ERROR_SSL:
default:
{
char errorString[SSL_ERROR_SIZE];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(ssl_error, errorString, sizeof(errorString));
error(__FILE__, __LINE__, errorString);
close_socket();
Expand Down Expand Up @@ -504,7 +504,7 @@ bool SimpleClient::response(libtest::vchar_t& response_)
case SSL_ERROR_SSL:
default:
{
char errorString[SSL_ERROR_SIZE];
char errorString[SSL_ERROR_SIZE]= { 0 };
ERR_error_string_n(readErr, errorString, sizeof(errorString));
error(__FILE__, __LINE__, errorString);
return false;
Expand Down

0 comments on commit a40856d

Please sign in to comment.